harmony-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From telli...@apache.org
Subject svn commit: r454536 - in /incubator/harmony/enhanced/classlib/trunk/modules/security/src: main/java/common/org/apache/harmony/security/internal/nls/ main/java/common/org/apache/harmony/security/provider/cert/ test/impl/java/org/apache/harmony/security/...
Date Mon, 09 Oct 2006 22:31:56 GMT
Author: tellison
Date: Mon Oct  9 15:31:55 2006
New Revision: 454536

URL: http://svn.apache.org/viewvc?view=rev&rev=454536
Log:
Apply patch HARMONY-1771 ([classlib][security] CertificateFactory fails to decode some PEM encoded structures)

Modified:
    incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/internal/nls/messages.properties
    incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CertFactoryImpl.java
    incubator/harmony/enhanced/classlib/trunk/modules/security/src/test/impl/java/org/apache/harmony/security/tests/java/security/cert/CertificateFactory_ImplTest.java

Modified: incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/internal/nls/messages.properties
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/internal/nls/messages.properties?view=diff&rev=454536&r1=454535&r2=454536
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/internal/nls/messages.properties (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/internal/nls/messages.properties Mon Oct  9 15:31:55 2006
@@ -118,20 +118,24 @@
 security.15=collection is read-only
 security.150=No suitable constructors found in permission class : {0}. Zero, one or two-argument constructor is expected
 security.151=Certificate Factory supports CRLs and Certificates in (PEM) ASN.1 DER encoded form, and Certification Paths in PkiPath and PKCS7 formats.
-security.152=Input Stream contains not enought data.
+security.152=Input Stream contains not enough data.
 security.153=Input stream should not be null.
 security.154=Invalid PKCS7 data provided
-security.155=Input Stream contains not enought data.
-security.156=Null input stream provided.
-security.157=Incorrect Base64 encoding: unexpected EOF.
-security.158=Incorrect Base64 encoding: boundary delimiter expected '{0}'
+security.155=There is no data in the stream.
+security.156=Incorrect PEM encoding: EOF before content.
+security.157=Incorrect Base64 encoding: EOF without closing delimiter.
+security.158=Incorrect Base64 encoding: New line code is expected before closing delimiter boundary.
 security.159=Incorrect Base64 encoding.
 security.15A=Could not reset the stream: position became invalid or stream has not been marked.
-security.15B=Input stream should not be null.
+security.15B=Incorrect PEM encoding: '-----BEGIN{0}' is expected as opening delimiter boundary.
+security.15B1=Incorrect PEM encoding: '-----END{0}' is expected as closing delimiter boundary.
+security.15B2=Incorrect PEM encoding: New line code is expected after the opening delimiter boundary."
+security.15B3=Bad Certificate encoding.
+security.15B4=Bad CRL encoding.
 security.15C=Signature was not verified.
 security.15D=One of provided certificates is not X509 certificate
 security.15E=Incorrect encoded form: {0}
-security.15F=Unsupported encoding: {0}
+security.15F=Unsupported encoding.
 security.16=invalid permission: {0}
 security.160=Incorrect PKCS7 encoded form: missing signed data
 security.161=Encoding Error occurred

Modified: incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CertFactoryImpl.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CertFactoryImpl.java?view=diff&rev=454536&r1=454535&r2=454536
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CertFactoryImpl.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CertFactoryImpl.java Mon Oct  9 15:31:55 2006
@@ -56,10 +56,14 @@
  */
 public class X509CertFactoryImpl extends CertificateFactorySpi {
 
+    // number of leading/trailing bytes used for cert hash computation
+    private static int CERT_CACHE_SEED_LENGTH = 28;
     // certificate cache
-    private static Cache CERT_CASHE = new Cache();
-    // crl cache, 24 leading/trailing bytes will be used for hash computation
-    private static Cache CRL_CASHE = new Cache(24);
+    private static Cache CERT_CACHE = new Cache(CERT_CACHE_SEED_LENGTH);
+    // number of leading/trailing bytes used for crl hash computation
+    private static int CRL_CACHE_SEED_LENGTH = 24;
+    // crl cache
+    private static Cache CRL_CACHE = new Cache(CRL_CACHE_SEED_LENGTH);
 
     /**
      * Default constructor.
@@ -75,7 +79,7 @@
      * <code>"-----END CERTIFICATE-----"</code> at the end) representation
      * of the former encoded form.
      *
-     * Before the generation the attempt the encoded form is looked up in
+     * Before the generation the encoded form is looked up in
      * the cache. If the cache contains the certificate with requested encoded
      * form it is returned from it, otherwise it is generated by ASN.1
      * decoder.
@@ -86,7 +90,7 @@
     public Certificate engineGenerateCertificate(InputStream inStream)
             throws CertificateException {
         if (inStream == null) {
-            throw new CertificateException(Messages.getString("security.15B")); //$NON-NLS-1$
+            throw new CertificateException(Messages.getString("security.153")); //$NON-NLS-1$
         }
         try {
             if (!inStream.markSupported()) {
@@ -95,60 +99,15 @@
             }
             // mark is needed to recognize the format of the provided encoding
             // (ASN.1 or PEM)
-            inStream.mark(32);
-            byte[] buff = new byte[28];
-            // read the prefix of the encoding
-            if (inStream.read(buff) < 28) {
-                throw new CertificateException(
-                        Messages.getString("security.152")); //$NON-NLS-1$
-            }
+            inStream.mark(1);
             // check whether the provided certificate is in PEM encoded form
-            if ("-----BEGIN CERTIFICATE-----".equals(new String(buff, 0, 27))) { //$NON-NLS-1$
-                byte[] encoding = decodePEM(inStream, "CERTIFICATE"); //$NON-NLS-1$
-                
-                long hash = CERT_CASHE.getHash(encoding);
-                if (CERT_CASHE.contains(hash)) {
-                    Certificate res = 
-                        (Certificate) CERT_CASHE.get(hash, encoding);
-                    if (res != null) {
-                        return res;
-                    }
-                }
-                Certificate res = new X509CertImpl(encoding);
-                CERT_CASHE.put(hash, encoding, res);
-                return res;
+            if (inStream.read() == '-') {
+                // decode PEM, retrieve CRL
+                return getCertificate(decodePEM(inStream, CERT_BOUND_SUFFIX));
             } else {
-                // read ASN.1 DER encoded form
                 inStream.reset();
-                // check whether certificate has already been generated and
-                // stored in the cache
-                long hash = CERT_CASHE.getHash(buff);
-                if (CERT_CASHE.contains(hash)) {
-                    // preliminary check is successful, do more accurate check.
-                    byte[] encoding = new byte[BerInputStream.getLength(buff)];
-                    // read full encoding form from the stream
-                    inStream.read(encoding);
-                    // try to retrieve from the cache
-                    Certificate res =
-                        (Certificate) CERT_CASHE.get(hash, encoding);
-                    if (res != null) {
-                        // found in the cache
-                        return res;
-                    }
-                    // there is no generated certificate in the cache,
-                    // so generate it
-                    res = new X509CertImpl(encoding);
-                    // put newly generated certificate in the cache
-                    CERT_CASHE.put(hash, encoding, res);
-                    return res;
-                } else {
-                    // there is no generated certificate in the cache,
-                    // so generate it
-                    Certificate res = new X509CertImpl(inStream);
-                    // put newly generated certificate in the cache
-                    CERT_CASHE.put(hash, res.getEncoded(), res);
-                    return res;
-                }
+                // retrieve CRL
+                return getCertificate(inStream);
             }
         } catch (IOException e) {
             throw new CertificateException(e);
@@ -173,65 +132,105 @@
                 // create the mark supporting wrapper
                 inStream = new RestoringInputStream(inStream);
             }
-            boolean isPKCS7 = false;
-            boolean isPEM = false;
-            // check whether it is a PKCS7 structure
-            inStream.mark(33);
-            if (inStream.read() == '-') { // it is Base64 encoded form
-                // check the boundary delimiter
-                byte[] delimiter = new byte[20];
-                inStream.read(delimiter);
-                if (new String(delimiter).startsWith("----BEGIN PKCS7-----")) { //$NON-NLS-1$
-                    // this is PEM encoded PKCS7 structure
-                    isPKCS7 = true;
-                    isPEM = true;
-                } else {
+            // if it is PEM encoded form this array will contain the encoding
+            // so ((it is PEM) <-> (encoding != null))
+            byte[] encoding = null;
+            // The following by SEQUENCE ASN.1 tag, used for
+            // recognizing the data format 
+            // (is it PKCS7 ContentInfo structure, X.509 Certificate, or
+            // unsupported encoding)
+            int second_asn1_tag = -1;
+            inStream.mark(1);
+            int ch;
+            while ((ch = inStream.read()) != -1) {
+                // check if it is PEM encoded form
+                if (ch == '-') { // beginning of PEM encoding ('-' char)
+                    // decode PEM chunk and store its content (ASN.1 encoding)
+                    encoding = decodePEM(inStream, FREE_BOUND_SUFFIX);
+                } else if (ch == 0x30) { // beginning of ASN.1 sequence (0x30)
+                    encoding = null;
                     inStream.reset();
+                    // prepare for data format determination
+                    inStream.mark(CERT_CACHE_SEED_LENGTH);
+                } else { // unsupported data
+                    if (result.size() == 0) {
+                        throw new CertificateException(
+                                Messages.getString("security.15F")); //$NON-NLS-1$
+                    } else {
+                        // it can be trailing user data,
+                        // so keep it in the stream
+                        inStream.reset();
+                        return result;
+                    }
                 }
-            } else {
-                // it is plain ASN.1 DER encoded form, 
-                // so reset the stream and check the structure
-                inStream.reset();
-                BerInputStream in = new BerInputStream(inStream);
-                if (in.next() == ASN1Constants.TAG_OID) { 
-                    // this is PKCS7 structure
-                    isPKCS7 = true;
+                // Check the data format
+                BerInputStream in = (encoding == null)
+                                        ? new BerInputStream(inStream)
+                                        : new BerInputStream(encoding);
+                // read the next ASN.1 tag
+                second_asn1_tag = in.next(); // inStream position changed
+                if (encoding == null) {
+                    // keep whole structure in the stream
+                    inStream.reset();
                 }
-                inStream.reset();
-            }
-            if (isPKCS7) {
-                ContentInfo info;
-                if (isPEM) {
-                    info = (ContentInfo) 
-                        ContentInfo.ASN1.decode(decodePEM(inStream, "PKCS7")); //$NON-NLS-1$
+                // check if it is a TBSCertificate structure
+                if (second_asn1_tag != ASN1Constants.TAG_C_SEQUENCE) {
+                    if (result.size() == 0) {
+                        // there were not read X.509 Certificates, so 
+                        // break the cycle and check 
+                        // whether it is PKCS7 structure
+                        break;
+                    } else {
+                        // it can be trailing user data,
+                        // so return what we already read
+                        return result;
+                    }
                 } else {
-                    info = (ContentInfo) ContentInfo.ASN1.decode(inStream);
+                    if (encoding == null) {
+                        result.add(getCertificate(inStream));
+                    } else {
+                        result.add(getCertificate(encoding));
+                    }
                 }
+                // mark for the next iteration
+                inStream.mark(1);
+            }
+            if (result.size() != 0) {
+                // some Certificates have been read
+                return result;
+            } else if (ch == -1) {
+                throw new CertificateException(
+                        Messages.getString("security.155")); //$NON-NLS-1$
+            }
+            // else: check if it is PKCS7
+            if (second_asn1_tag == ASN1Constants.TAG_OID) {
+                // it is PKCS7 ContentInfo structure, so decode it
+                ContentInfo info = (ContentInfo) 
+                    ((encoding != null)
+                        ? ContentInfo.ASN1.decode(encoding)
+                        : ContentInfo.ASN1.decode(inStream));
+                // retrieve SignedData
                 SignedData data = info.getSignedData();
                 if (data == null) {
-                    throw new CertificateException(Messages.getString("security.154")); //$NON-NLS-1$
+                    throw new CertificateException(
+                            Messages.getString("security.154")); //$NON-NLS-1$
                 }
-                List certificates = data.getCertificates();
-                if (certificates != null) {
-                    for (int i = 0; i < certificates.size(); i++) {
+                List certs = data.getCertificates();
+                if (certs != null) {
+                    for (int i = 0; i < certs.size(); i++) {
                         result.add(new X509CertImpl(
                             (org.apache.harmony.security.x509.Certificate)
-                            certificates.get(i)));
+                                certs.get(i)));
                     }
                 }
                 return result;
-            } else {
-                inStream.mark(1);
-                while (inStream.read() != -1) {
-                    inStream.reset();
-                    result.add(engineGenerateCertificate(inStream));
-                    inStream.mark(1);
-                }
             }
+            // else: Unknown data format
+            throw new CertificateException(
+                            Messages.getString("security.15F")); //$NON-NLS-1$
         } catch (IOException e) {
             throw new CertificateException(e);
         }
-        return result;
     }
 
     /**
@@ -245,50 +244,20 @@
         }
         try {
             if (!inStream.markSupported()) {
-                // create the mark supporting wrapper
+                // Create the mark supporting wrapper
+                // Mark is needed to recognize the format 
+                // of provided encoding form (ASN.1 or PEM)
                 inStream = new RestoringInputStream(inStream);
             }
-            // mark is needed to recognize the format of the provided encoding
-            // (ASN.1 or PEM)
-            inStream.mark(32);
-            byte[] buff = new byte[25]; // take one byte for new line
-            // read the prefix of the encoding
-            if (inStream.read(buff) < 25) {
-                throw new CRLException(
-                        Messages.getString("security.155")); //$NON-NLS-1$
-            }
+            inStream.mark(1);
             // check whether the provided crl is in PEM encoded form
-            if ("-----BEGIN X509 CRL-----".equals(new String(buff, 0, 24))) { //$NON-NLS-1$
-                byte[] encoding = decodePEM(inStream, "X509 CRL"); //$NON-NLS-1$
-                long hash = CRL_CASHE.getHash(encoding);
-                if (CRL_CASHE.contains(hash)) {
-                    X509CRL res = (X509CRL) CRL_CASHE.get(hash, encoding);
-                    if (res != null) {
-                        return res;
-                    }
-                }
-                X509CRL res = new X509CRLImpl(encoding);
-                CRL_CASHE.put(hash, encoding, res);
-                return res;
+            if (inStream.read() == '-') {
+                // decode PEM, retrieve CRL
+                return getCRL(decodePEM(inStream, FREE_BOUND_SUFFIX));
             } else {
                 inStream.reset();
-                long hash = CRL_CASHE.getHash(buff);
-                if (CRL_CASHE.contains(hash)) {
-                    byte[] encoding = new byte[BerInputStream.getLength(buff)];
-                    inStream.read(encoding);
-                    CRL res =
-                        (CRL) CRL_CASHE.get(hash, encoding);
-                    if (res != null) {
-                        return res;
-                    }
-                    res = new X509CRLImpl(encoding);
-                    CRL_CASHE.put(hash, encoding, res);
-                    return res;
-                } else {
-                    X509CRL res = new X509CRLImpl(inStream);
-                    CRL_CASHE.put(hash, res.getEncoded(), res);
-                    return res;
-                }
+                // retrieve CRL
+                return getCRL(inStream);
             }
         } catch (IOException e) {
             throw new CRLException(e);
@@ -302,52 +271,94 @@
     public Collection<? extends CRL> engineGenerateCRLs(InputStream inStream)
             throws CRLException {
         if (inStream == null) {
-            throw new CRLException(Messages.getString("security.156")); //$NON-NLS-1$
+            throw new CRLException(Messages.getString("security.153")); //$NON-NLS-1$
         }
         ArrayList result = new ArrayList();
         try {
             if (!inStream.markSupported()) {
                 inStream = new RestoringInputStream(inStream);
             }
-            boolean isPKCS7 = false;
-            boolean isPEM = false;
-            // check whether it is a PKCS7 structure
-            inStream.mark(33);
-            if (inStream.read() == '-') { // it is Base64 encoded form
-                // check the boundary delimiter
-                byte[] delimiter = new byte[20];
-                inStream.read(delimiter);
-                if (new String(delimiter).startsWith("----BEGIN PKCS7-----")) { //$NON-NLS-1$
-                    // this is PEM encoded PKCS7 structure
-                    isPKCS7 = true;
-                    isPEM = true;
-                } else {
+            // if it is PEM encoded form this array will contain the encoding
+            // so ((it is PEM) <-> (encoding != null))
+            byte[] encoding = null;
+            // The following by SEQUENCE ASN.1 tag, used for
+            // recognizing the data format 
+            // (is it PKCS7 ContentInfo structure, X.509 CRL, or
+            // unsupported encoding)
+            int second_asn1_tag = -1;
+            inStream.mark(1);
+            int ch;
+            while ((ch = inStream.read()) != -1) {
+                // check if it is PEM encoded form
+                if (ch == '-') { // beginning of PEM encoding ('-' char)
+                    // decode PEM chunk and store its content (ASN.1 encoding)
+                    encoding = decodePEM(inStream, FREE_BOUND_SUFFIX);
+                } else if (ch == 0x30) { // beginning of ASN.1 sequence (0x30)
+                    encoding = null;
                     inStream.reset();
+                    // prepare for data format determination
+                    inStream.mark(CRL_CACHE_SEED_LENGTH);
+                } else { // unsupported data
+                    if (result.size() == 0) {
+                        throw new CRLException(
+                                Messages.getString("security.15F")); //$NON-NLS-1$
+                    } else {
+                        // it can be trailing user data,
+                        // so keep it in the stream
+                        inStream.reset();
+                        return result;
+                    }
                 }
-            } else {
-                // it is plain ASN.1 DER encoded form, 
-                // so reset the stream and check the structure
-                inStream.reset();
-                BerInputStream in = new BerInputStream(inStream);
-                if (in.next() == ASN1Constants.TAG_OID) { 
-                    // this is PKCS7 structure
-                    isPKCS7 = true;
+                // Check the data format
+                BerInputStream in = (encoding == null)
+                                        ? new BerInputStream(inStream)
+                                        : new BerInputStream(encoding);
+                // read the next ASN.1 tag
+                second_asn1_tag = in.next();
+                if (encoding == null) {
+                    // keep whole structure in the stream
+                    inStream.reset();
                 }
-                inStream.reset();
-            }
-            if (isPKCS7) {
-                // decode ContentInfo structure
-                ContentInfo info;
-                if (isPEM) {
-                    info = (ContentInfo) 
-                        ContentInfo.ASN1.decode(decodePEM(inStream, "PKCS7")); //$NON-NLS-1$
+                // check if it is a TBSCertList structure
+                if (second_asn1_tag != ASN1Constants.TAG_C_SEQUENCE) {
+                    if (result.size() == 0) {
+                        // there were not read X.509 CRLs, so 
+                        // break the cycle and check 
+                        // whether it is PKCS7 structure
+                        break;
+                    } else {
+                        // it can be trailing user data,
+                        // so return what we already read
+                        return result;
+                    }
                 } else {
-                    info = (ContentInfo) ContentInfo.ASN1.decode(inStream);
+                    if (encoding == null) {
+                        result.add(getCRL(inStream));
+                    } else {
+                        result.add(getCRL(encoding));
+                    }
                 }
+                inStream.mark(1);
+            }
+            if (result.size() != 0) {
+                // the stream was read out
+                return result;
+            } else if (ch == -1) {
+                throw new CRLException(
+                        Messages.getString("security.155")); //$NON-NLS-1$
+            }
+            // else: check if it is PKCS7
+            if (second_asn1_tag == ASN1Constants.TAG_OID) {
+                // it is PKCS7 ContentInfo structure, so decode it
+                ContentInfo info = (ContentInfo) 
+                    ((encoding != null)
+                        ? ContentInfo.ASN1.decode(encoding)
+                        : ContentInfo.ASN1.decode(inStream));
                 // retrieve SignedData
                 SignedData data = info.getSignedData();
                 if (data == null) {
-                    throw new CRLException(Messages.getString("security.154")); //$NON-NLS-1$
+                    throw new CRLException(
+                            Messages.getString("security.154")); //$NON-NLS-1$
                 }
                 List crls = data.getCRLs();
                 if (crls != null) {
@@ -357,18 +368,13 @@
                     }
                 }
                 return result;
-            } else {
-                inStream.mark(1);
-                while (inStream.read() != -1) {
-                    inStream.reset();
-                    result.add(engineGenerateCRL(inStream));
-                    inStream.mark(1);
-                }
             }
+            // else: Unknown data format
+            throw new CRLException(
+                        Messages.getString("security.15F")); //$NON-NLS-1$
         } catch (IOException e) {
             throw new CRLException(e);
         }
-        return result;
     }
 
     /**
@@ -377,7 +383,11 @@
      */
     public CertPath engineGenerateCertPath(InputStream inStream)
             throws CertificateException {
-        return X509CertPathImpl.getInstance(inStream);
+        if (inStream == null) {
+            throw new CertificateException(
+                    Messages.getString("security.153")); //$NON-NLS-1$
+        }
+        return engineGenerateCertPath(inStream, "PkiPath"); //$NON-NLS-1$
     }
 
     /**
@@ -386,7 +396,33 @@
      */
     public CertPath engineGenerateCertPath(
             InputStream inStream, String encoding) throws CertificateException {
-        return X509CertPathImpl.getInstance(inStream, encoding);
+        if (inStream == null) {
+            throw new CertificateException(
+                    Messages.getString("security.153")); //$NON-NLS-1$
+        }
+        if (!inStream.markSupported()) {
+            inStream = new RestoringInputStream(inStream);
+        }
+        try {
+            inStream.mark(1);
+            int ch;
+
+            // check if it is PEM encoded form
+            if ((ch = inStream.read()) == '-') {
+                // decode PEM chunk into ASN.1 form and decode CertPath object
+                return X509CertPathImpl.getInstance(
+                        decodePEM(inStream, FREE_BOUND_SUFFIX), encoding);
+            } else if (ch == 0x30) { // ASN.1 Sequence
+                inStream.reset();
+                // decode ASN.1 form
+                return X509CertPathImpl.getInstance(inStream, encoding);
+            } else {
+                throw new CertificateException(
+                            Messages.getString("security.15F")); //$NON-NLS-1$
+            }
+        } catch (IOException e) {
+            throw new CertificateException(e);
+        }
     }
 
     /**
@@ -406,16 +442,98 @@
         return X509CertPathImpl.encodings.iterator();
     }
 
-    // Method retirieves the PEM encoded data from the stream 
-    // and returns its decoded representation.
-    // It is supposed that the data is bounded by
-    // "-----END" + boundary_mark + "-----" at the end.
-    private byte[] decodePEM(InputStream inStream, String boundary_mark) 
+    // ---------------------------------------------------------------------
+    // ------------------------ Staff methods ------------------------------
+    // ---------------------------------------------------------------------
+
+    private static byte[] pemBegin = "-----BEGIN".getBytes(); //$NON-NLS-1$
+    private static byte[] pemClose = "-----END".getBytes(); //$NON-NLS-1$
+    /**
+     * Code describing free format for PEM boundary suffix:
+     * "^-----BEGIN.*\n"         at the beginning, and<br>
+     * "\n-----END.*(EOF|\n)$"   at the end.
+     */
+    private static byte[] FREE_BOUND_SUFFIX = null;
+    /**
+     * Code describing PEM boundary suffix for X.509 certificate:
+     * "^-----BEGIN CERTIFICATE-----\n"   at the beginning, and<br>
+     * "\n-----END CERTIFICATE-----"   at the end.
+     */
+    private static byte[] CERT_BOUND_SUFFIX = 
+        " CERTIFICATE-----".getBytes(); //$NON-NLS-1$
+
+    /**
+     * Method retrieves the PEM encoded data from the stream 
+     * and returns its decoded representation.
+     * Method checks correctness of PEM boundaries. It supposes that
+     * the first '-' of the opening boundary has already been read from
+     * the stream. So first of all it checks that the leading bytes
+     * are equal to "-----BEGIN" boundary prefix. Than if boundary_suffix
+     * is not null, it checks that next bytes equal to boundary_suffix
+     * + new line char[s] ([CR]LF).
+     * If boundary_suffix parameter is null, method supposes free suffix
+     * format and skips any bytes until the new line.<br>
+     * After the opening boundary has been read and checked, the method
+     * read Base64 encoded data until closing PEM boundary is not reached.<br>
+     * Than it checks closing boundary - it should start with new line +
+     * "-----END" + boundary_suffix. If boundary_suffix is null, 
+     * any characters are skipped until the new line.<br>
+     * After this any trailing new line characters are skipped from the stream,
+     * Base64 encoding is decoded and returned.
+     * @param inStream the stream containing the PEM encoding.
+     * @param boundary_suffix the suffix of expected PEM multipart 
+     * boundary delimiter.<br>
+     * If it is null, that any character sequences are accepted.
+     * @throws IOException If PEM boundary delimiter does not comply 
+     * with expected or some I/O or decoding problems occur.
+     */
+    private byte[] decodePEM(InputStream inStream, byte[] boundary_suffix) 
                                                         throws IOException {
+        int ch; // the char to be read
+        // check and skip opening boundary delimiter 
+        // (first '-' is supposed as already read)
+        for (int i=1; i<pemBegin.length; i++) {
+            if (pemBegin[i] != (ch = inStream.read())) {
+                throw new IOException(
+                    "Incorrect PEM encoding: '-----BEGIN"
+                    + ((boundary_suffix == null) 
+                        ? "" : new String(boundary_suffix))
+                    + "' is expected as opening delimiter boundary.");
+            }
+        }
+        if (boundary_suffix == null) {
+            // read (skip) the trailing characters of 
+            // the beginning PEM boundary delimiter
+            while ((ch = inStream.read()) != '\n') {
+                if (ch == -1) {
+                    throw new IOException(
+                        Messages.getString("security.156")); //$NON-NLS-1$
+                }
+            }
+        } else {
+            for (int i=0; i<boundary_suffix.length; i++) {
+                if (boundary_suffix[i] != inStream.read()) {
+                    throw new IOException(
+                        Messages.getString("security.15B", //$NON-NLS-1$
+                            ((boundary_suffix == null) 
+                                ? "" 
+                                : new String(boundary_suffix)))); //$NON-NLS-1$
+                }
+            }
+            // read new line characters
+            if ((ch = inStream.read()) == '\r') {
+                // CR has been read, now read LF character
+                ch = inStream.read();
+            }
+            if (ch != '\n') {
+                throw new IOException(
+                    Messages.getString("security.15B2")); //$NON-NLS-1$
+            }
+        }
         int size = 1024; // the size of the buffer containing Base64 data
         byte[] buff = new byte[size];
-        int index=0, ch;
-        // read bytes while boundary delimiter is not reached
+        int index = 0;
+        // read bytes while ending boundary delimiter is not reached
         while ((ch = inStream.read()) != '-') {
             if (ch == -1) {
                 throw new IOException(
@@ -430,14 +548,37 @@
                 size += 1024;
             }
         }
-        // Check the boundary delimiter 
-        // one '-' has been already read
-        String boundary_delimiter = "----END " + boundary_mark + "-----"; //$NON-NLS-1$ //$NON-NLS-2$
-        byte[] tmp = new byte[boundary_delimiter.length()];
-        inStream.read(tmp);
-        if (!new String(tmp).startsWith(boundary_delimiter)) {
+        if (buff[index-1] != '\n') {
             throw new IOException(
-                Messages.getString("security.158", boundary_delimiter));//$NON-NLS-1$
+                Messages.getString("security.158")); //$NON-NLS-1$
+        }
+        // check and skip closing boundary delimiter prefix
+        // (first '-' was read)
+        for (int i=1; i<pemClose.length; i++) {
+            if (pemClose[i] != inStream.read()) {
+                throw new IOException(
+                    Messages.getString("security.15B1", //$NON-NLS-1$
+                        ((boundary_suffix == null) 
+                            ? "" 
+                            : new String(boundary_suffix)))); //$NON-NLS-1$
+            }
+        }
+        if (boundary_suffix == null) {
+            // read (skip) the trailing characters of 
+            // the closing PEM boundary delimiter
+            while (((ch = inStream.read()) != -1)
+                    && (ch != '\n') && (ch != '\r')) {
+            }
+        } else {
+            for (int i=0; i<boundary_suffix.length; i++) {
+                if (boundary_suffix[i] != inStream.read()) {
+                    throw new IOException(
+                        Messages.getString("security.15B1", //$NON-NLS-1$
+                            ((boundary_suffix == null) 
+                                ? "" 
+                                : new String(boundary_suffix)))); //$NON-NLS-1$
+                }
+            }
         }
         // skip trailing line breaks
         inStream.mark(1);
@@ -451,7 +592,175 @@
         }
         return buff;
     };
-    
+   
+    /**
+     * Reads the data of specified length from source 
+     * and returns it as an array.
+     * @return the byte array contained read data or 
+     * null if the stream contains not enough data
+     * @throws IOException if some I/O error has been occurred.
+     */
+    private static byte[] readBytes(InputStream source, int length) 
+                                                            throws IOException {
+        byte[] result = new byte[length];
+        for (int i=0; i<length; i++) {
+            int bytik = source.read();
+            if (bytik == -1) {
+                return null;
+            }
+            result[i] = (byte) bytik;
+        }
+        return result;
+    }
+
+    /**
+     * Returns the Certificate object corresponding to the provided encoding.
+     * Resulting object is retrieved from the cache 
+     * if it contains such correspondence 
+     * and is constructed on the base of encoding 
+     * and stored in the cache otherwise.
+     * @throws IOException if some decoding errors occur
+     * (in the case of cache miss).
+     */
+    private static Certificate getCertificate(byte[] encoding) 
+                                    throws CertificateException, IOException {
+        if (encoding.length < CERT_CACHE_SEED_LENGTH) {
+            throw new CertificateException(
+                    Messages.getString("security.152")); //$NON-NLS-1$
+        }
+        synchronized (CERT_CACHE) {
+            long hash = CERT_CACHE.getHash(encoding);
+            if (CERT_CACHE.contains(hash)) {
+                Certificate res = 
+                    (Certificate) CERT_CACHE.get(hash, encoding);
+                if (res != null) {
+                    return res;
+                }
+            }
+            Certificate res = new X509CertImpl(encoding);
+            CERT_CACHE.put(hash, encoding, res);
+            return res;
+        }
+    }
+
+    /**
+     * Returns the Certificate object corresponding to the encoding provided
+     * by the stream.
+     * Resulting object is retrieved from the cache 
+     * if it contains such correspondence 
+     * and is constructed on the base of encoding 
+     * and stored in the cache otherwise.
+     * @throws IOException if some decoding errors occur
+     * (in the case of cache miss).
+     */
+    private static Certificate getCertificate(InputStream inStream) 
+                                    throws CertificateException, IOException {
+        synchronized (CERT_CACHE) {
+            inStream.mark(CERT_CACHE_SEED_LENGTH);
+            // read the prefix of the encoding
+            byte[] buff = readBytes(inStream, CERT_CACHE_SEED_LENGTH);
+            inStream.reset();
+            if (buff == null) {
+                throw new CertificateException(
+                        Messages.getString("security.152")); //$NON-NLS-1$
+            }
+            long hash = CERT_CACHE.getHash(buff);
+            if (CERT_CACHE.contains(hash)) {
+                byte[] encoding = new byte[BerInputStream.getLength(buff)];
+                if (encoding.length < CERT_CACHE_SEED_LENGTH) {
+                    throw new CertificateException(
+                        Messages.getString("security.15B3")); //$NON-NLS-1$
+                }
+                inStream.read(encoding);
+                Certificate res = (Certificate) CERT_CACHE.get(hash, encoding);
+                if (res != null) {
+                    return res;
+                }
+                res = new X509CertImpl(encoding);
+                CERT_CACHE.put(hash, encoding, res);
+                return res;
+            } else {
+                inStream.reset();
+                Certificate res = new X509CertImpl(inStream);
+                CERT_CACHE.put(hash, res.getEncoded(), res);
+                return res;
+            }
+        }
+    }
+
+    /**
+     * Returns the CRL object corresponding to the provided encoding.
+     * Resulting object is retrieved from the cache 
+     * if it contains such correspondence 
+     * and is constructed on the base of encoding 
+     * and stored in the cache otherwise.
+     * @throws IOException if some decoding errors occur
+     * (in the case of cache miss).
+     */
+    private static CRL getCRL(byte[] encoding) 
+                                            throws CRLException, IOException {
+        if (encoding.length < CRL_CACHE_SEED_LENGTH) {
+            throw new CRLException(
+                    Messages.getString("security.152")); //$NON-NLS-1$
+        }
+        synchronized (CRL_CACHE) {
+            long hash = CRL_CACHE.getHash(encoding);
+            if (CRL_CACHE.contains(hash)) {
+                X509CRL res = (X509CRL) CRL_CACHE.get(hash, encoding);
+                if (res != null) {
+                    return res;
+                }
+            }
+            X509CRL res = new X509CRLImpl(encoding);
+            CRL_CACHE.put(hash, encoding, res);
+            return res;
+        }
+    }
+
+    /**
+     * Returns the CRL object corresponding to the encoding provided
+     * by the stream.
+     * Resulting object is retrieved from the cache 
+     * if it contains such correspondence 
+     * and is constructed on the base of encoding 
+     * and stored in the cache otherwise.
+     * @throws IOException if some decoding errors occur
+     * (in the case of cache miss).
+     */
+    private static CRL getCRL(InputStream inStream) 
+                                            throws CRLException, IOException {
+        synchronized (CRL_CACHE) {
+            inStream.mark(CRL_CACHE_SEED_LENGTH);
+            byte[] buff = readBytes(inStream, CRL_CACHE_SEED_LENGTH);
+            // read the prefix of the encoding
+            inStream.reset();
+            if (buff == null) {
+                throw new CRLException(
+                        Messages.getString("security.152")); //$NON-NLS-1$
+            }
+            long hash = CRL_CACHE.getHash(buff);
+            if (CRL_CACHE.contains(hash)) {
+                byte[] encoding = new byte[BerInputStream.getLength(buff)];
+                if (encoding.length < CRL_CACHE_SEED_LENGTH) {
+                    throw new CRLException(
+                        Messages.getString("security.15B4")); //$NON-NLS-1$
+                }
+                inStream.read(encoding);
+                CRL res = (CRL) CRL_CACHE.get(hash, encoding);
+                if (res != null) {
+                    return res;
+                }
+                res = new X509CRLImpl(encoding);
+                CRL_CACHE.put(hash, encoding, res);
+                return res;
+            } else {
+                X509CRL res = new X509CRLImpl(inStream);
+                CRL_CACHE.put(hash, res.getEncoded(), res);
+                return res;
+            }
+        }
+    }
+
     /*
      * This class extends any existing input stream with
      * mark functionality. It acts as a wrapper over the
@@ -597,7 +906,8 @@
             if (pos >= 0) {
                 pos = (end + 1) % BUFF_SIZE;
             } else {
-                throw new IOException(Messages.getString("security.15A")); //$NON-NLS-1$
+                throw new IOException(
+                        Messages.getString("security.15A")); //$NON-NLS-1$
             }
         }
 

Modified: incubator/harmony/enhanced/classlib/trunk/modules/security/src/test/impl/java/org/apache/harmony/security/tests/java/security/cert/CertificateFactory_ImplTest.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/security/src/test/impl/java/org/apache/harmony/security/tests/java/security/cert/CertificateFactory_ImplTest.java?view=diff&rev=454536&r1=454535&r2=454536
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/security/src/test/impl/java/org/apache/harmony/security/tests/java/security/cert/CertificateFactory_ImplTest.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/security/src/test/impl/java/org/apache/harmony/security/tests/java/security/cert/CertificateFactory_ImplTest.java Mon Oct  9 15:31:55 2006
@@ -26,12 +26,14 @@
 import java.security.KeyFactory;
 import java.security.NoSuchAlgorithmException;
 import java.security.PublicKey;
+import java.security.cert.CertPath;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509CRL;
 import java.security.cert.X509Certificate;
 import java.security.spec.X509EncodedKeySpec;
 import java.util.Collection;
 import java.util.Iterator;
+import java.util.List;
 import org.apache.harmony.luni.util.Base64;
 
 import junit.framework.TestCase;
@@ -48,56 +50,142 @@
 public class CertificateFactory_ImplTest extends TestCase {
 
     /**
-     * Base64 encoded PKCS7 SignedObject containing two X.509 CRLs.
+     * Base64 encoded PKCS7 SignedObject containing two X.509 
+     * Certificates and CRLs.
      */
     private static String pkcs7so =
-          "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";
+          "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"
+        + "8jLlMQA=";
+
+    /**
+     * Base64 encoded PkiPath object containing 2 X.509 certificates.
+     */
+    private static String pkiPath =
+          "MIIFMDCCApQwggJToAMCAQICAgIrMAkGByqGSM44BAMwHTEbMBkGA1UE"
+        + "ChMSQ2VydGlmaWNhdGUgSXNzdWVyMCMXDTA2MDkwNTExMDAyM1oYEjIz"
+        + "MzYxMDEzMTQwNDE4LjEyWjAdMRswGQYDVQQKExJDZXJ0aWZpY2F0ZSBJ"
+        + "c3N1ZXIwggG4MIIBLAYHKoZIzjgEATCCAR8CgYEA/X9TgR11EilS30qc"
+        + "Luzk5/YRt1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzX"
+        + "gTuAHTRv8mZgt2uZUKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7"
+        + "g/bTxR7DAjVUE1oWkTL2dfOuK2HXKu/yIgMZndFIAccCFQCXYFCPFSML"
+        + "zLKSuYKi64QL8Fgc9QKBgQD34aCF1ps93su8q1w2uFe5eZSvu/o66oL5"
+        + "V0wLPQeCZ1FZV4661FlP5nEHEIGAtEkWcSPoTCgWE7fPCTKMyKbhPBZ6"
+        + "i1R8jSjgo64eK7OmdZFuo38L+iE1YvH7YnoBJDvMpPG+qFGQiaiD3+Fa"
+        + "5Z8GkotmXoB7VSVkAUw7/s9JKgOBhQACgYEA8ggOwCuinqdrKMbfLSLF"
+        + "lpGn22HbngJHgTZ5uOh9DrXhWvNBzLiYyidC45T63YxTAESslvxgE7UI"
+        + "YIWPzKyDQB5inF+UIy9Q5LiSgzYICx6o+Q+nn7FpiysC75r4li81rY4e"
+        + "2BgWXi7dHs7tquPWinDs5JA7AkrDM9PbvdvOC+qjHjAcMBoGA1UdEQEB"
+        + "/wQQMA6BDHJmY0A4MjIuTmFtZTAJBgcqhkjOOAQDAzAAMC0CFQCAUA72"
+        + "3BIXNluugYcScXeb9vx5vAIUYreCA5ljANvzSsD0ofI+xph4//IwggKU"
+        + "MIICU6ADAgECAgICKzAJBgcqhkjOOAQDMB0xGzAZBgNVBAoTEkNlcnRp"
+        + "ZmljYXRlIElzc3VlcjAjFw0wNjA5MDUxMTAwMjNaGBIyMzM2MTAxMzE0"
+        + "MDQxOC4xMlowHTEbMBkGA1UEChMSQ2VydGlmaWNhdGUgSXNzdWVyMIIB"
+        + "uDCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdS"
+        + "PO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/Jm"
+        + "YLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1"
+        + "VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuE"
+        + "C/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdR"
+        + "WVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOu"
+        + "HiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6A"
+        + "e1UlZAFMO/7PSSoDgYUAAoGBAPIIDsArop6nayjG3y0ixZaRp9th254C"
+        + "R4E2ebjofQ614VrzQcy4mMonQuOU+t2MUwBErJb8YBO1CGCFj8ysg0Ae"
+        + "YpxflCMvUOS4koM2CAseqPkPp5+xaYsrAu+a+JYvNa2OHtgYFl4u3R7O"
+        + "7arj1opw7OSQOwJKwzPT273bzgvqox4wHDAaBgNVHREBAf8EEDAOgQxy"
+        + "ZmNAODIyLk5hbWUwCQYHKoZIzjgEAwMwADAtAhUAgFAO9twSFzZbroGH"
+        + "EnF3m/b8ebwCFGK3ggOZYwDb80rA9KHyPsaYeP/y";
+
+    /**
+     * Base64 encoded X.509 CRL.
+     */
+    private static String x509crl = 
+          "MIHWMIGWAgEBMAkGByqGSM44BAMwFTETMBEGA1UEChMKQ1JMIElzc3Vl"
+        + "chcNMDYwOTA1MDk1MzA4WhcNMDYwOTA1MDk1NDQ4WjBAMD4CAgIrFw0w"
+        + "NjA5MDUwOTUzMDhaMCkwCgYDVR0VBAMKAQEwGwYDVR0YBBQYEjIwMDYw"
+        + "OTA1MDk1MzA4Ljg5WqAPMA0wCwYDVR0UBAQCAhFcMAkGByqGSM44BAMD"
+        + "MAAwLQIUJ1KAJumw8mOpGXT/FS5K9WwOBRICFQCR+ez59x9GH3sKoByC"
+        + "IooeR20Q3Q==";
+
+    /**
+     * Base64 encoded X.509 Certificate.
+     */
+    private static String x509cert = 
+          "MIICkzCCAlOgAwIBAgICAiswCQYHKoZIzjgEAzAdMRswGQYDVQQKExJD"
+        + "ZXJ0aWZpY2F0ZSBJc3N1ZXIwIxcNMDYwOTA4MDU1NzUxWhgSMjMzNjEx"
+        + "MTAxMTM4NTUuNjJaMB0xGzAZBgNVBAoTEkNlcnRpZmljYXRlIElzc3Vl"
+        + "cjCCAbgwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OBHXUSKVLfSpwu7OTn"
+        + "9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9jVj6v8X1ujD2y5tVbNeBO4Ad"
+        + "NG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX58aophUPBPuD9tPF"
+        + "HsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8VIwvMspK5"
+        + "gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9"
+        + "B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyN"
+        + "KOCjrh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaS"
+        + "i2ZegHtVJWQBTDv+z0kqA4GFAAKBgQDyCA7AK6Kep2soxt8tIsWWkafb"
+        + "YdueAkeBNnm46H0OteFa80HMuJjKJ0LjlPrdjFMARKyW/GATtQhghY/M"
+        + "rINAHmKcX5QjL1DkuJKDNggLHqj5D6efsWmLKwLvmviWLzWtjh7YGBZe"
+        + "Lt0ezu2q49aKcOzkkDsCSsMz09u9284L6qMeMBwwGgYDVR0RAQH/BBAw"
+        + "DoEMcmZjQDgyMi5OYW1lMAkGByqGSM44BAMDLwAwLAIUO+JWKWai/8Si"
+        + "2oEfhKSobLttYeYCFFO5YVDvtnmVVnvQTtUvrPpsaxJR";
+
+    /**
+     * Base64 encoded Private Key used for data signing.
+     * This data is not directly used in the test, but it could be
+     * useful in future in case of implementation of additional 
+     * testing data structures.
+     */
+    private static String b64PrivateKeySpec =
+          "MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s"
+        + "5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7"
+        + "gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P2"
+        + "08UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yy"
+        + "krmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdM"
+        + "Cz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotU"
+        + "fI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWf"
+        + "BpKLZl6Ae1UlZAFMO/7PSSoEFgIUS24w346zv1ic3wsLOHzxQnf9aX0=";
 
     /**
      * Base64 encoded Public Key for signature verification.
-     * Key corresponds to the CRLs and Certificates in PKCS7 SignedObject.
      */
     private static String b64PublicKeySpec =
           "MIIBuDCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2"
@@ -107,10 +195,10 @@
         + "ouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0H"
         + "gmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o"
         + "4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKL"
-        + "Zl6Ae1UlZAFMO/7PSSoDgYUAAoGBAPBBWamz9YtVRtOOQz1/oJQMZzrN"
-        + "wjyol/b56lmw4eBFQDR4AqvX8LLhTKHTtTk3NLQOwmN/OjyShqaXBC5b"
-        + "2n6D8OkLKefffNBO5sGunXk5ncHY1x/bj+/54meIVQPsR4hV5eKCXq6K"
-        + "v/6XDTgo6O2bo2HPeeJA4slLBgbD9Lmn";
+        + "Zl6Ae1UlZAFMO/7PSSoDgYUAAoGBAPIIDsArop6nayjG3y0ixZaRp9th"
+        + "254CR4E2ebjofQ614VrzQcy4mMonQuOU+t2MUwBErJb8YBO1CGCFj8ys"
+        + "g0AeYpxflCMvUOS4koM2CAseqPkPp5+xaYsrAu+a+JYvNa2OHtgYFl4u"
+        + "3R7O7arj1opw7OSQOwJKwzPT273bzgvq";
 
     /**
      * The name of the algorithm used for Certificate/CRL signing.
@@ -140,8 +228,32 @@
         }
     }
 
+    // array contains allowed PEM delimiters
+    private static String[][] good = {
+        {"-----BEGIN\n", "\n-----END"},
+        {"-----BEGIN-----\n", "\n-----END-----"},
+        {"-----BEGIN PEM ENCODED DATA STRUCTURE-----\n", "\n-----END-----"},
+        {"-----BEGIN MEANINGLESS SEPARATOR\n", "\n-----END PEM"},
+    };
+
+    // array contains not allowed PEM delimiters
+    private static String[][] bad = {
+        {"----BEGI\n", "\n-----END"},
+        {"-----BEGI\n", "\n----END"},
+        {"-----BEGI\n", "\n-----END"},
+        {"-----BEGIN\n", "\n-----EN"},
+        {"-----BEGIN", "\n-----END"},
+        {"-----BEGIN\n", "-----END"},
+    };
+
+    // array contains bad PEM encoded content.
+    private static String[] bad_content = {
+        "MIIHDwYJ", "ABCD", "\r\n\r\n", "\n\r", ""
+    };
+
     /**
      * generateCRLs method testing.
+     * Generates CRLs on the base of PKCS7 SignedData Object
      */
     public void testGenerateCRLs() throws Exception {
         CertificateFactory factory = CertificateFactory.getInstance("X.509");
@@ -164,6 +276,454 @@
     }
 
     /**
+     * generateCRL/generateCertificate method testing.
+     * Tries to generates single CRL/Certificate 
+     * on the base of PKCS7 SignedData Object.
+     */
+    public void testGenerateCRL() throws Exception {
+        CertificateFactory factory = CertificateFactory.getInstance("X.509");
+
+        ByteArrayInputStream bais = new ByteArrayInputStream(
+                Base64.decode(pkcs7so.getBytes()));
+        try {
+            factory.generateCRL(bais);
+            fail("Expected exception was not thrown");
+        } catch (Exception e) { }
+        bais = new ByteArrayInputStream(Base64.decode(pkcs7so.getBytes()));
+        try {
+            factory.generateCertificate(bais);
+            fail("Expected exception was not thrown");
+        } catch (Exception e) { }
+    }
+
+    /**
+     * Generates CRLs on the base of PEM encoding.
+     */
+    public void testGenerateBase64CRL() throws Exception {
+        CertificateFactory factory = CertificateFactory.getInstance("X.509");
+        ByteArrayInputStream bais;
+        
+        for (int i=0; i<good.length; i++) {
+            bais = new ByteArrayInputStream(
+                    (good[i][0] + x509crl + good[i][1]).getBytes());
+
+            X509CRL crl = (X509CRL) factory.generateCRL(bais);
+            assertNotNull("Factory returned null on correct data", crl);
+
+            if (publicKey != null) {
+                // verify the signatures
+                crl.verify(publicKey);
+            }
+        }
+
+        for (int i=0; i<bad_content.length; i++) {
+            bais = new ByteArrayInputStream(
+                    (good[0][0] + bad_content[i] + good[0][1]).getBytes());
+            try {
+                factory.generateCRL(bais);
+                fail("Expected exception was not thrown");
+            } catch (Exception e) { 
+                // e.printStackTrace();
+            }
+        }
+
+        for (int i=0; i<bad.length; i++) {
+            bais = new ByteArrayInputStream(
+                    (bad[i][0] + x509crl + bad[i][1]).getBytes());
+            try {
+                factory.generateCRL(bais);
+                fail("Expected exception was not thrown");
+            } catch (Exception e) { }
+        }
+    }
+
+    private void verifyCRLs(Collection crls) throws Exception {
+        if (publicKey != null) {
+            // verify the signatures
+            for (Iterator it = crls.iterator(); it.hasNext();) {
+                ((X509CRL) it.next()).verify(publicKey);
+            }
+        }
+    };
+
+    private void verifyCertificates(Collection certs) throws Exception {
+        if (publicKey != null) {
+            // verify the signatures
+            for (Iterator it = certs.iterator(); it.hasNext();) {
+                ((X509Certificate) it.next()).verify(publicKey);
+            }
+        }
+    };
+
+    /**
+     * generateCRLs method testing.
+     * Generates CRLs on the base of consequent 
+     * PEM X.509(ASN.1)/X.509(ASN.1)/PKCS7 forms.
+     */
+    public void testGenerateBase64CRLs() throws Exception {
+        CertificateFactory factory = CertificateFactory.getInstance("X.509");
+            
+        // ------------------------ Test Data -----------------------------
+        // encoding describing codes
+        int pem_x509 = 0, asn_x509 = 1, pem_pkcs = 2, asn_pkcs = 3, 
+            bad = 4, npe_bad = 5, npe_bad2 = 6, num_of_variants = 7;
+        // error code, marks sequences as throwing exceptions
+        int error = 999;
+        // test sequences
+        int[][] sequences = {
+            {pem_x509, pem_x509}, 
+            {pem_x509, asn_x509}, 
+            {pem_x509, asn_x509, pem_x509}, 
+            {asn_x509, asn_x509}, 
+            {asn_x509, pem_x509}, 
+            {asn_x509, pem_x509, asn_x509},
+            // -1 means that only 1 (-(-1)) CRL will be generated 
+            // on the base of this encodings sequence
+            {-1, pem_x509, pem_pkcs},
+            {-1, pem_x509, bad},
+            // {-1/*-error*/, pem_x509, npe_bad2},
+            // {-1/*-error*/, pem_x509, npe_bad},
+            {-2, pem_pkcs, pem_x509}, // 2 CRLs are expected
+            {-2, pem_pkcs, bad},
+            {-2, pem_pkcs, npe_bad},
+            {-2, pem_pkcs, npe_bad2},
+            {-1, asn_x509, pem_pkcs},
+            {-1, asn_x509, bad},
+            // {-1/*-error*/, asn_x509, npe_bad},
+            // {-1/*-error*/, asn_x509, npe_bad2},
+            // exception is expected
+            {-error, bad},
+            {-error, bad, asn_x509},
+            {-error, npe_bad}, 
+            {-error, npe_bad2}, 
+        };
+        // actual encodings
+        byte[][] data = new byte[num_of_variants][];
+        data[pem_x509] = (good[0][0] + x509crl + good[0][1] + "\n").getBytes();
+        data[asn_x509] = Base64.decode(x509crl.getBytes());
+        data[pem_pkcs] = (good[0][0] + pkcs7so + good[0][1] + "\n").getBytes();
+        data[asn_pkcs] = Base64.decode(pkcs7so.getBytes());
+        data[bad] = new byte[] {0, 1, 1, 1, 1, 1, 0, 1};
+        data[npe_bad] = new byte[] {0, 1, 1, 1, 1, 1, 1, 0};
+        data[npe_bad2] = new byte[] {48, 0, 3, 4, 5, 6, 7};
+
+        // -------------------------- Test --------------------------------
+        // Tests CRL generation on the base of sequences of heterogeneous
+        // data format
+        for (int i=0; i<sequences.length; i++) { // for each of the sequences..
+            // expected size og generated CRL collection
+            int expected_size = (sequences[i][0] < 0)
+                ? -sequences[i][0]
+                : sequences[i].length;
+            // compute the size of the encoding described by sequence
+            int encoding_size = 0;
+            //System.out.print("Sequence:");
+            for (int j=0; j<sequences[i].length; j++) {
+                //System.out.print(" "+sequences[i][j]);
+                if (sequences[i][j] >= 0) {
+                    encoding_size += data[sequences[i][j]].length;
+                }
+            }
+            //System.out.println("");
+            // create the encoding of described sequence
+            byte[] encoding = new byte[encoding_size];
+            int position = 0;
+            for (int j=0; j<sequences[i].length; j++) {
+                if (sequences[i][j] >= 0) {
+                    System.arraycopy(
+                            data[sequences[i][j]], 0, // from
+                            encoding, position, // to
+                            data[sequences[i][j]].length); // length
+                    position += data[sequences[i][j]].length;
+                }
+            }
+
+            if (expected_size == error) { // exception throwing test
+                try {
+                    factory.generateCRLs(new ByteArrayInputStream(encoding));
+                    fail("Expected exception was not thrown");
+                } catch (Exception e) { }
+            } else {
+                Collection crls =
+                    factory.generateCRLs(new ByteArrayInputStream(encoding));
+                assertNotNull("Factory returned null on correct data", crls);
+                assertEquals("The size of collection differs from expected",
+                        expected_size, crls.size());
+                verifyCRLs(crls);
+            }
+        }
+    }
+
+    /**
+     * generateCertificates method testing.
+     * Generates Certificates on the base of consequent 
+     * PEM X.509(ASN.1)/X.509(ASN.1)/PKCS7 forms.
+     */
+    public void testGenerateBase64Certificates() throws Exception {
+        CertificateFactory factory = CertificateFactory.getInstance("X.509");
+            
+        // ------------------------ Test Data -----------------------------
+        // encoding describing codes
+        int pem_x509 = 0, asn_x509 = 1, pem_pkcs = 2, asn_pkcs = 3, 
+            bad = 4, bad1 = 5, bad2 = 6, num_of_variants = 7;
+        // error code, marks sequences as throwing exceptions
+        int error = 999;
+        // test sequences
+        int[][] sequences = {
+            {pem_x509, pem_x509}, 
+            {pem_x509, asn_x509}, 
+            {pem_x509, asn_x509, pem_x509}, 
+            {asn_x509, asn_x509}, 
+            {asn_x509, pem_x509}, 
+            {asn_x509, pem_x509, asn_x509},
+            // -1 means that only 1 (-(-1)) Certificate will be generated 
+            // on the base of this encodings sequence
+            // {-1/*-error*/, pem_x509, pem_pkcs},
+            // {-1/*-error*/, pem_x509, bad},
+            {-2, pem_pkcs, pem_x509}, // 2 Certificates are expected
+            {-2, pem_pkcs, bad},
+            {-2, pem_pkcs, bad1},
+            {-2, pem_pkcs, bad2},
+            // {-1/*-error*/, asn_x509, pem_pkcs},
+            // {-1/*-error*/, asn_x509, bad},
+            // {-1/*-error*/, asn_x509, bad1},
+            // {-1/*-error*/, pem_x509, bad1},
+            // {-1/*-error*/, asn_x509, bad2},
+            // {-1/*-error*/, pem_x509, bad2},
+            // exception is expected
+            {-error, bad},
+            {-error, bad, asn_x509},
+            {-error, bad1}, 
+            {-error, bad2}, 
+        };
+        // actual encodings
+        byte[][] data = new byte[num_of_variants][];
+        data[pem_x509] = (good[0][0] + x509cert + good[0][1] + "\n").getBytes();
+        data[asn_x509] = Base64.decode(x509cert.getBytes());
+        data[pem_pkcs] = (good[0][0] + pkcs7so + good[0][1] + "\n").getBytes();
+        data[asn_pkcs] = Base64.decode(pkcs7so.getBytes());
+        data[bad] = new byte[] {0, 1, 1, 1, 1, 1, 0, 1};
+        data[bad1] = new byte[] {0, 1, 1, 1, 1, 1, 1, 0};
+        data[bad2] = new byte[] {48, 0, 3, 4, 5, 6, 7};
+
+        // -------------------------- Test --------------------------------
+        // Tests Certificate generation on the base of sequences of heterogeneous
+        // data format
+        for (int i=0; i<sequences.length; i++) { // for each of the sequences..
+            // expected size og generated Certificate collection
+            int expected_size = (sequences[i][0] < 0)
+                ? -sequences[i][0]
+                : sequences[i].length;
+            // compute the size of the encoding described by sequence
+            int encoding_size = 0;
+            //System.out.print("Sequence:");
+            for (int j=0; j<sequences[i].length; j++) {
+                //System.out.print(" "+sequences[i][j]);
+                if (sequences[i][j] >= 0) {
+                    encoding_size += data[sequences[i][j]].length;
+                }
+            }
+            //System.out.println("");
+            // create the encoding of described sequence
+            byte[] encoding = new byte[encoding_size];
+            int position = 0;
+            for (int j=0; j<sequences[i].length; j++) {
+                if (sequences[i][j] >= 0) {
+                    System.arraycopy(
+                            data[sequences[i][j]], 0, // from
+                            encoding, position, // to
+                            data[sequences[i][j]].length); // length
+                    position += data[sequences[i][j]].length;
+                }
+            }
+
+            if (expected_size == error) { // exception throwing test
+                try {
+                    factory.generateCertificates(new ByteArrayInputStream(encoding));
+                    fail("Expected exception was not thrown");
+                } catch (Exception e) { }
+            } else {
+                Collection certs =
+                    factory.generateCertificates(new ByteArrayInputStream(encoding));
+                assertNotNull("Factory returned null on correct data", certs);
+                assertEquals("The size of collection differs from expected",
+                        expected_size, certs.size());
+                verifyCertificates(certs);
+            }
+        }
+    }
+
+    /**
+     * Generates CRLs/Certificates on the base of PEM PKCS7 encoding.
+     */
+    public void testGenerateBase64PKCS7() throws Exception {
+        CertificateFactory factory = CertificateFactory.getInstance("X.509");
+        
+        ByteArrayInputStream bais;
+        for (int i=0; i<good.length; i++) {
+            bais = new ByteArrayInputStream(
+                    (good[i][0] + pkcs7so + good[i][1]).getBytes());
+            Collection crls = factory.generateCRLs(bais);
+            assertNotNull("Factory returned null on correct PKCS7 data", crls);
+            assertEquals("The size of collection differs from expected",
+                    2, crls.size());
+            if (publicKey != null) {
+                // verify the signatures
+                for (Iterator it = crls.iterator(); it.hasNext();) {
+                    ((X509CRL) it.next()).verify(publicKey);
+                }
+            }
+            bais = new ByteArrayInputStream(
+                    (good[i][0] + pkcs7so + good[i][1]).getBytes());
+            Collection certs = factory.generateCertificates(bais);
+            assertNotNull("Factory returned null on correct PKCS7 data", certs);
+            assertEquals("The size of collection differs from expected",
+                    2, certs.size());
+            if (publicKey != null) {
+                // verify the signatures
+                for (Iterator it = certs.iterator(); it.hasNext();) {
+                    ((X509Certificate) it.next()).verify(publicKey);
+                }
+            }
+        }
+
+        for (int i=0; i<bad_content.length; i++) {
+            bais = new ByteArrayInputStream(
+                    (good[0][0] + bad_content[i] + good[0][1]).getBytes());
+            try {
+                factory.generateCertificates(bais);
+                fail("Expected exception was not thrown");
+            } catch (Exception e) { }
+            bais = new ByteArrayInputStream(
+                    (good[0][0] + bad_content[i] + good[0][1]).getBytes());
+            try {
+                factory.generateCRLs(bais);
+                fail("Expected exception was not thrown");
+            } catch (Exception e) { }
+        }
+
+        for (int i=0; i<bad.length; i++) {
+            bais = new ByteArrayInputStream(
+                    (bad[i][0] + pkcs7so + bad[i][1]).getBytes());
+            try {
+                factory.generateCRLs(bais);
+                fail("Expected exception was not thrown");
+            } catch (Exception e) { }
+            bais = new ByteArrayInputStream(
+                    (bad[i][0] + pkcs7so + bad[i][1]).getBytes());
+            try {
+                factory.generateCertificates(bais);
+                fail("Expected exception was not thrown");
+            } catch (Exception e) { }
+        }
+    }
+
+    /**
+     * Generates CertPaths on the base of PEM PkiPath/PKCS7 encoding.
+     */
+    public void testGenerateBase64CertPath() throws Exception {
+        CertificateFactory factory = CertificateFactory.getInstance("X.509");
+        
+        ByteArrayInputStream bais;
+        List certificates;
+        for (int i=0; i<good.length; i++) {
+            bais = new ByteArrayInputStream(
+                    (good[i][0] + pkiPath + good[i][1]).getBytes());
+
+            certificates = factory.generateCertPath(bais).getCertificates();
+            assertEquals("The size of the list differs from expected",
+                    2, certificates.size());
+
+            if (publicKey != null) {
+                // verify the signatures
+                for (Iterator it = certificates.iterator(); it.hasNext();) {
+                    ((X509Certificate) it.next()).verify(publicKey);
+                }
+            }
+
+            bais = new ByteArrayInputStream(
+                    (good[i][0] + pkiPath + good[i][1]).getBytes());
+
+            certificates = 
+                factory.generateCertPath(bais, "PkiPath").getCertificates();
+            assertEquals("The size of the list differs from expected",
+                    2, certificates.size());
+
+            if (publicKey != null) {
+                // verify the signatures
+                for (Iterator it = certificates.iterator(); it.hasNext();) {
+                    ((X509Certificate) it.next()).verify(publicKey);
+                }
+            }
+
+            bais = new ByteArrayInputStream(
+                    (good[i][0] + pkcs7so + good[i][1]).getBytes());
+
+            certificates = 
+                factory.generateCertPath(bais, "PKCS7").getCertificates();
+            assertEquals("The size of the list differs from expected",
+                    2, certificates.size());
+
+            if (publicKey != null) {
+                // verify the signatures
+                for (Iterator it = certificates.iterator(); it.hasNext();) {
+                    ((X509Certificate) it.next()).verify(publicKey);
+                }
+            }
+        }
+
+        // testing empty PkiPath structure (ASN.1 such as 0x30, 0x00)
+        bais = new ByteArrayInputStream(
+                (good[0][0] + "MAB=" + good[0][1]).getBytes()); // "MABCDEFG"
+        assertEquals("The size of the list differs from expected",
+                0, factory.generateCertPath(bais, "PkiPath")
+                                .getCertificates().size());
+
+        // testing with bad PEM content
+        for (int i=0; i<bad_content.length; i++) {
+            bais = new ByteArrayInputStream(
+                    (good[0][0] + bad_content[i] + good[0][1]).getBytes());
+            try {
+                factory.generateCertPath(bais);
+                fail("Expected exception was not thrown");
+            } catch (Exception e) { }
+            bais = new ByteArrayInputStream(
+                    (good[0][0] + bad_content[i] + good[0][1]).getBytes());
+            try {
+                factory.generateCertPath(bais, "PkiPath");
+                fail("Expected exception was not thrown");
+            } catch (Exception e) { }
+            bais = new ByteArrayInputStream(
+                    (good[0][0] + bad_content[i] + good[0][1]).getBytes());
+            try {
+                factory.generateCertPath(bais, "PKCS7");
+                fail("Expected exception was not thrown");
+            } catch (Exception e) { }
+        }
+
+        for (int i=0; i<bad.length; i++) {
+            bais = new ByteArrayInputStream(
+                    (bad[i][0] + pkiPath + bad[i][1]).getBytes());
+            try {
+                factory.generateCertPath(bais);
+                fail("Expected exception was not thrown");
+            } catch (Exception e) { }
+            bais = new ByteArrayInputStream(
+                    (bad[i][0] + pkiPath + bad[i][1]).getBytes());
+            try {
+                factory.generateCertPath(bais, "PkiPath");
+                fail("Expected exception was not thrown");
+            } catch (Exception e) { }
+            bais = new ByteArrayInputStream(
+                    (bad[i][0] + pkcs7so + bad[i][1]).getBytes());
+            try {
+                factory.generateCertPath(bais, "PKCS7");
+                fail("Expected exception was not thrown");
+            } catch (Exception e) { }
+        }
+    }
+
+    /**
      * generateCertificates method testing.
      */
     public void testGenerateCertificates() throws Exception {
@@ -209,6 +769,12 @@
                 ((X509Certificate) i.next()).verify(publicKey);
             }
         }
+
+        // testing empty PkiPath structure (ASN.1 such as 0x30, 0x00)
+        bais = new ByteArrayInputStream(new byte[] {(byte) 0x30, 0x00});
+        assertEquals("The size of the list differs from expected",
+                0, factory.generateCertPath(bais, "PkiPath")
+                                .getCertificates().size());
     }
 
 }



Mime
View raw message