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);
+ }
+ }
+ }
+}
+