You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by ml...@apache.org on 2006/05/30 14:26:43 UTC

svn commit: r410258 [1/2] - /incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/

Author: mloenko
Date: Tue May 30 05:26:43 2006
New Revision: 410258

URL: http://svn.apache.org/viewvc?rev=410258&view=rev
Log:
applied patch from HARMONY-531
[classlib] CertificateFactory source files are poorly documented

Modified:
    incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/Cache.java
    incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/DRLCertFactory.java
    incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CRLEntryImpl.java
    incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CRLImpl.java
    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/main/java/common/org/apache/harmony/security/provider/cert/X509CertImpl.java
    incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CertPathImpl.java

Modified: incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/Cache.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/Cache.java?rev=410258&r1=410257&r2=410258&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/Cache.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/Cache.java Tue May 30 05:26:43 2006
@@ -24,46 +24,109 @@
 import java.util.Arrays;
 
 /**
- * Makes correspondences between Objects and arrays of bytes.
- * Arrays of bytes should not be less than prefix_size.
+ * The caching mechanism designed to speed up the process
+ * of Certificates/CRLs generation in the case of their repeated
+ * generation.
+ *
+ * It keeps correspondences between Objects (Certificates or CLRs)
+ * and arrays of bytes on the base of which the Objects have been generated,
+ * and provides the means to determine whether it contains the object built on
+ * the base of particular encoded form or not. If there are such
+ * objects they are returned from the cache, if not - newly generated
+ * objects can be saved in the cache.<br>
+ *
+ * The process of Certificate/CRL generation
+ * (implemented in <code>X509CertFactoryImpl</code>) is accompanied with
+ * prereading of the beginning of encoded form. This prefix is used to determine
+ * whether provided form is PEM encoding or not.<br>
+ *
+ * So the use of the prefix is the first point to (approximately)
+ * determine whether object to be generated is in the cache or not.
+ *
+ * The failure of the predetermination process tells us that there were not
+ * object generated from the encoded form with such prefix and we should
+ * generate (decode) the object. If predetermination is successful,
+ * we conduct the accurate search on the base of whole encoded form. <br>
+ *
+ * So to speed up the object generation process this caching mechanism provides
+ * the following functionality:<br>
+ *
+ *      1. With having of the beginning of the encoded form (prefix)
+ * it is possible to predetermine whether object has already been
+ * generated on the base of the encoding with the SIMILAR prefix or not.
+ * This process is not computationally expensive and takes a little time.
+ * But it prevents us from use of expensive full encoding
+ * search in the case of its failure.<br>
+ *
+ *      2. If predetermination ends with success, the whole encoding
+ * form should be provided to make the final answer: whether object has
+ * already been generated on the base of this PARTICULAR encoded form or not.
+ * If it is so - the cached object is returned from the cache,
+ * if not - new object should be generated and saved in the cache.<br>
+ *
+ * Note: The length of the prefixes of the encoded forms should not be
+ * less than correspondance (default value is 28).
  */
 public class Cache {
-    
+
+    // Hash code consist of 6 bytes: AABB00
+    // where:
+    // AA - 2 bytes for prefix hash
+    //      value generated on the base of the prefix of encoding
+    // BB - 2 bytes for tail hash
+    //      value generated on the base of the tail of encoding
+    // 00 - 2 reserved bytes equals to 0
+    //
+    // Note, that it is possible for 2 different arrays to have
+    // the similar hash codes.
+
+    // The masks to work with hash codes:
+    // the hash code without the reserved bytes
+    private static final long HASH_MASK = 0xFFFFFFFFFFFF0000L;
+    // the hash code of the prefix
+    private static final long PREFIX_HASH_MASK = 0xFFFFFFFF00000000L;
+    // the index value contained in reserved bytes
+    private static final int  INDEX_MASK = 0x00FFFF;
+
     // size of the cache
     private final int cache_size;
+    // the number of bytes which will be used for array hash generation.
+    private final int prefix_size;
+
+    // The following 3 arrays contain the information about cached objects.
+    // This information includes: hash of the array, encoded form of the object,
+    // and the object itself.
+    // The hash-encoding-object correspondence is made by means of index
+    // in the particular array. I.e. for index N hash contained in hashes[N]
+    // corresponds to the encoding contained in encodings[N] which corresponds
+    // to the object cached at cache[N]
+
     // array containing the hash codes of encodings
-    // hash has the following structure:
-    // it consist of 6 bytes: 
-    //      2 bytes for prefix hash
-    //      2 bytes for tail hash
-    //      2 reserved bytes (equals 0 in this array)
     private final long[] hashes;
-    // array containing hash<->index correspondings:
-    // reserved 2 bytes contains the value of the index in cache table
-    private final long[] hashes_idx;
     // array containing the encodings of the cached objects
     private final byte[][] encodings;
-    // array containing the cached certificates
+    // array containing the cached objects
     private final Object[] cache;
-    // how many times cached value had been demanded
-    //private long[] demanded = new long[cache_size];
 
-    // the number of bytes which will be used for array hash generation.
-    private int prefix_size;
-    
+    // This array is used to speed up the process of the search in the cache.
+    // This is an ordered array of the hash codes from 'hashes' array (described
+    // above) with last 2 (reserved) bytes equals to the index of
+    // the hash in the 'hashes' array. I.e. hash code ABCD00 with index 10 in
+    // the hashes array will be represented in this array as ABCD0A (10==0x0A)
+    // So this array contains ordered <hash to index> correspondences.
+    // Note, that every item in this array is unique.
+    private final long[] hashes_idx;
+
+    // the index of the last cached object
     private int last_cached = 0;
+    // cache population indicator
     private boolean cache_is_full = false;
 
-    private static final int  INDEX_MASK = 0x00FFFF;
-    private static final long HASH_MASK = 0xFFFFFFFFFFFF0000L;
-    private static final long PREFIX_HASH_MASK = 0xFFFFFFFF00000000L;
-
     /**
-     * Creates the Cache object. Capasity of the cache is size, 
-     * 
-     * @param   size:   capacity of the cache. 
-     * @param   pref_size:  the number of bytes which will be used
-     * for array hash generation.
+     * Creates the Cache object.
+     * @param pref_size specifyes how many leading/trailing bytes of object's
+     * encoded form will be used for hash computation
+     * @param size capacity of the cache to be created.
      */
     public Cache(int pref_size, int size) {
         cache_size = size;
@@ -74,47 +137,113 @@
         cache = new Object[cache_size];
     }
 
+    /**
+     * Creates the Cache object of size of 900.
+     * @param pref_size specifyes how many leading/trailing bytes of object's
+     * encoded form will be used for hash computation
+     */
     public Cache(int pref_size) {
         this(pref_size, 900);
     }
-    
+
+    /**
+     * Creates the Cache object of size of 900.
+     */
     public Cache() {
         this(28, 900);
     }
 
-    // Returns the hash value of the array (which length should be
-    // greater of equal to prefix_size).
+    /**
+     * Returns the hash code for the array. This code is used to
+     * predetermine whether the object was built on the base of the
+     * similar encoding or not (by means of <code>contains(long)</code> method),
+     * to exactly determine whether object is contained in the cache or not,
+     * and to put the object in the cache.
+     * Note: parameter array should be of length not less than
+     * specified by <code>prefix_size</code> (default 28)
+     * @param arr the byte array containing at least prefix_size leading bytes
+     * of the encoding.
+     * @return hash code for specified encoding prefix
+     */
     public long getHash(byte[] arr) {
         long hash = 0;
         for (int i=1; i<prefix_size; i++) {
             hash += (arr[i] & 0xFF);
         } // it takes about 2 bytes for prefix_size == 28
 
-        // 2 bytes for array prefix hash, 2 for suffix hash, 2 bytes for index
+        // shift to the correct place
         hash = hash << 32;
-        //System.out.println("getHash: "+Long.toHexString(hash));
         return hash;
     }
-    
-    public long getSuffHash(byte[] arr) {
-        long hash_addon = 0;
-        for (int i=arr.length-1; i>arr.length - prefix_size; i--) {
-            hash_addon += (arr[i] & 0xFF);
+
+    /**
+     * Checks if there are any object in the cache generated
+     * on the base of encoding with prefix corresponding
+     * to the specified hash code.
+     * @param prefix_hash the hash code for the prefix
+     * of the encoding (retrieved by method <code>getHash(byte[]))</code>
+     * @return false if there were not any object generated
+     * on the base of encoding with specified hash code, true
+     * otherwise.
+     */
+    public boolean contains(long prefix_hash) {
+        int idx = -1*Arrays.binarySearch(hashes_idx, prefix_hash)-1;
+        if (idx == cache_size) {
+            return false;
+        } else {
+            return (hashes_idx[idx] & PREFIX_HASH_MASK) == prefix_hash;
         }
-        return hash_addon << 16;
     }
-    
-    public void put(long hash, byte[] encoding, Object cert) {
-        // index pointing to the item of the table to be overwritten
-        int index;
-        // TODO: make throw out line:
+
+    /**
+     * Returns the object built on the base on the specified encoded
+     * form if it is contained in the cache and null otherwise.
+     * This method is computationally expensive and should be called only if
+     * the method <code>contains(long)</code> for the hash code returned true.
+     * @param hash the hash code for the prefix of the encoding
+     * (retrieved by method <code>getHash(byte[])</code>)
+     * @param encoding encoded form of the required object.
+     * @return the object corresponding to specified encoding or null if
+     * there is no such correspondence.
+     */
+    public Object get(long hash, byte[] encoding) {
+        hash |= getSuffHash(encoding);
+        int idx = -1*Arrays.binarySearch(hashes_idx, hash)-1;
+        if (idx == cache_size) {
+            return null;
+        }
+        while ((hashes_idx[idx] & HASH_MASK) == hash) {
+            int i = (int) (hashes_idx[idx] & INDEX_MASK) - 1;
+            if (Arrays.equals(encoding, encodings[i])) {
+                return cache[i];
+            }
+            idx++;
+            if (idx == cache_size) {
+                return null;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Puts the object into the cache.
+     * @param hash hash code for the prefix of the encoding
+     * @param encoding the encoded form of the object
+     * @param object the object to be saved in the cache
+     */
+    public void put(long hash, byte[] encoding, Object object) {
+        // check for empty space in the cache
         if (last_cached == cache_size) {
+            // so cache is full, will erase the first entry in the
+            // cache (oldest entry). it could be better to throw out
+            // rarely used value instead of oldest one..
             last_cached = 0;
             cache_is_full = true;
         }
-        index = last_cached++;
+        // index pointing to the item of the table to be overwritten
+        int index = last_cached++;
 
-        // improove the hash value (now we know the tail of encoding):
+        // improve the hash value with info from the tail of encoding
         hash |= getSuffHash(encoding);
 
         if (cache_is_full) {
@@ -136,16 +265,16 @@
                     // hash and the same index in hash table
                     System.out.println("WARNING: ");
                     System.out.println(">> idx: "+idx+" new_idx: "+new_idx);
-                } 
+                }
             } else {
                 new_idx = -(new_idx + 1);
                 // replace in sorted array
                 if (new_idx > idx) {
-                    System.arraycopy(hashes_idx, idx+1, hashes_idx, idx, 
+                    System.arraycopy(hashes_idx, idx+1, hashes_idx, idx,
                             new_idx - idx - 1);
                     hashes_idx[new_idx-1] = new_hash_idx;
                 } else if (idx > new_idx) {
-                    System.arraycopy(hashes_idx, new_idx, hashes_idx, new_idx+1, 
+                    System.arraycopy(hashes_idx, new_idx, hashes_idx, new_idx+1,
                             idx - new_idx);
                     hashes_idx[new_idx] = new_hash_idx;
                 } else { // idx == new_idx
@@ -160,10 +289,10 @@
                 idx = -(idx + 1);
             }
             idx = idx - 1;
-            if (idx != cache_size - index - 1) { 
-                // if not in cell containing 0, do copy:
-                System.arraycopy(hashes_idx, cache_size - index, 
-                        hashes_idx, cache_size - index - 1, 
+            if (idx != cache_size - index - 1) {
+                // if not in the cell containing 0 (free cell), do copy:
+                System.arraycopy(hashes_idx, cache_size - index,
+                        hashes_idx, cache_size - index - 1,
                         idx - (cache_size - index) + 1);
             }
             hashes_idx[idx] = idx_hash;
@@ -171,58 +300,19 @@
         // overwrite the values in the tables:
         hashes[index] = hash;
         encodings[index] = encoding;
-        cache[index] = cert;
-    }
-   
-    private boolean arrEquals(byte[] arr1, byte[] arr2) {
-        return Arrays.equals(arr1, arr2);
-        /*
-        // comparison from the tail:
-        int length = arr1.length;
-        if (length != arr2.length) {
-            return false;
-        }
-        while (length > 0) {
-            if (arr1[--length] != arr2[length]) {
-                return false;
-            }
-        }
-        return true;
-        //*/
+        cache[index] = object;
     }
 
-    public Object get(long hash, byte[] encoding) {
-        hash |= getSuffHash(encoding);
-        int idx = -1*Arrays.binarySearch(hashes_idx, hash)-1;
-        if (idx == cache_size) {
-            return null;
-        }
-        while ((hashes_idx[idx] & HASH_MASK) == hash) {
-            int i = (int) (hashes_idx[idx] & INDEX_MASK) - 1;
-            if (arrEquals(encoding, encodings[i])) {
-                // Uncomment to see the number of objects 
-                // retrieved from the cache:
-                //
-                // if (XXX%2500 == 0)
-                //     System.out.println(">> "+XXX);
-                // XXX++;
-                return cache[i];
-            }
-            idx++;
-            if (idx == cache_size) {
-                return null;
-            }
-        }
-        return null;
-    }
-    
-    public boolean contains(long prefix_hash) {
-        int idx = -1*Arrays.binarySearch(hashes_idx, prefix_hash)-1;
-        if (idx == cache_size) {
-            return false;
-        } else {
-            return (hashes_idx[idx] & PREFIX_HASH_MASK) == prefix_hash;
+    // Returns the hash code built on the base of the tail of the encoded form
+    // @param arr - the array containing at least prefix_size trailing bytes
+    // of encoded form
+    private long getSuffHash(byte[] arr) {
+        long hash_addon = 0;
+        for (int i=arr.length-1; i>arr.length - prefix_size; i--) {
+            hash_addon += (arr[i] & 0xFF);
         }
+        return hash_addon << 16;
     }
+
 }
 

Modified: incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/DRLCertFactory.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/DRLCertFactory.java?rev=410258&r1=410257&r2=410258&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/DRLCertFactory.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/DRLCertFactory.java Tue May 30 05:26:43 2006
@@ -26,7 +26,8 @@
 
 
 /**
- * DRLCertFactory
+ * Master class (provider) for X509 Certificate Factory
+ * Implementation.
  */
 public final class DRLCertFactory extends Provider {
 
@@ -35,12 +36,21 @@
      */
     private static final long serialVersionUID = -7269650779605195879L;
 
+    /**
+     * Constructs the instance of the certificate factory provider.
+     */
     public DRLCertFactory() {
-        super("DRLCertFactory", 1.0, "DRL Certificate Factory");
+        // specification of the provider name, version, and description.
+        super("DRLCertFactory", 1.0,
+                "Certificate Factory supports CRLs and Certificates "
+                + "in (PEM) ASN.1 DER encoded form, and Certification Paths "
+                + "in PkiPath and PKCS7 formats.");
         AccessController.doPrivileged(new java.security.PrivilegedAction() {
             public Object run() {
-                put("CertificateFactory.X509", 
+                // register the service
+                put("CertificateFactory.X509",
                     "org.apache.harmony.security.provider.cert.X509CertFactoryImpl");
+                // mapping the alias
                 put("Alg.Alias.CertificateFactory.X.509", "X509");
                     return null;
             }

Modified: incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CRLEntryImpl.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CRLEntryImpl.java?rev=410258&r1=410257&r2=410258&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CRLEntryImpl.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CRLEntryImpl.java Tue May 30 05:26:43 2006
@@ -33,27 +33,51 @@
 import org.apache.harmony.security.x509.Extensions;
 import org.apache.harmony.security.x509.TBSCertList;
 
-
 /**
- * X509CRLEntryImpl
+ * Implementation of X509CRLEntry. It wraps the instance
+ * of org.apache.harmony.security.x509.TBSCertList.RevokedCertificate
+ * obtained during the decoding of TBSCertList substructure
+ * of the CertificateList structure which is an X.509 form of CRL.
+ * (see RFC 3280 at http://www.ietf.org/rfc/rfc3280.txt)
+ * Normally the instances of this class are constructed by involving
+ * X509CRLImpl object.
+ * @see org.apache.harmony.security.x509.TBSCertList
+ * @see org.apache.harmony.security.provider.cert.X509CRLImpl
+ * @see java.security.cert.X509CRLEntry
  */
 public class X509CRLEntryImpl extends X509CRLEntry {
 
+    // the crl entry object to be wrapped in X509CRLEntry
     private final TBSCertList.RevokedCertificate rcert;
+    // the extensions of the entry
     private final Extensions extensions;
+    // issuer of the revoked certificate described by this crl entry
     private final X500Principal issuer;
 
+    // encoded form of this revoked certificate entry
     private byte[] encoding;
-    
-    public X509CRLEntryImpl(TBSCertList.RevokedCertificate rcert, 
+
+    /**
+     * Creates an instance on the base of existing
+     * <code>TBSCertList.RevokedCertificate</code> object and
+     * information about the issuer of revoked certificate.
+     * If specified issuer is null, it is supposed that issuer
+     * of the revoked certificate is the same as for involving CRL.
+     */
+    public X509CRLEntryImpl(TBSCertList.RevokedCertificate rcert,
             X500Principal issuer) {
         this.rcert = rcert;
         this.extensions = rcert.getCrlEntryExtensions();
         this.issuer = issuer;
     }
 
+    // ---------------------------------------------------------------------
+    // ------ java.security.cert.X509CRLEntry method implementations -------
+    // ---------------------------------------------------------------------
+
     /**
-     * getEncoded
+     * @see java.security.cert.X509CRLEntry#getEncoded()
+     * method documentation for more info
      */
     public byte[] getEncoded() throws CRLException {
         if (encoding == null) {
@@ -65,43 +89,53 @@
     }
 
     /**
-     * getSerialNumber
+     * @see java.security.cert.X509CRLEntry#getSerialNumber()
+     * method documentation for more info
      */
     public BigInteger getSerialNumber() {
         return rcert.getUserCertificate();
     }
 
+    /**
+     * @see java.security.cert.X509CRLEntry#getCertificateIssuer()
+     * method documentation for more info
+     */
     public X500Principal getCertificateIssuer() {
         return issuer;
     }
 
     /**
-     * getRevocationDate
+     * @see java.security.cert.X509CRLEntry#getRevocationDate()
+     * method documentation for more info
      */
     public Date getRevocationDate() {
         return rcert.getRevocationDate();
     }
 
     /**
-     * @com.intel.drl.spec_ref
+     * @see java.security.cert.X509CRLEntry#hasExtensions()
+     * method documentation for more info
      */
     public boolean hasExtensions() {
         return (extensions != null) && (extensions.size() != 0);
     }
 
     /**
-     * toString
-     * FIXME: recognize and print the extensions 
+     * @see java.security.cert.X509CRLEntry#toString()
+     * method documentation for more info
      */
     public String toString() {
-        // FIXME
-        return "X509CRLEntryImpl:...";
+        return "X509CRLEntryImpl: "+rcert.toString();
     }
 
-    // 
-    // ----- java.security.cert.X509Extension methods implementations ----
-    //
+    // ---------------------------------------------------------------------
+    // ------ java.security.cert.X509Extension method implementations ------
+    // ---------------------------------------------------------------------
 
+    /**
+     * @see java.security.cert.X509Extension#getNonCriticalExtensionOIDs()
+     * method documentation for more info
+     */
     public Set getNonCriticalExtensionOIDs() {
         if (extensions == null) {
             return null;
@@ -109,6 +143,10 @@
         return extensions.getNonCriticalExtensions();
     }
 
+    /**
+     * @see java.security.cert.X509Extension#getCriticalExtensionOIDs()
+     * method documentation for more info
+     */
     public Set getCriticalExtensionOIDs() {
         if (extensions == null) {
             return null;
@@ -116,6 +154,10 @@
         return extensions.getCriticalExtensions();
     }
 
+    /**
+     * @see java.security.cert.X509Extension#getExtensionValue(String)
+     * method documentation for more info
+     */
     public byte[] getExtensionValue(String oid) {
         if (extensions == null) {
             return null;
@@ -124,17 +166,15 @@
         return (ext == null) ? null : ext.getRawExtnValue();
     }
 
+    /**
+     * @see java.security.cert.X509Extension#hasUnsupportedCriticalExtension()
+     * method documentation for more info
+     */
     public boolean hasUnsupportedCriticalExtension() {
         if (extensions == null) {
             return false;
         }
         return extensions.hasUnsupportedCritical();
     }
-
-
-    /**
-     * The main method.
-     */
-    public static void main(String[] args) {
-    }
 }
+

Modified: incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CRLImpl.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CRLImpl.java?rev=410258&r1=410257&r2=410258&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CRLImpl.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CRLImpl.java Tue May 30 05:26:43 2006
@@ -50,39 +50,69 @@
 import org.apache.harmony.security.x509.Extensions;
 import org.apache.harmony.security.x509.TBSCertList;
 
-
 /**
- * X509CRLImpl
+ * This class is an implementation of X509CRL. It wraps
+ * the instance of org.apache.harmony.security.x509.CertificateList
+ * built on the base of provided ASN.1 DER encoded form of
+ * CertificateList structure (as specified in RFC 3280
+ * http://www.ietf.org/rfc/rfc3280.txt).
+ * Implementation supports work with indirect CRLs.
+ * @see org.apache.harmony.security.x509.CertificateList
+ * @see java.security.cert.X509CRL
  */
 public class X509CRLImpl extends X509CRL {
-    
+
+    // the core object to be wrapped in X509CRL
     private final CertificateList crl;
+
+    // To speed up access to the info, the following fields
+    // cache values retrieved from the CertificateList object
     private final TBSCertList tbsCertList;
+    private byte[] tbsCertListEncoding;
     private final Extensions extensions;
-
-    private boolean isIndirectCRL;
-    // cached values
     private X500Principal issuer;
-    private byte[] encoding;
-    private byte[] tbsCertListEncoding;
     private ArrayList entries;
     private int entriesSize;
-    private int nonIndirectEntriesSize;
-    private boolean entriesRetrieved;
     private byte[] signature;
     private String sigAlgOID;
     private String sigAlgName;
     private byte[] sigAlgParams;
+
+    // encoded form of crl
+    private byte[] encoding;
+
+    // indicates whether the signature algorithm parameters are null
     private boolean nullSigAlgParams;
-    
+    // indicates whether the crl entries have already been retrieved
+    // from CertificateList object (crl)
+    private boolean entriesRetrieved;
+
+    // indicates whether this X.509 CRL is direct or indirect
+    // (see rfc 3280 http://www.ietf.org/rfc/rfc3280.txt, p 5.)
+    private boolean isIndirectCRL;
+    // if crl is indirect, this field holds an info about how
+    // many of the leading certificates in the list are issued
+    // by the same issuer as CRL.
+    private int nonIndirectEntriesSize;
+
+    /**
+     * Creates X.509 CRL by wrapping of the specified CertificateList object.
+     */
     public X509CRLImpl(CertificateList crl) {
         this.crl = crl;
         this.tbsCertList = crl.getTbsCertList();
         this.extensions = tbsCertList.getCrlExtensions();
     }
 
+    /**
+     * Creates X.509 CRL on the base of ASN.1 DER encoded form of
+     * the CRL (CertificateList structure described in RFC 3280)
+     * provided via input stream.
+     * @throws CRLException if decoding errors occur.
+     */
     public X509CRLImpl(InputStream in) throws CRLException {
         try {
+            // decode CertificateList structure
             this.crl = (CertificateList) CertificateList.ASN1.decode(in);
             this.tbsCertList = crl.getTbsCertList();
             this.extensions = tbsCertList.getCrlExtensions();
@@ -91,12 +121,23 @@
         }
     }
 
+    /**
+     * Creates X.509 CRL on the base of ASN.1 DER encoded form of
+     * the CRL (CertificateList structure described in RFC 3280)
+     * provided via array of bytes.
+     * @throws IOException if decoding errors occur.
+     */
     public X509CRLImpl(byte[] encoding) throws IOException {
-        this((CertificateList) CertificateList.ASN1.decode(encoding)); 
+        this((CertificateList) CertificateList.ASN1.decode(encoding));
     }
 
+    // ---------------------------------------------------------------------
+    // ----- java.security.cert.X509CRL abstract method implementations ----
+    // ---------------------------------------------------------------------
+
     /**
-     * getEncoded
+     * @see java.security.cert.X509CRL#getEncoded()
+     * method documentation for more info
      */
     public byte[] getEncoded() throws CRLException {
         if (encoding == null) {
@@ -108,14 +149,16 @@
     }
 
     /**
-     * getVersion
+     * @see java.security.cert.X509CRL#getVersion()
+     * method documentation for more info
      */
     public int getVersion() {
         return tbsCertList.getVersion();
     }
 
     /**
-     * getIssuerDN
+     * @see java.security.cert.X509CRL#getIssuerDN()
+     * method documentation for more info
      */
     public Principal getIssuerDN() {
         if (issuer == null) {
@@ -125,7 +168,8 @@
     }
 
     /**
-     * getIssuerX500Principal
+     * @see java.security.cert.X509CRL#getIssuerX500Principal()
+     * method documentation for more info
      */
     public X500Principal getIssuerX500Principal() {
         if (issuer == null) {
@@ -135,21 +179,26 @@
     }
 
     /**
-     * getThisUpdate
+     * @see java.security.cert.X509CRL#getThisUpdate()
+     * method documentation for more info
      */
     public Date getThisUpdate() {
         return tbsCertList.getThisUpdate();
     }
 
     /**
-     * getNextUpdate
+     * @see java.security.cert.X509CRL#getNextUpdate()
+     * method documentation for more info
      */
     public Date getNextUpdate() {
         return tbsCertList.getNextUpdate();
     }
 
-    // Retrieves the crl entries and converts it to the X509CRLEntryImpl
-    // objects
+    /*
+     * Retrieves the crl entries (TBSCertList.RevokedCertificate objects)
+     * from the TBSCertList structure and converts them to the
+     * X509CRLEntryImpl objects
+     */
     private void retirieveEntries() {
         entriesRetrieved = true;
         List rcerts = tbsCertList.getRevokedCertificates();
@@ -158,22 +207,34 @@
         }
         entriesSize = rcerts.size();
         entries = new ArrayList(entriesSize);
-        X500Principal rcertIssuer = null; // means that issuer is a CRL issuer
+        // null means that revoked certificate issuer is the same as CRL issuer
+        X500Principal rcertIssuer = null;
         for (int i=0; i<entriesSize; i++) {
-            TBSCertList.RevokedCertificate rcert = 
+            TBSCertList.RevokedCertificate rcert =
                 (TBSCertList.RevokedCertificate) rcerts.get(i);
             X500Principal iss = rcert.getIssuer();
             if (iss != null) {
+                // certificate issuer differs from CRL issuer
+                // and CRL is indirect.
                 rcertIssuer = iss;
                 isIndirectCRL = true;
+                // remember how many leading revoked certificates in the
+                // list are issued by the same issuer as issuer of CRL
+                // (these certificates are first in the list)
                 nonIndirectEntriesSize = i;
             }
             entries.add(new X509CRLEntryImpl(rcert, rcertIssuer));
         }
     }
-    
+
     /**
-     * getRevokedCertificate
+     * Searches for certificate in CRL.
+     * This method supports indirect CRLs: if CRL is indirect method takes
+     * into account serial number and issuer of the certificate,
+     * if CRL issued by CA (i.e. it is not indirect) search is done only
+     * by serial number of the specified certificate.
+     * @see java.security.cert.X509CRL#getRevokedCertificate(X509Certificate)
+     * method documentation for more info
      */
     public X509CRLEntry getRevokedCertificate(X509Certificate certificate) {
         if (certificate == null) {
@@ -187,25 +248,33 @@
         }
         BigInteger serialN = certificate.getSerialNumber();
         if (isIndirectCRL) {
+            // search in indirect crl
             X500Principal certIssuer = certificate.getIssuerX500Principal();
             if (certIssuer.equals(getIssuerX500Principal())) {
+                // certificate issuer is CRL issuer
                 certIssuer = null;
             }
             for (int i=0; i<entriesSize; i++) {
                 X509CRLEntry entry = (X509CRLEntry) entries.get(i);
+                // check the serial number of revoked certificate
                 if (serialN.equals(entry.getSerialNumber())) {
+                    // revoked certificate issuer
                     X500Principal iss = entry.getCertificateIssuer();
+                    // check the issuer of revoked certificate
                     if (certIssuer != null) {
+                        // certificate issuer is not a CRL issuer, so
+                        // check issuers for equality
                         if (certIssuer.equals(iss)) {
-                            //System.out.println("RETURN");
                             return entry;
                         }
                     } else if (iss == null) {
+                        // both certificates was issued by CRL issuer
                         return entry;
                     }
                 }
             }
         } else {
+            // search in CA's (non indirect) crl: just look up the serial number
             for (int i=0; i<entriesSize; i++) {
                 X509CRLEntry entry = (X509CRLEntry) entries.get(i);
                 if (serialN.equals(entry.getSerialNumber())) {
@@ -215,9 +284,12 @@
         }
         return null;
     }
-        
+
     /**
-     * getRevokedCertificate
+     * Method searches for CRL entry with specified serial number.
+     * The method will search only certificate issued by CRL's issuer.
+     * @see java.security.cert.X509CRL#getRevokedCertificate(BigInteger)
+     * method documentation for more info
      */
     public X509CRLEntry getRevokedCertificate(BigInteger serialNumber) {
         if (!entriesRetrieved) {
@@ -229,16 +301,17 @@
         for (int i=0; i<nonIndirectEntriesSize; i++) {
             X509CRLEntry entry = (X509CRLEntry) entries.get(i);
             if (serialNumber.equals(entry.getSerialNumber())) {
-                    return entry;
+                return entry;
             }
         }
         return null;
     }
 
     /**
-     * getRevokedCertificates
+     * @see java.security.cert.X509CRL#getRevokedCertificates()
+     * method documentation for more info
      */
-    public Set/*<? extends X509CRLEntry>*/ getRevokedCertificates() {
+    public Set<? extends X509CRLEntry> getRevokedCertificates() {
         if (!entriesRetrieved) {
             retirieveEntries();
         }
@@ -249,20 +322,22 @@
     }
 
     /**
-     * getTBSCertList
+     * @see java.security.cert.X509CRL#getTBSCertList()
+     * method documentation for more info
      */
     public byte[] getTBSCertList() throws CRLException {
         if (tbsCertListEncoding == null) {
             tbsCertListEncoding = tbsCertList.getEncoded();
         }
         byte[] result = new byte[tbsCertListEncoding.length];
-        System.arraycopy(tbsCertListEncoding, 0, 
+        System.arraycopy(tbsCertListEncoding, 0,
                 result, 0, tbsCertListEncoding.length);
         return result;
     }
 
     /**
-     * getSignature
+     * @see java.security.cert.X509CRL#getSignature()
+     * method documentation for more info
      */
     public byte[] getSignature() {
         if (signature == null) {
@@ -274,7 +349,8 @@
     }
 
     /**
-     * getSigAlgName
+     * @see java.security.cert.X509CRL#getSigAlgName()
+     * method documentation for more info
      */
     public String getSigAlgName() {
         if (sigAlgOID == null) {
@@ -288,7 +364,8 @@
     }
 
     /**
-     * getSigAlgOID
+     * @see java.security.cert.X509CRL#getSigAlgOID()
+     * method documentation for more info
      */
     public String getSigAlgOID() {
         if (sigAlgOID == null) {
@@ -302,7 +379,8 @@
     }
 
     /**
-     * getSigAlgParams
+     * @see java.security.cert.X509CRL#getSigAlgParams()
+     * method documentation for more info
      */
     public byte[] getSigAlgParams() {
         if (nullSigAlgParams) {
@@ -319,14 +397,14 @@
     }
 
     /**
-     * verify
+     * @see java.security.cert.X509CRL#verify(PublicKey key)
+     * method documentation for more info
      */
     public void verify(PublicKey key)
                      throws CRLException, NoSuchAlgorithmException,
                             InvalidKeyException, NoSuchProviderException,
                             SignatureException {
-        Signature signature = Signature.getInstance(
-                                tbsCertList.getSignature().getAlgorithm());
+        Signature signature = Signature.getInstance(getSigAlgName());
         signature.initVerify(key);
         byte[] tbsEncoding = tbsCertList.getEncoded();
         signature.update(tbsEncoding, 0, tbsEncoding.length);
@@ -336,14 +414,15 @@
     }
 
     /**
-     * verify
+     * @see java.security.cert.X509CRL#verify(PublicKey key, String sigProvider)
+     * method documentation for more info
      */
     public void verify(PublicKey key, String sigProvider)
                      throws CRLException, NoSuchAlgorithmException,
                             InvalidKeyException, NoSuchProviderException,
                             SignatureException {
         Signature signature = Signature.getInstance(
-                    tbsCertList.getSignature().getAlgorithm(), sigProvider);
+                                            getSigAlgName(), sigProvider);
         signature.initVerify(key);
         byte[] tbsEncoding = tbsCertList.getEncoded();
         signature.update(tbsEncoding, 0, tbsEncoding.length);
@@ -352,12 +431,13 @@
         }
     }
 
-    // 
-    // ----- java.security.cert.CRL methods implementations ------
-    //
-    
+    // ---------------------------------------------------------------------
+    // ------ java.security.cert.CRL abstract method implementations -------
+    // ---------------------------------------------------------------------
+
     /**
-     * isRevoked
+     * @see java.security.cert.CRL#isRevoked(Certificate)
+     * method documentation for more info
      */
     public boolean isRevoked(Certificate cert) {
         if (!(cert instanceof X509Certificate)) {
@@ -367,17 +447,21 @@
     }
 
     /**
-     * toString
+     * @see java.security.cert.CRL#toString()
+     * method documentation for more info
      */
     public String toString() {
-        // FIXME
-        return "X509CRLImpl:...";
+        return "X509CRLImpl: " + crl.toString();
     }
 
-    // 
-    // ----- java.security.cert.X509Extension methods implementations ----
-    //
+    // ---------------------------------------------------------------------
+    // ------ java.security.cert.X509Extension method implementations ------
+    // ---------------------------------------------------------------------
 
+    /**
+     * @see java.security.cert.X509Extension#getNonCriticalExtensionOIDs()
+     * method documentation for more info
+     */
     public Set getNonCriticalExtensionOIDs() {
         if (extensions == null) {
             return null;
@@ -385,6 +469,10 @@
         return extensions.getNonCriticalExtensions();
     }
 
+    /**
+     * @see java.security.cert.X509Extension#getCriticalExtensionOIDs()
+     * method documentation for more info
+     */
     public Set getCriticalExtensionOIDs() {
         if (extensions == null) {
             return null;
@@ -392,6 +480,10 @@
         return extensions.getCriticalExtensions();
     }
 
+    /**
+     * @see java.security.cert.X509Extension#getExtensionValue(String)
+     * method documentation for more info
+     */
     public byte[] getExtensionValue(String oid) {
         if (extensions == null) {
             return null;
@@ -400,6 +492,10 @@
         return (ext == null) ? null : ext.getRawExtnValue();
     }
 
+    /**
+     * @see java.security.cert.X509Extension#hasUnsupportedCriticalExtension()
+     * method documentation for more info
+     */
     public boolean hasUnsupportedCriticalExtension() {
         if (extensions == null) {
             return false;
@@ -407,3 +503,4 @@
         return extensions.hasUnsupportedCritical();
     }
 }
+

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?rev=410258&r1=410257&r2=410258&view=diff
==============================================================================
--- 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 Tue May 30 05:26:43 2006
@@ -1,414 +1,552 @@
-/*
- *  Copyright 2005 The Apache Software Foundation or its licensors, as applicable.
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-/**
-* @author Alexander Y. Kleymenov
-* @version $Revision$
-*/
-
-package org.apache.harmony.security.provider.cert;
-
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.cert.CRL;
-import java.security.cert.CRLException;
-import java.security.cert.CertPath;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactorySpi;
-import java.security.cert.X509CRL;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-
-import org.apache.harmony.luni.util.Base64;
-import org.apache.harmony.security.asn1.BerInputStream;
-
-/**
- * X509CertFactoryImpl
- */
-public class X509CertFactoryImpl extends CertificateFactorySpi {
-
-    private static Cache CERT_CASHE = new Cache();
-    private static Cache CRL_CASHE = new Cache(24);
-    
-    public X509CertFactoryImpl() {}
-
-    /**
-     * engineGenerateCertificate
-     */
-    public Certificate engineGenerateCertificate(InputStream inStream)
-            throws CertificateException {
-        try {
-            if (inStream.markSupported()) {
-            } else {
-                inStream = new RestoringInputStream(inStream);
-            }
-            inStream.mark(32);
-            byte[] buff = new byte[28];
-            if (inStream.read(buff) < 28) {
-                throw new CertificateException(
-                        "Input Stream contains not enought data.");
-            }
-            if ("-----BEGIN CERTIFICATE-----".equals(new String(buff, 0, 27))) {
-                int size = inStream.available();
-                if (size == 0) {
-                    size = 2048;
-                }
-                buff = new byte[size];
-                int index=0, ch;
-                while ((ch = inStream.read()) != '-') {
-                    if (ch == -1) {
-                        throw new CertificateException(
-                                "Incorrect Base64 encoding: unexpected EOF.");
-                    }
-                    buff[index++] = (byte) ch;
-                    if (index == size) {
-                        byte[] newbuff = new byte[size+1024];
-                        System.arraycopy(buff, 0, newbuff, 0, size);
-                        buff = newbuff;
-                    }
-                }
-                byte[] tmp = new byte[25];
-                inStream.read(tmp);
-                if (!new String(tmp).startsWith("----END CERTIFICATE-----")) {
-                    throw new CertificateException(
-                    "Incorrect Base64 encoding: 'END CERTIFICATE' expected.");
-                }
-                // skip new line: set the position to the next certificate:
-                inStream.mark(1);
-                while (((ch = inStream.read()) != -1) && (ch == '\n' || ch == '\r')) {
-                    inStream.mark(1);
-                }
-                inStream.reset();
-                buff = Base64.decode(buff, index);
-                if (buff == null) {
-                    throw new CertificateException("Incorrect Base64 encoding.");
-                }
-                long hash = CERT_CASHE.getHash(buff);
-                if (CERT_CASHE.contains(hash)) {
-                    Certificate res = (Certificate) CERT_CASHE.get(hash, buff);
-                    if (res != null) {
-                        return res;
-                    }
-                }
-                Certificate res = new X509CertImpl(buff);
-                CERT_CASHE.put(hash, buff, res);
-                return res;
-            } else {
-                inStream.reset();
-                long hash = CERT_CASHE.getHash(buff);
-                if (CERT_CASHE.contains(hash)) {
-                    byte[] encoding = new byte[BerInputStream.getLength(buff)];
-                    inStream.read(encoding);
-                    Certificate res = 
-                        (Certificate) CERT_CASHE.get(hash, encoding);
-                    if (res != null) {
-                        return res;
-                    }
-                    res = new X509CertImpl(encoding);
-                    CERT_CASHE.put(hash, encoding, res);
-                    return res;
-                } else {
-                    Certificate res = new X509CertImpl(inStream);
-                    CERT_CASHE.put(hash, res.getEncoded(), res);
-                    return res;
-                }
-            }
-        } catch (IOException e) {
-            throw new CertificateException(e);
-        }
-    }
-    
-    /**
-     * engineGenerateCertificates
-     * FIXME: 1.5 updates are needed Collection <? extends Certificate>
-     */
-    public Collection engineGenerateCertificates(InputStream inStream)
-            throws CertificateException {
-        ArrayList result = new ArrayList();
-        try {
-            if (inStream.markSupported()) {
-            } else {
-                inStream = new RestoringInputStream(inStream);
-            }
-            inStream.mark(1);
-            // FIXME: Check if it is a PKCS7 structure, if not, do following:
-            while (inStream.read() != -1) {
-                inStream.reset();
-                result.add(engineGenerateCertificate(inStream));
-                inStream.mark(1);
-            }
-        } catch (IOException e) {
-            e.printStackTrace();
-            throw new CertificateException(e);
-        }
-        return result;
-    }
-
-    /**
-     * engineGenerateCRL
-     */
-    public CRL engineGenerateCRL(InputStream inStream)
-            throws CRLException {
-        try {
-            if (inStream.markSupported()) {
-            } else {
-                inStream = new RestoringInputStream(inStream);
-            }
-            inStream.mark(32);
-            byte[] buff = new byte[25]; // take one byte for new line 
-            if (inStream.read(buff) < 25) {
-                throw new CRLException(
-                        "Input Stream contains not enought data.");
-            }
-            if ("-----BEGIN X509 CRL-----".equals(new String(buff, 0, 24))) {
-                int size = inStream.available();
-                if (size == 0) {
-                    size = 1024;
-                }
-                buff = new byte[size];
-                int index=0, ch;
-                while ((ch = inStream.read()) != '-') {
-                    if (ch == -1) {
-                        throw new CRLException(
-                                "Incorrect Base64 encoding: unexpected EOF.");
-                    }
-                    buff[index++] = (byte) ch;
-                    if (index == size) {
-                        byte[] newbuff = new byte[size+1024];
-                        System.arraycopy(buff, 0, newbuff, 0, size);
-                        buff = newbuff;
-                    }
-                }
-                byte[] tmp = new byte[21];
-                inStream.read(tmp);
-                if (!new String(tmp).startsWith("----END X509 CRL-----")) {
-                    throw new CRLException(
-                    "Incorrect Base64 encoding: 'END X509 CRL' expected.");
-                }
-                // skip new line: set the position to the next certificate:
-                inStream.mark(1);
-                while (((ch = inStream.read()) != -1) && (ch == '\n' || ch == '\r')) {
-                    inStream.mark(1);
-                }
-                inStream.reset();
-                buff = Base64.decode(buff, index);
-                if (buff == null) {
-                    throw new CRLException("Incorrect Base64 encoding.");
-                }
-                long hash = CRL_CASHE.getHash(buff);
-                if (CRL_CASHE.contains(hash)) {
-                    X509CRL res = (X509CRL) CRL_CASHE.get(hash, buff);
-                    if (res != null) {
-                        return res;
-                    }
-                }
-                X509CRL res = new X509CRLImpl(buff);
-                CRL_CASHE.put(hash, buff, res);
-                return res;
-            } 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;
-                }
-            }
-        } catch (IOException e) {
-            throw new CRLException(e);
-        }
-    }
-
-    /**
-     * engineGenerateCRLs
-     * FIXME: 1.5 updates are needed Collection <? extends CRL>
-     */
-    public Collection engineGenerateCRLs(InputStream inStream)
-            throws CRLException {
-        if (inStream == null) {
-            throw new CRLException("Null input stream provided.");
-        }
-        ArrayList result = new ArrayList();
-        try {
-            if (inStream.markSupported()) {
-            } else {
-                inStream = new RestoringInputStream(inStream);
-            }
-            inStream.mark(1);
-            // FIXME: Check if it is a PKCS7 structure, if not, do following:
-            while (inStream.read() != -1) {
-                inStream.reset();
-                result.add(engineGenerateCRL(inStream));
-                inStream.mark(1);
-            }
-        } catch (IOException e) {
-            e.printStackTrace();
-            throw new CRLException(e);
-        }
-        return result;
-    }
-
-    /**
-     * engineGenerateCertPath
-     */
-    public CertPath engineGenerateCertPath(InputStream inStream)
-            throws CertificateException {
-        return X509CertPathImpl.getInstance(inStream);
-    }
-
-    /**
-     * engineGenerateCertPath
-     */
-    public CertPath engineGenerateCertPath(InputStream inStream, String encoding)
-            throws CertificateException {
-        return X509CertPathImpl.getInstance(inStream, encoding);
-    }
-
-    /**
-     * engineGenerateCertPath
-     */
-    public CertPath engineGenerateCertPath(List certificates)
-            throws CertificateException {
-        return new X509CertPathImpl(certificates);
-    }
-
-    /**
-     * engineGetCertPathEncodings
-     * FIXME: 1.5 updates are needed Iterator <String>
-     */
-    public Iterator engineGetCertPathEncodings() {
-        return X509CertPathImpl.encodings.iterator();
-    }
-
-    /**
-     * Class represents the stream which supports reset to the
-     * marked state with readlimit == BUFF_SIZE.
-     */
-    private static class RestoringInputStream extends InputStream {
-
-        private final InputStream inStream;
-        private final static int BUFF_SIZE = 32;
-        private final int[] buff = new int[BUFF_SIZE*2];
-        // position in the buffer
-        private int pos = -1;
-        // the last byte in the buffer
-        private int bar = 0;
-        // the last cell of the buffer
-        private int end = 0;
-        
-        public RestoringInputStream(InputStream inStream) {
-            this.inStream = inStream;
-        }
-
-        public int available() throws IOException {
-            return (bar - pos) + inStream.available();
-        }
-
-        public void close() throws IOException {
-            inStream.close();
-        }
-
-        public void mark(int readlimit) {
-            if (pos < 0) {
-                pos = 0;
-                bar = 0;
-                end = BUFF_SIZE - 1;
-            } else {
-                end = (pos + BUFF_SIZE - 1) % BUFF_SIZE;
-            }
-        }
-
-        public boolean markSupported() {
-            return true;
-        }
-
-        public int read() throws IOException {
-            if (pos >= 0) {
-                int cur = pos % BUFF_SIZE;
-                if (cur < bar) {
-                    pos++;
-                    return buff[cur];
-                }
-                if (cur != end) {
-                    buff[cur] = inStream.read();
-                    bar = cur+1;
-                    pos++;
-                    return buff[cur];
-                } else {
-                    pos = -1; // can not operate anymore
-                }
-            }
-            return inStream.read();
-        }
-
-        public int read(byte[] b) throws IOException {
-            return read(b, 0, b.length);
-        }
-
-        public int read(byte[] b, int off, int len) throws IOException {
-            int read_b;
-            int i;
-            for (i=0; i<len; i++) {
-                if ((read_b = read()) == -1) {
-                    return (i == 0) ? -1 : i; 
-                }
-                b[off+i] = (byte) read_b;
-            }
-            return i;
-        }
-
-        public void reset() throws IOException {
-            if (pos >= 0) {
-                pos = (end + 1) % BUFF_SIZE;
-            } else {
-                throw new IOException("Could not reset the stream: "
-                    + "position became invalid or stream has not been marked.");
-            }
-        }
-
-        public long skip(long n) throws IOException {
-            if (pos >= 0) {
-                long i = 0;
-                int av = available();
-                if (av < n) {
-                    n = av;
-                }
-                while ((i < n) && (read() != -1)) {
-                    i++;
-                }
-                return i;
-            } else {
-                return inStream.skip(n);
-            }
-        }
-    }
-}
-
+/*
+ *  Copyright 2005 The Apache Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.provider.cert;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import java.security.cert.CertPath;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactorySpi;
+import java.security.cert.X509CRL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.harmony.luni.util.Base64;
+import org.apache.harmony.security.asn1.BerInputStream;
+
+/**
+ * X509 Certificate Factory Service Provider Interface Implementation.
+ * It supports CRLs and Certificates in (PEM) ASN.1 DER encoded form,
+ * and Certification Paths in PkiPath and PKCS7 formats.
+ * For Certificates and CRLs factory maintains the caching
+ * mechanisms allowing to speed up repeated Certificate/CRL
+ * generation.
+ * @see Cache
+ */
+public class X509CertFactoryImpl extends CertificateFactorySpi {
+
+    // 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);
+
+    /**
+     * Default constructor.
+     * Creates the instance of Certificate Factory SPI ready for use.
+     */
+    public X509CertFactoryImpl() { }
+
+    /**
+     * Generates the X.509 certificate from the data in the stream.
+     * The data in the stream can be either in ASN.1 DER encoded X.509
+     * certificate, or PEM (Base64 encoding bounded by
+     * <code>"-----BEGIN CERTIFICATE-----"</code> at the beginning and
+     * <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
+     * 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.
+     *
+     * @see java.security.cert.CertificateFactorySpi#engineGenerateCertificate(InputStream)
+     * method documentation for more info
+     */
+    public Certificate engineGenerateCertificate(InputStream inStream)
+            throws CertificateException {
+        try {
+            if (!inStream.markSupported()) {
+                // create the mark supporting wrapper
+                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[28];
+            // read the prefix of the encoding
+            if (inStream.read(buff) < 28) {
+                throw new CertificateException(
+                        "Input Stream contains not enought data.");
+            }
+            // check whether the provided certificate is in PEM encoded form
+            if ("-----BEGIN CERTIFICATE-----".equals(new String(buff, 0, 27))) {
+                // read PEM encoded form
+                int size = inStream.available();
+                if (size == 0) {
+                    size = 2048;
+                }
+                buff = new byte[size];
+                int index=0, ch;
+                // read the Base64 encoded certificate into the buffer
+                // expect "-----END CERTIFICATE-----" at the end
+                while ((ch = inStream.read()) != '-') {
+                    if (ch == -1) {
+                        throw new CertificateException(
+                                "Incorrect Base64 encoding: unexpected EOF.");
+                    }
+                    buff[index++] = (byte) ch;
+                    // enlarge the buffer if needed
+                    if (index == size) {
+                        byte[] newbuff = new byte[size+1024];
+                        System.arraycopy(buff, 0, newbuff, 0, size);
+                        buff = newbuff;
+                    }
+                }
+                byte[] tmp = new byte[25];
+                inStream.read(tmp);
+                // check the trailing sequence
+                if (!new String(tmp).startsWith("----END CERTIFICATE-----")) {
+                    throw new CertificateException(
+                    "Incorrect Base64 encoding: 'END CERTIFICATE' expected.");
+                }
+                // skip new line: set the position to the next certificate:
+                inStream.mark(1);
+                while (((ch = inStream.read()) != -1) 
+                        && (ch == '\n' || ch == '\r')) {
+                    inStream.mark(1);
+                }
+                inStream.reset();
+                // retrieve the ASN.1 DER encoded form
+                buff = Base64.decode(buff, index);
+                if (buff == null) {
+                    throw new CertificateException(
+                            "Incorrect Base64 encoding.");
+                }
+                // 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
+                    Certificate res = (Certificate) CERT_CASHE.get(hash, buff);
+                    if (res != null) {
+                        // found in the cache
+                        return res;
+                    }
+                }
+                // there is no generated certificate in the cache,
+                // so generate it
+                Certificate res = new X509CertImpl(buff);
+                // put newly generated certificate in the cache
+                CERT_CASHE.put(hash, buff, res);
+                return res;
+            } 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;
+                }
+            }
+        } catch (IOException e) {
+            throw new CertificateException(e);
+        }
+    }
+
+    /**
+     * Generates the collection of the certificates on the base of provided
+     * via input stream encodings.
+     * @see java.security.cert.CertificateFactorySpi#engineGenerateCertificates(InputStream)
+     * method documentation for more info
+     */
+    public Collection<? extends Certificate>
+            engineGenerateCertificates(InputStream inStream)
+                throws CertificateException {
+        ArrayList result = new ArrayList();
+        try {
+            if (!inStream.markSupported()) {
+                // create the mark supporting wrapper
+                inStream = new RestoringInputStream(inStream);
+            }
+            inStream.mark(1);
+            // until the end of the stream is not reached ..
+            while (inStream.read() != -1) {
+                inStream.reset();
+                // .. generate the certificate and add it to the resulting list
+                result.add(engineGenerateCertificate(inStream));
+                inStream.mark(1);
+            }
+        } catch (IOException e) {
+            throw new CertificateException(e);
+        }
+        return result;
+    }
+
+    /**
+     * @see java.security.cert.CertificateFactorySpi#engineGenerateCRL(InputStream)
+     * method documentation for more info
+     */
+    public CRL engineGenerateCRL(InputStream inStream)
+            throws CRLException {
+        try {
+            if (!inStream.markSupported()) {
+                // create the mark supporting wrapper
+                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(
+                        "Input Stream contains not enought data.");
+            }
+            // check whether the provided crl is in PEM encoded form
+            if ("-----BEGIN X509 CRL-----".equals(new String(buff, 0, 24))) {
+                // read PEM encoded form
+                int size = inStream.available();
+                if (size == 0) {
+                    size = 1024;
+                }
+                buff = new byte[size];
+                int index=0, ch;
+                // read the Base64 encoded crl into the buffer
+                while ((ch = inStream.read()) != '-') {
+                    if (ch == -1) {
+                        throw new CRLException(
+                                "Incorrect Base64 encoding: unexpected EOF.");
+                    }
+                    buff[index++] = (byte) ch;
+                    // enlarge the buffer if needed
+                    if (index == size) {
+                        byte[] newbuff = new byte[size+1024];
+                        System.arraycopy(buff, 0, newbuff, 0, size);
+                        buff = newbuff;
+                    }
+                }
+                byte[] tmp = new byte[21];
+                inStream.read(tmp);
+                if (!new String(tmp).startsWith("----END X509 CRL-----")) {
+                    throw new CRLException(
+                    "Incorrect Base64 encoding: 'END X509 CRL' expected.");
+                }
+                // skip new line: set the position to the next certificate:
+                inStream.mark(1);
+                while (((ch = inStream.read()) != -1) && (ch == '\n' || ch == '\r')) {
+                    inStream.mark(1);
+                }
+                inStream.reset();
+                buff = Base64.decode(buff, index);
+                if (buff == null) {
+                    throw new CRLException("Incorrect Base64 encoding.");
+                }
+                long hash = CRL_CASHE.getHash(buff);
+                if (CRL_CASHE.contains(hash)) {
+                    X509CRL res = (X509CRL) CRL_CASHE.get(hash, buff);
+                    if (res != null) {
+                        return res;
+                    }
+                }
+                X509CRL res = new X509CRLImpl(buff);
+                CRL_CASHE.put(hash, buff, res);
+                return res;
+            } 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;
+                }
+            }
+        } catch (IOException e) {
+            throw new CRLException(e);
+        }
+    }
+
+    /**
+     * @see java.security.cert.CertificateFactorySpi#engineGenerateCRLs(InputStream)
+     * method documentation for more info
+     */
+    public Collection<? extends CRL> engineGenerateCRLs(InputStream inStream)
+            throws CRLException {
+        if (inStream == null) {
+            throw new CRLException("Null input stream provided.");
+        }
+        ArrayList result = new ArrayList();
+        try {
+            if (!inStream.markSupported()) {
+                inStream = new RestoringInputStream(inStream);
+            }
+            inStream.mark(1);
+            // FIXME: Check if it is a PKCS7 structure, if not, do following:
+            while (inStream.read() != -1) {
+                inStream.reset();
+                result.add(engineGenerateCRL(inStream));
+                inStream.mark(1);
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+            throw new CRLException(e);
+        }
+        return result;
+    }
+
+    /**
+     * @see java.security.cert.CertificateFactorySpi#engineGenerateCertPath(InputStream)
+     * method documentation for more info
+     */
+    public CertPath engineGenerateCertPath(InputStream inStream)
+            throws CertificateException {
+        return X509CertPathImpl.getInstance(inStream);
+    }
+
+    /**
+     * @see java.security.cert.CertificateFactorySpi#engineGenerateCertPath(InputStream,String)
+     * method documentation for more info
+     */
+    public CertPath engineGenerateCertPath(
+            InputStream inStream, String encoding) throws CertificateException {
+        return X509CertPathImpl.getInstance(inStream, encoding);
+    }
+
+    /**
+     * @see java.security.cert.CertificateFactorySpi#engineGenerateCertPath(List)
+     * method documentation for more info
+     */
+    public CertPath engineGenerateCertPath(List certificates)
+            throws CertificateException {
+        return new X509CertPathImpl(certificates);
+    }
+
+    /**
+     * @see java.security.cert.CertificateFactorySpi#engineGetCertPathEncodings()
+     * method documentation for more info
+     */
+    public Iterator<String> engineGetCertPathEncodings() {
+        return X509CertPathImpl.encodings.iterator();
+    }
+
+    /*
+     * This class extends any existing input stream with
+     * mark functionality. It acts as a wrapper over the
+     * stream and supports reset to the
+     * marked state with readlimit no more than BUFF_SIZE.
+     */
+    private static class RestoringInputStream extends InputStream {
+
+        // wrapped input stream
+        private final InputStream inStream;
+        // specifies how much of the read data is buffered
+        // after the mark has been set up
+        private static final int BUFF_SIZE = 32;
+        // buffer to keep the bytes read after the mark has been set up
+        private final int[] buff = new int[BUFF_SIZE*2];
+        // position of the next byte to read,
+        // the value of -1 indicates that the buffer is not used
+        // (mark was not set up or was invalidated, or reset to the marked
+        // position has been done and all the buffered data was read out)
+        private int pos = -1;
+        // position of the last buffered byte
+        private int bar = 0;
+        // position in the buffer where the mark becomes invalidated
+        private int end = 0;
+
+        /**
+         * Creates the mark supporting wrapper over the stream.
+         */
+        public RestoringInputStream(InputStream inStream) {
+            this.inStream = inStream;
+        }
+
+        /**
+         * @see java.io.InputStream#available()
+         * method documentation for more info
+         */
+        public int available() throws IOException {
+            return (bar - pos) + inStream.available();
+        }
+
+        /**
+         * @see java.io.InputStream#close()
+         * method documentation for more info
+         */
+        public void close() throws IOException {
+            inStream.close();
+        }
+
+        /**
+         * @see java.io.InputStream#mark(int readlimit)
+         * method documentation for more info
+         */
+        public void mark(int readlimit) {
+            if (pos < 0) {
+                pos = 0;
+                bar = 0;
+                end = BUFF_SIZE - 1;
+            } else {
+                end = (pos + BUFF_SIZE - 1) % BUFF_SIZE;
+            }
+        }
+
+        /**
+         * @see java.io.InputStream#markSupported()
+         * method documentation for more info
+         */
+        public boolean markSupported() {
+            return true;
+        }
+
+        /**
+         * Reads the byte from the stream. If mark has been set up
+         * and was not invalidated byte is read from the underlying
+         * stream and saved into the buffer. If the current read position
+         * has been reset to the marked position and there are remaining
+         * bytes in the buffer, the byte is taken from it. In the other cases
+         * (if mark has been invalidated, or there are no buffered bytes)
+         * the byte is taken directly from the underlying stream and it is
+         * returned without saving to the buffer.
+         *
+         * @see java.io.InputStream#read()
+         * method documentation for more info
+         */
+        public int read() throws IOException {
+            // if buffer is currently used
+            if (pos >= 0) {
+                // current position in the buffer
+                int cur = pos % BUFF_SIZE;
+                // check whether the buffer contains the data to be read
+                if (cur < bar) {
+                    // return the data from the buffer
+                    pos++;
+                    return buff[cur];
+                }
+                // check whether buffer has free space
+                if (cur != end) {
+                    // it has, so read the data from the wrapped stream
+                    // and place it in the buffer
+                    buff[cur] = inStream.read();
+                    bar = cur+1;
+                    pos++;
+                    return buff[cur];
+                } else {
+                    // buffer if full and can not operate
+                    // any more, so invalidate the mark position
+                    // and turn off the using of buffer
+                    pos = -1;
+                }
+            }
+            // buffer is not used, so return the data from the wrapped stream
+            return inStream.read();
+        }
+
+        /**
+         * @see java.io.InputStream#read(byte[] b)
+         * method documentation for more info
+         */
+        public int read(byte[] b) throws IOException {
+            return read(b, 0, b.length);
+        }
+
+        /**
+         * @see java.io.InputStream#read(byte[] b, int off, int len)
+         * method documentation for more info
+         */
+        public int read(byte[] b, int off, int len) throws IOException {
+            int read_b;
+            int i;
+            for (i=0; i<len; i++) {
+                if ((read_b = read()) == -1) {
+                    return (i == 0) ? -1 : i;
+                }
+                b[off+i] = (byte) read_b;
+            }
+            return i;
+        }
+
+        /**
+         * @see java.io.InputStream#reset()
+         * method documentation for more info
+         */
+        public void reset() throws IOException {
+            if (pos >= 0) {
+                pos = (end + 1) % BUFF_SIZE;
+            } else {
+                throw new IOException("Could not reset the stream: "
+                    + "position became invalid or stream has not been marked.");
+            }
+        }
+
+        /**
+         * @see java.io.InputStream#skip(long n)
+         * method documentation for more info
+         */
+        public long skip(long n) throws IOException {
+            if (pos >= 0) {
+                long i = 0;
+                int av = available();
+                if (av < n) {
+                    n = av;
+                }
+                while ((i < n) && (read() != -1)) {
+                    i++;
+                }
+                return i;
+            } else {
+                return inStream.skip(n);
+            }
+        }
+    }
+}
+