View Javadoc

1   package org.eparapher.core.crypto.cert;
2   
3   import java.io.BufferedReader;
4   import java.io.ByteArrayInputStream;
5   import java.io.ByteArrayOutputStream;
6   import java.io.DataOutputStream;
7   import java.io.File;
8   import java.io.FileInputStream;
9   import java.io.FileWriter;
10  import java.io.IOException;
11  import java.io.InputStream;
12  import java.io.InputStreamReader;
13  import java.io.PrintStream;
14  import java.security.NoSuchProviderException;
15  import java.security.cert.CertPath;
16  import java.security.cert.Certificate;
17  import java.security.cert.CertificateEncodingException;
18  import java.security.cert.CertificateException;
19  import java.security.cert.CertificateFactory;
20  import java.security.cert.CertificateParsingException;
21  import java.security.cert.X509CRL;
22  import java.security.cert.X509Certificate;
23  import java.util.ArrayList;
24  import java.util.Collection;
25  import java.util.Enumeration;
26  import java.util.HashSet;
27  import java.util.Hashtable;
28  import java.util.Iterator;
29  import java.util.List;
30  import java.util.Set;
31  
32  import org.apache.log4j.Logger;
33  import org.bouncycastle.asn1.ASN1InputStream;
34  import org.bouncycastle.asn1.ASN1OctetString;
35  import org.bouncycastle.asn1.ASN1Sequence;
36  import org.bouncycastle.asn1.ASN1TaggedObject;
37  import org.bouncycastle.asn1.DEREncodable;
38  import org.bouncycastle.asn1.DERInteger;
39  import org.bouncycastle.asn1.DERNull;
40  import org.bouncycastle.asn1.DERObject;
41  import org.bouncycastle.asn1.DERObjectIdentifier;
42  import org.bouncycastle.asn1.DERTaggedObject;
43  import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
44  import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
45  import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
46  import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
47  import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
48  import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
49  import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
50  import org.bouncycastle.asn1.x509.CRLDistPoint;
51  import org.bouncycastle.asn1.x509.DistributionPoint;
52  import org.bouncycastle.asn1.x509.X509Extensions;
53  import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
54  import org.bouncycastle.cms.CMSException;
55  import org.bouncycastle.cms.CMSSignedData;
56  import org.bouncycastle.jce.ECNamedCurveTable;
57  import org.bouncycastle.jce.PKCS10CertificationRequest;
58  import org.bouncycastle.jce.provider.X509CertificateObject;
59  import org.bouncycastle.util.Strings;
60  import org.bouncycastle.util.encoders.Base64;
61  import org.bouncycastle.x509.NoSuchStoreException;
62  import org.bouncycastle.x509.X509CertStoreSelector;
63  import org.bouncycastle.x509.X509Store;
64  import org.eparapher.core.EParapherManager;
65  import org.eparapher.core.tools.FileUtil;
66  
67  
68  public class X509Util {
69  	
70  	private static Logger log = Logger.getLogger(X509Util.class);
71  	
72      private static Hashtable algorithms = new Hashtable();
73      private static Hashtable params     = new Hashtable();
74      private static Set       noParams  = new HashSet();
75      
76      private static final String X509_CERT_TYPE = "X.509";
77      private static final String PKCS7_ENCODING = "PKCS7";
78      public  static final String BEGIN_CERT     = "-----BEGIN CERTIFICATE-----";
79      public  static final String END_CERT       = "-----END CERTIFICATE-----";
80      public  static final int    CERT_LINE_LENGTH = 64;
81      public  static final String BEGIN_CERT_REQ = "-----BEGIN CERTIFICATE REQUEST-----";
82      public  static final String END_CERT_REQ   = "-----END CERTIFICATE REQUEST-----";
83      public  static final int    CERT_REQ_LINE_LENGTH = 76;
84  
85      static
86      {   
87          algorithms.put("MD2WITHRSAENCRYPTION", PKCSObjectIdentifiers.md2WithRSAEncryption);
88          algorithms.put("MD2WITHRSA", PKCSObjectIdentifiers.md2WithRSAEncryption);
89          algorithms.put("MD5WITHRSAENCRYPTION", PKCSObjectIdentifiers.md5WithRSAEncryption);
90          algorithms.put("MD5WITHRSA", PKCSObjectIdentifiers.md5WithRSAEncryption);
91          algorithms.put("SHA1WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha1WithRSAEncryption);
92          algorithms.put("SHA1WITHRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption);
93          algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
94          algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
95          algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
96          algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
97          algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
98          algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
99          algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
100         algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
101         algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
102         algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
103         algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
104         algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
105         algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
106         algorithms.put("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
107         algorithms.put("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
108         algorithms.put("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
109         algorithms.put("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
110         algorithms.put("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
111         algorithms.put("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
112         algorithms.put("SHA1WITHDSA", X9ObjectIdentifiers.id_dsa_with_sha1);
113         algorithms.put("DSAWITHSHA1", X9ObjectIdentifiers.id_dsa_with_sha1);
114         algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
115         algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
116         algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
117         algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
118         algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
119         algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
120         algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
121         algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
122         algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
123         algorithms.put("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
124         algorithms.put("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
125         algorithms.put("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
126         algorithms.put("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
127 
128         //
129         // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field. 
130         // The parameters field SHALL be NULL for RSA based signature algorithms.
131         //
132         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
133         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
134         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
135         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
136         noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
137         noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
138         noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
139         noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
140 
141         //
142         // RFC 4491
143         //
144         noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
145         noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
146 
147         //
148         // explicit params
149         //
150         AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, new DERNull());
151         params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20));
152 
153         AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, new DERNull());
154         params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
155 
156         AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, new DERNull());
157         params.put("SHA256WITHRSAANDMGF1", creatPSSParams(sha256AlgId, 32));
158 
159         AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, new DERNull());
160         params.put("SHA384WITHRSAANDMGF1", creatPSSParams(sha384AlgId, 48));
161 
162         AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512, new DERNull());
163         params.put("SHA512WITHRSAANDMGF1", creatPSSParams(sha512AlgId, 64));
164     }
165 
166     private static RSASSAPSSparams creatPSSParams(AlgorithmIdentifier hashAlgId, int saltSize)
167     {
168         return new RSASSAPSSparams(
169             hashAlgId,
170             new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId),
171             new DERInteger(saltSize),
172             new DERInteger(1));
173     }
174 
175     static DERObjectIdentifier getAlgorithmOID(String algorithmName)
176     {
177         algorithmName = Strings.toUpperCase(algorithmName);
178         
179         if (algorithms.containsKey(algorithmName))
180         {
181             return (DERObjectIdentifier)algorithms.get(algorithmName);
182         }
183         
184         return new DERObjectIdentifier(algorithmName);
185     }
186     
187     static AlgorithmIdentifier getSigAlgID( DERObjectIdentifier sigOid, String algorithmName)
188     {
189         if (noParams.contains(sigOid))
190         {
191             return new AlgorithmIdentifier(sigOid);
192         }
193 
194         algorithmName = Strings.toUpperCase(algorithmName);
195 
196         if (params.containsKey(algorithmName))
197         {
198             return new AlgorithmIdentifier(sigOid, (DEREncodable)params.get(algorithmName));
199         }
200         else
201         {
202             return new AlgorithmIdentifier(sigOid, new DERNull());
203         }
204     }
205     
206     public static Iterator<String> getAlgNames()
207     {
208         Enumeration<String> e = algorithms.keys();
209         List<String>        l = new ArrayList<String>();
210         
211         while (e.hasMoreElements())
212         {
213             l.add(e.nextElement());
214         }
215         
216         return l.iterator();
217     }
218     public static String[] getECSpecsNames()
219     {
220     	
221         Enumeration		e = ECNamedCurveTable.getNames();
222         List<String>	l = new ArrayList<String>();
223         
224         while (e.hasMoreElements())
225             l.add((String) e.nextElement());
226         
227         return l.toArray(new String[] {});
228     }
229 /*
230     static Signature getSignatureInstance(
231         String algorithm)
232         throws NoSuchAlgorithmException
233     {
234         return Signature.getInstance(algorithm);
235     }
236 
237     static Signature getSignatureInstance(
238         String algorithm,
239         String provider)
240         throws NoSuchProviderException, NoSuchAlgorithmException
241     {
242         if (provider != null)
243         {
244             return Signature.getInstance(algorithm, provider);
245         }
246         else
247         {
248             return Signature.getInstance(algorithm);
249         }
250     }*/
251 /*
252     static byte[] calculateSignature(
253         DERObjectIdentifier sigOid,
254         String              sigName,
255         PrivateKey          key,
256         SecureRandom        random,
257         ASN1Encodable       object)
258         throws IOException, NoSuchAlgorithmException, InvalidKeyException, SignatureException
259     {
260         Signature sig;
261 
262         if (sigOid == null)
263         {
264             throw new IllegalStateException("no signature algorithm specified");
265         }
266 
267         sig = X509Util.getSignatureInstance(sigName);
268 
269         if (random != null)
270         {
271             sig.initSign(key, random);
272         }
273         else
274         {
275             sig.initSign(key);
276         }
277 
278         sig.update(object.getEncoded(ASN1Encodable.DER));
279 
280         return sig.sign();
281     }*/
282 /*
283     static byte[] calculateSignature(
284         DERObjectIdentifier sigOid,
285         String              sigName,
286         String              provider,
287         PrivateKey          key,
288         SecureRandom        random,
289         ASN1Encodable       object)
290         throws IOException, NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException, SignatureException
291     {
292         Signature sig;
293 
294         if (sigOid == null)
295         {
296             throw new IllegalStateException("no signature algorithm specified");
297         }
298 
299         sig = X509Util.getSignatureInstance(sigName, provider);
300 
301         if (random != null)
302         {
303             sig.initSign(key, random);
304         }
305         else
306         {
307             sig.initSign(key);
308         }
309 
310         sig.update(object.getEncoded(ASN1Encodable.DER));
311 
312         return sig.sign();
313     }
314 */
315     /*
316     static X509Principal convertPrincipal(
317         X500Principal principal)
318     {
319         try
320         {
321             return new X509Principal(principal.getEncoded());
322         }
323         catch (IOException e)
324         {
325             throw new IllegalArgumentException("cannot convert principal");
326         }
327     }
328 */	
329 
330     /**
331      * Return an Extension DERObject from a certificate
332      */
333     public static DERObject getExtensionValue(X509Certificate cert, String oid)
334       throws IOException {
335         byte[] bytes = cert.getExtensionValue(oid);
336         if (bytes == null) {
337             return null;
338         }
339         ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(bytes));
340         ASN1OctetString octs = (ASN1OctetString) aIn.readObject();
341         aIn = new ASN1InputStream(new ByteArrayInputStream(octs.getOctets()));
342         return aIn.readObject();
343     } //getExtensionValue
344     
345     private static String getStringFromGeneralNames(DERObject names) {
346             ASN1Sequence namesSequence = ASN1Sequence.getInstance((ASN1TaggedObject)names, false);
347             if (namesSequence.size() == 0) {
348                 return null;
349             }
350             DERTaggedObject taggedObject = (DERTaggedObject)namesSequence.getObjectAt(0);
351             return new String(ASN1OctetString.getInstance(taggedObject, false).getOctets());
352     }
353     
354 	/**
355      * Return the CRL distribution point URL form a certificate.
356      */
357     public static DistributionPoint[] getCrlDistributionPoint(X509Certificate certificate)
358       throws CertificateParsingException {
359         try {
360             DERObject obj = getExtensionValue(certificate, X509Extensions.CRLDistributionPoints.getId());
361             if (obj != null) {
362                 CRLDistPoint crldp = new CRLDistPoint((ASN1Sequence) obj);
363                 DistributionPoint[] alldp = crldp.getDistributionPoints();
364                 return alldp;
365             }
366         }
367         catch (Exception e) {
368             log.error("Error parsing CrlDistributionPoint", e);
369             throw new CertificateParsingException(e.toString());
370         }
371 		return null;
372     }
373     
374     
375     
376 	public static X509Certificate[] convertCertChaintoX509( Certificate[] certChain) {
377 		if (certChain==null)
378 			return null;
379 		X509Certificate[] tempX509CertificateChain = new X509Certificate[certChain.length];
380 		for (int i = 0; i < certChain.length; i++) {
381 			if ( certChain[i] instanceof X509Certificate)
382 				tempX509CertificateChain[i] = (X509Certificate) certChain[i];
383 		}
384 		return tempX509CertificateChain;
385 	}
386 	
387 	/**
388 	 * Return Certificate Base 64 Encoded (PEM format)
389 	 * @param cert
390 	 * @return
391 	 */
392     public static String getCertBase64Encoded(X509Certificate cert) {
393     	try {
394 	        String sTmp = new String(Base64.encode(cert.getEncoded()));
395 	        String sEncoded = BEGIN_CERT + "\r\n";
396 	        for(int iCnt = 0; iCnt < sTmp.length(); iCnt += 64)
397 	        {
398 	            int iLineLength;
399 	            if(iCnt + 64 > sTmp.length())
400 	                iLineLength = sTmp.length() - iCnt;
401 	            else
402 	                iLineLength = 64;
403 	            sEncoded = sEncoded + sTmp.substring(iCnt, iCnt + iLineLength) + "\r\n";
404 	        }
405 	
406 	        sEncoded = sEncoded + END_CERT + "\r\n";
407 	        return sEncoded;
408 	    } catch(CertificateException e) {
409 			log.debug(""+e.getLocalizedMessage(),e);
410 	    }
411 	    return null;
412     }
413 
414     /**
415      * Save a X509 Certificate to a file, in Base64 format
416      * 
417      * @param filename The file that will  certificate
418      * @param cert Certificate to save
419      * @return
420      */
421     public static boolean saveX509toFile(String filename, X509Certificate cert) {
422         if (filename==null || filename.equals("")) {
423         	log.warn("Bad filename to save certificate");
424         	return false;
425         }
426         if ((new File(filename)).exists())
427         	if ( !EParapherManager.getInstance().getUI().askUserYesNo( filename+ "already exists.\r\nOverwrite it?") ) {
428         		log.warn("not overwriting " + filename);
429         		return false;
430         	}
431 
432         FileWriter output;
433 		try {
434 			output = new FileWriter(filename, false);
435 	        output.write(getCertBase64Encoded(cert));
436 	        output.flush();
437 	        output.close();
438 	        return true;
439 		} catch (IOException e) {
440 			String msg = "Error writing certificate to " + filename + " : " + e.getMessage();
441 			EParapherManager.getInstance().getUI().errorMessage(msg,e);
442 			log.error(msg, e);
443 		}
444 		return false;
445     }
446     
447     /**
448      * Extract X509 Certificates from p7b files
449      * @param p7bfilename
450      * @return
451      * @throws IOException
452      * @throws CertificateException
453      * @throws CMSException 
454      * @throws NoSuchStoreException 
455      * @throws NoSuchProviderException 
456      */
457     public static Collection<X509Certificate> getCertsFromPKCS7(String p7bfilename) throws IOException, CertificateException, CMSException, NoSuchProviderException, NoSuchStoreException {
458     	log.info("Importing certificates from PKCS7 file " + p7bfilename);
459     	
460     	//Load File
461     	byte[] p7bcontent = FileUtil.readFile(p7bfilename);
462         CMSSignedData data = new CMSSignedData(p7bcontent);
463         X509Store store = data.getCertificates("Collection", "BC");
464         
465         /* Select only end user certificates */
466         X509CertStoreSelector selector = new X509CertStoreSelector();
467         selector.setBasicConstraints(-2);
468         Collection certificates = store.getMatches(selector);
469         
470         Integer size = certificates.size();
471         Iterator it = certificates.iterator();
472         log.debug("Number of final certificates in the store: " + size);
473         while(it.hasNext()) {
474             X509Certificate certificate = (X509Certificate) it.next();
475             log.info("Found certificate: " + certificate.getSubjectDN().toString() +", serial:"+certificate.getSerialNumber());
476         }
477         
478         return certificates;
479     }
480     /**
481      * Reads a certificate in PEM-format from a file. The file may contain other things,
482      * the first certificate in the file is read.
483      *
484      * @param certFile the file containing the certificate in PEM-format
485      * @return Ordered Collection of X509Certificate, first certificate first, or empty Collection
486      * @exception IOException if the filen cannot be read.
487      * @exception CertificateException if the filen does not contain a correct certificate.
488      */
489     public static Collection<X509Certificate> getCertsFromPEM(String certFile) throws IOException, CertificateException {
490         log.info("Importing certificates from PEM file " + certFile);
491         InputStream inStrm = null;
492         Collection certs = null;
493 		try {
494 			inStrm = new FileInputStream(certFile);
495 			certs = getCertsFromPEM(inStrm);
496 		} catch (IOException e ) {
497 			log.debug("error while parsing " + certFile + " : "+e.getLocalizedMessage(),e);
498 		} catch (CertificateException e) {
499 			log.debug("error while parsing certificate in " + certFile + " : "+e.getLocalizedMessage(),e);
500 		} finally {
501 		
502 			if (inStrm != null) inStrm.close();
503 		}
504         return certs;
505     }
506 
507     /**
508      * Reads a certificate in PEM-format from an InputStream. The stream may contain other things,
509      * the first certificate in the stream is read.
510      *
511      * @param certFile the input stream containing the certificate in PEM-format
512      * @return Ordered Collection of X509Certificate, first certificate first, or empty Collection
513      * @exception IOException if the stream cannot be read.
514      * @exception CertificateException if the stream does not contain a correct certificate.
515      */
516     public static Collection<X509Certificate> getCertsFromPEM(InputStream certstream) throws IOException, CertificateException {
517         ArrayList ret = new ArrayList();
518         BufferedReader bufRdr = null;
519         ByteArrayOutputStream ostr = null;
520         PrintStream opstr = null;
521 		try {
522 			bufRdr = new BufferedReader(new InputStreamReader(certstream));
523 			while (bufRdr.ready()) {
524 				ostr = new ByteArrayOutputStream();
525 				opstr = new PrintStream(ostr);
526 				String temp;
527 				while ((temp = bufRdr.readLine()) != null
528 						&& !temp.equals(BEGIN_CERT))
529 					continue;
530 				if (temp == null)
531 					throw new IOException("Error in " + certstream.toString()
532 							+ ", missing " + BEGIN_CERT + " boundary");
533 				while ((temp = bufRdr.readLine()) != null
534 						&& !temp.equals(END_CERT))
535 					opstr.print(temp);
536 				if (temp == null)
537 					throw new IOException("Error in " + certstream.toString()
538 							+ ", missing " + END_CERT + " boundary");
539 				opstr.close();
540 
541 				byte[] certbuf = Base64.decode(ostr.toByteArray());
542 				ostr.close();
543 				// Phweeew, were done, now decode the cert from file back to X509Certificate object
544 				CertificateFactory cf = getCertificateFactory();
545 				X509Certificate x509cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(certbuf));
546 				ret.add(x509cert);
547 			}
548 		} finally {
549 			if (bufRdr != null) bufRdr.close();
550 			if (opstr != null) opstr.close();
551 			if (ostr != null) ostr.close();
552 		}        
553 		//log.debug("<getcertfromPEM:" + ret.size());
554         return ret;
555     } // getCertsFromPEM
556     /**
557      * Reads a certificate in PEM-format from an InputStream. The stream may contain other things,
558      * the first certificate in the stream is read.
559      *
560      * @param certFile the input stream containing the certificate in PEM-format
561      * @return Ordered Collection of X509Certificate, first certificate first, or empty Collection
562      * @exception IOException if the stream cannot be read.
563      * @exception CertificateException if the stream does not contain a correct certificate.
564      */
565     public static PKCS10CertificationRequest getCSRFromPEM(String csrFile) throws IOException, CertificateException {
566     	
567     	log.info("Loading certificate signing request from PEM file " + csrFile);
568 
569         BufferedReader bufRdr = null;
570         ByteArrayOutputStream ostr = null;
571         PrintStream opstr = null;
572         PKCS10CertificationRequest pkcs10 = null;
573         
574 		try {
575 			InputStream inStrm = new FileInputStream(csrFile);
576 			bufRdr = new BufferedReader(new InputStreamReader(inStrm));
577 			
578 			while (bufRdr.ready()) {
579 				ostr = new ByteArrayOutputStream();
580 				opstr = new PrintStream(ostr);
581 				String temp;
582 				
583 				//Jump CSR Header
584 				while ((temp = bufRdr.readLine()) != null
585 					&& !temp.equals(BEGIN_CERT_REQ))
586 					continue;
587 				if (!temp.equals(BEGIN_CERT_REQ))
588 					throw new IOException("Error in " + csrFile + ", missing " + BEGIN_CERT_REQ + " boundary");
589 				
590 				//Read Base 64 encoded lines
591 				while ((temp = bufRdr.readLine()) != null
592 					&& !temp.equals(END_CERT_REQ))
593 					opstr.print(temp);
594 				
595 				//Jump CSR Footer
596 				if (!temp.equals(END_CERT_REQ))
597 					throw new IOException("Error in "+csrFile+", missing " + END_CERT_REQ + " boundary");
598 				opstr.close();
599 
600 				byte[] certbuf = Base64.decode(ostr.toByteArray());
601 				ostr.close();
602 				
603 				//Now decode the CSR from file back to PKCS10CertificationRequest object
604 				pkcs10 = new PKCS10CertificationRequest(certbuf);
605 			}
606 		} finally {
607 			if (bufRdr != null) bufRdr.close();
608 			if (opstr != null) opstr.close();
609 		}
610         return pkcs10;
611     }
612 
613 	public static byte[] getCertEncodedPkcs7(X509Certificate cert) {
614 	    return getCertsEncodedPkcs7(new X509Certificate[] { cert } );
615 	}
616 
617 	public static byte[] getCertsEncodedPkcs7(X509Certificate certs[]) {
618 	    try
619 	    {
620 	        ArrayList alCerts = new ArrayList();
621 	        for(int iCnt = 0; iCnt < certs.length; iCnt++)
622 	            alCerts.add(certs[iCnt]);
623 	        CertificateFactory cf = CertificateFactory.getInstance("X.509");
624 	        CertPath cp = cf.generateCertPath(alCerts);
625 	        return cp.getEncoded("PKCS7");
626 	    } catch(CertificateException e) {
627 			log.error("getCertsEncodedPkcs7 error :",e);
628 	    }
629 	    return null;
630 	}
631     public static CertificateFactory getCertificateFactory() {
632         try {
633             return CertificateFactory.getInstance("X.509", "BC");
634         } catch (NoSuchProviderException e) {
635 			log.debug("error while getting BC Certificate Factory : " + e.getLocalizedMessage(),e);
636         } catch (CertificateException e) {
637         	log.debug("error while getting BC Certificate Factory : " + e.getLocalizedMessage(),e);
638         }
639         return null;
640     }
641     
642 	// Fast convert a byte array to a hex string
643 	// with possible leading zero.
644     public static String toHexString ( byte[] b ) {
645     	StringBuffer sb = new StringBuffer( b.length * 2 );
646     	for ( int i=0; i<b.length; i++ ) {
647     		// look up high nibble char
648     		sb.append( hexChar [( b[i] & 0xf0 ) >>> 4] );
649     		// look up low nibble char
650     		sb.append( hexChar [b[i] & 0x0f] );
651     	}
652 	    return sb.toString();
653 	}
654 
655 	// table to convert a nibble to a hex char.
656 	static char[] hexChar = { '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f'};
657 	
658 	/** and be formed only of digits 0-9 A-F or
659 	* a-f. No spaces, minus or plus signs.
660 	* @return corresponding byte array.
661 	*/
662 	public static byte[] fromHexString ( String s )
663 	   {
664 	   int stringLength = s.length();
665 	   if ( (stringLength & 0x1) != 0 )
666 	      {
667 	      throw new IllegalArgumentException ( "fromHexString requires an even number of hex characters" );
668 	      }byte[] b = new byte[stringLength / 2];
669 
670 	   for ( int i=0,j=0; i<stringLength; i+=2,j++ )
671 	      {
672 	      int high = charToNibble( s.charAt ( i ) );
673 	      int low = charToNibble( s.charAt ( i+1 ) );
674 	      b[j] = (byte)( ( high << 4 ) | low );
675 	      }
676 	   return b;
677 	   }
678 
679 	/**
680 	 * Convert any X509Certificate implementation from any Security Provider to BouncyCastle Security Provider implementation.<br/>
681 	 * If convertion failed for any reason, it return the input X509Certificate object.
682 	 * 
683 	 * @param cert the certificate object to convert
684 	 * @return X509CertificateObject implementation of X509Certificate
685 	 */
686 	public static X509Certificate getBCCertificate(X509Certificate cert) {
687 	    if ( cert!=null && !(cert instanceof X509CertificateObject) )
688 	            try {
689 	                ByteArrayInputStream bais = new ByteArrayInputStream(cert.getEncoded());
690 	                cert = (X509Certificate) getCertificateFactory().generateCertificate(bais);
691 	            } catch (CertificateEncodingException e) {
692 	                log.error("Certificate conversion to Bouncy Castle Object error",e);
693 	            } catch (CertificateException e) {
694                     log.error("Certificate conversion to Bouncy Castle Object error",e);
695 	            } catch (Exception e) {
696                     log.error("Certificate conversion to Bouncy Castle Object error",e);
697 	            }
698 	     return cert;
699 	}
700 	/**
701 	* convert a single char to corresponding nibble.
702 	*
703 	* @param c char to convert. must be 0-9 a-f A-F, no
704 	* spaces, plus or minus signs.
705 	*
706 	* @return corresponding integer
707 	*/
708 	private static int charToNibble ( char c )
709 	   {
710 	   if ( '0' <= c && c <= '9' )
711 	      {
712 	      return c - '0';
713 	      }
714 	   else if ( 'a' <= c && c <= 'f' )
715 	      {
716 	      return c - 'a' + 0xa;
717 	      }
718 	   else if ( 'A' <= c && c <= 'F' )
719 	      {
720 	      return c - 'A' + 0xa;
721 	      }
722 	   else
723 	      {
724 	      throw new IllegalArgumentException ( "Invalid hex character: " + c );
725 	      }
726 	   }
727 
728 	public static X509CRL loadCRLFromDP(DistributionPoint dp) {
729 	  //TODO: download crl from CDP
730 		return null;
731 	}
732 }