Util | Line # 96 | 82 | 28 | 51.1% |
0.5112782
|
(1) | |||
Result | |||
0.38345864
|
issrg.test.ds.TestDS.testIssuing issrg.test.ds.TestDS.testIssuing | 1 PASS | |
1 | /* | |
2 | * Copyright (c) 2006, University of Kent | |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions are met: | |
7 | * | |
8 | * Redistributions of source code must retain the above copyright notice, this | |
9 | * list of conditions and the following disclaimer. | |
10 | * | |
11 | * Redistributions in binary form must reproduce the above copyright notice, | |
12 | * this list of conditions and the following disclaimer in the documentation | |
13 | * and/or other materials provided with the distribution. | |
14 | * | |
15 | * 1. Neither the name of the University of Kent nor the names of its | |
16 | * contributors may be used to endorse or promote products derived from this | |
17 | * software without specific prior written permission. | |
18 | * | |
19 | * 2. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS | |
20 | * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |
21 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
22 | * PURPOSE ARE DISCLAIMED. | |
23 | * | |
24 | * 3. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
25 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
31 | * POSSIBILITY OF SUCH DAMAGE. | |
32 | * | |
33 | * 4. YOU AGREE THAT THE EXCLUSIONS IN PARAGRAPHS 2 AND 3 ABOVE ARE REASONABLE | |
34 | * IN THE CIRCUMSTANCES. IN PARTICULAR, YOU ACKNOWLEDGE (1) THAT THIS | |
35 | * SOFTWARE HAS BEEN MADE AVAILABLE TO YOU FREE OF CHARGE, (2) THAT THIS | |
36 | * SOFTWARE IS NOT "PRODUCT" QUALITY, BUT HAS BEEN PRODUCED BY A RESEARCH | |
37 | * GROUP WHO DESIRE TO MAKE THIS SOFTWARE FREELY AVAILABLE TO PEOPLE WHO WISH | |
38 | * TO USE IT, AND (3) THAT BECAUSE THIS SOFTWARE IS NOT OF "PRODUCT" QUALITY | |
39 | * IT IS INEVITABLE THAT THERE WILL BE BUGS AND ERRORS, AND POSSIBLY MORE | |
40 | * SERIOUS FAULTS, IN THIS SOFTWARE. | |
41 | * | |
42 | * 5. This license is governed, except to the extent that local laws | |
43 | * necessarily apply, by the laws of England and Wales. | |
44 | */ | |
45 | /* | |
46 | * Copyright (c) 2000-2005, University of Salford | |
47 | * All rights reserved. | |
48 | * | |
49 | * Redistribution and use in source and binary forms, with or without | |
50 | * modification, are permitted provided that the following conditions are met: | |
51 | * | |
52 | * Redistributions of source code must retain the above copyright notice, this | |
53 | * list of conditions and the following disclaimer. | |
54 | * | |
55 | * Redistributions in binary form must reproduce the above copyright notice, | |
56 | * this list of conditions and the following disclaimer in the documentation | |
57 | * and/or other materials provided with the distribution. | |
58 | * | |
59 | * Neither the name of the University of Salford nor the names of its | |
60 | * contributors may be used to endorse or promote products derived from this | |
61 | * software without specific prior written permission. | |
62 | * | |
63 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
64 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
65 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
66 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
67 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
68 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
69 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
70 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
71 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
72 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
73 | * POSSIBILITY OF SUCH DAMAGE. | |
74 | */ | |
75 | ||
76 | package issrg.ac; | |
77 | ||
78 | import iaik.asn1.structures.GeneralNames; | |
79 | //import issrg.acm.DefaultSigningUtility; | |
80 | import issrg.utils.EnvironmentalVariables; | |
81 | ||
82 | import java.security.MessageDigest; | |
83 | import java.util.Calendar; | |
84 | import java.util.GregorianCalendar; | |
85 | import java.util.Map; | |
86 | import java.math.BigInteger; | |
87 | ||
88 | /** | |
89 | * This class contains various utility routines for converting things from one | |
90 | * representation into another. | |
91 | * | |
92 | * @author A Otenko | |
93 | * @version 1.0 | |
94 | */ | |
95 | ||
96 | public class Util { | |
97 | /** | |
98 | * This variable sets the attribute type for the serial number in the DN, when | |
99 | * constructing it for the IssuerSerial case. | |
100 | */ | |
101 | final public static String SN_ATTRIBUTE_TYPE = "SN"; | |
102 | ||
103 | /** | |
104 | * Converts the given general Name in iaik representation into a String. | |
105 | * | |
106 | * @param gns the GeneralNames construct to convert; must be an X.500 | |
107 | * directory name. | |
108 | * @return the string representation of a General Name in reverse | |
109 | * order; for example, "cn=Sassa, ou=ISI, o=Salford University, c=GB" | |
110 | */ | |
111 | 3651 | public static String generalNamesToString(iaik.asn1.structures.GeneralNames gns){ |
112 | 3651 | try{ |
113 | 3651 | iaik.asn1.structures.Name name=new iaik.asn1.structures.Name(); |
114 | 3651 | if (gns!=null){ |
115 | ||
116 | 7302 | for (java.util.Enumeration e = gns.getNames(); e.hasMoreElements(); ){ |
117 | 3651 | iaik.asn1.structures.GeneralName gn = (iaik.asn1.structures.GeneralName)e.nextElement(); |
118 | 3651 | if (gn.getType()==iaik.asn1.structures.GeneralName.directoryName){ |
119 | 3651 | iaik.asn1.structures.Name n=(iaik.asn1.structures.Name)gn.getName(); |
120 | 18514 | for (java.util.Enumeration e_rdns=n.elements(); e_rdns.hasMoreElements();){ |
121 | 14863 | name.addRDN((iaik.asn1.structures.RDN)e_rdns.nextElement()); |
122 | } | |
123 | } | |
124 | } | |
125 | } | |
126 | ||
127 | 3651 | return name.getRFC2253String(); |
128 | }catch (iaik.utils.RFC2253NameParserException re){ | |
129 | 0 | return null; |
130 | } | |
131 | } | |
132 | ||
133 | /** | |
134 | * This is the universal way for constructing the LDAP DN for the entry, whose | |
135 | * name is constructed out of the PKC Issuer DN and PKC SN. | |
136 | * | |
137 | * @param issuerDN - the DN of the issuer | |
138 | * @param serialNumber - the serial number of the PKC issued by that issuer | |
139 | * | |
140 | * @return the DN combining the serial number and the issuer DN | |
141 | */ | |
142 | 0 | public static String issuerSerialToDN(String issuerDN, java.math.BigInteger serialNumber){ |
143 | 0 | if (issuerDN==null || serialNumber==null){ |
144 | // TODO: do I throw an exception instead? | |
145 | 0 | return null; |
146 | } | |
147 | 0 | return SN_ATTRIBUTE_TYPE+"="+serialNumber.toString()+((issuerDN.intern()=="")?"":(","+issuerDN)); |
148 | } | |
149 | ||
150 | /** | |
151 | * Returns the string representation of the Issuer General Name, if V1Form or | |
152 | * IssuerName of the V2Form is present. Otherwise, returns null. | |
153 | * | |
154 | * @param aci - the AttCertIssuer structure | |
155 | * | |
156 | * @return String of the Issuer GeneralName, or null, if the name is not | |
157 | * present | |
158 | * in the given AttCertIssuer structure. | |
159 | */ | |
160 | 0 | public static String issuerToString(AttCertIssuer aci){ |
161 | 0 | String issuer = null; |
162 | 0 | if (aci.getV1Form() != null) issuer=generalNamesToString(aci.getV1Form()); |
163 | 0 | else if (aci.getV2Form() != null){ |
164 | 0 | if (aci.getV2Form().getIssuerName() != null) issuer=generalNamesToString(aci.getV2Form().getIssuerName()); |
165 | } | |
166 | ||
167 | 0 | return issuer; |
168 | } | |
169 | ||
170 | /** | |
171 | * This method builds a General Names construct out of the string | |
172 | * representation of an LDAP DN that should be RFC2253 compliant. Note that | |
173 | * the | |
174 | * attribute names are case insensitive, even though RFC2253 specifies | |
175 | * otherwise. | |
176 | * | |
177 | * @param DN is the String with LDAP DN; if a parse error occures, a | |
178 | * GeneralNames | |
179 | * corresponding to the null DN will be constructed | |
180 | * | |
181 | * @return a GeneralNames construct; is never null | |
182 | */ | |
183 | 22 | public static iaik.asn1.structures.GeneralNames buildGeneralNames(String DN){ |
184 | // builds GeneralNames out of string representation of a Directory Name | |
185 | 22 | try{ |
186 | 22 | DN = issrg.utils.RFC2253NameParser.toCanonicalDN(issrg.utils.RFC2253NameParser.distinguishedName(DN)); |
187 | ||
188 | 22 | iaik.asn1.structures.GeneralNames result=new iaik.asn1.structures.GeneralNames( |
189 | new iaik.asn1.structures.GeneralName( | |
190 | iaik.asn1.structures.GeneralName.directoryName, | |
191 | new iaik.utils.RFC2253NameParser(DN).parse() | |
192 | )); | |
193 | ||
194 | 22 | if (result==null){ |
195 | 0 | throw new iaik.utils.RFC2253NameParserException(); |
196 | } | |
197 | ||
198 | 22 | return result; |
199 | }catch (issrg.utils.RFC2253ParsingException npe){ | |
200 | 0 | return new iaik.asn1.structures.GeneralNames( |
201 | new iaik.asn1.structures.GeneralName( | |
202 | iaik.asn1.structures.GeneralName.directoryName, | |
203 | new iaik.asn1.structures.Name() | |
204 | ) | |
205 | ); | |
206 | }catch (iaik.utils.RFC2253NameParserException re){ | |
207 | 0 | return new iaik.asn1.structures.GeneralNames( |
208 | new iaik.asn1.structures.GeneralName( | |
209 | iaik.asn1.structures.GeneralName.directoryName, | |
210 | new iaik.asn1.structures.Name() | |
211 | ) | |
212 | ); | |
213 | } | |
214 | } | |
215 | ||
216 | /** | |
217 | * This method converts the hash byte array to string. Use this method, | |
218 | * if you are looking for filenames, so the filenames are created in a | |
219 | * uniform fashion. | |
220 | * | |
221 | * @param hash - the byte array of the hash | |
222 | * | |
223 | * @return the String of the hash in hexadecimal form | |
224 | */ | |
225 | 48 | public static String hashToString(byte [] hash){ |
226 | 48 | BigInteger bi = new BigInteger(hash); |
227 | 48 | if (bi.signum()<0) bi = bi.xor(BigInteger.ONE. |
228 | negate(). | |
229 | shiftLeft(hash.length<<3) | |
230 | ); | |
231 | ||
232 | 48 | return bi.toString(16); // clear the sign bit |
233 | } | |
234 | ||
235 | /** | |
236 | * Returns MD5 hash of the given string. Returns null, if the string is null. | |
237 | * | |
238 | * @param s - the string of which the hash has to be calculated. | |
239 | * | |
240 | * @return the MD5 hash, or null, if the string is null, or MD5 provider was | |
241 | * not found | |
242 | */ | |
243 | 48 | public static byte[] hashString(String s){ |
244 | 0 | if (s==null) return null; |
245 | ||
246 | 48 | try{ |
247 | 48 | MessageDigest md5 = MessageDigest.getInstance("MD5"); |
248 | 48 | return md5.digest(s.getBytes()); |
249 | }catch(java.security.NoSuchAlgorithmException nse){ | |
250 | 0 | return null; |
251 | } | |
252 | } | |
253 | ||
254 | /** | |
255 | * This method converts the given string to a canonical DN, then calculates its | |
256 | * hash using hashString. If the string is not a canonical DN, null will be | |
257 | * hashed (see hashString). | |
258 | * | |
259 | * @param name - the DN to canonicalise and hash | |
260 | * | |
261 | * @return the MD5 hash of the canonical RFC2253 DN | |
262 | */ | |
263 | 48 | public static byte[] hashDN(String name){ |
264 | 48 | try{ |
265 | 48 | name = issrg.utils.RFC2253NameParser.toCanonicalDN(issrg.utils.RFC2253NameParser.distinguishedName(name)).toUpperCase(); |
266 | }catch (issrg.utils.RFC2253ParsingException rpe){ | |
267 | 0 | name = null; |
268 | } | |
269 | ||
270 | 48 | return hashString(name); |
271 | } | |
272 | ||
273 | /** | |
274 | * This is a utility method that returns the hash of the DN contained in the | |
275 | * GeneralNames. | |
276 | * | |
277 | * @param gn - the GeneralNames of which the directoryName will be converted | |
278 | * to a canonical RFC2253-compliant LDAP distinguished name and then hashed | |
279 | */ | |
280 | 0 | public static byte[] hashName(GeneralNames gn){ |
281 | 0 | String name = Util.generalNamesToString(gn); |
282 | 0 | return hashDN(name); |
283 | } | |
284 | ||
285 | /** | |
286 | * Builds a date out of a string representation of it in date. | |
287 | * | |
288 | * @param date the string representation of the date in form | |
289 | * "yyyy.mm.dd hh:mm:ss". The separators between numbers are defined by | |
290 | * DATE_SEPARATOR and TIME_SEPARATOR respectively, the space between | |
291 | * date and time is not redefinable. The lengths of numbers and ranges of | |
292 | * their values are not checked (unless Generalized_Time or GregorianCalendar | |
293 | * constructor does. More specific time values can be omitted. That is, | |
294 | * "yyyy" is a valid value, and "yyyy.mm", and "yyyy.mm.dd hh", etc; but "yyyy.mm hh" is not: | |
295 | * day must be specified first. | |
296 | * @return returns Generalized_Time object, which contains the date. | |
297 | * @throws ACCreationException if the string representation does not comply with | |
298 | * the rules specified above. | |
299 | */ | |
300 | 60 | public static issrg.ac.Generalized_Time buildGeneralizedTime(String date) throws ACCreationException{ |
301 | 60 | int yr=0, mon=1, day=1; |
302 | 60 | int hour=0, min=0, sec=0; |
303 | ||
304 | 60 | int i; |
305 | 60 | String d = date+Util.DATE_SEPARATOR; // now i know what the string will end with, and if there is no separator somewhere... |
306 | ||
307 | 60 | try{ |
308 | 60 | i=d.indexOf(Util.DATE_SEPARATOR); // cannot be negative: there's always a DATE_SEPARATOR in this string. |
309 | 60 | yr = Integer.parseInt(d.substring(0, i)); |
310 | 0 | if ((d = d.substring(i+Util.DATE_SEPARATOR.length())).intern()!=""){ |
311 | 60 | i=d.indexOf(Util.DATE_SEPARATOR); // still, cannot be negative: either d is empty (and gone by other branch in previous if), or a DATE_SEPARATOR is present |
312 | 60 | mon = Integer.parseInt(d.substring(0, i)); |
313 | 0 | if ((d = d.substring(i+Util.DATE_SEPARATOR.length())).intern()!=""){ |
314 | 60 | d=d.substring(0, d.length()-Util.DATE_SEPARATOR.length())+" "; |
315 | 60 | i=d.indexOf(" "); |
316 | 60 | day = Integer.parseInt(d.substring(0, i)); |
317 | 0 | if ((d = d.substring(i+1)).intern()!=""){ |
318 | 60 | d=d.substring(0, d.length()-1)+Util.TIME_SEPARATOR; |
319 | 60 | i=d.indexOf(Util.TIME_SEPARATOR); |
320 | 60 | hour = Integer.parseInt(d.substring(0, i)); |
321 | 0 | if ((d = d.substring(i+Util.TIME_SEPARATOR.length())).intern()!=""){ |
322 | 60 | i=d.indexOf(Util.TIME_SEPARATOR); |
323 | 60 | min = Integer.parseInt(d.substring(0, i)); |
324 | 0 | if ((d = d.substring(i+Util.TIME_SEPARATOR.length())).intern()!=""){ |
325 | 60 | i=d.indexOf(Util.TIME_SEPARATOR); |
326 | 60 | sec = Integer.parseInt(d.substring(0, i)); |
327 | 0 | if ((d = d.substring(i+Util.TIME_SEPARATOR.length())).intern()!=""){ |
328 | 0 | throw new NumberFormatException(); // in fact, at this moment the string must be empty |
329 | } | |
330 | } | |
331 | } | |
332 | } | |
333 | } | |
334 | } | |
335 | ||
336 | 60 | return new issrg.ac.Generalized_Time(new java.util.GregorianCalendar(yr, mon-1, day, hour, min, sec)); |
337 | // note that Calendar keeps Months in range 0..11 | |
338 | ||
339 | }catch (NumberFormatException nfe){ | |
340 | 0 | throw new ACCreationException("Invalid date format in ["+date+"].\n[yyyy"+Util.DATE_SEPARATOR+"mm"+Util.DATE_SEPARATOR+"dd hh"+Util.TIME_SEPARATOR+"mm"+Util.TIME_SEPARATOR+"ss] was expected."); |
341 | } | |
342 | } | |
343 | ||
344 | /** | |
345 | * This is the separator between the times. You can change it at runtime | |
346 | */ | |
347 | public static String TIME_SEPARATOR = ":"; | |
348 | /** | |
349 | * This is the separator between the serial number and the DN of the Issuer. You can change it at runtime | |
350 | */ | |
351 | public static String SN_NAME_SEPARATOR = ";"; | |
352 | /** | |
353 | * This is the separator between the dates. You can change it at runtime | |
354 | */ | |
355 | public static String DATE_SEPARATOR = "."; | |
356 | ||
357 | /** | |
358 | * Converts the given date into internal format "ccyy.mm.dd hh:mm:ss". Actual | |
359 | * date and time separators are taken from the corresponding constants | |
360 | * DATE_SEPARATOR and TIME_SEPARATOR. | |
361 | * | |
362 | * @param date the date to convert. | |
363 | * @return returns the string representation of the date in format | |
364 | * "ccyy.mm.dd hh:mm:ss" | |
365 | */ | |
366 | 0 | public static String timeToString(java.util.Calendar date){ |
367 | 0 | return date.get(date.YEAR)+Util.DATE_SEPARATOR+ |
368 | (date.get(date.MONTH)+1)+Util.DATE_SEPARATOR+ | |
369 | // note that Calendar keeps Months in range 0..11 | |
370 | date.get(date.DAY_OF_MONTH)+" "+ | |
371 | date.get(date.HOUR_OF_DAY)+Util.TIME_SEPARATOR+ | |
372 | date.get(date.MINUTE)+Util.TIME_SEPARATOR+ | |
373 | date.get(date.SECOND); | |
374 | } | |
375 | ||
376 | 0 | public static issrg.ac.IssuerSerial buildIssuerSerial(String what) throws ACCreationException{ |
377 | // builds an Issuer Serial ASN1 construct out of a string representation; issuer UID is null. | |
378 | // the string should be of the form: S/N;Holder_directory_name | |
379 | 0 | if (what.equals("")) return null; |
380 | ||
381 | 0 | int i = what.indexOf(Util.SN_NAME_SEPARATOR); |
382 | 0 | if (i<1){ // apparently illegal string |
383 | 0 | throw new ACCreationException("Illegal separator between Serial Number and Issuer Name: \""+Util.SN_NAME_SEPARATOR+"\" was expected"); |
384 | } | |
385 | 0 | try{ |
386 | 0 | return new issrg.ac.IssuerSerial(buildGeneralNames(what.substring(i+1)), |
387 | new java.math.BigInteger(what.substring(0,i)), | |
388 | null); | |
389 | ||
390 | }catch (NumberFormatException nfe){ | |
391 | 0 | throw new ACCreationException("Issuer's Certificate Serial Number must be a valid Integer value"); |
392 | } | |
393 | } | |
394 | } |
|