Clover Coverage Report
Coverage timestamp: Sun Mar 23 2008 08:24:39 GMT
82   394   28   7.45
40   164   0.46   11
11     3.45  
1    
 
 
  Util       Line # 96 82 28 51.1% 0.5112782
 
  (1)
 
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 toggle 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 toggle 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 toggle 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 toggle 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 toggle 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 toggle 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 toggle 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 toggle 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 toggle 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 toggle 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 togglepublic 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    }