Index: modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CertPathImpl.java
===================================================================
--- modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CertPathImpl.java (revision 410209)
+++ modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CertPathImpl.java (working copy)
@@ -15,9 +15,9 @@
*/
/**
-* @author Alexander Y. Kleymenov
-* @version $Revision$
-*/
+ * @author Alexander Y. Kleymenov
+ * @version $Revision$
+ */
package org.apache.harmony.security.provider.cert;
@@ -41,12 +41,33 @@
import org.apache.harmony.security.pkcs7.SignedData;
import org.apache.harmony.security.x509.Certificate;
-
/**
- * X509CertPathImpl
+ * This class is an implementation of X.509 CertPath. This implementation
+ * provides ability to create the instance of X.509 Certification Path
+ * by several means:
+ *
+ * 1. It can be created over the list of X.509 certificates
+ * (implementations of X509Certificate class) provided in constructor.
+ *
+ * 2. It can be created by means of getInstance methods
+ * on the base of the following ASN.1 DER encoded forms:
+ *
+ * - PkiPath as defined in
+ * ITU-T Recommendation X.509(2000) Corrigendum 1(2001)
+ * (can be seen at
+ * ftp://ftp.bull.com/pub/OSIdirectory/DefectResolution/TechnicalCorrigenda/ApprovedTechnicalCorrigendaToX.509/8%7CX.509-TC1(4th).pdf)
+ *
+ * - PKCS #7 SignedData object provided in the form of
+ * ContentInfo structure. CertPath object is generated on the base of
+ * certificates presented in ‘certificates’ field of the SignedData
+ * object which in its turn is retrieved from ContentInfo structure.
+ * (see http://www.rsasecurity.com/rsalabs/node.asp?id=2129
+ * for more info on PKCS #7)
+ *
+ *
*/
public class X509CertPathImpl extends CertPath {
-
+
/**
* @serial
*/
@@ -55,29 +76,32 @@
// supported encoding types:
public static final int PKI_PATH = 0;
public static final int PKCS7 = 1;
-
- // supported encoding names:
- private static final String[] encodingsArr =
+
+ // supported encoding names
+ private static final String[] encodingsArr =
new String[] {"PkiPath", "PKCS7"};
static final List encodings = Collections.unmodifiableList(
Arrays.asList(encodingsArr));
+ // the list of certificates representing this certification path
private final List certificates;
+ // PkiPath encoding of the certification path
private byte[] pkiPathEncoding;
+ // PKCS7 encoding of the certification path
private byte[] pkcs7Encoding;
-
+
+ /**
+ * Creates an instance of X.509 Certification Path over the specified
+ * list of certificates.
+ * @throws CertificateException if some of the object in the list
+ * is not an instance of subclass of X509Certificate.
+ */
public X509CertPathImpl(List certs) throws CertificateException {
super("X.509");
- // if (certs == null) {
- // throw new CertificateException(
- // "Provided list of certificates provided is null.");
- // }
- // throw NullPointerException:
int size = certs.size();
certificates = new ArrayList(size);
for (int i=0; iencoding.
+ * @throws CertificateException if specified encoding form is not supported,
+ * or some problems occurred during the decoding.
+ */
+ public static X509CertPathImpl getInstance(InputStream in, String encoding)
throws CertificateException {
if (!encodings.contains(encoding)) {
throw new CertificateException(
@@ -115,16 +161,19 @@
}
try {
if (encodingsArr[0].equals(encoding)) {
+ // generate the object from PkiPath encoded form
return (X509CertPathImpl) ASN1.decode(in);
} else {
+ // generate the object from PKCS #7 encoded form
ContentInfo ci = (ContentInfo) ContentInfo.ASN1.decode(in);
SignedData sd = ci.getSignedData();
if (sd == null) {
throw new CertificateException(
- "Incorrect PKCS7 encoded form: missing signed data");
+ "Incorrect PKCS7 encoded form: missing signed data");
}
List certs = sd.getCertificates();
if (certs == null) {
+ // empty chain of certificates
certs = new ArrayList();
}
return new X509CertPathImpl(certs, PKCS7, ci.getEncoded());
@@ -135,7 +184,13 @@
}
}
- public static X509CertPathImpl getInstance(byte[] in)
+ /**
+ * Generates certification path object on the base of PkiPath
+ * encoded form provided via array of bytes.
+ * @throws CertificateException if some problems occurred during
+ * the decoding.
+ */
+ public static X509CertPathImpl getInstance(byte[] in)
throws CertificateException {
try {
return (X509CertPathImpl) ASN1.decode(in);
@@ -145,7 +200,14 @@
}
}
- public static X509CertPathImpl getInstance(byte[] in, String encoding)
+ /**
+ * Generates certification path object on the base of encoding provided via
+ * array of bytes. The format of provided encoded form is specified by
+ * parameter encoding.
+ * @throws CertificateException if specified encoding form is not supported,
+ * or some problems occurred during the decoding.
+ */
+ public static X509CertPathImpl getInstance(byte[] in, String encoding)
throws CertificateException {
if (!encodings.contains(encoding)) {
throw new CertificateException(
@@ -153,13 +215,15 @@
}
try {
if (encodingsArr[0].equals(encoding)) {
+ // generate the object from PkiPath encoded form
return (X509CertPathImpl) ASN1.decode(in);
- } else { // PKCS7
+ } else {
+ // generate the object from PKCS #7 encoded form
ContentInfo ci = (ContentInfo) ContentInfo.ASN1.decode(in);
SignedData sd = ci.getSignedData();
if (sd == null) {
throw new CertificateException(
- "Incorrect PKCS7 encoded form: missing signed data");
+ "Incorrect PKCS7 encoded form: missing signed data");
}
List certs = sd.getCertificates();
if (certs == null) {
@@ -173,15 +237,21 @@
}
}
+ // ---------------------------------------------------------------------
+ // ---- java.security.cert.CertPath abstract method implementations ----
+ // ---------------------------------------------------------------------
+
/**
- * getCertificates
+ * @see java.security.cert.CertPath#getCertificates()
+ * method documentation for more info
*/
public List getCertificates() {
return Collections.unmodifiableList(certificates);
}
/**
- * getEncoded
+ * @see java.security.cert.CertPath#getEncoded()
+ * method documentation for more info
*/
public byte[] getEncoded() throws CertificateEncodingException {
if (pkiPathEncoding == null) {
@@ -193,7 +263,8 @@
}
/**
- * getEncoded
+ * @see java.security.cert.CertPath#getEncoded(String)
+ * method documentation for more info
*/
public byte[] getEncoded(String encoding)
throws CertificateEncodingException {
@@ -202,47 +273,70 @@
"Unsupported encoding: "+encoding);
}
if (encodingsArr[0].equals(encoding)) {
+ // PkiPath encoded form
return getEncoded();
} else {
- // FIXME: PKCS7 encoding support
- // PKCS7 encoded form:
+ // PKCS7 encoded form
if (pkcs7Encoding == null) {
- SignedData sd = new SignedData(1, new ArrayList(),
+ SignedData sd = new SignedData(1, new ArrayList(),
new ContentInfo(ContentInfo.DATA, null), certificates,
null, new ArrayList());
ContentInfo ci = new ContentInfo(ContentInfo.SIGNED_DATA, sd);
pkcs7Encoding = ci.getEncoded();
}
byte[] result = new byte[pkiPathEncoding.length];
- System.arraycopy(pkcs7Encoding, 0, result, 0,
+ System.arraycopy(pkcs7Encoding, 0, result, 0,
pkcs7Encoding.length);
return result;
}
}
/**
- * getEncodings
+ * @see java.security.cert.CertPath#getEncodings()
+ * method documentation for more info
*/
public Iterator getEncodings() {
return encodings.iterator();
}
- public static ASN1SequenceOf ASN1 = new ASN1SequenceOf(ASN1Any.getInstance()) {
-
+ /**
+ * ASN.1 DER Encoder/Decoder for PkiPath structure.
+ */
+ public static ASN1SequenceOf ASN1 =
+ new ASN1SequenceOf(ASN1Any.getInstance()) {
+
+ /**
+ * Builds the instance of X509CertPathImpl on the base of the list
+ * of ASN.1 encodings of X.509 certificates provided via
+ * PkiPath structure.
+ * This method participates in decoding process.
+ */
public Object getDecodedObject(BerInputStream in) throws IOException {
+ // retrieve the decoded content
List encodings = (List) in.content;
int size = encodings.size();
List certificates = new ArrayList(size);
for (int i=0; i
+ *
+ * The process of Certificate/CRL generation
+ * (implemented in X509CertFactoryImpl) is accompanied with
+ * prereading of the beginning of encoded form. This prefix is used to determine
+ * whether provided form is PEM encoding or not.
+ *
+ * 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.
+ *
+ * So to speed up the object generation process this caching mechanism provides
+ * the following functionality:
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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 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 contains(long) 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 prefix_size (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; iarr.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 getHash(byte[]))
+ * @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 contains(long) for the hash code returned true.
+ * @param hash the hash code for the prefix of the encoding
+ * (retrieved by method getHash(byte[]))
+ * @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;
+ cache[index] = object;
}
-
- 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;
+
+ // 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);
}
- while (length > 0) {
- if (arr1[--length] != arr2[length]) {
- return false;
- }
- }
- return true;
- //*/
+ return hash_addon << 16;
}
- 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;
- }
- }
}
Index: modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CertImpl.java
===================================================================
--- modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CertImpl.java (revision 410209)
+++ modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CertImpl.java (working copy)
@@ -15,9 +15,9 @@
*/
/**
-* @author Alexander Y. Kleymenov
-* @version $Revision$
-*/
+ * @author Alexander Y. Kleymenov
+ * @version $Revision$
+ */
package org.apache.harmony.security.provider.cert;
@@ -51,20 +51,28 @@
import org.apache.harmony.security.x509.TBSCertificate;
/**
- * X509CertImpl
+ * This class is an implementation of X509Certificate. It wraps
+ * the instance of org.apache.harmony.security.x509.Certificate
+ * built on the base of provided ASN.1 DER encoded form of
+ * Certificate structure (as specified in RFC 3280
+ * http://www.ietf.org/rfc/rfc3280.txt).
+ * @see org.apache.harmony.security.x509.Certificate
+ * @see java.security.cert.X509Certificate
*/
public class X509CertImpl extends X509Certificate {
-
+
/**
* @serial
*/
private static final long serialVersionUID = 2972248729446736154L;
+ // the core object to be wrapped in X509Certificate
private final Certificate certificate;
+
+ // to speed up access to the info, the following fields
+ // cache values retrieved from the certificate object
private final TBSCertificate tbsCert;
private final Extensions extensions;
-
- // cached values
private long notBefore = -1;
private long notAfter;
private BigInteger serialNumber;
@@ -75,42 +83,68 @@
private String sigAlgName;
private String sigAlgOID;
private byte[] sigAlgParams;
+ // indicates whether the signature algorithm parameters are null
private boolean nullSigAlgParams;
- //Values are taken directly from tbsCerttificate:
- // private boolean[] issuerUniqueID;
- // private boolean[] subjectUniqueID;
private PublicKey publicKey;
-
+
+ // encoding of the certificate
private byte[] encoding;
-
+
+ //
+ // ---------------------- Constructors -------------------------------
+ //
+
+ /**
+ * Constructs the instance on the base of ASN.1 encoded
+ * form of X.509 certificate provided via stream parameter.
+ * @param in input stream containing ASN.1 encoded form of certificate.
+ * @throws CertificateException if some decoding problems occur.
+ */
public X509CertImpl(InputStream in) throws CertificateException {
try {
+ // decode the Certificate object
this.certificate = (Certificate) Certificate.ASN1.decode(in);
+ // cache the values of TBSCertificate and Extensions
this.tbsCert = certificate.getTbsCertificate();
this.extensions = tbsCert.getExtensions();
} catch (IOException e) {
throw new CertificateException(e);
}
}
-
+
+ /**
+ * Constructs the instance on the base of existing Certificate object to
+ * be wrapped.
+ */
public X509CertImpl(Certificate certificate) {
this.certificate = certificate;
+ // cache the values of TBSCertificate and Extensions
this.tbsCert = certificate.getTbsCertificate();
this.extensions = tbsCert.getExtensions();
}
+ /**
+ * Constructs the instance on the base of ASN.1 encoded
+ * form of X.509 certificate provided via array of bytes.
+ * @param encoding byte array containing ASN.1 encoded form of certificate.
+ * @throws IOException if some decoding problems occur.
+ */
public X509CertImpl(byte[] encoding) throws IOException {
- this((Certificate) Certificate.ASN1.decode(encoding));
+ this((Certificate) Certificate.ASN1.decode(encoding));
}
-
- //
+ //
// ----------------- Public methods implementations ------------------
//
+ /**
+ * @see java.security.cert.X509Certificate#checkValidity()
+ * method documentation for more information.
+ */
public void checkValidity() throws CertificateExpiredException,
CertificateNotYetValidException {
if (notBefore == -1) {
+ // retrieve and cache the value of validity period
notBefore = tbsCert.getValidity().getNotBefore().getTime();
notAfter = tbsCert.getValidity().getNotAfter().getTime();
}
@@ -123,10 +157,15 @@
}
}
- public void checkValidity(Date date)
- throws CertificateExpiredException,
+ /**
+ * @see java.security.cert.X509Certificate#checkValidity(Date)
+ * method documentation for more information.
+ */
+ public void checkValidity(Date date)
+ throws CertificateExpiredException,
CertificateNotYetValidException {
if (notBefore == -1) {
+ // retrieve and cache the value of validity period
notBefore = tbsCert.getValidity().getNotBefore().getTime();
notAfter = tbsCert.getValidity().getNotAfter().getTime();
}
@@ -138,11 +177,19 @@
throw new CertificateExpiredException();
}
}
-
+
+ /**
+ * @see java.security.cert.X509Certificate#getVersion()
+ * method documentation for more information.
+ */
public int getVersion() {
return tbsCert.getVersion() + 1;
}
+ /**
+ * @see java.security.cert.X509Certificate#getSerialNumber()
+ * method documentation for more information.
+ */
public BigInteger getSerialNumber() {
if (serialNumber == null) {
serialNumber = tbsCert.getSerialNumber();
@@ -150,54 +197,88 @@
return serialNumber;
}
+ /**
+ * @see java.security.cert.X509Certificate#getIssuerDN()
+ * method documentation for more information.
+ */
public Principal getIssuerDN() {
if (issuer == null) {
+ // retrieve the issuer's principal
issuer = tbsCert.getIssuer().getX500Principal();
}
return issuer;
}
+ /**
+ * @see java.security.cert.X509Certificate#getIssuerX500Principal()
+ * method documentation for more information.
+ */
public X500Principal getIssuerX500Principal() {
if (issuer == null) {
+ // retrieve the issuer's principal
issuer = tbsCert.getIssuer().getX500Principal();
}
return issuer;
}
-
+
+ /**
+ * @see java.security.cert.X509Certificate#getSubjectDN()
+ * method documentation for more information.
+ */
public Principal getSubjectDN() {
if (subject == null) {
+ // retrieve the subject's principal
subject = tbsCert.getSubject().getX500Principal();
}
return subject;
}
+ /**
+ * @see java.security.cert.X509Certificate#getSubjectX500Principal()
+ * method documentation for more information.
+ */
public X500Principal getSubjectX500Principal() {
if (subject == null) {
+ // retrieve the subject's principal
subject = tbsCert.getSubject().getX500Principal();
}
return subject;
}
+ /**
+ * @see java.security.cert.X509Certificate#getNotBefore()
+ * method documentation for more information.
+ */
public Date getNotBefore() {
if (notBefore == -1) {
+ // the value was not retrieved from the certificate, do it:
notBefore = tbsCert.getValidity().getNotBefore().getTime();
notAfter = tbsCert.getValidity().getNotAfter().getTime();
}
return new Date(notBefore);
}
+ /**
+ * @see java.security.cert.X509Certificate#getNotAfter()
+ * method documentation for more information.
+ */
public Date getNotAfter() {
if (notBefore == -1) {
+ // the value was not retrieved from the certificate, do it:
notBefore = tbsCert.getValidity().getNotBefore().getTime();
notAfter = tbsCert.getValidity().getNotAfter().getTime();
}
return new Date(notAfter);
}
+ /**
+ * @see java.security.cert.X509Certificate#getTBSCertificate()
+ * method documentation for more information.
+ */
public byte[] getTBSCertificate()
- throws CertificateEncodingException
- {
+ throws CertificateEncodingException {
if (tbsCertificate == null) {
+ // retrieve the encoded form of the TBSCertificate structure
tbsCertificate = tbsCert.getEncoded();
}
byte[] result = new byte[tbsCertificate.length];
@@ -205,8 +286,13 @@
return result;
}
+ /**
+ * @see java.security.cert.X509Certificate#getSignature()
+ * method documentation for more information.
+ */
public byte[] getSignature() {
if (signature == null) {
+ // retrieve the value of the signature
signature = certificate.getSignatureValue();
}
byte[] result = new byte[signature.length];
@@ -214,28 +300,46 @@
return result;
}
+ /**
+ * @see java.security.cert.X509Certificate#getSigAlgName()
+ * method documentation for more information.
+ */
public String getSigAlgName() {
if (sigAlgOID == null) {
+ // if info was not retrieved (and cached), do it:
sigAlgOID = tbsCert.getSignature().getAlgorithm();
+ // retrieve the name of the signing algorithm
sigAlgName = AlgNameMapper.map2AlgName(sigAlgOID);
if (sigAlgName == null) {
+ // if could not be found, use OID as a name
sigAlgName = sigAlgOID;
}
}
return sigAlgName;
}
+ /**
+ * @see java.security.cert.X509Certificate#getSigAlgOID()
+ * method documentation for more information.
+ */
public String getSigAlgOID() {
if (sigAlgOID == null) {
+ // if info was not retrieved (and cached), do it:
sigAlgOID = tbsCert.getSignature().getAlgorithm();
+ // retrieve the name of the signing algorithm
sigAlgName = AlgNameMapper.map2AlgName(sigAlgOID);
if (sigAlgName == null) {
+ // if could not be found, use OID as a name
sigAlgName = sigAlgOID;
}
}
return sigAlgOID;
}
+ /**
+ * @see java.security.cert.X509Certificate#getSigAlgParams()
+ * method documentation for more information.
+ */
public byte[] getSigAlgParams() {
if (nullSigAlgParams) {
return null;
@@ -251,21 +355,24 @@
}
/**
- * @return
+ * @see java.security.cert.X509Certificate#getIssuerUniqueID()
+ * method documentation for more information.
*/
public boolean[] getIssuerUniqueID() {
return tbsCert.getIssuerUniqueID();
}
/**
- * @return
+ * @see java.security.cert.X509Certificate#getSubjectUniqueID()
+ * method documentation for more information.
*/
public boolean[] getSubjectUniqueID() {
return tbsCert.getSubjectUniqueID();
}
/**
- * @return
+ * @see java.security.cert.X509Certificate#getKeyUsage()
+ * method documentation for more information.
*/
public boolean[] getKeyUsage() {
if (extensions == null) {
@@ -274,6 +381,10 @@
return extensions.valueOfKeyUsage();
}
+ /**
+ * @see java.security.cert.X509Certificate#getExtendedKeyUsage()
+ * method documentation for more information.
+ */
public List/**/ getExtendedKeyUsage()
throws CertificateParsingException {
if (extensions == null) {
@@ -286,6 +397,10 @@
}
}
+ /**
+ * @see java.security.cert.X509Certificate#getBasicConstraints()
+ * method documentation for more information.
+ */
public int getBasicConstraints() {
if (extensions == null) {
return Integer.MAX_VALUE;
@@ -293,36 +408,53 @@
return extensions.valueOfBasicConstrains();
}
+ /**
+ * @see java.security.cert.X509Certificate#getSubjectAlternativeNames()
+ * method documentation for more information.
+ */
public Collection/*>*/ getSubjectAlternativeNames()
throws CertificateParsingException {
if (extensions == null) {
return null;
}
try {
+ // Retrieve the extension value from the cached extensions object
+ // This extension is not checked for correctness during
+ // certificate generation, so now it can throw exception
return extensions.valueOfSubjectAlternativeName();
} catch (IOException e) {
throw new CertificateParsingException(e);
}
}
+ /**
+ * @see java.security.cert.X509Certificate#getIssuerAlternativeNames()
+ * method documentation for more information.
+ */
public Collection/*FIXME >*/ getIssuerAlternativeNames()
throws CertificateParsingException {
if (extensions == null) {
return null;
}
try {
+ // Retrieve the extension value from the cached extensions object
+ // This extension is not checked for correctness during
+ // certificate generation, so now it can throw exception
return extensions.valueOfIssuerAlternativeName();
} catch (IOException e) {
throw new CertificateParsingException(e);
}
}
- //
+ //
// ----- java.security.cert.Certificate methods implementations ------
//
-
- public byte[] getEncoded() throws CertificateEncodingException
- {
+
+ /**
+ * @see java.security.cert.Certificate#getEncoded()
+ * method documentation for more information.
+ */
+ public byte[] getEncoded() throws CertificateEncodingException {
if (encoding == null) {
encoding = certificate.getEncoded();
}
@@ -331,102 +463,122 @@
return result;
}
+ /**
+ * @see java.security.cert.Certificate#getPublicKey()
+ * method documentation for more information.
+ */
public PublicKey getPublicKey() {
if (publicKey == null) {
+ // retrieve the public key from SubjectPublicKeyInfo
+ // substructure of X.509 certificate
publicKey = tbsCert.getSubjectPublicKeyInfo().getPublicKey();
}
return publicKey;
}
/**
- * TODO: should be fully implemented.
- * @return
+ * @see java.security.cert.Certificate#toString()
+ * method documentation for more information.
*/
public String toString() {
return certificate.toString();
}
-
+
/**
- * TODO
- * @param key: PublicKey
- * @return
- * @throwsCertificateException
- * @throwsNoSuchAlgorithmException
- * @throwsInvalidKeyException
- * @throwsNoSuchProviderException
- * @throwsSignatureException
+ * Verifies the signature of the certificate.
+ * @see java.security.cert.Certificate#verify(PublicKey)
+ * method documentation for more information.
*/
public void verify(PublicKey key)
throws CertificateException, NoSuchAlgorithmException,
InvalidKeyException, NoSuchProviderException,
- SignatureException
- {
- Signature signature = Signature.getInstance(
- tbsCert.getSignature().getAlgorithm());
+ SignatureException {
+ Signature signature = Signature.getInstance(getSigAlgName());
signature.initVerify(key);
- byte[] tbsCertEncoding = tbsCert.getEncoded();
- signature.update(tbsCertEncoding, 0, tbsCertEncoding.length);
+ // retrieve the ecnoding of the TBSCertificate structure
+ if (tbsCertificate == null) {
+ tbsCertificate = tbsCert.getEncoded();
+ }
+ // compute and verify the signature
+ signature.update(tbsCertificate, 0, tbsCertificate.length);
if (!signature.verify(certificate.getSignatureValue())) {
throw new SignatureException("Signature was not verified.");
}
}
/**
- * TODO
- * @param key: PublicKey
- * @param sigProvider: String
- * @return
- * @throwsCertificateException
- * @throwsNoSuchAlgorithmException
- * @throwsInvalidKeyException
- * @throwsNoSuchProviderException
- * @throwsSignatureException
+ * Verifies the signature of the certificate.
+ * @see java.security.cert.Certificate#verify(PublicKey,String)
+ * method documentation for more information.
*/
public void verify(PublicKey key, String sigProvider)
throws CertificateException, NoSuchAlgorithmException,
InvalidKeyException, NoSuchProviderException,
- SignatureException
- {
- Signature signature = Signature.getInstance(
- tbsCert.getSignature().getAlgorithm(), sigProvider);
+ SignatureException {
+ Signature signature =
+ Signature.getInstance(getSigAlgName(), sigProvider);
signature.initVerify(key);
- byte[] tbsCertEncoding = tbsCert.getEncoded();
- signature.update(tbsCertEncoding, 0, tbsCertEncoding.length);
+ // retrieve the ecnoding of the TBSCertificate structure
+ if (tbsCertificate == null) {
+ tbsCertificate = tbsCert.getEncoded();
+ }
+ // compute and verify the signature
+ signature.update(tbsCertificate, 0, tbsCertificate.length);
if (!signature.verify(certificate.getSignatureValue())) {
throw new SignatureException("Signature was not verified.");
}
}
- //
+ //
// ----- java.security.cert.X509Extension methods implementations ----
//
+ /**
+ * @see java.security.cert.X509Extension#getNonCriticalExtensionOIDs()
+ * method documentation for more information.
+ */
public Set getNonCriticalExtensionOIDs() {
if (extensions == null) {
return null;
}
+ // retrieve the info from the cached extensions object
return extensions.getNonCriticalExtensions();
}
+ /**
+ * @see java.security.cert.X509Extension#getCriticalExtensionOIDs()
+ * method documentation for more information.
+ */
public Set getCriticalExtensionOIDs() {
if (extensions == null) {
return null;
}
+ // retrieve the info from the cached extensions object
return extensions.getCriticalExtensions();
}
+ /**
+ * @see java.security.cert.X509Extension#getExtensionValue(String)
+ * method documentation for more information.
+ */
public byte[] getExtensionValue(String oid) {
if (extensions == null) {
return null;
}
+ // retrieve the info from the cached extensions object
Extension ext = extensions.getExtensionByOID(oid);
return (ext == null) ? null : ext.getRawExtnValue();
}
+ /**
+ * @see java.security.cert.X509Extension#hasUnsupportedCriticalExtension()
+ * method documentation for more information.
+ */
public boolean hasUnsupportedCriticalExtension() {
if (extensions == null) {
return false;
}
+ // retrieve the info from the cached extensions object
return extensions.hasUnsupportedCritical();
}
Index: modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/DRLCertFactory.java
===================================================================
--- modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/DRLCertFactory.java (revision 410209)
+++ modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/DRLCertFactory.java (working copy)
@@ -15,9 +15,9 @@
*/
/**
-* @author Alexander Y. Kleymenov
-* @version $Revision$
-*/
+ * @author Alexander Y. Kleymenov
+ * @version $Revision$
+ */
package org.apache.harmony.security.provider.cert;
@@ -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;
}
Index: modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CRLImpl.java
===================================================================
--- modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CRLImpl.java (revision 410209)
+++ modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CRLImpl.java (working copy)
@@ -15,9 +15,9 @@
*/
/**
-* @author Alexander Y. Kleymenov
-* @version $Revision$
-*/
+ * @author Alexander Y. Kleymenov
+ * @version $Revision$
+ */
package org.apache.harmony.security.provider.cert;
@@ -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*/ 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();
}
}
+
Index: modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CRLEntryImpl.java
===================================================================
--- modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CRLEntryImpl.java (revision 410209)
+++ modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CRLEntryImpl.java (working copy)
@@ -15,9 +15,9 @@
*/
/**
-* @author Alexander Y. Kleymenov
-* @version $Revision$
-*/
+ * @author Alexander Y. Kleymenov
+ * @version $Revision$
+ */
package org.apache.harmony.security.provider.cert;
@@ -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
+ * TBSCertList.RevokedCertificate 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) {
- }
-}
Index: modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CertFactoryImpl.java
===================================================================
--- modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CertFactoryImpl.java (revision 410209)
+++ modules/security/src/main/java/common/org/apache/harmony/security/provider/cert/X509CertFactoryImpl.java (working copy)
@@ -15,9 +15,9 @@
*/
/**
-* @author Alexander Y. Kleymenov
-* @version $Revision$
-*/
+ * @author Alexander Y. Kleymenov
+ * @version $Revision$
+ */
package org.apache.harmony.security.provider.cert;
@@ -40,44 +40,77 @@
import org.apache.harmony.security.asn1.BerInputStream;
/**
- * X509CertFactoryImpl
+ * 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);
-
- public X509CertFactoryImpl() {}
/**
- * engineGenerateCertificate
+ * 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
+ * "-----BEGIN CERTIFICATE-----" at the beginning and
+ * "-----END CERTIFICATE-----" 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()) {
- } else {
+ 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);
@@ -86,46 +119,70 @@
}
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')) {
+ 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.");
+ 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);
- Certificate res =
+ // 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;
}
@@ -134,62 +191,73 @@
throw new CertificateException(e);
}
}
-
+
/**
- * engineGenerateCertificates
- * FIXME: 1.5 updates are needed Collection extends Certificate>
+ * 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 engineGenerateCertificates(InputStream inStream)
- throws CertificateException {
+ public Collection extends Certificate>
+ engineGenerateCertificates(InputStream inStream)
+ throws CertificateException {
ArrayList result = new ArrayList();
try {
- if (inStream.markSupported()) {
- } else {
+ if (!inStream.markSupported()) {
+ // create the mark supporting wrapper
inStream = new RestoringInputStream(inStream);
}
inStream.mark(1);
- // FIXME: Check if it is a PKCS7 structure, if not, do following:
+ // 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) {
- e.printStackTrace();
throw new CertificateException(e);
}
return result;
}
/**
- * engineGenerateCRL
+ * @see java.security.cert.CertificateFactorySpi#engineGenerateCRL(InputStream)
+ * method documentation for more info
*/
public CRL engineGenerateCRL(InputStream inStream)
throws CRLException {
try {
- if (inStream.markSupported()) {
- } else {
+ 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
+ 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);
@@ -228,7 +296,7 @@
if (CRL_CASHE.contains(hash)) {
byte[] encoding = new byte[BerInputStream.getLength(buff)];
inStream.read(encoding);
- CRL res =
+ CRL res =
(CRL) CRL_CASHE.get(hash, encoding);
if (res != null) {
return res;
@@ -248,18 +316,17 @@
}
/**
- * engineGenerateCRLs
- * FIXME: 1.5 updates are needed Collection extends CRL>
+ * @see java.security.cert.CertificateFactorySpi#engineGenerateCRLs(InputStream)
+ * method documentation for more info
*/
- public Collection engineGenerateCRLs(InputStream inStream)
+ 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()) {
- } else {
+ if (!inStream.markSupported()) {
inStream = new RestoringInputStream(inStream);
}
inStream.mark(1);
@@ -277,7 +344,8 @@
}
/**
- * engineGenerateCertPath
+ * @see java.security.cert.CertificateFactorySpi#engineGenerateCertPath(InputStream)
+ * method documentation for more info
*/
public CertPath engineGenerateCertPath(InputStream inStream)
throws CertificateException {
@@ -285,15 +353,17 @@
}
/**
- * engineGenerateCertPath
+ * @see java.security.cert.CertificateFactorySpi#engineGenerateCertPath(InputStream,String)
+ * method documentation for more info
*/
- public CertPath engineGenerateCertPath(InputStream inStream, String encoding)
- throws CertificateException {
+ public CertPath engineGenerateCertPath(
+ InputStream inStream, String encoding) throws CertificateException {
return X509CertPathImpl.getInstance(inStream, encoding);
}
/**
- * engineGenerateCertPath
+ * @see java.security.cert.CertificateFactorySpi#engineGenerateCertPath(List)
+ * method documentation for more info
*/
public CertPath engineGenerateCertPath(List certificates)
throws CertificateException {
@@ -301,41 +371,65 @@
}
/**
- * engineGetCertPathEncodings
- * FIXME: 1.5 updates are needed Iterator
+ * @see java.security.cert.CertificateFactorySpi#engineGetCertPathEncodings()
+ * method documentation for more info
*/
- public Iterator engineGetCertPathEncodings() {
+ public Iterator engineGetCertPathEncodings() {
return X509CertPathImpl.encodings.iterator();
}
- /**
- * Class represents the stream which supports reset to the
- * marked state with readlimit == BUFF_SIZE.
+ /*
+ * 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;
- private final static int BUFF_SIZE = 32;
+ // 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 in the buffer
+ // 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;
- // the last byte in the buffer
+ // position of the last buffered byte
private int bar = 0;
- // the last cell of the buffer
+ // 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;
@@ -346,45 +440,85 @@
}
}
+ /**
+ * @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 {
- pos = -1; // can not operate anymore
+ // 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= 0) {
pos = (end + 1) % BUFF_SIZE;
@@ -394,6 +528,10 @@
}
}
+ /**
+ * @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;