KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > lowagie > text > pdf > PdfPKCS7


1 /*
2  * Copyright 2004 by Paulo Soares.
3  *
4  * The contents of this file are subject to the Mozilla Public License Version 1.1
5  * (the "License"); you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at http://www.mozilla.org/MPL/
7  *
8  * Software distributed under the License is distributed on an "AS IS" basis,
9  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
10  * for the specific language governing rights and limitations under the License.
11  *
12  * The Original Code is 'iText, a free JAVA-PDF library'.
13  *
14  * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
15  * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
16  * All Rights Reserved.
17  * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
18  * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
19  *
20  * Contributor(s): all the names of the contributors are added in the source code
21  * where applicable.
22  *
23  * Alternatively, the contents of this file may be used under the terms of the
24  * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
25  * provisions of LGPL are applicable instead of those above. If you wish to
26  * allow use of your version of this file only under the terms of the LGPL
27  * License and not to allow others to use your version of this file under
28  * the MPL, indicate your decision by deleting the provisions above and
29  * replace them with the notice and other provisions required by the LGPL.
30  * If you do not delete the provisions above, a recipient may use your version
31  * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
32  *
33  * This library is free software; you can redistribute it and/or modify it
34  * under the terms of the MPL as stated above or under the terms of the GNU
35  * Library General Public License as published by the Free Software Foundation;
36  * either version 2 of the License, or any later version.
37  *
38  * This library is distributed in the hope that it will be useful, but WITHOUT
39  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
40  * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
41  * details.
42  *
43  * If you didn't download this code from the following link, you should check if
44  * you aren't using an obsolete version:
45  * http://www.lowagie.com/iText/
46  */

47 package com.lowagie.text.pdf;
48
49 import java.io.ByteArrayInputStream JavaDoc;
50 import java.io.ByteArrayOutputStream JavaDoc;
51 import java.io.File JavaDoc;
52 import java.io.FileInputStream JavaDoc;
53 import java.io.IOException JavaDoc;
54 import java.security.InvalidKeyException JavaDoc;
55 import java.security.KeyStore JavaDoc;
56 import java.security.MessageDigest JavaDoc;
57 import java.security.NoSuchAlgorithmException JavaDoc;
58 import java.security.NoSuchProviderException JavaDoc;
59 import java.security.PrivateKey JavaDoc;
60 import java.security.Signature JavaDoc;
61 import java.security.SignatureException JavaDoc;
62 import java.security.cert.CRL JavaDoc;
63 import java.security.cert.CRLException JavaDoc;
64 import java.security.cert.Certificate JavaDoc;
65 import java.security.cert.CertificateException JavaDoc;
66 import java.security.cert.X509CRL JavaDoc;
67 import java.security.cert.X509Certificate JavaDoc;
68 import java.util.ArrayList JavaDoc;
69 import java.util.Arrays JavaDoc;
70 import java.util.Calendar JavaDoc;
71 import java.util.Collection JavaDoc;
72 import java.util.Enumeration JavaDoc;
73 import java.util.GregorianCalendar JavaDoc;
74 import java.util.HashMap JavaDoc;
75 import java.util.HashSet JavaDoc;
76 import java.util.Iterator JavaDoc;
77 import java.util.Set JavaDoc;
78
79 import com.lowagie.text.ExceptionConverter;
80 import java.math.BigInteger JavaDoc;
81 import org.bouncycastle.asn1.ASN1EncodableVector;
82 import org.bouncycastle.asn1.ASN1InputStream;
83 import org.bouncycastle.asn1.ASN1OutputStream;
84 import org.bouncycastle.asn1.ASN1Sequence;
85 import org.bouncycastle.asn1.ASN1Set;
86 import org.bouncycastle.asn1.ASN1TaggedObject;
87 import org.bouncycastle.asn1.DERConstructedSet;
88 import org.bouncycastle.asn1.DERInteger;
89 import org.bouncycastle.asn1.DERNull;
90 import org.bouncycastle.asn1.DERObject;
91 import org.bouncycastle.asn1.DERObjectIdentifier;
92 import org.bouncycastle.asn1.DEROctetString;
93 import org.bouncycastle.asn1.DERSequence;
94 import org.bouncycastle.asn1.DERSet;
95 import org.bouncycastle.asn1.DERString;
96 import org.bouncycastle.asn1.DERTaggedObject;
97 import org.bouncycastle.asn1.DERUTCTime;
98 import org.bouncycastle.jce.provider.X509CRLParser;
99 import org.bouncycastle.jce.provider.X509CertParser;
100 import org.bouncycastle.util.StreamParsingException;
101
102 /**
103  * This class does all the processing related to signing and verifying a PKCS#7
104  * signature.
105  * <p>
106  * It's based in code found at org.bouncycastle.
107  */

108 public class PdfPKCS7 {
109
110     private byte sigAttr[];
111     private byte digestAttr[];
112     private int version, signerversion;
113     private Set JavaDoc digestalgos;
114     private Collection JavaDoc certs, crls;
115     private X509Certificate JavaDoc signCert;
116     private byte[] digest;
117     private MessageDigest JavaDoc messageDigest;
118     private String JavaDoc digestAlgorithm, digestEncryptionAlgorithm;
119     private Signature JavaDoc sig;
120     private transient PrivateKey JavaDoc privKey;
121     private byte RSAdata[];
122     private boolean verified;
123     private boolean verifyResult;
124     private byte externalDigest[];
125     private byte externalRSAdata[];
126     
127     private static final String JavaDoc ID_PKCS7_DATA = "1.2.840.113549.1.7.1";
128     private static final String JavaDoc ID_PKCS7_SIGNED_DATA = "1.2.840.113549.1.7.2";
129     private static final String JavaDoc ID_MD5 = "1.2.840.113549.2.5";
130     private static final String JavaDoc ID_MD2 = "1.2.840.113549.2.2";
131     private static final String JavaDoc ID_SHA1 = "1.3.14.3.2.26";
132     private static final String JavaDoc ID_RSA = "1.2.840.113549.1.1.1";
133     private static final String JavaDoc ID_DSA = "1.2.840.10040.4.1";
134     private static final String JavaDoc ID_CONTENT_TYPE = "1.2.840.113549.1.9.3";
135     private static final String JavaDoc ID_MESSAGE_DIGEST = "1.2.840.113549.1.9.4";
136     private static final String JavaDoc ID_SIGNING_TIME = "1.2.840.113549.1.9.5";
137     private static final String JavaDoc ID_MD2RSA = "1.2.840.113549.1.1.2";
138     private static final String JavaDoc ID_MD5RSA = "1.2.840.113549.1.1.4";
139     private static final String JavaDoc ID_SHA1RSA = "1.2.840.113549.1.1.5";
140     private static final String JavaDoc ID_ADBE_REVOCATION = "1.2.840.113583.1.1.8";
141     /**
142      * Holds value of property reason.
143      */

144     private String JavaDoc reason;
145     
146     /**
147      * Holds value of property location.
148      */

149     private String JavaDoc location;
150     
151     /**
152      * Holds value of property signDate.
153      */

154     private Calendar JavaDoc signDate;
155     
156     /**
157      * Holds value of property signName.
158      */

159     private String JavaDoc signName;
160     
161     /**
162      * Verifies a signature using the sub-filter adbe.x509.rsa_sha1.
163      * @param contentsKey the /Contents key
164      * @param certsKey the /Cert key
165      * @param provider the provider or <code>null</code> for the default provider
166      * @throws SecurityException on error
167      * @throws InvalidKeyException on error
168      * @throws CertificateException on error
169      * @throws NoSuchProviderException on error
170      * @throws NoSuchAlgorithmException on error
171      * @throws IOException on error
172      */

173     public PdfPKCS7(byte[] contentsKey, byte[] certsKey, String JavaDoc provider) throws SecurityException JavaDoc, InvalidKeyException JavaDoc, CertificateException JavaDoc, NoSuchProviderException JavaDoc, NoSuchAlgorithmException JavaDoc, IOException JavaDoc, StreamParsingException {
174         X509CertParser cr = new X509CertParser();
175         cr.engineInit(new ByteArrayInputStream JavaDoc(certsKey));
176         certs = cr.engineReadAll();
177         signCert = (X509Certificate JavaDoc)certs.iterator().next();
178         crls = new ArrayList JavaDoc();
179         ASN1InputStream in = new ASN1InputStream(new ByteArrayInputStream JavaDoc(contentsKey));
180         digest = ((DEROctetString)in.readObject()).getOctets();
181         if (provider == null)
182             sig = Signature.getInstance("SHA1withRSA");
183         else
184             sig = Signature.getInstance("SHA1withRSA", provider);
185         sig.initVerify(signCert.getPublicKey());
186     }
187     
188     /**
189      * Verifies a signature using the sub-filter adbe.pkcs7.detached or
190      * adbe.pkcs7.sha1.
191      * @param contentsKey the /Contents key
192      * @param provider the provider or <code>null</code> for the default provider
193      * @throws SecurityException on error
194      * @throws CRLException on error
195      * @throws InvalidKeyException on error
196      * @throws CertificateException on error
197      * @throws NoSuchProviderException on error
198      * @throws NoSuchAlgorithmException on error
199      */

200     public PdfPKCS7(byte[] contentsKey, String JavaDoc provider) throws SecurityException JavaDoc, CRLException JavaDoc, InvalidKeyException JavaDoc, CertificateException JavaDoc, NoSuchProviderException JavaDoc, NoSuchAlgorithmException JavaDoc, StreamParsingException {
201         ASN1InputStream din = new ASN1InputStream(new ByteArrayInputStream JavaDoc(contentsKey));
202         
203         //
204
// Basic checks to make sure it's a PKCS#7 SignedData Object
205
//
206
DERObject pkcs;
207         
208         try {
209             pkcs = din.readObject();
210         }
211         catch (IOException JavaDoc e) {
212             throw new SecurityException JavaDoc("can't decode PKCS7SignedData object");
213         }
214         if (!(pkcs instanceof ASN1Sequence)) {
215             throw new SecurityException JavaDoc("Not a valid PKCS#7 object - not a sequence");
216         }
217         ASN1Sequence signedData = (ASN1Sequence)pkcs;
218         DERObjectIdentifier objId = (DERObjectIdentifier)signedData.getObjectAt(0);
219         if (!objId.getId().equals(ID_PKCS7_SIGNED_DATA))
220             throw new SecurityException JavaDoc("Not a valid PKCS#7 object - not signed data");
221         ASN1Sequence content = (ASN1Sequence)((DERTaggedObject)signedData.getObjectAt(1)).getObject();
222         // the positions that we care are:
223
// 0 - version
224
// 1 - digestAlgorithms
225
// 2 - possible ID_PKCS7_DATA
226
// (the certificates and crls are taken out by other means)
227
// last - signerInfos
228

229         // the version
230
version = ((DERInteger)content.getObjectAt(0)).getValue().intValue();
231         
232         // the digestAlgorithms
233
digestalgos = new HashSet JavaDoc();
234         Enumeration JavaDoc e = ((ASN1Set)content.getObjectAt(1)).getObjects();
235         while (e.hasMoreElements())
236         {
237             ASN1Sequence s = (ASN1Sequence)e.nextElement();
238             DERObjectIdentifier o = (DERObjectIdentifier)s.getObjectAt(0);
239             digestalgos.add(o.getId());
240         }
241         
242         // the certificates and crls
243
X509CertParser cr = new X509CertParser();
244         cr.engineInit(new ByteArrayInputStream JavaDoc(contentsKey));
245         certs = cr.engineReadAll();
246         X509CRLParser cl = new X509CRLParser();
247         cl.engineInit(new ByteArrayInputStream JavaDoc(contentsKey));
248         crls = cl.engineReadAll();
249         
250         // the possible ID_PKCS7_DATA
251
ASN1Sequence rsaData = (ASN1Sequence)content.getObjectAt(2);
252         if (rsaData.size() > 1) {
253             DEROctetString rsaDataContent = (DEROctetString)((DERTaggedObject)rsaData.getObjectAt(1)).getObject();
254             RSAdata = rsaDataContent.getOctets();
255         }
256         
257         // the signerInfos
258
int next = 3;
259         while (content.getObjectAt(next) instanceof DERTaggedObject)
260             ++next;
261         ASN1Set signerInfos = (ASN1Set)content.getObjectAt(next);
262         if (signerInfos.size() != 1)
263             throw new SecurityException JavaDoc("This PKCS#7 object has multiple SignerInfos - only one is supported at this time");
264         ASN1Sequence signerInfo = (ASN1Sequence)signerInfos.getObjectAt(0);
265         // the positions that we care are
266
// 0 - version
267
// 1 - the signing certificate serial number
268
// 2 - the digest algorithm
269
// 3 or 4 - digestEncryptionAlgorithm
270
// 4 or 5 - encryptedDigest
271
signerversion = ((DERInteger)signerInfo.getObjectAt(0)).getValue().intValue();
272         // Get the signing certificate
273
ASN1Sequence issuerAndSerialNumber = (ASN1Sequence)signerInfo.getObjectAt(1);
274         BigInteger JavaDoc serialNumber = ((DERInteger)issuerAndSerialNumber.getObjectAt(1)).getValue();
275         for (Iterator JavaDoc i = certs.iterator(); i.hasNext();) {
276             X509Certificate JavaDoc cert = (X509Certificate JavaDoc)i.next();
277             if (serialNumber.equals(cert.getSerialNumber())) {
278                 signCert = cert;
279                 break;
280             }
281         }
282         if (signCert == null) {
283             throw new SecurityException JavaDoc("Can't find signing certificate with serial " + serialNumber.toString(16));
284         }
285         digestAlgorithm = ((DERObjectIdentifier)((ASN1Sequence)signerInfo.getObjectAt(2)).getObjectAt(0)).getId();
286         next = 3;
287         if (signerInfo.getObjectAt(next) instanceof ASN1TaggedObject) {
288             ASN1TaggedObject tagsig = (ASN1TaggedObject)signerInfo.getObjectAt(next);
289             ASN1Sequence sseq = (ASN1Sequence)tagsig.getObject();
290             ByteArrayOutputStream JavaDoc bOut = new ByteArrayOutputStream JavaDoc();
291             ASN1OutputStream dout = new ASN1OutputStream(bOut);
292             try {
293                 ASN1EncodableVector attribute = new ASN1EncodableVector();
294                 for (int k = 0; k < sseq.size(); ++k) {
295                     attribute.add(sseq.getObjectAt(k));
296                 }
297                 dout.writeObject(new DERSet(attribute));
298                 dout.close();
299             }
300             catch (IOException JavaDoc ioe){}
301             sigAttr = bOut.toByteArray();
302             
303             for (int k = 0; k < sseq.size(); ++k) {
304                 ASN1Sequence seq2 = (ASN1Sequence)sseq.getObjectAt(k);
305                 if (((DERObjectIdentifier)seq2.getObjectAt(0)).getId().equals(ID_MESSAGE_DIGEST)) {
306                     ASN1Set set = (ASN1Set)seq2.getObjectAt(1);
307                     digestAttr = ((DEROctetString)set.getObjectAt(0)).getOctets();
308                     break;
309                 }
310             }
311             if (digestAttr == null)
312                 throw new SecurityException JavaDoc("Authenticated attribute is missing the digest.");
313             ++next;
314         }
315         digestEncryptionAlgorithm = ((DERObjectIdentifier)((ASN1Sequence)signerInfo.getObjectAt(next++)).getObjectAt(0)).getId();
316         digest = ((DEROctetString)signerInfo.getObjectAt(next)).getOctets();
317         if (RSAdata != null || digestAttr != null) {
318             if (provider == null || provider.startsWith("SunPKCS11"))
319                 messageDigest = MessageDigest.getInstance(getHashAlgorithm());
320             else
321                 messageDigest = MessageDigest.getInstance(getHashAlgorithm(), provider);
322         }
323         if (provider == null)
324             sig = Signature.getInstance(getDigestAlgorithm());
325         else
326             sig = Signature.getInstance(getDigestAlgorithm(), provider);
327         sig.initVerify(signCert.getPublicKey());
328     }
329
330     /**
331      * Generates a signature.
332      * @param privKey the private key
333      * @param certChain the certificate chain
334      * @param crlList the certificate revocation list
335      * @param hashAlgorithm the hash algorithm
336      * @param provider the provider or <code>null</code> for the default provider
337      * @param hasRSAdata <CODE>true</CODE> if the sub-filter is adbe.pkcs7.sha1
338      * @throws SecurityException on error
339      * @throws InvalidKeyException on error
340      * @throws NoSuchProviderException on error
341      * @throws NoSuchAlgorithmException on error
342      */

343     public PdfPKCS7(PrivateKey JavaDoc privKey, Certificate JavaDoc[] certChain, CRL JavaDoc[] crlList,
344                     String JavaDoc hashAlgorithm, String JavaDoc provider, boolean hasRSAdata)
345       throws SecurityException JavaDoc, InvalidKeyException JavaDoc, NoSuchProviderException JavaDoc,
346       NoSuchAlgorithmException JavaDoc
347     {
348         this.privKey = privKey;
349         
350         if (hashAlgorithm.equals("MD5")) {
351             digestAlgorithm = ID_MD5;
352         }
353         else if (hashAlgorithm.equals("MD2")) {
354             digestAlgorithm = ID_MD2;
355         }
356         else if (hashAlgorithm.equals("SHA")) {
357             digestAlgorithm = ID_SHA1;
358         }
359         else if (hashAlgorithm.equals("SHA1")) {
360             digestAlgorithm = ID_SHA1;
361         }
362         else {
363             throw new NoSuchAlgorithmException JavaDoc("Unknown Hash Algorithm "+hashAlgorithm);
364         }
365         
366         version = signerversion = 1;
367         certs = new ArrayList JavaDoc();
368         crls = new ArrayList JavaDoc();
369         digestalgos = new HashSet JavaDoc();
370         digestalgos.add(digestAlgorithm);
371         
372         //
373
// Copy in the certificates and crls used to sign the private key.
374
//
375
signCert = (X509Certificate JavaDoc)certChain[0];
376         for (int i = 0;i < certChain.length;i++) {
377             certs.add(certChain[i]);
378         }
379         
380         if (crlList != null) {
381             for (int i = 0;i < crlList.length;i++) {
382                 crls.add(crlList[i]);
383             }
384         }
385         
386         if (privKey != null) {
387             //
388
// Now we have private key, find out what the digestEncryptionAlgorithm is.
389
//
390
digestEncryptionAlgorithm = privKey.getAlgorithm();
391             if (digestEncryptionAlgorithm.equals("RSA")) {
392                 digestEncryptionAlgorithm = ID_RSA;
393             }
394             else if (digestEncryptionAlgorithm.equals("DSA")) {
395                 digestEncryptionAlgorithm = ID_DSA;
396             }
397             else {
398                 throw new NoSuchAlgorithmException JavaDoc("Unknown Key Algorithm "+digestEncryptionAlgorithm);
399             }
400         }
401         if (hasRSAdata) {
402             RSAdata = new byte[0];
403             if (provider == null || provider.startsWith("SunPKCS11"))
404                 messageDigest = MessageDigest.getInstance(getHashAlgorithm());
405             else
406                 messageDigest = MessageDigest.getInstance(getHashAlgorithm(), provider);
407         }
408
409         if (privKey != null) {
410             if (provider == null)
411                 sig = Signature.getInstance(getDigestAlgorithm());
412             else
413                 sig = Signature.getInstance(getDigestAlgorithm(), provider);
414
415             sig.initSign(privKey);
416         }
417     }
418
419     /**
420      * Update the digest with the specified bytes. This method is used both for signing and verifying
421      * @param buf the data buffer
422      * @param off the offset in the data buffer
423      * @param len the data length
424      * @throws SignatureException on error
425      */

426     public void update(byte[] buf, int off, int len) throws SignatureException JavaDoc {
427         if (RSAdata != null || digestAttr != null)
428             messageDigest.update(buf, off, len);
429         else
430             sig.update(buf, off, len);
431     }
432     
433     /**
434      * Verify the digest.
435      * @throws SignatureException on error
436      * @return <CODE>true</CODE> if the signature checks out, <CODE>false</CODE> otherwise
437      */

438     public boolean verify() throws SignatureException JavaDoc {
439         if (verified)
440             return verifyResult;
441         if (sigAttr != null) {
442             sig.update(sigAttr);
443             if (RSAdata != null) {
444                 byte msd[] = messageDigest.digest();
445                 messageDigest.update(msd);
446             }
447             verifyResult = (Arrays.equals(messageDigest.digest(), digestAttr) && sig.verify(digest));
448         }
449         else {
450             if (RSAdata != null)
451                 sig.update(messageDigest.digest());
452             verifyResult = sig.verify(digest);
453         }
454         verified = true;
455         return verifyResult;
456     }
457     
458     /**
459      * Get the X.509 certificates associated with this PKCS#7 object
460      * @return the X.509 certificates associated with this PKCS#7 object
461      */

462     public Certificate JavaDoc[] getCertificates() {
463         return (X509Certificate JavaDoc[])certs.toArray(new X509Certificate JavaDoc[certs.size()]);
464     }
465     
466     /**
467      * Get the X.509 certificate revocation lists associated with this PKCS#7 object
468      * @return the X.509 certificate revocation lists associated with this PKCS#7 object
469      */

470     public Collection JavaDoc getCRLs() {
471         return crls;
472     }
473     
474     /**
475      * Get the X.509 certificate actually used to sign the digest.
476      * @return the X.509 certificate actually used to sign the digest
477      */

478     public X509Certificate JavaDoc getSigningCertificate() {
479         return signCert;
480     }
481     
482     /**
483      * Get the version of the PKCS#7 object. Always 1
484      * @return the version of the PKCS#7 object. Always 1
485      */

486     public int getVersion() {
487         return version;
488     }
489     
490     /**
491      * Get the version of the PKCS#7 "SignerInfo" object. Always 1
492      * @return the version of the PKCS#7 "SignerInfo" object. Always 1
493      */

494     public int getSigningInfoVersion() {
495         return signerversion;
496     }
497     
498     /**
499      * Get the algorithm used to calculate the message digest
500      * @return the algorithm used to calculate the message digest
501      */

502     public String JavaDoc getDigestAlgorithm() {
503         String JavaDoc dea = digestEncryptionAlgorithm;
504         
505         if (digestEncryptionAlgorithm.equals(ID_RSA) || digestEncryptionAlgorithm.equals(ID_MD5RSA)
506             || digestEncryptionAlgorithm.equals(ID_MD2RSA) || digestEncryptionAlgorithm.equals(ID_SHA1RSA)) {
507             dea = "RSA";
508         }
509         else if (digestEncryptionAlgorithm.equals(ID_DSA)) {
510             dea = "DSA";
511         }
512         
513         return getHashAlgorithm() + "with" + dea;
514     }
515
516     /**
517      * Returns the algorithm.
518      * @return the digest algorithm
519      */

520     public String JavaDoc getHashAlgorithm() {
521         String JavaDoc da = digestAlgorithm;
522         
523         if (digestAlgorithm.equals(ID_MD5) || digestAlgorithm.equals(ID_MD5RSA)) {
524             da = "MD5";
525         }
526         else if (digestAlgorithm.equals(ID_MD2) || digestAlgorithm.equals(ID_MD2RSA)) {
527             da = "MD2";
528         }
529         else if (digestAlgorithm.equals(ID_SHA1) || digestAlgorithm.equals(ID_SHA1RSA)) {
530             da = "SHA1";
531         }
532         return da;
533     }
534
535     /**
536      * Loads the default root certificates at &lt;java.home&gt;/lib/security/cacerts
537      * with the default provider.
538      * @return a <CODE>KeyStore</CODE>
539      */

540     public static KeyStore JavaDoc loadCacertsKeyStore() {
541         return loadCacertsKeyStore(null);
542     }
543
544     /**
545      * Loads the default root certificates at &lt;java.home&gt;/lib/security/cacerts.
546      * @param provider the provider or <code>null</code> for the default provider
547      * @return a <CODE>KeyStore</CODE>
548      */

549     public static KeyStore JavaDoc loadCacertsKeyStore(String JavaDoc provider) {
550         File JavaDoc file = new File JavaDoc(System.getProperty("java.home"), "lib");
551         file = new File JavaDoc(file, "security");
552         file = new File JavaDoc(file, "cacerts");
553         FileInputStream JavaDoc fin = null;
554         try {
555             fin = new FileInputStream JavaDoc(file);
556             KeyStore JavaDoc k;
557             if (provider == null)
558                 k = KeyStore.getInstance("JKS");
559             else
560                 k = KeyStore.getInstance("JKS", provider);
561             k.load(fin, null);
562             return k;
563         }
564         catch (Exception JavaDoc e) {
565             throw new ExceptionConverter(e);
566         }
567         finally {
568             try{if (fin != null) {fin.close();}}catch(Exception JavaDoc ex){}
569         }
570     }
571     
572     /**
573      * Verifies a single certificate.
574      * @param cert the certificate to verify
575      * @param crls the certificate revocation list or <CODE>null</CODE>
576      * @param calendar the date or <CODE>null</CODE> for the current date
577      * @return a <CODE>String</CODE> with the error description or <CODE>null</CODE>
578      * if no error
579      */

580     public static String JavaDoc verifyCertificate(X509Certificate JavaDoc cert, Collection JavaDoc crls, Calendar JavaDoc calendar) {
581         if (calendar == null)
582             calendar = new GregorianCalendar JavaDoc();
583         if (cert.hasUnsupportedCriticalExtension())
584             return "Has unsupported critical extension";
585         try {
586             cert.checkValidity(calendar.getTime());
587         }
588         catch (Exception JavaDoc e) {
589             return e.getMessage();
590         }
591         if (crls != null) {
592             for (Iterator JavaDoc it = crls.iterator(); it.hasNext();) {
593                 if (((CRL JavaDoc)it.next()).isRevoked(cert))
594                     return "Certificate revoked";
595             }
596         }
597         return null;
598     }
599     
600     /**
601      * Verifies a certificate chain against a KeyStore.
602      * @param certs the certificate chain
603      * @param keystore the <CODE>KeyStore</CODE>
604      * @param crls the certificate revocation list or <CODE>null</CODE>
605      * @param calendar the date or <CODE>null</CODE> for the current date
606      * @return <CODE>null</CODE> if the certificate chain could be validade or a
607      * <CODE>Object[]{cert,error}</CODE> where <CODE>cert</CODE> is the
608      * failed certificate and <CODE>error</CODE> is the error message
609      */

610     public static Object JavaDoc[] verifyCertificates(Certificate JavaDoc certs[], KeyStore JavaDoc keystore, Collection JavaDoc crls, Calendar JavaDoc calendar) {
611         if (calendar == null)
612             calendar = new GregorianCalendar JavaDoc();
613         for (int k = 0; k < certs.length; ++k) {
614             X509Certificate JavaDoc cert = (X509Certificate JavaDoc)certs[k];
615             String JavaDoc err = verifyCertificate(cert, crls, calendar);
616             if (err != null)
617                 return new Object JavaDoc[]{cert, err};
618             try {
619                 for (Enumeration JavaDoc aliases = keystore.aliases(); aliases.hasMoreElements();) {
620                     try {
621                         String JavaDoc alias = (String JavaDoc)aliases.nextElement();
622                         if (!keystore.isCertificateEntry(alias))
623                             continue;
624                         X509Certificate JavaDoc certStoreX509 = (X509Certificate JavaDoc)keystore.getCertificate(alias);
625                         if (verifyCertificate(certStoreX509, crls, calendar) != null)
626                             continue;
627                         try {
628                             cert.verify(certStoreX509.getPublicKey());
629                             return null;
630                         }
631                         catch (Exception JavaDoc e) {
632                             continue;
633                         }
634                     }
635                     catch (Exception JavaDoc ex) {
636                     }
637                 }
638             }
639             catch (Exception JavaDoc e) {
640             }
641             int j;
642             for (j = 0; j < certs.length; ++j) {
643                 if (j == k)
644                     continue;
645                 X509Certificate JavaDoc certNext = (X509Certificate JavaDoc)certs[j];
646                 try {
647                     cert.verify(certNext.getPublicKey());
648                     break;
649                 }
650                 catch (Exception JavaDoc e) {
651                 }
652             }
653             if (j == certs.length)
654                 return new Object JavaDoc[]{cert, "Cannot be verified against the KeyStore or the certificate chain"};
655         }
656         return new Object JavaDoc[]{null, "Invalid state. Possible circular certificate chain"};
657     }
658
659     /**
660      * Get the "issuer" from the TBSCertificate bytes that are passed in
661      * @param enc a TBSCertificate in a byte array
662      * @return a DERObject
663      */

664     private static DERObject getIssuer(byte[] enc) {
665         try {
666             ASN1InputStream in = new ASN1InputStream(new ByteArrayInputStream JavaDoc(enc));
667             ASN1Sequence seq = (ASN1Sequence)in.readObject();
668             return (DERObject)seq.getObjectAt(seq.getObjectAt(0) instanceof DERTaggedObject ? 3 : 2);
669         }
670         catch (IOException JavaDoc e) {
671             throw new ExceptionConverter(e);
672         }
673     }
674
675     /**
676      * Get the "subject" from the TBSCertificate bytes that are passed in
677      * @param enc A TBSCertificate in a byte array
678      * @return a DERObject
679      */

680     private static DERObject getSubject(byte[] enc) {
681         try {
682             ASN1InputStream in = new ASN1InputStream(new ByteArrayInputStream JavaDoc(enc));
683             ASN1Sequence seq = (ASN1Sequence)in.readObject();
684             return (DERObject)seq.getObjectAt(seq.getObjectAt(0) instanceof DERTaggedObject ? 5 : 4);
685         }
686         catch (IOException JavaDoc e) {
687             throw new ExceptionConverter(e);
688         }
689     }
690
691     /**
692      * Get the issuer fields from an X509 Certificate
693      * @param cert an X509Certificate
694      * @return an X509Name
695      */

696     public static X509Name getIssuerFields(X509Certificate JavaDoc cert) {
697         try {
698             return new X509Name((ASN1Sequence)getIssuer(cert.getTBSCertificate()));
699         }
700         catch (Exception JavaDoc e) {
701             throw new ExceptionConverter(e);
702         }
703     }
704
705     /**
706      * Get the subject fields from an X509 Certificate
707      * @param cert an X509Certificate
708      * @return an X509Name
709      */

710     public static X509Name getSubjectFields(X509Certificate JavaDoc cert) {
711         try {
712             return new X509Name((ASN1Sequence)getSubject(cert.getTBSCertificate()));
713         }
714         catch (Exception JavaDoc e) {
715             throw new ExceptionConverter(e);
716         }
717     }
718     
719     /**
720      * Gets the bytes for the PKCS#1 object.
721      * @return a byte array
722      */

723     public byte[] getEncodedPKCS1() {
724         try {
725             if (externalDigest != null)
726                 digest = externalDigest;
727             else
728                 digest = sig.sign();
729             ByteArrayOutputStream JavaDoc bOut = new ByteArrayOutputStream JavaDoc();
730             
731             ASN1OutputStream dout = new ASN1OutputStream(bOut);
732             dout.writeObject(new DEROctetString(digest));
733             dout.close();
734             
735             return bOut.toByteArray();
736         }
737         catch (Exception JavaDoc e) {
738             throw new ExceptionConverter(e);
739         }
740     }
741     
742     /**
743      * Sets the digest/signature to an external calculated value.
744      * @param digest the digest. This is the actual signature
745      * @param RSAdata the extra data that goes into the data tag in PKCS#7
746      * @param digestEncryptionAlgorithm the encryption algorithm. It may must be <CODE>null</CODE> if the <CODE>digest</CODE>
747      * is also <CODE>null</CODE>. If the <CODE>digest</CODE> is not <CODE>null</CODE>
748      * then it may be "RSA" or "DSA"
749      */

750     public void setExternalDigest(byte digest[], byte RSAdata[], String JavaDoc digestEncryptionAlgorithm) {
751         externalDigest = digest;
752         externalRSAdata = RSAdata;
753         if (digestEncryptionAlgorithm != null) {
754             if (digestEncryptionAlgorithm.equals("RSA")) {
755                 this.digestEncryptionAlgorithm = ID_RSA;
756             }
757             else if (digestEncryptionAlgorithm.equals("DSA")) {
758                 this.digestEncryptionAlgorithm = ID_DSA;
759             }
760             else
761                 throw new ExceptionConverter(new NoSuchAlgorithmException JavaDoc("Unknown Key Algorithm "+digestEncryptionAlgorithm));
762         }
763     }
764     
765     /**
766      * Gets the bytes for the PKCS7SignedData object.
767      * @return the bytes for the PKCS7SignedData object
768      */

769     public byte[] getEncodedPKCS7() {
770         return getEncodedPKCS7(null, null);
771     }
772     
773     /**
774      * Gets the bytes for the PKCS7SignedData object. Optionally the authenticatedAttributes
775      * in the signerInfo can also be set. If either of the parameters is <CODE>null</CODE>, none will be used.
776      * @param secondDigest the digest in the authenticatedAttributes
777      * @param signingTime the signing time in the authenticatedAttributes
778      * @return the bytes for the PKCS7SignedData object
779      */

780     public byte[] getEncodedPKCS7(byte secondDigest[], Calendar JavaDoc signingTime) {
781         try {
782             if (externalDigest != null) {
783                 digest = externalDigest;
784                 if (RSAdata != null)
785                     RSAdata = externalRSAdata;
786             }
787             else if (externalRSAdata != null && RSAdata != null) {
788                 RSAdata = externalRSAdata;
789                 sig.update(RSAdata);
790                 digest = sig.sign();
791             }
792             else {
793                 if (RSAdata != null) {
794                     RSAdata = messageDigest.digest();
795                     sig.update(RSAdata);
796                 }
797                 digest = sig.sign();
798             }
799             
800             // Create the set of Hash algorithms
801
DERConstructedSet digestAlgorithms = new DERConstructedSet();
802             for(Iterator JavaDoc it = digestalgos.iterator(); it.hasNext();) {
803                 ASN1EncodableVector algos = new ASN1EncodableVector();
804                 algos.add(new DERObjectIdentifier((String JavaDoc)it.next()));
805                 algos.add(new DERNull());
806                 digestAlgorithms.addObject(new DERSequence(algos));
807             }
808             
809             // Create the contentInfo.
810
ASN1EncodableVector v = new ASN1EncodableVector();
811             v.add(new DERObjectIdentifier(ID_PKCS7_DATA));
812             if (RSAdata != null)
813                 v.add(new DERTaggedObject(0, new DEROctetString(RSAdata)));
814             DERSequence contentinfo = new DERSequence(v);
815             
816             // Get all the certificates
817
//
818
v = new ASN1EncodableVector();
819             for (Iterator JavaDoc i = certs.iterator(); i.hasNext();) {
820                 ASN1InputStream tempstream = new ASN1InputStream(new ByteArrayInputStream JavaDoc(((X509Certificate JavaDoc)i.next()).getEncoded()));
821                 v.add(tempstream.readObject());
822             }
823             
824             DERSet dercertificates = new DERSet(v);
825             
826             // Create signerinfo structure.
827
//
828
ASN1EncodableVector signerinfo = new ASN1EncodableVector();
829             
830             // Add the signerInfo version
831
//
832
signerinfo.add(new DERInteger(signerversion));
833             
834             v = new ASN1EncodableVector();
835             v.add(getIssuer(signCert.getTBSCertificate()));
836             v.add(new DERInteger(signCert.getSerialNumber()));
837             signerinfo.add(new DERSequence(v));
838             
839             // Add the digestAlgorithm
840
v = new ASN1EncodableVector();
841             v.add(new DERObjectIdentifier(digestAlgorithm));
842             v.add(new DERNull());
843             signerinfo.add(new DERSequence(v));
844             
845             // add the authenticated attribute if present
846
if (secondDigest != null && signingTime != null) {
847                 ASN1EncodableVector attribute = new ASN1EncodableVector();
848                 v = new ASN1EncodableVector();
849                 v.add(new DERObjectIdentifier(ID_CONTENT_TYPE));
850                 v.add(new DERSet(new DERObjectIdentifier(ID_PKCS7_DATA)));
851                 attribute.add(new DERSequence(v));
852                 v = new ASN1EncodableVector();
853                 v.add(new DERObjectIdentifier(ID_SIGNING_TIME));
854                 v.add(new DERSet(new DERUTCTime(signingTime.getTime())));
855                 attribute.add(new DERSequence(v));
856                 v = new ASN1EncodableVector();
857                 v.add(new DERObjectIdentifier(ID_MESSAGE_DIGEST));
858                 v.add(new DERSet(new DEROctetString(secondDigest)));
859                 attribute.add(new DERSequence(v));
860                 if (!crls.isEmpty()) {
861                     v = new ASN1EncodableVector();
862                     v.add(new DERObjectIdentifier(ID_ADBE_REVOCATION));
863                     ASN1EncodableVector v2 = new ASN1EncodableVector();
864                     for (Iterator JavaDoc i = crls.iterator();i.hasNext();) {
865                         ASN1InputStream t = new ASN1InputStream(new ByteArrayInputStream JavaDoc((((X509CRL JavaDoc)i.next()).getEncoded())));
866                         v2.add(t.readObject());
867                     }
868                     v.add(new DERSet(new DERSequence(new DERTaggedObject(true, 0, new DERSequence(v2)))));
869                     attribute.add(new DERSequence(v));
870                 }
871                 signerinfo.add(new DERTaggedObject(false, 0, new DERSet(attribute)));
872             }
873             // Add the digestEncryptionAlgorithm
874
v = new ASN1EncodableVector();
875             v.add(new DERObjectIdentifier(digestEncryptionAlgorithm));
876             v.add(new DERNull());
877             signerinfo.add(new DERSequence(v));
878             
879             // Add the digest
880
signerinfo.add(new DEROctetString(digest));
881             
882             
883             // Finally build the body out of all the components above
884
ASN1EncodableVector body = new ASN1EncodableVector();
885             body.add(new DERInteger(version));
886             body.add(digestAlgorithms);
887             body.add(contentinfo);
888             body.add(new DERTaggedObject(false, 0, dercertificates));
889             
890             if (!crls.isEmpty()) {
891                 v = new ASN1EncodableVector();
892                 for (Iterator JavaDoc i = crls.iterator();i.hasNext();) {
893                     ASN1InputStream t = new ASN1InputStream(new ByteArrayInputStream JavaDoc((((X509CRL JavaDoc)i.next()).getEncoded())));
894                     v.add(t.readObject());
895                 }
896                 DERSet dercrls = new DERSet(v);
897                 body.add(new DERTaggedObject(false, 1, dercrls));
898             }
899             
900             // Only allow one signerInfo
901
body.add(new DERSet(new DERSequence(signerinfo)));
902             
903             // Now we have the body, wrap it in it's PKCS7Signed shell
904
// and return it
905
//
906
ASN1EncodableVector whole = new ASN1EncodableVector();
907             whole.add(new DERObjectIdentifier(ID_PKCS7_SIGNED_DATA));
908             whole.add(new DERTaggedObject(0, new DERSequence(body)));
909             
910             ByteArrayOutputStream JavaDoc bOut = new ByteArrayOutputStream JavaDoc();
911             
912             ASN1OutputStream dout = new ASN1OutputStream(bOut);
913             dout.writeObject(new DERSequence(whole));
914             dout.close();
915             
916             return bOut.toByteArray();
917         }
918         catch (Exception JavaDoc e) {
919             throw new ExceptionConverter(e);
920         }
921     }
922     
923     
924     /**
925      * When using authenticatedAttributes the authentication process is different.
926      * The document digest is generated and put inside the attribute. The signing is done over the DER encoded
927      * authenticatedAttributes. This method provides that encoding and the parameters must be
928      * exactly the same as in {@link #getEncodedPKCS7(byte[],Calendar)}.
929      * <p>
930      * A simple example:
931      * <p>
932      * <pre>
933      * Calendar cal = Calendar.getInstance();
934      * PdfPKCS7 pk7 = new PdfPKCS7(key, chain, null, "SHA1", null, false);
935      * MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
936      * byte buf[] = new byte[8192];
937      * int n;
938      * InputStream inp = sap.getRangeStream();
939      * while ((n = inp.read(buf)) &gt; 0) {
940      * messageDigest.update(buf, 0, n);
941      * }
942      * byte hash[] = messageDigest.digest();
943      * byte sh[] = pk7.getAuthenticatedAttributeBytes(hash, cal);
944      * pk7.update(sh, 0, sh.length);
945      * byte sg[] = pk7.getEncodedPKCS7(hash, cal);
946      * </pre>
947      * @param secondDigest the content digest
948      * @param signingTime the signing time
949      * @return the byte array representation of the authenticatedAttributes ready to be signed
950      */

951     public byte[] getAuthenticatedAttributeBytes(byte secondDigest[], Calendar JavaDoc signingTime) {
952         try {
953             ASN1EncodableVector attribute = new ASN1EncodableVector();
954             ASN1EncodableVector v = new ASN1EncodableVector();
955             v.add(new DERObjectIdentifier(ID_CONTENT_TYPE));
956             v.add(new DERSet(new DERObjectIdentifier(ID_PKCS7_DATA)));
957             attribute.add(new DERSequence(v));
958             v = new ASN1EncodableVector();
959             v.add(new DERObjectIdentifier(ID_SIGNING_TIME));
960             v.add(new DERSet(new DERUTCTime(signingTime.getTime())));
961             attribute.add(new DERSequence(v));
962             v = new ASN1EncodableVector();
963             v.add(new DERObjectIdentifier(ID_MESSAGE_DIGEST));
964             v.add(new DERSet(new DEROctetString(secondDigest)));
965             attribute.add(new DERSequence(v));
966             if (!crls.isEmpty()) {
967                 v = new ASN1EncodableVector();
968                 v.add(new DERObjectIdentifier(ID_ADBE_REVOCATION));
969                 ASN1EncodableVector v2 = new ASN1EncodableVector();
970                 for (Iterator JavaDoc i = crls.iterator();i.hasNext();) {
971                     ASN1InputStream t = new ASN1InputStream(new ByteArrayInputStream JavaDoc((((X509CRL JavaDoc)i.next()).getEncoded())));
972                     v2.add(t.readObject());
973                 }
974                 v.add(new DERSet(new DERSequence(new DERTaggedObject(true, 0, new DERSequence(v2)))));
975                 attribute.add(new DERSequence(v));
976             }
977             ByteArrayOutputStream JavaDoc bOut = new ByteArrayOutputStream JavaDoc();
978             
979             ASN1OutputStream dout = new ASN1OutputStream(bOut);
980             dout.writeObject(new DERSet(attribute));
981             dout.close();
982             
983             return bOut.toByteArray();
984         }
985         catch (Exception JavaDoc e) {
986             throw new ExceptionConverter(e);
987         }
988     }
989     /**
990      * Getter for property reason.
991      * @return Value of property reason.
992      */

993     public String JavaDoc getReason() {
994         return this.reason;
995     }
996     
997     /**
998      * Setter for property reason.
999      * @param reason New value of property reason.
1000     */

1001    public void setReason(String JavaDoc reason) {
1002        this.reason = reason;
1003    }
1004    
1005    /**
1006     * Getter for property location.
1007     * @return Value of property location.
1008     */

1009    public String JavaDoc getLocation() {
1010        return this.location;
1011    }
1012    
1013    /**
1014     * Setter for property location.
1015     * @param location New value of property location.
1016     */

1017    public void setLocation(String JavaDoc location) {
1018        this.location = location;
1019    }
1020    
1021    /**
1022     * Getter for property signDate.
1023     * @return Value of property signDate.
1024     */

1025    public Calendar JavaDoc getSignDate() {
1026        return this.signDate;
1027    }
1028    
1029    /**
1030     * Setter for property signDate.
1031     * @param signDate New value of property signDate.
1032     */

1033    public void setSignDate(Calendar JavaDoc signDate) {
1034        this.signDate = signDate;
1035    }
1036    
1037    /**
1038     * Getter for property sigName.
1039     * @return Value of property sigName.
1040     */

1041    public String JavaDoc getSignName() {
1042        return this.signName;
1043    }
1044    
1045    /**
1046     * Setter for property sigName.
1047     * @param signName New value of property sigName.
1048     */

1049    public void setSignName(String JavaDoc signName) {
1050        this.signName = signName;
1051    }
1052    
1053    /**
1054     * a class that holds an X509 name
1055     */

1056    public static class X509Name {
1057        /**
1058         * country code - StringType(SIZE(2))
1059         */

1060        public static final DERObjectIdentifier C = new DERObjectIdentifier("2.5.4.6");
1061
1062        /**
1063         * organization - StringType(SIZE(1..64))
1064         */

1065        public static final DERObjectIdentifier O = new DERObjectIdentifier("2.5.4.10");
1066
1067        /**
1068         * organizational unit name - StringType(SIZE(1..64))
1069         */

1070        public static final DERObjectIdentifier OU = new DERObjectIdentifier("2.5.4.11");
1071
1072        /**
1073         * Title
1074         */

1075        public static final DERObjectIdentifier T = new DERObjectIdentifier("2.5.4.12");
1076
1077        /**
1078         * common name - StringType(SIZE(1..64))
1079         */

1080        public static final DERObjectIdentifier CN = new DERObjectIdentifier("2.5.4.3");
1081
1082        /**
1083         * device serial number name - StringType(SIZE(1..64))
1084         */

1085        public static final DERObjectIdentifier SN = new DERObjectIdentifier("2.5.4.5");
1086
1087        /**
1088         * locality name - StringType(SIZE(1..64))
1089         */

1090        public static final DERObjectIdentifier L = new DERObjectIdentifier("2.5.4.7");
1091
1092        /**
1093         * state, or province name - StringType(SIZE(1..64))
1094         */

1095        public static final DERObjectIdentifier ST = new DERObjectIdentifier("2.5.4.8");
1096
1097        /** Naming attribute of type X520name */
1098        public static final DERObjectIdentifier SURNAME = new DERObjectIdentifier("2.5.4.4");
1099        /** Naming attribute of type X520name */
1100        public static final DERObjectIdentifier GIVENNAME = new DERObjectIdentifier("2.5.4.42");
1101        /** Naming attribute of type X520name */
1102        public static final DERObjectIdentifier INITIALS = new DERObjectIdentifier("2.5.4.43");
1103        /** Naming attribute of type X520name */
1104        public static final DERObjectIdentifier GENERATION = new DERObjectIdentifier("2.5.4.44");
1105        /** Naming attribute of type X520name */
1106        public static final DERObjectIdentifier UNIQUE_IDENTIFIER = new DERObjectIdentifier("2.5.4.45");
1107
1108        /**
1109         * Email address (RSA PKCS#9 extension) - IA5String.
1110         * <p>Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.
1111         */

1112        public static final DERObjectIdentifier EmailAddress = new DERObjectIdentifier("1.2.840.113549.1.9.1");
1113
1114        /**
1115         * email address in Verisign certificates
1116         */

1117        public static final DERObjectIdentifier E = EmailAddress;
1118
1119        /** object identifier */
1120        public static final DERObjectIdentifier DC = new DERObjectIdentifier("0.9.2342.19200300.100.1.25");
1121
1122        /** LDAP User id. */
1123        public static final DERObjectIdentifier UID = new DERObjectIdentifier("0.9.2342.19200300.100.1.1");
1124
1125        /** A HashMap with default symbols */
1126        public static HashMap JavaDoc DefaultSymbols = new HashMap JavaDoc();
1127        
1128        static {
1129            DefaultSymbols.put(C, "C");
1130            DefaultSymbols.put(O, "O");
1131            DefaultSymbols.put(T, "T");
1132            DefaultSymbols.put(OU, "OU");
1133            DefaultSymbols.put(CN, "CN");
1134            DefaultSymbols.put(L, "L");
1135            DefaultSymbols.put(ST, "ST");
1136            DefaultSymbols.put(SN, "SN");
1137            DefaultSymbols.put(EmailAddress, "E");
1138            DefaultSymbols.put(DC, "DC");
1139            DefaultSymbols.put(UID, "UID");
1140            DefaultSymbols.put(SURNAME, "SURNAME");
1141            DefaultSymbols.put(GIVENNAME, "GIVENNAME");
1142            DefaultSymbols.put(INITIALS, "INITIALS");
1143            DefaultSymbols.put(GENERATION, "GENERATION");
1144        }
1145        /** A HashMap with values */
1146        public HashMap JavaDoc values = new HashMap JavaDoc();
1147
1148        /**
1149         * Constructs an X509 name
1150         * @param seq an ASN1 Sequence
1151         */

1152        public X509Name(ASN1Sequence seq) {
1153            Enumeration JavaDoc e = seq.getObjects();
1154            
1155            while (e.hasMoreElements()) {
1156                ASN1Set set = (ASN1Set)e.nextElement();
1157                
1158                for (int i = 0; i < set.size(); i++) {
1159                    ASN1Sequence s = (ASN1Sequence)set.getObjectAt(i);
1160                    String JavaDoc id = (String JavaDoc)DefaultSymbols.get(s.getObjectAt(0));
1161                    if (id == null)
1162                        continue;
1163                    ArrayList JavaDoc vs = (ArrayList JavaDoc)values.get(id);
1164                    if (vs == null) {
1165                        vs = new ArrayList JavaDoc();
1166                        values.put(id, vs);
1167                    }
1168                    vs.add(((DERString)s.getObjectAt(1)).getString());
1169                }
1170            }
1171        }
1172        /**
1173         * Constructs an X509 name
1174         * @param dirName a directory name
1175         */

1176        public X509Name(String JavaDoc dirName) {
1177            X509NameTokenizer nTok = new X509NameTokenizer(dirName);
1178            
1179            while (nTok.hasMoreTokens()) {
1180                String JavaDoc token = nTok.nextToken();
1181                int index = token.indexOf('=');
1182                
1183                if (index == -1) {
1184                    throw new IllegalArgumentException JavaDoc("badly formated directory string");
1185                }
1186                
1187                String JavaDoc id = token.substring(0, index).toUpperCase();
1188                String JavaDoc value = token.substring(index + 1);
1189                ArrayList JavaDoc vs = (ArrayList JavaDoc)values.get(id);
1190                if (vs == null) {
1191                    vs = new ArrayList JavaDoc();
1192                    values.put(id, vs);
1193                }
1194                vs.add(value);
1195            }
1196            
1197        }
1198        
1199        public String JavaDoc getField(String JavaDoc name) {
1200            ArrayList JavaDoc vs = (ArrayList JavaDoc)values.get(name);
1201            return vs == null ? null : (String JavaDoc)vs.get(0);
1202        }
1203
1204        /**
1205         * gets a field array from the values Hashmap
1206         * @param name
1207         * @return an ArrayList
1208         */

1209        public ArrayList JavaDoc getFieldArray(String JavaDoc name) {
1210            ArrayList JavaDoc vs = (ArrayList JavaDoc)values.get(name);
1211            return vs == null ? null : vs;
1212        }
1213        
1214        /**
1215         * getter for values
1216         * @return a HashMap with the fields of the X509 name
1217         */

1218        public HashMap JavaDoc getFields() {
1219            return values;
1220        }
1221        
1222        /**
1223         * @see java.lang.Object#toString()
1224         */

1225        public String JavaDoc toString() {
1226            return values.toString();
1227        }
1228    }
1229    
1230    /**
1231     * class for breaking up an X500 Name into it's component tokens, ala
1232     * java.util.StringTokenizer. We need this class as some of the
1233     * lightweight Java environment don't support classes like
1234     * StringTokenizer.
1235     */

1236    public static class X509NameTokenizer {
1237        private String JavaDoc oid;
1238        private int index;
1239        private StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
1240        
1241        public X509NameTokenizer(
1242        String JavaDoc oid) {
1243            this.oid = oid;
1244            this.index = -1;
1245        }
1246        
1247        public boolean hasMoreTokens() {
1248            return (index != oid.length());
1249        }
1250        
1251        public String JavaDoc nextToken() {
1252            if (index == oid.length()) {
1253                return null;
1254            }
1255            
1256            int end = index + 1;
1257            boolean quoted = false;
1258            boolean escaped = false;
1259            
1260            buf.setLength(0);
1261            
1262            while (end != oid.length()) {
1263                char c = oid.charAt(end);
1264                
1265                if (c == '"') {
1266                    if (!escaped) {
1267                        quoted = !quoted;
1268                    }
1269                    else {
1270                        buf.append(c);
1271                    }
1272                    escaped = false;
1273                }
1274                else {
1275                    if (escaped || quoted) {
1276                        buf.append(c);
1277                        escaped = false;
1278                    }
1279                    else if (c == '\\') {
1280                        escaped = true;
1281                    }
1282                    else if (c == ',') {
1283                        break;
1284                    }
1285                    else {
1286                        buf.append(c);
1287                    }
1288                }
1289                end++;
1290            }
1291            
1292            index = end;
1293            return buf.toString().trim();
1294        }
1295    }
1296}
1297
Popular Tags