diff options
Diffstat (limited to 'prov/src/main/jdk1.3/org/spongycastle/jce')
54 files changed, 18052 insertions, 0 deletions
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/ECKeyUtil.java b/prov/src/main/jdk1.3/org/spongycastle/jce/ECKeyUtil.java new file mode 100644 index 00000000..c2343e10 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/ECKeyUtil.java @@ -0,0 +1,229 @@ +package org.spongycastle.jce; + +import java.io.UnsupportedEncodingException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Security; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PrivateKeyInfo; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.asn1.x9.X962Parameters; +import org.spongycastle.asn1.x9.X9ECParameters; +import org.spongycastle.asn1.x9.X9ObjectIdentifiers; +import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil; +import org.spongycastle.jce.provider.BouncyCastleProvider; + +/** + * Utility class to allow conversion of EC key parameters to explicit from named + * curves and back (where possible). + */ +public class ECKeyUtil +{ + /** + * Convert a passed in public EC key to have explicit parameters. If the key + * is already using explicit parameters it is returned. + * + * @param key key to be converted + * @param providerName provider name to be used. + * @return the equivalent key with explicit curve parameters + * @throws IllegalArgumentException + * @throws NoSuchAlgorithmException + * @throws NoSuchProviderException + */ + public static PublicKey publicToExplicitParameters(PublicKey key, String providerName) + throws IllegalArgumentException, NoSuchAlgorithmException, NoSuchProviderException + { + Provider provider = Security.getProvider(providerName); + + if (provider == null) + { + throw new NoSuchProviderException("cannot find provider: " + providerName); + } + + return publicToExplicitParameters(key, provider); + } + + /** + * Convert a passed in public EC key to have explicit parameters. If the key + * is already using explicit parameters it is returned. + * + * @param key key to be converted + * @param provider provider to be used. + * @return the equivalent key with explicit curve parameters + * @throws IllegalArgumentException + * @throws NoSuchAlgorithmException + */ + public static PublicKey publicToExplicitParameters(PublicKey key, Provider provider) + throws IllegalArgumentException, NoSuchAlgorithmException + { + try + { + SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(key.getEncoded())); + + if (info.getAlgorithmId().getObjectId().equals(CryptoProObjectIdentifiers.gostR3410_2001)) + { + throw new IllegalArgumentException("cannot convert GOST key to explicit parameters."); + } + else + { + X962Parameters params = X962Parameters.getInstance(info.getAlgorithmId().getParameters()); + X9ECParameters curveParams; + + if (params.isNamedCurve()) + { + ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters()); + + curveParams = ECUtil.getNamedCurveByOid(oid); + // ignore seed value due to JDK bug + curveParams = new X9ECParameters(curveParams.getCurve(), curveParams.getG(), curveParams.getN(), curveParams.getH()); + } + else if (params.isImplicitlyCA()) + { + curveParams = new X9ECParameters(BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getCurve(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getG(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getN(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getH()); + } + else + { + return key; // already explicit + } + + params = new X962Parameters(curveParams); + + info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), info.getPublicKeyData().getBytes()); + + KeyFactory keyFact = KeyFactory.getInstance(key.getAlgorithm(), provider.getName()); + + return keyFact.generatePublic(new X509EncodedKeySpec(info.getEncoded())); + } + } + catch (IllegalArgumentException e) + { + throw e; + } + catch (NoSuchAlgorithmException e) + { + throw e; + } + catch (Exception e) + { // shouldn't really happen... + throw new UnexpectedException(e); + } + } + + /** + * Convert a passed in private EC key to have explicit parameters. If the key + * is already using explicit parameters it is returned. + * + * @param key key to be converted + * @param providerName provider name to be used. + * @return the equivalent key with explicit curve parameters + * @throws IllegalArgumentException + * @throws NoSuchAlgorithmException + * @throws NoSuchProviderException + */ + public static PrivateKey privateToExplicitParameters(PrivateKey key, String providerName) + throws IllegalArgumentException, NoSuchAlgorithmException, NoSuchProviderException + { + Provider provider = Security.getProvider(providerName); + + if (provider == null) + { + throw new NoSuchProviderException("cannot find provider: " + providerName); + } + + return privateToExplicitParameters(key, provider); + } + + /** + * Convert a passed in private EC key to have explicit parameters. If the key + * is already using explicit parameters it is returned. + * + * @param key key to be converted + * @param provider provider to be used. + * @return the equivalent key with explicit curve parameters + * @throws IllegalArgumentException + * @throws NoSuchAlgorithmException + */ + public static PrivateKey privateToExplicitParameters(PrivateKey key, Provider provider) + throws IllegalArgumentException, NoSuchAlgorithmException + { + try + { + PrivateKeyInfo info = PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(key.getEncoded())); + + if (info.getAlgorithmId().getObjectId().equals(CryptoProObjectIdentifiers.gostR3410_2001)) + { + throw new UnsupportedEncodingException("cannot convert GOST key to explicit parameters."); + } + else + { + X962Parameters params = X962Parameters.getInstance(info.getAlgorithmId().getParameters()); + X9ECParameters curveParams; + + if (params.isNamedCurve()) + { + ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters()); + + curveParams = ECUtil.getNamedCurveByOid(oid); + // ignore seed value due to JDK bug + curveParams = new X9ECParameters(curveParams.getCurve(), curveParams.getG(), curveParams.getN(), curveParams.getH()); + } + else if (params.isImplicitlyCA()) + { + curveParams = new X9ECParameters(BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getCurve(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getG(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getN(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getH()); + } + else + { + return key; // already explicit + } + + params = new X962Parameters(curveParams); + + info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), info.parsePrivateKey()); + + KeyFactory keyFact = KeyFactory.getInstance(key.getAlgorithm(), provider.getName()); + + return keyFact.generatePrivate(new PKCS8EncodedKeySpec(info.getEncoded())); + } + } + catch (IllegalArgumentException e) + { + throw e; + } + catch (NoSuchAlgorithmException e) + { + throw e; + } + catch (Exception e) + { // shouldn't really happen + throw new UnexpectedException(e); + } + } + + private static class UnexpectedException + extends RuntimeException + { + private Throwable cause; + + UnexpectedException(Throwable cause) + { + super(cause.toString()); + + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/MultiCertStoreParameters.java b/prov/src/main/jdk1.3/org/spongycastle/jce/MultiCertStoreParameters.java new file mode 100644 index 00000000..42f46648 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/MultiCertStoreParameters.java @@ -0,0 +1,51 @@ +package org.spongycastle.jce; + +import org.spongycastle.jce.cert.CertStoreParameters; +import java.util.Collection; + +public class MultiCertStoreParameters + implements CertStoreParameters +{ + private Collection certStores; + private boolean searchAllStores; + + /** + * Create a parameters object which specifies searching of all the passed in stores. + * + * @param certStores CertStores making up the multi CertStore + */ + public MultiCertStoreParameters(Collection certStores) + { + this(certStores, true); + } + + /** + * Create a parameters object which can be to used to make a multi store made up + * of the passed in CertStores. If the searchAllStores parameter is false, any search on + * the multi-store will terminate as soon as a search query produces a result. + * + * @param certStores CertStores making up the multi CertStore + * @param searchAllStores true if all CertStores should be searched on request, false if a result + * should be returned on the first successful CertStore query. + */ + public MultiCertStoreParameters(Collection certStores, boolean searchAllStores) + { + this.certStores = certStores; + this.searchAllStores = searchAllStores; + } + + public Collection getCertStores() + { + return certStores; + } + + public boolean getSearchAllStores() + { + return searchAllStores; + } + + public Object clone() + { + return this; + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/PKCS10CertificationRequest.java b/prov/src/main/jdk1.3/org/spongycastle/jce/PKCS10CertificationRequest.java new file mode 100644 index 00000000..b9bc6e52 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/PKCS10CertificationRequest.java @@ -0,0 +1,583 @@ +package org.spongycastle.jce; + +import java.io.IOException; +import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Set; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.DERBitString; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.pkcs.CertificationRequest; +import org.spongycastle.asn1.pkcs.CertificationRequestInfo; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.pkcs.RSASSAPSSparams; +import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.asn1.x509.X509Name; +import org.spongycastle.asn1.x9.X9ObjectIdentifiers; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.util.Strings; + +/** + * A class for verifying and creating PKCS10 Certification requests. + * <pre> + * CertificationRequest ::= SEQUENCE { + * certificationRequestInfo CertificationRequestInfo, + * signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }}, + * signature BIT STRING + * } + * + * CertificationRequestInfo ::= SEQUENCE { + * version INTEGER { v1(0) } (v1,...), + * subject Name, + * subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }}, + * attributes [0] Attributes{{ CRIAttributes }} + * } + * + * Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }} + * + * Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE { + * type ATTRIBUTE.&id({IOSet}), + * values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type}) + * } + * </pre> + * @deprecated use classes in org.spongycastle.pkcs. + */ +public class PKCS10CertificationRequest + extends CertificationRequest +{ + private static Hashtable algorithms = new Hashtable(); + private static Hashtable params = new Hashtable(); + private static Hashtable keyAlgorithms = new Hashtable(); + private static Hashtable oids = new Hashtable(); + private static Set noParams = new HashSet(); + + static + { + algorithms.put("MD2WITHRSAENCRYPTION", new ASN1ObjectIdentifier("1.2.840.113549.1.1.2")); + algorithms.put("MD2WITHRSA", new ASN1ObjectIdentifier("1.2.840.113549.1.1.2")); + algorithms.put("MD5WITHRSAENCRYPTION", new ASN1ObjectIdentifier("1.2.840.113549.1.1.4")); + algorithms.put("MD5WITHRSA", new ASN1ObjectIdentifier("1.2.840.113549.1.1.4")); + algorithms.put("RSAWITHMD5", new ASN1ObjectIdentifier("1.2.840.113549.1.1.4")); + algorithms.put("SHA1WITHRSAENCRYPTION", new ASN1ObjectIdentifier("1.2.840.113549.1.1.5")); + algorithms.put("SHA1WITHRSA", new ASN1ObjectIdentifier("1.2.840.113549.1.1.5")); + algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption); + algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption); + algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption); + algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption); + algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption); + algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption); + algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption); + algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption); + algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS); + algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS); + algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS); + algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS); + algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS); + algorithms.put("RSAWITHSHA1", new ASN1ObjectIdentifier("1.2.840.113549.1.1.5")); + algorithms.put("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128); + algorithms.put("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128); + algorithms.put("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160); + algorithms.put("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160); + algorithms.put("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256); + algorithms.put("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256); + algorithms.put("SHA1WITHDSA", new ASN1ObjectIdentifier("1.2.840.10040.4.3")); + algorithms.put("DSAWITHSHA1", new ASN1ObjectIdentifier("1.2.840.10040.4.3")); + algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224); + algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256); + algorithms.put("SHA384WITHDSA", NISTObjectIdentifiers.dsa_with_sha384); + algorithms.put("SHA512WITHDSA", NISTObjectIdentifiers.dsa_with_sha512); + algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1); + algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224); + algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256); + algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384); + algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512); + algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1); + algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94); + algorithms.put("GOST3410WITHGOST3411", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94); + algorithms.put("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001); + algorithms.put("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001); + algorithms.put("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001); + + // + // reverse mappings + // + oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA"); + oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA"); + oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA"); + oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA"); + oids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WITHRSA"); + oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3411WITHGOST3410"); + oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "GOST3411WITHECGOST3410"); + + oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA"); + oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA"); + oids.put(new ASN1ObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA"); + oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WITHECDSA"); + oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA"); + oids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256WITHECDSA"); + oids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384WITHECDSA"); + oids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512WITHECDSA"); + oids.put(OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA"); + oids.put(OIWObjectIdentifiers.dsaWithSHA1, "SHA1WITHDSA"); + oids.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WITHDSA"); + oids.put(NISTObjectIdentifiers.dsa_with_sha256, "SHA256WITHDSA"); + + // + // key types + // + keyAlgorithms.put(PKCSObjectIdentifiers.rsaEncryption, "RSA"); + keyAlgorithms.put(X9ObjectIdentifiers.id_dsa, "DSA"); + + // + // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field. + // The parameters field SHALL be NULL for RSA based signature algorithms. + // + noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1); + noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224); + noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256); + noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384); + noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512); + noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1); + noParams.add(NISTObjectIdentifiers.dsa_with_sha224); + noParams.add(NISTObjectIdentifiers.dsa_with_sha256); + + // + // RFC 4491 + // + noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94); + noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001); + // + // explicit params + // + AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, new DERNull()); + params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20)); + + AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, new DERNull()); + params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28)); + + AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, new DERNull()); + params.put("SHA256WITHRSAANDMGF1", creatPSSParams(sha256AlgId, 32)); + + AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, new DERNull()); + params.put("SHA384WITHRSAANDMGF1", creatPSSParams(sha384AlgId, 48)); + + AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512, new DERNull()); + params.put("SHA512WITHRSAANDMGF1", creatPSSParams(sha512AlgId, 64)); + } + + private static RSASSAPSSparams creatPSSParams(AlgorithmIdentifier hashAlgId, int saltSize) + { + return new RSASSAPSSparams( + hashAlgId, + new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId), + new ASN1Integer(saltSize), + new ASN1Integer(1)); + } + + private static ASN1Sequence toDERSequence( + byte[] bytes) + { + try + { + ASN1InputStream dIn = new ASN1InputStream(bytes); + + return (ASN1Sequence)dIn.readObject(); + } + catch (Exception e) + { + throw new IllegalArgumentException("badly encoded request"); + } + } + + /** + * construct a PKCS10 certification request from a DER encoded + * byte stream. + */ + public PKCS10CertificationRequest( + byte[] bytes) + { + super(toDERSequence(bytes)); + } + + public PKCS10CertificationRequest( + ASN1Sequence sequence) + { + super(sequence); + } + + /** + * create a PKCS10 certfication request using the BC provider. + */ + public PKCS10CertificationRequest( + String signatureAlgorithm, + X509Name subject, + PublicKey key, + ASN1Set attributes, + PrivateKey signingKey) + throws NoSuchAlgorithmException, NoSuchProviderException, + InvalidKeyException, SignatureException + { + this(signatureAlgorithm, subject, key, attributes, signingKey, BouncyCastleProvider.PROVIDER_NAME); + } + + + /** + * create a PKCS10 certfication request using the named provider. + */ + public PKCS10CertificationRequest( + String signatureAlgorithm, + X509Name subject, + PublicKey key, + ASN1Set attributes, + PrivateKey signingKey, + String provider) + throws NoSuchAlgorithmException, NoSuchProviderException, + InvalidKeyException, SignatureException + { + String algorithmName = Strings.toUpperCase(signatureAlgorithm); + ASN1ObjectIdentifier sigOID = (ASN1ObjectIdentifier)algorithms.get(algorithmName); + + if (sigOID == null) + { + try + { + sigOID = new ASN1ObjectIdentifier(algorithmName); + } + catch (Exception e) + { + throw new IllegalArgumentException("Unknown signature type requested"); + } + } + + if (subject == null) + { + throw new IllegalArgumentException("subject must not be null"); + } + + if (key == null) + { + throw new IllegalArgumentException("public key must not be null"); + } + + if (noParams.contains(sigOID)) + { + this.sigAlgId = new AlgorithmIdentifier(sigOID); + } + else if (params.containsKey(algorithmName)) + { + this.sigAlgId = new AlgorithmIdentifier(sigOID, (ASN1Encodable)params.get(algorithmName)); + } + else + { + this.sigAlgId = new AlgorithmIdentifier(sigOID, DERNull.INSTANCE); + } + + try + { + ASN1Sequence seq = (ASN1Sequence)ASN1Primitive.fromByteArray(key.getEncoded()); + this.reqInfo = new CertificationRequestInfo(subject, new SubjectPublicKeyInfo(seq), attributes); + } + catch (IOException e) + { + throw new IllegalArgumentException("can't encode public key"); + } + + Signature sig; + if (provider == null) + { + sig = Signature.getInstance(signatureAlgorithm); + } + else + { + sig = Signature.getInstance(signatureAlgorithm, provider); + } + + sig.initSign(signingKey); + + try + { + sig.update(reqInfo.getEncoded(ASN1Encoding.DER)); + } + catch (Exception e) + { + throw new IllegalArgumentException("exception encoding TBS cert request - " + e); + } + + this.sigBits = new DERBitString(sig.sign()); + } + + /** + * return the public key associated with the certification request - + * the public key is created using the BC provider. + */ + public PublicKey getPublicKey() + throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException + { + return getPublicKey(BouncyCastleProvider.PROVIDER_NAME); + } + + public PublicKey getPublicKey( + String provider) + throws NoSuchAlgorithmException, NoSuchProviderException, + InvalidKeyException + { + SubjectPublicKeyInfo subjectPKInfo = reqInfo.getSubjectPublicKeyInfo(); + + + try + { + X509EncodedKeySpec xspec = new X509EncodedKeySpec(new DERBitString(subjectPKInfo).getBytes()); + AlgorithmIdentifier keyAlg = subjectPKInfo.getAlgorithm(); + try + { + if (provider == null) + { + return KeyFactory.getInstance(keyAlg.getAlgorithm().getId()).generatePublic(xspec); + } + else + { + return KeyFactory.getInstance(keyAlg.getAlgorithm().getId(), provider).generatePublic(xspec); + } + } + catch (NoSuchAlgorithmException e) + { + // + // try an alternate + // + if (keyAlgorithms.get(keyAlg.getObjectId()) != null) + { + String keyAlgorithm = (String)keyAlgorithms.get(keyAlg.getObjectId()); + + if (provider == null) + { + return KeyFactory.getInstance(keyAlgorithm).generatePublic(xspec); + } + else + { + return KeyFactory.getInstance(keyAlgorithm, provider).generatePublic(xspec); + } + } + + throw e; + } + } + catch (InvalidKeySpecException e) + { + throw new InvalidKeyException("error decoding public key"); + } + catch (IOException e) + { + throw new InvalidKeyException("error decoding public key"); + } + } + + /** + * verify the request using the BC provider. + */ + public boolean verify() + throws NoSuchAlgorithmException, NoSuchProviderException, + InvalidKeyException, SignatureException + { + return verify(BouncyCastleProvider.PROVIDER_NAME); + } + + /** + * verify the request using the passed in provider. + */ + public boolean verify( + String provider) + throws NoSuchAlgorithmException, NoSuchProviderException, + InvalidKeyException, SignatureException + { + return verify(this.getPublicKey(provider), provider); + } + + /** + * verify the request using the passed in public key and the provider.. + */ + public boolean verify( + PublicKey pubKey, + String provider) + throws NoSuchAlgorithmException, NoSuchProviderException, + InvalidKeyException, SignatureException + { + Signature sig; + + try + { + if (provider == null) + { + sig = Signature.getInstance(getSignatureName(sigAlgId)); + } + else + { + sig = Signature.getInstance(getSignatureName(sigAlgId), provider); + } + } + catch (NoSuchAlgorithmException e) + { + // + // try an alternate + // + if (oids.get(sigAlgId.getObjectId()) != null) + { + String signatureAlgorithm = (String)oids.get(sigAlgId.getObjectId()); + + if (provider == null) + { + sig = Signature.getInstance(signatureAlgorithm); + } + else + { + sig = Signature.getInstance(signatureAlgorithm, provider); + } + } + else + { + throw e; + } + } + + setSignatureParameters(sig, sigAlgId.getParameters(), provider); + + sig.initVerify(pubKey); + + try + { + sig.update(reqInfo.getEncoded(ASN1Encoding.DER)); + } + catch (Exception e) + { + throw new SignatureException("exception encoding TBS cert request - " + e); + } + + return sig.verify(sigBits.getBytes()); + } + + /** + * return a DER encoded byte array representing this object + */ + public byte[] getEncoded() + { + try + { + return this.getEncoded(ASN1Encoding.DER); + } + catch (IOException e) + { + throw new RuntimeException(e.toString()); + } + } + + private void setSignatureParameters( + Signature signature, + ASN1Encodable params, + String provider) + throws NoSuchAlgorithmException, NoSuchProviderException, SignatureException, InvalidKeyException + { + if (params != null && !DERNull.INSTANCE.equals(params)) + { + AlgorithmParameters sigParams = AlgorithmParameters.getInstance(signature.getAlgorithm(), provider); + + try + { + sigParams.init(params.toASN1Primitive().getEncoded(ASN1Encoding.DER)); + } + catch (IOException e) + { + throw new SignatureException("IOException decoding parameters: " + e.getMessage()); + } + } + } + + static String getSignatureName( + AlgorithmIdentifier sigAlgId) + { + ASN1Encodable params = sigAlgId.getParameters(); + + if (params != null && !DERNull.INSTANCE.equals(params)) + { + if (sigAlgId.getObjectId().equals(PKCSObjectIdentifiers.id_RSASSA_PSS)) + { + RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params); + return getDigestAlgName(rsaParams.getHashAlgorithm().getObjectId()) + "withRSAandMGF1"; + } + } + + return sigAlgId.getObjectId().getId(); + } + + private static String getDigestAlgName( + ASN1ObjectIdentifier digestAlgOID) + { + if (PKCSObjectIdentifiers.md5.equals(digestAlgOID)) + { + return "MD5"; + } + else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID)) + { + return "SHA1"; + } + else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID)) + { + return "SHA224"; + } + else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID)) + { + return "SHA256"; + } + else if (NISTObjectIdentifiers.id_sha384.equals(digestAlgOID)) + { + return "SHA384"; + } + else if (NISTObjectIdentifiers.id_sha512.equals(digestAlgOID)) + { + return "SHA512"; + } + else if (TeleTrusTObjectIdentifiers.ripemd128.equals(digestAlgOID)) + { + return "RIPEMD128"; + } + else if (TeleTrusTObjectIdentifiers.ripemd160.equals(digestAlgOID)) + { + return "RIPEMD160"; + } + else if (TeleTrusTObjectIdentifiers.ripemd256.equals(digestAlgOID)) + { + return "RIPEMD256"; + } + else if (CryptoProObjectIdentifiers.gostR3411.equals(digestAlgOID)) + { + return "GOST3411"; + } + else + { + return digestAlgOID.getId(); + } + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CRLSelector.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CRLSelector.java new file mode 100644 index 00000000..0cafff5c --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CRLSelector.java @@ -0,0 +1,41 @@ +package org.spongycastle.jce.cert; + +import java.security.cert.CRL; + +/** + * A selector that defines a set of criteria for selecting <code>CRL</code>s. + * Classes that implement this interface are often used to specify + * which <code>CRL</code>s should be retrieved from a <code>CertStore</code>.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this interface are not + * thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize. + * + * @see CRL + * @see CertStore + * @see CertStore#getCRLs + **/ +public interface CRLSelector extends Cloneable +{ + /** + * Decides whether a <code>CRL</code> should be selected. + * + * @param crl the <code>CRL</code> to be checked + * + * @return <code>true</code> if the <code>CRL</code> should be selected, + * <code>false</code> otherwise + */ + public boolean match(CRL crl); + + /** + * Makes a copy of this <code>CRLSelector</code>. Changes to the + * copy will not affect the original and vice versa. + * + * @return a copy of this <code>CRLSelector</code> + */ + public Object clone(); +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPath.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPath.java new file mode 100644 index 00000000..34f9c628 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPath.java @@ -0,0 +1,296 @@ +package org.spongycastle.jce.cert; + +import java.io.ByteArrayInputStream; +import java.io.NotSerializableException; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +/** + * An immutable sequence of certificates (a certification path).<br /> + * <br /> + * This is an abstract class that defines the methods common to all CertPaths. + * Subclasses can handle different kinds of certificates (X.509, PGP, etc.).<br /> + * <br /> + * All CertPath objects have a type, a list of Certificates, and one or more + * supported encodings. Because the CertPath class is immutable, a CertPath + * cannot change in any externally visible way after being constructed. This + * stipulation applies to all public fields and methods of this class and any + * added or overridden by subclasses.<br /> + * <br /> + * The type is a String that identifies the type of Certificates in the + * certification path. For each certificate cert in a certification path + * certPath, cert.getType().equals(certPath.getType()) must be true.<br /> + * <br /> + * The list of Certificates is an ordered List of zero or more Certificates. + * This List and all of the Certificates contained in it must be immutable.<br /> + * <br /> + * Each CertPath object must support one or more encodings so that the object + * can be translated into a byte array for storage or transmission to other + * parties. Preferably, these encodings should be well-documented standards + * (such as PKCS#7). One of the encodings supported by a CertPath is considered + * the default encoding. This encoding is used if no encoding is explicitly + * requested (for the {@link #getEncoded()} method, for instance).<br /> + * <br /> + * All CertPath objects are also Serializable. CertPath objects are resolved + * into an alternate {@link CertPathRep} object during serialization. This + * allows a CertPath object to be serialized into an equivalent representation + * regardless of its underlying implementation.<br /> + * <br /> + * CertPath objects can be created with a CertificateFactory or they can be + * returned by other classes, such as a CertPathBuilder.<br /> + * <br /> + * By convention, X.509 CertPaths (consisting of X509Certificates), are ordered + * starting with the target certificate and ending with a certificate issued by + * the trust anchor. That is, the issuer of one certificate is the subject of + * the following one. The certificate representing the + * {@link TrustAnchor TrustAnchor} should not be included in the certification + * path. Unvalidated X.509 CertPaths may not follow these conventions. PKIX + * CertPathValidators will detect any departure from these conventions that + * cause the certification path to be invalid and throw a + * CertPathValidatorException.<br /> + * <br /> + * <strong>Concurrent Access</strong><br /> + * <br /> + * All CertPath objects must be thread-safe. That is, multiple threads may + * concurrently invoke the methods defined in this class on a single CertPath + * object (or more than one) with no ill effects. This is also true for the List + * returned by CertPath.getCertificates.<br /> + * <br /> + * Requiring CertPath objects to be immutable and thread-safe allows them to be + * passed around to various pieces of code without worrying about coordinating + * access. Providing this thread-safety is generally not difficult, since the + * CertPath and List objects in question are immutable. + * + * @see CertificateFactory + * @see CertPathBuilder + */ +public abstract class CertPath extends Object implements Serializable +{ + private String type; + + /** + * Alternate <code>CertPath</code> class for serialization. + */ + protected static class CertPathRep implements Serializable + { + private String type; + + private byte[] data; + + /** + * Creates a <code>CertPathRep</code> with the specified type and + * encoded form of a certification path. + * + * @param type + * the standard name of a CertPath + * @param typedata + * the encoded form of the certification path + */ + protected CertPathRep(String type, byte[] data) + { + this.type = type; + this.data = data; + } + + /** + * Returns a CertPath constructed from the type and data. + * + * @return the resolved CertPath object + * @exception ObjectStreamException + * if a CertPath could not be constructed + */ + protected Object readResolve() throws ObjectStreamException + { + try + { + ByteArrayInputStream inStream = new ByteArrayInputStream(data); + CertificateFactory cf = CertificateFactory.getInstance(type); + return cf.generateCertPath(inStream); + } + catch (CertificateException ce) + { + throw new NotSerializableException( + " java.security.cert.CertPath: " + type); + } + } + } + + /** + * Creates a CertPath of the specified type. This constructor is protected + * because most users should use a CertificateFactory to create CertPaths. + * + * @param type + * the standard name of the type of Certificatesin this path + */ + protected CertPath(String type) + { + this.type = type; + } + + /** + * Returns the type of Certificates in this certification path. This is the + * same string that would be returned by + * {@link java.security.cert.Certificate#getType()} for all Certificates in + * the certification path. + * + * @return the type of Certificates in this certification path (never null) + */ + public String getType() + { + return type; + } + + /** + * Returns an iteration of the encodings supported by this certification + * path, with the default encoding first. Attempts to modify the returned + * Iterator via its remove method result in an + * UnsupportedOperationException. + * + * @return an Iterator over the names of the supported encodings (as + * Strings) + */ + public abstract Iterator getEncodings(); + + /** + * Compares this certification path for equality with the specified object. + * Two CertPaths are equal if and only if their types are equal and their + * certificate Lists (and by implication the Certificates in those Lists) + * are equal. A CertPath is never equal to an object that is not a CertPath.<br /> + * <br /> + * This algorithm is implemented by this method. If it is overridden, the + * behavior specified here must be maintained. + * + * @param other + * the object to test for equality with this certification path + * + * @return true if the specified object is equal to this certification path, + * false otherwise + * + * @see Object#hashCode() Object.hashCode() + */ + public boolean equals(Object other) + { + if (!(other instanceof CertPath)) + { + return false; + } + + CertPath otherCertPath = (CertPath)other; + if (!getType().equals(otherCertPath.getType())) + { + return false; + } + return getCertificates().equals(otherCertPath.getCertificates()); + } + + /** + * Returns the hashcode for this certification path. The hash code of a + * certification path is defined to be the result of the following + * calculation: + * + * <pre> + * hashCode = path.getType().hashCode(); + * hashCode = 31 * hashCode + path.getCertificates().hashCode(); + * </pre> + * + * This ensures that path1.equals(path2) implies that + * path1.hashCode()==path2.hashCode() for any two certification paths, path1 + * and path2, as required by the general contract of Object.hashCode. + * + * @return The hashcode value for this certification path + * + * @see #equals(Object) + */ + public int hashCode() + { + return getType().hashCode() * 31 + getCertificates().hashCode(); + } + + /** + * Returns a string representation of this certification path. This calls + * the toString method on each of the Certificates in the path. + * + * @return a string representation of this certification path + */ + public String toString() + { + StringBuffer s = new StringBuffer(); + List certs = getCertificates(); + ListIterator iter = certs.listIterator(); + s.append('\n').append(getType()).append(" Cert Path: length = ").append(certs.size()) + .append("\n[\n"); + while (iter.hasNext()) + { + s + .append("=========================================================Certificate ") + .append(iter.nextIndex()).append('\n'); + s.append(iter.next()).append('\n'); + s + .append("========================================================Certificate end\n\n\n"); + } + s.append("\n]"); + return s.toString(); + } + + /** + * Returns the encoded form of this certification path, using the default + * encoding. + * + * @return the encoded bytes + * + * @exception CertificateEncodingException + * if an encoding error occurs + */ + public abstract byte[] getEncoded() throws CertificateEncodingException; + + /** + * Returns the encoded form of this certification path, using the specified + * encoding. + * + * @param encoding + * the name of the encoding to use + * + * @return the encoded bytes + * + * @exception CertificateEncodingException + * if an encoding error occurs or the encoding requested is + * not supported + */ + public abstract byte[] getEncoded(String encoding) + throws CertificateEncodingException; + + /** + * Returns the list of certificates in this certification path. The List + * returned must be immutable and thread-safe. + * + * @return an immutable List of Certificates (may be empty, but not null) + */ + public abstract List getCertificates(); + + /** + * Replaces the CertPath to be serialized with a CertPathRep object. + * + * @return the CertPathRep to be serialized + * + * @exception ObjectStreamException + * if a CertPathRep object representing this certification + * path could not be created + */ + protected Object writeReplace() throws ObjectStreamException + { + try + { + return new CertPathRep(getType(), getEncoded()); + } + catch (CertificateException ce) + { + throw new NotSerializableException(" java.security.cert.CertPath: " + + getType()); + } + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilder.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilder.java new file mode 100644 index 00000000..54585689 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilder.java @@ -0,0 +1,255 @@ +package org.spongycastle.jce.cert; + +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.Security; + +/** + * A class for building certification paths (also known as certificate chains).<br /> + * <br /> + * This class uses a provider-based architecture, as described in the Java + * Cryptography Architecture. To create a <code>CertPathBuilder</code>, call + * one of the static <code>getInstance</code> methods, passing in the + * algorithm name of the CertPathBuilder desired and optionally the name of the + * provider desired.<br /> + * <br /> + * Once a <code>CertPathBuilder</code> object has been created, certification + * paths can be constructed by calling the {@link #build build} method and + * passing it an algorithm-specific set of parameters. If successful, the result + * (including the CertPath that was built) is returned in an object that + * implements the <code>CertPathBuilderResult</code> interface.<br /> + * <br /> + * <strong>Concurrent Access</strong><br /> + * <br /> + * The static methods of this class are guaranteed to be thread-safe. Multiple + * threads may concurrently invoke the static methods defined in this class with + * no ill effects.<br /> + * <br /> + * However, this is not true for the non-static methods defined by this class. + * Unless otherwise documented by a specific provider, threads that need to + * access a single <code>CertPathBuilder</code> instance concurrently should + * synchronize amongst themselves and provide the necessary locking. Multiple + * threads each manipulating a different <code>CertPathBuilder</code> instance + * need not synchronize.<br /> + * <br /> + */ +public class CertPathBuilder extends Object +{ + private CertPathBuilderSpi builderSpi; + + private Provider provider; + + private String algorithm; + + /** + * Creates a CertPathBuilder object of the given algorithm, and encapsulates + * the given provider implementation (SPI object) in it. + * + * @param builderSpi + * the provider implementation + * @param provider + * the provider + * @param algorithm + * the algorithm name + */ + protected CertPathBuilder( + CertPathBuilderSpi builderSpi, + Provider provider, + String algorithm) + { + this.builderSpi = builderSpi; + this.provider = provider; + this.algorithm = algorithm; + } + + /** + * Returns a CertPathBuilder object that implements the specified algorithm.<br /> + * <br /> + * If the default provider package provides an implementation of the + * specified CertPathBuilder algorithm, an instance of CertPathBuilder + * containing that implementation is returned. If the requested algorithm is + * not available in the default package, other packages are searched.<br /> + * <br /> + * + * @param algorithm + * the name of the requested CertPathBuilder algorithm + * + * @return a CertPathBuilder object that implements the specified algorithm + * + * @exception NoSuchAlgorithmException + * if the requested algorithm is not available in the default + * provider package or any of the other provider packages + * that were searched + */ + public static CertPathBuilder getInstance(String algorithm) + throws NoSuchAlgorithmException + { + try + { + CertUtil.Implementation imp = CertUtil.getImplementation( + "CertPathBuilder", algorithm, (String)null); + if (imp != null) + { + return new CertPathBuilder((CertPathBuilderSpi)imp.getEngine(), + imp.getProvider(), algorithm); + } + } + catch (NoSuchProviderException ex) + { + } + throw new NoSuchAlgorithmException("can't find type " + algorithm); + } + + /** + * Returns a CertPathBuilder object that implements the specified algorithm, + * as supplied by the specified provider. + * + * @param algorithm + * the name of the requested CertPathBuilder algorithm + * @param provider + * the name of the provider + * + * @return a CertPathBuilder object that implements the specified algorithm, + * as supplied by the specified provider + * + * @exception NoSuchAlgorithmException + * if the requested algorithm is not available from the + * specified provider + * @exception NoSuchProviderException + * if the provider has not been configured + * @exception IllegalArgumentException + * if the provider is null + */ + public static CertPathBuilder getInstance(String algorithm, String provider) + throws NoSuchAlgorithmException, NoSuchProviderException + { + if (provider == null) + { + throw new IllegalArgumentException("provider must be non-null"); + } + CertUtil.Implementation imp = CertUtil.getImplementation( + "CertPathBuilder", algorithm, provider); + + if (imp != null) + { + return new CertPathBuilder((CertPathBuilderSpi)imp.getEngine(), imp + .getProvider(), algorithm); + } + throw new NoSuchAlgorithmException("can't find type " + algorithm); + } + + /** + * Returns a CertPathBuilder object that implements the specified algorithm, + * as supplied by the specified provider. Note: the provider doesn't have to + * be registered. + * + * @param algorithm + * the name of the requested CertPathBuilder algorithm + * @param provider + * the provider + * @return a CertPathBuilder object that implements the specified algorithm, + * as supplied by the specified provider + * + * @exception NoSuchAlgorithmException + * if the requested algorithm is not available from the + * specified provider + * @exception IllegalArgumentException + * if the provider is null. + */ + public static CertPathBuilder getInstance(String algorithm, + Provider provider) throws NoSuchAlgorithmException + { + if (provider == null) + { + throw new IllegalArgumentException("provider must be non-null"); + } + CertUtil.Implementation imp = CertUtil.getImplementation( + "CertPathBuilder", algorithm, provider); + + if (imp != null) + { + return new CertPathBuilder((CertPathBuilderSpi)imp.getEngine(), + provider, algorithm); + } + throw new NoSuchAlgorithmException("can't find type " + algorithm); + } + + /** + * Returns the provider of this <code>CertPathBuilder</code>. + * + * @return the provider of this <code>CertPathBuilder</code> + */ + public final Provider getProvider() + { + return provider; + } + + /** + * Returns the name of the algorithm of this <code>CertPathBuilder</code>. + * + * @return the name of the algorithm of this <code>CertPathBuilder</code> + */ + public final String getAlgorithm() + { + return algorithm; + } + + /** + * Attempts to build a certification path using the specified algorithm + * parameter set. + * + * @param params + * the algorithm parameters + * + * @return the result of the build algorithm + * + * @exception CertPathBuilderException + * if the builder is unable to construct a certification path + * that satisfies the specified parameters + * @exception InvalidAlgorithmParameterException + * if the specified parameters * are inappropriate for this + * <code>CertPathBuilder</code> + */ + public final CertPathBuilderResult build(CertPathParameters params) + throws CertPathBuilderException, InvalidAlgorithmParameterException + { + return builderSpi.engineBuild(params); + } + + /** + * Returns the default <code>CertPathBuilder</code> type as specified in + * the Java security properties file, or the string "PKIX" if no + * such property exists. The Java security properties file is located in the + * file named <JAVA_HOME>/lib/security/java.security, where + * <JAVA_HOME> refers to the directory where the SDK was installed.<br /> + * <br /> + * The default <code>CertPathBuilder</code> type can be used by + * applications that do not want to use a hard-coded type when calling one + * of the <code>getInstance</code> methods, and want to provide a default + * type in case a user does not specify its own.<br /> + * <br /> + * The default <code>CertPathBuilder</code> type can be changed by setting + * the value of the "certpathbuilder.type" security property (in the Java + * security properties file) to the desired type. + * + * @return the default <code>CertPathBuilder</code> type as specified in + * the Java security properties file, or the string "PKIX" + * if no such property exists. + */ + public static final String getDefaultType() + { + String defaulttype = null; + defaulttype = Security.getProperty("certpathbuilder.type"); + + if (defaulttype == null || defaulttype.length() <= 0) + { + return "PKIX"; + } + else + { + return defaulttype; + } + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderException.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderException.java new file mode 100644 index 00000000..1dce8758 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderException.java @@ -0,0 +1,182 @@ +package org.spongycastle.jce.cert; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.security.GeneralSecurityException; + +/** + * An exception indicating one of a variety of problems encountered + * when building a certification path with a + * <code>CertPathBuilder</code>.<br /> + * <br /> + * A <code>CertPathBuilderException</code> provides support for + * wrapping exceptions. The {@link #getCause() getCause} method + * returns the throwable, if any, that caused this exception to be + * thrown.<br /> + * <br /> + * <strong>Concurrent Access</strong><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are + * not thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize. + * + * @see CertPathBuilder + **/ +public class CertPathBuilderException extends GeneralSecurityException +{ + private Throwable cause; + + /** + * Creates a <code>CertPathBuilderException</code> with <code>null</code> + * as its detail message. + */ + public CertPathBuilderException() + { + } + + /** + * Creates a <code>CertPathBuilderException</code> with the given detail + * message. The detail message is a <code>String</code> that describes + * this particular exception in more detail. + * + * @param msg + * the detail message + */ + public CertPathBuilderException(String message) + { + super(message); + } + + /** + * Creates a <code>CertPathBuilderException</code> that wraps the + * specified throwable. This allows any exception to be converted into a + * <code>CertPathBuilderException</code>, while retaining information + * about the wrapped exception, which may be useful for debugging. The + * detail message is set to + * <code>(cause==null ? null : cause.toString())</code> (which typically + * contains the class and detail message of cause). + * + * @param cause + * the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A null value is permitted, and + * indicates that the cause is nonexistent or unknown.) + */ + public CertPathBuilderException(String message, Throwable cause) + { + super(message); + this.cause = cause; + } + + /** + * Creates a <code>CertPathBuilderException</code> with the specified + * detail message and cause. + * + * @param msg + * the detail message + * @param cause + * the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A null value is permitted, and + * indicates that the cause is nonexistent or unknown.) + */ + public CertPathBuilderException(Throwable cause) + { + this.cause = cause; + } + + /** + * Returns the internal (wrapped) cause, or null if the cause is nonexistent + * or unknown. + * + * @return the cause of this throwable or <code>null</code> if the cause + * is nonexistent or unknown. + */ + public Throwable getCause() + { + return cause; + } + + /** + * Returns the detail message for this CertPathBuilderException. + * + * @return the detail message, or <code>null</code> if neither the message + * nor internal cause were specified + */ + public String getMessage() + { + String message = super.getMessage(); + + if (message == null && cause == null) + { + return null; + } + + if (cause != null) + { + return cause.getMessage(); + } + + return message; + } + + /** + * Returns a string describing this exception, including a description of + * the internal (wrapped) cause if there is one. + * + * @return a string representation of this + * <code>CertPathBuilderException</code> + */ + public String toString() + { + String message = getMessage(); + if (message == null) + { + return ""; + } + + return message; + } + + /** + * Prints a stack trace to <code>System.err</code>, including the + * backtrace of the cause, if any. + */ + public void printStackTrace() + { + printStackTrace(System.err); + } + + /** + * Prints a stack trace to a <code>PrintStream</code>, including the + * backtrace of the cause, if any. + * + * @param ps + * the <code>PrintStream</code> to use for output + */ + public void printStackTrace(PrintStream ps) + { + super.printStackTrace(ps); + if (getCause() != null) + { + getCause().printStackTrace(ps); + } + } + + /** + * Prints a stack trace to a <code>PrintWriter</code>, including the + * backtrace of the cause, if any. + * + * @param ps + * the <code>PrintWriter</code> to use for output + */ + public void printStackTrace(PrintWriter pw) + { + super.printStackTrace(pw); + if (getCause() != null) + { + getCause().printStackTrace(pw); + } + } +} + diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderResult.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderResult.java new file mode 100644 index 00000000..a1518cba --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderResult.java @@ -0,0 +1,38 @@ +package org.spongycastle.jce.cert; + +/** + * A specification of the result of a certification path builder algorithm. + * All results returned by the {@link CertPathBuilder#build CertPathBuilder.build} method + * must implement this interface.<br /> + * <br /> + * At a minimum, a CertPathBuilderResult contains the CertPath built by the + * CertPathBuilder instance. Implementations of this interface may add methods + * to return implementation or algorithm specific information, such as + * debugging information or certification path validation results.<br /> + * <br /> + * <strong>Concurrent Access</strong><br /> + * <br /> + * Unless otherwise specified, the methods defined in this interface are not + * thread-safe. Multiple threads that need to access a single object + * concurrently should synchronize amongst themselves and provide the + * necessary locking. Multiple threads each manipulating separate objects + * need not synchronize. + **/ +public interface CertPathBuilderResult extends Cloneable +{ + /** + * Returns the built certification path. + * + * @return the certification path (never <code>null</code>) + */ + public CertPath getCertPath(); + + /** + * Makes a copy of this <code>CertPathBuilderResult</code>. + * Changes to the copy will not affect the original and vice + * versa. + * + * @return a copy of this CertPathBuilderResult + */ + public Object clone(); +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderSpi.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderSpi.java new file mode 100644 index 00000000..bb08d99a --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderSpi.java @@ -0,0 +1,50 @@ +package org.spongycastle.jce.cert; + +import java.security.InvalidAlgorithmParameterException; + +/** + * The Service Provider Interface (SPI) for the CertPathBuilder + * class. All CertPathBuilder implementations must include a class + * (the SPI class) that extends this class (CertPathBuilderSpi) and + * implements all of its methods. In general, instances of this class + * should only be accessed through the CertPathBuilder class. For + * details, see the Java Cryptography Architecture.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Instances of this class need not be protected against concurrent + * access from multiple threads. Threads that need to access a single + * CertPathBuilderSpi instance concurrently should synchronize amongst + * themselves and provide the necessary locking before calling the + * wrapping CertPathBuilder object.<br /> + * <br /> + * However, implementations of CertPathBuilderSpi may still encounter + * concurrency issues, since multiple threads each manipulating a + * different CertPathBuilderSpi instance need not synchronize. + **/ +public abstract class CertPathBuilderSpi + extends Object +{ + /** + * The default constructor. + */ + public CertPathBuilderSpi() {} + + /** + * Attempts to build a certification path using the specified + * algorithm parameter set. + * + * @param params the algorithm parameters + * + * @return the result of the build algorithm + * + * @exception CertPathBuilderException if the builder is unable + * to construct a certification path that satisfies the + * specified + * @exception parametersInvalidAlgorithmParameterException if the + * specified parameters are inappropriate for this CertPathBuilder + */ + public abstract CertPathBuilderResult engineBuild(CertPathParameters params) + throws CertPathBuilderException, + InvalidAlgorithmParameterException; +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathParameters.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathParameters.java new file mode 100644 index 00000000..96978bd7 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathParameters.java @@ -0,0 +1,18 @@ +package org.spongycastle.jce.cert; + +/** + * A specification of certification path algorithm parameters. The purpose + * of this interface is to group (and provide type safety for) all CertPath + * parameter specifications. All <code>CertPath</code> parameter specifications must + * implement this interface. + **/ +public interface CertPathParameters extends Cloneable +{ + /** + * Makes a copy of this <code>CertPathParameters</code>. Changes to the + * copy will not affect the original and vice versa. + * + * @return a copy of this <code>CertPathParameters</code> + **/ + public Object clone(); +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidator.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidator.java new file mode 100644 index 00000000..d2e59931 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidator.java @@ -0,0 +1,276 @@ +package org.spongycastle.jce.cert; + +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.Security; + +/** + * A class for validating certification paths (also known as certificate + * chains).<br /> + * <br /> + * This class uses a provider-based architecture, as described in the Java + * Cryptography Architecture. To create a <code>CertPathValidator</code>, + * call one of the static <code>getInstance</code> methods, passing in the + * algorithm name of the <code>CertPathValidator</code> desired and + * optionally the name of the provider desired. <br /> + * <br /> + * Once a <code>CertPathValidator</code> object has been created, it can + * be used to validate certification paths by calling the {@link #validate + * validate} method and passing it the <code>CertPath</code> to be validated + * and an algorithm-specific set of parameters. If successful, the result is + * returned in an object that implements the + * <code>CertPathValidatorResult</code> interface.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * The static methods of this class are guaranteed to be thread-safe. + * Multiple threads may concurrently invoke the static methods defined in + * this class with no ill effects.<br /> + * <br /> + * However, this is not true for the non-static methods defined by this class. + * Unless otherwise documented by a specific provider, threads that need to + * access a single <code>CertPathValidator</code> instance concurrently should + * synchronize amongst themselves and provide the necessary locking. Multiple + * threads each manipulating a different <code>CertPathValidator</code> + * instance need not synchronize.<br /> + * <br /> + * @see CertPath + **/ +public class CertPathValidator extends Object +{ + private CertPathValidatorSpi validatorSpi; + + private Provider provider; + + private String algorithm; + + /** + * Creates a <code>CertPathValidator</code> object of the given algorithm, + * and encapsulates the given provider implementation (SPI object) in it. + * + * @param validatorSpi + * the provider implementation + * @param provider + * the provider + * @param algorithm + * the algorithm name + */ + protected CertPathValidator( + CertPathValidatorSpi validatorSpi, + Provider provider, + String algorithm) + { + this.validatorSpi = validatorSpi; + this.provider = provider; + this.algorithm = algorithm; + } + + /** + * Returns a <code>CertPathValidator</code> object that implements the + * specified algorithm.<br /> + * <br /> + * If the default provider package provides an implementation of the + * specified <code>CertPathValidator</code> algorithm, an instance of + * <code>CertPathValidator</code> containing that implementation is + * returned. If the requested algorithm is not available in the default + * package, other packages are searched. + * + * @param algorithm + * the name of the requested <code>CertPathValidator</code> + * algorithm + * + * @return a <code>CertPathValidator</code> object that implements the + * specified algorithm + * + * @exception NoSuchAlgorithmException + * if the requested algorithm is not available in the default + * provider package or any of the other provider packages + * that were searched + */ + public static CertPathValidator getInstance(String algorithm) + throws NoSuchAlgorithmException + { + try + { + CertUtil.Implementation imp = CertUtil.getImplementation( + "CertPathValidator", algorithm, (String)null); + if (imp != null) + { + return new CertPathValidator((CertPathValidatorSpi)imp + .getEngine(), imp.getProvider(), algorithm); + } + } + catch (NoSuchProviderException ex) + { + } + throw new NoSuchAlgorithmException("can't find algorithm " + algorithm); + } + + /** + * Returns a <code>CertPathValidator</code> object that implements the + * specified algorithm, as supplied by the specified provider. + * + * @param algorithm + * the name of the requested <code>CertPathValidator</code> + * algorithm + * @param provider + * the name of the provider + * + * @return a <code>CertPathValidator</code> object that implements the + * specified algorithm, as supplied by the specified provider + * + * @exception NoSuchAlgorithmException + * if the requested algorithm is not available from the + * specified provider + * @exception NoSuchProviderException + * if the provider has not been configured + * @exception IllegalArgumentException + * if the <code>provider</code> is null + */ + public static CertPathValidator getInstance(String algorithm, + String provider) throws NoSuchAlgorithmException, + NoSuchProviderException + { + if (provider == null) + { + throw new IllegalArgumentException("provider must be non-null"); + } + + CertUtil.Implementation imp = CertUtil.getImplementation( + "CertPathValidator", algorithm, provider); + if (imp != null) + { + return new CertPathValidator((CertPathValidatorSpi)imp.getEngine(), + imp.getProvider(), algorithm); + } + throw new NoSuchAlgorithmException("can't find algorithm " + algorithm); + } + + /** + * Returns a <code>CertPathValidator</code> object that implements the + * specified algorithm, as supplied by the specified provider. Note: the + * <code>provider</code> doesn't have to be registered. + * + * @param algorithm + * the name of the requested <code>CertPathValidator</code> + * algorithm + * @param provider + * the provider + * + * @return a <code>CertPathValidator</code> object that implements the + * specified algorithm, as supplied by the specified provider + * + * @exception NoSuchAlgorithmException + * if the requested algorithm is not available from the + * specified provider + * @exception IllegalArgumentException + * if the <code>provider</code> is null + */ + public static CertPathValidator getInstance(String algorithm, + Provider provider) throws NoSuchAlgorithmException + { + if (provider == null) + { + throw new IllegalArgumentException("provider must be non-null"); + } + + CertUtil.Implementation imp = CertUtil.getImplementation( + "CertPathValidator", algorithm, provider); + if (imp != null) + { + return new CertPathValidator((CertPathValidatorSpi)imp.getEngine(), + provider, algorithm); + } + throw new NoSuchAlgorithmException("can't find algorithm " + algorithm); + } + + /** + * Returns the <code>Provider</code> of this + * <code>CertPathValidator</code>. + * + * @return the <code>Provider</code> of this + * <code>CertPathValidator</code> + */ + public final Provider getProvider() + { + return provider; + } + + /** + * Returns the algorithm name of this <code>CertPathValidator</code>. + * + * @return the algorithm name of this <code>CertPathValidator</code> + */ + public final String getAlgorithm() + { + return algorithm; + } + + /** + * Validates the specified certification path using the specified algorithm + * parameter set.<br /> + * <br /> + * The <code>CertPath</code> specified must be of a type that is supported + * by the validation algorithm, otherwise an + * <code>InvalidAlgorithmParameterException</code> will be thrown. For + * example, a <code>CertPathValidator</code> that implements the PKIX + * algorithm validates <code>CertPath</code> objects of type X.509. + * + * @param certPath + * the <code>CertPath</code> to be validated + * @param params + * the algorithm parameters + * + * @return the result of the validation algorithm + * + * @exception CertPathValidatorException + * if the <code>CertPath</code> does not validate + * @exception InvalidAlgorithmParameterException + * if the specified parameters or the type of the specified + * <code>CertPath</code> are inappropriate for this + * <code>CertPathValidator</code> + */ + public final CertPathValidatorResult validate(CertPath certPath, + CertPathParameters params) throws CertPathValidatorException, + InvalidAlgorithmParameterException + { + return validatorSpi.engineValidate(certPath, params); + } + + /** + * Returns the default <code>CertPathValidator</code> type as specified in + * the Java security properties file, or the string "PKIX" if no + * such property exists. The Java security properties file is located in the + * file named <JAVA_HOME>/lib/security/java.security, where + * <JAVA_HOME> refers to the directory where the SDK was installed.<br /> + * <br /> + * The default <code>CertPathValidator</code> type can be used by + * applications that do not want to use a hard-coded type when calling one + * of the <code>getInstance</code> methods, and want to provide a default + * type in case a user does not specify its own.<br /> + * <br /> + * The default <code>CertPathValidator</code> type can be changed by + * setting the value of the "certpathvalidator.type" security property (in + * the Java security properties file) to the desired type. + * + * @return the default <code>CertPathValidator</code> type as specified in + * the Java security properties file, or the string "PKIX" + * if no such property exists. + */ + public static final String getDefaultType() + { + String defaulttype = null; + defaulttype = Security.getProperty("certpathvalidator.type"); + + if (defaulttype == null || defaulttype.length() <= 0) + { + return "PKIX"; + } + else + { + return defaulttype; + } + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorException.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorException.java new file mode 100644 index 00000000..bcd67a4a --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorException.java @@ -0,0 +1,271 @@ +package org.spongycastle.jce.cert; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.security.GeneralSecurityException; + +/** + * An exception indicating one of a variety of problems encountered when + * validating a certification path. <br /> + * <br /> + * A <code>CertPathValidatorException</code> provides support for wrapping + * exceptions. The {@link #getCause getCause} method returns the throwable, + * if any, that caused this exception to be thrown. <br /> + * <br /> + * A <code>CertPathValidatorException</code> may also include the + * certification path that was being validated when the exception was thrown + * and the index of the certificate in the certification path that caused the + * exception to be thrown. Use the {@link #getCertPath getCertPath} and + * {@link #getIndex getIndex} methods to retrieve this information.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are not + * thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize. + * + * @see CertPathValidator + **/ +public class CertPathValidatorException extends GeneralSecurityException +{ + private Throwable cause; + private CertPath certPath; + private int index = -1; + + /** + * Creates a <code>CertPathValidatorException</code> with no detail + * message. + */ + public CertPathValidatorException() + { + super(); + } + + /** + * Creates a <code>CertPathValidatorException</code> with the given detail + * message. A detail message is a <code>String</code> that describes this + * particular exception. + * + * @param messag + * the detail message + */ + public CertPathValidatorException(String message) + { + super(message); + } + + /** + * Creates a <code>CertPathValidatorException</code> with the specified + * detail message and cause. + * + * @param msg + * the detail message + * @param cause + * the cause (which is saved for later retrieval by the + * {@link #getCause getCause()} method). (A <code>null</code> + * value is permitted, and indicates that the cause is + * nonexistent or unknown.) + */ + public CertPathValidatorException(String message, Throwable cause) + { + super(message); + this.cause = cause; + } + + /** + * Creates a <code>CertPathValidatorException</code> with the specified + * detail message, cause, certification path, and index. + * + * @param msg + * the detail message (or <code>null</code> if none) + * @param cause + * the cause (or <code>null</code> if none) + * @param certPath + * the certification path that was in the process of being + * validated when the error was encountered + * @param index + * the index of the certificate in the certification path that + * caused the error (or -1 if not applicable). Note that the list + * of certificates in a <code>CertPath</code> is zero based. + * + * @exception IndexOutOfBoundsException + * if the index is out of range + * <code>(index < -1 || (certPath != null && index >= + * certPath.getCertificates().size())</code> + * @exception IllegalArgumentException + * if <code>certPath</code> is <code>null</code> and + * <code>index</code> is not -1 + */ + public CertPathValidatorException( + String message, + Throwable cause, + CertPath certPath, + int index) + { + super(message); + + if (certPath == null && index != -1) + { + throw new IllegalArgumentException( + "certPath = null and index != -1"); + } + if (index < -1 + || (certPath != null && index >= certPath.getCertificates() + .size())) + { + throw new IndexOutOfBoundsException( + " index < -1 or out of bound of certPath.getCertificates()"); + } + + this.cause = cause; + this.certPath = certPath; + this.index = index; + } + + /** + * Creates a <code>CertPathValidatorException</code> that wraps the + * specified throwable. This allows any exception to be converted into a + * <code>CertPathValidatorException</code>, while retaining information + * about the wrapped exception, which may be useful for debugging. The + * detail message is set to (<code>cause==null ? null : cause.toString() + * </code>) + * (which typically contains the class and detail message of cause). + * + * @param cause + * the cause (which is saved for later retrieval by the + * {@link #getCause getCause()} method). (A <code>null</code> + * value is permitted, and indicates that the cause is + * nonexistent or unknown.) + */ + public CertPathValidatorException(Throwable cause) + { + this.cause = cause; + } + + /** + * Returns the detail message for this + * <code>CertPathValidatorException</code>. + * + * @return the detail message, or <code>null</code> if neither the message + * nor cause were specified + */ + public String getMessage() + { + String message = super.getMessage(); + + if (message != null) + { + return message; + } + + if (cause != null) + { + return cause.getMessage(); + } + + return null; + } + + /** + * Returns the certification path that was being validated when the + * exception was thrown. + * + * @return the <code>CertPath</code> that was being validated when the + * exception was thrown (or <code>null</code> if not specified) + */ + public CertPath getCertPath() + { + return certPath; + } + + /** + * Returns the index of the certificate in the certification path that + * caused the exception to be thrown. Note that the list of certificates in + * a <code>CertPath</code> is zero based. If no index has been set, -1 is + * returned. + * + * @return the index that has been set, or -1 if none has been set + */ + public int getIndex() + { + return index; + } + + /** + * Returns the cause of this <code>CertPathValidatorException</code> or + * <code>null</code> if the cause is nonexistent or unknown. + * + * @return the cause of this throwable or <code>null</code> if the cause + * is nonexistent or unknown. + */ + public Throwable getCause() + { + return cause; + } + + /** + * Returns a string describing this exception, including a description of + * the internal (wrapped) cause if there is one. + * + * @return a string representation of this + * <code>CertPathValidatorException</code> + */ + public String toString() + { + StringBuffer sb = new StringBuffer(); + String s = getMessage(); + if (s != null) + { + sb.append(s); + } + if (getIndex() >= 0) + { + sb.append("index in certpath: ").append(getIndex()).append('\n'); + sb.append(getCertPath()); + } + return sb.toString(); + } + + /** + * Prints a stack trace to <code>System.err</code>, including the + * backtrace of the cause, if any. + */ + public void printStackTrace() + { + printStackTrace(System.err); + } + + /** + * Prints a stack trace to a <code>PrintStream</code>, including the + * backtrace of the cause, if any. + * + * @param ps + * the <code>PrintStream</code> to use for output + */ + public void printStackTrace(PrintStream ps) + { + super.printStackTrace(ps); + if (getCause() != null) + { + getCause().printStackTrace(ps); + } + } + + /** + * Prints a stack trace to a <code>PrintWriter</code>, including the + * backtrace of the cause, if any. + * + * @param pw + * the <code>PrintWriter</code> to use for output + */ + public void printStackTrace(PrintWriter pw) + { + super.printStackTrace(pw); + if (getCause() != null) + { + getCause().printStackTrace(pw); + } + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorResult.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorResult.java new file mode 100644 index 00000000..e31b23f2 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorResult.java @@ -0,0 +1,22 @@ +package org.spongycastle.jce.cert; + +/** + * A specification of the result of a certification path validator algorithm.<br /> + * <br /> + * The purpose of this interface is to group (and provide type safety + * for) all certification path validator results. All results returned + * by the {@link CertPathValidator#validate CertPathValidator.validate} + * method must implement this interface. + * + * @see CertPathValidator + **/ +public interface CertPathValidatorResult extends Cloneable +{ + /** + * Makes a copy of this <code>CertPathValidatorResult</code>. Changes to the + * copy will not affect the original and vice versa. + * + * @return a copy of this <code>CertPathValidatorResult</code> + */ + public Object clone(); +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorSpi.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorSpi.java new file mode 100644 index 00000000..39f706d2 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorSpi.java @@ -0,0 +1,59 @@ +package org.spongycastle.jce.cert; + +import java.security.InvalidAlgorithmParameterException; + +/** + * + * The <i>Service Provider Interface</i> (<b>SPI</b>) + * for the {@link CertPathValidator CertPathValidator} class. All + * <code>CertPathValidator</code> implementations must include a class (the + * SPI class) that extends this class (<code>CertPathValidatorSpi</code>) + * and implements all of its methods. In general, instances of this class + * should only be accessed through the <code>CertPathValidator</code> class. + * For details, see the Java Cryptography Architecture.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Instances of this class need not be protected against concurrent + * access from multiple threads. Threads that need to access a single + * <code>CertPathValidatorSpi</code> instance concurrently should synchronize + * amongst themselves and provide the necessary locking before calling the + * wrapping <code>CertPathValidator</code> object.<br /> + * <br /> + * However, implementations of <code>CertPathValidatorSpi</code> may still + * encounter concurrency issues, since multiple threads each + * manipulating a different <code>CertPathValidatorSpi</code> instance need not + * synchronize. + **/ +public abstract class CertPathValidatorSpi extends Object +{ + /** + * The default constructor. + */ + public CertPathValidatorSpi() {} + + /** + * Validates the specified certification path using the specified + * algorithm parameter set.<br /> + * <br /> + * The <code>CertPath</code> specified must be of a type that is + * supported by the validation algorithm, otherwise an + * <code>InvalidAlgorithmParameterException</code> will be thrown. For + * example, a <code>CertPathValidator</code> that implements the PKIX + * algorithm validates <code>CertPath</code> objects of type X.509. + * + * @param certPath the <code>CertPath</code> to be validated + * @param params the algorithm parameters + * + * @return the result of the validation algorithm + * + * @exception CertPathValidatorException if the <code>CertPath</code> + * does not validate + * @exception InvalidAlgorithmParameterException if the specified + * parameters or the type of the specified <code>CertPath</code> are + * inappropriate for this <code>CertPathValidator</code> + */ + public abstract CertPathValidatorResult engineValidate(CertPath certPath, CertPathParameters params) + throws CertPathValidatorException, + InvalidAlgorithmParameterException; +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertSelector.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertSelector.java new file mode 100644 index 00000000..2f2b0b46 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertSelector.java @@ -0,0 +1,41 @@ +package org.spongycastle.jce.cert; + +import java.security.cert.Certificate; + +/** + * A selector that defines a set of criteria for selecting + * <code>Certificate</code>s. Classes that implement this interface + * are often used to specify which <code>Certificate</code>s should + * be retrieved from a <code>CertStore</code>.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this interface are not + * thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize. + * + * @see Certificate + * @see CertStore + * @see CertStore#getCertificates + */ +public interface CertSelector extends Cloneable +{ + /** + * Decides whether a <code>Certificate</code> should be selected. + * + * @param cert the <code>Certificate</code> to be checked + * @return <code>true</code> if the <code>Certificate</code> + * should be selected, <code>false</code> otherwise + */ + public boolean match(Certificate cert); + + /** + * Makes a copy of this <code>CertSelector</code>. Changes to the + * copy will not affect the original and vice versa. + * + * @return a copy of this <code>CertSelector</code> + */ + public Object clone(); +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStore.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStore.java new file mode 100644 index 00000000..8a284262 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStore.java @@ -0,0 +1,382 @@ +package org.spongycastle.jce.cert; + +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.Security; +import java.util.Collection; + +/** + * A class for retrieving <code>Certificate</code>s and <code>CRL</code>s + * from a repository.<br /> + * <br /> + * This class uses a provider-based architecture, as described in the + * Java Cryptography Architecture. + * To create a <code>CertStore</code>, call one of the static + * <code>getInstance</code> methods, passing in the type of + * <code>CertStore</code> desired, any applicable initialization parameters + * and optionally the name of the provider desired. <br /> + * <br /> + * Once the <code>CertStore</code> has been created, it can be used to + * retrieve <code>Certificate</code>s and <code>CRL</code>s by calling its + * {@link #getCertificates(CertSelector selector) getCertificates} and + * {@link #getCRLs(CRLSelector selector) getCRLs} methods.<br /> + * <br /> + * Unlike a {@link java.security.KeyStore KeyStore}, which provides access + * to a cache of private keys and trusted certificates, a + * <code>CertStore</code> is designed to provide access to a potentially + * vast repository of untrusted certificates and CRLs. For example, an LDAP + * implementation of <code>CertStore</code> provides access to certificates + * and CRLs stored in one or more directories using the LDAP protocol and the + * schema as defined in the RFC service attribute. See Appendix A in the + * Java Certification Path API Programmer's Guide for more information about + * standard <code>CertStore</code> types.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * All public methods of <code>CertStore</code> objects must be thread-safe. + * That is, multiple threads may concurrently invoke these methods on a + * single <code>CertStore</code> object (or more than one) with no + * ill effects. This allows a <code>CertPathBuilder</code> to search for a + * CRL while simultaneously searching for further certificates, for instance.<br /> + * <br /> + * The static methods of this class are also guaranteed to be thread-safe. + * Multiple threads may concurrently invoke the static methods defined in + * this class with no ill effects.<br /> + * <br /> + **/ +public class CertStore extends Object +{ + private CertStoreSpi storeSpi; + + private Provider provider; + + private String type; + + private CertStoreParameters params; + + /** + * Creates a <code>CertStore</code> object of the given type, and + * encapsulates the given provider implementation (SPI object) in it. + * + * @param storeSpi + * the provider implementation + * @param provider + * the provider + * @param type + * the type + * @param params + * the initialization parameters (may be <code>null</code>) + */ + protected CertStore( + CertStoreSpi storeSpi, + Provider provider, + String type, + CertStoreParameters params) + { + this.storeSpi = storeSpi; + this.provider = provider; + this.type = type; + this.params = params; + } + + /** + * Returns a <code>Collection</code> of <code>Certificate</code>s that + * match the specified selector. If no <code>Certificate</code>s match + * the selector, an empty <code>Collection</code> will be returned.<br /> + * <br /> + * For some <code>CertStore</code> types, the resulting + * <code>Collection</code> may not contain <b>all</b> of the + * <code>Certificate</code>s that match the selector. For instance, an + * LDAP <code>CertStore</code> may not search all entries in the + * directory. Instead, it may just search entries that are likely to contain + * the <code>Certificate</code>s it is looking for.<br /> + * <br /> + * Some <code>CertStore</code> implementations (especially LDAP + * <code>CertStore</code>s) may throw a <code>CertStoreException</code> + * unless a non-null <code>CertSelector</code> is provided that includes + * specific criteria that can be used to find the certificates. Issuer + * and/or subject names are especially useful criteria. + * + * @param selector + * A <code>CertSelector</code> used to select which + * <code>Certificate</code>s should be returned. Specify + * <code>null</code> to return all <code>Certificate</code>s + * (if supported). + * + * @return A <code>Collection</code> of <code>Certificate</code>s that + * match the specified selector (never <code>null</code>) + * @exception CertStoreException + * if an exception occurs + */ + public final Collection getCertificates(CertSelector selector) + throws CertStoreException + { + return storeSpi.engineGetCertificates(selector); + } + + /** + * Returns a <code>Collection</code> of <code>CRL</code>s that match + * the specified selector. If no <code>CRL</code>s match the selector, an + * empty <code>Collection</code> will be returned.<br /> + * <br /> + * For some <code>CertStore</code> types, the resulting + * <code>Collection</code> may not contain <b>all</b> of the + * <code>CRL</code>s that match the selector. For instance, an LDAP + * <code>CertStore</code> may not search all entries in the directory. + * Instead, it may just search entries that are likely to contain the + * <code>CRL</code>s it is looking for.<br /> + * <br /> + * Some <code>CertStore</code> implementations (especially LDAP + * <code>CertStore</code>s) may throw a <code>CertStoreException</code> + * unless a non-null <code>CRLSelector</code> is provided that includes + * specific criteria that can be used to find the CRLs. Issuer names and/or + * the certificate to be checked are especially useful. + * + * @param selector + * A <code>CRLSelector</code> used to select which + * <code>CRL</code>s should be returned. Specify + * <code>null</code> to return all <code>CRL</code>s (if + * supported). + * + * @return A <code>Collection</code> of <code>CRL</code>s that match + * the specified selector (never <code>null</code>) + * + * @exception CertStoreException + * if an exception occurs + */ + public final Collection getCRLs(CRLSelector selector) + throws CertStoreException + { + return storeSpi.engineGetCRLs(selector); + } + + /** + * Returns a <code>CertStore</code> object that implements the specified + * <code>CertStore</code> type and is initialized with the specified + * parameters.<br /> + * <br /> + * If the default provider package provides an implementation of the + * specified <code>CertStore</code> type, an instance of + * <code>CertStore</code> containing that implementation is returned. If + * the requested type is not available in the default package, other + * packages are searched.<br /> + * <br /> + * The <code>CertStore</code> that is returned is initialized with the + * specified <code>CertStoreParameters</code>. The type of parameters + * needed may vary between different types of <code>CertStore</code>s. + * Note that the specified <code>CertStoreParameters</code> object is + * cloned. + * + * @param type + * the name of the requested <code>CertStore</code> type + * @param params + * the initialization parameters (may be <code>null</code>) + * + * @return a <code>CertStore</code> object that implements the specified + * <code>CertStore</code> type + * + * @exception NoSuchAlgorithmException + * if the requested type is not available in the default + * provider package or any of the other provider packages + * that were searched + * @exception InvalidAlgorithmParameterException + * if the specified initialization parameters are + * inappropriate for this <code>CertStore</code> + */ + public static CertStore getInstance(String type, CertStoreParameters params) + throws InvalidAlgorithmParameterException, NoSuchAlgorithmException + { + try + { + CertUtil.Implementation imp = CertUtil.getImplementation( + "CertStore", type, (String)null, + new Class[] { CertStoreParameters.class }, + new Object[] { params }); + if (imp != null) + { + return new CertStore((CertStoreSpi)imp.getEngine(), imp + .getProvider(), type, params); + } + } + catch (NoSuchProviderException ex) + { + } + throw new NoSuchAlgorithmException("can't find type " + type); + } + + /** + * Returns a <code>CertStore</code> object that implements the specified + * <code>CertStore</code> type, as supplied by the specified provider and + * initialized with the specified parameters.<br /> + * <br /> + * The <code>CertStore</code> that is returned is initialized with the + * specified <code>CertStoreParameters</code>. The type of parameters + * needed may vary between different types of <code>CertStore</code>s. + * Note that the specified <code>CertStoreParameters</code> object is + * cloned. + * + * @param type + * the requested <code>CertStore</code> type + * @param params + * the initialization parameters (may be <code>null</code>) + * @param provider + * the name of the provider + * + * @return a <code>CertStore</code> object that implements the specified + * type, as supplied by the specified provider + * + * @exception NoSuchAlgorithmException + * if the requested type is not available from the specified + * provider + * @exception InvalidAlgorithmParameterException + * if the specified initialization parameters are + * inappropriate for this <code>CertStore</code> + * @exception NoSuchProviderException + * if the provider has not been configured + * @exception IllegalArgumentException + * if the <code>provider</code> is null + */ + public static CertStore getInstance(String type, + CertStoreParameters params, String provider) + throws InvalidAlgorithmParameterException, + NoSuchAlgorithmException, NoSuchProviderException, + IllegalArgumentException + { + if (provider == null) + { + throw new IllegalArgumentException("provider must be non-null"); + } + + CertUtil.Implementation imp = CertUtil.getImplementation("CertStore", + type, provider, new Class[] { CertStoreParameters.class }, + new Object[] { params }); + if (imp != null) + { + return new CertStore((CertStoreSpi)imp.getEngine(), imp + .getProvider(), type, params); + } + throw new NoSuchAlgorithmException("can't find type " + type); + } + + /** + * Returns a <code>CertStore</code> object that implements the specified + * <code>CertStore</code> type, as supplied by the specified provider and + * initialized with the specified parameters. Note: the + * <code>provider</code> doesn't have to be registered.<br /> + * <br /> + * The <code>CertStore</code> that is returned is initialized with the + * specified <code>CertStoreParameters</code>. The type of parameters + * needed may vary between different types of <code>CertStore</code>s. + * Note that the specified <code>CertStoreParameters</code> object is + * cloned. + * + * @param type + * the requested <code>CertStore</code> type + * @param params + * the initialization parameters (may be <code>null</code>) + * @param provider + * the provider + * + * @return a <code>CertStore</code> object that implements the specified + * type, as supplied by the specified provider + * + * @exception NoSuchAlgorithmException + * if the requested type is not available from the specified + * provider + * @exception InvalidAlgorithmParameterException + * if the specified initialization parameters are + * inappropriate for this <code>CertStore</code> + * @exception IllegalArgumentException + * if the <code>provider</code> is null + */ + public static CertStore getInstance(String type, + CertStoreParameters params, Provider provider) + throws NoSuchAlgorithmException, + InvalidAlgorithmParameterException, IllegalArgumentException + { + if (provider == null) + { + throw new IllegalArgumentException("provider must be non-null"); + } + CertUtil.Implementation imp = CertUtil.getImplementation("CertStore", + type, provider, new Class[] { CertStoreParameters.class }, + new Object[] { params }); + if (imp != null) + { + return new CertStore((CertStoreSpi)imp.getEngine(), provider, type, + params); + } + throw new NoSuchAlgorithmException("can't find type " + type); + } + + /** + * Returns the parameters used to initialize this <code>CertStore</code>. + * Note that the <code>CertStoreParameters</code> object is cloned before + * it is returned. + * + * @return the parameters used to initialize this <code>CertStore</code> + * (may be <code>null</code>) + */ + public final CertStoreParameters getCertStoreParameters() + { + return params; + } + + /** + * Returns the type of this <code>CertStore</code>. + * + * @return the type of this <code>CertStore</code> + */ + public final String getType() + { + return type; + } + + /** + * Returns the provider of this <code>CertStore</code>. + * + * @return the provider of this <code>CertStore</code> + */ + public final Provider getProvider() + { + return provider; + } + + /** + * Returns the default <code>CertStore</code> type as specified in the + * Java security properties file, or the string "LDAP" if no such + * property exists. The Java security properties file is located in the file + * named <JAVA_HOME>/lib/security/java.security, where + * <JAVA_HOME> refers to the directory where the SDK was installed.<br /> + * <br /> + * The default <code>CertStore</code> type can be used by applications + * that do not want to use a hard-coded type when calling one of the + * <code>getInstance</code> methods, and want to provide a default + * <code>CertStore</code> type in case a user does not specify its own.<br /> + * <br /> + * The default <code>CertStore</code> type can be changed by setting the + * value of the "certstore.type" security property (in the Java security + * properties file) to the desired type. + * + * @return the default <code>CertStore</code> type as specified in the + * Java security properties file, or the string "LDAP" if + * no such property exists. + */ + public static final String getDefaultType() + { + String defaulttype = null; + defaulttype = Security.getProperty("certstore.type"); + + if (defaulttype == null || defaulttype.length() <= 0) + { + return "LDAP"; + } + else + { + return defaulttype; + } + } +} + diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreException.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreException.java new file mode 100644 index 00000000..56c9fcfd --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreException.java @@ -0,0 +1,187 @@ +package org.spongycastle.jce.cert; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.security.GeneralSecurityException; + +/** + * An exception indicating one of a variety of problems retrieving + * certificates and CRLs from a <code>CertStore</code>.<br /> + * <br /> + * A <code>CertStoreException</code> provides support for wrapping + * exceptions. The {@link #getCause getCause} method returns the throwable, + * if any, that caused this exception to be thrown.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are not + * thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize. + * + * @see CertStore + **/ +public class CertStoreException extends GeneralSecurityException +{ + private Throwable cause; + + /** + * Creates a <code>CertStoreException</code> with <code>null</code> as + * its detail message. + */ + public CertStoreException() + { + super(); + } + + /** + * Creates a <code>CertStoreException</code> with the given detail + * message. A detail message is a <code>String</code> that describes this + * particular exception. + * + * @param messag + * the detail message + */ + public CertStoreException(String message) + { + super(message); + } + + /** + * Creates a <code>CertStoreException</code> with the specified detail + * message and cause. + * + * @param messag + * the detail message + * @param cause + * the cause (which is saved for later retrieval by the + * {@link #getCause getCause()} method). (A <code>null</code> + * value is permitted, and indicates that the cause is + * nonexistent or unknown.) + */ + public CertStoreException(String message, Throwable cause) + { + super(message); + this.cause = cause; + } + + /** + * Creates a <code>CertStoreException</code> that wraps the specified + * throwable. This allows any exception to be converted into a + * <code>CertStoreException</code>, while retaining information about the + * cause, which may be useful for debugging. The detail message is set to (<code>cause==null ? null : cause.toString()</code>) + * (which typically contains the class and detail message of cause). + * + * @param cause + * the cause (which is saved for later retrieval by the + * {@link #getCause getCause()} method). (A <code>null</code> + * value is permitted, and indicates that the cause is + * nonexistent or unknown.) + */ + public CertStoreException(Throwable cause) + { + this.cause = cause; + } + + /** + * Returns the detail message for this <code>CertStoreException</code>. + * + * @return the detail message, or <code>null</code> if neither the message + * nor cause were specified + */ + public String getMessage() + { + String message = super.getMessage(); + + if (message == null && cause == null) + { + return null; + } + + StringBuffer s = new StringBuffer(); + if (message != null) + { + s.append(message).append('\n'); + } + if (cause != null) + { + s.append("Cause:\n").append(cause.getMessage()); + } + return s.toString(); + } + + /** + * Returns the cause of this <code>CertStoreException</code> or + * <code>null</code> if the cause is nonexistent or unknown. + * + * @return the cause of this throwable or <code>null</code> if the cause + * is nonexistent or unknown. + */ + public Throwable getCause() + { + return cause; + } + + /** + * Returns a string describing this exception, including a description of + * the internal (wrapped) cause if there is one. + * + * @return a string representation of this <code>CertStoreException</code> + */ + public String toString() + { + String message = getMessage(); + if (message == null) + { + return ""; + } + + return message; + } + + /** + * Prints a stack trace to <code>System.err</code>, including the + * backtrace of the cause, if any. + */ + public void printStackTrace() + { + printStackTrace(System.err); + } + + /** + * Prints a stack trace to a <code>PrintStream</code>, including the + * backtrace of the cause, if any. + * + * @param ps + * the <code>PrintStream</code> to use for output + */ + public void printStackTrace(PrintStream ps) + { + super.printStackTrace(ps); + if (cause != null) + { + cause.printStackTrace(ps); + } + } + + /** + * Prints a stack trace to a <code>PrintWriter</code>, including the + * backtrace of the cause, if any. + * + * @param pw + * the <code>PrintWriter</code> to use for output + */ + public void printStackTrace(PrintWriter pw) + { + if (cause != null) + { + cause.printStackTrace(pw); + } + super.printStackTrace(pw); + if (cause != null) + { + cause.printStackTrace(pw); + } + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreParameters.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreParameters.java new file mode 100644 index 00000000..0ec14ede --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreParameters.java @@ -0,0 +1,52 @@ +package org.spongycastle.jce.cert; + +/** + * A specification of <code>CertStore</code> parameters.<br /> + * <br /> + * The purpose of this interface is to group (and provide type safety for) + * all <code>CertStore</code> parameter specifications. All + * <code>CertStore</code> parameter specifications must implement this + * interface. <br /> + * <br /> + * Typically, a <code>CertStoreParameters</code> object is passed as a parameter + * to one of the {@link CertStore#getInstance CertStore.getInstance} methods. + * The <code>getInstance</code> method returns a <code>CertStore</code> that + * is used for retrieving <code>Certificate</code>s and <code>CRL</code>s. The + * <code>CertStore</code> that is returned is initialized with the specified + * parameters. The type of parameters needed may vary between different types + * of <code>CertStore</code>s. + * + * @see CertStore#getInstance + **/ +public interface CertStoreParameters extends Cloneable +{ + /** + * Makes a copy of this <code>CertStoreParameters</code>.<br /> + * <br /> + * The precise meaning of "copy" may depend on the class of + * the <code>CertStoreParameters</code> object. A typical implementation + * performs a "deep copy" of this object, but this is not an absolute + * requirement. Some implementations may perform a "shallow copy" of some + * or all of the fields of this object.<br /> + * <br /> + * Note that the <code>CertStore.getInstance</code> methods make a copy + * of the specified <code>CertStoreParameters</code>. A deep copy + * implementation of <code>clone</code> is safer and more robust, as it + * prevents the caller from corrupting a shared <code>CertStore</code> by + * subsequently modifying the contents of its initialization parameters. + * However, a shallow copy implementation of <code>clone</code> is more + * appropriate for applications that need to hold a reference to a + * parameter contained in the <code>CertStoreParameters</code>. For example, + * a shallow copy clone allows an application to release the resources of + * a particular <code>CertStore</code> initialization parameter immediately, + * rather than waiting for the garbage collection mechanism. This should + * be done with the utmost care, since the <code>CertStore</code> may still + * be in use by other threads.<br /> + * <br /> + * Each subclass should state the precise behavior of this method so + * that users and developers know what to expect. + * + * @return a copy of this <code>CertStoreParameters</code> + */ + public Object clone(); +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreSpi.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreSpi.java new file mode 100644 index 00000000..fd9fe6a3 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreSpi.java @@ -0,0 +1,104 @@ +package org.spongycastle.jce.cert; + +import java.security.InvalidAlgorithmParameterException; +import java.util.Collection; + +/** + * The <i>Service Provider Interface</i> (<b>SPI</b>) + * for the {@link CertStore CertStore} class. All <code>CertStore</code> + * implementations must include a class (the SPI class) that extends + * this class (<code>CertStoreSpi</code>), provides a constructor with + * a single argument of type <code>CertStoreParameters</code>, and implements + * all of its methods. In general, instances of this class should only be + * accessed through the <code>CertStore</code> class. + * For details, see the Java Cryptography Architecture.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * The public methods of all <code>CertStoreSpi</code> objects must be + * thread-safe. That is, multiple threads may concurrently invoke these + * methods on a single <code>CertStoreSpi</code> object (or more than one) + * with no ill effects. This allows a <code>CertPathBuilder</code> to search + * for a CRL while simultaneously searching for further certificates, for + * instance.<br /> + * <br /> + * Simple <code>CertStoreSpi</code> implementations will probably ensure + * thread safety by adding a <code>synchronized</code> keyword to their + * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods. + * More sophisticated ones may allow truly concurrent access. + **/ +public abstract class CertStoreSpi + extends Object +{ + + /** + * The sole constructor. + * + * @param params the initialization parameters (may be <code>null</code>) + * @exception InvalidAlgorithmParameterException if the initialization + * parameters are inappropriate for this <code>CertStoreSpi</code> + */ + public CertStoreSpi(CertStoreParameters params) + throws InvalidAlgorithmParameterException {} + + /** + * Returns a <code>Collection</code> of <code>Certificate</code>s that + * match the specified selector. If no <code>Certificate</code>s + * match the selector, an empty <code>Collection</code> will be returned.<br /> + * <br /> + * For some <code>CertStore</code> types, the resulting + * <code>Collection</code> may not contain <b>all</b> of the + * <code>Certificate</code>s that match the selector. For instance, + * an LDAP <code>CertStore</code> may not search all entries in the + * directory. Instead, it may just search entries that are likely to + * contain the <code>Certificate</code>s it is looking for.<br /> + * <br /> + * Some <code>CertStore</code> implementations (especially LDAP + * <code>CertStore</code>s) may throw a <code>CertStoreException</code> + * unless a non-null <code>CertSelector</code> is provided that includes + * specific criteria that can be used to find the certificates. Issuer + * and/or subject names are especially useful criteria. + * + * @param selector A <code>CertSelector</code> used to select which + * <code>Certificate</code>s should be returned. Specify <code>null</code> + * to return all <code>Certificate</code>s (if supported). + * + * @return A <code>Collection</code> of <code>Certificate</code>s that + * match the specified selector (never <code>null</code>) + * + * @exception CertStoreException if an exception occurs + */ + public abstract Collection engineGetCertificates(CertSelector selector) + throws CertStoreException; + + /** + * Returns a <code>Collection</code> of <code>CRL</code>s that + * match the specified selector. If no <code>CRL</code>s + * match the selector, an empty <code>Collection</code> will be returned.<br /> + * <br /> + * For some <code>CertStore</code> types, the resulting + * <code>Collection</code> may not contain <b>all</b> of the + * <code>CRL</code>s that match the selector. For instance, + * an LDAP <code>CertStore</code> may not search all entries in the + * directory. Instead, it may just search entries that are likely to + * contain the <code>CRL</code>s it is looking for. <br /> + * <br /> + * Some <code>CertStore</code> implementations (especially LDAP + * <code>CertStore</code>s) may throw a <code>CertStoreException</code> + * unless a non-null <code>CRLSelector</code> is provided that includes + * specific criteria that can be used to find the CRLs. Issuer names + * and/or the certificate to be checked are especially useful. + * + * @param selector A <code>CRLSelector</code> used to select which + * <code>CRL</code>s should be returned. Specify <code>null</code> + * to return all <code>CRL</code>s (if supported). + * + * @return A <code>Collection</code> of <code>CRL</code>s that + * match the specified selector (never <code>null</code>) + * + * @exception CertStoreException if an exception occurs + */ + public abstract Collection engineGetCRLs(CRLSelector selector) + throws CertStoreException; +} + diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertUtil.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertUtil.java new file mode 100644 index 00000000..60c5e8b0 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertUtil.java @@ -0,0 +1,556 @@ +package org.spongycastle.jce.cert; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.Security; + +import org.spongycastle.asn1.ASN1Object; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERIA5String; +import org.spongycastle.asn1.DEROutputStream; +import org.spongycastle.asn1.OIDTokenizer; +import org.spongycastle.asn1.x509.X509Name; +import org.spongycastle.util.Strings; + +class CertUtil +{ + static class Implementation + { + Object engine; + Provider provider; + + Implementation( + Object engine, + Provider provider) + { + this.engine = engine; + this.provider = provider; + } + + Object getEngine() + { + return engine; + } + + Provider getProvider() + { + return provider; + } + } + + /** + * see if we can find an algorithm (or its alias and what it represents) in + * the property table for the given provider. + * + * @return null if no algorithm found, an Implementation if it is. + */ + static Implementation getImplementation( + String baseName, + String algorithm, + Provider prov) + { + if (prov == null) + { + Provider[] provider = Security.getProviders(); + + // + // search every provider looking for the algorithm we want. + // + for (int i = 0; i != provider.length; i++) + { + Implementation imp = getImplementation(baseName, algorithm, provider[i]); + if (imp != null) + { + return imp; + } + } + + return null; + } + + String alias; + + while ((alias = prov.getProperty("Alg.Alias." + baseName + "." + algorithm)) != null) + { + algorithm = alias; + } + + String className = prov.getProperty(baseName + "." + algorithm); + + if (className != null) + { + try + { + return new Implementation(Class.forName(className).newInstance(), prov); + } + catch (ClassNotFoundException e) + { + throw new IllegalStateException( + "algorithm " + algorithm + " in provider " + prov.getName() + " but no class found!"); + } + catch (Exception e) + { + throw new IllegalStateException( + "algorithm " + algorithm + " in provider " + prov.getName() + " but class inaccessible: " + e.toString()); + } + } + + return null; + } + + /** + * return an implementation for a given algorithm/provider. + * If the provider is null, we grab the first avalaible who has the required algorithm. + * + * @return null if no algorithm found, an Implementation if it is. + * @exception NoSuchProviderException if a provider is specified and not found. + */ + static Implementation getImplementation( + String baseName, + String algorithm, + String provider) + throws NoSuchProviderException + { + if (provider == null) + { + Provider[] prov = Security.getProviders(); + + // + // search every provider looking for the algorithm we want. + // + for (int i = 0; i != prov.length; i++) + { + Implementation imp = getImplementation(baseName, algorithm, prov[i]); + if (imp != null) + { + return imp; + } + } + } + else + { + Provider prov = Security.getProvider(provider); + + if (prov == null) + { + throw new NoSuchProviderException("Provider " + provider + " not found"); + } + + return getImplementation(baseName, algorithm, prov); + } + + return null; + } + + /** + * see if we can find an algorithm (or its alias and what it represents) in + * the property table for the given provider. + * + * @return null if no algorithm found, an Implementation if it is. + */ + static Implementation getImplementation(String baseName, String algorithm, + Provider prov, Class[] ctorparamtype, Object[] ctorparam) + throws InvalidAlgorithmParameterException + { + String alias; + + while ((alias = prov.getProperty("Alg.Alias." + baseName + "." + + algorithm)) != null) + { + algorithm = alias; + } + + String className = prov.getProperty(baseName + "." + algorithm); + + if (className != null) + { + try + { + return new Implementation(Class.forName(className) + .getConstructor(ctorparamtype).newInstance(ctorparam), + prov); + } + catch (ClassNotFoundException e) + { + throw new IllegalStateException("algorithm " + algorithm + + " in provider " + prov.getName() + + " but no class found!"); + } + catch (Exception e) + { + if (e instanceof InvalidAlgorithmParameterException) + { + throw (InvalidAlgorithmParameterException)e; + } + + throw new IllegalStateException("algorithm " + algorithm + + " in provider " + prov.getName() + + " but class inaccessible!"); + } + } + + return null; + } + + /** + * return an implementation for a given algorithm/provider. If the provider + * is null, we grab the first avalaible who has the required algorithm. + * + * @return null if no algorithm found, an Implementation if it is. + * + * @exception NoSuchProviderException + * if a provider is specified and not found. + */ + static Implementation getImplementation(String baseName, String algorithm, + String provider, Class[] ctorparamtype, Object[] ctorparam) + throws NoSuchProviderException, InvalidAlgorithmParameterException + { + if (provider == null) + { + Provider[] prov = Security.getProviders(); + + // + // search every provider looking for the algorithm we want. + // + for (int i = 0; i != prov.length; i++) + { + Implementation imp = getImplementation(baseName, algorithm, + prov[i], ctorparamtype, ctorparam); + if (imp != null) + { + return imp; + } + } + } + else + { + Provider prov = Security.getProvider(provider); + + if (prov == null) + { + throw new NoSuchProviderException("Provider " + provider + + " not found"); + } + + return getImplementation(baseName, algorithm, prov, ctorparamtype, + ctorparam); + } + + return null; + } + + static byte[] parseGeneralName(int type, String data) throws IOException + { + byte[] encoded = null; + + switch (type) + { + case 0: + throw new IOException( + "unable to parse OtherName String representation"); + case 1: + encoded = parseRfc822(data.trim()); + break; + case 2: + encoded = parseDNSName(data.trim()); + break; + case 3: + throw new IOException( + "unable to parse ORAddress String representation"); + case 4: + encoded = parseX509Name(data.trim()); + break; + case 5: + throw new IOException( + "unable to parse EDIPartyName String representation"); + case 6: + encoded = parseURI(data.trim()); + break; + case 7: + encoded = parseIP(data.trim()); + break; + case 8: + encoded = parseOID(data.trim()); + break; + default: + throw new IOException( + "unable to parse unkown type String representation"); + } + return encoded; + } + + /** + * Check the format of an OID.<br /> + * Throw an IOException if the first component is not 0, 1 or 2 or the + * second component is greater than 39.<br /> + * <br /> + * User {@link org.spongycastle.asn1.OIDTokenizer OIDTokenizer} + * + * @param the + * OID to be checked. + * + * @exception IOException + * if the first component is not 0, 1 or 2 or the second + * component is greater than 39. + */ + static byte[] parseOID(String oid) throws IOException + { + OIDTokenizer tokenizer = new OIDTokenizer(oid); + String token; + if (!tokenizer.hasMoreTokens()) + { + throw new IOException("OID contains no tokens"); + } + token = tokenizer.nextToken(); + if (token == null) + { + throw new IOException("OID contains no tokens"); + } + try + { + int test = (Integer.valueOf(token)).intValue(); + if (test < 0 || test > 2) + { + throw new IOException("first token is not >= 0 and <=2"); + } + if (!tokenizer.hasMoreTokens()) + { + throw new IOException("OID contains only one token"); + } + token = tokenizer.nextToken(); + if (token == null) + { + throw new IOException("OID contains only one token"); + } + test = (Integer.valueOf(token)).intValue(); + if (test < 0 || test > 39) + { + throw new IOException("secon token is not >= 0 and <=39"); + } + } + catch (NumberFormatException ex) + { + throw new IOException("token: " + token + ": " + ex.toString()); + } + ASN1Object derData = new ASN1ObjectIdentifier(oid); + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + DEROutputStream derOutStream = new DEROutputStream(outStream); + derOutStream.writeObject(derData); + derOutStream.close(); + return outStream.toByteArray(); + } + + /** + * Parse the given IPv4 or IPv6 into DER encoded byte array representation. + * + * @param the + * IP in well known String format + * + * @return the IP as byte array + * + * @exception IOException + * if the String could not be parsed + */ + private static byte[] parseIP(String data) throws IOException + { + byte[] encoded = parseIPv4(data); + + if (encoded == null) + { + encoded = parseIPv6(data); + } + + if (encoded == null) + { + throw new IOException( + "unable to parse IP to DER encoded byte array"); + } + + return encoded; + } + + /** + * Parse the given IPv4 into DER encoded byte array representation. + * + * @param the + * IP in well known String format + * + * @return the IP as byte array or <code>null</code> if not parseable + */ + private static byte[] parseIPv4(String data) + { + if (data.length() == 0) + { + return null; + } + + int octet; + int octets = 0; + byte[] dst = new byte[4]; + + int pos = 0; + int start = 0; + while (start < data.length() + && (pos = data.indexOf('.', start)) > start && pos - start > 3) + { + try + { + octet = (Integer.valueOf(data.substring(start, pos - start))) + .intValue(); + } + catch (NumberFormatException ex) + { + return null; + } + if (octet < 0 || octet > 255) + { + return null; + } + dst[octets++] = (byte)(octet & 0xff); + + start = pos + 1; + } + + if (octets < 4) + { + return null; + } + + return dst; + } + + /** + * Parse the given IPv6 into DER encoded byte array representation.<br /> + * <br /> + * <b>TODO: implement this</b> + * + * @param the + * IP in well known String format + * + * @return the IP as byte array or <code>null</code> if not parseable + */ + private static byte[] parseIPv6(String data) + { + return null; + } + + /** + * Parse the given URI into DER encoded byte array representation. + * + * @param the + * URI in well known String format + * + * @return the URI as byte array + * + * @exception IOException + * if the String could not be parsed + */ + private static byte[] parseURI(String data) throws IOException + { + // TODO do parsing test + ASN1Object derData = new DERIA5String(data); + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + DEROutputStream derOutStream = new DEROutputStream(outStream); + derOutStream.writeObject(derData); + derOutStream.close(); + return outStream.toByteArray(); + } + + /** + * Parse the given rfc822 addr-spec into DER encoded byte array + * representation. + * + * @param the + * rfc822 addr-spec in well known String format + * + * @return the rfc822 addr-spec as byte array + * + * @exception IOException + * if the String could not be parsed + */ + private static byte[] parseRfc822(String data) throws IOException + { + int tmpInt = data.indexOf('@'); + if (tmpInt < 0 || tmpInt >= data.length() - 1) + { + throw new IOException("wrong format of rfc822Name:" + data); + } + // TODO more test for illegal charateers + ASN1Object derData = new DERIA5String(data); + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + DEROutputStream derOutStream = new DEROutputStream(outStream); + derOutStream.writeObject(derData); + derOutStream.close(); + return outStream.toByteArray(); + } + + /** + * Parse the given DNS name into DER encoded byte array representation. The + * String must be in den preffered name syntax as defined in RFC 1034. + * + * @param the + * DNS name in well known String format + * + * @return the DNS name as byte array + * + * @exception IOException + * if the String could not be parsed + */ + private static byte[] parseDNSName(String data) throws IOException + { + // TODO more test for illegal charateers + ASN1Object derData = new DERIA5String(data); + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + DEROutputStream derOutStream = new DEROutputStream(outStream); + derOutStream.writeObject(derData); + derOutStream.close(); + return outStream.toByteArray(); + } + + /** + * Parse the given X.509 name into DER encoded byte array representation. + * + * @param the + * X.509 name in well known String format + * + * @return the X.509 name as byte array + * + * @exception IOException + * if the String could not be parsed + */ + private static byte[] parseX509Name(String data) throws IOException + { + // TODO more test for illegal charateers + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + DEROutputStream derOutStream = new DEROutputStream(outStream); + derOutStream.writeObject(new X509Name(trimX509Name(data))); + derOutStream.close(); + return outStream.toByteArray(); + } + + /** + * Returns the given name converted to upper case and all multi spaces squezed + * to one space. + **/ + static String trimX509Name(String name) + { + String data = Strings.toUpperCase(name.trim()); + int pos; + while ((pos = data.indexOf(" ")) >= 0) + { + data = data.substring(0, pos) + data.substring(pos + 1); + } + while ((pos = data.indexOf(" =")) >= 0) + { + data = data.substring(0, pos) + data.substring(pos + 1); + } + while ((pos = data.indexOf("= ")) >= 0) + { + data = data.substring(0, pos + 1) + data.substring(pos + 2); + } + return data; + } +}
\ No newline at end of file diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertificateFactory.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertificateFactory.java new file mode 100644 index 00000000..a1ead1a6 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertificateFactory.java @@ -0,0 +1,183 @@ +package org.spongycastle.jce.cert; + +import java.io.InputStream; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.cert.CRL; +import java.security.cert.CRLException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +/** + **/ +public class CertificateFactory +{ + private CertificateFactorySpi certFacSpi; + private Provider provider; + private String type; + + protected CertificateFactory( + CertificateFactorySpi certFacSpi, + Provider provider, + String type) + { + this.certFacSpi = certFacSpi; + this.provider = provider; + this.type = type; + } + + public final CRL generateCRL(InputStream inStream) + throws CRLException + { + return certFacSpi.engineGenerateCRL(inStream); + } + + public final Collection generateCRLs(InputStream inStream) + throws CRLException + { + return certFacSpi.engineGenerateCRLs(inStream); + } + + public final Certificate generateCertificate(InputStream inStream) + throws CertificateException + { + return certFacSpi.engineGenerateCertificate(inStream); + } + + public final /*Sk13 Vector*/ Collection generateCertificates(InputStream inStream) + throws CertificateException + { + return certFacSpi.engineGenerateCertificates(inStream); + } + + /** + * Returns an iteration of the <code>CertPath</code> encodings supported + * by this certificate factory, with the default encoding first. See + * Appendix A in the + * Java Certification Path API Programmer's Guide for information about + * standard encoding names and their formats.<br /> + * <br /> + * Attempts to modify the returned <code>Iterator</code> via its + * <code>remove</code> method result in an + * <code>UnsupportedOperationException</code>. + * + * @return an <code>Iterator</code> over the names of the supported + * <code>CertPath</code> encodings (as <code>String</code>s) + */ + public final Iterator getCertPathEncodings() + { + return certFacSpi.engineGetCertPathEncodings(); + } + + /** + * Generates a <code>CertPath</code> object and initializes it with + * the data read from the <code>InputStream</code> inStream. The data + * is assumed to be in the default encoding. The name of the default + * encoding is the first element of the <code>Iterator</code> returned by + * the {@link #getCertPathEncodings getCertPathEncodings} method. + * + * @param inStream an <code>InputStream</code> containing the data + * + * @return a <code>CertPath</code> initialized with the data from the + * <code>InputStream</code> + * + * @exception CertificateException if an exception occurs while decoding + */ + public final CertPath generateCertPath(InputStream inStream) + throws CertificateException + { + return certFacSpi.engineGenerateCertPath(inStream); + } + + /** + * Generates a <code>CertPath</code> object and initializes it with + * the data read from the <code>InputStream</code> inStream. The data + * is assumed to be in the specified encoding. See Appendix A in the + * <a href="../../../../guide/security/certpath/CertPathProgGuide.html#AppA"> + * Java Certification Path API Programmer's Guide</a> + * for information about standard encoding names and their formats. + * + * @param inStream an <code>InputStream</code> containing the data + * @param encoding the encoding used for the data + * + * @return a <code>CertPath</code> initialized with the data from the + * <code>InputStream</code> + * + * @exception CertificateException if an exception occurs while decoding or + * the encoding requested is not supported + */ + public final CertPath generateCertPath(InputStream inStream, String encoding) + throws CertificateException + { + return certFacSpi.engineGenerateCertPath(inStream, encoding); + } + + /** + * Generates a <code>CertPath</code> object and initializes it with + * a <code>List</code> of <code>Certificate</code>s.<br /> + * <br /> + * The certificates supplied must be of a type supported by the + * <code>CertificateFactory</code>. They will be copied out of the supplied + * <code>List</code> object. + * + * @param certificates a <code>List</code> of <code>Certificate</code>s + * + * @return a <code>CertPath</code> initialized with the supplied list of + * certificates + * + * @exception CertificateException if an exception occurs + */ + public final CertPath generateCertPath(List certificates) + throws CertificateException + { + return certFacSpi.engineGenerateCertPath(certificates); + } + + public static final CertificateFactory getInstance(String type) + throws CertificateException + { + try + { + CertUtil.Implementation imp = CertUtil.getImplementation("CertificateFactory", type, (String)null); + + if (imp != null) + { + return new CertificateFactory((CertificateFactorySpi)imp.getEngine(), imp.getProvider(), type); + } + + throw new CertificateException("can't find type " + type); + } + catch (NoSuchProviderException e) + { + throw new CertificateException(type + " not found"); + } + } + + public static final CertificateFactory getInstance( + String type, + String provider) + throws CertificateException, NoSuchProviderException + { + CertUtil.Implementation imp = CertUtil.getImplementation("CertificateFactory", type, provider); + + if (imp != null) + { + return new CertificateFactory((CertificateFactorySpi)imp.getEngine(), imp.getProvider(), type); + } + + throw new CertificateException("can't find type " + type); + } + + public final Provider getProvider() + { + return provider; + } + + public final String getType() + { + return type; + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertificateFactorySpi.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertificateFactorySpi.java new file mode 100644 index 00000000..1bed7721 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertificateFactorySpi.java @@ -0,0 +1,99 @@ +package org.spongycastle.jce.cert; + +import java.io.InputStream; +import java.security.cert.CertificateException; +import java.util.Iterator; +import java.util.List; + +public abstract class CertificateFactorySpi + extends java.security.cert.CertificateFactorySpi +{ + public CertificateFactorySpi() + { + } + + /** + * Returns an iteration of the <code>CertPath</code> encodings supported + * by this certificate factory, with the default encoding first. See + * Appendix A in the + * Java Certification Path API Programmer's Guide + * for information about standard encoding names.<br /> + * <br /> + * Attempts to modify the returned <code>Iterator</code> via its + * <code>remove</code> method result in an + * <code>UnsupportedOperationException</code>.<br /> + * <br /> + * This method was added to version 1.4 of the Java 2 Platform + * Standard Edition. In order to maintain backwards compatibility with + * existing service providers, this method cannot be <code>abstract</code> + * and by default throws an <code>UnsupportedOperationException</code>. + * + * @return an <code>Iterator</code> over the names of the supported + * <code>CertPath</code> encodings (as <code>String</code>s) + * + * @exception UnsupportedOperationException if the method is not supported + */ + public abstract Iterator engineGetCertPathEncodings(); + + /** + * Generates a <code>CertPath</code> object and initializes it with + * the data read from the <code>InputStream</code> inStream. The data + * is assumed to be in the default encoding. + * + * @param inStream an <code>InputStream</code> containing the data + * + * @return a <code>CertPath</code> initialized with the data from the + * <code>InputStream</code> + * + * @exception CertificateException if an exception occurs while decoding + */ + public abstract CertPath engineGenerateCertPath(InputStream inStream) + throws CertificateException; + + /** + * Generates a <code>CertPath</code> object and initializes it with + * the data read from the <code>InputStream</code> inStream. The data + * is assumed to be in the specified encoding.<br /> + * <br /> + * This method was added to version 1.4 of the Java 2 Platform + * Standard Edition. In order to maintain backwards compatibility with + * existing service providers, this method cannot be <code>abstract</code> + * and by default throws an <code>UnsupportedOperationException</code>. + * + * @param inStream an <code>InputStream</code> containing the data + * @param encoding the encoding used for the data + * + * @return a <code>CertPath</code> initialized with the data from the + * <code>InputStream</code> + * + * @exception CertificateException if an exception occurs while decoding or + * the encoding requested is not supported + * @exception UnsupportedOperationException if the method is not supported + */ + public abstract CertPath engineGenerateCertPath(InputStream inStream, String encoding) + throws CertificateException; + + /** + * Generates a <code>CertPath</code> object and initializes it with + * a <code>List</code> of <code>Certificate</code>s.<br /> + * <br /> + * The certificates supplied must be of a type supported by the + * <code>CertificateFactory</code>. They will be copied out of the supplied + * <code>List</code> object.<br /> + * <br /> + * This method was added to version 1.4 of the Java 2 Platform + * Standard Edition. In order to maintain backwards compatibility with + * existing service providers, this method cannot be <code>abstract</code> + * and by default throws an <code>UnsupportedOperationException</code>. + * + * @param certificates a <code>List</code> of <code>Certificate</code>s + * + * @return a <code>CertPath</code> initialized with the supplied list of + * certificates + * + * @exception CertificateException if an exception occurs + * @exception UnsupportedOperationException if the method is not supported + */ + public abstract CertPath engineGenerateCertPath(List certificates) + throws CertificateException; +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CollectionCertStoreParameters.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CollectionCertStoreParameters.java new file mode 100644 index 00000000..1692fefa --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CollectionCertStoreParameters.java @@ -0,0 +1,124 @@ +package org.spongycastle.jce.cert; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * Parameters used as input for the Collection <code>CertStore</code> + * algorithm.<br /> + * <br /> + * This class is used to provide necessary configuration parameters + * to implementations of the Collection <code>CertStore</code> + * algorithm. The only parameter included in this class is the + * <code>Collection</code> from which the <code>CertStore</code> will + * retrieve certificates and CRLs.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are not + * thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize. + * + * @see java.util.Collection + * @see CertStore + **/ +public class CollectionCertStoreParameters implements CertStoreParameters +{ + private Collection collection; + + /** + * Creates an instance of <code>CollectionCertStoreParameters</code> which + * will allow certificates and CRLs to be retrieved from the specified + * <code>Collection</code>. If the specified <code>Collection</code> + * contains an object that is not a <code>Certificate</code> or + * <code>CRL</code>, that object will be ignored by the Collection + * <code>CertStore</code>.<br /> + * <br /> + * The <code>Collection</code> is <b>not</b> copied. Instead, a reference + * is used. This allows the caller to subsequently add or remove + * <code>Certificates</code> or <code>CRL</code>s from the + * <code>Collection</code>, thus changing the set of + * <code>Certificates</code> or <code>CRL</code>s available to the + * Collection <code>CertStore</code>. The Collection + * <code>CertStore</code> will not modify the contents of the + * <code>Collection</code>.<br /> + * <br /> + * If the <code>Collection</code> will be modified by one thread while + * another thread is calling a method of a Collection <code>CertStore</code> + * that has been initialized with this <code>Collection</code>, the + * <code>Collection</code> must have fail-fast iterators. + * + * @param collection + * a <code>Collection</code> of <code>Certificate</code>s + * and <code>CRL</code>s + * + * @exception NullPointerException + * if <code>collection</code> is <code>null</code> + */ + public CollectionCertStoreParameters(Collection collection) + { + if (collection == null) + { + throw new NullPointerException("collection must be non-null"); + } + this.collection = collection; + } + + /** + * Creates an instance of <code>CollectionCertStoreParameters</code> with + * the an empty Collection. + */ + public CollectionCertStoreParameters() + { + collection = new ArrayList(); + } + + /** + * Returns the <code>Collection</code> from which <code>Certificate</code>s + * and <code>CRL</code>s are retrieved. This is <b>not</b> a copy of the + * <code>Collection</code>, it is a reference. This allows the caller to + * subsequently add or remove <code>Certificates</code> or + * <code>CRL</code>s from the <code>Collection</code>. + * + * @return the <code>Collection</code> (never null) + */ + public Collection getCollection() + { + return collection; + } + + /** + * Returns a copy of this object. Note that only a reference to the + * <code>Collection</code> is copied, and not the contents. + * + * @return the copy + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + /* Cannot happen */ + throw new InternalError(e.toString()); + } + } + + /** + * Returns a formatted string describing the parameters. + * + * @return a formatted string describing the parameters + */ + public String toString() + { + StringBuffer s = new StringBuffer(); + s.append("CollectionCertStoreParameters: [\n collections:\n"); + s.append(getCollection()); + s.append("\n]"); + return s.toString(); + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/LDAPCertStoreParameters.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/LDAPCertStoreParameters.java new file mode 100644 index 00000000..306c6661 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/LDAPCertStoreParameters.java @@ -0,0 +1,138 @@ +package org.spongycastle.jce.cert; + +/** + * Parameters used as input for the LDAP <code>CertStore</code> algorithm.<br /> + * <br /> + * This class is used to provide necessary configuration parameters (server + * name and port number) to implementations of the LDAP <code>CertStore</code> + * algorithm.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are not + * thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize. + * + * @see CertStore + **/ +public class LDAPCertStoreParameters implements CertStoreParameters +{ + private static final int LDAP_DEFAULT_PORT = 389; + + /** + * the port number of the LDAP server + */ + private String serverName; + + /** + * the DNS name of the LDAP server + */ + private int port; + + /** + * Creates an instance of <code>LDAPCertStoreParameters</code> with the + * default parameter values (server name "localhost", port 389). + */ + public LDAPCertStoreParameters() + { + this("localhost", LDAP_DEFAULT_PORT); + } + + /** + * Creates an instance of <code>LDAPCertStoreParameters</code> with the + * specified server name and a default port of 389. + * + * @param serverName + * the DNS name of the LDAP server + * + * @exception NullPointerException + * if <code>serverName</code> is <code>null</code> + */ + public LDAPCertStoreParameters(String serverName) + { + this(serverName, LDAP_DEFAULT_PORT); + } + + /** + * Creates an instance of <code>LDAPCertStoreParameters</code> with the + * specified parameter values. + * + * @param serverName + * the DNS name of the LDAP server + * @param port + * the port number of the LDAP server + * + * @exception NullPointerException + * if <code>serverName</code> is <code>null</code> + */ + public LDAPCertStoreParameters(String serverName, int port) + { + if (serverName == null) + { + throw new NullPointerException("serverName must be non-null"); + } + this.serverName = serverName; + this.port = port; + } + + /** + * Returns the DNS name of the LDAP server. + * + * @return the name (not <code>null</code>) + */ + public String getServerName() + { + return serverName; + } + + /** + * Returns the port number of the LDAP server. + * + * @return the port number + */ + public int getPort() + { + return port; + } + + /** + * Returns a copy of this object. Changes to the copy will not affect the + * original and vice versa.<br /> + * <br /> + * Note: this method currently performs a shallow copy of the object (simply + * calls <code>Object.clone()</code>). This may be changed in a future + * revision to perform a deep copy if new parameters are added that should + * not be shared. + * + * @return the copy + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + /* Cannot happen */ + throw new InternalError(e.toString()); + } + } + + /** + * Returns a formatted string describing the parameters. + * + * @return a formatted string describing the parameters + */ + public String toString() + { + StringBuffer sb = new StringBuffer(); + sb.append("LDAPCertStoreParameters: [\n"); + sb.append(" serverName: ").append(serverName).append('\n'); + sb.append(" port: ").append(port).append('\n'); + sb.append(']'); + return sb.toString(); + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXBuilderParameters.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXBuilderParameters.java new file mode 100644 index 00000000..79136ad3 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXBuilderParameters.java @@ -0,0 +1,190 @@ +package org.spongycastle.jce.cert; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.util.Set; + +/** + * Parameters used as input for the PKIX <code>CertPathBuilder</code> + * algorithm.<br /> + * <br /> + * A PKIX <code>CertPathBuilder</code> uses these parameters to {@link + * CertPathBuilder#build build} a <code>CertPath</code> which has been + * validated according to the PKIX certification path validation algorithm.<br /> + * <br /> + * To instantiate a <code>PKIXBuilderParameters</code> object, an + * application must specify one or more <i>most-trusted CAs</i> as defined by + * the PKIX certification path validation algorithm. The most-trusted CA + * can be specified using one of two constructors. An application + * can call {@link #PKIXBuilderParameters(Set, CertSelector) + * PKIXBuilderParameters(Set, CertSelector)}, specifying a + * <code>Set</code> of <code>TrustAnchor</code> objects, each of which + * identifies a most-trusted CA. Alternatively, an application can call + * {@link #PKIXBuilderParameters(KeyStore, CertSelector) + * PKIXBuilderParameters(KeyStore, CertSelector)}, specifying a + * <code>KeyStore</code> instance containing trusted certificate entries, each + * of which will be considered as a most-trusted CA.<br /> + * <br /> + * In addition, an application must specify constraints on the target + * certificate that the <code>CertPathBuilder</code> will attempt + * to build a path to. The constraints are specified as a + * <code>CertSelector</code> object. These constraints should provide the + * <code>CertPathBuilder</code> with enough search criteria to find the target + * certificate. Minimal criteria for an <code>X509Certificate</code> usually + * include the subject name and/or one or more subject alternative names. + * If enough criteria is not specified, the <code>CertPathBuilder</code> + * may throw a <code>CertPathBuilderException</code>.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are not + * thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize. + * + * @see CertPathBuilder + **/ +public class PKIXBuilderParameters extends PKIXParameters +{ + private int maxPathLength = 5; + + /** + * Creates an instance of <code>PKIXBuilderParameters</code> with the + * specified <code>Set</code> of most-trusted CAs. Each element of the set + * is a {@link TrustAnchor TrustAnchor}.<br /> + * <br /> + * Note that the <code>Set</code> is copied to protect against subsequent + * modifications. + * + * @param trustAnchors + * a <code>Set</code> of <code>TrustAnchor</code>s + * @param targetConstraints + * a <code>CertSelector</code> specifying the constraints on + * the target certificate + * + * @exception InvalidAlgorithmParameterException + * if <code>trustAnchors</code> is empty + * <code>(trustAnchors.isEmpty() == true)</code> + * @exception NullPointerException + * if <code>trustAnchors</code> is <code>null</code> + * @exception ClassCastException + * if any of the elements of <code>trustAnchors</code> are + * not of type <code>java.security.cert.TrustAnchor</code> + */ + public PKIXBuilderParameters( + Set trustAnchors, + CertSelector targetConstraints) + throws InvalidAlgorithmParameterException + { + super(trustAnchors); + setTargetCertConstraints(targetConstraints); + } + + /** + * Creates an instance of <code>PKIXBuilderParameters</code> that + * populates the set of most-trusted CAs from the trusted certificate + * entries contained in the specified <code>KeyStore</code>. Only + * keystore entries that contain trusted <code>X509Certificate</code>s + * are considered; all other certificate types are ignored. + * + * @param keystore + * a <code>KeyStore</code> from which the set of most-trusted + * CAs will be populated + * @param targetConstraints + * a <code>CertSelector</code> specifying the constraints on + * the target certificate + * + * @exception KeyStoreException + * if <code>keystore</code> has not been initialized + * @exception InvalidAlgorithmParameterException + * if <code>keystore</code> does not contain at least one + * trusted certificate entry + * @exception NullPointerException + * if <code>keystore</code> is <code>null</code> + */ + public PKIXBuilderParameters( + KeyStore keystore, + CertSelector targetConstraints) throws KeyStoreException, + InvalidAlgorithmParameterException + { + super(keystore); + setTargetCertConstraints(targetConstraints); + } + + /** + * Sets the value of the maximum number of non-self-issued intermediate + * certificates that may exist in a certification path. A certificate is + * self-issued if the DNs that appear in the subject and issuer fields are + * identical and are not empty. Note that the last certificate in a + * certification path is not an intermediate certificate, and is not + * included in this limit. Usually the last certificate is an end entity + * certificate, but it can be a CA certificate. A PKIX + * <code>CertPathBuilder</code> instance must not build paths longer than + * the length specified.<br /> + * <br /> + * A value of 0 implies that the path can only contain a single certificate. + * A value of -1 implies that the path length is unconstrained (i.e. there + * is no maximum). The default maximum path length, if not specified, is 5. + * Setting a value less than -1 will cause an exception to be thrown.<br /> + * <br /> + * If any of the CA certificates contain the + * <code>BasicConstraintsExtension</code>, the value of the + * <code>pathLenConstraint</code> field of the extension overrides the + * maximum path length parameter whenever the result is a certification path + * of smaller length. + * + * @param maxPathLength + * the maximum number of non-self-issued intermediate + * certificates that may exist in a certification path + * + * @exception InvalidParameterException + * if <code>maxPathLength</code> is set to a value less + * than -1 + * + * @see #getMaxPathLength + */ + public void setMaxPathLength(int maxPathLength) + { + if (maxPathLength < -1) + { + throw new InvalidParameterException( + "the maximum path length parameter can not be less than -1"); + } + this.maxPathLength = maxPathLength; + } + + /** + * Returns the value of the maximum number of intermediate non-self-issued + * certificates that may exist in a certification path. See the + * {@link #setMaxPathLength} method for more details. + * + * @return the maximum number of non-self-issued intermediate certificates + * that may exist in a certification path, or -1 if there is no + * limit + * + * @see #setMaxPathLength + */ + public int getMaxPathLength() + { + return maxPathLength; + } + + /** + * Returns a formatted string describing the parameters. + * + * @return a formatted string describing the parameters + */ + public String toString() + { + StringBuffer s = new StringBuffer(); + s.append("PKIXBuilderParameters [\n"); + s.append(super.toString()); + s.append(" Maximum Path Length: "); + s.append(getMaxPathLength()); + s.append("\n]\n"); + return s.toString(); + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathBuilderResult.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathBuilderResult.java new file mode 100644 index 00000000..0288b850 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathBuilderResult.java @@ -0,0 +1,103 @@ +package org.spongycastle.jce.cert; + +import java.security.PublicKey; + +/** + * This class represents the successful result of the PKIX certification + * path builder algorithm. All certification paths that are built and + * returned using this algorithm are also validated according to the PKIX + * certification path validation algorithm.<br /> + * <br /> + * Instances of <code>PKIXCertPathBuilderResult</code> are returned by + * the <code>build</code> method of <code>CertPathBuilder</code> + * objects implementing the PKIX algorithm.<br /> + * <br /> + * All <code>PKIXCertPathBuilderResult</code> objects contain the + * certification path constructed by the build algorithm, the + * valid policy tree and subject public key resulting from the build + * algorithm, and a <code>TrustAnchor</code> describing the certification + * authority (CA) that served as a trust anchor for the certification path.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are not + * thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize. + * + * @see CertPathBuilderResult + * + **/ +public class PKIXCertPathBuilderResult extends PKIXCertPathValidatorResult + implements CertPathBuilderResult +{ + private CertPath certPath; + + /** + * Creates an instance of <code>PKIXCertPathBuilderResult</code> + * containing the specified parameters. + * + * @param certPath + * the validated <code>CertPath</code> + * @param trustAnchor + * a <code>TrustAnchor</code> describing the CA that served as + * a trust anchor for the certification path + * @param policyTree + * the immutable valid policy tree, or <code>null</code> if + * there are no valid policies + * @param subjectPublicKey + * the public key of the subject + * + * @exception NullPointerException + * if the <code>certPath</code>, <code>trustAnchor</code> + * or <code>subjectPublicKey</code> parameters are + * <code>null</code> + */ + public PKIXCertPathBuilderResult( + CertPath certPath, + TrustAnchor trustAnchor, + PolicyNode policyTree, + PublicKey subjectPublicKey) + { + super(trustAnchor, policyTree, subjectPublicKey); + if (certPath == null) + { + throw new NullPointerException("certPath must be non-null"); + } + this.certPath = certPath; + } + + /** + * Returns the built and validated certification path. The + * <code>CertPath</code> object does not include the trust anchor. + * Instead, use the {@link #getTrustAnchor() getTrustAnchor()} method to + * obtain the <code>TrustAnchor</code> that served as the trust anchor for + * the certification path. + * + * @return the built and validated <code>CertPath</code> (never + * <code>null</code>) + */ + public CertPath getCertPath() + { + return certPath; + } + + /** + * Return a printable representation of this + * <code>PKIXCertPathBuilderResult</code>. + * + * @return a <code>String</code> describing the contents of this + * <code>PKIXCertPathBuilderResult</code> + */ + public String toString() + { + StringBuffer s = new StringBuffer(); + s.append("PKIXCertPathBuilderResult: [\n"); + s.append(" Certification Path: ").append(getCertPath()).append('\n'); + s.append(" Trust Anchor: ").append(getTrustAnchor()).append('\n'); + s.append(" Policy Tree: ").append(getPolicyTree()).append('\n'); + s.append(" Subject Public Key: ").append(getPublicKey()).append("\n]"); + return s.toString(); + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathChecker.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathChecker.java new file mode 100644 index 00000000..07c71ca2 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathChecker.java @@ -0,0 +1,163 @@ +package org.spongycastle.jce.cert; + +import java.security.cert.Certificate; +import java.util.Collection; +import java.util.Set; + +/** + * An abstract class that performs one or more checks on an + * <code>X509Certificate</code>. <br /> + * <br /> + * A concrete implementation of the <code>PKIXCertPathChecker</code> class + * can be created to extend the PKIX certification path validation algorithm. + * For example, an implementation may check for and process a critical private + * extension of each certificate in a certification path.<br /> + * <br /> + * Instances of <code>PKIXCertPathChecker</code> are passed as parameters + * using the {@link PKIXParameters#setCertPathCheckers setCertPathCheckers} + * or {@link PKIXParameters#addCertPathChecker addCertPathChecker} methods + * of the <code>PKIXParameters</code> and <code>PKIXBuilderParameters</code> + * class. Each of the <code>PKIXCertPathChecker</code>s {@link #check check} + * methods will be called, in turn, for each certificate processed by a PKIX + * <code>CertPathValidator</code> or <code>CertPathBuilder</code> + * implementation.<br /> + * <br /> + * A <code>PKIXCertPathChecker</code> may be called multiple times on + * successive certificates in a certification path. Concrete subclasses + * are expected to maintain any internal state that may be necessary to + * check successive certificates. The {@link #init init} method is used + * to initialize the internal state of the checker so that the certificates + * of a new certification path may be checked. A stateful implementation + * <b>must</b> override the {@link #clone clone} method if necessary in + * order to allow a PKIX <code>CertPathBuilder</code> to efficiently + * backtrack and try other paths. In these situations, the + * <code>CertPathBuilder</code> is able to restore prior path validation + * states by restoring the cloned <code>PKIXCertPathChecker</code>s.<br /> + * <br /> + * The order in which the certificates are presented to the + * <code>PKIXCertPathChecker</code> may be either in the forward direction + * (from target to most-trusted CA) or in the reverse direction (from + * most-trusted CA to target). A <code>PKIXCertPathChecker</code> implementation + * <b>must</b> support reverse checking (the ability to perform its checks when + * it is presented with certificates in the reverse direction) and <b>may</b> + * support forward checking (the ability to perform its checks when it is + * presented with certificates in the forward direction). The + * {@link #isForwardCheckingSupported isForwardCheckingSupported} method + * indicates whether forward checking is supported.<br /> + * <br /> + * Additional input parameters required for executing the check may be + * specified through constructors of concrete implementations of this class.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are not + * thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize. + * + * @see PKIXParameters + * @see PKIXBuilderParameters + **/ +public abstract class PKIXCertPathChecker implements Cloneable +{ + + /** + * Default constructor. + */ + protected PKIXCertPathChecker() + { + } + + /** + * Initializes the internal state of this <code>PKIXCertPathChecker</code>. + * <p> + * The <code>forward</code> flag specifies the order that certificates + * will be passed to the {@link #check check} method (forward or reverse). A + * <code>PKIXCertPathChecker</code> <b>must</b> support reverse checking + * and <b>may</b> support forward checking. + * + * @param forward + * the order that certificates are presented to the + * <code>check</code> method. If <code>true</code>, + * certificates are presented from target to most-trusted CA + * (forward); if <code>false</code>, from most-trusted CA to + * target (reverse). + * @exception CertPathValidatorException + * if this <code>PKIXCertPathChecker</code> is unable to + * check certificates in the specified order; it should never + * be thrown if the forward flag is false since reverse + * checking must be supported + */ + public abstract void init(boolean forward) + throws CertPathValidatorException; + + /** + * Indicates if forward checking is supported. Forward checking refers to + * the ability of the <code>PKIXCertPathChecker</code> to perform its + * checks when certificates are presented to the <code>check</code> method + * in the forward direction (from target to most-trusted CA). + * + * @return <code>true</code> if forward checking is supported, + * <code>false</code> otherwise + */ + public abstract boolean isForwardCheckingSupported(); + + /** + * Returns an immutable <code>Set</code> of X.509 certificate extensions + * that this <code>PKIXCertPathChecker</code> supports (i.e. recognizes, + * is able to process), or <code>null</code> if no extensions are + * supported. + * <p> + * Each element of the set is a <code>String</code> representing the + * Object Identifier (OID) of the X.509 extension that is supported. The OID + * is represented by a set of nonnegative integers separated by periods. + * <p> + * All X.509 certificate extensions that a <code>PKIXCertPathChecker</code> + * might possibly be able to process should be included in the set. + * + * @return an immutable <code>Set</code> of X.509 extension OIDs (in + * <code>String</code> format) supported by this + * <code>PKIXCertPathChecker</code>, or <code>null</code> if no + * extensions are supported + */ + public abstract Set getSupportedExtensions(); + + /** + * Performs the check(s) on the specified certificate using its internal + * state and removes any critical extensions that it processes from the + * specified collection of OID strings that represent the unresolved + * critical extensions. The certificates are presented in the order + * specified by the <code>init</code> method. + * + * @param cert + * the <code>Certificate</code> to be checked + * @param unresolvedCritExts + * a <code>Collection</code> of OID strings representing the + * current set of unresolved critical extensions + * @exception CertPathValidatorException + * if the specified certificate does not pass the check + */ + public abstract void check(Certificate cert, Collection unresolvedCritExts) + throws CertPathValidatorException; + + /** + * Returns a clone of this object. Calls the <code>Object.clone()</code> + * method. All subclasses which maintain state must support and override + * this method, if necessary. + * + * @return a copy of this <code>PKIXCertPathChecker</code> + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException ex) + { + /* Cannot happen */ + throw new InternalError(ex.toString()); + } + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathValidatorResult.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathValidatorResult.java new file mode 100644 index 00000000..aa9b530f --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathValidatorResult.java @@ -0,0 +1,150 @@ +package org.spongycastle.jce.cert; + +import java.security.PublicKey; + +/** + * This class represents the successful result of the PKIX certification path + * validation algorithm. <br /> + * <br /> + * Instances of <code>PKIXCertPathValidatorResult</code> are returned by the + * {@link CertPathValidator#validate validate} method of + * <code>CertPathValidator</code> objects implementing the PKIX algorithm.<br /> + * <br /> + * All <code>PKIXCertPathValidatorResult</code> objects contain the valid + * policy tree and subject public key resulting from the validation algorithm, + * as well as a <code>TrustAnchor</code> describing the certification + * authority (CA) that served as a trust anchor for the certification path.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are not + * thread-safe. Multiple threads that need to access a single object + * concurrently should synchronize amongst themselves and provide the necessary + * locking. Multiple threads each manipulating separate objects need not + * synchronize. + * + * @see CertPathValidatorResult + */ +public class PKIXCertPathValidatorResult implements CertPathValidatorResult +{ + private TrustAnchor trustAnchor; + + private PolicyNode policyTree; + + private PublicKey subjectPublicKey; + + /** + * Creates an instance of <code>PKIXCertPathValidatorResult</code> + * containing the specified parameters. + * + * @param trustAnchor + * a <code>TrustAnchor</code> describing the CA that served as + * a trust anchor for the certification path + * @param policyTree + * the immutable valid policy tree, or <code>null</code> if + * there are no valid policies + * @param subjectPublicKey + * the public key of the subject + * + * @exception NullPointerException + * if the <code>subjectPublicKey</code> or + * <code>trustAnchor</code> parameters are + * <code>null</code> + */ + public PKIXCertPathValidatorResult( + TrustAnchor trustAnchor, + PolicyNode policyTree, + PublicKey subjectPublicKey) + { + if (subjectPublicKey == null) + { + throw new NullPointerException("subjectPublicKey must be non-null"); + } + if (trustAnchor == null) + { + throw new NullPointerException("trustAnchor must be non-null"); + } + + this.trustAnchor = trustAnchor; + this.policyTree = policyTree; + this.subjectPublicKey = subjectPublicKey; + } + + /** + * Returns the <code>TrustAnchor</code> describing the CA that served as a + * trust anchor for the certification path. + * + * @return the <code>TrustAnchor</code> (never <code>null</code>) + */ + public TrustAnchor getTrustAnchor() + { + return trustAnchor; + } + + /** + * Returns the root node of the valid policy tree resulting from the PKIX + * certification path validation algorithm. The <code>PolicyNode</code> + * object that is returned and any objects that it returns through public + * methods are immutable.<br /> + * <br /> + * Most applications will not need to examine the valid policy tree. They + * can achieve their policy processing goals by setting the policy-related + * parameters in <code>PKIXParameters</code>. However, more sophisticated + * applications, especially those that process policy qualifiers, may need + * to traverse the valid policy tree using the + * {@link PolicyNode#getParent PolicyNode.getParent} and + * {@link PolicyNode#getChildren PolicyNode.getChildren} methods. + * + * @return the root node of the valid policy tree, or <code>null</code> if + * there are no valid policies + */ + public PolicyNode getPolicyTree() + { + return policyTree; + } + + /** + * Returns the public key of the subject (target) of the certification path, + * including any inherited public key parameters if applicable. + * + * @return the public key of the subject (never <code>null</code>) + */ + public PublicKey getPublicKey() + { + return subjectPublicKey; + } + + /** + * Returns a copy of this object. + * + * @return the copy + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException ex) + { + throw new InternalError(ex.toString()); + } + } + + /** + * Return a printable representation of this + * <code>PKIXCertPathValidatorResult</code>. + * + * @return a <code>String</code> describing the contents of this + * <code>PKIXCertPathValidatorResult</code> + */ + public String toString() + { + StringBuffer s = new StringBuffer(); + s.append("PKIXCertPathValidatorResult: [ \n"); + s.append(" Trust Anchor: ").append(getTrustAnchor()).append('\n'); + s.append(" Policy Tree: ").append(getPolicyTree()).append('\n'); + s.append(" Subject Public Key: ").append(getPublicKey()).append("\n]"); + return s.toString(); + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXParameters.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXParameters.java new file mode 100644 index 00000000..a9d2d383 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXParameters.java @@ -0,0 +1,844 @@ +package org.spongycastle.jce.cert; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +/** + * Parameters used as input for the PKIX CertPathValidator algorithm.<br /> + * <br /> + * A PKIX <code>CertPathValidator</code> uses these parameters to validate a + * <code>CertPath</code> according to the PKIX certification path validation + * algorithm.<br /> + * <br /> + * To instantiate a <code>PKIXParameters</code> object, an application must + * specify one or more <i>most-trusted CAs</i> as defined by the PKIX + * certification path validation algorithm. The most-trusted CAs can be + * specified using one of two constructors. An application can call + * {@link #PKIXParameters(Set)}, specifying a Set of <code>TrustAnchor</code> + * objects, each of which identify a most-trusted CA. Alternatively, an + * application can call {@link #PKIXParameters(KeyStore)}, specifying a + * <code>KeyStore</code> instance containing trusted certificate entries, each + * of which will be considered as a most-trusted CA.<br /> + * <br /> + * Once a <code>PKIXParameters</code> object has been created, other + * parameters can be specified (by calling {@link #setInitialPolicies} or + * {@link #setDate}, for instance) and then the <code>PKIXParameters</code> + * is passed along with the <code>CertPath</code> to be validated to + * {@link CertPathValidator#validate}.<br /> + * <br /> + * Any parameter that is not set (or is set to null) will be set to the default + * value for that parameter. The default value for the date parameter is null, + * which indicates the current time when the path is validated. The default for + * the remaining parameters is the least constrained.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are not + * thread-safe. Multiple threads that need to access a single object + * concurrently should synchronize amongst themselves and provide the necessary + * locking. Multiple threads each manipulating separate objects need not + * synchronize. + * + * @see CertPathValidator + */ +public class PKIXParameters implements CertPathParameters +{ + private Set trustAnchors; + + private Set initialPolicies = new HashSet(); + + private List certStores = new ArrayList(); + + private CertSelector certSelector; + + private List certPathCheckers = new ArrayList(); + + private boolean revocationEnabled = true; + + private boolean explicitPolicyRequired = false; + + private boolean policyMappingInhibited = false; + + private boolean anyPolicyInhibited = false; + + private boolean policyQualifiersRejected = true; + + private Date date; + + private String sigProvider; + + /** + * Creates an instance of PKIXParameters with the specified Set of + * most-trusted CAs. Each element of the set is a TrustAnchor.<br /> + * <br /> + * Note that the Set is copied to protect against subsequent modifications. + * + * @param trustAnchors + * a Set of TrustAnchors + * + * @exception InvalidAlgorithmParameterException + * if the specified Set is empty + * <code>(trustAnchors.isEmpty() == true)</code> + * @exception NullPointerException + * if the specified Set is <code>null</code> + * @exception ClassCastException + * if any of the elements in the Set are not of type + * <code>java.security.cert.TrustAnchor</code> + */ + public PKIXParameters(Set trustAnchors) + throws InvalidAlgorithmParameterException + { + setTrustAnchors(trustAnchors); + } + + /** + * Creates an instance of PKIXParameters that populates the set of + * most-trusted CAs from the trusted certificate entries contained in the + * specified KeyStore. Only keystore entries that contain trusted + * X509Certificates are considered; all other certificate types are ignored. + * + * @param keystore + * a KeyStore from which the set of most-trusted CAs will be + * populated + * + * @exception KeyStoreException + * if the keystore has not been initialized + * @exception InvalidAlgorithmParameterException + * if the keystore does not contain at least one trusted + * certificate entry + * @exception NullPointerException + * if the keystore is null + */ + public PKIXParameters(KeyStore keystore) throws KeyStoreException, + InvalidAlgorithmParameterException + { + if (keystore == null) + { + throw new NullPointerException( + "the keystore parameter must be non-null"); + } + + Set trustAnchors = new HashSet(); + String alias; + Certificate cert; + Enumeration enum = keystore.aliases(); + while (enum.hasMoreElements()) + { + alias = (String)enum.nextElement(); + if (keystore.isCertificateEntry(alias)) + { + cert = keystore.getCertificate(alias); + if (cert instanceof X509Certificate) + { + trustAnchors.add(new TrustAnchor((X509Certificate)cert, + null)); + } + } + } + setTrustAnchors(trustAnchors); + } + + /** + * Returns an immutable Set of the most-trusted CAs. + * + * @return an immutable <code>Set</code> of <code>TrustAnchors</code> + * (never <code>null</code>) + * + * @see #setTrustAnchors + */ + public Set getTrustAnchors() + { + return Collections.unmodifiableSet(trustAnchors); + } + + /** + * Sets the Set of most-trusted CAs.<br /> + * <br /> + * Note that the Set is copied to protect against subsequent modifications.<br /> + * <br /> + * + * @param trustAnchors + * a Set of TrustAnchors + * + * @exception InvalidAlgorithmParameterException + * if the specified Set is empty + * <code>(trustAnchors.isEmpty() == true)</code> + * @exception NullPointerException + * if the specified Set is <code>null</code> + * @exception ClassCastException + * if any of the elements in the set are not of type + * java.security.cert.TrustAnchor + * + * @see #getTrustAnchors + */ + public void setTrustAnchors(Set trustAnchors) + throws InvalidAlgorithmParameterException + { + if (trustAnchors == null) + { + throw new NullPointerException( + "the trustAnchors parameter must be non-null"); + } + if (trustAnchors.isEmpty()) + { + throw new InvalidAlgorithmParameterException( + "the trustAnchors parameter must be non-empty"); + } + + Iterator iter = trustAnchors.iterator(); + TrustAnchor obj; + this.trustAnchors = new HashSet(); + while (iter.hasNext()) + { + obj = (TrustAnchor)iter.next(); + if (obj != null) + { + this.trustAnchors.add(obj); + } + } + } + + /** + * Returns an immutable Set of initial policy identifiers (OID strings), + * indicating that any one of these policies would be acceptable to the + * certificate user for the purposes of certification path processing. The + * default return value is an empty <code>Set</code>, which is + * interpreted as meaning that any policy would be acceptable. + * + * @return an immutable <code>Set</code> of initial policy OIDs in String + * format, or an empty <code>Set</code> (implying any policy is + * acceptable). Never returns <code>null</code>. + * + * @see #setInitialPolicies(java.util.Set) + */ + public Set getInitialPolicies() + { + Set returnSet = initialPolicies; + if (initialPolicies == null) + { + returnSet = new HashSet(); + } + + return Collections.unmodifiableSet(returnSet); + } + + /** + * Sets the <code>Set</code> of initial policy identifiers (OID strings), + * indicating that any one of these policies would be acceptable to the + * certificate user for the purposes of certification path processing. By + * default, any policy is acceptable (i.e. all policies), so a user that + * wants to allow any policy as acceptable does not need to call this + * method, or can call it with an empty <code>Set</code> (or + * <code>null</code>).<br /> + * <br /> + * Note that the Set is copied to protect against subsequent modifications.<br /> + * <br /> + * + * @param initialPolicies + * a Set of initial policy OIDs in String format (or + * <code>null</code>) + * + * @exception ClassCastException + * if any of the elements in the set are not of type String + * + * @see #getInitialPolicies() + */ + public void setInitialPolicies(Set initialPolicies) + { + if (initialPolicies == null || initialPolicies.isEmpty()) + { + this.initialPolicies = null; + } + else + { + Iterator iter = initialPolicies.iterator(); + this.initialPolicies = new HashSet(); + String obj; + while (iter.hasNext()) + { + obj = (String)iter.next(); + if (obj != null) + { + this.initialPolicies.add(obj); + } + } + } + } + + /** + * Sets the list of CertStores to be used in finding certificates and CRLs. + * May be null, in which case no CertStores will be used. The first + * CertStores in the list may be preferred to those that appear later.<br /> + * <br /> + * Note that the List is copied to protect against subsequent modifications.<br /> + * <br /> + * + * @param stores + * a List of CertStores (or <code>null</code>) + * + * @exception ClassCastException + * if any of the elements in the list are not of type + * <code>java.security.cert.CertStore</code> + * + * @see #getCertStores() + */ + public void setCertStores(List stores) + { + certStores = new ArrayList(); + if (stores != null && !stores.isEmpty()) + { + Iterator iter = stores.iterator(); + CertStore obj; + while (iter.hasNext()) + { + obj = (CertStore)iter.next(); + if (obj != null) + { + certStores.add(obj); + } + } + } + } + + /** + * Adds a CertStore to the end of the list of CertStores used in finding + * certificates and CRLs. + * + * @param store + * the <code>CertStore</code> to add. If + * <code>null</code<, the store is ignored (not added to + * list). + */ + public void addCertStore(CertStore store) + { + if (store != null) + { + certStores.add(store); + } + } + + /** + * Returns an immutable List of CertStores that are used to find + * certificates and CRLs. + * + * @return an immutable List of CertStores (may be empty, but never + * <code>null</code>) + * + * @see #setCertStores(java.util.List) + */ + public List getCertStores() + { + return Collections.unmodifiableList(certStores); + } + + /** + * Sets the RevocationEnabled flag. If this flag is true, the default + * revocation checking mechanism of the underlying PKIX service provider + * will be used. If this flag is false, the default revocation checking + * mechanism will be disabled (not used).<br /> + * <br /> + * When a <code>PKIXParameters</code> object is created, this flag is set + * to true. This setting reflects the most common strategy for checking + * revocation, since each service provider must support revocation checking + * to be PKIX compliant. Sophisticated applications should set this flag to + * false when it is not practical to use a PKIX service provider's default + * revocation checking mechanism or when an alternative revocation checking + * mechanism is to be substituted (by also calling the + * {@link #addCertPathChecker addCertPathChecker} or {@link + * #setCertPathCheckers setCertPathCheckers} methods). + * + * @param val + * the new value of the RevocationEnabled flag + */ + public void setRevocationEnabled(boolean val) + { + revocationEnabled = val; + } + + /** + * Checks the RevocationEnabled flag. If this flag is true, the default + * revocation checking mechanism of the underlying PKIX service provider + * will be used. If this flag is false, the default revocation checking + * mechanism will be disabled (not used). See the setRevocationEnabled + * method for more details on setting the value of this flag. + * + * @return the current value of the RevocationEnabled flag + */ + public boolean isRevocationEnabled() + { + return revocationEnabled; + } + + /** + * Sets the ExplicitPolicyRequired flag. If this flag is true, an acceptable + * policy needs to be explicitly identified in every certificate. By + * default, the ExplicitPolicyRequired flag is false. + * + * @param val + * true if explicit policy is to be required, false otherwise + */ + public void setExplicitPolicyRequired(boolean val) + { + explicitPolicyRequired = val; + } + + /** + * Checks if explicit policy is required. If this flag is true, an + * acceptable policy needs to be explicitly identified in every certificate. + * By default, the ExplicitPolicyRequired flag is false. + * + * @return true if explicit policy is required, false otherwise + */ + public boolean isExplicitPolicyRequired() + { + return explicitPolicyRequired; + } + + /** + * Sets the PolicyMappingInhibited flag. If this flag is true, policy + * mapping is inhibited. By default, policy mapping is not inhibited (the + * flag is false). + * + * @param val + * true if policy mapping is to be inhibited, false otherwise + */ + public void setPolicyMappingInhibited(boolean val) + { + policyMappingInhibited = val; + } + + /** + * Checks if policy mapping is inhibited. If this flag is true, policy + * mapping is inhibited. By default, policy mapping is not inhibited (the + * flag is false). + * + * @return true if policy mapping is inhibited, false otherwise + */ + public boolean isPolicyMappingInhibited() + { + return policyMappingInhibited; + } + + /** + * Sets state to determine if the any policy OID should be processed if it + * is included in a certificate. By default, the any policy OID is not + * inhibited ({@link #isAnyPolicyInhibited()} returns false). + * + * @return val - <code>true</code> if the any policy OID is to be + * inhibited, <code>false</code> otherwise + */ + public void setAnyPolicyInhibited(boolean val) + { + anyPolicyInhibited = val; + } + + /** + * Checks whether the any policy OID should be processed if it is included + * in a certificate. + * + * @return <code>true</code> if the any policy OID is inhibited, + * <code>false</code> otherwise + */ + public boolean isAnyPolicyInhibited() + { + return anyPolicyInhibited; + } + + /** + * Sets the PolicyQualifiersRejected flag. If this flag is true, + * certificates that include policy qualifiers in a certificate policies + * extension that is marked critical are rejected. If the flag is false, + * certificates are not rejected on this basis.<br /> + * <br /> + * When a <code>PKIXParameters</code> object is created, this flag is set + * to true. This setting reflects the most common (and simplest) strategy + * for processing policy qualifiers. Applications that want to use a more + * sophisticated policy must set this flag to false.<br /> + * <br /> + * Note that the PKIX certification path validation algorithm specifies that + * any policy qualifier in a certificate policies extension that is marked + * critical must be processed and validated. Otherwise the certification + * path must be rejected. If the policyQualifiersRejected flag is set to + * false, it is up to the application to validate all policy qualifiers in + * this manner in order to be PKIX compliant. + * + * @param qualifiersRejected + * the new value of the PolicyQualifiersRejected flag + * + * @see #getPolicyQualifiersRejected() + * @see PolicyQualifierInfo + */ + public void setPolicyQualifiersRejected(boolean qualifiersRejected) + { + policyQualifiersRejected = qualifiersRejected; + } + + /** + * Gets the PolicyQualifiersRejected flag. If this flag is true, + * certificates that include policy qualifiers in a certificate policies + * extension that is marked critical are rejected. If the flag is false, + * certificates are not rejected on this basis.<br /> + * <br /> + * When a PKIXParameters object is created, this flag is set to true. This + * setting reflects the most common (and simplest) strategy for processing + * policy qualifiers. Applications that want to use a more sophisticated + * policy must set this flag to false. + * + * @return the current value of the PolicyQualifiersRejected flag + * + * @see #setPolicyQualifiersRejected(boolean) + */ + public boolean getPolicyQualifiersRejected() + { + return policyQualifiersRejected; + } + + /** + * Returns the time for which the validity of the certification path should + * be determined. If null, the current time is used.<br /> + * <br /> + * Note that the Date returned is copied to protect against subsequent + * modifications. + * + * @return the Date, or <code>null</code> if not set + * + * @see #setDate(java.util.Date) + */ + public Date getDate() + { + if (date == null) + { + return null; + } + + return new Date(date.getTime()); + } + + /** + * Sets the time for which the validity of the certification path should be + * determined. If null, the current time is used.<br /> + * <br /> + * Note that the Date supplied here is copied to protect against subsequent + * modifications. + * + * @param date + * the Date, or <code>null</code> for the current time + * + * @see #getDate() + */ + public void setDate(Date date) + { + if (date == null) + { + this.date = null; + } + else + { + this.date = new Date(date.getTime()); + } + } + + /** + * Sets a <code>List</code> of additional certification path checkers. If + * the specified List contains an object that is not a PKIXCertPathChecker, + * it is ignored.<br /> + * <br /> + * Each <code>PKIXCertPathChecker</code> specified implements additional + * checks on a certificate. Typically, these are checks to process and + * verify private extensions contained in certificates. Each + * <code>PKIXCertPathChecker</code> should be instantiated with any + * initialization parameters needed to execute the check.<br /> + * <br /> + * This method allows sophisticated applications to extend a PKIX + * <code>CertPathValidator</code> or <code>CertPathBuilder</code>. Each + * of the specified PKIXCertPathCheckers will be called, in turn, by a PKIX + * <code>CertPathValidator</code> or <code>CertPathBuilder</code> for + * each certificate processed or validated.<br /> + * <br /> + * Regardless of whether these additional PKIXCertPathCheckers are set, a + * PKIX <code>CertPathValidator</code> or <code>CertPathBuilder</code> + * must perform all of the required PKIX checks on each certificate. The one + * exception to this rule is if the RevocationEnabled flag is set to false + * (see the {@link #setRevocationEnabled(boolean) setRevocationEnabled} + * method).<br /> + * <br /> + * Note that the List supplied here is copied and each PKIXCertPathChecker + * in the list is cloned to protect against subsequent modifications. + * + * @param checkers + * a List of PKIXCertPathCheckers. May be null, in which case no + * additional checkers will be used. + * @exception ClassCastException + * if any of the elements in the list are not of type + * <code>java.security.cert.PKIXCertPathChecker</code> + * @see #getCertPathCheckers() + */ + public void setCertPathCheckers(List checkers) + { + certPathCheckers = new ArrayList(); + if (checkers == null) + { + return; + } + Iterator iter = checkers.iterator(); + while (iter.hasNext()) + { + certPathCheckers + .add((PKIXCertPathChecker)((PKIXCertPathChecker)iter.next()) + .clone()); + } + } + + /** + * Returns the List of certification path checkers. The returned List is + * immutable, and each PKIXCertPathChecker in the List is cloned to protect + * against subsequent modifications. + * + * @return an immutable List of PKIXCertPathCheckers (may be empty, but not + * <code>null</code>) + * + * @see #setCertPathCheckers(java.util.List) + */ + public List getCertPathCheckers() + { + List checkers = new ArrayList(); + Iterator iter = certPathCheckers.iterator(); + while (iter.hasNext()) + { + checkers + .add((PKIXCertPathChecker)((PKIXCertPathChecker)iter.next()) + .clone()); + } + return Collections.unmodifiableList(checkers); + } + + /** + * Adds a PKIXCertPathChecker to the list of certification path checkers. + * See the {@link #setCertPathCheckers} method for more details.<br /> + * <br /> + * Note that the <code>PKIXCertPathChecker</code> is cloned to protect + * against subsequent modifications. + * + * @param checker + * a <code>PKIXCertPathChecker</code> to add to the list of + * checks. If <code>null</code>, the checker is ignored (not + * added to list). + */ + public void addCertPathChecker(PKIXCertPathChecker checker) + { + if (checker != null) + { + certPathCheckers.add(checker.clone()); + } + } + + /** + * Returns the signature provider's name, or <code>null</code> if not set. + * + * @return the signature provider's name (or <code>null</code>) + * + * @see #setSigProvider(java.lang.String) + */ + public String getSigProvider() + { + return sigProvider; + } + + /** + * Sets the signature provider's name. The specified provider will be + * preferred when creating Signature objects. If null or not set, the first + * provider found supporting the algorithm will be used. + * + * @param sigProvider + * the signature provider's name (or <code>null</code>) + * + * @see #getSigProvider() + */ + public void setSigProvider(String sigProvider) + { + this.sigProvider = sigProvider; + } + + /** + * Returns the required constraints on the target certificate. The + * constraints are returned as an instance of CertSelector. If + * <code>null</code>, no constraints are defined.<br /> + * <br /> + * Note that the CertSelector returned is cloned to protect against + * subsequent modifications. + * + * @return a CertSelector specifying the constraints on the target + * certificate (or <code>null</code>) + * + * @see #setTargetCertConstraints(CertSelector) + */ + public CertSelector getTargetCertConstraints() + { + if (certSelector == null) + { + return null; + } + + return (CertSelector)certSelector.clone(); + } + + /** + * Sets the required constraints on the target certificate. The constraints + * are specified as an instance of CertSelector. If null, no constraints are + * defined.<br /> + * <br /> + * Note that the CertSelector specified is cloned to protect against + * subsequent modifications. + * + * @param selector + * a CertSelector specifying the constraints on the target + * certificate (or <code>null</code>) + * + * @see #getTargetCertConstraints() + */ + public void setTargetCertConstraints(CertSelector selector) + { + if (selector == null) + { + certSelector = null; + } + else + { + certSelector = (CertSelector)selector.clone(); + } + } + + /** + * Makes a copy of this PKIXParameters object. Changes to the copy will not + * affect the original and vice versa. + * + * @return a copy of this <code>PKIXParameters</code> object + */ + public Object clone() + { + try + { + PKIXParameters obj = (PKIXParameters)super.clone(); + obj.certStores = new ArrayList(certStores); + Iterator iter = certPathCheckers.iterator(); + obj.certPathCheckers = new ArrayList(); + while (iter.hasNext()) + { + obj.certPathCheckers.add(((PKIXCertPathChecker)iter.next()) + .clone()); + } + if (initialPolicies != null) + { + obj.initialPolicies = new HashSet(initialPolicies); + } + if (trustAnchors != null) + { + obj.trustAnchors = new HashSet(trustAnchors); + } + if (certSelector != null) + { + obj.certSelector = (CertSelector)certSelector.clone(); + } + return obj; + } + catch (CloneNotSupportedException ex) + { + throw new InternalError(); + } + } + + /** + * Returns a formatted string describing the parameters. + * + * @return a formatted string describing the parameters. + */ + public String toString() + { + StringBuffer s = new StringBuffer(); + s.append("[\n"); + if (trustAnchors != null) + { + s.append(" Trust Anchors: ").append(trustAnchors).append('\n'); + } + if (initialPolicies != null) + { + if (initialPolicies.isEmpty()) + { + s.append(" Initial Policy OIDs: any\n"); + } + else + { + s.append(" Initial Policy OIDs: [") + .append(initialPolicies).append("]\n"); + } + } + s.append(" Validity Date: "); + if (date != null) + { + s.append(date); + } + else + { + s.append("null"); + } + s.append('\n'); + + s.append(" Signature Provider: "); + if (sigProvider != null) + { + s.append(sigProvider); + } + else + { + s.append("null"); + } + s.append('\n'); + + s.append(" Default Revocation Enabled: "); + s.append(revocationEnabled); + s.append('\n'); + + s.append(" Explicit Policy Required: "); + s.append(explicitPolicyRequired); + s.append('\n'); + + s.append(" Policy Mapping Inhibited: "); + s.append(policyMappingInhibited); + s.append('\n'); + + s.append(" Any Policy Inhibited: "); + s.append(anyPolicyInhibited); + s.append('\n'); + + s.append(" Policy Qualifiers Rejected: "); + s.append(policyQualifiersRejected); + s.append('\n'); + + s.append(" Target Cert Constraints: "); + s.append(certSelector); + s.append('\n'); + + s.append(" Certification Path Checkers: ["); + s.append(certPathCheckers); + s.append("}\n"); + + s.append(" CertStores: ["); + s.append(certStores); + s.append("}\n"); + + s.append("]\n"); + + return s.toString(); + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PolicyNode.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PolicyNode.java new file mode 100644 index 00000000..ae9199b3 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PolicyNode.java @@ -0,0 +1,107 @@ +package org.spongycastle.jce.cert; + +import java.util.Iterator; +import java.util.Set; + +/** + * An immutable valid policy tree node as defined by the PKIX certification + * path validation algorithm.<br /> + * <br /> + * One of the outputs of the PKIX certification path validation + * algorithm is a valid policy tree, which includes the policies that + * were determined to be valid, how this determination was reached, + * and any policy qualifiers encountered. This tree is of depth + * <i>n</i>, where <i>n</i> is the length of the certification + * path that has been validated.<br /> + * <br /> + * Most applications will not need to examine the valid policy tree. + * They can achieve their policy processing goals by setting the + * policy-related parameters in <code>PKIXParameters</code>. However, + * the valid policy tree is available for more sophisticated applications, + * especially those that process policy qualifiers.<br /> + * <br /> + * {@link PKIXCertPathValidatorResult#getPolicyTree() + * PKIXCertPathValidatorResult.getPolicyTree} returns the root node of the + * valid policy tree. The tree can be traversed using the + * {@link #getChildren getChildren} and {@link #getParent getParent} methods. + * Data about a particular node can be retrieved using other methods of + * <code>PolicyNode</code>.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * All <code>PolicyNode</code> objects must be immutable and + * thread-safe. Multiple threads may concurrently invoke the methods defined + * in this class on a single <code>PolicyNode</code> object (or more than one) + * with no ill effects. This stipulation applies to all public fields and + * methods of this class and any added or overridden by subclasses. + **/ +public interface PolicyNode +{ + + /** + * Returns the parent of this node, or <code>null</code> if this is the + * root node. + * + * @return the parent of this node, or <code>null</code> if this is the + * root node + */ + public PolicyNode getParent(); + + /** + * Returns an iterator over the children of this node. Any attempts to + * modify the children of this node through the + * <code>Iterator</code>'s remove method must throw an + * <code>UnsupportedOperationException</code>. + * + * @return an iterator over the children of this node + */ + public Iterator getChildren(); + + /** + * Returns the depth of this node in the valid policy tree. + * + * @return the depth of this node (0 for the root node, 1 for its + * children, and so on) + */ + public int getDepth(); + + /** + * Returns the valid policy represented by this node. + * + * @return the <code>String</code> OID of the valid policy + * represented by this node, or the special value "any-policy". For + * the root node, this method always returns the special value "any-policy". + */ + public String getValidPolicy(); + + /** + * Returns the set of policy qualifiers associated with the + * valid policy represented by this node. + * + * @return an immutable <code>Set</code> of + * <code>PolicyQualifierInfo</code>s. For the root node, this + * is always an empty <code>Set</code>. + */ + public Set getPolicyQualifiers(); + + /** + * Returns the set of expected policies that would satisfy this + * node's valid policy in the next certificate to be processed. + * + * @return an immutable <code>Set</code> of expected policy + * <code>String</code> OIDs, or an immutable <code>Set</code> with + * the single special value "any-policy". For the root node, this method + * always returns a <code>Set</code> with the single value "any-policy". + */ + public Set getExpectedPolicies(); + + /** + * Returns the criticality indicator of the certificate policy extension + * in the most recently processed certificate. + * + * @return <code>true</code> if extension marked critical, + * <code>false</code> otherwise. For the root node, <code>false</code> + * is always returned. + */ + public boolean isCritical(); +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PolicyQualifierInfo.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PolicyQualifierInfo.java new file mode 100644 index 00000000..97e9c5fa --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PolicyQualifierInfo.java @@ -0,0 +1,196 @@ +package org.spongycastle.jce.cert; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1Object; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.DEROutputStream; +import org.spongycastle.asn1.util.ASN1Dump; + +/** + * An immutable policy qualifier represented by the ASN.1 PolicyQualifierInfo + * structure.<br /> + * <br /> + * The ASN.1 definition is as follows:<br /> + * <br /> + * + * <pre> + * PolicyQualifierInfo ::= SEQUENCE { + * policyQualifierId PolicyQualifierId, + * qualifier ANY DEFINED BY policyQualifierId } + * </pre> + * + * <br /> + * <br /> + * A certificate policies extension, if present in an X.509 version 3 + * certificate, contains a sequence of one or more policy information terms, + * each of which consists of an object identifier (OID) and optional qualifiers. + * In an end-entity certificate, these policy information terms indicate the + * policy under which the certificate has been issued and the purposes for which + * the certificate may be used. In a CA certificate, these policy information + * terms limit the set of policies for certification paths which include this + * certificate.<br /> + * <br /> + * A <code>Set</code> of <code>PolicyQualifierInfo</code> objects are + * returned by the + * {@link PolicyNode#getPolicyQualifiers PolicyNode.getPolicyQualifiers} method. + * This allows applications with specific policy requirements to process and + * validate each policy qualifier. Applications that need to process policy + * qualifiers should explicitly set the <code>policyQualifiersRejected</code> + * flag to false (by calling the + * {@link PKIXParameters#setPolicyQualifiersRejected + * PKIXParameters.setPolicyQualifiersRejected} method) before validating a + * certification path.<br /> + * <br /> + * Note that the PKIX certification path validation algorithm specifies that any + * policy qualifier in a certificate policies extension that is marked critical + * must be processed and validated. Otherwise the certification path must be + * rejected. If the <code>policyQualifiersRejected</code> flag is set to + * false, it is up to the application to validate all policy qualifiers in this + * manner in order to be PKIX compliant.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * All <code>PolicyQualifierInfo</code> objects must be immutable and + * thread-safe. That is, multiple threads may concurrently invoke the methods + * defined in this class on a single <code>PolicyQualifierInfo</code> object + * (or more than one) with no ill effects. Requiring + * <code>PolicyQualifierInfo</code> objects to be immutable and thread-safe + * allows them to be passed around to various pieces of code without worrying + * about coordinating access.<br /> + * <br /> + * Uses {@link org.spongycastle.asn1.ASN1InputStream ASN1InputStream}, + * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence}, + * {@link org.spongycastle.asn1.ASN1ObjectIdentifier ASN1ObjectIdentifier}, + * {@link org.spongycastle.asn1.DEROutputStream DEROutputStream}, + * {@link org.spongycastle.asn1.ASN1Object ASN1Object} + */ +public final class PolicyQualifierInfo +{ + private String id; + + private byte[] encoded; + + private byte[] qualifier; + + /** + * Creates an instance of <code>PolicyQualifierInfo</code> from the + * encoded bytes. The encoded byte array is copied on construction.<br /> + * <br /> + * Uses {@link org.spongycastle.asn1.ASN1InputStream ASN1InputStream}, + * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence}, + * {@link org.spongycastle.asn1.ASN1ObjectIdentifier ASN1ObjectIdentifier} and + * {@link org.spongycastle.asn1.DEROutputStream DEROutputStream} + * + * @param encoded + * a byte array containing the qualifier in DER encoding + * + * @exception IOException + * thrown if the byte array does not represent a valid and + * parsable policy qualifier + */ + public PolicyQualifierInfo(byte[] encoded) throws IOException + { + this.encoded = (byte[])encoded.clone(); + try + { + ByteArrayInputStream inStream = new ByteArrayInputStream( + this.encoded); + ASN1InputStream derInStream = new ASN1InputStream(inStream); + ASN1Sequence obj = (ASN1Sequence)derInStream.readObject(); + id = ((ASN1ObjectIdentifier)obj.getObjectAt(0)).getId(); + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + DEROutputStream derOutStream = new DEROutputStream(outStream); + + derOutStream.writeObject(obj.getObjectAt(1)); + derOutStream.close(); + + qualifier = outStream.toByteArray(); + } + catch (Exception ex) + { + throw new IOException("parsing exception : " + ex.toString()); + } + } + + /** + * Returns the <code>policyQualifierId</code> field of this + * <code>PolicyQualifierInfo</code>. The <code>policyQualifierId</code> + * is an Object Identifier (OID) represented by a set of nonnegative + * integers separated by periods. + * + * @return the OID (never <code>null</code>) + */ + public String getPolicyQualifierId() + { + return id; + } + + /** + * Returns the ASN.1 DER encoded form of this + * <code>PolicyQualifierInfo</code>. + * + * @return the ASN.1 DER encoded bytes (never <code>null</code>). Note + * that a copy is returned, so the data is cloned each time this + * method is called. + */ + public byte[] getEncoded() + { + return (byte[])encoded.clone(); + } + + /** + * Returns the ASN.1 DER encoded form of the <code>qualifier</code> field + * of this <code>PolicyQualifierInfo</code>. + * + * @return the ASN.1 DER encoded bytes of the <code>qualifier</code> + * field. Note that a copy is returned, so the data is cloned each + * time this method is called. + */ + public byte[] getPolicyQualifier() + { + if (qualifier == null) + { + return null; + } + + return (byte[])qualifier.clone(); + } + + /** + * Return a printable representation of this + * <code>PolicyQualifierInfo</code>.<br /> + * <br /> + * Uses {@link org.spongycastle.asn1.ASN1InputStream ASN1InputStream}, + * {@link org.spongycastle.asn1.ASN1Object ASN1Object} + * + * @return a <code>String</code> describing the contents of this + * <code>PolicyQualifierInfo</code> + */ + public String toString() + { + StringBuffer s = new StringBuffer(); + s.append("PolicyQualifierInfo: [\n"); + s.append("qualifierID: ").append(id).append('\n'); + try + { + ByteArrayInputStream inStream = new ByteArrayInputStream(qualifier); + ASN1InputStream derInStream = new ASN1InputStream(inStream); + ASN1Object derObject = derInStream.readObject(); + s + .append(" qualifier:\n").append(ASN1Dump.dumpAsString(derObject)) + .append('\n'); + } + catch (IOException ex) + { + s.append(ex.getMessage()); + } + s.append("qualifier: ").append(id).append('\n'); + s.append(']'); + return s.toString(); + } +}
\ No newline at end of file diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/TrustAnchor.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/TrustAnchor.java new file mode 100644 index 00000000..68a9abf3 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/TrustAnchor.java @@ -0,0 +1,293 @@ +package org.spongycastle.jce.cert; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.security.PublicKey; +import java.security.cert.X509Certificate; + +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1Object; +import org.spongycastle.asn1.ASN1Sequence; + +/** + * A trust anchor or most-trusted Certification Authority (CA). <br /> + * <br /> + * This class represents a "most-trusted CA", which is used as a trust anchor + * for validating X.509 certification paths. A most-trusted CA includes the + * public key of the CA, the CA's name, and any constraints upon the set of + * paths which may be validated using this key. These parameters can be + * specified in the form of a trusted X509Certificate or as individual + * parameters. <br /> + * <br /> + * <strong>Concurrent Access</strong><br /> + * <br /> + * All TrustAnchor objects must be immutable and thread-safe. That is, multiple + * threads may concurrently invoke the methods defined in this class on a + * single TrustAnchor object (or more than one) with no ill effects. Requiring + * TrustAnchor objects to be immutable and thread-safe allows them to be passed + * around to various pieces of code without worrying about coordinating access. + * This stipulation applies to all public fields and methods of this class and + * any added or overridden by subclasses.<br /> + * <br /> + * <b>TODO: implement better nameConstraints testing.</b> + **/ +public class TrustAnchor +{ + private X509Certificate trustCert = null; + + private PublicKey trustPublicKey = null; + + private String trustName = null; + + private byte[] nameConstraints = null; + + /** + * Creates an instance of TrustAnchor with the specified X509Certificate and + * optional name constraints, which are intended to be used as additional + * constraints when validating an X.509 certification path.<br /> + * <br /> + * The name constraints are specified as a byte array. This byte array + * should contain the DER encoded form of the name constraints, as they + * would appear in the NameConstraints structure defined in RFC 2459 and + * X.509. The ASN.1 definition of this structure appears below.<br /> + * <br /> + * + * <pre> + * NameConstraints ::= SEQUENCE { + * permittedSubtrees [0] GeneralSubtrees OPTIONAL, + * excludedSubtrees [1] GeneralSubtrees OPTIONAL } + * + * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree + * + * GeneralSubtree ::= SEQUENCE { + * base GeneralName, + * minimum [0] BaseDistance DEFAULT 0, + * maximum [1] BaseDistance OPTIONAL } + * + * BaseDistance ::= INTEGER (0..MAX) + * + * GeneralName ::= CHOICE { + * otherName [0] OtherName, + * rfc822Name [1] IA5String, + * dNSName [2] IA5String, + * x400Address [3] ORAddress, + * directoryName [4] Name, + * ediPartyName [5] EDIPartyName, + * uniformResourceIdentifier [6] IA5String, + * iPAddress [7] OCTET STRING, + * registeredID [8] OBJECT IDENTIFIER} + * </pre> + * + * <br /> + * <br /> + * Note that the name constraints byte array supplied is cloned to protect + * against subsequent modifications. + * + * @param trustedCert + * a trusted X509Certificate + * @param nameConstraints + * a byte array containing the ASN.1 DER encoding of a + * NameConstraints extension to be used for checking name + * constraints. Only the value of the extension is included, not + * the OID or criticality flag. Specify null to omit the + * parameter. + * + * @exception IllegalArgumentException + * if the name constraints cannot be decoded + * @exception NullPointerException + * if the specified X509Certificate is null + */ + public TrustAnchor(X509Certificate trustedCert, byte[] nameConstraints) + { + if (trustedCert == null) + { + throw new NullPointerException("trustedCert must be non-null"); + } + + this.trustCert = trustedCert; + if (nameConstraints != null) + { + this.nameConstraints = (byte[])nameConstraints.clone(); + checkNameConstraints(this.nameConstraints); + } + } + + /** + * Creates an instance of <code>TrustAnchor</code> where the most-trusted + * CA is specified as a distinguished name and public key. Name constraints + * are an optional parameter, and are intended to be used as additional + * constraints when validating an X.509 certification path. + * + * The name constraints are specified as a byte array. This byte array + * contains the DER encoded form of the name constraints, as they would + * appear in the NameConstraints structure defined in RFC 2459 and X.509. + * The ASN.1 notation for this structure is supplied in the documentation + * for {@link #TrustAnchor(X509Certificate trustedCert, byte[] + * nameConstraints) TrustAnchor(X509Certificate trustedCert, byte[] + * nameConstraints) }. + * + * Note that the name constraints byte array supplied here is cloned to + * protect against subsequent modifications. + * + * @param caName + * the X.500 distinguished name of the most-trusted CA in RFC + * 2253 String format + * @param pubKey + * the public key of the most-trusted CA + * @param nameConstraints + * a byte array containing the ASN.1 DER encoding of a + * NameConstraints extension to be used for checking name + * constraints. Only the value of the extension is included, not + * the OID or criticality flag. Specify null to omit the + * parameter. + * + * @exception IllegalArgumentException + * if the specified caName parameter is empty (<code>caName.length() == 0</code>) + * or incorrectly formatted or the name constraints cannot be + * decoded + * @exception NullPointerException + * if the specified caName or pubKey parameter is null + */ + public TrustAnchor(String caName, PublicKey pubKey, byte[] nameConstraints) + { + if (caName == null) + { + throw new NullPointerException("caName must be non-null"); + } + if (pubKey == null) + { + throw new NullPointerException("pubKey must be non-null"); + } + if (caName.length() == 0) + { + throw new IllegalArgumentException( + "caName can not be an empty string"); + } + + this.trustName = caName; + this.trustPublicKey = pubKey; + if (nameConstraints != null) + { + this.nameConstraints = (byte[])nameConstraints.clone(); + checkNameConstraints(this.nameConstraints); + } + } + + /** + * Returns the most-trusted CA certificate. + * + * @return a trusted <code>X509Certificate</code> or <code>null</code> + * if the trust anchor was not specified as a trusted certificate + */ + public final X509Certificate getTrustedCert() + { + return trustCert; + } + + /** + * Returns the name of the most-trusted CA in RFC 2253 String format. + * + * @return the X.500 distinguished name of the most-trusted CA, or + * <code>null</code> if the trust anchor was not specified as a + * trusted public key and name pair + */ + public final String getCAName() + { + return trustName; + } + + /** + * Returns the public key of the most-trusted CA. + * + * @return the public key of the most-trusted CA, or null if the trust + * anchor was not specified as a trusted public key and name pair + */ + public final PublicKey getCAPublicKey() + { + return trustPublicKey; + } + + /** + * Returns the name constraints parameter. The specified name constraints + * are associated with this trust anchor and are intended to be used as + * additional constraints when validating an X.509 certification path.<br /> + * <br /> + * The name constraints are returned as a byte array. This byte array + * contains the DER encoded form of the name constraints, as they would + * appear in the NameConstraints structure defined in RFC 2459 and X.509. + * The ASN.1 notation for this structure is supplied in the documentation + * for <code>TrustAnchor(X509Certificate trustedCert, byte[] + * nameConstraints)</code>.<br /> + * <br /> + * Note that the byte array returned is cloned to protect against subsequent + * modifications. + * + * @return a byte array containing the ASN.1 DER encoding of a + * NameConstraints extension used for checking name constraints, or + * <code>null</code> if not set. + */ + public final byte[] getNameConstraints() + { + return (byte[])nameConstraints.clone(); + } + + /** + * Returns a formatted string describing the <code>TrustAnchor</code>. + * + * @return a formatted string describing the <code>TrustAnchor</code> + */ + public String toString() + { + StringBuffer sb = new StringBuffer(); + sb.append("[\n"); + if (getCAPublicKey() != null) + { + sb.append(" Trusted CA Public Key: ").append(getCAPublicKey()).append('\n'); + sb.append(" Trusted CA Issuer Name: ").append(getCAName()).append('\n'); + } + else + { + sb.append(" Trusted CA cert: ").append(getTrustedCert()).append('\n'); + } + if (nameConstraints != null) + { + sb.append(" Name Constraints: ").append(nameConstraints).append('\n'); + } + return sb.toString(); + } + + /** + * Check given DER encoded nameConstraints for correct decoding. Currently + * only basic DER decoding test.<br /> + * <br /> + * <b>TODO: implement more testing.</b> + * + * @param data + * the DER encoded nameConstrains to be checked or + * <code>null</code> + * @exception IllegalArgumentException + * if the check failed. + */ + private void checkNameConstraints(byte[] data) + { + if (data != null) + { + try + { + ByteArrayInputStream inStream = new ByteArrayInputStream(data); + ASN1InputStream derInStream = new ASN1InputStream(inStream); + ASN1Object derObject = derInStream.readObject(); + if (!(derObject instanceof ASN1Sequence)) + { + throw new IllegalArgumentException( + "nameConstraints parameter decoding error"); + } + } + catch (IOException ex) + { + throw new IllegalArgumentException( + "nameConstraints parameter decoding error: " + ex); + } + } + } +}
\ No newline at end of file diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CRLSelector.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CRLSelector.java new file mode 100644 index 00000000..4a377ed3 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CRLSelector.java @@ -0,0 +1,717 @@ +package org.spongycastle.jce.cert; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.cert.CRL; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1Object; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.x509.X509Extensions; +import org.spongycastle.asn1.x509.X509Name; +import org.spongycastle.jce.PrincipalUtil; + +/** + * A <code>CRLSelector</code> that selects <code>X509CRLs</code> that match + * all specified criteria. This class is particularly useful when selecting CRLs + * from a <code>CertStore</code> to check revocation status of a particular + * certificate.<br /> + * <br /> + * When first constructed, an <code>X509CRLSelector</code> has no criteria + * enabled and each of the <code>get</code> methods return a default value (<code>null</code>). + * Therefore, the {@link #match match} method would return <code>true</code> + * for any <code>X509CRL</code>. Typically, several criteria are enabled (by + * calling {@link #setIssuerNames setIssuerNames} or + * {@link #setDateAndTime setDateAndTime}, for instance) and then the + * <code>X509CRLSelector</code> is passed to + * {@link CertStore#getCRLs CertStore.getCRLs} or some similar method.<br /> + * <br /> + * Please refer to RFC 2459 for definitions of the X.509 CRL fields and + * extensions mentioned below.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are not + * thread-safe. Multiple threads that need to access a single object + * concurrently should synchronize amongst themselves and provide the necessary + * locking. Multiple threads each manipulating separate objects need not + * synchronize.<br /> + * <br /> + * Uses {@link org.spongycastle.asn1.ASN1InputStream ASN1InputStream}, + * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence}, + * {@link org.spongycastle.asn1.ASN1ObjectIdentifier ASN1ObjectIdentifier}, + * {@link org.spongycastle.asn1.DEROutputStream DEROutputStream}, + * {@link org.spongycastle.asn1.ASN1Object ASN1Object}, + * {@link org.spongycastle.asn1.x509.X509Name X509Name} + * + * @see CRLSelector + * @see X509CRL + */ +public class X509CRLSelector implements CRLSelector +{ + private Set issuerNames = null; + + private Set issuerNamesX509 = null; + + private BigInteger minCRL = null; + + private BigInteger maxCRL = null; + + private Date dateAndTime = null; + + private X509Certificate certChecking = null; + + /** + * Creates an <code>X509CRLSelector</code>. Initially, no criteria are + * set so any <code>X509CRL</code> will match. + */ + public X509CRLSelector() + { + } + + /** + * Sets the issuerNames criterion. The issuer distinguished name in the + * <code>X509CRL</code> must match at least one of the specified + * distinguished names. If <code>null</code>, any issuer distinguished + * name will do.<br /> + * <br /> + * This method allows the caller to specify, with a single method call, the + * complete set of issuer names which <code>X509CRLs</code> may contain. + * The specified value replaces the previous value for the issuerNames + * criterion.<br /> + * <br /> + * The <code>names</code> parameter (if not <code>null</code>) is a + * <code>Collection</code> of names. Each name is a <code>String</code> + * or a byte array representing a distinguished name (in RFC 2253 or ASN.1 + * DER encoded form, respectively). If <code>null</code> is supplied as + * the value for this argument, no issuerNames check will be performed.<br /> + * <br /> + * Note that the <code>names</code> parameter can contain duplicate + * distinguished names, but they may be removed from the + * <code>Collection</code> of names returned by the + * {@link #getIssuerNames getIssuerNames} method.<br /> + * <br /> + * If a name is specified as a byte array, it should contain a single DER + * encoded distinguished name, as defined in X.501. The ASN.1 notation for + * this structure is as follows. + * + * <pre><code> + * Name ::= CHOICE { + * RDNSequence } + * + * RDNSequence ::= SEQUENCE OF RDN + * + * RDN ::= + * SET SIZE (1 .. MAX) OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY DEFINED BY AttributeType + * .... + * DirectoryString ::= CHOICE { + * teletexString TeletexString (SIZE (1..MAX)), + * printableString PrintableString (SIZE (1..MAX)), + * universalString UniversalString (SIZE (1..MAX)), + * utf8String UTF8String (SIZE (1.. MAX)), + * bmpString BMPString (SIZE (1..MAX)) } + * </code></pre> + * + * <br /> + * <br /> + * Note that a deep copy is performed on the <code>Collection</code> to + * protect against subsequent modifications. + * + * @param names + * a <code>Collection</code> of names (or <code>null</code>) + * + * @exception IOException + * if a parsing error occurs + * + * @see #getIssuerNames + */ + public void setIssuerNames(Collection names) throws IOException + { + if (names == null || names.isEmpty()) + { + issuerNames = null; + issuerNamesX509 = null; + } + else + { + Object item; + Iterator iter = names.iterator(); + while (iter.hasNext()) + { + item = iter.next(); + if (item instanceof String) + { + addIssuerName((String)item); + } + else if (item instanceof byte[]) + { + addIssuerName((byte[])item); + } + else + { + throw new IOException("name not byte[]or String: " + + item.toString()); + } + } + } + } + + /** + * Adds a name to the issuerNames criterion. The issuer distinguished name + * in the <code>X509CRL</code> must match at least one of the specified + * distinguished names.<br /> + * <br /> + * This method allows the caller to add a name to the set of issuer names + * which <code>X509CRLs</code> may contain. The specified name is added to + * any previous value for the issuerNames criterion. If the specified name + * is a duplicate, it may be ignored.<br /> + * <br /> + * Uses {@link org.spongycastle.asn1.x509.X509Name X509Name} for parsing the + * name + * + * @param name + * the name in RFC 2253 form + * + * @exception IOException + * if a parsing error occurs + */ + public void addIssuerName(String name) throws IOException + { + if (issuerNames == null) + { + issuerNames = new HashSet(); + issuerNamesX509 = new HashSet(); + } + X509Name nameX509; + try + { + nameX509 = new X509Name(name); + } + catch (IllegalArgumentException ex) + { + throw new IOException(ex.getMessage()); + } + issuerNamesX509.add(nameX509); + issuerNames.add(name); + } + + /** + * Adds a name to the issuerNames criterion. The issuer distinguished name + * in the <code>X509CRL</code> must match at least one of the specified + * distinguished names.<br /> + * <br /> + * This method allows the caller to add a name to the set of issuer names + * which <code>X509CRLs</code> may contain. The specified name is added to + * any previous value for the issuerNames criterion. If the specified name + * is a duplicate, it may be ignored. If a name is specified as a byte + * array, it should contain a single DER encoded distinguished name, as + * defined in X.501. The ASN.1 notation for this structure is as follows.<br /> + * <br /> + * The name is provided as a byte array. This byte array should contain a + * single DER encoded distinguished name, as defined in X.501. The ASN.1 + * notation for this structure appears in the documentation for + * {@link #setIssuerNames setIssuerNames(Collection names)}.<br /> + * <br /> + * Note that the byte array supplied here is cloned to protect against + * subsequent modifications.<br /> + * <br /> + * Uses {@link org.spongycastle.asn1.x509.X509Name X509Name} for parsing the + * name, {@link org.spongycastle.asn1.ASN1InputStream ASN1InputStream}, + * {@link org.spongycastle.asn1.ASN1Object ASN1Object} and + * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence} + * + * @param name + * a byte array containing the name in ASN.1 DER encoded form + * + * @exception IOException + * if a parsing error occurs + */ + public void addIssuerName(byte[] name) throws IOException + { + if (issuerNames == null) + { + issuerNames = new HashSet(); + issuerNamesX509 = new HashSet(); + } + + ByteArrayInputStream inStream = new ByteArrayInputStream(name); + ASN1InputStream derInStream = new ASN1InputStream(inStream); + ASN1Object obj = derInStream.readObject(); + if (obj instanceof ASN1Sequence) + { + issuerNamesX509.add(new X509Name((ASN1Sequence)obj)); + } + else + { + throw new IOException("parsing error"); + } + issuerNames.add(name.clone()); + } + + /** + * Sets the minCRLNumber criterion. The <code>X509CRL</code> must have a + * CRL number extension whose value is greater than or equal to the + * specified value. If <code>null</code>, no minCRLNumber check will be + * done. + * + * @param minCRL + * the minimum CRL number accepted (or <code>null</code>) + */ + public void setMinCRLNumber(BigInteger minCRL) + { + this.minCRL = minCRL; + } + + /** + * Sets the maxCRLNumber criterion. The <code>X509CRL</code> must have a + * CRL number extension whose value is less than or equal to the specified + * value. If <code>null</code>, no maxCRLNumber check will be done. + * + * @param maxCRL + * the maximum CRL number accepted (or <code>null</code>) + */ + public void setMaxCRLNumber(BigInteger maxCRL) + { + this.maxCRL = maxCRL; + } + + /** + * Sets the dateAndTime criterion. The specified date must be equal to or + * later than the value of the thisUpdate component of the + * <code>X509CRL</code> and earlier than the value of the nextUpdate + * component. There is no match if the <code>X509CRL</code> does not + * contain a nextUpdate component. If <code>null</code>, no dateAndTime + * check will be done.<br /> + * <br /> + * Note that the <code>Date</code> supplied here is cloned to protect + * against subsequent modifications. + * + * @param dateAndTime + * the <code>Date</code> to match against (or <code>null</code>) + * + * @see #getDateAndTime + */ + public void setDateAndTime(Date dateAndTime) + { + if (dateAndTime == null) + { + this.dateAndTime = null; + } + else + { + this.dateAndTime = new Date(dateAndTime.getTime()); + } + } + + /** + * Sets the certificate being checked. This is not a criterion. Rather, it + * is optional information that may help a <code>CertStore</code> find + * CRLs that would be relevant when checking revocation for the specified + * certificate. If <code>null</code> is specified, then no such optional + * information is provided. + * + * @param cert + * the <code>X509Certificate</code> being checked (or + * <code>null</code>) + * + * @see #getCertificateChecking + */ + public void setCertificateChecking(X509Certificate cert) + { + certChecking = cert; + } + + /** + * Returns a copy of the issuerNames criterion. The issuer distinguished + * name in the <code>X509CRL</code> must match at least one of the + * specified distinguished names. If the value returned is <code>null</code>, + * any issuer distinguished name will do.<br /> + * <br /> + * If the value returned is not <code>null</code>, it is a + * <code>Collection</code> of names. Each name is a <code>String</code> + * or a byte array representing a distinguished name (in RFC 2253 or ASN.1 + * DER encoded form, respectively). Note that the <code>Collection</code> + * returned may contain duplicate names.<br /> + * <br /> + * If a name is specified as a byte array, it should contain a single DER + * encoded distinguished name, as defined in X.501. The ASN.1 notation for + * this structure is given in the documentation for + * {@link #setIssuerNames setIssuerNames(Collection names)}.<br /> + * <br /> + * Note that a deep copy is performed on the <code>Collection</code> to + * protect against subsequent modifications. + * + * @return a <code>Collection</code> of names (or <code>null</code>) + * @see #setIssuerNames + */ + public Collection getIssuerNames() + { + if (issuerNames == null) + { + return null; + } + + Collection set = new HashSet(); + Iterator iter = issuerNames.iterator(); + Object item; + while (iter.hasNext()) + { + item = iter.next(); + if (item instanceof String) + { + set.add(new String((String)item)); + } + else if (item instanceof byte[]) + { + set.add(((byte[])item).clone()); + } + } + return set; + } + + /** + * Returns the minCRLNumber criterion. The <code>X509CRL</code> must have + * a CRL number extension whose value is greater than or equal to the + * specified value. If <code>null</code>, no minCRLNumber check will be + * done. + * + * @return the minimum CRL number accepted (or <code>null</code>) + */ + public BigInteger getMinCRL() + { + return minCRL; + } + + /** + * Returns the maxCRLNumber criterion. The <code>X509CRL</code> must have + * a CRL number extension whose value is less than or equal to the specified + * value. If <code>null</code>, no maxCRLNumber check will be done. + * + * @return the maximum CRL number accepted (or <code>null</code>) + */ + public BigInteger getMaxCRL() + { + return maxCRL; + } + + /** + * Returns the dateAndTime criterion. The specified date must be equal to or + * later than the value of the thisUpdate component of the + * <code>X509CRL</code> and earlier than the value of the nextUpdate + * component. There is no match if the <code>X509CRL</code> does not + * contain a nextUpdate component. If <code>null</code>, no dateAndTime + * check will be done.<br /> + * <br /> + * Note that the <code>Date</code> returned is cloned to protect against + * subsequent modifications. + * + * @return the <code>Date</code> to match against (or <code>null</code>) + * + * @see #setDateAndTime + */ + public Date getDateAndTime() + { + if (dateAndTime == null) + { + return null; + } + + return new Date(dateAndTime.getTime()); + } + + /** + * Returns the certificate being checked. This is not a criterion. Rather, + * it is optional information that may help a <code>CertStore</code> find + * CRLs that would be relevant when checking revocation for the specified + * certificate. If the value returned is <code>null</code>, then no such + * optional information is provided. + * + * @return the certificate being checked (or <code>null</code>) + * + * @see #setCertificateChecking + */ + public X509Certificate getCertificateChecking() + { + return certChecking; + } + + /** + * Returns a printable representation of the <code>X509CRLSelector</code>.<br /> + * <br /> + * Uses + * {@link org.spongycastle.asn1.x509.X509Name#toString X509Name.toString} to + * format the output + * + * @return a <code>String</code> describing the contents of the + * <code>X509CRLSelector</code>. + */ + public String toString() + { + StringBuffer s = new StringBuffer(); + s.append("X509CRLSelector: [\n"); + if (issuerNamesX509 != null) + { + s.append(" IssuerNames:\n"); + Iterator iter = issuerNamesX509.iterator(); + while (iter.hasNext()) + { + s.append(" ").append(iter.next()).append('\n'); + } + } + if (minCRL != null) + { + s.append(" minCRLNumber: ").append(minCRL).append('\n'); + } + if (maxCRL != null) + { + s.append(" maxCRLNumber: ").append(maxCRL).append('\n'); + } + if (dateAndTime != null) + { + s.append(" dateAndTime: ").append(dateAndTime).append('\n'); + } + if (certChecking != null) + { + s.append(" Certificate being checked: ").append(certChecking).append('\n'); + } + s.append(']'); + return s.toString(); + } + + /** + * Decides whether a <code>CRL</code> should be selected.<br /> + * <br /> + * Uses + * {@link org.spongycastle.asn1.x509.X509Name#toString X509Name.toString} to + * parse and to compare the crl parameter issuer and + * {@link org.spongycastle.asn1.x509.X509Extensions#CRLNumber CRLNumber} to + * access the CRL number extension. + * + * @param crl + * the <code>CRL</code> to be checked + * + * @return <code>true</code> if the <code>CRL</code> should be selected, + * <code>false</code> otherwise + */ + public boolean match(CRL crl) + { + if (!(crl instanceof X509CRL)) + { + return false; + } + + X509CRL crlX509 = (X509CRL)crl; + boolean test; + + if (issuerNamesX509 != null) + { + Iterator iter = issuerNamesX509.iterator(); + test = false; + X509Name crlIssuer = null; + try + { + crlIssuer = PrincipalUtil.getIssuerX509Principal(crlX509); + } + catch (Exception ex) + { + + return false; + } + + while (iter.hasNext()) + { + if (crlIssuer.equals(iter.next(), true)) + { + test = true; + break; + } + } + if (!test) + { + return false; + } + } + + byte[] data = crlX509.getExtensionValue(X509Extensions.CRLNumber + .getId()); + if (data != null) + { + try + { + ByteArrayInputStream inStream = new ByteArrayInputStream(data); + ASN1InputStream derInputStream = new ASN1InputStream(inStream); + inStream = new ByteArrayInputStream( + ((ASN1OctetString)derInputStream.readObject()) + .getOctets()); + derInputStream = new ASN1InputStream(inStream); + BigInteger crlNumber = ((ASN1Integer)derInputStream.readObject()) + .getPositiveValue(); + if (minCRL != null && minCRL.compareTo(crlNumber) > 0) + { + return false; + } + if (maxCRL != null && maxCRL.compareTo(crlNumber) < 0) + { + return false; + } + } + catch (IOException ex) + { + return false; + } + } + else if (minCRL != null || maxCRL != null) + { + return false; + } + + if (dateAndTime != null) + { + Date check = crlX509.getThisUpdate(); + if (check == null) + { + return false; + } + else if (dateAndTime.before(check)) + { + return false; + } + + check = crlX509.getNextUpdate(); + if (check == null) + { + return false; + } + else if (!dateAndTime.before(check)) + { + return false; + } + } + + return true; + } + + /** + * Returns a copy of this object. + * + * @return the copy + */ + public Object clone() + { + try + { + X509CRLSelector copy = (X509CRLSelector)super.clone(); + if (issuerNames != null) + { + copy.issuerNames = new HashSet(); + Iterator iter = issuerNames.iterator(); + Object obj; + while (iter.hasNext()) + { + obj = iter.next(); + if (obj instanceof byte[]) + { + copy.issuerNames.add(((byte[])obj).clone()); + } + else + { + copy.issuerNames.add(obj); + } + } + copy.issuerNamesX509 = new HashSet(issuerNamesX509); + } + return copy; + } + catch (CloneNotSupportedException e) + { + /* Cannot happen */ + throw new InternalError(e.toString()); + } + } + + /** + * Decides whether a <code>CRL</code> should be selected. + * + * @param crl + * the <code>CRL</code> to be checked + * + * @return <code>true</code> if the <code>CRL</code> should be selected, + * <code>false</code> otherwise + */ + public boolean equals(Object obj) + { + if (!(obj instanceof X509CRLSelector)) + { + return false; + } + + X509CRLSelector equalsCRL = (X509CRLSelector)obj; + + if (!equals(dateAndTime, equalsCRL.dateAndTime)) + { + return false; + } + + if (!equals(minCRL, equalsCRL.minCRL)) + { + return false; + } + + if (!equals(maxCRL, equalsCRL.maxCRL)) + { + return false; + } + + if (!equals(issuerNamesX509, equalsCRL.issuerNamesX509)) + { + return false; + } + + if (!equals(certChecking, equalsCRL.certChecking)) + { + return false; + } + + return true; + } + + /** + * Return <code>true</code> if two Objects are unequal. + * This means that one is <code>null</code> and the other is + * not or <code>obj1.equals(obj2)</code> returns + * <code>false</code>. + **/ + private boolean equals(Object obj1, Object obj2) + { + if (obj1 == null) + { + if (obj2 != null) + { + return true; + } + } + else if (!obj1.equals(obj2)) + { + return true; + } + return false; + } +}
\ No newline at end of file diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CertSelector.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CertSelector.java new file mode 100644 index 00000000..0b288faa --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CertSelector.java @@ -0,0 +1,2469 @@ +package org.spongycastle.jce.cert; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.PublicKey; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1Object; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.ASN1TaggedObject; +import org.spongycastle.asn1.DERGeneralizedTime; +import org.spongycastle.asn1.ASN1GeneralizedTime; +import org.spongycastle.asn1.DEROutputStream; +import org.spongycastle.asn1.util.ASN1Dump; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.ExtendedKeyUsage; +import org.spongycastle.asn1.x509.KeyPurposeId; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.asn1.x509.X509Extensions; +import org.spongycastle.asn1.x509.X509Name; +import org.spongycastle.jce.PrincipalUtil; +import org.spongycastle.util.Integers; + +/** + * A <code>CertSelector</code> that selects + * <code>X509Certificates that match all + * specified criteria. This class is particularly useful when + * selecting certificates from a CertStore to build a PKIX-compliant + * certification path.<br /> + * <br /> + * When first constructed, an <code>X509CertSelector</code> has no criteria enabled + * and each of the get methods return a default value (<code>null</code>, or -1 for + * the {@link #getBasicConstraints} method). Therefore, the {@link #match} method would + * return true for any <code>X509Certificate</code>. Typically, several criteria + * are enabled (by calling {@link #setIssuer} or {@link #setKeyUsage}, for instance) and + * then the <code>X509CertSelector</code> is passed to {@link CertStore#getCertificates} or + * some similar method.<br /> + * <br /> + * Several criteria can be enabled (by calling {@link #setIssuer} and + * {@link #setSerialNumber}, for example) such that the match method usually + * uniquely matches a single <code>X509Certificate</code>. We say usually, since it + * is possible for two issuing CAs to have the same distinguished name + * and each issue a certificate with the same serial number. Other + * unique combinations include the issuer, subject, + * subjectKeyIdentifier and/or the subjectPublicKey criteria.<br /> + * <br /> + * Please refer to RFC 2459 for definitions of the X.509 certificate + * extensions mentioned below.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are + * not thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize.<br /> + * <br /> + * <b>TODO: implement name constraints</b> + * <b>TODO: implement match check for path to names</b><br /> + * <br /> + * Uses {@link org.spongycastle.asn1.ASN1InputStream ASN1InputStream}, + * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence}, + * {@link org.spongycastle.asn1.ASN1ObjectIdentifier ASN1ObjectIdentifier}, + * {@link org.spongycastle.asn1.DEROutputStream DEROutputStream}, + * {@link org.spongycastle.asn1.ASN1Object ASN1Object}, + * {@link org.spongycastle.asn1.OIDTokenizer OIDTokenizer}, + * {@link org.spongycastle.asn1.x509.X509Name X509Name}, + * {@link org.spongycastle.asn1.x509.X509Extensions X509Extensions}, + * {@link org.spongycastle.asn1.x509.ExtendedKeyUsage ExtendedKeyUsage}, + * {@link org.spongycastle.asn1.x509.KeyPurposeId KeyPurposeId}, + * {@link org.spongycastle.asn1.x509.SubjectPublicKeyInfo SubjectPublicKeyInfo}, + * {@link org.spongycastle.asn1.x509.AlgorithmIdentifier AlgorithmIdentifier} + */ +public class X509CertSelector implements CertSelector +{ + private static final Hashtable keyPurposeIdMap = new Hashtable(); + static + { + keyPurposeIdMap.put(KeyPurposeId.id_kp_serverAuth.getId(), + KeyPurposeId.id_kp_serverAuth); + keyPurposeIdMap.put(KeyPurposeId.id_kp_clientAuth.getId(), + KeyPurposeId.id_kp_clientAuth); + keyPurposeIdMap.put(KeyPurposeId.id_kp_codeSigning.getId(), + KeyPurposeId.id_kp_codeSigning); + keyPurposeIdMap.put(KeyPurposeId.id_kp_emailProtection.getId(), + KeyPurposeId.id_kp_emailProtection); + keyPurposeIdMap.put(KeyPurposeId.id_kp_ipsecEndSystem.getId(), + KeyPurposeId.id_kp_ipsecEndSystem); + keyPurposeIdMap.put(KeyPurposeId.id_kp_ipsecTunnel.getId(), + KeyPurposeId.id_kp_ipsecTunnel); + keyPurposeIdMap.put(KeyPurposeId.id_kp_ipsecUser.getId(), + KeyPurposeId.id_kp_ipsecUser); + keyPurposeIdMap.put(KeyPurposeId.id_kp_timeStamping.getId(), + KeyPurposeId.id_kp_timeStamping); + } + + private X509Certificate x509Cert = null; + + private BigInteger serialNumber = null; + + private Object issuerDN = null; + + private X509Name issuerDNX509 = null; + + private Object subjectDN = null; + + private X509Name subjectDNX509 = null; + + private byte[] subjectKeyID = null; + + private byte[] authorityKeyID = null; + + private Date certValid = null; + + private Date privateKeyValid = null; + + private ASN1ObjectIdentifier subjectKeyAlgID = null; + + private PublicKey subjectPublicKey = null; + + private byte[] subjectPublicKeyByte = null; + + private boolean[] keyUsage = null; + + private Set keyPurposeSet = null; + + private boolean matchAllSubjectAltNames = true; + + private Set subjectAltNames = null; + + private Set subjectAltNamesByte = null; + + private int minMaxPathLen = -1; + + private Set policy = null; + + private Set policyOID = null; + + private Set pathToNames = null; + + private Set pathToNamesByte = null; + + /** + * Creates an <code>X509CertSelector</code>. Initially, no criteria are + * set so any <code>X509Certificate</code> will match. + */ + public X509CertSelector() + { + } + + /** + * Sets the certificateEquals criterion. The specified + * <code>X509Certificate</code> must be equal to the + * <code>X509Certificate</code> passed to the match method. If + * <code>null</code>, then this check is not applied.<br /> + * <br /> + * This method is particularly useful when it is necessary to match a single + * certificate. Although other criteria can be specified in conjunction with + * the certificateEquals criterion, it is usually not practical or + * necessary. + * + * @param cert + * the X509Certificate to match (or <code>null</code>) + * + * @see #getCertificate() + */ + public void setCertificate(X509Certificate cert) + { + x509Cert = cert; + } + + /** + * Sets the serialNumber criterion. The specified serial number must match + * the certificate serial number in the <code>X509Certificate</code>. If + * <code>null</code>, any certificate serial number will do. + * + * @param serial + * the certificate serial number to match (or <code>null</code>) + * + * @see #getSerialNumber() + */ + public void setSerialNumber(BigInteger serial) + { + serialNumber = serial; + } + + /** + * Sets the issuer criterion. The specified distinguished name must match + * the issuer distinguished name in the <code>X509Certificate</code>. If + * <code>null</code>, any issuer distinguished name will do.<br /> + * <br /> + * If <code>issuerDN</code> is not <code>null</code>, it should contain + * a distinguished name, in RFC 2253 format.<br /> + * <br /> + * Uses {@link org.spongycastle.asn1.x509.X509Name X509Name} for parsing the + * issuerDN. + * + * @param issuerDN + * a distinguished name in RFC 2253 format (or <code>null</code>) + * + * @exception IOException + * if a parsing error occurs (incorrect form for DN) + */ + public void setIssuer(String issuerDN) throws IOException + { + if (issuerDN == null) + { + this.issuerDN = null; + this.issuerDNX509 = null; + } + else + { + X509Name nameX509; + try + { + nameX509 = new X509Name(issuerDN); + } + catch (IllegalArgumentException ex) + { + throw new IOException(ex.getMessage()); + } + this.issuerDNX509 = nameX509; + this.issuerDN = issuerDN; + } + } + + /** + * Sets the issuer criterion. The specified distinguished name must match + * the issuer distinguished name in the <code>X509Certificate</code>. If + * null is specified, the issuer criterion is disabled and any issuer + * distinguished name will do.<br /> + * <br /> + * If <code>issuerDN</code> is not <code>null</code>, it should contain + * a single DER encoded distinguished name, as defined in X.501. The ASN.1 + * notation for this structure is as follows.<br /> + * <br /> + * + * <pre> + * Name ::= CHOICE { + * RDNSequence } + * + * RDNSequence ::= SEQUENCE OF RDN + * + * RDN ::= + * SET SIZE (1 .. MAX) OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY DEFINED BY AttributeType + * .... + * DirectoryString ::= CHOICE { + * teletexString TeletexString (SIZE (1..MAX)), + * printableString PrintableString (SIZE (1..MAX)), + * universalString UniversalString (SIZE (1..MAX)), + * utf8String UTF8String (SIZE (1.. MAX)), + * bmpString BMPString (SIZE (1..MAX)) } + * </pre> + * + * <br /> + * <br /> + * Note that the byte array specified here is cloned to protect against + * subsequent modifications.<br /> + * <br /> + * Uses {@link org.spongycastle.asn1.ASN1InputStream ASN1InputStream}, + * {@link org.spongycastle.asn1.ASN1Object ASN1Object}, + * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence}, + * {@link org.spongycastle.asn1.x509.X509Name X509Name} + * + * @param issuerDN - + * a byte array containing the distinguished name in ASN.1 DER + * encoded form (or <code>null</code>) + * + * @exception IOException + * if an encoding error occurs (incorrect form for DN) + */ + public void setIssuer(byte[] issuerDN) throws IOException + { + if (issuerDN == null) + { + this.issuerDN = null; + this.issuerDNX509 = null; + } + else + { + ByteArrayInputStream inStream = new ByteArrayInputStream(issuerDN); + ASN1InputStream derInStream = new ASN1InputStream(inStream); + ASN1Object obj = derInStream.readObject(); + if (obj instanceof ASN1Sequence) + { + this.issuerDNX509 = new X509Name((ASN1Sequence)obj); + } + else + { + throw new IOException("parsing error"); + } + this.issuerDN = (byte[])issuerDN.clone(); + } + } + + /** + * Sets the subject criterion. The specified distinguished name must match + * the subject distinguished name in the <code>X509Certificate</code>. If + * null, any subject distinguished name will do.<br /> + * <br /> + * If <code>subjectDN</code> is not <code>null</code>, it should + * contain a distinguished name, in RFC 2253 format.<br /> + * <br /> + * Uses {@link org.spongycastle.asn1.x509.X509Name X509Name} for parsing the + * subjectDN. + * + * @param subjectDN + * a distinguished name in RFC 2253 format (or <code>null</code>) + * + * @exception IOException + * if a parsing error occurs (incorrect form for DN) + */ + public void setSubject(String subjectDN) throws IOException + { + if (subjectDN == null) + { + this.subjectDN = null; + this.subjectDNX509 = null; + } + else + { + X509Name nameX509; + try + { + nameX509 = new X509Name(subjectDN); + } + catch (IllegalArgumentException ex) + { + throw new IOException(ex.getMessage()); + } + + this.subjectDNX509 = nameX509; + this.subjectDN = subjectDN; + } + } + + /** + * Sets the subject criterion. The specified distinguished name must match + * the subject distinguished name in the <code>X509Certificate</code>. If + * null, any subject distinguished name will do.<br /> + * <br /> + * If <code>subjectDN</code> is not <code>null</code>, it should + * contain a single DER encoded distinguished name, as defined in X.501. For + * the ASN.1 notation for this structure, see + * {@link #setIssuer(byte []) setIssuer(byte [] issuerDN)}.<br /> + * <br /> + * Uses {@link org.spongycastle.asn1.ASN1InputStream ASN1InputStream}, + * {@link org.spongycastle.asn1.ASN1Object ASN1Object}, + * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence}, + * {@link org.spongycastle.asn1.x509.X509Name X509Name} + * + * @param subjectDN + * a byte array containing the distinguished name in ASN.1 DER + * format (or <code>null</code>) + * + * @exception IOException + * if an encoding error occurs (incorrect form for DN) + */ + public void setSubject(byte[] subjectDN) throws IOException + { + if (subjectDN == null) + { + this.subjectDN = null; + this.subjectDNX509 = null; + } + else + { + ByteArrayInputStream inStream = new ByteArrayInputStream(subjectDN); + ASN1InputStream derInStream = new ASN1InputStream(inStream); + ASN1Object obj = derInStream.readObject(); + + if (obj instanceof ASN1Sequence) + { + this.subjectDNX509 = new X509Name((ASN1Sequence)obj); + } + else + { + throw new IOException("parsing error"); + } + this.subjectDN = (byte[])subjectDN.clone(); + } + } + + /** + * Sets the subjectKeyIdentifier criterion. The <code>X509Certificate</code> + * must contain a SubjectKeyIdentifier extension for which the contents of + * the extension matches the specified criterion value. If the criterion + * value is null, no subjectKeyIdentifier check will be done.<br /> + * <br /> + * If <code>subjectKeyID</code> is not <code>null</code>, it should + * contain a single DER encoded value corresponding to the contents of the + * extension value (not including the object identifier, criticality + * setting, and encapsulating OCTET STRING) for a SubjectKeyIdentifier + * extension. The ASN.1 notation for this structure follows.<br /> + * <br /> + * + * <pre> + * SubjectKeyIdentifier ::= KeyIdentifier + * + * KeyIdentifier ::= OCTET STRING + * </pre> + * + * <br /> + * <br /> + * Since the format of subject key identifiers is not mandated by any + * standard, subject key identifiers are not parsed by the + * <code>X509CertSelector</code>. Instead, the values are compared using + * a byte-by-byte comparison.<br /> + * <br /> + * Note that the byte array supplied here is cloned to protect against + * subsequent modifications. + * + * @param subjectKeyID - + * the subject key identifier (or <code>null</code>) + * + * @see #getSubjectKeyIdentifier() + */ + public void setSubjectKeyIdentifier(byte[] subjectKeyID) + { + if (subjectKeyID == null) + { + this.subjectKeyID = null; + } + else + { + this.subjectKeyID = (byte[])subjectKeyID.clone(); + } + } + + /** + * Sets the authorityKeyIdentifier criterion. The + * <code>X509Certificate</code> must contain an AuthorityKeyIdentifier + * extension for which the contents of the extension value matches the + * specified criterion value. If the criterion value is <code>null</code>, + * no authorityKeyIdentifier check will be done.<br /> + * <br /> + * If <code>authorityKeyID</code> is not <code>null</code>, it should + * contain a single DER encoded value corresponding to the contents of the + * extension value (not including the object identifier, criticality + * setting, and encapsulating OCTET STRING) for an AuthorityKeyIdentifier + * extension. The ASN.1 notation for this structure follows.<br /> + * <br /> + * + * <pre> + * AuthorityKeyIdentifier ::= SEQUENCE { + * keyIdentifier [0] KeyIdentifier OPTIONAL, + * authorityCertIssuer [1] GeneralNames OPTIONAL, + * authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL } + * + * KeyIdentifier ::= OCTET STRING + * </pre> + * + * <br /> + * <br /> + * Authority key identifiers are not parsed by the + * <code>X509CertSelector</code>. Instead, the values are compared using + * a byte-by-byte comparison.<br /> + * <br /> + * When the <code>keyIdentifier</code> field of + * <code>AuthorityKeyIdentifier</code> is populated, the value is usually + * taken from the SubjectKeyIdentifier extension in the issuer's + * certificate. Note, however, that the result of + * X509Certificate.getExtensionValue(<SubjectKeyIdentifier Object + * Identifier>) on the issuer's certificate may NOT be used directly as the + * input to setAuthorityKeyIdentifier. This is because the + * SubjectKeyIdentifier contains only a KeyIdentifier OCTET STRING, and not + * a SEQUENCE of KeyIdentifier, GeneralNames, and CertificateSerialNumber. + * In order to use the extension value of the issuer certificate's + * SubjectKeyIdentifier extension, it will be necessary to extract the value + * of the embedded KeyIdentifier OCTET STRING, then DER encode this OCTET + * STRING inside a SEQUENCE. For more details on SubjectKeyIdentifier, see + * {@link #setSubjectKeyIdentifier(byte[]) setSubjectKeyIdentifier(byte[] subjectKeyID }).<br /> + * <br /> + * Note also that the byte array supplied here is cloned to protect against + * subsequent modifications. + * + * @param authorityKeyID + * the authority key identifier (or <code>null</code>) + * + * @see #getAuthorityKeyIdentifier() + */ + public void setAuthorityKeyIdentifier(byte[] authorityKeyID) + { + if (authorityKeyID == null) + { + this.authorityKeyID = null; + } + else + { + this.authorityKeyID = (byte[])authorityKeyID.clone(); + } + } + + /** + * Sets the certificateValid criterion. The specified date must fall within + * the certificate validity period for the X509Certificate. If + * <code>null</code>, no certificateValid check will be done.<br /> + * <br /> + * Note that the Date supplied here is cloned to protect against subsequent + * modifications. + * + * @param certValid + * the Date to check (or <code>null</code>) + * + * @see #getCertificateValid() + */ + public void setCertificateValid(Date certValid) + { + if (certValid == null) + { + this.certValid = null; + } + else + { + this.certValid = new Date(certValid.getTime()); + } + } + + /** + * Sets the privateKeyValid criterion. The specified date must fall within + * the private key validity period for the X509Certificate. If + * <code>null</code>, no privateKeyValid check will be done.<br /> + * <br /> + * Note that the Date supplied here is cloned to protect against subsequent + * modifications. + * + * @param privateKeyValid + * the Date to check (or <code>null</code>) + * + * @see #getPrivateKeyValid() + */ + public void setPrivateKeyValid(Date privateKeyValid) + { + if (privateKeyValid == null) + { + this.privateKeyValid = null; + } + else + { + this.privateKeyValid = new Date(privateKeyValid.getTime()); + } + } + + /** + * Sets the subjectPublicKeyAlgID criterion. The X509Certificate must + * contain a subject public key with the specified algorithm. If + * <code>null</code>, no subjectPublicKeyAlgID check will be done. + * + * @param oid + * The object identifier (OID) of the algorithm to check for (or + * <code>null</code>). An OID is represented by a set of + * nonnegative integers separated by periods. + * + * @exception IOException + * if the OID is invalid, such as the first component being + * not 0, 1 or 2 or the second component being greater than + * 39. + * + * @see #getSubjectPublicKeyAlgID() + */ + public void setSubjectPublicKeyAlgID(String oid) throws IOException + { + if (oid != null) + { + CertUtil.parseOID(oid); + subjectKeyAlgID = new ASN1ObjectIdentifier(oid); + } + else + { + subjectKeyAlgID = null; + } + } + + /** + * Sets the subjectPublicKey criterion. The X509Certificate must contain the + * specified subject public key. If null, no subjectPublicKey check will be + * done. + * + * @param key + * the subject public key to check for (or null) + * + * @see #getSubjectPublicKey() + */ + public void setSubjectPublicKey(PublicKey key) + { + if (key == null) + { + subjectPublicKey = null; + subjectPublicKeyByte = null; + } + else + { + subjectPublicKey = key; + subjectPublicKeyByte = key.getEncoded(); + } + } + + /** + * Sets the subjectPublicKey criterion. The <code>X509Certificate</code> + * must contain the specified subject public key. If <code>null</code>, + * no subjectPublicKey check will be done.<br /> + * <br /> + * Because this method allows the public key to be specified as a byte + * array, it may be used for unknown key types.<br /> + * <br /> + * If key is not <code>null</code>, it should contain a single DER + * encoded SubjectPublicKeyInfo structure, as defined in X.509. The ASN.1 + * notation for this structure is as follows.<br /> + * <br /> + * + * <pre> + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + * -- contains a value of the type + * -- registered for use with the + * -- algorithm object identifier value + * </pre> + * + * <br /> + * <br /> + * Note that the byte array supplied here is cloned to protect against + * subsequent modifications. + * + * @param key + * a byte array containing the subject public key in ASN.1 DER + * form (or <code>null</code>) + * + * @exception IOException + * if an encoding error occurs (incorrect form for subject + * public key) + * + * @see #getSubjectPublicKey() + */ + public void setSubjectPublicKey(byte[] key) throws IOException + { + if (key == null) + { + subjectPublicKey = null; + subjectPublicKeyByte = null; + } + else + { + subjectPublicKey = null; + subjectPublicKeyByte = (byte[])key.clone(); + // TODO + // try to generyte PublicKey Object from subjectPublicKeyByte + } + } + + /** + * Sets the keyUsage criterion. The X509Certificate must allow the specified + * keyUsage values. If null, no keyUsage check will be done. Note that an + * X509Certificate that has no keyUsage extension implicitly allows all + * keyUsage values.<br /> + * <br /> + * Note that the boolean array supplied here is cloned to protect against + * subsequent modifications. + * + * @param keyUsage + * a boolean array in the same format as the boolean array + * returned by X509Certificate.getKeyUsage(). Or + * <code>null</code>. + * + * @see #getKeyUsage() + */ + public void setKeyUsage(boolean[] keyUsage) + { + if (keyUsage == null) + { + this.keyUsage = null; + } + else + { + this.keyUsage = (boolean[])keyUsage.clone(); + } + } + + /** + * Sets the extendedKeyUsage criterion. The <code>X509Certificate</code> + * must allow the specified key purposes in its extended key usage + * extension. If <code>keyPurposeSet</code> is empty or <code>null</code>, + * no extendedKeyUsage check will be done. Note that an + * <code>X509Certificate</code> that has no extendedKeyUsage extension + * implicitly allows all key purposes.<br /> + * <br /> + * Note that the Set is cloned to protect against subsequent modifications.<br /> + * <br /> + * Uses {@link org.spongycastle.asn1.x509.KeyPurposeId KeyPurposeId} + * + * @param keyPurposeSet + * a <code>Set</code> of key purpose OIDs in string format (or + * <code>null</code>). Each OID is represented by a set of + * nonnegative integers separated by periods. + * + * @exception IOException + * if the OID is invalid, such as the first component being + * not 0, 1 or 2 or the second component being greater than + * 39. + * + * @see #getExtendedKeyUsage() + */ + public void setExtendedKeyUsage(Set keyPurposeSet) throws IOException + { + if (keyPurposeSet == null || keyPurposeSet.isEmpty()) + { + this.keyPurposeSet = keyPurposeSet; + } + else + { + this.keyPurposeSet = new HashSet(); + Iterator iter = keyPurposeSet.iterator(); + Object obj; + KeyPurposeId purposeID; + while (iter.hasNext()) + { + obj = iter.next(); + if (obj instanceof String) + { + purposeID = (KeyPurposeId)keyPurposeIdMap.get((String)obj); + if (purposeID == null) + { + throw new IOException("unknown purposeID " + + (String)obj); + } + this.keyPurposeSet.add(purposeID); + } + } + } + } + + /** + * Enables/disables matching all of the subjectAlternativeNames specified in + * the {@link #setSubjectAlternativeNames setSubjectAlternativeNames} or + * {@link #addSubjectAlternativeName addSubjectAlternativeName} methods. If + * enabled, the <code>X509Certificate</code> must contain all of the + * specified subject alternative names. If disabled, the X509Certificate + * must contain at least one of the specified subject alternative names.<br /> + * <br /> + * The matchAllNames flag is <code>true</code> by default. + * + * @param matchAllNames + * if <code>true</code>, the flag is enabled; if + * <code>false</code>, the flag is disabled. + * + * @see #getMatchAllSubjectAltNames() + */ + public void setMatchAllSubjectAltNames(boolean matchAllNames) + { + matchAllSubjectAltNames = matchAllNames; + } + + /** + * Sets the subjectAlternativeNames criterion. The + * <code>X509Certificate</code> must contain all or at least one of the + * specified subjectAlternativeNames, depending on the value of the + * matchAllNames flag (see {@link #setMatchAllSubjectAltNames}).<br /> + * <br /> + * This method allows the caller to specify, with a single method call, the + * complete set of subject alternative names for the subjectAlternativeNames + * criterion. The specified value replaces the previous value for the + * subjectAlternativeNames criterion.<br /> + * <br /> + * The <code>names</code> parameter (if not <code>null</code>) is a + * <code>Collection</code> with one entry for each name to be included in + * the subject alternative name criterion. Each entry is a <code>List</code> + * whose first entry is an <code>Integer</code> (the name type, 0-8) and + * whose second entry is a <code>String</code> or a byte array (the name, + * in string or ASN.1 DER encoded form, respectively). There can be multiple + * names of the same type. If <code>null</code> is supplied as the value + * for this argument, no subjectAlternativeNames check will be performed.<br /> + * <br /> + * Each subject alternative name in the <code>Collection</code> may be + * specified either as a <code>String</code> or as an ASN.1 encoded byte + * array. For more details about the formats used, see + * {@link #addSubjectAlternativeName(int, String) addSubjectAlternativeName(int type, String name)} + * and + * {@link #addSubjectAlternativeName(int, byte[]) addSubjectAlternativeName(int type, byte [] name}).<br /> + * <br /> + * Note that the <code>names</code> parameter can contain duplicate names + * (same name and name type), but they may be removed from the + * <code>Collection</code> of names returned by the + * {@link #getSubjectAlternativeNames} method.<br /> + * <br /> + * Note that a deep copy is performed on the Collection to protect against + * subsequent modifications. + * + * @param names - + * a Collection of names (or null) + * + * @exception IOException + * if a parsing error occurs + * + * @see #getSubjectAlternativeNames() + */ + public void setSubjectAlternativeNames(Collection names) throws IOException + { + try + { + if (names == null || names.isEmpty()) + { + subjectAltNames = null; + subjectAltNamesByte = null; + } + else + { + subjectAltNames = new HashSet(); + subjectAltNamesByte = new HashSet(); + Iterator iter = names.iterator(); + List item; + int type; + Object data; + while (iter.hasNext()) + { + item = (List)iter.next(); + type = ((Integer)item.get(0)).intValue(); + data = item.get(1); + if (data instanceof String) + { + addSubjectAlternativeName(type, (String)data); + } + else if (data instanceof byte[]) + { + addSubjectAlternativeName(type, (byte[])data); + } + else + { + throw new IOException( + "parsing error: unknown data type"); + } + } + } + } + catch (Exception ex) + { + throw new IOException("parsing exception:\n" + ex.toString()); + } + } + + /** + * Adds a name to the subjectAlternativeNames criterion. The + * <code>X509Certificate</code> must contain all or at least one of the + * specified subjectAlternativeNames, depending on the value of the + * matchAllNames flag (see {@link #setMatchAllSubjectAltNames}).<br /> + * <br /> + * This method allows the caller to add a name to the set of subject + * alternative names. The specified name is added to any previous value for + * the subjectAlternativeNames criterion. If the specified name is a + * duplicate, it may be ignored.<br /> + * <br /> + * The name is provided in string format. RFC 822, DNS, and URI names use + * the well-established string formats for those types (subject to the + * restrictions included in RFC 2459). IPv4 address names are supplied using + * dotted quad notation. OID address names are represented as a series of + * nonnegative integers separated by periods. And directory names + * (distinguished names) are supplied in RFC 2253 format. No standard string + * format is defined for otherNames, X.400 names, EDI party names, IPv6 + * address names, or any other type of names. They should be specified using + * the + * {@link #addSubjectAlternativeName(int, byte[]) addSubjectAlternativeName(int type, byte [] name)} + * method. + * + * @param type + * the name type (0-8, as specified in RFC 2459, section 4.2.1.7) + * @param name - + * the name in string form (not null) + * + * @exception IOException + * if a parsing error occurs + */ + public void addSubjectAlternativeName(int type, String name) + throws IOException + { + // TODO full implementation of CertUtil.parseGeneralName + byte[] encoded = CertUtil.parseGeneralName(type, name); + List tmpList = new ArrayList(); + tmpList.add(Integers.valueOf(type)); + tmpList.add(name); + subjectAltNames.add(tmpList); + tmpList.set(1, encoded); + subjectAltNamesByte.add(tmpList); + } + + /** + * Adds a name to the subjectAlternativeNames criterion. The + * <code>X509Certificate</code> must contain all or at least one of the + * specified subjectAlternativeNames, depending on the value of the + * matchAllNames flag (see {@link #setMatchAllSubjectAltNames}).<br /> + * <br /> + * This method allows the caller to add a name to the set of subject + * alternative names. The specified name is added to any previous value for + * the subjectAlternativeNames criterion. If the specified name is a + * duplicate, it may be ignored.<br /> + * <br /> + * The name is provided as a byte array. This byte array should contain the + * DER encoded name, as it would appear in the GeneralName structure defined + * in RFC 2459 and X.509. The encoded byte array should only contain the + * encoded value of the name, and should not include the tag associated with + * the name in the GeneralName structure. The ASN.1 definition of this + * structure appears below.<br /> + * <br /> + * + * <pre> + * GeneralName ::= CHOICE { + * otherName [0] OtherName, + * rfc822Name [1] IA5String, + * dNSName [2] IA5String, + * x400Address [3] ORAddress, + * directoryName [4] Name, + * ediPartyName [5] EDIPartyName, + * uniformResourceIdentifier [6] IA5String, + * iPAddress [7] OCTET STRING, + * registeredID [8] OBJECT IDENTIFIER} + * </pre> + * + * <br /> + * <br /> + * Note that the byte array supplied here is cloned to protect against + * subsequent modifications.<br /> + * <br /> + * <b>TODO: check encoded format</b> + * + * @param type + * the name type (0-8, as listed above) + * @param name + * a byte array containing the name in ASN.1 DER encoded form + * + * @exception IOException + * if a parsing error occurs + */ + public void addSubjectAlternativeName(int type, byte[] name) + throws IOException + { + // TODO check encoded format + List tmpList = new ArrayList(); + tmpList.add(Integers.valueOf(type)); + tmpList.add(name.clone()); + subjectAltNames.add(tmpList); + subjectAltNamesByte.add(tmpList); + } + + /** + * Sets the name constraints criterion. The <code>X509Certificate</code> + * must have subject and subject alternative names that meet the specified + * name constraints.<br /> + * <br /> + * The name constraints are specified as a byte array. This byte array + * should contain the DER encoded form of the name constraints, as they + * would appear in the NameConstraints structure defined in RFC 2459 and + * X.509. The ASN.1 definition of this structure appears below.<br /> + * <br /> + * + * <pre> + * NameConstraints ::= SEQUENCE { + * permittedSubtrees [0] GeneralSubtrees OPTIONAL, + * excludedSubtrees [1] GeneralSubtrees OPTIONAL } + * + * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree + * + * GeneralSubtree ::= SEQUENCE { + * base GeneralName, + * minimum [0] BaseDistance DEFAULT 0, + * maximum [1] BaseDistance OPTIONAL } + * + * BaseDistance ::= INTEGER (0..MAX) + * + * GeneralName ::= CHOICE { + * otherName [0] OtherName, + * rfc822Name [1] IA5String, + * dNSName [2] IA5String, + * x400Address [3] ORAddress, + * directoryName [4] Name, + * ediPartyName [5] EDIPartyName, + * uniformResourceIdentifier [6] IA5String, + * iPAddress [7] OCTET STRING, + * registeredID [8] OBJECT IDENTIFIER} + * </pre> + * + * <br /> + * <br /> + * Note that the byte array supplied here is cloned to protect against + * subsequent modifications.<br /> + * <br /> + * <b>TODO: implement this</b> + * + * @param bytes + * a byte array containing the ASN.1 DER encoding of a + * NameConstraints extension to be used for checking name + * constraints. Only the value of the extension is included, not + * the OID or criticality flag. Can be <code>null</code>, in + * which case no name constraints check will be performed + * + * @exception IOException + * if a parsing error occurs + * @exception UnsupportedOperationException + * because this method is not supported + * @see #getNameConstraints() + */ + public void setNameConstraints(byte[] bytes) throws IOException + { + throw new UnsupportedOperationException(); + } + + /** + * Sets the basic constraints constraint. If the value is greater than or + * equal to zero, <code>X509Certificates</code> must include a + * basicConstraints extension with a pathLen of at least this value. If the + * value is -2, only end-entity certificates are accepted. If the value is + * -1, no check is done.<br /> + * <br /> + * This constraint is useful when building a certification path forward + * (from the target toward the trust anchor. If a partial path has been + * built, any candidate certificate must have a maxPathLen value greater + * than or equal to the number of certificates in the partial path. + * + * @param minMaxPathLen + * the value for the basic constraints constraint + * + * @exception IllegalArgumentException + * if the value is less than -2 + * + * @see #getBasicConstraints() + */ + public void setBasicConstraints(int minMaxPathLen) + { + if (minMaxPathLen < -2) + { + throw new IllegalArgumentException("minMaxPathLen must be >= -2"); + } + + this.minMaxPathLen = minMaxPathLen; + } + + /** + * Sets the policy constraint. The X509Certificate must include at least one + * of the specified policies in its certificate policies extension. If + * certPolicySet is empty, then the X509Certificate must include at least + * some specified policy in its certificate policies extension. If + * certPolicySet is null, no policy check will be performed.<br /> + * <br /> + * Note that the Set is cloned to protect against subsequent modifications.<br /> + * <br /> + * <b>TODO: implement match check for this</b> + * + * @param certPolicySet + * a Set of certificate policy OIDs in string format (or null). + * Each OID is represented by a set of nonnegative integers + * separated by periods. + * + * @exception IOException + * if a parsing error occurs on the OID such as the first + * component is not 0, 1 or 2 or the second component is + * greater than 39. + * + * @see #getPolicy() + */ + public void setPolicy(Set certPolicySet) throws IOException + { + if (certPolicySet == null) + { + policy = null; + policyOID = null; + } + else + { + policyOID = new HashSet(); + Iterator iter = certPolicySet.iterator(); + Object item; + while (iter.hasNext()) + { + item = iter.next(); + if (item instanceof String) + { + CertUtil.parseOID((String)item); + policyOID.add(new ASN1ObjectIdentifier((String)item)); + } + else + { + throw new IOException( + "certPolicySet contains null values or non String objects"); + } + } + policy = new HashSet(certPolicySet); + } + } + + /** + * Sets the pathToNames criterion. The <code>X509Certificate</code> must + * not include name constraints that would prohibit building a path to the + * specified names.<br /> + * <br /> + * This method allows the caller to specify, with a single method call, the + * complete set of names which the <code>X509Certificates</code>'s name + * constraints must permit. The specified value replaces the previous value + * for the pathToNames criterion.<br /> + * <br /> + * This constraint is useful when building a certification path forward + * (from the target toward the trust anchor. If a partial path has been + * built, any candidate certificate must not include name constraints that + * would prohibit building a path to any of the names in the partial path.<br /> + * <br /> + * The names parameter (if not <code>null</code>) is a + * <code>Collection</code> with one entry for each name to be included in + * the pathToNames criterion. Each entry is a <code>List</code> whose + * first entry is an Integer (the name type, 0-8) and whose second entry is + * a <code>String</code> or a byte array (the name, in string or ASN.1 DER + * encoded form, respectively). There can be multiple names of the same + * type. If <code>null</code> is supplied as the value for this argument, + * no pathToNames check will be performed.<br /> + * <br /> + * Each name in the Collection may be specified either as a String or as an + * ASN.1 encoded byte array. For more details about the formats used, see + * {@link #addPathToName(int, String) addPathToName(int type, String name)} + * and + * {@link #addPathToName(int, byte[]) addPathToName(int type, byte [] name)}.<br /> + * <br /> + * Note that the names parameter can contain duplicate names (same name and + * name type), but they may be removed from the Collection of names returned + * by the {@link #getPathToNames} method.<br /> + * <br /> + * Note that a deep copy is performed on the Collection to protect against + * subsequent modifications.<br /> + * <br /> + * <b>TODO: implement this match check for this</b> + * + * @param names + * a Collection with one entry per name (or <code>null</code>) + * + * @exception IOException + * if a parsing error occurs + * @exception UnsupportedOperationException + * because this method is not supported + * + * @see #getPathToNames() + */ + public void setPathToNames(Collection names) throws IOException + { + try + { + if (names == null || names.isEmpty()) + { + pathToNames = null; + pathToNamesByte = null; + } + else + { + pathToNames = new HashSet(); + pathToNamesByte = new HashSet(); + Iterator iter = names.iterator(); + List item; + int type; + Object data; + + while (iter.hasNext()) + { + item = (List)iter.next(); + type = ((Integer)item.get(0)).intValue(); + data = item.get(1); + if (data instanceof String) + { + addPathToName(type, (String)data); + } + else if (data instanceof byte[]) + { + addPathToName(type, (byte[])data); + } + else + { + throw new IOException( + "parsing error: unknown data type"); + } + } + } + } + catch (Exception ex) + { + throw new IOException("parsing exception:\n" + ex.toString()); + } + } + + /** + * Adds a name to the pathToNames criterion. The + * <code>X509Certificate</code> must not include name constraints that + * would prohibit building a path to the specified name.<br /> + * <br /> + * This method allows the caller to add a name to the set of names which the + * <code>X509Certificates</code>'s name constraints must permit. The + * specified name is added to any previous value for the pathToNames + * criterion. If the name is a duplicate, it may be ignored.<br /> + * <br /> + * The name is provided in string format. RFC 822, DNS, and URI names use + * the well-established string formats for those types (subject to the + * restrictions included in RFC 2459). IPv4 address names are supplied using + * dotted quad notation. OID address names are represented as a series of + * nonnegative integers separated by periods. And directory names + * (distinguished names) are supplied in RFC 2253 format. No standard string + * format is defined for otherNames, X.400 names, EDI party names, IPv6 + * address names, or any other type of names. They should be specified using + * the + * {@link #addPathToName(int, byte[]) addPathToName(int type, byte [] name)} + * method.<br /> + * <br /> + * <b>TODO: implement this match check for this</b> + * + * @param type + * the name type (0-8, as specified in RFC 2459, section 4.2.1.7) + * @param name + * the name in string form + * + * @exceptrion IOException if a parsing error occurs + */ + public void addPathToName(int type, String name) throws IOException + { + // TODO full implementation of CertUtil.parseGeneralName + byte[] encoded = CertUtil.parseGeneralName(type, name); + List tmpList = new ArrayList(); + tmpList.add(Integers.valueOf(type)); + tmpList.add(name); + pathToNames.add(tmpList); + tmpList.set(1, encoded); + pathToNamesByte.add(tmpList); + throw new UnsupportedOperationException(); + } + + /** + * Adds a name to the pathToNames criterion. The + * <code>X509Certificate</code> must not include name constraints that + * would prohibit building a path to the specified name.<br /> + * <br /> + * This method allows the caller to add a name to the set of names which the + * <code>X509Certificates</code>'s name constraints must permit. The + * specified name is added to any previous value for the pathToNames + * criterion. If the name is a duplicate, it may be ignored.<br /> + * <br /> + * The name is provided as a byte array. This byte array should contain the + * DER encoded name, as it would appear in the GeneralName structure defined + * in RFC 2459 and X.509. The ASN.1 definition of this structure appears in + * the documentation for + * {@link #addSubjectAlternativeName(int,byte[]) addSubjectAlternativeName(int type, byte[] name)}.<br /> + * <br /> + * Note that the byte array supplied here is cloned to protect against + * subsequent modifications.<br /> + * <br /> + * <b>TODO: implement this match check for this</b> + * + * @param type + * the name type (0-8, as specified in RFC 2459, section 4.2.1.7) + * @param name + * a byte array containing the name in ASN.1 DER encoded form + * + * @exception IOException + * if a parsing error occurs + */ + public void addPathToName(int type, byte[] name) throws IOException + { + // TODO check encoded format + List tmpList = new ArrayList(); + tmpList.add(Integers.valueOf(type)); + tmpList.add(name.clone()); + pathToNames.add(tmpList); + pathToNamesByte.add(tmpList); + } + + /** + * Returns the certificateEquals criterion. The specified + * <code>X509Certificate</code> must be equal to the + * <code>X509Certificate</code> passed to the match method. If + * <code>null</code>, this check is not applied. + * + * @retrun the <code>X509Certificate</code> to match (or <code>null</code>) + * + * @see #setCertificate(java.security.cert.X509Certificate) + */ + public X509Certificate getCertificate() + { + return x509Cert; + } + + /** + * Returns the serialNumber criterion. The specified serial number must + * match the certificate serial number in the <code>X509Certificate</code>. + * If <code>null</code>, any certificate serial number will do. + * + * @return the certificate serial number to match (or <code>null</code>) + * + * @see #setSerialNumber(java.math.BigInteger) + */ + public BigInteger getSerialNumber() + { + return serialNumber; + } + + /** + * Returns the issuer criterion as a String. This distinguished name must + * match the issuer distinguished name in the <code>X509Certificate</code>. + * If <code>null</code>, the issuer criterion is disabled and any issuer + * distinguished name will do.<br /> + * <br /> + * If the value returned is not <code>null</code>, it is a distinguished + * name, in RFC 2253 format.<br /> + * <br /> + * Uses {@link org.spongycastle.asn1.x509.X509Name X509Name} for formatiing + * byte[] issuerDN to String. + * + * @return the required issuer distinguished name in RFC 2253 format (or + * <code>null</code>) + */ + public String getIssuerAsString() + { + if (issuerDN instanceof String) + { + return new String((String)issuerDN); + } + else if (issuerDNX509 != null) + { + return issuerDNX509.toString(); + } + + return null; + } + + /** + * Returns the issuer criterion as a byte array. This distinguished name + * must match the issuer distinguished name in the + * <code>X509Certificate</code>. If <code>null</code>, the issuer + * criterion is disabled and any issuer distinguished name will do.<br /> + * <br /> + * If the value returned is not <code>null</code>, it is a byte array + * containing a single DER encoded distinguished name, as defined in X.501. + * The ASN.1 notation for this structure is supplied in the documentation + * for {@link #setIssuer(byte[]) setIssuer(byte [] issuerDN)}.<br /> + * <br /> + * Note that the byte array returned is cloned to protect against subsequent + * modifications.<br /> + * <br /> + * Uses {@link org.spongycastle.asn1.DEROutputStream DEROutputStream}, + * {@link org.spongycastle.asn1.x509.X509Name X509Name} to gnerate byte[] + * output for String issuerDN. + * + * @return a byte array containing the required issuer distinguished name in + * ASN.1 DER format (or <code>null</code>) + * + * @exception IOException + * if an encoding error occurs + */ + public byte[] getIssuerAsBytes() throws IOException + { + if (issuerDN instanceof byte[]) + { + return (byte[])((byte[])issuerDN).clone(); + } + else if (issuerDNX509 != null) + { + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + DEROutputStream derOutStream = new DEROutputStream(outStream); + + derOutStream.writeObject(issuerDNX509.toASN1Primitive()); + derOutStream.close(); + + return outStream.toByteArray(); + } + + return null; + } + + /** + * Returns the subject criterion as a String. This distinguished name must + * match the subject distinguished name in the <code>X509Certificate</code>. + * If <code>null</code>, the subject criterion is disabled and any + * subject distinguished name will do.<br /> + * <br /> + * If the value returned is not <code>null</code>, it is a distinguished + * name, in RFC 2253 format.<br /> + * <br /> + * Uses {@link org.spongycastle.asn1.x509.X509Name X509Name} for formatiing + * byte[] subjectDN to String. + * + * @return the required subject distinguished name in RFC 2253 format (or + * <code>null</code>) + */ + public String getSubjectAsString() + { + if (subjectDN instanceof String) + { + return new String((String)subjectDN); + } + else if (subjectDNX509 != null) + { + return subjectDNX509.toString(); + } + + return null; + } + + /** + * Returns the subject criterion as a byte array. This distinguished name + * must match the subject distinguished name in the + * <code>X509Certificate</code>. If <code>null</code>, the subject + * criterion is disabled and any subject distinguished name will do.<br /> + * <br /> + * If the value returned is not <code>null</code>, it is a byte array + * containing a single DER encoded distinguished name, as defined in X.501. + * The ASN.1 notation for this structure is supplied in the documentation + * for {@link #setSubject(byte [] subjectDN) setSubject(byte [] subjectDN)}.<br /> + * <br /> + * Note that the byte array returned is cloned to protect against subsequent + * modifications.<br /> + * <br /> + * Uses {@link org.spongycastle.asn1.DEROutputStream DEROutputStream}, + * {@link org.spongycastle.asn1.x509.X509Name X509Name} to gnerate byte[] + * output for String subjectDN. + * + * @return a byte array containing the required subject distinguished name + * in ASN.1 DER format (or <code>null</code>) + * + * @exception IOException + * if an encoding error occurs + */ + public byte[] getSubjectAsBytes() throws IOException + { + if (subjectDN instanceof byte[]) + { + return (byte[])((byte[])subjectDN).clone(); + } + else if (subjectDNX509 != null) + { + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + DEROutputStream derOutStream = new DEROutputStream(outStream); + + derOutStream.writeObject(subjectDNX509.toASN1Primitive()); + derOutStream.close(); + + return outStream.toByteArray(); + } + + return null; + } + + /** + * Returns the subjectKeyIdentifier criterion. The + * <code>X509Certificate</code> must contain a SubjectKeyIdentifier + * extension with the specified value. If <code>null</code>, no + * subjectKeyIdentifier check will be done.<br /> + * <br /> + * Note that the byte array returned is cloned to protect against subsequent + * modifications. + * + * @return the key identifier (or <code>null</code>) + * + * @see #setSubjectKeyIdentifier + */ + public byte[] getSubjectKeyIdentifier() + { + if (subjectKeyID != null) + { + return (byte[])subjectKeyID.clone(); + } + + return null; + } + + /** + * Returns the authorityKeyIdentifier criterion. The + * <code>X509Certificate</code> must contain a AuthorityKeyIdentifier + * extension with the specified value. If <code>null</code>, no + * authorityKeyIdentifier check will be done.<br /> + * <br /> + * Note that the byte array returned is cloned to protect against subsequent + * modifications. + * + * @return the key identifier (or <code>null</code>) + * + * @see #setAuthorityKeyIdentifier + */ + public byte[] getAuthorityKeyIdentifier() + { + if (authorityKeyID != null) + { + return (byte[])authorityKeyID.clone(); + } + + return null; + } + + /** + * Returns the certificateValid criterion. The specified date must fall + * within the certificate validity period for the + * <code>X509Certificate</code>. If <code>null</code>, no + * certificateValid check will be done.<br /> + * <br /> + * Note that the <code>Date</code> returned is cloned to protect against + * subsequent modifications. + * + * @return the <code>Date</code> to check (or <code>null</code>) + * + * @see #setCertificateValid + */ + public Date getCertificateValid() + { + if (certValid != null) + { + return new Date(certValid.getTime()); + } + + return null; + } + + /** + * Returns the privateKeyValid criterion. The specified date must fall + * within the private key validity period for the + * <code>X509Certificate</code>. If <code>null</code>, no + * privateKeyValid check will be done.<br /> + * <br /> + * Note that the <code>Date</code> returned is cloned to protect against + * subsequent modifications. + * + * @return the <code>Date</code> to check (or <code>null</code>) + * + * @see #setPrivateKeyValid + */ + public Date getPrivateKeyValid() + { + if (privateKeyValid != null) + { + return new Date(privateKeyValid.getTime()); + } + + return null; + } + + /** + * Returns the subjectPublicKeyAlgID criterion. The + * <code>X509Certificate</code> must contain a subject public key with the + * specified algorithm. If <code>null</code>, no subjectPublicKeyAlgID + * check will be done. + * + * @return the object identifier (OID) of the signature algorithm to check + * for (or <code>null</code>). An OID is represented by a set of + * nonnegative integers separated by periods. + * + * @see #setSubjectPublicKeyAlgID + */ + public String getSubjectPublicKeyAlgID() + { + if (subjectKeyAlgID != null) + { + return subjectKeyAlgID.toString(); + } + + return null; + } + + /** + * Returns the subjectPublicKey criterion. The <code>X509Certificate</code> + * must contain the specified subject public key. If <code>null</code>, + * no subjectPublicKey check will be done. + * + * @return the subject public key to check for (or <code>null</code>) + * + * @see #setSubjectPublicKey + */ + public PublicKey getSubjectPublicKey() + { + return subjectPublicKey; + } + + /** + * Returns the keyUsage criterion. The <code>X509Certificate</code> must + * allow the specified keyUsage values. If null, no keyUsage check will be + * done.<br /> + * <br /> + * Note that the boolean array returned is cloned to protect against + * subsequent modifications. + * + * @return a boolean array in the same format as the boolean array returned + * by + * {@link X509Certificate#getKeyUsage() X509Certificate.getKeyUsage()}. + * Or <code>null</code>. + * + * @see #setKeyUsage + */ + public boolean[] getKeyUsage() + { + if (keyUsage != null) + { + return (boolean[])keyUsage.clone(); + } + + return null; + } + + /** + * Returns the extendedKeyUsage criterion. The <code>X509Certificate</code> + * must allow the specified key purposes in its extended key usage + * extension. If the <code>keyPurposeSet</code> returned is empty or + * <code>null</code>, no extendedKeyUsage check will be done. Note that + * an <code>X509Certificate</code> that has no extendedKeyUsage extension + * implicitly allows all key purposes. + * + * @return an immutable <code>Set</code> of key purpose OIDs in string + * format (or <code>null</code>) + * @see #setExtendedKeyUsage + */ + public Set getExtendedKeyUsage() + { + if (keyPurposeSet == null || keyPurposeSet.isEmpty()) + { + return keyPurposeSet; + } + + Set returnSet = new HashSet(); + Iterator iter = keyPurposeSet.iterator(); + while (iter.hasNext()) + { + returnSet.add(iter.next().toString()); + } + + return Collections.unmodifiableSet(returnSet); + } + + /** + * Indicates if the <code>X509Certificate</code> must contain all or at + * least one of the subjectAlternativeNames specified in the + * {@link #setSubjectAlternativeNames setSubjectAlternativeNames} or + * {@link #addSubjectAlternativeName addSubjectAlternativeName} methods. If + * <code>true</code>, the <code>X509Certificate</code> must contain all + * of the specified subject alternative names. If <code>false</code>, the + * <code>X509Certificate</code> must contain at least one of the specified + * subject alternative names. + * + * @return <code>true</code> if the flag is enabled; <code>false</code> + * if the flag is disabled. The flag is <code>true</code> by + * default. + * + * @see #setMatchAllSubjectAltNames + */ + public boolean getMatchAllSubjectAltNames() + { + return matchAllSubjectAltNames; + } + + /** + * Returns a copy of the subjectAlternativeNames criterion. The + * <code>X509Certificate</code> must contain all or at least one of the + * specified subjectAlternativeNames, depending on the value of the + * matchAllNames flag (see {@link #getMatchAllSubjectAltNames + * getMatchAllSubjectAltNames}). If the value returned is <code>null</code>, + * no subjectAlternativeNames check will be performed.<br /> + * <br /> + * If the value returned is not <code>null</code>, it is a + * <code>Collection</code> with one entry for each name to be included in + * the subject alternative name criterion. Each entry is a <code>List</code> + * whose first entry is an <code>Integer</code> (the name type, 0-8) and + * whose second entry is a <code>String</code> or a byte array (the name, + * in string or ASN.1 DER encoded form, respectively). There can be multiple + * names of the same type. Note that the <code>Collection</code> returned + * may contain duplicate names (same name and name type).<br /> + * <br /> + * Each subject alternative name in the <code>Collection</code> may be + * specified either as a <code>String</code> or as an ASN.1 encoded byte + * array. For more details about the formats used, see + * {@link #addSubjectAlternativeName(int type, String name) + * addSubjectAlternativeName(int type, String name)} and + * {@link #addSubjectAlternativeName(int type, byte [] name) + * addSubjectAlternativeName(int type, byte [] name)}.<br /> + * <br /> + * Note that a deep copy is performed on the <code>Collection</code> to + * protect against subsequent modifications. + * + * @return a <code>Collection</code> of names (or <code>null</code>) + * + * @see #setSubjectAlternativeNames + */ + public Collection getSubjectAlternativeNames() + { + if (subjectAltNames != null) + { + return null; + } + + Set returnAltNames = new HashSet(); + List returnList; + Iterator iter = subjectAltNames.iterator(); + List obj; + while (iter.hasNext()) + { + obj = (List)iter.next(); + returnList = new ArrayList(); + returnList.add(obj.get(0)); + if (obj.get(1) instanceof byte[]) + { + returnList.add(((byte[])obj.get(1)).clone()); + } + else + { + returnList.add(obj.get(1)); + } + returnAltNames.add(returnList); + } + + return returnAltNames; + } + + /** + * Returns the name constraints criterion. The <code>X509Certificate</code> + * must have subject and subject alternative names that meet the specified + * name constraints.<br /> + * <br /> + * The name constraints are returned as a byte array. This byte array + * contains the DER encoded form of the name constraints, as they would + * appear in the NameConstraints structure defined in RFC 2459 and X.509. + * The ASN.1 notation for this structure is supplied in the documentation + * for + * {@link #setNameConstraints(byte [] bytes) setNameConstraints(byte [] bytes)}.<br /> + * <br /> + * Note that the byte array returned is cloned to protect against subsequent + * modifications.<br /> + * <br /> + * <b>TODO: implement this</b> + * + * @return a byte array containing the ASN.1 DER encoding of a + * NameConstraints extension used for checking name constraints. + * <code>null</code> if no name constraints check will be + * performed. + * + * @exception UnsupportedOperationException + * because this method is not supported + * + * @see #setNameConstraints + */ + public byte[] getNameConstraints() + { + throw new UnsupportedOperationException(); + } + + /** + * Returns the basic constraints constraint. If the value is greater than or + * equal to zero, the <code>X509Certificates</code> must include a + * basicConstraints extension with a pathLen of at least this value. If the + * value is -2, only end-entity certificates are accepted. If the value is + * -1, no basicConstraints check is done. + * + * @return the value for the basic constraints constraint + * + * @see #setBasicConstraints + */ + public int getBasicConstraints() + { + return minMaxPathLen; + } + + /** + * Returns the policy criterion. The <code>X509Certificate</code> must + * include at least one of the specified policies in its certificate + * policies extension. If the <code>Set</code> returned is empty, then the + * <code>X509Certificate</code> must include at least some specified + * policy in its certificate policies extension. If the <code>Set</code> + * returned is <code>null</code>, no policy check will be performed. + * + * @return an immutable <code>Set</code> of certificate policy OIDs in + * string format (or <code>null</code>) + * + * @see #setPolicy + */ + public Set getPolicy() + { + if (policy == null) + { + return null; + } + + return Collections.unmodifiableSet(policy); + } + + /** + * Returns a copy of the pathToNames criterion. The + * <code>X509Certificate</code> must not include name constraints that + * would prohibit building a path to the specified names. If the value + * returned is <code>null</code>, no pathToNames check will be performed.<br /> + * <br /> + * If the value returned is not <code>null</code>, it is a + * <code>Collection</code> with one entry for each name to be included in + * the pathToNames criterion. Each entry is a <code>List</code> whose + * first entry is an <code>Integer</code> (the name type, 0-8) and whose + * second entry is a <code>String</code> or a byte array (the name, in + * string or ASN.1 DER encoded form, respectively). There can be multiple + * names of the same type. Note that the <code>Collection</code> returned + * may contain duplicate names (same name and name type).<br /> + * <br /> + * Each name in the <code>Collection</code> may be specified either as a + * <code>String</code> or as an ASN.1 encoded byte array. For more details + * about the formats used, see {@link #addPathToName(int type, String name) + * addPathToName(int type, String name)} and + * {@link #addPathToName(int type, byte [] name) addPathToName(int type, + * byte [] name)}.<br /> + * <br /> + * Note that a deep copy is performed on the <code>Collection</code> to + * protect against subsequent modifications. + * + * @return a <code>Collection</code> of names (or <code>null</code>) + * + * @see #setPathToNames + */ + public Collection getPathToNames() + { + if (pathToNames == null) + { + return null; + } + + Set returnPathToNames = new HashSet(); + List returnList; + Iterator iter = pathToNames.iterator(); + List obj; + + while (iter.hasNext()) + { + obj = (List)iter.next(); + returnList = new ArrayList(); + returnList.add(obj.get(0)); + if (obj.get(1) instanceof byte[]) + { + returnList.add(((byte[])obj.get(1)).clone()); + } + else + { + returnList.add(obj.get(1)); + } + returnPathToNames.add(returnList); + } + + return returnPathToNames; + } + + /** + * Return a printable representation of the <code>CertSelector</code>.<br /> + * <br /> + * <b>TODO: implement output for currently unsupported options(name + * constraints)</b><br /> + * <br /> + * Uses {@link org.spongycastle.asn1.ASN1InputStream ASN1InputStream}, + * {@link org.spongycastle.asn1.ASN1Object ASN1Object}, + * {@link org.spongycastle.asn1.x509.KeyPurposeId KeyPurposeId} + * + * @return a <code>String</code> describing the contents of the + * <code>CertSelector</code> + */ + public String toString() + { + StringBuffer sb = new StringBuffer(); + sb.append("X509CertSelector: [\n"); + if (x509Cert != null) + { + sb.append(" Certificate: ").append(x509Cert).append('\n'); + } + if (serialNumber != null) + { + sb.append(" Serial Number: ").append(serialNumber).append('\n'); + } + if (issuerDN != null) + { + sb.append(" Issuer: ").append(getIssuerAsString()).append('\n'); + } + if (subjectDN != null) + { + sb.append(" Subject: ").append(getSubjectAsString()).append('\n'); + } + try + { + if (subjectKeyID != null) + { + ByteArrayInputStream inStream = new ByteArrayInputStream( + subjectKeyID); + ASN1InputStream derInStream = new ASN1InputStream(inStream); + ASN1Object derObject = derInStream.readObject(); + sb.append(" Subject Key Identifier: ") + .append(ASN1Dump.dumpAsString(derObject)).append('\n'); + } + if (authorityKeyID != null) + { + ByteArrayInputStream inStream = new ByteArrayInputStream( + authorityKeyID); + ASN1InputStream derInStream = new ASN1InputStream(inStream); + ASN1Object derObject = derInStream.readObject(); + sb.append(" Authority Key Identifier: ") + .append(ASN1Dump.dumpAsString(derObject)).append('\n'); + } + } + catch (IOException ex) + { + sb.append(ex.getMessage()).append('\n'); + } + if (certValid != null) + { + sb.append(" Certificate Valid: ").append(certValid).append('\n'); + } + if (privateKeyValid != null) + { + sb.append(" Private Key Valid: ").append(privateKeyValid) + .append('\n'); + } + if (subjectKeyAlgID != null) + { + sb.append(" Subject Public Key AlgID: ") + .append(subjectKeyAlgID).append('\n'); + } + if (subjectPublicKey != null) + { + sb.append(" Subject Public Key: ").append(subjectPublicKey) + .append('\n'); + } + if (keyUsage != null) + { + sb.append(" Key Usage: ").append(keyUsage).append('\n'); + } + if (keyPurposeSet != null) + { + sb.append(" Extended Key Usage: ").append(keyPurposeSet) + .append('\n'); + } + if (policy != null) + { + sb.append(" Policy: ").append(policy).append('\n'); + } + sb.append(" matchAllSubjectAltNames flag: ") + .append(matchAllSubjectAltNames).append('\n'); + if (subjectAltNamesByte != null) + { + sb.append(" SubjectAlternativNames: \n["); + Iterator iter = subjectAltNamesByte.iterator(); + List obj; + try + { + while (iter.hasNext()) + { + obj = (List)iter.next(); + ByteArrayInputStream inStream = new ByteArrayInputStream( + (byte[])obj.get(1)); + ASN1InputStream derInStream = new ASN1InputStream(inStream); + ASN1Object derObject = derInStream.readObject(); + sb.append(" Type: ").append(obj.get(0)).append(" Data: ") + .append(ASN1Dump.dumpAsString(derObject)).append('\n'); + } + } + catch (IOException ex) + { + sb.append(ex.getMessage()).append('\n'); + } + sb.append("]\n"); + } + if (pathToNamesByte != null) + { + sb.append(" PathToNamesNames: \n["); + Iterator iter = pathToNamesByte.iterator(); + List obj; + try + { + while (iter.hasNext()) + { + obj = (List)iter.next(); + ByteArrayInputStream inStream = new ByteArrayInputStream( + (byte[])obj.get(1)); + ASN1InputStream derInStream = new ASN1InputStream(inStream); + ASN1Object derObject = derInStream.readObject(); + sb.append(" Type: ").append(obj.get(0)).append(" Data: ") + .append(ASN1Dump.dumpAsString(derObject)).append('\n'); + } + } + catch (IOException ex) + { + sb.append(ex.getMessage()).append('\n'); + } + sb.append("]\n"); + } + sb.append(']'); + return sb.toString(); + } + + /** + * Decides whether a <code>Certificate</code> should be selected.<br /> + * <br /> + * <b>TODO: implement missing tests (name constraints and path to names)</b><br /> + * <br /> + * Uses {@link org.spongycastle.asn1.ASN1InputStream ASN1InputStream}, + * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence}, + * {@link org.spongycastle.asn1.ASN1ObjectIdentifier ASN1ObjectIdentifier}, + * {@link org.spongycastle.asn1.ASN1Object ASN1Object}, + * {@link org.spongycastle.asn1.DERGeneralizedTime DERGeneralizedTime}, + * {@link org.spongycastle.asn1.x509.X509Name X509Name}, + * {@link org.spongycastle.asn1.x509.X509Extensions X509Extensions}, + * {@link org.spongycastle.asn1.x509.ExtendedKeyUsage ExtendedKeyUsage}, + * {@link org.spongycastle.asn1.x509.KeyPurposeId KeyPurposeId}, + * {@link org.spongycastle.asn1.x509.SubjectPublicKeyInfo SubjectPublicKeyInfo}, + * {@link org.spongycastle.asn1.x509.AlgorithmIdentifier AlgorithmIdentifier} + * to access X509 extensions + * + * @param cert + * the <code>Certificate</code> to be checked + * + * @return <code>true</code> if the <code>Certificate</code> should be + * selected, <code>false</code> otherwise + */ + public boolean match(Certificate cert) + { + boolean[] booleanArray; + List tempList; + Iterator tempIter; + + if (!(cert instanceof X509Certificate)) + { + return false; + } + X509Certificate certX509 = (X509Certificate)cert; + + if (x509Cert != null && !x509Cert.equals(certX509)) + { + return false; + } + if (serialNumber != null + && !serialNumber.equals(certX509.getSerialNumber())) + { + return false; + } + try + { + if (issuerDNX509 != null) + { + if (!issuerDNX509.equals(PrincipalUtil + .getIssuerX509Principal(certX509), true)) + { + return false; + } + } + if (subjectDNX509 != null) + { + if (!subjectDNX509.equals(PrincipalUtil + .getSubjectX509Principal(certX509), true)) + { + return false; + } + } + } + catch (Exception ex) + { + return false; + } + if (subjectKeyID != null) + { + byte[] data = certX509 + .getExtensionValue(X509Extensions.SubjectKeyIdentifier + .getId()); + if (data == null) + { + return false; + } + try + { + ByteArrayInputStream inStream = new ByteArrayInputStream(data); + ASN1InputStream derInputStream = new ASN1InputStream(inStream); + byte[] testData = ((ASN1OctetString)derInputStream.readObject()) + .getOctets(); + if (!Arrays.equals(subjectKeyID, testData)) + { + return false; + } + } + catch (IOException ex) + { + return false; + } + } + if (authorityKeyID != null) + { + byte[] data = certX509 + .getExtensionValue(X509Extensions.AuthorityKeyIdentifier + .getId()); + if (data == null) + { + return false; + } + try + { + ByteArrayInputStream inStream = new ByteArrayInputStream(data); + ASN1InputStream derInputStream = new ASN1InputStream(inStream); + byte[] testData = ((ASN1OctetString)derInputStream.readObject()) + .getOctets(); + if (!Arrays.equals(authorityKeyID, testData)) + { + return false; + } + } + catch (IOException ex) + { + return false; + } + } + if (certValid != null) + { + if (certX509.getNotAfter() != null + && certValid.after(certX509.getNotAfter())) + { + return false; + } + if (certX509.getNotBefore() != null + && certValid.before(certX509.getNotBefore())) + { + return false; + } + } + if (privateKeyValid != null) + { + try + { + byte[] data = certX509 + .getExtensionValue(X509Extensions.PrivateKeyUsagePeriod + .getId()); + if (data != null) + { + ByteArrayInputStream inStream = new ByteArrayInputStream( + data); + ASN1InputStream derInputStream = new ASN1InputStream(inStream); + inStream = new ByteArrayInputStream( + ((ASN1OctetString)derInputStream.readObject()) + .getOctets()); + derInputStream = new ASN1InputStream(inStream); + // TODO fix this, Sequence contains tagged objects + ASN1Sequence derObject = (ASN1Sequence)derInputStream + .readObject(); + ASN1GeneralizedTime derDate = ASN1GeneralizedTime + .getInstance(derObject.getObjectAt(0)); + SimpleDateFormat dateF = new SimpleDateFormat( + "yyyyMMddHHmmssZ"); + if (privateKeyValid.before(dateF.parse(derDate.getTime()))) + { + return false; + } + derDate = ASN1GeneralizedTime.getInstance(derObject + .getObjectAt(1)); + if (privateKeyValid.after(dateF.parse(derDate.getTime()))) + { + return false; + } + } + } + catch (Exception ex) + { + return false; + } + } + if (subjectKeyAlgID != null) + { + try + { + ByteArrayInputStream inStream = new ByteArrayInputStream( + certX509.getPublicKey().getEncoded()); + ASN1InputStream derInputStream = new ASN1InputStream(inStream); + SubjectPublicKeyInfo publicKeyInfo = new SubjectPublicKeyInfo( + (ASN1Sequence)derInputStream.readObject()); + AlgorithmIdentifier algInfo = publicKeyInfo.getAlgorithmId(); + if (!algInfo.getObjectId().equals(subjectKeyAlgID)) + { + return false; + } + } + catch (Exception ex) + { + return false; + } + } + if (subjectPublicKeyByte != null) + { + if (!Arrays.equals(subjectPublicKeyByte, certX509.getPublicKey() + .getEncoded())) + { + return false; + } + } + if (subjectPublicKey != null) + { + if (!subjectPublicKey.equals(certX509.getPublicKey())) + { + return false; + } + } + if (keyUsage != null) + { + booleanArray = certX509.getKeyUsage(); + if (booleanArray != null) + { + for (int i = 0; i < keyUsage.length; i++) + { + if (keyUsage[i] + && (booleanArray.length <= i || !booleanArray[i])) + { + return false; + } + } + } + } + if (keyPurposeSet != null && !keyPurposeSet.isEmpty()) + { + try + { + byte[] data = certX509 + .getExtensionValue(X509Extensions.ExtendedKeyUsage + .getId()); + if (data != null) + { + ByteArrayInputStream inStream = new ByteArrayInputStream( + data); + ASN1InputStream derInputStream = new ASN1InputStream(inStream); + ExtendedKeyUsage extendedKeyUsage = ExtendedKeyUsage.getInstance( + derInputStream.readObject()); + tempIter = keyPurposeSet.iterator(); + while (tempIter.hasNext()) + { + if (!extendedKeyUsage + .hasKeyPurposeId((KeyPurposeId)tempIter.next())) + { + return false; + } + } + } + } + catch (Exception ex) + { + return false; + } + } + if (minMaxPathLen != -1) + { + if (minMaxPathLen == -2 && certX509.getBasicConstraints() != -1) + { + return false; + } + if (minMaxPathLen >= 0 + && certX509.getBasicConstraints() < minMaxPathLen) + { + return false; + } + } + if (policyOID != null) + { + try + { + byte[] data = certX509 + .getExtensionValue(X509Extensions.CertificatePolicies + .getId()); + if (data == null) + { + return false; + } + if (!policyOID.isEmpty()) + { + ByteArrayInputStream inStream = new ByteArrayInputStream( + data); + ASN1InputStream derInputStream = new ASN1InputStream(inStream); + inStream = new ByteArrayInputStream( + ((ASN1OctetString)derInputStream.readObject()) + .getOctets()); + derInputStream = new ASN1InputStream(inStream); + Enumeration policySequence = ((ASN1Sequence)derInputStream + .readObject()).getObjects(); + ASN1Sequence policyObject; + boolean test = false; + while (policySequence.hasMoreElements() && !test) + { + policyObject = (ASN1Sequence)policySequence + .nextElement(); + if (policyOID.contains(policyObject.getObjectAt(0))) + { + test = true; + } + } + if (!test) + { + return false; + } + } + } + catch (Exception ex) + { + ex.printStackTrace(); + return false; + } + } + if (subjectAltNamesByte != null) + { + try + { + byte[] data = certX509 + .getExtensionValue(X509Extensions.SubjectAlternativeName + .getId()); + if (data == null) + { + return false; + } + ByteArrayInputStream inStream = new ByteArrayInputStream(data); + ASN1InputStream derInputStream = new ASN1InputStream(inStream); + inStream = new ByteArrayInputStream( + ((ASN1OctetString)derInputStream.readObject()) + .getOctets()); + derInputStream = new ASN1InputStream(inStream); + Enumeration altNamesSequence = ((ASN1Sequence)derInputStream + .readObject()).getObjects(); + ASN1TaggedObject altNameObject; + boolean test = false; + Set testSet = new HashSet(subjectAltNamesByte); + List testList; + ASN1Object derData; + ByteArrayOutputStream outStream; + DEROutputStream derOutStream; + while (altNamesSequence.hasMoreElements() && !test) + { + altNameObject = (ASN1TaggedObject)altNamesSequence + .nextElement(); + testList = new ArrayList(2); + testList.add(Integers.valueOf(altNameObject.getTagNo())); + derData = altNameObject.getObject(); + outStream = new ByteArrayOutputStream(); + derOutStream = new DEROutputStream(outStream); + derOutStream.writeObject(derData); + derOutStream.close(); + testList.add(outStream.toByteArray()); + + if (testSet.remove(testList)) + { + test = true; + } + + if (matchAllSubjectAltNames && !testSet.isEmpty()) + { + test = false; + } + } + if (!test) + { + return false; + } + } + catch (Exception ex) + { + ex.printStackTrace(); + return false; + } + } + + return true; + } + + /** + * Returns a copy of this object. + * + * @return the copy + */ + public Object clone() + { + try + { + X509CertSelector copy = (X509CertSelector)super.clone(); + if (issuerDN instanceof byte[]) + { + copy.issuerDN = ((byte[])issuerDN).clone(); + } + if (subjectDN instanceof byte[]) + { + copy.subjectDN = ((byte[])subjectDN).clone(); + } + if (subjectKeyID != null) + { + copy.subjectKeyID = (byte[])subjectKeyID.clone(); + } + if (authorityKeyID != null) + { + copy.authorityKeyID = (byte[])authorityKeyID.clone(); + } + if (subjectPublicKeyByte != null) + { + copy.subjectPublicKeyByte = (byte[])subjectPublicKeyByte + .clone(); + } + if (keyUsage != null) + { + copy.keyUsage = (boolean[])keyUsage.clone(); + } + if (keyPurposeSet != null) + { + copy.keyPurposeSet = new HashSet(keyPurposeSet); + } + if (policy != null) + { + copy.policy = new HashSet(policy); + copy.policyOID = new HashSet(); + Iterator iter = policyOID.iterator(); + while (iter.hasNext()) + { + copy.policyOID.add(new ASN1ObjectIdentifier( + ((ASN1ObjectIdentifier)iter.next()).getId())); + } + } + if (subjectAltNames != null) + { + copy.subjectAltNames = new HashSet(getSubjectAlternativeNames()); + Iterator iter = subjectAltNamesByte.iterator(); + List obj; + List cloneObj; + while (iter.hasNext()) + { + obj = (List)iter.next(); + cloneObj = new ArrayList(); + cloneObj.add(obj.get(0)); + cloneObj.add(((byte[])obj.get(1)).clone()); + copy.subjectAltNamesByte.add(cloneObj); + } + } + if (pathToNames != null) + { + copy.pathToNames = new HashSet(getPathToNames()); + Iterator iter = pathToNamesByte.iterator(); + List obj; + List cloneObj; + while (iter.hasNext()) + { + obj = (List)iter.next(); + cloneObj = new ArrayList(); + cloneObj.add(obj.get(0)); + cloneObj.add(((byte[])obj.get(1)).clone()); + copy.pathToNamesByte.add(cloneObj); + } + } + return copy; + } + catch (CloneNotSupportedException e) + { + /* Cannot happen */ + throw new InternalError(e.toString()); + } + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509Extension.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509Extension.java new file mode 100644 index 00000000..f2c7e199 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509Extension.java @@ -0,0 +1,12 @@ + +package org.spongycastle.jce.cert; + +import java.util.Set; + +public interface X509Extension +{ + public abstract Set getCriticalExtensionOIDs(); + public abstract byte[] getExtensionValue(String oid); + public abstract Set getNonCriticalExtensionOIDs(); + public abstract boolean hasUnsupportedCriticalExtension(); +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/package.html b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/package.html new file mode 100644 index 00000000..c5cd3f6a --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/package.html @@ -0,0 +1,5 @@ +<html> +<body bgcolor="#ffffff"> +Compatibility API for the JDK 1.4 CertPath API. +</body> +</html> diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/exception/ExtCertPathBuilderException.java b/prov/src/main/jdk1.3/org/spongycastle/jce/exception/ExtCertPathBuilderException.java new file mode 100644 index 00000000..b238580f --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/exception/ExtCertPathBuilderException.java @@ -0,0 +1,29 @@ +package org.spongycastle.jce.exception; + +import org.spongycastle.jce.cert.CertPath; +import org.spongycastle.jce.cert.CertPathBuilderException; + +public class ExtCertPathBuilderException + extends CertPathBuilderException + implements ExtException +{ + private Throwable cause; + + public ExtCertPathBuilderException(String message, Throwable cause) + { + super(message); + this.cause = cause; + } + + public ExtCertPathBuilderException(String msg, Throwable cause, + CertPath certPath, int index) + { + super(msg, cause); + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/exception/ExtCertPathValidatorException.java b/prov/src/main/jdk1.3/org/spongycastle/jce/exception/ExtCertPathValidatorException.java new file mode 100644 index 00000000..ec2b667d --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/exception/ExtCertPathValidatorException.java @@ -0,0 +1,30 @@ +package org.spongycastle.jce.exception; + +import org.spongycastle.jce.cert.CertPath; +import org.spongycastle.jce.cert.CertPathValidatorException; + +public class ExtCertPathValidatorException + extends CertPathValidatorException + implements ExtException +{ + + private Throwable cause; + + public ExtCertPathValidatorException(String message, Throwable cause) + { + super(message); + this.cause = cause; + } + + public ExtCertPathValidatorException(String msg, Throwable cause, + CertPath certPath, int index) + { + super(msg, cause, certPath, index); + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/CertPathValidatorUtilities.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/CertPathValidatorUtilities.java new file mode 100644 index 00000000..40bf81da --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/CertPathValidatorUtilities.java @@ -0,0 +1,1417 @@ +package org.spongycastle.jce.provider; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.cert.CRLException; +import org.spongycastle.jce.cert.CertPath; +import org.spongycastle.jce.cert.CertPathValidatorException; +import org.spongycastle.jce.cert.CertStore; +import org.spongycastle.jce.cert.CertStoreException; +import java.security.cert.Certificate; +import java.security.cert.CertificateParsingException; +import org.spongycastle.jce.cert.PKIXParameters; +import org.spongycastle.jce.cert.PolicyQualifierInfo; +import org.spongycastle.jce.cert.TrustAnchor; +import java.security.cert.X509CRL; +import java.security.cert.X509CRLEntry; +import org.spongycastle.jce.cert.X509CRLSelector; +import org.spongycastle.jce.cert.X509CertSelector; +import java.security.cert.X509Certificate; +import java.security.interfaces.DSAParams; +import java.security.interfaces.DSAPublicKey; +import java.security.spec.DSAPublicKeySpec; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1OutputStream; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.ASN1Enumerated; +import org.spongycastle.asn1.ASN1GeneralizedTime; +import org.spongycastle.asn1.DERIA5String; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.isismtt.ISISMTTObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.CRLDistPoint; +import org.spongycastle.asn1.x509.CRLReason; +import org.spongycastle.asn1.x509.CertificateList; +import org.spongycastle.asn1.x509.DistributionPoint; +import org.spongycastle.asn1.x509.DistributionPointName; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.asn1.x509.GeneralNames; +import org.spongycastle.asn1.x509.PolicyInformation; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.asn1.x509.X509Extension; +import org.spongycastle.asn1.x509.X509Extensions; +import org.spongycastle.jce.exception.ExtCertPathValidatorException; +import org.spongycastle.jce.X509Principal; +import org.spongycastle.jce.PrincipalUtil; +import org.spongycastle.util.Selector; +import org.spongycastle.util.StoreException; +import org.spongycastle.x509.ExtendedPKIXBuilderParameters; +import org.spongycastle.x509.ExtendedPKIXParameters; +import org.spongycastle.x509.X509AttributeCertStoreSelector; +import org.spongycastle.x509.X509AttributeCertificate; +import org.spongycastle.x509.X509CRLStoreSelector; +import org.spongycastle.x509.X509CertStoreSelector; +import org.spongycastle.x509.X509Store; + +public class CertPathValidatorUtilities +{ + protected static final PKIXCRLUtil CRL_UTIL = new PKIXCRLUtil(); + + protected static final String CERTIFICATE_POLICIES = X509Extensions.CertificatePolicies.getId(); + protected static final String BASIC_CONSTRAINTS = X509Extensions.BasicConstraints.getId(); + protected static final String POLICY_MAPPINGS = X509Extensions.PolicyMappings.getId(); + protected static final String SUBJECT_ALTERNATIVE_NAME = X509Extensions.SubjectAlternativeName.getId(); + protected static final String NAME_CONSTRAINTS = X509Extensions.NameConstraints.getId(); + protected static final String KEY_USAGE = X509Extensions.KeyUsage.getId(); + protected static final String INHIBIT_ANY_POLICY = X509Extensions.InhibitAnyPolicy.getId(); + protected static final String ISSUING_DISTRIBUTION_POINT = X509Extensions.IssuingDistributionPoint.getId(); + protected static final String DELTA_CRL_INDICATOR = X509Extensions.DeltaCRLIndicator.getId(); + protected static final String POLICY_CONSTRAINTS = X509Extensions.PolicyConstraints.getId(); + protected static final String FRESHEST_CRL = X509Extensions.FreshestCRL.getId(); + protected static final String CRL_DISTRIBUTION_POINTS = X509Extensions.CRLDistributionPoints.getId(); + protected static final String AUTHORITY_KEY_IDENTIFIER = X509Extensions.AuthorityKeyIdentifier.getId(); + + protected static final String ANY_POLICY = "2.5.29.32.0"; + + protected static final String CRL_NUMBER = X509Extensions.CRLNumber.getId(); + + /* + * key usage bits + */ + protected static final int KEY_CERT_SIGN = 5; + protected static final int CRL_SIGN = 6; + + protected static final String[] crlReasons = new String[]{ + "unspecified", + "keyCompromise", + "cACompromise", + "affiliationChanged", + "superseded", + "cessationOfOperation", + "certificateHold", + "unknown", + "removeFromCRL", + "privilegeWithdrawn", + "aACompromise"}; + + /** + * Search the given Set of TrustAnchor's for one that is the + * issuer of the given X509 certificate. Uses the default provider + * for signature verification. + * + * @param cert the X509 certificate + * @param trustAnchors a Set of TrustAnchor's + * @return the <code>TrustAnchor</code> object if found or + * <code>null</code> if not. + * @throws AnnotatedException if a TrustAnchor was found but the signature verification + * on the given certificate has thrown an exception. + */ + protected static TrustAnchor findTrustAnchor( + X509Certificate cert, + Set trustAnchors) + throws AnnotatedException + { + return findTrustAnchor(cert, trustAnchors, null); + } + + /** + * Search the given Set of TrustAnchor's for one that is the + * issuer of the given X509 certificate. Uses the specified + * provider for signature verification, or the default provider + * if null. + * + * @param cert the X509 certificate + * @param trustAnchors a Set of TrustAnchor's + * @param sigProvider the provider to use for signature verification + * @return the <code>TrustAnchor</code> object if found or + * <code>null</code> if not. + * @throws AnnotatedException if a TrustAnchor was found but the signature verification + * on the given certificate has thrown an exception. + */ + protected static TrustAnchor findTrustAnchor( + X509Certificate cert, + Set trustAnchors, + String sigProvider) + throws AnnotatedException + { + TrustAnchor trust = null; + PublicKey trustPublicKey = null; + Exception invalidKeyEx = null; + + X509CertSelector certSelectX509 = new X509CertSelector(); + X509Principal certIssuer = getEncodedIssuerPrincipal(cert); + + try + { + certSelectX509.setSubject(certIssuer.getEncoded()); + } + catch (IOException ex) + { + throw new AnnotatedException("Cannot set subject search criteria for trust anchor.", ex); + } + + Iterator iter = trustAnchors.iterator(); + while (iter.hasNext() && trust == null) + { + trust = (TrustAnchor)iter.next(); + if (trust.getTrustedCert() != null) + { + if (certSelectX509.match(trust.getTrustedCert())) + { + trustPublicKey = trust.getTrustedCert().getPublicKey(); + } + else + { + trust = null; + } + } + else if (trust.getCAName() != null + && trust.getCAPublicKey() != null) + { + try + { + X509Principal caName = new X509Principal(trust.getCAName()); + if (certIssuer.equals(caName)) + { + trustPublicKey = trust.getCAPublicKey(); + } + else + { + trust = null; + } + } + catch (IllegalArgumentException ex) + { + trust = null; + } + } + else + { + trust = null; + } + + if (trustPublicKey != null) + { + try + { + verifyX509Certificate(cert, trustPublicKey, sigProvider); + } + catch (Exception ex) + { + invalidKeyEx = ex; + trust = null; + trustPublicKey = null; + } + } + } + + if (trust == null && invalidKeyEx != null) + { + throw new AnnotatedException("TrustAnchor found but certificate validation failed.", invalidKeyEx); + } + + return trust; + } + + protected static void addAdditionalStoresFromAltNames( + X509Certificate cert, + ExtendedPKIXParameters pkixParams) + throws CertificateParsingException + { + // if in the IssuerAltName extension an URI + // is given, add an additinal X.509 store +/* + if (cert.getIssuerAlternativeNames() != null) + { + Iterator it = cert.getIssuerAlternativeNames().iterator(); + while (it.hasNext()) + { + // look for URI + List list = (List)it.next(); + if (list.get(0).equals(new Integer(GeneralName.uniformResourceIdentifier))) + { + // found + String temp = (String)list.get(1); + CertPathValidatorUtilities.addAdditionalStoreFromLocation(temp, pkixParams); + } + } + } +*/ + } + + /** + * Returns the issuer of an attribute certificate or certificate. + * + * @param cert The attribute certificate or certificate. + * @return The issuer as <code>X509Principal</code>. + */ + protected static X509Principal getEncodedIssuerPrincipal( + Object cert) + { + if (cert instanceof X509Certificate) + { +try +{ + return PrincipalUtil.getIssuerX509Principal((X509Certificate)cert); +} +catch (Exception e) +{ +throw new IllegalStateException(e.toString()); +} + } + else + { + return (X509Principal)((X509AttributeCertificate)cert).getIssuer().getPrincipals()[0]; + } + } + + protected static Date getValidDate(PKIXParameters paramsPKIX) + { + Date validDate = paramsPKIX.getDate(); + + if (validDate == null) + { + validDate = new Date(); + } + + return validDate; + } + + protected static X509Principal getSubjectPrincipal(X509Certificate cert) + { +try +{ + return PrincipalUtil.getSubjectX509Principal(cert); +} +catch (Exception e) +{ +throw new IllegalStateException(e.toString()); +} + } + + protected static boolean isSelfIssued(X509Certificate cert) + { + return cert.getSubjectDN().equals(cert.getIssuerDN()); + } + + + /** + * Extract the value of the given extension, if it exists. + * + * @param ext The extension object. + * @param oid The object identifier to obtain. + * @throws AnnotatedException if the extension cannot be read. + */ + protected static ASN1Primitive getExtensionValue( + java.security.cert.X509Extension ext, + String oid) + throws AnnotatedException + { + byte[] bytes = ext.getExtensionValue(oid); + if (bytes == null) + { + return null; + } + + return getObject(oid, bytes); + } + + private static ASN1Primitive getObject( + String oid, + byte[] ext) + throws AnnotatedException + { + try + { + ASN1InputStream aIn = new ASN1InputStream(ext); + ASN1OctetString octs = (ASN1OctetString)aIn.readObject(); + + aIn = new ASN1InputStream(octs.getOctets()); + return aIn.readObject(); + } + catch (Exception e) + { + throw new AnnotatedException("exception processing extension " + oid, e); + } + } + + protected static X509Principal getIssuerPrincipal(X509CRL crl) + { +try +{ + return PrincipalUtil.getIssuerX509Principal(crl); +} +catch (Exception e) +{ + throw new IllegalStateException(e.toString()); +} + } + + protected static AlgorithmIdentifier getAlgorithmIdentifier( + PublicKey key) + throws CertPathValidatorException + { + try + { + ASN1InputStream aIn = new ASN1InputStream(key.getEncoded()); + + SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(aIn.readObject()); + + return info.getAlgorithmId(); + } + catch (Exception e) + { + throw new ExtCertPathValidatorException("Subject public key cannot be decoded.", e); + } + } + + // crl checking + + + // + // policy checking + // + + protected static final Set getQualifierSet(ASN1Sequence qualifiers) + throws CertPathValidatorException + { + Set pq = new HashSet(); + + if (qualifiers == null) + { + return pq; + } + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ASN1OutputStream aOut = new ASN1OutputStream(bOut); + + Enumeration e = qualifiers.getObjects(); + + while (e.hasMoreElements()) + { + try + { + aOut.writeObject((ASN1Encodable)e.nextElement()); + + pq.add(new PolicyQualifierInfo(bOut.toByteArray())); + } + catch (IOException ex) + { + throw new ExtCertPathValidatorException("Policy qualifier info cannot be decoded.", ex); + } + + bOut.reset(); + } + + return pq; + } + + protected static PKIXPolicyNode removePolicyNode( + PKIXPolicyNode validPolicyTree, + List[] policyNodes, + PKIXPolicyNode _node) + { + PKIXPolicyNode _parent = (PKIXPolicyNode)_node.getParent(); + + if (validPolicyTree == null) + { + return null; + } + + if (_parent == null) + { + for (int j = 0; j < policyNodes.length; j++) + { + policyNodes[j] = new ArrayList(); + } + + return null; + } + else + { + _parent.removeChild(_node); + removePolicyNodeRecurse(policyNodes, _node); + + return validPolicyTree; + } + } + + private static void removePolicyNodeRecurse( + List[] policyNodes, + PKIXPolicyNode _node) + { + policyNodes[_node.getDepth()].remove(_node); + + if (_node.hasChildren()) + { + Iterator _iter = _node.getChildren(); + while (_iter.hasNext()) + { + PKIXPolicyNode _child = (PKIXPolicyNode)_iter.next(); + removePolicyNodeRecurse(policyNodes, _child); + } + } + } + + + protected static boolean processCertD1i( + int index, + List[] policyNodes, + ASN1ObjectIdentifier pOid, + Set pq) + { + List policyNodeVec = policyNodes[index - 1]; + + for (int j = 0; j < policyNodeVec.size(); j++) + { + PKIXPolicyNode node = (PKIXPolicyNode)policyNodeVec.get(j); + Set expectedPolicies = node.getExpectedPolicies(); + + if (expectedPolicies.contains(pOid.getId())) + { + Set childExpectedPolicies = new HashSet(); + childExpectedPolicies.add(pOid.getId()); + + PKIXPolicyNode child = new PKIXPolicyNode(new ArrayList(), + index, + childExpectedPolicies, + node, + pq, + pOid.getId(), + false); + node.addChild(child); + policyNodes[index].add(child); + + return true; + } + } + + return false; + } + + protected static void processCertD1ii( + int index, + List[] policyNodes, + ASN1ObjectIdentifier _poid, + Set _pq) + { + List policyNodeVec = policyNodes[index - 1]; + + for (int j = 0; j < policyNodeVec.size(); j++) + { + PKIXPolicyNode _node = (PKIXPolicyNode)policyNodeVec.get(j); + + if (ANY_POLICY.equals(_node.getValidPolicy())) + { + Set _childExpectedPolicies = new HashSet(); + _childExpectedPolicies.add(_poid.getId()); + + PKIXPolicyNode _child = new PKIXPolicyNode(new ArrayList(), + index, + _childExpectedPolicies, + _node, + _pq, + _poid.getId(), + false); + _node.addChild(_child); + policyNodes[index].add(_child); + return; + } + } + } + + protected static void prepareNextCertB1( + int i, + List[] policyNodes, + String id_p, + Map m_idp, + X509Certificate cert + ) + throws AnnotatedException, CertPathValidatorException + { + boolean idp_found = false; + Iterator nodes_i = policyNodes[i].iterator(); + while (nodes_i.hasNext()) + { + PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next(); + if (node.getValidPolicy().equals(id_p)) + { + idp_found = true; + node.expectedPolicies = (Set)m_idp.get(id_p); + break; + } + } + + if (!idp_found) + { + nodes_i = policyNodes[i].iterator(); + while (nodes_i.hasNext()) + { + PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next(); + if (ANY_POLICY.equals(node.getValidPolicy())) + { + Set pq = null; + ASN1Sequence policies = null; + try + { + policies = DERSequence.getInstance(getExtensionValue(cert, CERTIFICATE_POLICIES)); + } + catch (Exception e) + { + throw new AnnotatedException("Certificate policies cannot be decoded.", e); + } + Enumeration e = policies.getObjects(); + while (e.hasMoreElements()) + { + PolicyInformation pinfo = null; + + try + { + pinfo = PolicyInformation.getInstance(e.nextElement()); + } + catch (Exception ex) + { + throw new AnnotatedException("Policy information cannot be decoded.", ex); + } + if (ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId())) + { + try + { + pq = getQualifierSet(pinfo.getPolicyQualifiers()); + } + catch (CertPathValidatorException ex) + { + throw new ExtCertPathValidatorException( + "Policy qualifier info set could not be built.", ex); + } + break; + } + } + boolean ci = false; + if (cert.getCriticalExtensionOIDs() != null) + { + ci = cert.getCriticalExtensionOIDs().contains(CERTIFICATE_POLICIES); + } + + PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent(); + if (ANY_POLICY.equals(p_node.getValidPolicy())) + { + PKIXPolicyNode c_node = new PKIXPolicyNode( + new ArrayList(), i, + (Set)m_idp.get(id_p), + p_node, pq, id_p, ci); + p_node.addChild(c_node); + policyNodes[i].add(c_node); + } + break; + } + } + } + } + + protected static PKIXPolicyNode prepareNextCertB2( + int i, + List[] policyNodes, + String id_p, + PKIXPolicyNode validPolicyTree) + { + Iterator nodes_i = policyNodes[i].iterator(); + while (nodes_i.hasNext()) + { + PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next(); + if (node.getValidPolicy().equals(id_p)) + { + PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent(); + p_node.removeChild(node); + nodes_i.remove(); + for (int k = (i - 1); k >= 0; k--) + { + List nodes = policyNodes[k]; + for (int l = 0; l < nodes.size(); l++) + { + PKIXPolicyNode node2 = (PKIXPolicyNode)nodes.get(l); + if (!node2.hasChildren()) + { + validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, node2); + if (validPolicyTree == null) + { + break; + } + } + } + } + } + } + return validPolicyTree; + } + + protected static boolean isAnyPolicy( + Set policySet) + { + return policySet == null || policySet.contains(ANY_POLICY) || policySet.isEmpty(); + } + + protected static void addAdditionalStoreFromLocation(String location, + ExtendedPKIXParameters pkixParams) + { + } + + /** + * Return a Collection of all certificates or attribute certificates found + * in the X509Store's that are matching the certSelect criteriums. + * + * @param certSelect a {@link Selector} object that will be used to select + * the certificates + * @param certStores a List containing only {@link X509Store} objects. These + * are used to search for certificates. + * @return a Collection of all found {@link X509Certificate} or + * {@link org.spongycastle.x509.X509AttributeCertificate} objects. + * May be empty but never <code>null</code>. + */ + protected static Collection findCertificates(X509CertStoreSelector certSelect, + List certStores) + throws AnnotatedException + { + Set certs = new HashSet(); + Iterator iter = certStores.iterator(); + + while (iter.hasNext()) + { + Object obj = iter.next(); + + if (obj instanceof X509Store) + { + X509Store certStore = (X509Store)obj; + try + { + certs.addAll(certStore.getMatches(certSelect)); + } + catch (StoreException e) + { + throw new AnnotatedException( + "Problem while picking certificates from X.509 store.", e); + } + } + else + { + CertStore certStore = (CertStore)obj; + + try + { + certs.addAll(certStore.getCertificates(certSelect)); + } + catch (CertStoreException e) + { + throw new AnnotatedException( + "Problem while picking certificates from certificate store.", + e); + } + } + } + return certs; + } + + protected static Collection findCertificates(X509AttributeCertStoreSelector certSelect, + List certStores) + throws AnnotatedException + { + Set certs = new HashSet(); + Iterator iter = certStores.iterator(); + + while (iter.hasNext()) + { + Object obj = iter.next(); + + if (obj instanceof X509Store) + { + X509Store certStore = (X509Store)obj; + try + { + certs.addAll(certStore.getMatches(certSelect)); + } + catch (StoreException e) + { + throw new AnnotatedException( + "Problem while picking certificates from X.509 store.", e); + } + } + } + return certs; + } + + protected static void addAdditionalStoresFromCRLDistributionPoint( + CRLDistPoint crldp, ExtendedPKIXParameters pkixParams) + throws AnnotatedException + { + if (crldp != null) + { + DistributionPoint dps[] = null; + try + { + dps = crldp.getDistributionPoints(); + } + catch (Exception e) + { + throw new AnnotatedException( + "Distribution points could not be read.", e); + } + for (int i = 0; i < dps.length; i++) + { + DistributionPointName dpn = dps[i].getDistributionPoint(); + // look for URIs in fullName + if (dpn != null) + { + if (dpn.getType() == DistributionPointName.FULL_NAME) + { + GeneralName[] genNames = GeneralNames.getInstance( + dpn.getName()).getNames(); + // look for an URI + for (int j = 0; j < genNames.length; j++) + { + if (genNames[j].getTagNo() == GeneralName.uniformResourceIdentifier) + { + String location = DERIA5String.getInstance( + genNames[j].getName()).getString(); + CertPathValidatorUtilities + .addAdditionalStoreFromLocation(location, + pkixParams); + } + } + } + } + } + } + } + + /** + * Add the CRL issuers from the cRLIssuer field of the distribution point or + * from the certificate if not given to the issuer criterion of the + * <code>selector</code>. + * <p/> + * The <code>issuerPrincipals</code> are a collection with a single + * <code>X509Principal</code> for <code>X509Certificate</code>s. For + * {@link X509AttributeCertificate}s the issuer may contain more than one + * <code>X509Principal</code>. + * + * @param dp The distribution point. + * @param issuerPrincipals The issuers of the certificate or attribute + * certificate which contains the distribution point. + * @param selector The CRL selector. + * @param pkixParams The PKIX parameters containing the cert stores. + * @throws AnnotatedException if an exception occurs while processing. + * @throws ClassCastException if <code>issuerPrincipals</code> does not + * contain only <code>X509Principal</code>s. + */ + protected static void getCRLIssuersFromDistributionPoint( + DistributionPoint dp, + Collection issuerPrincipals, + X509CRLSelector selector, + ExtendedPKIXParameters pkixParams) + throws AnnotatedException + { + List issuers = new ArrayList(); + // indirect CRL + if (dp.getCRLIssuer() != null) + { + GeneralName genNames[] = dp.getCRLIssuer().getNames(); + // look for a DN + for (int j = 0; j < genNames.length; j++) + { + if (genNames[j].getTagNo() == GeneralName.directoryName) + { + try + { + issuers.add(new X509Principal(genNames[j].getName() + .toASN1Primitive().getEncoded())); + } + catch (IOException e) + { + throw new AnnotatedException( + "CRL issuer information from distribution point cannot be decoded.", + e); + } + } + } + } + else + { + /* + * certificate issuer is CRL issuer, distributionPoint field MUST be + * present. + */ + if (dp.getDistributionPoint() == null) + { + throw new AnnotatedException( + "CRL issuer is omitted from distribution point but no distributionPoint field present."); + } + // add and check issuer principals + for (Iterator it = issuerPrincipals.iterator(); it.hasNext(); ) + { + issuers.add((X509Principal)it.next()); + } + } + // TODO: is not found although this should correctly add the rel name. selector of Sun is buggy here or PKI test case is invalid + // distributionPoint +// if (dp.getDistributionPoint() != null) +// { +// // look for nameRelativeToCRLIssuer +// if (dp.getDistributionPoint().getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER) +// { +// // append fragment to issuer, only one +// // issuer can be there, if this is given +// if (issuers.size() != 1) +// { +// throw new AnnotatedException( +// "nameRelativeToCRLIssuer field is given but more than one CRL issuer is given."); +// } +// ASN1Encodable relName = dp.getDistributionPoint().getName(); +// Iterator it = issuers.iterator(); +// List issuersTemp = new ArrayList(issuers.size()); +// while (it.hasNext()) +// { +// Enumeration e = null; +// try +// { +// e = ASN1Sequence.getInstance( +// new ASN1InputStream(((X500Principal) it.next()) +// .getEncoded()).readObject()).getObjects(); +// } +// catch (IOException ex) +// { +// throw new AnnotatedException( +// "Cannot decode CRL issuer information.", ex); +// } +// ASN1EncodableVector v = new ASN1EncodableVector(); +// while (e.hasMoreElements()) +// { +// v.add((ASN1Encodable) e.nextElement()); +// } +// v.add(relName); +// issuersTemp.add(new X500Principal(new DERSequence(v) +// .getDEREncoded())); +// } +// issuers.clear(); +// issuers.addAll(issuersTemp); +// } +// } + Iterator it = issuers.iterator(); + while (it.hasNext()) + { + try + { + selector.addIssuerName(((X509Principal)it.next()).getEncoded()); + } + catch (IOException ex) + { + throw new AnnotatedException( + "Cannot decode CRL issuer information.", ex); + } + } + } + + private static BigInteger getSerialNumber( + Object cert) + { + if (cert instanceof X509Certificate) + { + return ((X509Certificate)cert).getSerialNumber(); + } + else + { + return ((X509AttributeCertificate)cert).getSerialNumber(); + } + } + + protected static void getCertStatus( + Date validDate, + X509CRL crl, + Object cert, + CertStatus certStatus) + throws AnnotatedException + { + X509CRLEntry crl_entry = null; + + boolean isIndirect; + try + { + isIndirect = X509CRLObject.isIndirectCRL(crl); + } + catch (CRLException exception) + { + throw new AnnotatedException("Failed check for indirect CRL.", exception); + } + + if (isIndirect) + { + if (!(crl instanceof X509CRLObject)) + { + try + { + crl = new X509CRLObject(CertificateList.getInstance(crl.getEncoded())); + } + catch (CRLException exception) + { + throw new AnnotatedException("Failed to recode indirect CRL.", exception); + } + } + + crl_entry = crl.getRevokedCertificate(getSerialNumber(cert)); + + if (crl_entry == null) + { + return; + } + + X509Principal certIssuer = ((X509CRLEntryObject)crl_entry).getCertificateIssuer(); + + if (certIssuer == null) + { + certIssuer = getIssuerPrincipal(crl); + } + + if (!getEncodedIssuerPrincipal(cert).equals(certIssuer)) + { + return; + } + } + else if (!getEncodedIssuerPrincipal(cert).equals(getIssuerPrincipal(crl))) + { + return; // not for our issuer, ignore + } + else + { + crl_entry = crl.getRevokedCertificate(getSerialNumber(cert)); + + if (crl_entry == null) + { + return; + } + } + + ASN1Enumerated reasonCode = null; + if (crl_entry.hasExtensions()) + { + try + { + reasonCode = ASN1Enumerated + .getInstance(CertPathValidatorUtilities + .getExtensionValue(crl_entry, + X509Extension.reasonCode.getId())); + } + catch (Exception e) + { + throw new AnnotatedException( + "Reason code CRL entry extension could not be decoded.", + e); + } + } + + // for reason keyCompromise, caCompromise, aACompromise or + // unspecified + if (!(validDate.getTime() < crl_entry.getRevocationDate().getTime()) + || reasonCode == null + || reasonCode.getValue().intValue() == 0 + || reasonCode.getValue().intValue() == 1 + || reasonCode.getValue().intValue() == 2 + || reasonCode.getValue().intValue() == 8) + { + + // (i) or (j) (1) + if (reasonCode != null) + { + certStatus.setCertStatus(reasonCode.getValue().intValue()); + } + // (i) or (j) (2) + else + { + certStatus.setCertStatus(CRLReason.unspecified); + } + certStatus.setRevocationDate(crl_entry.getRevocationDate()); + } + } + + /** + * Fetches delta CRLs according to RFC 3280 section 5.2.4. + * + * @param currentDate The date for which the delta CRLs must be valid. + * @param paramsPKIX The extended PKIX parameters. + * @param completeCRL The complete CRL the delta CRL is for. + * @return A <code>Set</code> of <code>X509CRL</code>s with delta CRLs. + * @throws AnnotatedException if an exception occurs while picking the delta + * CRLs. + */ + protected static Set getDeltaCRLs(Date currentDate, + ExtendedPKIXParameters paramsPKIX, X509CRL completeCRL) + throws AnnotatedException + { + + X509CRLStoreSelector deltaSelect = new X509CRLStoreSelector(); + + // 5.2.4 (a) + try + { + deltaSelect.addIssuerName(CertPathValidatorUtilities + .getIssuerPrincipal(completeCRL).getEncoded()); + } + catch (IOException e) + { + throw new AnnotatedException("Cannot extract issuer from CRL.", e); + } + + BigInteger completeCRLNumber = null; + try + { + ASN1Primitive derObject = CertPathValidatorUtilities.getExtensionValue(completeCRL, + CRL_NUMBER); + if (derObject != null) + { + completeCRLNumber = ASN1Integer.getInstance(derObject).getPositiveValue(); + } + } + catch (Exception e) + { + throw new AnnotatedException( + "CRL number extension could not be extracted from CRL.", e); + } + + // 5.2.4 (b) + byte[] idp = null; + try + { + idp = completeCRL.getExtensionValue(ISSUING_DISTRIBUTION_POINT); + } + catch (Exception e) + { + throw new AnnotatedException( + "Issuing distribution point extension value could not be read.", + e); + } + + // 5.2.4 (d) + + deltaSelect.setMinCRLNumber(completeCRLNumber == null ? null : completeCRLNumber + .add(BigInteger.valueOf(1))); + + deltaSelect.setIssuingDistributionPoint(idp); + deltaSelect.setIssuingDistributionPointEnabled(true); + + // 5.2.4 (c) + deltaSelect.setMaxBaseCRLNumber(completeCRLNumber); + + // find delta CRLs + Set temp = CRL_UTIL.findCRLs(deltaSelect, paramsPKIX, currentDate); + + Set result = new HashSet(); + + for (Iterator it = temp.iterator(); it.hasNext(); ) + { + X509CRL crl = (X509CRL)it.next(); + + if (isDeltaCRL(crl)) + { + result.add(crl); + } + } + + return result; + } + + private static boolean isDeltaCRL(X509CRL crl) + { + Set critical = crl.getCriticalExtensionOIDs(); + + if (critical == null) + { + return false; + } + + return critical.contains(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR); + } + + /** + * Fetches complete CRLs according to RFC 3280. + * + * @param dp The distribution point for which the complete CRL + * @param cert The <code>X509Certificate</code> or + * {@link org.spongycastle.x509.X509AttributeCertificate} for + * which the CRL should be searched. + * @param currentDate The date for which the delta CRLs must be valid. + * @param paramsPKIX The extended PKIX parameters. + * @return A <code>Set</code> of <code>X509CRL</code>s with complete + * CRLs. + * @throws AnnotatedException if an exception occurs while picking the CRLs + * or no CRLs are found. + */ + protected static Set getCompleteCRLs(DistributionPoint dp, Object cert, + Date currentDate, ExtendedPKIXParameters paramsPKIX) + throws AnnotatedException + { + X509CRLStoreSelector crlselect = new X509CRLStoreSelector(); + try + { + Set issuers = new HashSet(); + if (cert instanceof X509AttributeCertificate) + { + issuers.add(((X509AttributeCertificate)cert) + .getIssuer().getPrincipals()[0]); + } + else + { + issuers.add(getEncodedIssuerPrincipal(cert)); + } + CertPathValidatorUtilities.getCRLIssuersFromDistributionPoint(dp, issuers, crlselect, paramsPKIX); + } + catch (AnnotatedException e) + { + throw new AnnotatedException( + "Could not get issuer information from distribution point.", e); + } + if (cert instanceof X509Certificate) + { + crlselect.setCertificateChecking((X509Certificate)cert); + } + else if (cert instanceof X509AttributeCertificate) + { + crlselect.setAttrCertificateChecking((X509AttributeCertificate)cert); + } + + + crlselect.setCompleteCRLEnabled(true); + + Set crls = CRL_UTIL.findCRLs(crlselect, paramsPKIX, currentDate); + + if (crls.isEmpty()) + { + if (cert instanceof X509AttributeCertificate) + { + X509AttributeCertificate aCert = (X509AttributeCertificate)cert; + + throw new AnnotatedException("No CRLs found for issuer \"" + aCert.getIssuer().getPrincipals()[0] + "\""); + } + else + { + X509Certificate xCert = (X509Certificate)cert; + + throw new AnnotatedException("No CRLs found for issuer \"" + xCert.getIssuerDN() + "\""); + } + } + return crls; + } + + protected static Date getValidCertDateFromValidityModel( + ExtendedPKIXParameters paramsPKIX, CertPath certPath, int index) + throws AnnotatedException + { + if (paramsPKIX.getValidityModel() == ExtendedPKIXParameters.CHAIN_VALIDITY_MODEL) + { + // if end cert use given signing/encryption/... time + if (index <= 0) + { + return CertPathValidatorUtilities.getValidDate(paramsPKIX); + // else use time when previous cert was created + } + else + { + if (index - 1 == 0) + { + ASN1GeneralizedTime dateOfCertgen = null; + try + { + byte[] extBytes = ((X509Certificate)certPath.getCertificates().get(index - 1)).getExtensionValue(ISISMTTObjectIdentifiers.id_isismtt_at_dateOfCertGen.getId()); + if (extBytes != null) + { + dateOfCertgen = ASN1GeneralizedTime.getInstance(ASN1Primitive.fromByteArray(extBytes)); + } + } + catch (IOException e) + { + throw new AnnotatedException( + "Date of cert gen extension could not be read."); + } + catch (IllegalArgumentException e) + { + throw new AnnotatedException( + "Date of cert gen extension could not be read."); + } + if (dateOfCertgen != null) + { + try + { + return dateOfCertgen.getDate(); + } + catch (ParseException e) + { + throw new AnnotatedException( + "Date from date of cert gen extension could not be parsed.", + e); + } + } + return ((X509Certificate)certPath.getCertificates().get( + index - 1)).getNotBefore(); + } + else + { + return ((X509Certificate)certPath.getCertificates().get( + index - 1)).getNotBefore(); + } + } + } + else + { + return getValidDate(paramsPKIX); + } + } + + /** + * Return the next working key inheriting DSA parameters if necessary. + * <p> + * This methods inherits DSA parameters from the indexed certificate or + * previous certificates in the certificate chain to the returned + * <code>PublicKey</code>. The list is searched upwards, meaning the end + * certificate is at position 0 and previous certificates are following. + * </p> + * <p> + * If the indexed certificate does not contain a DSA key this method simply + * returns the public key. If the DSA key already contains DSA parameters + * the key is also only returned. + * </p> + * + * @param certs The certification path. + * @param index The index of the certificate which contains the public key + * which should be extended with DSA parameters. + * @return The public key of the certificate in list position + * <code>index</code> extended with DSA parameters if applicable. + * @throws AnnotatedException if DSA parameters cannot be inherited. + */ + protected static PublicKey getNextWorkingKey(List certs, int index) + throws CertPathValidatorException + { + Certificate cert = (Certificate)certs.get(index); + PublicKey pubKey = cert.getPublicKey(); + if (!(pubKey instanceof DSAPublicKey)) + { + return pubKey; + } + DSAPublicKey dsaPubKey = (DSAPublicKey)pubKey; + if (dsaPubKey.getParams() != null) + { + return dsaPubKey; + } + for (int i = index + 1; i < certs.size(); i++) + { + X509Certificate parentCert = (X509Certificate)certs.get(i); + pubKey = parentCert.getPublicKey(); + if (!(pubKey instanceof DSAPublicKey)) + { + throw new CertPathValidatorException( + "DSA parameters cannot be inherited from previous certificate."); + } + DSAPublicKey prevDSAPubKey = (DSAPublicKey)pubKey; + if (prevDSAPubKey.getParams() == null) + { + continue; + } + DSAParams dsaParams = prevDSAPubKey.getParams(); + DSAPublicKeySpec dsaPubKeySpec = new DSAPublicKeySpec( + dsaPubKey.getY(), dsaParams.getP(), dsaParams.getQ(), dsaParams.getG()); + try + { + KeyFactory keyFactory = KeyFactory.getInstance("DSA", BouncyCastleProvider.PROVIDER_NAME); + return keyFactory.generatePublic(dsaPubKeySpec); + } + catch (Exception exception) + { + throw new RuntimeException(exception.getMessage()); + } + } + throw new CertPathValidatorException("DSA parameters cannot be inherited from previous certificate."); + } + + /** + * Find the issuer certificates of a given certificate. + * + * @param cert The certificate for which an issuer should be found. + * @param pkixParams + * @return A <code>Collection</code> object containing the issuer + * <code>X509Certificate</code>s. Never <code>null</code>. + * @throws AnnotatedException if an error occurs. + */ + protected static Collection findIssuerCerts( + X509Certificate cert, + ExtendedPKIXBuilderParameters pkixParams) + throws AnnotatedException + { + X509CertStoreSelector certSelect = new X509CertStoreSelector(); + Set certs = new HashSet(); + try + { + certSelect.setSubject(PrincipalUtil.getSubjectX509Principal(cert).getEncoded()); + } + catch (Exception ex) + { + throw new AnnotatedException( + "Subject criteria for certificate selector to find issuer certificate could not be set.", ex); + } + + Iterator iter; + + try + { + List matches = new ArrayList(); + + matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getCertStores())); + matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getStores())); + matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getAdditionalStores())); + + iter = matches.iterator(); + } + catch (AnnotatedException e) + { + throw new AnnotatedException("Issuer certificate cannot be searched.", e); + } + + X509Certificate issuer = null; + while (iter.hasNext()) + { + issuer = (X509Certificate)iter.next(); + // issuer cannot be verified because possible DSA inheritance + // parameters are missing + certs.add(issuer); + } + return certs; + } + + protected static void verifyX509Certificate(X509Certificate cert, PublicKey publicKey, + String sigProvider) + throws GeneralSecurityException + { + if (sigProvider == null) + { + cert.verify(publicKey); + } + else + { + cert.verify(publicKey, sigProvider); + } + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/CertStoreCollectionSpi.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/CertStoreCollectionSpi.java new file mode 100644 index 00000000..a894cf84 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/CertStoreCollectionSpi.java @@ -0,0 +1,104 @@ +package org.spongycastle.jce.provider; + +import java.security.InvalidAlgorithmParameterException; +import java.security.cert.CRL; +import org.spongycastle.jce.cert.CRLSelector; +import org.spongycastle.jce.cert.CertSelector; +import org.spongycastle.jce.cert.CertStoreException; +import org.spongycastle.jce.cert.CertStoreParameters; +import org.spongycastle.jce.cert.CertStoreSpi; +import java.security.cert.Certificate; +import org.spongycastle.jce.cert.CollectionCertStoreParameters; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +public class CertStoreCollectionSpi extends CertStoreSpi +{ + private CollectionCertStoreParameters params; + + public CertStoreCollectionSpi(CertStoreParameters params) + throws InvalidAlgorithmParameterException + { + super(params); + + if (!(params instanceof CollectionCertStoreParameters)) + { + throw new InvalidAlgorithmParameterException("org.spongycastle.jce.provider.CertStoreCollectionSpi: parameter must be a CollectionCertStoreParameters object\n" + params.toString()); + } + + this.params = (CollectionCertStoreParameters)params; + } + + public Collection engineGetCertificates( + CertSelector selector) + throws CertStoreException + { + List col = new ArrayList(); + Iterator iter = params.getCollection().iterator(); + + if (selector == null) + { + while (iter.hasNext()) + { + Object obj = iter.next(); + + if (obj instanceof Certificate) + { + col.add(obj); + } + } + } + else + { + while (iter.hasNext()) + { + Object obj = iter.next(); + + if ((obj instanceof Certificate) && selector.match((Certificate)obj)) + { + col.add(obj); + } + } + } + + return col; + } + + + public Collection engineGetCRLs( + CRLSelector selector) + throws CertStoreException + { + List col = new ArrayList(); + Iterator iter = params.getCollection().iterator(); + + if (selector == null) + { + while (iter.hasNext()) + { + Object obj = iter.next(); + + if (obj instanceof CRL) + { + col.add(obj); + } + } + } + else + { + while (iter.hasNext()) + { + Object obj = iter.next(); + + if ((obj instanceof CRL) && selector.match((CRL)obj)) + { + col.add(obj); + } + } + } + + return col; + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JCEPBEKey.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JCEPBEKey.java new file mode 100644 index 00000000..53c9d66e --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JCEPBEKey.java @@ -0,0 +1,146 @@ +package org.spongycastle.jce.provider; + +import javax.crypto.SecretKey; +import javax.crypto.spec.PBEKeySpec; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.PBEParametersGenerator; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.jcajce.provider.symmetric.util.PBE; + +public class JCEPBEKey + implements SecretKey +{ + String algorithm; + ASN1ObjectIdentifier oid; + int type; + int digest; + int keySize; + int ivSize; + CipherParameters param; + PBEKeySpec pbeKeySpec; + boolean tryWrong = false; + + /** + * @param param + */ + public JCEPBEKey( + String algorithm, + ASN1ObjectIdentifier oid, + int type, + int digest, + int keySize, + int ivSize, + PBEKeySpec pbeKeySpec, + CipherParameters param) + { + this.algorithm = algorithm; + this.oid = oid; + this.type = type; + this.digest = digest; + this.keySize = keySize; + this.ivSize = ivSize; + this.pbeKeySpec = pbeKeySpec; + this.param = param; + } + + public String getAlgorithm() + { + return algorithm; + } + + public String getFormat() + { + return "RAW"; + } + + public byte[] getEncoded() + { + if (param != null) + { + KeyParameter kParam; + + if (param instanceof ParametersWithIV) + { + kParam = (KeyParameter)((ParametersWithIV)param).getParameters(); + } + else + { + kParam = (KeyParameter)param; + } + + return kParam.getKey(); + } + else + { + if (type == PBE.PKCS12) + { + return PBEParametersGenerator.PKCS12PasswordToBytes(pbeKeySpec.getPassword()); + } + else + { + return PBEParametersGenerator.PKCS5PasswordToBytes(pbeKeySpec.getPassword()); + } + } + } + + int getType() + { + return type; + } + + int getDigest() + { + return digest; + } + + int getKeySize() + { + return keySize; + } + + int getIvSize() + { + return ivSize; + } + + CipherParameters getParam() + { + return param; + } + + /** + * these should never be called. + */ + int getIterationCount() + { + return 0; + } + + byte[] getSalt() + { + return null; + } + + /** + * Return the object identifier associated with this algorithm + * + * @return the oid for this PBE key + */ + public ASN1ObjectIdentifier getOID() + { + return oid; + } + + void setTryWrongPKCS12Zero(boolean tryWrong) + { + this.tryWrong = tryWrong; + } + + boolean shouldTryWrongPKCS12() + { + return tryWrong; + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JCESecretKeyFactory.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JCESecretKeyFactory.java new file mode 100644 index 00000000..b1c358b9 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JCESecretKeyFactory.java @@ -0,0 +1,557 @@ +package org.spongycastle.jce.provider; + +import java.lang.reflect.Constructor; +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.DESKeySpec; +import javax.crypto.spec.DESedeKeySpec; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.jcajce.provider.symmetric.util.BCPBEKey; +import org.spongycastle.jcajce.provider.symmetric.util.PBE; + +public class JCESecretKeyFactory + extends SecretKeyFactorySpi + implements PBE +{ + protected String algName; + protected ASN1ObjectIdentifier algOid; + + protected JCESecretKeyFactory( + String algName, + ASN1ObjectIdentifier algOid) + { + this.algName = algName; + this.algOid = algOid; + } + + protected SecretKey engineGenerateSecret( + KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof SecretKeySpec) + { + return (SecretKey)keySpec; + } + + throw new InvalidKeySpecException("Invalid KeySpec"); + } + + protected KeySpec engineGetKeySpec( + SecretKey key, + Class keySpec) + throws InvalidKeySpecException + { + if (keySpec == null) + { + throw new InvalidKeySpecException("keySpec parameter is null"); + } + if (key == null) + { + throw new InvalidKeySpecException("key parameter is null"); + } + + if (SecretKeySpec.class.isAssignableFrom(keySpec)) + { + return new SecretKeySpec(key.getEncoded(), algName); + } + + try + { + Class[] parameters = { byte[].class }; + + Constructor c = keySpec.getConstructor(parameters); + Object[] p = new Object[1]; + + p[0] = key.getEncoded(); + + return (KeySpec)c.newInstance(p); + } + catch (Exception e) + { + throw new InvalidKeySpecException(e.toString()); + } + } + + protected SecretKey engineTranslateKey( + SecretKey key) + throws InvalidKeyException + { + if (key == null) + { + throw new InvalidKeyException("key parameter is null"); + } + + if (!key.getAlgorithm().equalsIgnoreCase(algName)) + { + throw new InvalidKeyException("Key not of type " + algName + "."); + } + + return new SecretKeySpec(key.getEncoded(), algName); + } + + /* + * classes that inherit from us + */ + + static public class PBEKeyFactory + extends JCESecretKeyFactory + { + private boolean forCipher; + private int scheme; + private int digest; + private int keySize; + private int ivSize; + + public PBEKeyFactory( + String algorithm, + ASN1ObjectIdentifier oid, + boolean forCipher, + int scheme, + int digest, + int keySize, + int ivSize) + { + super(algorithm, oid); + + this.forCipher = forCipher; + this.scheme = scheme; + this.digest = digest; + this.keySize = keySize; + this.ivSize = ivSize; + } + + protected SecretKey engineGenerateSecret( + KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof PBEKeySpec) + { + PBEKeySpec pbeSpec = (PBEKeySpec)keySpec; + CipherParameters param; + + return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null); + } + + throw new InvalidKeySpecException("Invalid KeySpec"); + } + } + + static public class DESPBEKeyFactory + extends JCESecretKeyFactory + { + private boolean forCipher; + private int scheme; + private int digest; + private int keySize; + private int ivSize; + + public DESPBEKeyFactory( + String algorithm, + ASN1ObjectIdentifier oid, + boolean forCipher, + int scheme, + int digest, + int keySize, + int ivSize) + { + super(algorithm, oid); + + this.forCipher = forCipher; + this.scheme = scheme; + this.digest = digest; + this.keySize = keySize; + this.ivSize = ivSize; + } + + protected SecretKey engineGenerateSecret( + KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof PBEKeySpec) + { + PBEKeySpec pbeSpec = (PBEKeySpec)keySpec; + CipherParameters param; + + return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null); + } + + throw new InvalidKeySpecException("Invalid KeySpec"); + } + } + + static public class DES + extends JCESecretKeyFactory + { + public DES() + { + super("DES", null); + } + + protected SecretKey engineGenerateSecret( + KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof DESKeySpec) + { + DESKeySpec desKeySpec = (DESKeySpec)keySpec; + return new SecretKeySpec(desKeySpec.getKey(), "DES"); + } + + return super.engineGenerateSecret(keySpec); + } + } + + static public class DESede + extends JCESecretKeyFactory + { + public DESede() + { + super("DESede", null); + } + + protected KeySpec engineGetKeySpec( + SecretKey key, + Class keySpec) + throws InvalidKeySpecException + { + if (keySpec == null) + { + throw new InvalidKeySpecException("keySpec parameter is null"); + } + if (key == null) + { + throw new InvalidKeySpecException("key parameter is null"); + } + + if (SecretKeySpec.class.isAssignableFrom(keySpec)) + { + return new SecretKeySpec(key.getEncoded(), algName); + } + else if (DESedeKeySpec.class.isAssignableFrom(keySpec)) + { + byte[] bytes = key.getEncoded(); + + try + { + if (bytes.length == 16) + { + byte[] longKey = new byte[24]; + + System.arraycopy(bytes, 0, longKey, 0, 16); + System.arraycopy(bytes, 0, longKey, 16, 8); + + return new DESedeKeySpec(longKey); + } + else + { + return new DESedeKeySpec(bytes); + } + } + catch (Exception e) + { + throw new InvalidKeySpecException(e.toString()); + } + } + + throw new InvalidKeySpecException("Invalid KeySpec"); + } + + protected SecretKey engineGenerateSecret( + KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof DESedeKeySpec) + { + DESedeKeySpec desKeySpec = (DESedeKeySpec)keySpec; + return new SecretKeySpec(desKeySpec.getKey(), "DESede"); + } + + return super.engineGenerateSecret(keySpec); + } + } + + /** + * PBEWithMD5AndDES + */ + static public class PBEWithMD5AndDES + extends DESPBEKeyFactory + { + public PBEWithMD5AndDES() + { + super("PBEwithMD5andDES", null, true, PKCS5S1, MD5, 64, 64); + } + } + + /** + * PBEWithMD5AndRC2 + */ + static public class PBEWithMD5AndRC2 + extends PBEKeyFactory + { + public PBEWithMD5AndRC2() + { + super("PBEwithMD5andRC2", null, true, PKCS5S1, MD5, 64, 64); + } + } + + /** + * PBEWithSHA1AndDES + */ + static public class PBEWithSHA1AndDES + extends PBEKeyFactory + { + public PBEWithSHA1AndDES() + { + super("PBEwithSHA1andDES", null, true, PKCS5S1, SHA1, 64, 64); + } + } + + /** + * PBEWithSHA1AndRC2 + */ + static public class PBEWithSHA1AndRC2 + extends PBEKeyFactory + { + public PBEWithSHA1AndRC2() + { + super("PBEwithSHA1andRC2", null, true, PKCS5S1, SHA1, 64, 64); + } + } + + /** + * PBEWithSHAAnd3-KeyTripleDES-CBC + */ + static public class PBEWithSHAAndDES3Key + extends PBEKeyFactory + { + public PBEWithSHAAndDES3Key() + { + super("PBEwithSHAandDES3Key-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, true, PKCS12, SHA1, 192, 64); + } + } + + /** + * PBEWithSHAAnd2-KeyTripleDES-CBC + */ + static public class PBEWithSHAAndDES2Key + extends PBEKeyFactory + { + public PBEWithSHAAndDES2Key() + { + super("PBEwithSHAandDES2Key-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC, true, PKCS12, SHA1, 128, 64); + } + } + + /** + * PBEWithSHAAnd128BitRC2-CBC + */ + static public class PBEWithSHAAnd128BitRC2 + extends PBEKeyFactory + { + public PBEWithSHAAnd128BitRC2() + { + super("PBEwithSHAand128BitRC2-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC, true, PKCS12, SHA1, 128, 64); + } + } + + /** + * PBEWithSHAAnd40BitRC2-CBC + */ + static public class PBEWithSHAAnd40BitRC2 + extends PBEKeyFactory + { + public PBEWithSHAAnd40BitRC2() + { + super("PBEwithSHAand40BitRC2-CBC", PKCSObjectIdentifiers.pbewithSHAAnd40BitRC2_CBC, true, PKCS12, SHA1, 40, 64); + } + } + + /** + * PBEWithSHAAndTwofish-CBC + */ + static public class PBEWithSHAAndTwofish + extends PBEKeyFactory + { + public PBEWithSHAAndTwofish() + { + super("PBEwithSHAandTwofish-CBC", null, true, PKCS12, SHA1, 256, 128); + } + } + + /** + * PBEWithSHAAnd128BitRC4 + */ + static public class PBEWithSHAAnd128BitRC4 + extends PBEKeyFactory + { + public PBEWithSHAAnd128BitRC4() + { + super("PBEWithSHAAnd128BitRC4", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, true, PKCS12, SHA1, 128, 0); + } + } + + /** + * PBEWithSHAAnd40BitRC4 + */ + static public class PBEWithSHAAnd40BitRC4 + extends PBEKeyFactory + { + public PBEWithSHAAnd40BitRC4() + { + super("PBEWithSHAAnd128BitRC4", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, true, PKCS12, SHA1, 40, 0); + } + } + + /** + * PBEWithHmacRIPEMD160 + */ + public static class PBEWithRIPEMD160 + extends PBEKeyFactory + { + public PBEWithRIPEMD160() + { + super("PBEwithHmacRIPEMD160", null, false, PKCS12, RIPEMD160, 160, 0); + } + } + + /** + * PBEWithHmacSHA + */ + public static class PBEWithSHA + extends PBEKeyFactory + { + public PBEWithSHA() + { + super("PBEwithHmacSHA", null, false, PKCS12, SHA1, 160, 0); + } + } + + /** + * PBEWithHmacTiger + */ + public static class PBEWithTiger + extends PBEKeyFactory + { + public PBEWithTiger() + { + super("PBEwithHmacTiger", null, false, PKCS12, TIGER, 192, 0); + } + } + + /** + * PBEWithSHA1And128BitAES-BC + */ + static public class PBEWithSHAAnd128BitAESBC + extends PBEKeyFactory + { + public PBEWithSHAAnd128BitAESBC() + { + super("PBEWithSHA1And128BitAES-CBC-BC", null, true, PKCS12, SHA1, 128, 128); + } + } + + /** + * PBEWithSHA1And192BitAES-BC + */ + static public class PBEWithSHAAnd192BitAESBC + extends PBEKeyFactory + { + public PBEWithSHAAnd192BitAESBC() + { + super("PBEWithSHA1And192BitAES-CBC-BC", null, true, PKCS12, SHA1, 192, 128); + } + } + + /** + * PBEWithSHA1And256BitAES-BC + */ + static public class PBEWithSHAAnd256BitAESBC + extends PBEKeyFactory + { + public PBEWithSHAAnd256BitAESBC() + { + super("PBEWithSHA1And256BitAES-CBC-BC", null, true, PKCS12, SHA1, 256, 128); + } + } + + /** + * PBEWithSHA256And128BitAES-BC + */ + static public class PBEWithSHA256And128BitAESBC + extends PBEKeyFactory + { + public PBEWithSHA256And128BitAESBC() + { + super("PBEWithSHA256And128BitAES-CBC-BC", null, true, PKCS12, SHA256, 128, 128); + } + } + + /** + * PBEWithSHA256And192BitAES-BC + */ + static public class PBEWithSHA256And192BitAESBC + extends PBEKeyFactory + { + public PBEWithSHA256And192BitAESBC() + { + super("PBEWithSHA256And192BitAES-CBC-BC", null, true, PKCS12, SHA256, 192, 128); + } + } + + /** + * PBEWithSHA256And256BitAES-BC + */ + static public class PBEWithSHA256And256BitAESBC + extends PBEKeyFactory + { + public PBEWithSHA256And256BitAESBC() + { + super("PBEWithSHA256And256BitAES-CBC-BC", null, true, PKCS12, SHA256, 256, 128); + } + } + + /** + * PBEWithMD5And128BitAES-OpenSSL + */ + static public class PBEWithMD5And128BitAESCBCOpenSSL + extends PBEKeyFactory + { + public PBEWithMD5And128BitAESCBCOpenSSL() + { + super("PBEWithMD5And128BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 128, 128); + } + } + + /** + * PBEWithMD5And128BitAES-OpenSSL + */ + static public class PBEWithMD5And192BitAESCBCOpenSSL + extends PBEKeyFactory + { + public PBEWithMD5And192BitAESCBCOpenSSL() + { + super("PBEWithMD5And128BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 192, 128); + } + } + + /** + * PBEWithMD5And128BitAES-OpenSSL + */ + static public class PBEWithMD5And256BitAESCBCOpenSSL + extends PBEKeyFactory + { + public PBEWithMD5And256BitAESCBCOpenSSL() + { + super("PBEWithMD5And128BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 256, 128); + } + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JDKAlgorithmParameters.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JDKAlgorithmParameters.java new file mode 100644 index 00000000..9b33841f --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JDKAlgorithmParameters.java @@ -0,0 +1,643 @@ +package org.spongycastle.jce.provider; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.AlgorithmParametersSpi; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; + +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.PBEParameterSpec; +import javax.crypto.spec.RC2ParameterSpec; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.DEROutputStream; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.misc.CAST5CBCParameters; +import org.spongycastle.asn1.pkcs.PKCS12PBEParams; +import org.spongycastle.asn1.pkcs.RC2CBCParameter; +import org.spongycastle.jce.spec.IESParameterSpec; + +public abstract class JDKAlgorithmParameters + extends AlgorithmParametersSpi +{ + protected boolean isASN1FormatString(String format) + { + return format == null || format.equals("ASN.1"); + } + + protected AlgorithmParameterSpec engineGetParameterSpec( + Class paramSpec) + throws InvalidParameterSpecException + { + if (paramSpec == null) + { + throw new NullPointerException("argument to getParameterSpec must not be null"); + } + + return localEngineGetParameterSpec(paramSpec); + } + + protected abstract AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec) + throws InvalidParameterSpecException; + + public static class IVAlgorithmParameters + extends JDKAlgorithmParameters + { + private byte[] iv; + + protected byte[] engineGetEncoded() + throws IOException + { + return engineGetEncoded("ASN.1"); + } + + protected byte[] engineGetEncoded( + String format) + throws IOException + { + if (this.isASN1FormatString(format)) + { + return new DEROctetString(engineGetEncoded("RAW")).getEncoded(); + } + + if (format.equals("RAW")) + { + byte[] tmp = new byte[iv.length]; + + System.arraycopy(iv, 0, tmp, 0, iv.length); + return tmp; + } + + return null; + } + + protected AlgorithmParameterSpec localEngineGetParameterSpec( + Class paramSpec) + throws InvalidParameterSpecException + { + if (paramSpec == IvParameterSpec.class) + { + return new IvParameterSpec(iv); + } + + throw new InvalidParameterSpecException("unknown parameter spec passed to IV parameters object."); + } + + protected void engineInit( + AlgorithmParameterSpec paramSpec) + throws InvalidParameterSpecException + { + if (!(paramSpec instanceof IvParameterSpec)) + { + throw new InvalidParameterSpecException("IvParameterSpec required to initialise a IV parameters algorithm parameters object"); + } + + this.iv = ((IvParameterSpec)paramSpec).getIV(); + } + + protected void engineInit( + byte[] params) + throws IOException + { + // + // check that we don't have a DER encoded octet string + // + if ((params.length % 8) != 0 + && params[0] == 0x04 && params[1] == params.length - 2) + { + ASN1InputStream aIn = new ASN1InputStream(params); + ASN1OctetString oct = (ASN1OctetString)aIn.readObject(); + + params = oct.getOctets(); + } + + this.iv = new byte[params.length]; + + System.arraycopy(params, 0, iv, 0, iv.length); + } + + protected void engineInit( + byte[] params, + String format) + throws IOException + { + if (this.isASN1FormatString(format)) + { + ASN1InputStream aIn = new ASN1InputStream(params); + + try + { + ASN1OctetString oct = (ASN1OctetString)aIn.readObject(); + + engineInit(oct.getOctets()); + } + catch (Exception e) + { + throw new IOException("Exception decoding: " + e); + } + + return; + } + + if (format.equals("RAW")) + { + engineInit(params); + return; + } + + throw new IOException("Unknown parameters format in IV parameters object"); + } + + protected String engineToString() + { + return "IV Parameters"; + } + } + + public static class RC2AlgorithmParameters + extends JDKAlgorithmParameters + { + private short[] table = { + 0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0, + 0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a, + 0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36, + 0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c, + 0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60, + 0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa, + 0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e, + 0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf, + 0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6, + 0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3, + 0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c, + 0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2, + 0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5, + 0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5, + 0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f, + 0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab + }; + + private short[] ekb = { + 0x5d, 0xbe, 0x9b, 0x8b, 0x11, 0x99, 0x6e, 0x4d, 0x59, 0xf3, 0x85, 0xa6, 0x3f, 0xb7, 0x83, 0xc5, + 0xe4, 0x73, 0x6b, 0x3a, 0x68, 0x5a, 0xc0, 0x47, 0xa0, 0x64, 0x34, 0x0c, 0xf1, 0xd0, 0x52, 0xa5, + 0xb9, 0x1e, 0x96, 0x43, 0x41, 0xd8, 0xd4, 0x2c, 0xdb, 0xf8, 0x07, 0x77, 0x2a, 0xca, 0xeb, 0xef, + 0x10, 0x1c, 0x16, 0x0d, 0x38, 0x72, 0x2f, 0x89, 0xc1, 0xf9, 0x80, 0xc4, 0x6d, 0xae, 0x30, 0x3d, + 0xce, 0x20, 0x63, 0xfe, 0xe6, 0x1a, 0xc7, 0xb8, 0x50, 0xe8, 0x24, 0x17, 0xfc, 0x25, 0x6f, 0xbb, + 0x6a, 0xa3, 0x44, 0x53, 0xd9, 0xa2, 0x01, 0xab, 0xbc, 0xb6, 0x1f, 0x98, 0xee, 0x9a, 0xa7, 0x2d, + 0x4f, 0x9e, 0x8e, 0xac, 0xe0, 0xc6, 0x49, 0x46, 0x29, 0xf4, 0x94, 0x8a, 0xaf, 0xe1, 0x5b, 0xc3, + 0xb3, 0x7b, 0x57, 0xd1, 0x7c, 0x9c, 0xed, 0x87, 0x40, 0x8c, 0xe2, 0xcb, 0x93, 0x14, 0xc9, 0x61, + 0x2e, 0xe5, 0xcc, 0xf6, 0x5e, 0xa8, 0x5c, 0xd6, 0x75, 0x8d, 0x62, 0x95, 0x58, 0x69, 0x76, 0xa1, + 0x4a, 0xb5, 0x55, 0x09, 0x78, 0x33, 0x82, 0xd7, 0xdd, 0x79, 0xf5, 0x1b, 0x0b, 0xde, 0x26, 0x21, + 0x28, 0x74, 0x04, 0x97, 0x56, 0xdf, 0x3c, 0xf0, 0x37, 0x39, 0xdc, 0xff, 0x06, 0xa4, 0xea, 0x42, + 0x08, 0xda, 0xb4, 0x71, 0xb0, 0xcf, 0x12, 0x7a, 0x4e, 0xfa, 0x6c, 0x1d, 0x84, 0x00, 0xc8, 0x7f, + 0x91, 0x45, 0xaa, 0x2b, 0xc2, 0xb1, 0x8f, 0xd5, 0xba, 0xf2, 0xad, 0x19, 0xb2, 0x67, 0x36, 0xf7, + 0x0f, 0x0a, 0x92, 0x7d, 0xe3, 0x9d, 0xe9, 0x90, 0x3e, 0x23, 0x27, 0x66, 0x13, 0xec, 0x81, 0x15, + 0xbd, 0x22, 0xbf, 0x9f, 0x7e, 0xa9, 0x51, 0x4b, 0x4c, 0xfb, 0x02, 0xd3, 0x70, 0x86, 0x31, 0xe7, + 0x3b, 0x05, 0x03, 0x54, 0x60, 0x48, 0x65, 0x18, 0xd2, 0xcd, 0x5f, 0x32, 0x88, 0x0e, 0x35, 0xfd + }; + + private byte[] iv; + private int parameterVersion = 58; + + protected byte[] engineGetEncoded() + { + byte[] tmp = new byte[iv.length]; + + System.arraycopy(iv, 0, tmp, 0, iv.length); + return tmp; + } + + protected byte[] engineGetEncoded( + String format) + throws IOException + { + if (this.isASN1FormatString(format)) + { + if (parameterVersion == -1) + { + return new RC2CBCParameter(engineGetEncoded()).getEncoded(); + } + else + { + return new RC2CBCParameter(parameterVersion, engineGetEncoded()).getEncoded(); + } + } + + if (format.equals("RAW")) + { + return engineGetEncoded(); + } + + return null; + } + + protected AlgorithmParameterSpec localEngineGetParameterSpec( + Class paramSpec) + throws InvalidParameterSpecException + { + if (paramSpec == RC2ParameterSpec.class) + { + if (parameterVersion != -1) + { + if (parameterVersion < 256) + { + return new RC2ParameterSpec(ekb[parameterVersion], iv); + } + else + { + return new RC2ParameterSpec(parameterVersion, iv); + } + } + } + + if (paramSpec == IvParameterSpec.class) + { + return new IvParameterSpec(iv); + } + + throw new InvalidParameterSpecException("unknown parameter spec passed to RC2 parameters object."); + } + + protected void engineInit( + AlgorithmParameterSpec paramSpec) + throws InvalidParameterSpecException + { + if (paramSpec instanceof IvParameterSpec) + { + this.iv = ((IvParameterSpec)paramSpec).getIV(); + } + else if (paramSpec instanceof RC2ParameterSpec) + { + int effKeyBits = ((RC2ParameterSpec)paramSpec).getEffectiveKeyBits(); + if (effKeyBits != -1) + { + if (effKeyBits < 256) + { + parameterVersion = table[effKeyBits]; + } + else + { + parameterVersion = effKeyBits; + } + } + + this.iv = ((RC2ParameterSpec)paramSpec).getIV(); + } + else + { + throw new InvalidParameterSpecException("IvParameterSpec or RC2ParameterSpec required to initialise a RC2 parameters algorithm parameters object"); + } + } + + protected void engineInit( + byte[] params) + throws IOException + { + this.iv = new byte[params.length]; + + System.arraycopy(params, 0, iv, 0, iv.length); + } + + protected void engineInit( + byte[] params, + String format) + throws IOException + { + if (this.isASN1FormatString(format)) + { + ASN1InputStream aIn = new ASN1InputStream(params); + RC2CBCParameter p = RC2CBCParameter.getInstance(aIn.readObject()); + + if (p.getRC2ParameterVersion() != null) + { + parameterVersion = p.getRC2ParameterVersion().intValue(); + } + + iv = p.getIV(); + + return; + } + + if (format.equals("RAW")) + { + engineInit(params); + return; + } + + throw new IOException("Unknown parameters format in IV parameters object"); + } + + protected String engineToString() + { + return "RC2 Parameters"; + } + } + + public static class CAST5AlgorithmParameters + extends JDKAlgorithmParameters + { + private byte[] iv; + private int keyLength = 128; + + protected byte[] engineGetEncoded() + { + byte[] tmp = new byte[iv.length]; + + System.arraycopy(iv, 0, tmp, 0, iv.length); + return tmp; + } + + protected byte[] engineGetEncoded( + String format) + throws IOException + { + if (this.isASN1FormatString(format)) + { + return new CAST5CBCParameters(engineGetEncoded(), keyLength).getEncoded(); + } + + if (format.equals("RAW")) + { + return engineGetEncoded(); + } + + + return null; + } + + protected AlgorithmParameterSpec localEngineGetParameterSpec( + Class paramSpec) + throws InvalidParameterSpecException + { + if (paramSpec == IvParameterSpec.class) + { + return new IvParameterSpec(iv); + } + + throw new InvalidParameterSpecException("unknown parameter spec passed to CAST5 parameters object."); + } + + protected void engineInit( + AlgorithmParameterSpec paramSpec) + throws InvalidParameterSpecException + { + if (paramSpec instanceof IvParameterSpec) + { + this.iv = ((IvParameterSpec)paramSpec).getIV(); + } + else + { + throw new InvalidParameterSpecException("IvParameterSpec required to initialise a CAST5 parameters algorithm parameters object"); + } + } + + protected void engineInit( + byte[] params) + throws IOException + { + this.iv = new byte[params.length]; + + System.arraycopy(params, 0, iv, 0, iv.length); + } + + protected void engineInit( + byte[] params, + String format) + throws IOException + { + if (this.isASN1FormatString(format)) + { + ASN1InputStream aIn = new ASN1InputStream(params); + CAST5CBCParameters p = CAST5CBCParameters.getInstance(aIn.readObject()); + + keyLength = p.getKeyLength(); + + iv = p.getIV(); + + return; + } + + if (format.equals("RAW")) + { + engineInit(params); + return; + } + + throw new IOException("Unknown parameters format in IV parameters object"); + } + + protected String engineToString() + { + return "CAST5 Parameters"; + } + } + + public static class PKCS12PBE + extends JDKAlgorithmParameters + { + PKCS12PBEParams params; + + protected byte[] engineGetEncoded() + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + DEROutputStream dOut = new DEROutputStream(bOut); + + try + { + dOut.writeObject(params); + } + catch (IOException e) + { + throw new RuntimeException("Oooops! " + e.toString()); + } + + return bOut.toByteArray(); + } + + protected byte[] engineGetEncoded( + String format) + { + if (this.isASN1FormatString(format)) + { + return engineGetEncoded(); + } + + return null; + } + + protected AlgorithmParameterSpec localEngineGetParameterSpec( + Class paramSpec) + throws InvalidParameterSpecException + { + if (paramSpec == PBEParameterSpec.class) + { + return new PBEParameterSpec(params.getIV(), + params.getIterations().intValue()); + } + + throw new InvalidParameterSpecException("unknown parameter spec passed to PKCS12 PBE parameters object."); + } + + protected void engineInit( + AlgorithmParameterSpec paramSpec) + throws InvalidParameterSpecException + { + if (!(paramSpec instanceof PBEParameterSpec)) + { + throw new InvalidParameterSpecException("PBEParameterSpec required to initialise a PKCS12 PBE parameters algorithm parameters object"); + } + + PBEParameterSpec pbeSpec = (PBEParameterSpec)paramSpec; + + this.params = new PKCS12PBEParams(pbeSpec.getSalt(), + pbeSpec.getIterationCount()); + } + + protected void engineInit( + byte[] params) + throws IOException + { + ASN1InputStream aIn = new ASN1InputStream(params); + + this.params = PKCS12PBEParams.getInstance(aIn.readObject()); + } + + protected void engineInit( + byte[] params, + String format) + throws IOException + { + if (this.isASN1FormatString(format)) + { + engineInit(params); + return; + } + + throw new IOException("Unknown parameters format in PKCS12 PBE parameters object"); + } + + protected String engineToString() + { + return "PKCS12 PBE Parameters"; + } + } + + public static class IES + extends JDKAlgorithmParameters + { + IESParameterSpec currentSpec; + + /** + * in the abscence of a standard way of doing it this will do for + * now... + */ + protected byte[] engineGetEncoded() + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + DEROutputStream dOut = new DEROutputStream(bOut); + + try + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new DEROctetString(currentSpec.getDerivationV())); + v.add(new DEROctetString(currentSpec.getEncodingV())); + v.add(new ASN1Integer(currentSpec.getMacKeySize())); + + dOut.writeObject(new DERSequence(v)); + dOut.close(); + } + catch (IOException e) + { + throw new RuntimeException("Error encoding IESParameters"); + } + + return bOut.toByteArray(); + } + + protected byte[] engineGetEncoded( + String format) + { + if (this.isASN1FormatString(format) || format.equalsIgnoreCase("X.509")) + { + return engineGetEncoded(); + } + + return null; + } + + protected AlgorithmParameterSpec localEngineGetParameterSpec( + Class paramSpec) + throws InvalidParameterSpecException + { + if (paramSpec == IESParameterSpec.class) + { + return currentSpec; + } + + throw new InvalidParameterSpecException("unknown parameter spec passed to ElGamal parameters object."); + } + + protected void engineInit( + AlgorithmParameterSpec paramSpec) + throws InvalidParameterSpecException + { + if (!(paramSpec instanceof IESParameterSpec)) + { + throw new InvalidParameterSpecException("IESParameterSpec required to initialise a IES algorithm parameters object"); + } + + this.currentSpec = (IESParameterSpec)paramSpec; + } + + protected void engineInit( + byte[] params) + throws IOException + { + ASN1InputStream aIn = new ASN1InputStream(params); + + try + { + ASN1Sequence s = (ASN1Sequence)aIn.readObject(); + + this.currentSpec = new IESParameterSpec( + ((ASN1OctetString)s.getObjectAt(0)).getOctets(), + ((ASN1OctetString)s.getObjectAt(0)).getOctets(), + ((ASN1Integer)s.getObjectAt(0)).getValue().intValue()); + } + catch (ClassCastException e) + { + throw new IOException("Not a valid IES Parameter encoding."); + } + catch (ArrayIndexOutOfBoundsException e) + { + throw new IOException("Not a valid IES Parameter encoding."); + } + } + + protected void engineInit( + byte[] params, + String format) + throws IOException + { + if (this.isASN1FormatString(format) || format.equalsIgnoreCase("X.509")) + { + engineInit(params); + } + else + { + throw new IOException("Unknown parameter format " + format); + } + } + + protected String engineToString() + { + return "IES Parameters"; + } + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/MultiCertStoreSpi.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/MultiCertStoreSpi.java new file mode 100644 index 00000000..e3102c77 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/MultiCertStoreSpi.java @@ -0,0 +1,85 @@ +package org.spongycastle.jce.provider; + +import org.spongycastle.jce.MultiCertStoreParameters; + +import java.security.InvalidAlgorithmParameterException; +import org.spongycastle.jce.cert.CRLSelector; +import org.spongycastle.jce.cert.CertSelector; +import org.spongycastle.jce.cert.CertStore; +import org.spongycastle.jce.cert.CertStoreException; +import org.spongycastle.jce.cert.CertStoreParameters; +import org.spongycastle.jce.cert.CertStoreSpi; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +public class MultiCertStoreSpi + extends CertStoreSpi +{ + private MultiCertStoreParameters params; + + public MultiCertStoreSpi(CertStoreParameters params) + throws InvalidAlgorithmParameterException + { + super(params); + + if (!(params instanceof MultiCertStoreParameters)) + { + throw new InvalidAlgorithmParameterException("org.spongycastle.jce.provider.MultiCertStoreSpi: parameter must be a MultiCertStoreParameters object\n" + params.toString()); + } + + this.params = (MultiCertStoreParameters)params; + } + + public Collection engineGetCertificates(CertSelector certSelector) + throws CertStoreException + { + boolean searchAllStores = params.getSearchAllStores(); + Iterator iter = params.getCertStores().iterator(); + List allCerts = searchAllStores ? new ArrayList() : Collections.EMPTY_LIST; + + while (iter.hasNext()) + { + CertStore store = (CertStore)iter.next(); + Collection certs = store.getCertificates(certSelector); + + if (searchAllStores) + { + allCerts.addAll(certs); + } + else if (!certs.isEmpty()) + { + return certs; + } + } + + return allCerts; + } + + public Collection engineGetCRLs(CRLSelector crlSelector) + throws CertStoreException + { + boolean searchAllStores = params.getSearchAllStores(); + Iterator iter = params.getCertStores().iterator(); + List allCRLs = searchAllStores ? new ArrayList() : Collections.EMPTY_LIST; + + while (iter.hasNext()) + { + CertStore store = (CertStore)iter.next(); + Collection crls = store.getCRLs(crlSelector); + + if (searchAllStores) + { + allCRLs.addAll(crls); + } + else if (!crls.isEmpty()) + { + return crls; + } + } + + return allCRLs; + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCRLUtil.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCRLUtil.java new file mode 100644 index 00000000..3e22d9f6 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCRLUtil.java @@ -0,0 +1,155 @@ +package org.spongycastle.jce.provider; + +import org.spongycastle.jce.cert.CertStore; +import org.spongycastle.jce.cert.CertStoreException; +import org.spongycastle.jce.cert.PKIXParameters; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.spongycastle.util.StoreException; +import org.spongycastle.x509.ExtendedPKIXParameters; +import org.spongycastle.x509.X509CRLStoreSelector; +import org.spongycastle.x509.X509Store; + +public class PKIXCRLUtil +{ + public Set findCRLs(X509CRLStoreSelector crlselect, ExtendedPKIXParameters paramsPKIX, Date currentDate) + throws AnnotatedException + { + Set initialSet = new HashSet(); + + // get complete CRL(s) + try + { + initialSet.addAll(findCRLs(crlselect, paramsPKIX.getAdditionalStores())); + initialSet.addAll(findCRLs(crlselect, paramsPKIX.getStores())); + initialSet.addAll(findCRLs(crlselect, paramsPKIX.getCertStores())); + } + catch (AnnotatedException e) + { + throw new AnnotatedException("Exception obtaining complete CRLs.", e); + } + + Set finalSet = new HashSet(); + Date validityDate = currentDate; + + if (paramsPKIX.getDate() != null) + { + validityDate = paramsPKIX.getDate(); + } + + // based on RFC 5280 6.3.3 + for (Iterator it = initialSet.iterator(); it.hasNext();) + { + X509CRL crl = (X509CRL)it.next(); + + if (crl.getNextUpdate().after(validityDate)) + { + X509Certificate cert = crlselect.getCertificateChecking(); + + if (cert != null) + { + if (crl.getThisUpdate().before(cert.getNotAfter())) + { + finalSet.add(crl); + } + } + else + { + finalSet.add(crl); + } + } + } + + return finalSet; + } + + public Set findCRLs(X509CRLStoreSelector crlselect, PKIXParameters paramsPKIX) + throws AnnotatedException + { + Set completeSet = new HashSet(); + + // get complete CRL(s) + try + { + completeSet.addAll(findCRLs(crlselect, paramsPKIX.getCertStores())); + } + catch (AnnotatedException e) + { + throw new AnnotatedException("Exception obtaining complete CRLs.", e); + } + + return completeSet; + } + +/** + * Return a Collection of all CRLs found in the X509Store's that are + * matching the crlSelect criteriums. + * + * @param crlSelect a {@link X509CRLStoreSelector} object that will be used + * to select the CRLs + * @param crlStores a List containing only + * {@link org.spongycastle.x509.X509Store X509Store} objects. + * These are used to search for CRLs + * + * @return a Collection of all found {@link java.security.cert.X509CRL X509CRL} objects. May be + * empty but never <code>null</code>. + */ + private final Collection findCRLs(X509CRLStoreSelector crlSelect, + List crlStores) throws AnnotatedException + { + Set crls = new HashSet(); + Iterator iter = crlStores.iterator(); + + AnnotatedException lastException = null; + boolean foundValidStore = false; + + while (iter.hasNext()) + { + Object obj = iter.next(); + + if (obj instanceof X509Store) + { + X509Store store = (X509Store)obj; + + try + { + crls.addAll(store.getMatches(crlSelect)); + foundValidStore = true; + } + catch (StoreException e) + { + lastException = new AnnotatedException( + "Exception searching in X.509 CRL store.", e); + } + } + else + { + CertStore store = (CertStore)obj; + + try + { + crls.addAll(store.getCRLs(crlSelect)); + foundValidStore = true; + } + catch (CertStoreException e) + { + lastException = new AnnotatedException( + "Exception searching in X.509 CRL store.", e); + } + } + } + if (!foundValidStore && lastException != null) + { + throw lastException; + } + return crls; + } + +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCertPathBuilderSpi.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCertPathBuilderSpi.java new file mode 100644 index 00000000..d02dd511 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCertPathBuilderSpi.java @@ -0,0 +1,395 @@ +package org.spongycastle.jce.provider; + +import java.io.IOException; +import java.security.InvalidAlgorithmParameterException; +import java.security.PublicKey; +import org.spongycastle.jce.cert.CertPath; +import org.spongycastle.jce.cert.CertPathBuilderException; +import org.spongycastle.jce.cert.CertPathBuilderResult; +import org.spongycastle.jce.cert.CertPathBuilderSpi; +import org.spongycastle.jce.cert.CertPathParameters; +import org.spongycastle.jce.cert.CertPathValidator; +import org.spongycastle.jce.cert.CertPathValidatorException; +import org.spongycastle.jce.cert.CertSelector; +import org.spongycastle.jce.cert.CertStore; +import org.spongycastle.jce.cert.CertStoreException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import org.spongycastle.jce.cert.CertificateFactory; +import org.spongycastle.jce.cert.PKIXBuilderParameters; +import org.spongycastle.jce.cert.PKIXBuilderParameters; +import org.spongycastle.jce.cert.PKIXCertPathBuilderResult; +import org.spongycastle.jce.cert.PKIXCertPathValidatorResult; +import org.spongycastle.jce.cert.TrustAnchor; +import org.spongycastle.jce.cert.X509CertSelector; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.spongycastle.jce.X509Principal; +import org.spongycastle.x509.ExtendedPKIXBuilderParameters; +import org.spongycastle.jce.PrincipalUtil; + +/** + * Implements the PKIX CertPathBuilding algorithem for BouncyCastle. + * <br /> + * <b>MAYBE: implement more CertPath validation whil build path to omit invalid pathes</b> + * + * @see CertPathBuilderSpi + **/ +public class PKIXCertPathBuilderSpi + extends CertPathBuilderSpi +{ + /** + * Build and validate a CertPath using the given parameter. + * + * @param params PKIXBuilderParameters object containing all + * information to build the CertPath + **/ + public CertPathBuilderResult engineBuild( + CertPathParameters params) + throws CertPathBuilderException, InvalidAlgorithmParameterException + { + if (!(params instanceof PKIXBuilderParameters) + && !(params instanceof ExtendedPKIXBuilderParameters)) + { + throw new InvalidAlgorithmParameterException( + "Parameters must be an instance of " + + PKIXBuilderParameters.class.getName() + " or " + + ExtendedPKIXBuilderParameters.class.getName() + "."); + } + + ExtendedPKIXBuilderParameters pkixParams = null; + if (params instanceof ExtendedPKIXBuilderParameters) + { + pkixParams = (ExtendedPKIXBuilderParameters) params; + } + else + { + pkixParams = (ExtendedPKIXBuilderParameters) ExtendedPKIXBuilderParameters + .getInstance((PKIXBuilderParameters) params); + } + + Collection targets; + Iterator targetIter; + List certPathList = new ArrayList(); + Set certPathSet = new HashSet(); + X509Certificate cert; + Collection certs; + CertPath certPath = null; + Exception certPathException = null; + + // search target certificates + CertSelector certSelect = pkixParams.getTargetCertConstraints(); + if (certSelect == null) + { + throw new CertPathBuilderException("targetCertConstraints must be non-null for CertPath building"); + } + + try + { + targets = findCertificates(certSelect, pkixParams.getCertStores()); + } + catch (CertStoreException e) + { + throw new CertPathBuilderException(e); + } + + if (targets.isEmpty()) + { + throw new CertPathBuilderException("no certificate found matching targetCertContraints"); + } + + CertificateFactory cFact; + CertPathValidator validator; + + try + { + cFact = CertificateFactory.getInstance("X.509", "SC"); + validator = CertPathValidator.getInstance("PKIX", "SC"); + } + catch (Exception e) + { + throw new CertPathBuilderException("exception creating support classes: " + e); + } + + // + // check all potential target certificates + targetIter = targets.iterator(); + while (targetIter.hasNext()) + { + cert = (X509Certificate)targetIter.next(); + certPathList.clear(); + certPathSet.clear(); + while (cert != null) + { + // add cert to the certpath + certPathList.add(cert); + certPathSet.add(cert); + + // check whether the issuer of <cert> is a TrustAnchor + if (findTrustAnchor(cert, pkixParams.getTrustAnchors()) != null) + { + try + { + certPath = cFact.generateCertPath(certPathList); + + PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult)validator.validate(certPath, pkixParams); + + return new PKIXCertPathBuilderResult(certPath, + result.getTrustAnchor(), + result.getPolicyTree(), + result.getPublicKey()); + } + catch (CertificateException ex) + { + certPathException = ex; + } + catch (CertPathValidatorException ex) + { + certPathException = ex; + } + // if validation failed go to next certificate + cert = null; + } + else + { + // try to get the issuer certificate from one + // of the CertStores + try + { + X509Certificate issuer = findIssuer(cert, pkixParams.getCertStores()); + if (issuer.equals(cert)) + { + cert = null; + } + else + { + cert = issuer; + // validation failed - circular path detected, go to next certificate + if (certPathSet.contains(cert)) + { + cert = null; + } + } + } + catch (CertPathValidatorException ex) + { + certPathException = ex; + cert = null; + } + } + } + } + + if (certPath != null) + { + throw new CertPathBuilderException("found certificate chain, but could not be validated", certPathException); + } + + throw new CertPathBuilderException("unable to find certificate chain"); + } + + /** + * Search the given Set of TrustAnchor's for one that is the + * issuer of the fiven X509 certificate. + * + * @param cert the X509 certificate + * @param trustAnchors a Set of TrustAnchor's + * + * @return the <code>TrustAnchor</code> object if found or + * <code>null</code> if not. + * + * @exception CertPathValidatorException if a TrustAnchor was + * found but the signature verificytion on the given certificate + * has thrown an exception. This Exception can be obtainted with + * <code>getCause()</code> method. + **/ + final TrustAnchor findTrustAnchor( + X509Certificate cert, + Set trustAnchors) + throws CertPathBuilderException + { + Iterator iter = trustAnchors.iterator(); + TrustAnchor trust = null; + PublicKey trustPublicKey = null; + Exception invalidKeyEx = null; + + X509CertSelector certSelectX509 = new X509CertSelector(); + + try + { + certSelectX509.setSubject(PrincipalUtil.getIssuerX509Principal(cert).getEncoded()); + } + catch (Exception ex) + { + throw new CertPathBuilderException("can't get trust anchor principal",null); + } + + while (iter.hasNext() && trust == null) + { + trust = (TrustAnchor)iter.next(); + if (trust.getTrustedCert() != null) + { + if (certSelectX509.match(trust.getTrustedCert())) + { + trustPublicKey = trust.getTrustedCert().getPublicKey(); + } + else + { + trust = null; + } + } + else if (trust.getCAName() != null + && trust.getCAPublicKey() != null) + { + try + { + X509Principal certIssuer = PrincipalUtil.getIssuerX509Principal(cert); + X509Principal caName = new X509Principal(trust.getCAName()); + if (certIssuer.equals(caName)) + { + trustPublicKey = trust.getCAPublicKey(); + } + else + { + trust = null; + } + } + catch (Exception ex) + { + trust = null; + } + } + else + { + trust = null; + } + + if (trustPublicKey != null) + { + try + { + cert.verify(trustPublicKey); + } + catch (Exception ex) + { + invalidKeyEx = ex; + trust = null; + } + } + } + + if (trust == null && invalidKeyEx != null) + { + throw new CertPathBuilderException("TrustAnchor found put certificate validation failed",invalidKeyEx); + } + + return trust; + } + + /** + * Return a Collection of all certificates found in the + * CertStore's that are matching the certSelect criteriums. + * + * @param certSelect a {@link CertSelector CertSelector} + * object that will be used to select the certificates + * @param certStores a List containing only {@link CertStore + * CertStore} objects. These are used to search for + * certificates + * + * @return a Collection of all found {@link Certificate Certificate} + * objects. May be empty but never <code>null</code>. + **/ + private Collection findCertificates( + CertSelector certSelect, + List certStores) + throws CertStoreException + { + Set certs = new HashSet(); + Iterator iter = certStores.iterator(); + + while (iter.hasNext()) + { + CertStore certStore = (CertStore)iter.next(); + + certs.addAll(certStore.getCertificates(certSelect)); + } + + return certs; + } + + /** + * Find the issuer certificate of the given certificate. + * + * @param cert the certificate hows issuer certificate should + * be found. + * @param certStores a list of <code>CertStore</code> object + * that will be searched + * + * @return then <code>X509Certificate</code> object containing + * the issuer certificate or <code>null</code> if not found + * + * @exception CertPathValidatorException if a TrustAnchor was + * found but the signature verificytion on the given certificate + * has thrown an exception. This Exception can be obtainted with + * <code>getCause()</code> method. + **/ + private X509Certificate findIssuer( + X509Certificate cert, + List certStores) + throws CertPathValidatorException + { + Exception invalidKeyEx = null; + X509CertSelector certSelect = new X509CertSelector(); + try + { + certSelect.setSubject(PrincipalUtil.getIssuerX509Principal(cert).getEncoded()); + } + catch (Exception ex) + { + throw new CertPathValidatorException("Issuer not found", null, null, -1); + } + + Iterator iter; + try + { + iter = findCertificates(certSelect, certStores).iterator(); + } + catch (CertStoreException e) + { + throw new CertPathValidatorException(e); + } + + X509Certificate issuer = null; + while (iter.hasNext() && issuer == null) + { + issuer = (X509Certificate)iter.next(); + try + { + cert.verify(issuer.getPublicKey()); + } + catch (Exception ex) + { + invalidKeyEx = ex; + issuer = null; + } + } + + if (issuer == null && invalidKeyEx == null) + { + throw new CertPathValidatorException("Issuer not found", null, null, -1); + } + + if (issuer == null && invalidKeyEx != null) + { + throw new CertPathValidatorException("issuer found but certificate validation failed",invalidKeyEx,null,-1); + } + + return issuer; + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java new file mode 100644 index 00000000..989d9c9a --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java @@ -0,0 +1,431 @@ +package org.spongycastle.jce.provider; + +import java.security.InvalidAlgorithmParameterException; +import java.security.PublicKey; +import org.spongycastle.jce.cert.CertPath; +import org.spongycastle.jce.cert.CertPathParameters; +import org.spongycastle.jce.cert.CertPathValidatorException; +import org.spongycastle.jce.cert.CertPathValidatorResult; +import org.spongycastle.jce.cert.CertPathValidatorSpi; +import org.spongycastle.jce.cert.PKIXCertPathChecker; +import org.spongycastle.jce.cert.PKIXCertPathValidatorResult; +import org.spongycastle.jce.cert.PKIXParameters; +import org.spongycastle.jce.cert.TrustAnchor; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.spongycastle.jce.X509Principal; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.jce.exception.ExtCertPathValidatorException; +import org.spongycastle.x509.ExtendedPKIXParameters; + +/** + * CertPathValidatorSpi implementation for X.509 Certificate validation � la RFC + * 3280. + */ +public class PKIXCertPathValidatorSpi + extends CertPathValidatorSpi +{ + + public CertPathValidatorResult engineValidate( + CertPath certPath, + CertPathParameters params) + throws CertPathValidatorException, + InvalidAlgorithmParameterException + { + if (!(params instanceof PKIXParameters)) + { + throw new InvalidAlgorithmParameterException("Parameters must be a " + PKIXParameters.class.getName() + + " instance."); + } + + ExtendedPKIXParameters paramsPKIX; + if (params instanceof ExtendedPKIXParameters) + { + paramsPKIX = (ExtendedPKIXParameters)params; + } + else + { + paramsPKIX = ExtendedPKIXParameters.getInstance((PKIXParameters)params); + } + if (paramsPKIX.getTrustAnchors() == null) + { + throw new InvalidAlgorithmParameterException( + "trustAnchors is null, this is not allowed for certification path validation."); + } + + // + // 6.1.1 - inputs + // + + // + // (a) + // + List certs = certPath.getCertificates(); + int n = certs.size(); + + if (certs.isEmpty()) + { + throw new CertPathValidatorException("Certification path is empty.", null, certPath, 0); + } + + // + // (b) + // + // Date validDate = CertPathValidatorUtilities.getValidDate(paramsPKIX); + + // + // (c) + // + Set userInitialPolicySet = paramsPKIX.getInitialPolicies(); + + // + // (d) + // + TrustAnchor trust; + try + { + trust = CertPathValidatorUtilities.findTrustAnchor((X509Certificate) certs.get(certs.size() - 1), + paramsPKIX.getTrustAnchors(), paramsPKIX.getSigProvider()); + } + catch (AnnotatedException e) + { + throw new CertPathValidatorException(e.getMessage(), e, certPath, certs.size() - 1); + } + + if (trust == null) + { + throw new CertPathValidatorException("Trust anchor for certification path not found.", null, certPath, -1); + } + + // + // (e), (f), (g) are part of the paramsPKIX object. + // + Iterator certIter; + int index = 0; + int i; + // Certificate for each interation of the validation loop + // Signature information for each iteration of the validation loop + // + // 6.1.2 - setup + // + + // + // (a) + // + List[] policyNodes = new ArrayList[n + 1]; + for (int j = 0; j < policyNodes.length; j++) + { + policyNodes[j] = new ArrayList(); + } + + Set policySet = new HashSet(); + + policySet.add(RFC3280CertPathUtilities.ANY_POLICY); + + PKIXPolicyNode validPolicyTree = new PKIXPolicyNode(new ArrayList(), 0, policySet, null, new HashSet(), + RFC3280CertPathUtilities.ANY_POLICY, false); + + policyNodes[0].add(validPolicyTree); + + // + // (b) and (c) + // + PKIXNameConstraintValidator nameConstraintValidator = new PKIXNameConstraintValidator(); + + // (d) + // + int explicitPolicy; + Set acceptablePolicies = new HashSet(); + + if (paramsPKIX.isExplicitPolicyRequired()) + { + explicitPolicy = 0; + } + else + { + explicitPolicy = n + 1; + } + + // + // (e) + // + int inhibitAnyPolicy; + + if (paramsPKIX.isAnyPolicyInhibited()) + { + inhibitAnyPolicy = 0; + } + else + { + inhibitAnyPolicy = n + 1; + } + + // + // (f) + // + int policyMapping; + + if (paramsPKIX.isPolicyMappingInhibited()) + { + policyMapping = 0; + } + else + { + policyMapping = n + 1; + } + + // + // (g), (h), (i), (j) + // + PublicKey workingPublicKey; + X509Principal workingIssuerName; + + X509Certificate sign = trust.getTrustedCert(); + try + { + if (sign != null) + { + workingIssuerName = CertPathValidatorUtilities.getSubjectPrincipal(sign); + workingPublicKey = sign.getPublicKey(); + } + else + { + workingIssuerName = new X509Principal(trust.getCAName()); + workingPublicKey = trust.getCAPublicKey(); + } + } + catch (IllegalArgumentException ex) + { + throw new ExtCertPathValidatorException("Subject of trust anchor could not be (re)encoded.", ex, certPath, + -1); + } + + AlgorithmIdentifier workingAlgId = null; + try + { + workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey); + } + catch (CertPathValidatorException e) + { + throw new ExtCertPathValidatorException( + "Algorithm identifier of public key of trust anchor could not be read.", e, certPath, -1); + } + ASN1ObjectIdentifier workingPublicKeyAlgorithm = workingAlgId.getObjectId(); + ASN1Encodable workingPublicKeyParameters = workingAlgId.getParameters(); + + // + // (k) + // + int maxPathLength = n; + + // + // 6.1.3 + // + + if (paramsPKIX.getTargetConstraints() != null + && !paramsPKIX.getTargetConstraints().match((X509Certificate) certs.get(0))) + { + throw new ExtCertPathValidatorException( + "Target certificate in certification path does not match targetConstraints.", null, certPath, 0); + } + + // + // initialize CertPathChecker's + // + List pathCheckers = paramsPKIX.getCertPathCheckers(); + certIter = pathCheckers.iterator(); + while (certIter.hasNext()) + { + ((PKIXCertPathChecker) certIter.next()).init(false); + } + + X509Certificate cert = null; + + for (index = certs.size() - 1; index >= 0; index--) + { + // try + // { + // + // i as defined in the algorithm description + // + i = n - index; + + // + // set certificate to be checked in this round + // sign and workingPublicKey and workingIssuerName are set + // at the end of the for loop and initialized the + // first time from the TrustAnchor + // + cert = (X509Certificate) certs.get(index); + boolean verificationAlreadyPerformed = (index == certs.size() - 1); + + // + // 6.1.3 + // + + RFC3280CertPathUtilities.processCertA(certPath, paramsPKIX, index, workingPublicKey, + verificationAlreadyPerformed, workingIssuerName, sign); + + RFC3280CertPathUtilities.processCertBC(certPath, index, nameConstraintValidator); + + validPolicyTree = RFC3280CertPathUtilities.processCertD(certPath, index, acceptablePolicies, + validPolicyTree, policyNodes, inhibitAnyPolicy); + + validPolicyTree = RFC3280CertPathUtilities.processCertE(certPath, index, validPolicyTree); + + RFC3280CertPathUtilities.processCertF(certPath, index, validPolicyTree, explicitPolicy); + + // + // 6.1.4 + // + + if (i != n) + { + if (cert != null && cert.getVersion() == 1) + { + throw new CertPathValidatorException("Version 1 certificates can't be used as CA ones.", null, + certPath, index); + } + + RFC3280CertPathUtilities.prepareNextCertA(certPath, index); + + validPolicyTree = RFC3280CertPathUtilities.prepareCertB(certPath, index, policyNodes, validPolicyTree, + policyMapping); + + RFC3280CertPathUtilities.prepareNextCertG(certPath, index, nameConstraintValidator); + + // (h) + explicitPolicy = RFC3280CertPathUtilities.prepareNextCertH1(certPath, index, explicitPolicy); + policyMapping = RFC3280CertPathUtilities.prepareNextCertH2(certPath, index, policyMapping); + inhibitAnyPolicy = RFC3280CertPathUtilities.prepareNextCertH3(certPath, index, inhibitAnyPolicy); + + // + // (i) + // + explicitPolicy = RFC3280CertPathUtilities.prepareNextCertI1(certPath, index, explicitPolicy); + policyMapping = RFC3280CertPathUtilities.prepareNextCertI2(certPath, index, policyMapping); + + // (j) + inhibitAnyPolicy = RFC3280CertPathUtilities.prepareNextCertJ(certPath, index, inhibitAnyPolicy); + + // (k) + RFC3280CertPathUtilities.prepareNextCertK(certPath, index); + + // (l) + maxPathLength = RFC3280CertPathUtilities.prepareNextCertL(certPath, index, maxPathLength); + + // (m) + maxPathLength = RFC3280CertPathUtilities.prepareNextCertM(certPath, index, maxPathLength); + + // (n) + RFC3280CertPathUtilities.prepareNextCertN(certPath, index); + + Set criticalExtensions = cert.getCriticalExtensionOIDs(); + if (criticalExtensions != null) + { + criticalExtensions = new HashSet(criticalExtensions); + + // these extensions are handled by the algorithm + criticalExtensions.remove(RFC3280CertPathUtilities.KEY_USAGE); + criticalExtensions.remove(RFC3280CertPathUtilities.CERTIFICATE_POLICIES); + criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_MAPPINGS); + criticalExtensions.remove(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY); + criticalExtensions.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT); + criticalExtensions.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR); + criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_CONSTRAINTS); + criticalExtensions.remove(RFC3280CertPathUtilities.BASIC_CONSTRAINTS); + criticalExtensions.remove(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME); + criticalExtensions.remove(RFC3280CertPathUtilities.NAME_CONSTRAINTS); + } + else + { + criticalExtensions = new HashSet(); + } + + // (o) + RFC3280CertPathUtilities.prepareNextCertO(certPath, index, criticalExtensions, pathCheckers); + + // set signing certificate for next round + sign = cert; + + // (c) + workingIssuerName = CertPathValidatorUtilities.getSubjectPrincipal(sign); + + // (d) + try + { + workingPublicKey = CertPathValidatorUtilities.getNextWorkingKey(certPath.getCertificates(), index); + } + catch (CertPathValidatorException e) + { + throw new CertPathValidatorException("Next working key could not be retrieved.", e, certPath, index); + } + + workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey); + // (f) + workingPublicKeyAlgorithm = workingAlgId.getObjectId(); + // (e) + workingPublicKeyParameters = workingAlgId.getParameters(); + } + } + + // + // 6.1.5 Wrap-up procedure + // + + explicitPolicy = RFC3280CertPathUtilities.wrapupCertA(explicitPolicy, cert); + + explicitPolicy = RFC3280CertPathUtilities.wrapupCertB(certPath, index + 1, explicitPolicy); + + // + // (c) (d) and (e) are already done + // + + // + // (f) + // + Set criticalExtensions = cert.getCriticalExtensionOIDs(); + + if (criticalExtensions != null) + { + criticalExtensions = new HashSet(criticalExtensions); + // these extensions are handled by the algorithm + criticalExtensions.remove(RFC3280CertPathUtilities.KEY_USAGE); + criticalExtensions.remove(RFC3280CertPathUtilities.CERTIFICATE_POLICIES); + criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_MAPPINGS); + criticalExtensions.remove(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY); + criticalExtensions.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT); + criticalExtensions.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR); + criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_CONSTRAINTS); + criticalExtensions.remove(RFC3280CertPathUtilities.BASIC_CONSTRAINTS); + criticalExtensions.remove(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME); + criticalExtensions.remove(RFC3280CertPathUtilities.NAME_CONSTRAINTS); + criticalExtensions.remove(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS); + } + else + { + criticalExtensions = new HashSet(); + } + + RFC3280CertPathUtilities.wrapupCertF(certPath, index + 1, pathCheckers, criticalExtensions); + + PKIXPolicyNode intersection = RFC3280CertPathUtilities.wrapupCertG(certPath, paramsPKIX, userInitialPolicySet, + index + 1, policyNodes, validPolicyTree, acceptablePolicies); + + if ((explicitPolicy > 0) || (intersection != null)) + { + return new PKIXCertPathValidatorResult(trust, intersection, cert.getPublicKey()); + } + + throw new CertPathValidatorException("Path processing failed on policy.", null, certPath, index); + } + +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXPolicyNode.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXPolicyNode.java new file mode 100644 index 00000000..1a0b4e7b --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXPolicyNode.java @@ -0,0 +1,169 @@ +package org.spongycastle.jce.provider; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.spongycastle.jce.cert.PolicyNode; + +public class PKIXPolicyNode + implements PolicyNode +{ + protected List children; + protected int depth; + protected Set expectedPolicies; + protected PolicyNode parent; + protected Set policyQualifiers; + protected String validPolicy; + protected boolean critical; + + /* + * + * CONSTRUCTORS + * + */ + + public PKIXPolicyNode( + List _children, + int _depth, + Set _expectedPolicies, + PolicyNode _parent, + Set _policyQualifiers, + String _validPolicy, + boolean _critical) + { + children = _children; + depth = _depth; + expectedPolicies = _expectedPolicies; + parent = _parent; + policyQualifiers = _policyQualifiers; + validPolicy = _validPolicy; + critical = _critical; + } + + public void addChild( + PKIXPolicyNode _child) + { + children.add(_child); + _child.setParent(this); + } + + public Iterator getChildren() + { + return children.iterator(); + } + + public int getDepth() + { + return depth; + } + + public Set getExpectedPolicies() + { + return expectedPolicies; + } + + public PolicyNode getParent() + { + return parent; + } + + public Set getPolicyQualifiers() + { + return policyQualifiers; + } + + public String getValidPolicy() + { + return validPolicy; + } + + public boolean hasChildren() + { + return !children.isEmpty(); + } + + public boolean isCritical() + { + return critical; + } + + public void removeChild(PKIXPolicyNode _child) + { + children.remove(_child); + } + + public void setCritical(boolean _critical) + { + critical = _critical; + } + + public void setParent(PKIXPolicyNode _parent) + { + parent = _parent; + } + + public String toString() + { + return toString(""); + } + + public String toString(String _indent) + { + StringBuffer _buf = new StringBuffer(); + _buf.append(_indent); + _buf.append(validPolicy); + _buf.append(" {\n"); + + for(int i = 0; i < children.size(); i++) + { + _buf.append(((PKIXPolicyNode)children.get(i)).toString(_indent + " ")); + } + + _buf.append(_indent); + _buf.append("}\n"); + return _buf.toString(); + } + + public Object clone() + { + return copy(); + } + + public PKIXPolicyNode copy() + { + Set _expectedPolicies = new HashSet(); + Iterator _iter = expectedPolicies.iterator(); + while (_iter.hasNext()) + { + _expectedPolicies.add(new String((String)_iter.next())); + } + + Set _policyQualifiers = new HashSet(); + _iter = policyQualifiers.iterator(); + while (_iter.hasNext()) + { + _policyQualifiers.add(new String((String)_iter.next())); + } + + PKIXPolicyNode _node = new PKIXPolicyNode(new ArrayList(), + depth, + _expectedPolicies, + null, + _policyQualifiers, + new String(validPolicy), + critical); + + _iter = children.iterator(); + while (_iter.hasNext()) + { + PKIXPolicyNode _child = ((PKIXPolicyNode)_iter.next()).copy(); + _child.setParent(_node); + _node.addChild(_child); + } + + return _node; + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/ProviderUtil.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/ProviderUtil.java new file mode 100644 index 00000000..74efc9a9 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/ProviderUtil.java @@ -0,0 +1,72 @@ +package org.spongycastle.jce.provider; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.Permission; + +import org.spongycastle.jcajce.provider.config.ConfigurableProvider; +import org.spongycastle.jcajce.provider.config.ProviderConfigurationPermission; +import org.spongycastle.jce.spec.ECParameterSpec; + +public class ProviderUtil +{ + private static Permission BC_EC_LOCAL_PERMISSION = new ProviderConfigurationPermission( + "SC", ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA); + private static Permission BC_EC_PERMISSION = new ProviderConfigurationPermission( + "SC", ConfigurableProvider.EC_IMPLICITLY_CA); + + private static ThreadLocal threadSpec = new ThreadLocal(); + private static volatile ECParameterSpec ecImplicitCaParams; + + static void setParameter(String parameterName, Object parameter) + { + SecurityManager securityManager = System.getSecurityManager(); + + if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA)) + { + ECParameterSpec curveSpec; + + if (securityManager != null) + { + securityManager.checkPermission(BC_EC_LOCAL_PERMISSION); + } + + curveSpec = (ECParameterSpec)parameter; + + threadSpec.set(curveSpec); + } + else if (parameterName.equals(ConfigurableProvider.EC_IMPLICITLY_CA)) + { + if (securityManager != null) + { + securityManager.checkPermission(BC_EC_PERMISSION); + } + + ecImplicitCaParams = (ECParameterSpec)parameter; + } + } + + public static ECParameterSpec getEcImplicitlyCa() + { + ECParameterSpec spec = (ECParameterSpec)threadSpec.get(); + + if (spec != null) + { + return spec; + } + + return ecImplicitCaParams; + } + + static int getReadLimit(InputStream in) + throws IOException + { + if (in instanceof ByteArrayInputStream) + { + return in.available(); + } + + return Integer.MAX_VALUE; + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/RFC3280CertPathUtilities.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/RFC3280CertPathUtilities.java new file mode 100644 index 00000000..3f37d4c9 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/RFC3280CertPathUtilities.java @@ -0,0 +1,2582 @@ +package org.spongycastle.jce.provider; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.security.PublicKey; +import java.text.SimpleDateFormat; +import org.spongycastle.jce.cert.CertPath; +import org.spongycastle.jce.cert.CertPathBuilder; +import org.spongycastle.jce.cert.CertPathBuilderException; +import org.spongycastle.jce.cert.CertPathValidatorException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; +import org.spongycastle.jce.cert.PKIXCertPathChecker; +import java.security.cert.CRLException; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.security.cert.X509Extension; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TimeZone; +import java.util.Vector; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.ASN1TaggedObject; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.x509.BasicConstraints; +import org.spongycastle.asn1.x509.CRLDistPoint; +import org.spongycastle.asn1.x509.CRLReason; +import org.spongycastle.asn1.x509.DistributionPoint; +import org.spongycastle.asn1.x509.DistributionPointName; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.asn1.x509.GeneralNames; +import org.spongycastle.asn1.x509.GeneralSubtree; +import org.spongycastle.asn1.x509.IssuingDistributionPoint; +import org.spongycastle.asn1.x509.NameConstraints; +import org.spongycastle.asn1.x509.PolicyInformation; +import org.spongycastle.asn1.x509.X509Extensions; +import org.spongycastle.asn1.x509.X509Name; +import org.spongycastle.jce.exception.ExtCertPathValidatorException; +import org.spongycastle.jce.X509Principal; +import org.spongycastle.jce.PrincipalUtil; +import org.spongycastle.util.Arrays; +import org.spongycastle.x509.ExtendedPKIXBuilderParameters; +import org.spongycastle.x509.ExtendedPKIXParameters; +import org.spongycastle.x509.X509CRLStoreSelector; +import org.spongycastle.x509.X509CertStoreSelector; + +public class RFC3280CertPathUtilities +{ + private static final PKIXCRLUtil CRL_UTIL = new PKIXCRLUtil(); + + /** + * If the complete CRL includes an issuing distribution point (IDP) CRL + * extension check the following: + * <p/> + * (i) If the distribution point name is present in the IDP CRL extension + * and the distribution field is present in the DP, then verify that one of + * the names in the IDP matches one of the names in the DP. If the + * distribution point name is present in the IDP CRL extension and the + * distribution field is omitted from the DP, then verify that one of the + * names in the IDP matches one of the names in the cRLIssuer field of the + * DP. + * </p> + * <p/> + * (ii) If the onlyContainsUserCerts boolean is asserted in the IDP CRL + * extension, verify that the certificate does not include the basic + * constraints extension with the cA boolean asserted. + * </p> + * <p/> + * (iii) If the onlyContainsCACerts boolean is asserted in the IDP CRL + * extension, verify that the certificate includes the basic constraints + * extension with the cA boolean asserted. + * </p> + * <p/> + * (iv) Verify that the onlyContainsAttributeCerts boolean is not asserted. + * </p> + * + * @param dp The distribution point. + * @param cert The certificate. + * @param crl The CRL. + * @throws AnnotatedException if one of the conditions is not met or an error occurs. + */ + protected static void processCRLB2( + DistributionPoint dp, + Object cert, + X509CRL crl) + throws AnnotatedException + { + IssuingDistributionPoint idp = null; + try + { + idp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(crl, + RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT)); + } + catch (Exception e) + { + throw new AnnotatedException("Issuing distribution point extension could not be decoded.", e); + } + // (b) (2) (i) + // distribution point name is present + if (idp != null) + { + if (idp.getDistributionPoint() != null) + { + // make list of names + DistributionPointName dpName = IssuingDistributionPoint.getInstance(idp).getDistributionPoint(); + List names = new ArrayList(); + + if (dpName.getType() == DistributionPointName.FULL_NAME) + { + GeneralName[] genNames = GeneralNames.getInstance(dpName.getName()).getNames(); + for (int j = 0; j < genNames.length; j++) + { + names.add(genNames[j]); + } + } + if (dpName.getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER) + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + try + { + Enumeration e = ASN1Sequence.getInstance( + ASN1Sequence.fromByteArray(CertPathValidatorUtilities.getIssuerPrincipal(crl) + .getEncoded())).getObjects(); + while (e.hasMoreElements()) + { + vec.add((ASN1Encodable)e.nextElement()); + } + } + catch (IOException e) + { + throw new AnnotatedException("Could not read CRL issuer.", e); + } + vec.add(dpName.getName()); + names.add(new GeneralName(X509Name.getInstance(new DERSequence(vec)))); + } + boolean matches = false; + // verify that one of the names in the IDP matches one + // of the names in the DP. + if (dp.getDistributionPoint() != null) + { + dpName = dp.getDistributionPoint(); + GeneralName[] genNames = null; + if (dpName.getType() == DistributionPointName.FULL_NAME) + { + genNames = GeneralNames.getInstance(dpName.getName()).getNames(); + } + if (dpName.getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER) + { + if (dp.getCRLIssuer() != null) + { + genNames = dp.getCRLIssuer().getNames(); + } + else + { + genNames = new GeneralName[1]; + try + { + genNames[0] = new GeneralName(new X509Name( + (ASN1Sequence)ASN1Sequence.fromByteArray(CertPathValidatorUtilities + .getEncodedIssuerPrincipal(cert).getEncoded()))); + } + catch (IOException e) + { + throw new AnnotatedException("Could not read certificate issuer.", e); + } + } + for (int j = 0; j < genNames.length; j++) + { + Enumeration e = ASN1Sequence.getInstance(genNames[j].getName().toASN1Primitive()).getObjects(); + ASN1EncodableVector vec = new ASN1EncodableVector(); + while (e.hasMoreElements()) + { + vec.add((ASN1Encodable)e.nextElement()); + } + vec.add(dpName.getName()); + genNames[j] = new GeneralName(new X509Name(new DERSequence(vec))); + } + } + if (genNames != null) + { + for (int j = 0; j < genNames.length; j++) + { + if (names.contains(genNames[j])) + { + matches = true; + break; + } + } + } + if (!matches) + { + throw new AnnotatedException( + "No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point."); + } + } + // verify that one of the names in + // the IDP matches one of the names in the cRLIssuer field of + // the DP + else + { + if (dp.getCRLIssuer() == null) + { + throw new AnnotatedException("Either the cRLIssuer or the distributionPoint field must " + + "be contained in DistributionPoint."); + } + GeneralName[] genNames = dp.getCRLIssuer().getNames(); + for (int j = 0; j < genNames.length; j++) + { + if (names.contains(genNames[j])) + { + matches = true; + break; + } + } + if (!matches) + { + throw new AnnotatedException( + "No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point."); + } + } + } + BasicConstraints bc = null; + try + { + bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue((X509Extension)cert, + BASIC_CONSTRAINTS)); + } + catch (Exception e) + { + throw new AnnotatedException("Basic constraints extension could not be decoded.", e); + } + + if (cert instanceof X509Certificate) + { + // (b) (2) (ii) + if (idp.onlyContainsUserCerts() && (bc != null && bc.isCA())) + { + throw new AnnotatedException("CA Cert CRL only contains user certificates."); + } + + // (b) (2) (iii) + if (idp.onlyContainsCACerts() && (bc == null || !bc.isCA())) + { + throw new AnnotatedException("End CRL only contains CA certificates."); + } + } + + // (b) (2) (iv) + if (idp.onlyContainsAttributeCerts()) + { + throw new AnnotatedException("onlyContainsAttributeCerts boolean is asserted."); + } + } + } + + /** + * If the DP includes cRLIssuer, then verify that the issuer field in the + * complete CRL matches cRLIssuer in the DP and that the complete CRL + * contains an issuing distribution point extension with the indirectCRL + * boolean asserted. Otherwise, verify that the CRL issuer matches the + * certificate issuer. + * + * @param dp The distribution point. + * @param cert The certificate ot attribute certificate. + * @param crl The CRL for <code>cert</code>. + * @throws AnnotatedException if one of the above conditions does not apply or an error + * occurs. + */ + protected static void processCRLB1( + DistributionPoint dp, + Object cert, + X509CRL crl) + throws AnnotatedException + { + ASN1Primitive idp = CertPathValidatorUtilities.getExtensionValue(crl, ISSUING_DISTRIBUTION_POINT); + boolean isIndirect = false; + if (idp != null) + { + if (IssuingDistributionPoint.getInstance(idp).isIndirectCRL()) + { + isIndirect = true; + } + } + byte[] issuerBytes = CertPathValidatorUtilities.getIssuerPrincipal(crl).getEncoded(); + + boolean matchIssuer = false; + if (dp.getCRLIssuer() != null) + { + GeneralName genNames[] = dp.getCRLIssuer().getNames(); + for (int j = 0; j < genNames.length; j++) + { + if (genNames[j].getTagNo() == GeneralName.directoryName) + { + try + { + if (Arrays.areEqual(genNames[j].getName().toASN1Primitive().getEncoded(), issuerBytes)) + { + matchIssuer = true; + } + } + catch (IOException e) + { + throw new AnnotatedException( + "CRL issuer information from distribution point cannot be decoded.", e); + } + } + } + if (matchIssuer && !isIndirect) + { + throw new AnnotatedException("Distribution point contains cRLIssuer field but CRL is not indirect."); + } + if (!matchIssuer) + { + throw new AnnotatedException("CRL issuer of CRL does not match CRL issuer of distribution point."); + } + } + else + { + if (CertPathValidatorUtilities.getIssuerPrincipal(crl).equals( + CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert))) + { + matchIssuer = true; + } + } + if (!matchIssuer) + { + throw new AnnotatedException("Cannot find matching CRL issuer for certificate."); + } + } + + protected static ReasonsMask processCRLD( + X509CRL crl, + DistributionPoint dp) + throws AnnotatedException + { + IssuingDistributionPoint idp = null; + try + { + idp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(crl, + RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT)); + } + catch (Exception e) + { + throw new AnnotatedException("Issuing distribution point extension could not be decoded.", e); + } + // (d) (1) + if (idp != null && idp.getOnlySomeReasons() != null && dp.getReasons() != null) + { + return new ReasonsMask(dp.getReasons()).intersect(new ReasonsMask(idp.getOnlySomeReasons())); + } + // (d) (4) + if ((idp == null || idp.getOnlySomeReasons() == null) && dp.getReasons() == null) + { + return ReasonsMask.allReasons; + } + // (d) (2) and (d)(3) + return (dp.getReasons() == null + ? ReasonsMask.allReasons + : new ReasonsMask(dp.getReasons())).intersect(idp == null + ? ReasonsMask.allReasons + : new ReasonsMask(idp.getOnlySomeReasons())); + + } + + public static final String CERTIFICATE_POLICIES = X509Extensions.CertificatePolicies.getId(); + + public static final String POLICY_MAPPINGS = X509Extensions.PolicyMappings.getId(); + + public static final String INHIBIT_ANY_POLICY = X509Extensions.InhibitAnyPolicy.getId(); + + public static final String ISSUING_DISTRIBUTION_POINT = X509Extensions.IssuingDistributionPoint.getId(); + + public static final String FRESHEST_CRL = X509Extensions.FreshestCRL.getId(); + + public static final String DELTA_CRL_INDICATOR = X509Extensions.DeltaCRLIndicator.getId(); + + public static final String POLICY_CONSTRAINTS = X509Extensions.PolicyConstraints.getId(); + + public static final String BASIC_CONSTRAINTS = X509Extensions.BasicConstraints.getId(); + + public static final String CRL_DISTRIBUTION_POINTS = X509Extensions.CRLDistributionPoints.getId(); + + public static final String SUBJECT_ALTERNATIVE_NAME = X509Extensions.SubjectAlternativeName.getId(); + + public static final String NAME_CONSTRAINTS = X509Extensions.NameConstraints.getId(); + + public static final String AUTHORITY_KEY_IDENTIFIER = X509Extensions.AuthorityKeyIdentifier.getId(); + + public static final String KEY_USAGE = X509Extensions.KeyUsage.getId(); + + public static final String CRL_NUMBER = X509Extensions.CRLNumber.getId(); + + public static final String ANY_POLICY = "2.5.29.32.0"; + + /* + * key usage bits + */ + protected static final int KEY_CERT_SIGN = 5; + + protected static final int CRL_SIGN = 6; + + /** + * Obtain and validate the certification path for the complete CRL issuer. + * If a key usage extension is present in the CRL issuer's certificate, + * verify that the cRLSign bit is set. + * + * @param crl CRL which contains revocation information for the certificate + * <code>cert</code>. + * @param cert The attribute certificate or certificate to check if it is + * revoked. + * @param defaultCRLSignCert The issuer certificate of the certificate <code>cert</code>. + * @param defaultCRLSignKey The public key of the issuer certificate + * <code>defaultCRLSignCert</code>. + * @param paramsPKIX paramsPKIX PKIX parameters. + * @param certPathCerts The certificates on the certification path. + * @return A <code>Set</code> with all keys of possible CRL issuer + * certificates. + * @throws AnnotatedException if the CRL is not valid or the status cannot be checked or + * some error occurs. + */ + protected static Set processCRLF( + X509CRL crl, + Object cert, + X509Certificate defaultCRLSignCert, + PublicKey defaultCRLSignKey, + ExtendedPKIXParameters paramsPKIX, + List certPathCerts) + throws AnnotatedException + { + // (f) + + // get issuer from CRL + X509CertStoreSelector selector = new X509CertStoreSelector(); + try + { + byte[] issuerPrincipal = CertPathValidatorUtilities.getIssuerPrincipal(crl).getEncoded(); + selector.setSubject(issuerPrincipal); + } + catch (IOException e) + { + throw new AnnotatedException( + "Subject criteria for certificate selector to find issuer certificate for CRL could not be set.", e); + } + + // get CRL signing certs + Collection coll; + try + { + coll = CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getStores()); + coll.addAll(CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getAdditionalStores())); + coll.addAll(CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getCertStores())); + } + catch (AnnotatedException e) + { + throw new AnnotatedException("Issuer certificate for CRL cannot be searched.", e); + } + + coll.add(defaultCRLSignCert); + + Iterator cert_it = coll.iterator(); + + List validCerts = new ArrayList(); + List validKeys = new ArrayList(); + + while (cert_it.hasNext()) + { + X509Certificate signingCert = (X509Certificate)cert_it.next(); + + /* + * CA of the certificate, for which this CRL is checked, has also + * signed CRL, so skip the path validation, because is already done + */ + if (signingCert.equals(defaultCRLSignCert)) + { + validCerts.add(signingCert); + validKeys.add(defaultCRLSignKey); + continue; + } + try + { + CertPathBuilder builder = CertPathBuilder.getInstance("PKIX", BouncyCastleProvider.PROVIDER_NAME); + selector = new X509CertStoreSelector(); + selector.setCertificate(signingCert); + ExtendedPKIXParameters temp = (ExtendedPKIXParameters)paramsPKIX.clone(); + temp.setTargetCertConstraints(selector); + ExtendedPKIXBuilderParameters params = (ExtendedPKIXBuilderParameters)ExtendedPKIXBuilderParameters + .getInstance(temp); + /* + * if signingCert is placed not higher on the cert path a + * dependency loop results. CRL for cert is checked, but + * signingCert is needed for checking the CRL which is dependent + * on checking cert because it is higher in the cert path and so + * signing signingCert transitively. so, revocation is disabled, + * forgery attacks of the CRL are detected in this outer loop + * for all other it must be enabled to prevent forgery attacks + */ + if (certPathCerts.contains(signingCert)) + { + params.setRevocationEnabled(false); + } + else + { + params.setRevocationEnabled(true); + } + List certs = builder.build(params).getCertPath().getCertificates(); + validCerts.add(signingCert); + validKeys.add(CertPathValidatorUtilities.getNextWorkingKey(certs, 0)); + } + catch (CertPathBuilderException e) + { + throw new AnnotatedException("Internal error.", e); + } + catch (CertPathValidatorException e) + { + throw new AnnotatedException("Public key of issuer certificate of CRL could not be retrieved.", e); + } + catch (Exception e) + { + throw new RuntimeException(e.getMessage()); + } + } + + Set checkKeys = new HashSet(); + + AnnotatedException lastException = null; + for (int i = 0; i < validCerts.size(); i++) + { + X509Certificate signCert = (X509Certificate)validCerts.get(i); + boolean[] keyusage = signCert.getKeyUsage(); + + if (keyusage != null && (keyusage.length < 7 || !keyusage[CRL_SIGN])) + { + lastException = new AnnotatedException( + "Issuer certificate key usage extension does not permit CRL signing."); + } + else + { + checkKeys.add(validKeys.get(i)); + } + } + + if (checkKeys.isEmpty() && lastException == null) + { + throw new AnnotatedException("Cannot find a valid issuer certificate."); + } + if (checkKeys.isEmpty() && lastException != null) + { + throw lastException; + } + + return checkKeys; + } + + protected static PublicKey processCRLG( + X509CRL crl, + Set keys) + throws AnnotatedException + { + Exception lastException = null; + for (Iterator it = keys.iterator(); it.hasNext();) + { + PublicKey key = (PublicKey)it.next(); + try + { + crl.verify(key); + return key; + } + catch (Exception e) + { + lastException = e; + } + } + throw new AnnotatedException("Cannot verify CRL.", lastException); + } + + protected static X509CRL processCRLH( + Set deltacrls, + PublicKey key) + throws AnnotatedException + { + Exception lastException = null; + + for (Iterator it = deltacrls.iterator(); it.hasNext();) + { + X509CRL crl = (X509CRL)it.next(); + try + { + crl.verify(key); + return crl; + } + catch (Exception e) + { + lastException = e; + } + } + + if (lastException != null) + { + throw new AnnotatedException("Cannot verify delta CRL.", lastException); + } + return null; + } + + protected static Set processCRLA1i( + Date currentDate, + ExtendedPKIXParameters paramsPKIX, + X509Certificate cert, + X509CRL crl) + throws AnnotatedException + { + Set set = new HashSet(); + if (paramsPKIX.isUseDeltasEnabled()) + { + CRLDistPoint freshestCRL = null; + try + { + freshestCRL = CRLDistPoint + .getInstance(CertPathValidatorUtilities.getExtensionValue(cert, FRESHEST_CRL)); + } + catch (AnnotatedException e) + { + throw new AnnotatedException("Freshest CRL extension could not be decoded from certificate.", e); + } + if (freshestCRL == null) + { + try + { + freshestCRL = CRLDistPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(crl, + FRESHEST_CRL)); + } + catch (AnnotatedException e) + { + throw new AnnotatedException("Freshest CRL extension could not be decoded from CRL.", e); + } + } + if (freshestCRL != null) + { + try + { + CertPathValidatorUtilities.addAdditionalStoresFromCRLDistributionPoint(freshestCRL, paramsPKIX); + } + catch (AnnotatedException e) + { + throw new AnnotatedException( + "No new delta CRL locations could be added from Freshest CRL extension.", e); + } + // get delta CRL(s) + try + { + set.addAll(CertPathValidatorUtilities.getDeltaCRLs(currentDate, paramsPKIX, crl)); + } + catch (AnnotatedException e) + { + throw new AnnotatedException("Exception obtaining delta CRLs.", e); + } + } + } + return set; + } + + protected static Set[] processCRLA1ii( + Date currentDate, + ExtendedPKIXParameters paramsPKIX, + X509Certificate cert, + X509CRL crl) + throws AnnotatedException + { + Set deltaSet = new HashSet(); + X509CRLStoreSelector crlselect = new X509CRLStoreSelector(); + crlselect.setCertificateChecking(cert); + + try + { + crlselect.addIssuerName(PrincipalUtil.getIssuerX509Principal(crl).getEncoded()); + } + catch (CRLException e) + { + throw new AnnotatedException("Cannot extract issuer from CRL." + e, e); + } + catch (IOException e) + { + throw new AnnotatedException("Cannot extract issuer from CRL." + e, e); + } + + crlselect.setCompleteCRLEnabled(true); + Set completeSet = CRL_UTIL.findCRLs(crlselect, paramsPKIX, currentDate); + + if (paramsPKIX.isUseDeltasEnabled()) + { + // get delta CRL(s) + try + { + deltaSet.addAll(CertPathValidatorUtilities.getDeltaCRLs(currentDate, paramsPKIX, crl)); + } + catch (AnnotatedException e) + { + throw new AnnotatedException("Exception obtaining delta CRLs.", e); + } + } + return new Set[] + { + completeSet, + deltaSet}; + } + + + + /** + * If use-deltas is set, verify the issuer and scope of the delta CRL. + * + * @param deltaCRL The delta CRL. + * @param completeCRL The complete CRL. + * @param pkixParams The PKIX paramaters. + * @throws AnnotatedException if an exception occurs. + */ + protected static void processCRLC( + X509CRL deltaCRL, + X509CRL completeCRL, + ExtendedPKIXParameters pkixParams) + throws AnnotatedException + { + if (deltaCRL == null) + { + return; + } + IssuingDistributionPoint completeidp = null; + try + { + completeidp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue( + completeCRL, RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT)); + } + catch (Exception e) + { + throw new AnnotatedException("Issuing distribution point extension could not be decoded.", e); + } + + if (pkixParams.isUseDeltasEnabled()) + { + // (c) (1) + try + { + if (!PrincipalUtil.getIssuerX509Principal(deltaCRL).equals(PrincipalUtil.getIssuerX509Principal(completeCRL))) + { + throw new AnnotatedException("Complete CRL issuer does not match delta CRL issuer."); + } + } + catch (CRLException e) + { + throw new AnnotatedException( + "Cannot extract issuer from CRL.", e); + } + + // (c) (2) + IssuingDistributionPoint deltaidp = null; + try + { + deltaidp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue( + deltaCRL, ISSUING_DISTRIBUTION_POINT)); + } + catch (Exception e) + { + throw new AnnotatedException( + "Issuing distribution point extension from delta CRL could not be decoded.", e); + } + + boolean match = false; + if (completeidp == null) + { + if (deltaidp == null) + { + match = true; + } + } + else + { + if (completeidp.equals(deltaidp)) + { + match = true; + } + } + if (!match) + { + throw new AnnotatedException( + "Issuing distribution point extension from delta CRL and complete CRL does not match."); + } + + // (c) (3) + ASN1Primitive completeKeyIdentifier = null; + try + { + completeKeyIdentifier = CertPathValidatorUtilities.getExtensionValue( + completeCRL, AUTHORITY_KEY_IDENTIFIER); + } + catch (AnnotatedException e) + { + throw new AnnotatedException( + "Authority key identifier extension could not be extracted from complete CRL.", e); + } + + ASN1Primitive deltaKeyIdentifier = null; + try + { + deltaKeyIdentifier = CertPathValidatorUtilities.getExtensionValue( + deltaCRL, AUTHORITY_KEY_IDENTIFIER); + } + catch (AnnotatedException e) + { + throw new AnnotatedException( + "Authority key identifier extension could not be extracted from delta CRL.", e); + } + + if (completeKeyIdentifier == null) + { + throw new AnnotatedException("CRL authority key identifier is null."); + } + + if (deltaKeyIdentifier == null) + { + throw new AnnotatedException("Delta CRL authority key identifier is null."); + } + + if (!completeKeyIdentifier.equals(deltaKeyIdentifier)) + { + throw new AnnotatedException( + "Delta CRL authority key identifier does not match complete CRL authority key identifier."); + } + } + } + + protected static void processCRLI( + Date validDate, + X509CRL deltacrl, + Object cert, + CertStatus certStatus, + ExtendedPKIXParameters pkixParams) + throws AnnotatedException + { + if (pkixParams.isUseDeltasEnabled() && deltacrl != null) + { + CertPathValidatorUtilities.getCertStatus(validDate, deltacrl, cert, certStatus); + } + } + + protected static void processCRLJ( + Date validDate, + X509CRL completecrl, + Object cert, + CertStatus certStatus) + throws AnnotatedException + { + if (certStatus.getCertStatus() == CertStatus.UNREVOKED) + { + CertPathValidatorUtilities.getCertStatus(validDate, completecrl, cert, certStatus); + } + } + + protected static PKIXPolicyNode prepareCertB( + CertPath certPath, + int index, + List[] policyNodes, + PKIXPolicyNode validPolicyTree, + int policyMapping) + throws CertPathValidatorException + { + List certs = certPath.getCertificates(); + X509Certificate cert = (X509Certificate)certs.get(index); + int n = certs.size(); + // i as defined in the algorithm description + int i = n - index; + // (b) + // + ASN1Sequence pm = null; + try + { + pm = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, + RFC3280CertPathUtilities.POLICY_MAPPINGS)); + } + catch (AnnotatedException ex) + { + throw new ExtCertPathValidatorException("Policy mappings extension could not be decoded.", ex, certPath, + index); + } + PKIXPolicyNode _validPolicyTree = validPolicyTree; + if (pm != null) + { + ASN1Sequence mappings = (ASN1Sequence)pm; + Map m_idp = new HashMap(); + Set s_idp = new HashSet(); + + for (int j = 0; j < mappings.size(); j++) + { + ASN1Sequence mapping = (ASN1Sequence)mappings.getObjectAt(j); + String id_p = ((ASN1ObjectIdentifier)mapping.getObjectAt(0)).getId(); + String sd_p = ((ASN1ObjectIdentifier)mapping.getObjectAt(1)).getId(); + Set tmp; + + if (!m_idp.containsKey(id_p)) + { + tmp = new HashSet(); + tmp.add(sd_p); + m_idp.put(id_p, tmp); + s_idp.add(id_p); + } + else + { + tmp = (Set)m_idp.get(id_p); + tmp.add(sd_p); + } + } + + Iterator it_idp = s_idp.iterator(); + while (it_idp.hasNext()) + { + String id_p = (String)it_idp.next(); + + // + // (1) + // + if (policyMapping > 0) + { + boolean idp_found = false; + Iterator nodes_i = policyNodes[i].iterator(); + while (nodes_i.hasNext()) + { + PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next(); + if (node.getValidPolicy().equals(id_p)) + { + idp_found = true; + node.expectedPolicies = (Set)m_idp.get(id_p); + break; + } + } + + if (!idp_found) + { + nodes_i = policyNodes[i].iterator(); + while (nodes_i.hasNext()) + { + PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next(); + if (RFC3280CertPathUtilities.ANY_POLICY.equals(node.getValidPolicy())) + { + Set pq = null; + ASN1Sequence policies = null; + try + { + policies = (ASN1Sequence)CertPathValidatorUtilities.getExtensionValue(cert, + RFC3280CertPathUtilities.CERTIFICATE_POLICIES); + } + catch (AnnotatedException e) + { + throw new ExtCertPathValidatorException( + "Certificate policies extension could not be decoded.", e, certPath, index); + } + Enumeration e = policies.getObjects(); + while (e.hasMoreElements()) + { + PolicyInformation pinfo = null; + try + { + pinfo = PolicyInformation.getInstance(e.nextElement()); + } + catch (Exception ex) + { + throw new CertPathValidatorException( + "Policy information could not be decoded.", ex, certPath, index); + } + if (RFC3280CertPathUtilities.ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId())) + { + try + { + pq = CertPathValidatorUtilities + .getQualifierSet(pinfo.getPolicyQualifiers()); + } + catch (CertPathValidatorException ex) + { + + throw new ExtCertPathValidatorException( + "Policy qualifier info set could not be decoded.", ex, certPath, + index); + } + break; + } + } + boolean ci = false; + if (cert.getCriticalExtensionOIDs() != null) + { + ci = cert.getCriticalExtensionOIDs().contains( + RFC3280CertPathUtilities.CERTIFICATE_POLICIES); + } + + PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent(); + if (RFC3280CertPathUtilities.ANY_POLICY.equals(p_node.getValidPolicy())) + { + PKIXPolicyNode c_node = new PKIXPolicyNode(new ArrayList(), i, (Set)m_idp + .get(id_p), p_node, pq, id_p, ci); + p_node.addChild(c_node); + policyNodes[i].add(c_node); + } + break; + } + } + } + + // + // (2) + // + } + else if (policyMapping <= 0) + { + Iterator nodes_i = policyNodes[i].iterator(); + while (nodes_i.hasNext()) + { + PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next(); + if (node.getValidPolicy().equals(id_p)) + { + PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent(); + p_node.removeChild(node); + nodes_i.remove(); + for (int k = (i - 1); k >= 0; k--) + { + List nodes = policyNodes[k]; + for (int l = 0; l < nodes.size(); l++) + { + PKIXPolicyNode node2 = (PKIXPolicyNode)nodes.get(l); + if (!node2.hasChildren()) + { + _validPolicyTree = CertPathValidatorUtilities.removePolicyNode( + _validPolicyTree, policyNodes, node2); + if (_validPolicyTree == null) + { + break; + } + } + } + } + } + } + } + } + } + return _validPolicyTree; + } + + protected static void prepareNextCertA( + CertPath certPath, + int index) + throws CertPathValidatorException + { + List certs = certPath.getCertificates(); + X509Certificate cert = (X509Certificate)certs.get(index); + // + // + // (a) check the policy mappings + // + ASN1Sequence pm = null; + try + { + pm = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, + RFC3280CertPathUtilities.POLICY_MAPPINGS)); + } + catch (AnnotatedException ex) + { + throw new ExtCertPathValidatorException("Policy mappings extension could not be decoded.", ex, certPath, + index); + } + if (pm != null) + { + ASN1Sequence mappings = pm; + + for (int j = 0; j < mappings.size(); j++) + { + ASN1ObjectIdentifier issuerDomainPolicy = null; + ASN1ObjectIdentifier subjectDomainPolicy = null; + try + { + ASN1Sequence mapping = DERSequence.getInstance(mappings.getObjectAt(j)); + + issuerDomainPolicy = ASN1ObjectIdentifier.getInstance(mapping.getObjectAt(0)); + subjectDomainPolicy = ASN1ObjectIdentifier.getInstance(mapping.getObjectAt(1)); + } + catch (Exception e) + { + throw new ExtCertPathValidatorException("Policy mappings extension contents could not be decoded.", + e, certPath, index); + } + + if (RFC3280CertPathUtilities.ANY_POLICY.equals(issuerDomainPolicy.getId())) + { + + throw new CertPathValidatorException("IssuerDomainPolicy is anyPolicy", null, certPath, index); + } + + if (RFC3280CertPathUtilities.ANY_POLICY.equals(subjectDomainPolicy.getId())) + { + + throw new CertPathValidatorException("SubjectDomainPolicy is anyPolicy,", null, certPath, index); + } + } + } + } + + protected static void processCertF( + CertPath certPath, + int index, + PKIXPolicyNode validPolicyTree, + int explicitPolicy) + throws CertPathValidatorException + { + // + // (f) + // + if (explicitPolicy <= 0 && validPolicyTree == null) + { + throw new ExtCertPathValidatorException("No valid policy tree found when one expected.", null, certPath, + index); + } + } + + protected static PKIXPolicyNode processCertE( + CertPath certPath, + int index, + PKIXPolicyNode validPolicyTree) + throws CertPathValidatorException + { + List certs = certPath.getCertificates(); + X509Certificate cert = (X509Certificate)certs.get(index); + // + // (e) + // + ASN1Sequence certPolicies = null; + try + { + certPolicies = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, + RFC3280CertPathUtilities.CERTIFICATE_POLICIES)); + } + catch (AnnotatedException e) + { + throw new ExtCertPathValidatorException("Could not read certificate policies extension from certificate.", + e, certPath, index); + } + if (certPolicies == null) + { + validPolicyTree = null; + } + return validPolicyTree; + } + + protected static void processCertBC( + CertPath certPath, + int index, + PKIXNameConstraintValidator nameConstraintValidator) + throws CertPathValidatorException + { + List certs = certPath.getCertificates(); + X509Certificate cert = (X509Certificate)certs.get(index); + int n = certs.size(); + // i as defined in the algorithm description + int i = n - index; + // + // (b), (c) permitted and excluded subtree checking. + // + if (!(CertPathValidatorUtilities.isSelfIssued(cert) && (i < n))) + { + X509Principal principal = CertPathValidatorUtilities.getSubjectPrincipal(cert); + ASN1InputStream aIn = new ASN1InputStream(principal.getEncoded()); + ASN1Sequence dns; + + try + { + dns = DERSequence.getInstance(aIn.readObject()); + } + catch (Exception e) + { + throw new CertPathValidatorException("Exception extracting subject name when checking subtrees.", e, + certPath, index); + } + + try + { + nameConstraintValidator.checkPermittedDN(dns); + nameConstraintValidator.checkExcludedDN(dns); + } + catch (PKIXNameConstraintValidatorException e) + { + throw new CertPathValidatorException("Subtree check for certificate subject failed.", e, certPath, + index); + } + + GeneralNames altName = null; + try + { + altName = GeneralNames.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, + RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME)); + } + catch (Exception e) + { + throw new CertPathValidatorException("Subject alternative name extension could not be decoded.", e, + certPath, index); + } + Vector emails = new X509Name(dns).getValues(X509Name.EmailAddress); + for (Enumeration e = emails.elements(); e.hasMoreElements();) + { + String email = (String)e.nextElement(); + GeneralName emailAsGeneralName = new GeneralName(GeneralName.rfc822Name, email); + try + { + nameConstraintValidator.checkPermitted(emailAsGeneralName); + nameConstraintValidator.checkExcluded(emailAsGeneralName); + } + catch (PKIXNameConstraintValidatorException ex) + { + throw new CertPathValidatorException( + "Subtree check for certificate subject alternative email failed.", ex, certPath, index); + } + } + if (altName != null) + { + GeneralName[] genNames = null; + try + { + genNames = altName.getNames(); + } + catch (Exception e) + { + throw new CertPathValidatorException("Subject alternative name contents could not be decoded.", e, + certPath, index); + } + for (int j = 0; j < genNames.length; j++) + { + + try + { + nameConstraintValidator.checkPermitted(genNames[j]); + nameConstraintValidator.checkExcluded(genNames[j]); + } + catch (PKIXNameConstraintValidatorException e) + { + throw new CertPathValidatorException( + "Subtree check for certificate subject alternative name failed.", e, certPath, index); + } + } + } + } + } + + protected static PKIXPolicyNode processCertD( + CertPath certPath, + int index, + Set acceptablePolicies, + PKIXPolicyNode validPolicyTree, + List[] policyNodes, + int inhibitAnyPolicy) + throws CertPathValidatorException + { + List certs = certPath.getCertificates(); + X509Certificate cert = (X509Certificate)certs.get(index); + int n = certs.size(); + // i as defined in the algorithm description + int i = n - index; + // + // (d) policy Information checking against initial policy and + // policy mapping + // + ASN1Sequence certPolicies = null; + try + { + certPolicies = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, + RFC3280CertPathUtilities.CERTIFICATE_POLICIES)); + } + catch (AnnotatedException e) + { + throw new ExtCertPathValidatorException("Could not read certificate policies extension from certificate.", + e, certPath, index); + } + if (certPolicies != null && validPolicyTree != null) + { + // + // (d) (1) + // + Enumeration e = certPolicies.getObjects(); + Set pols = new HashSet(); + + while (e.hasMoreElements()) + { + PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement()); + ASN1ObjectIdentifier pOid = pInfo.getPolicyIdentifier(); + + pols.add(pOid.getId()); + + if (!RFC3280CertPathUtilities.ANY_POLICY.equals(pOid.getId())) + { + Set pq = null; + try + { + pq = CertPathValidatorUtilities.getQualifierSet(pInfo.getPolicyQualifiers()); + } + catch (CertPathValidatorException ex) + { + throw new ExtCertPathValidatorException("Policy qualifier info set could not be build.", ex, + certPath, index); + } + + boolean match = CertPathValidatorUtilities.processCertD1i(i, policyNodes, pOid, pq); + + if (!match) + { + CertPathValidatorUtilities.processCertD1ii(i, policyNodes, pOid, pq); + } + } + } + + if (acceptablePolicies.isEmpty() || acceptablePolicies.contains(RFC3280CertPathUtilities.ANY_POLICY)) + { + acceptablePolicies.clear(); + acceptablePolicies.addAll(pols); + } + else + { + Iterator it = acceptablePolicies.iterator(); + Set t1 = new HashSet(); + + while (it.hasNext()) + { + Object o = it.next(); + + if (pols.contains(o)) + { + t1.add(o); + } + } + acceptablePolicies.clear(); + acceptablePolicies.addAll(t1); + } + + // + // (d) (2) + // + if ((inhibitAnyPolicy > 0) || ((i < n) && CertPathValidatorUtilities.isSelfIssued(cert))) + { + e = certPolicies.getObjects(); + + while (e.hasMoreElements()) + { + PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement()); + + if (RFC3280CertPathUtilities.ANY_POLICY.equals(pInfo.getPolicyIdentifier().getId())) + { + Set _apq = CertPathValidatorUtilities.getQualifierSet(pInfo.getPolicyQualifiers()); + List _nodes = policyNodes[i - 1]; + + for (int k = 0; k < _nodes.size(); k++) + { + PKIXPolicyNode _node = (PKIXPolicyNode)_nodes.get(k); + + Iterator _policySetIter = _node.getExpectedPolicies().iterator(); + while (_policySetIter.hasNext()) + { + Object _tmp = _policySetIter.next(); + + String _policy; + if (_tmp instanceof String) + { + _policy = (String)_tmp; + } + else if (_tmp instanceof ASN1ObjectIdentifier) + { + _policy = ((ASN1ObjectIdentifier)_tmp).getId(); + } + else + { + continue; + } + + boolean _found = false; + Iterator _childrenIter = _node.getChildren(); + + while (_childrenIter.hasNext()) + { + PKIXPolicyNode _child = (PKIXPolicyNode)_childrenIter.next(); + + if (_policy.equals(_child.getValidPolicy())) + { + _found = true; + } + } + + if (!_found) + { + Set _newChildExpectedPolicies = new HashSet(); + _newChildExpectedPolicies.add(_policy); + + PKIXPolicyNode _newChild = new PKIXPolicyNode(new ArrayList(), i, + _newChildExpectedPolicies, _node, _apq, _policy, false); + _node.addChild(_newChild); + policyNodes[i].add(_newChild); + } + } + } + break; + } + } + } + + PKIXPolicyNode _validPolicyTree = validPolicyTree; + // + // (d) (3) + // + for (int j = (i - 1); j >= 0; j--) + { + List nodes = policyNodes[j]; + + for (int k = 0; k < nodes.size(); k++) + { + PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k); + if (!node.hasChildren()) + { + _validPolicyTree = CertPathValidatorUtilities.removePolicyNode(_validPolicyTree, policyNodes, + node); + if (_validPolicyTree == null) + { + break; + } + } + } + } + + // + // d (4) + // + Set criticalExtensionOids = cert.getCriticalExtensionOIDs(); + + if (criticalExtensionOids != null) + { + boolean critical = criticalExtensionOids.contains(RFC3280CertPathUtilities.CERTIFICATE_POLICIES); + + List nodes = policyNodes[i]; + for (int j = 0; j < nodes.size(); j++) + { + PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(j); + node.setCritical(critical); + } + } + return _validPolicyTree; + } + return null; + } + + protected static void processCertA( + CertPath certPath, + ExtendedPKIXParameters paramsPKIX, + int index, + PublicKey workingPublicKey, + boolean verificationAlreadyPerformed, + X509Principal workingIssuerName, + X509Certificate sign) + throws ExtCertPathValidatorException + { + List certs = certPath.getCertificates(); + X509Certificate cert = (X509Certificate)certs.get(index); + // + // (a) verify + // + if (!verificationAlreadyPerformed) + { + try + { + // (a) (1) + // + CertPathValidatorUtilities.verifyX509Certificate(cert, workingPublicKey, + paramsPKIX.getSigProvider()); + } + catch (GeneralSecurityException e) + { + throw new ExtCertPathValidatorException("Could not validate certificate signature.", e, certPath, index); + } + } + + try + { + // (a) (2) + // + cert.checkValidity(CertPathValidatorUtilities + .getValidCertDateFromValidityModel(paramsPKIX, certPath, index)); + } + catch (CertificateExpiredException e) + { + throw new ExtCertPathValidatorException("Could not validate certificate: " + e.getMessage(), e, certPath, index); + } + catch (CertificateNotYetValidException e) + { + throw new ExtCertPathValidatorException("Could not validate certificate: " + e.getMessage(), e, certPath, index); + } + catch (AnnotatedException e) + { + throw new ExtCertPathValidatorException("Could not validate time of certificate.", e, certPath, index); + } + + // + // (a) (3) + // + if (paramsPKIX.isRevocationEnabled()) + { + try + { + checkCRLs(paramsPKIX, cert, CertPathValidatorUtilities.getValidCertDateFromValidityModel(paramsPKIX, + certPath, index), sign, workingPublicKey, certs); + } + catch (AnnotatedException e) + { + Throwable cause = e; + if (null != e.getCause()) + { + cause = e.getCause(); + } + throw new ExtCertPathValidatorException(e.getMessage(), cause, certPath, index); + } + } + + // + // (a) (4) name chaining + // + if (!CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert).equals(workingIssuerName)) + { + throw new ExtCertPathValidatorException("IssuerName(" + CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert) + + ") does not match SubjectName(" + workingIssuerName + ") of signing certificate.", null, + certPath, index); + } + } + + protected static int prepareNextCertI1( + CertPath certPath, + int index, + int explicitPolicy) + throws CertPathValidatorException + { + List certs = certPath.getCertificates(); + X509Certificate cert = (X509Certificate)certs.get(index); + // + // (i) + // + ASN1Sequence pc = null; + try + { + pc = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, + RFC3280CertPathUtilities.POLICY_CONSTRAINTS)); + } + catch (Exception e) + { + throw new ExtCertPathValidatorException("Policy constraints extension cannot be decoded.", e, certPath, + index); + } + + int tmpInt; + + if (pc != null) + { + Enumeration policyConstraints = pc.getObjects(); + + while (policyConstraints.hasMoreElements()) + { + try + { + + ASN1TaggedObject constraint = ASN1TaggedObject.getInstance(policyConstraints.nextElement()); + if (constraint.getTagNo() == 0) + { + tmpInt = ASN1Integer.getInstance(constraint, false).getValue().intValue(); + if (tmpInt < explicitPolicy) + { + return tmpInt; + } + break; + } + } + catch (IllegalArgumentException e) + { + throw new ExtCertPathValidatorException("Policy constraints extension contents cannot be decoded.", + e, certPath, index); + } + } + } + return explicitPolicy; + } + + protected static int prepareNextCertI2( + CertPath certPath, + int index, + int policyMapping) + throws CertPathValidatorException + { + List certs = certPath.getCertificates(); + X509Certificate cert = (X509Certificate)certs.get(index); + // + // (i) + // + ASN1Sequence pc = null; + try + { + pc = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, + RFC3280CertPathUtilities.POLICY_CONSTRAINTS)); + } + catch (Exception e) + { + throw new ExtCertPathValidatorException("Policy constraints extension cannot be decoded.", e, certPath, + index); + } + + int tmpInt; + + if (pc != null) + { + Enumeration policyConstraints = pc.getObjects(); + + while (policyConstraints.hasMoreElements()) + { + try + { + ASN1TaggedObject constraint = ASN1TaggedObject.getInstance(policyConstraints.nextElement()); + if (constraint.getTagNo() == 1) + { + tmpInt = ASN1Integer.getInstance(constraint, false).getValue().intValue(); + if (tmpInt < policyMapping) + { + return tmpInt; + } + break; + } + } + catch (IllegalArgumentException e) + { + throw new ExtCertPathValidatorException("Policy constraints extension contents cannot be decoded.", + e, certPath, index); + } + } + } + return policyMapping; + } + + protected static void prepareNextCertG( + CertPath certPath, + int index, + PKIXNameConstraintValidator nameConstraintValidator) + throws CertPathValidatorException + { + List certs = certPath.getCertificates(); + X509Certificate cert = (X509Certificate)certs.get(index); + // + // (g) handle the name constraints extension + // + NameConstraints nc = null; + try + { + ASN1Sequence ncSeq = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, + RFC3280CertPathUtilities.NAME_CONSTRAINTS)); + if (ncSeq != null) + { + nc = NameConstraints.getInstance(ncSeq); + } + } + catch (Exception e) + { + throw new ExtCertPathValidatorException("Name constraints extension could not be decoded.", e, certPath, + index); + } + if (nc != null) + { + + // + // (g) (1) permitted subtrees + // + GeneralSubtree[] permitted = nc.getPermittedSubtrees(); + if (permitted != null) + { + try + { + nameConstraintValidator.intersectPermittedSubtree(permitted); + } + catch (Exception ex) + { + throw new ExtCertPathValidatorException( + "Permitted subtrees cannot be build from name constraints extension.", ex, certPath, index); + } + } + + // + // (g) (2) excluded subtrees + // + GeneralSubtree[] excluded = nc.getExcludedSubtrees(); + if (excluded != null) + { + for (int i = 0; i != excluded.length; i++) + try + { + nameConstraintValidator.addExcludedSubtree(excluded[i]); + } + catch (Exception ex) + { + throw new ExtCertPathValidatorException( + "Excluded subtrees cannot be build from name constraints extension.", ex, certPath, index); + } + } + } + } + + /** + * Checks a distribution point for revocation information for the + * certificate <code>cert</code>. + * + * @param dp The distribution point to consider. + * @param paramsPKIX PKIX parameters. + * @param cert Certificate to check if it is revoked. + * @param validDate The date when the certificate revocation status should be + * checked. + * @param defaultCRLSignCert The issuer certificate of the certificate <code>cert</code>. + * @param defaultCRLSignKey The public key of the issuer certificate + * <code>defaultCRLSignCert</code>. + * @param certStatus The current certificate revocation status. + * @param reasonMask The reasons mask which is already checked. + * @param certPathCerts The certificates of the certification path. + * @throws AnnotatedException if the certificate is revoked or the status cannot be checked + * or some error occurs. + */ + private static void checkCRL( + DistributionPoint dp, + ExtendedPKIXParameters paramsPKIX, + X509Certificate cert, + Date validDate, + X509Certificate defaultCRLSignCert, + PublicKey defaultCRLSignKey, + CertStatus certStatus, + ReasonsMask reasonMask, + List certPathCerts) + throws AnnotatedException + { + Date currentDate = new Date(System.currentTimeMillis()); + if (validDate.getTime() > currentDate.getTime()) + { + throw new AnnotatedException("Validation time is in future."); + } + + // (a) + /* + * We always get timely valid CRLs, so there is no step (a) (1). + * "locally cached" CRLs are assumed to be in getStore(), additional + * CRLs must be enabled in the ExtendedPKIXParameters and are in + * getAdditionalStore() + */ + + Set crls = CertPathValidatorUtilities.getCompleteCRLs(dp, cert, currentDate, paramsPKIX); + boolean validCrlFound = false; + AnnotatedException lastException = null; + Iterator crl_iter = crls.iterator(); + + while (crl_iter.hasNext() && certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonMask.isAllReasons()) + { + try + { + X509CRL crl = (X509CRL)crl_iter.next(); + + // (d) + ReasonsMask interimReasonsMask = RFC3280CertPathUtilities.processCRLD(crl, dp); + + // (e) + /* + * The reasons mask is updated at the end, so only valid CRLs + * can update it. If this CRL does not contain new reasons it + * must be ignored. + */ + if (!interimReasonsMask.hasNewReasons(reasonMask)) + { + continue; + } + + // (f) + Set keys = RFC3280CertPathUtilities.processCRLF(crl, cert, defaultCRLSignCert, defaultCRLSignKey, + paramsPKIX, certPathCerts); + // (g) + PublicKey key = RFC3280CertPathUtilities.processCRLG(crl, keys); + + X509CRL deltaCRL = null; + + if (paramsPKIX.isUseDeltasEnabled()) + { + // get delta CRLs + Set deltaCRLs = CertPathValidatorUtilities.getDeltaCRLs(currentDate, paramsPKIX, crl); + // we only want one valid delta CRL + // (h) + deltaCRL = RFC3280CertPathUtilities.processCRLH(deltaCRLs, key); + } + + /* + * CRL must be be valid at the current time, not the validation + * time. If a certificate is revoked with reason keyCompromise, + * cACompromise, it can be used for forgery, also for the past. + * This reason may not be contained in older CRLs. + */ + + /* + * in the chain model signatures stay valid also after the + * certificate has been expired, so they do not have to be in + * the CRL validity time + */ + + if (paramsPKIX.getValidityModel() != ExtendedPKIXParameters.CHAIN_VALIDITY_MODEL) + { + /* + * if a certificate has expired, but was revoked, it is not + * more in the CRL, so it would be regarded as valid if the + * first check is not done + */ + if (cert.getNotAfter().getTime() < crl.getThisUpdate().getTime()) + { + throw new AnnotatedException("No valid CRL for current time found."); + } + } + + RFC3280CertPathUtilities.processCRLB1(dp, cert, crl); + + // (b) (2) + RFC3280CertPathUtilities.processCRLB2(dp, cert, crl); + + // (c) + RFC3280CertPathUtilities.processCRLC(deltaCRL, crl, paramsPKIX); + + // (i) + RFC3280CertPathUtilities.processCRLI(validDate, deltaCRL, cert, certStatus, paramsPKIX); + + // (j) + RFC3280CertPathUtilities.processCRLJ(validDate, crl, cert, certStatus); + + // (k) + if (certStatus.getCertStatus() == CRLReason.removeFromCRL) + { + certStatus.setCertStatus(CertStatus.UNREVOKED); + } + + // update reasons mask + reasonMask.addReasons(interimReasonsMask); + + Set criticalExtensions = crl.getCriticalExtensionOIDs(); + if (criticalExtensions != null) + { + criticalExtensions = new HashSet(criticalExtensions); + criticalExtensions.remove(X509Extensions.IssuingDistributionPoint.getId()); + criticalExtensions.remove(X509Extensions.DeltaCRLIndicator.getId()); + + if (!criticalExtensions.isEmpty()) + { + throw new AnnotatedException("CRL contains unsupported critical extensions."); + } + } + + if (deltaCRL != null) + { + criticalExtensions = deltaCRL.getCriticalExtensionOIDs(); + if (criticalExtensions != null) + { + criticalExtensions = new HashSet(criticalExtensions); + criticalExtensions.remove(X509Extensions.IssuingDistributionPoint.getId()); + criticalExtensions.remove(X509Extensions.DeltaCRLIndicator.getId()); + if (!criticalExtensions.isEmpty()) + { + throw new AnnotatedException("Delta CRL contains unsupported critical extension."); + } + } + } + + validCrlFound = true; + } + catch (AnnotatedException e) + { + lastException = e; + } + } + if (!validCrlFound) + { + throw lastException; + } + } + + /** + * Checks a certificate if it is revoked. + * + * @param paramsPKIX PKIX parameters. + * @param cert Certificate to check if it is revoked. + * @param validDate The date when the certificate revocation status should be + * checked. + * @param sign The issuer certificate of the certificate <code>cert</code>. + * @param workingPublicKey The public key of the issuer certificate <code>sign</code>. + * @param certPathCerts The certificates of the certification path. + * @throws AnnotatedException if the certificate is revoked or the status cannot be checked + * or some error occurs. + */ + protected static void checkCRLs( + ExtendedPKIXParameters paramsPKIX, + X509Certificate cert, + Date validDate, + X509Certificate sign, + PublicKey workingPublicKey, + List certPathCerts) + throws AnnotatedException + { + AnnotatedException lastException = null; + CRLDistPoint crldp = null; + try + { + crldp = CRLDistPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, + RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS)); + } + catch (Exception e) + { + throw new AnnotatedException("CRL distribution point extension could not be read.", e); + } + try + { + CertPathValidatorUtilities.addAdditionalStoresFromCRLDistributionPoint(crldp, paramsPKIX); + } + catch (AnnotatedException e) + { + throw new AnnotatedException( + "No additional CRL locations could be decoded from CRL distribution point extension.", e); + } + CertStatus certStatus = new CertStatus(); + ReasonsMask reasonsMask = new ReasonsMask(); + + boolean validCrlFound = false; + // for each distribution point + if (crldp != null) + { + DistributionPoint dps[] = null; + try + { + dps = crldp.getDistributionPoints(); + } + catch (Exception e) + { + throw new AnnotatedException("Distribution points could not be read.", e); + } + if (dps != null) + { + for (int i = 0; i < dps.length && certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonsMask.isAllReasons(); i++) + { + ExtendedPKIXParameters paramsPKIXClone = (ExtendedPKIXParameters)paramsPKIX.clone(); + try + { + checkCRL(dps[i], paramsPKIXClone, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask, certPathCerts); + validCrlFound = true; + } + catch (AnnotatedException e) + { + lastException = e; + } + } + } + } + + /* + * If the revocation status has not been determined, repeat the process + * above with any available CRLs not specified in a distribution point + * but issued by the certificate issuer. + */ + + if (certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonsMask.isAllReasons()) + { + try + { + /* + * assume a DP with both the reasons and the cRLIssuer fields + * omitted and a distribution point name of the certificate + * issuer. + */ + ASN1Primitive issuer = null; + try + { + issuer = new ASN1InputStream(CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert).getEncoded()) + .readObject(); + } + catch (Exception e) + { + throw new AnnotatedException("Issuer from certificate for CRL could not be reencoded.", e); + } + DistributionPoint dp = new DistributionPoint(new DistributionPointName(0, new GeneralNames( + new GeneralName(GeneralName.directoryName, issuer))), null, null); + ExtendedPKIXParameters paramsPKIXClone = (ExtendedPKIXParameters)paramsPKIX.clone(); + checkCRL(dp, paramsPKIXClone, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask, + certPathCerts); + validCrlFound = true; + } + catch (AnnotatedException e) + { + lastException = e; + } + } + + if (!validCrlFound) + { + if (lastException instanceof AnnotatedException) + { + throw lastException; + } + + throw new AnnotatedException("No valid CRL found.", lastException); + } + if (certStatus.getCertStatus() != CertStatus.UNREVOKED) + { + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss +0000"); + df.setTimeZone(TimeZone.getTimeZone("UTC")); + String message = "Certificate revocation after " + df.format(certStatus.getRevocationDate()); + message += ", reason: " + crlReasons[certStatus.getCertStatus()]; + throw new AnnotatedException(message); + } + if (!reasonsMask.isAllReasons() && certStatus.getCertStatus() == CertStatus.UNREVOKED) + { + certStatus.setCertStatus(CertStatus.UNDETERMINED); + } + if (certStatus.getCertStatus() == CertStatus.UNDETERMINED) + { + throw new AnnotatedException("Certificate status could not be determined."); + } + } + + protected static int prepareNextCertJ( + CertPath certPath, + int index, + int inhibitAnyPolicy) + throws CertPathValidatorException + { + List certs = certPath.getCertificates(); + X509Certificate cert = (X509Certificate)certs.get(index); + // + // (j) + // + ASN1Integer iap = null; + try + { + iap = ASN1Integer.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, + RFC3280CertPathUtilities.INHIBIT_ANY_POLICY)); + } + catch (Exception e) + { + throw new ExtCertPathValidatorException("Inhibit any-policy extension cannot be decoded.", e, certPath, + index); + } + + if (iap != null) + { + int _inhibitAnyPolicy = iap.getValue().intValue(); + + if (_inhibitAnyPolicy < inhibitAnyPolicy) + { + return _inhibitAnyPolicy; + } + } + return inhibitAnyPolicy; + } + + protected static void prepareNextCertK( + CertPath certPath, + int index) + throws CertPathValidatorException + { + List certs = certPath.getCertificates(); + X509Certificate cert = (X509Certificate)certs.get(index); + // + // (k) + // + BasicConstraints bc = null; + try + { + bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, + RFC3280CertPathUtilities.BASIC_CONSTRAINTS)); + } + catch (Exception e) + { + throw new ExtCertPathValidatorException("Basic constraints extension cannot be decoded.", e, certPath, + index); + } + if (bc != null) + { + if (!(bc.isCA())) + { + throw new CertPathValidatorException("Not a CA certificate"); + } + } + else + { + throw new CertPathValidatorException("Intermediate certificate lacks BasicConstraints"); + } + } + + protected static int prepareNextCertL( + CertPath certPath, + int index, + int maxPathLength) + throws CertPathValidatorException + { + List certs = certPath.getCertificates(); + X509Certificate cert = (X509Certificate)certs.get(index); + // + // (l) + // + if (!CertPathValidatorUtilities.isSelfIssued(cert)) + { + if (maxPathLength <= 0) + { + throw new ExtCertPathValidatorException("Max path length not greater than zero", null, certPath, index); + } + + return maxPathLength - 1; + } + return maxPathLength; + } + + protected static int prepareNextCertM( + CertPath certPath, + int index, + int maxPathLength) + throws CertPathValidatorException + { + List certs = certPath.getCertificates(); + X509Certificate cert = (X509Certificate)certs.get(index); + + // + // (m) + // + BasicConstraints bc = null; + try + { + bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, + RFC3280CertPathUtilities.BASIC_CONSTRAINTS)); + } + catch (Exception e) + { + throw new ExtCertPathValidatorException("Basic constraints extension cannot be decoded.", e, certPath, + index); + } + if (bc != null) + { + BigInteger _pathLengthConstraint = bc.getPathLenConstraint(); + + if (_pathLengthConstraint != null) + { + int _plc = _pathLengthConstraint.intValue(); + + if (_plc < maxPathLength) + { + return _plc; + } + } + } + return maxPathLength; + } + + protected static void prepareNextCertN( + CertPath certPath, + int index) + throws CertPathValidatorException + { + List certs = certPath.getCertificates(); + X509Certificate cert = (X509Certificate)certs.get(index); + + // + // (n) + // + boolean[] _usage = cert.getKeyUsage(); + + if ((_usage != null) && !_usage[RFC3280CertPathUtilities.KEY_CERT_SIGN]) + { + throw new ExtCertPathValidatorException( + "Issuer certificate keyusage extension is critical and does not permit key signing.", null, + certPath, index); + } + } + + protected static void prepareNextCertO( + CertPath certPath, + int index, + Set criticalExtensions, + List pathCheckers) + throws CertPathValidatorException + { + List certs = certPath.getCertificates(); + X509Certificate cert = (X509Certificate)certs.get(index); + // + // (o) + // + + Iterator tmpIter; + tmpIter = pathCheckers.iterator(); + while (tmpIter.hasNext()) + { + try + { + ((PKIXCertPathChecker)tmpIter.next()).check(cert, criticalExtensions); + } + catch (CertPathValidatorException e) + { + throw new CertPathValidatorException(e.getMessage(), e.getCause(), certPath, index); + } + } + if (!criticalExtensions.isEmpty()) + { + throw new ExtCertPathValidatorException("Certificate has unsupported critical extension: " + criticalExtensions, null, certPath, + index); + } + } + + protected static int prepareNextCertH1( + CertPath certPath, + int index, + int explicitPolicy) + { + List certs = certPath.getCertificates(); + X509Certificate cert = (X509Certificate)certs.get(index); + // + // (h) + // + if (!CertPathValidatorUtilities.isSelfIssued(cert)) + { + // + // (1) + // + if (explicitPolicy != 0) + { + return explicitPolicy - 1; + } + } + return explicitPolicy; + } + + protected static int prepareNextCertH2( + CertPath certPath, + int index, + int policyMapping) + { + List certs = certPath.getCertificates(); + X509Certificate cert = (X509Certificate)certs.get(index); + // + // (h) + // + if (!CertPathValidatorUtilities.isSelfIssued(cert)) + { + // + // (2) + // + if (policyMapping != 0) + { + return policyMapping - 1; + } + } + return policyMapping; + } + + protected static int prepareNextCertH3( + CertPath certPath, + int index, + int inhibitAnyPolicy) + { + List certs = certPath.getCertificates(); + X509Certificate cert = (X509Certificate)certs.get(index); + // + // (h) + // + if (!CertPathValidatorUtilities.isSelfIssued(cert)) + { + // + // (3) + // + if (inhibitAnyPolicy != 0) + { + return inhibitAnyPolicy - 1; + } + } + return inhibitAnyPolicy; + } + + protected static final String[] crlReasons = new String[] + { + "unspecified", + "keyCompromise", + "cACompromise", + "affiliationChanged", + "superseded", + "cessationOfOperation", + "certificateHold", + "unknown", + "removeFromCRL", + "privilegeWithdrawn", + "aACompromise"}; + + protected static int wrapupCertA( + int explicitPolicy, + X509Certificate cert) + { + // + // (a) + // + if (!CertPathValidatorUtilities.isSelfIssued(cert) && (explicitPolicy != 0)) + { + explicitPolicy--; + } + return explicitPolicy; + } + + protected static int wrapupCertB( + CertPath certPath, + int index, + int explicitPolicy) + throws CertPathValidatorException + { + List certs = certPath.getCertificates(); + X509Certificate cert = (X509Certificate)certs.get(index); + // + // (b) + // + int tmpInt; + ASN1Sequence pc = null; + try + { + pc = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, + RFC3280CertPathUtilities.POLICY_CONSTRAINTS)); + } + catch (AnnotatedException e) + { + throw new ExtCertPathValidatorException("Policy constraints could not be decoded.", e, certPath, index); + } + if (pc != null) + { + Enumeration policyConstraints = pc.getObjects(); + + while (policyConstraints.hasMoreElements()) + { + ASN1TaggedObject constraint = (ASN1TaggedObject)policyConstraints.nextElement(); + switch (constraint.getTagNo()) + { + case 0: + try + { + tmpInt = ASN1Integer.getInstance(constraint, false).getValue().intValue(); + } + catch (Exception e) + { + throw new ExtCertPathValidatorException( + "Policy constraints requireExplicitPolicy field could not be decoded.", e, certPath, + index); + } + if (tmpInt == 0) + { + return 0; + } + break; + } + } + } + return explicitPolicy; + } + + protected static void wrapupCertF( + CertPath certPath, + int index, + List pathCheckers, + Set criticalExtensions) + throws CertPathValidatorException + { + List certs = certPath.getCertificates(); + X509Certificate cert = (X509Certificate)certs.get(index); + Iterator tmpIter; + tmpIter = pathCheckers.iterator(); + while (tmpIter.hasNext()) + { + try + { + ((PKIXCertPathChecker)tmpIter.next()).check(cert, criticalExtensions); + } + catch (CertPathValidatorException e) + { + throw new ExtCertPathValidatorException("Additional certificate path checker failed.", e, certPath, + index); + } + } + + if (!criticalExtensions.isEmpty()) + { + throw new ExtCertPathValidatorException("Certificate has unsupported critical extension: " + criticalExtensions, null, certPath, + index); + } + } + + protected static PKIXPolicyNode wrapupCertG( + CertPath certPath, + ExtendedPKIXParameters paramsPKIX, + Set userInitialPolicySet, + int index, + List[] policyNodes, + PKIXPolicyNode validPolicyTree, + Set acceptablePolicies) + throws CertPathValidatorException + { + int n = certPath.getCertificates().size(); + // + // (g) + // + PKIXPolicyNode intersection; + + // + // (g) (i) + // + if (validPolicyTree == null) + { + if (paramsPKIX.isExplicitPolicyRequired()) + { + throw new ExtCertPathValidatorException("Explicit policy requested but none available.", null, + certPath, index); + } + intersection = null; + } + else if (CertPathValidatorUtilities.isAnyPolicy(userInitialPolicySet)) // (g) + // (ii) + { + if (paramsPKIX.isExplicitPolicyRequired()) + { + if (acceptablePolicies.isEmpty()) + { + throw new ExtCertPathValidatorException("Explicit policy requested but none available.", null, + certPath, index); + } + else + { + Set _validPolicyNodeSet = new HashSet(); + + for (int j = 0; j < policyNodes.length; j++) + { + List _nodeDepth = policyNodes[j]; + + for (int k = 0; k < _nodeDepth.size(); k++) + { + PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k); + + if (RFC3280CertPathUtilities.ANY_POLICY.equals(_node.getValidPolicy())) + { + Iterator _iter = _node.getChildren(); + while (_iter.hasNext()) + { + _validPolicyNodeSet.add(_iter.next()); + } + } + } + } + + Iterator _vpnsIter = _validPolicyNodeSet.iterator(); + while (_vpnsIter.hasNext()) + { + PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next(); + String _validPolicy = _node.getValidPolicy(); + + if (!acceptablePolicies.contains(_validPolicy)) + { + // validPolicyTree = + // removePolicyNode(validPolicyTree, policyNodes, + // _node); + } + } + if (validPolicyTree != null) + { + for (int j = (n - 1); j >= 0; j--) + { + List nodes = policyNodes[j]; + + for (int k = 0; k < nodes.size(); k++) + { + PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k); + if (!node.hasChildren()) + { + validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, + policyNodes, node); + } + } + } + } + } + } + + intersection = validPolicyTree; + } + else + { + // + // (g) (iii) + // + // This implementation is not exactly same as the one described in + // RFC3280. + // However, as far as the validation result is concerned, both + // produce + // adequate result. The only difference is whether AnyPolicy is + // remain + // in the policy tree or not. + // + // (g) (iii) 1 + // + Set _validPolicyNodeSet = new HashSet(); + + for (int j = 0; j < policyNodes.length; j++) + { + List _nodeDepth = policyNodes[j]; + + for (int k = 0; k < _nodeDepth.size(); k++) + { + PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k); + + if (RFC3280CertPathUtilities.ANY_POLICY.equals(_node.getValidPolicy())) + { + Iterator _iter = _node.getChildren(); + while (_iter.hasNext()) + { + PKIXPolicyNode _c_node = (PKIXPolicyNode)_iter.next(); + if (!RFC3280CertPathUtilities.ANY_POLICY.equals(_c_node.getValidPolicy())) + { + _validPolicyNodeSet.add(_c_node); + } + } + } + } + } + + // + // (g) (iii) 2 + // + Iterator _vpnsIter = _validPolicyNodeSet.iterator(); + while (_vpnsIter.hasNext()) + { + PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next(); + String _validPolicy = _node.getValidPolicy(); + + if (!userInitialPolicySet.contains(_validPolicy)) + { + validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes, _node); + } + } + + // + // (g) (iii) 4 + // + if (validPolicyTree != null) + { + for (int j = (n - 1); j >= 0; j--) + { + List nodes = policyNodes[j]; + + for (int k = 0; k < nodes.size(); k++) + { + PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k); + if (!node.hasChildren()) + { + validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes, + node); + } + } + } + } + + intersection = validPolicyTree; + } + return intersection; + } + +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CRLEntryObject.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CRLEntryObject.java new file mode 100644 index 00000000..dd0a32c9 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CRLEntryObject.java @@ -0,0 +1,293 @@ +package org.spongycastle.jce.provider; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.cert.CRLException; +import java.security.cert.X509CRLEntry; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Set; + +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Enumerated; +import org.spongycastle.asn1.util.ASN1Dump; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.CRLReason; +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.asn1.x509.Extensions; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.asn1.x509.GeneralNames; +import org.spongycastle.asn1.x509.TBSCertList; +import org.spongycastle.asn1.x509.X509Extension; +import org.spongycastle.x509.extension.X509ExtensionUtil; +import org.spongycastle.jce.X509Principal; + +/** + * The following extensions are listed in RFC 2459 as relevant to CRL Entries + * + * ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer + * (critical) + */ +public class X509CRLEntryObject extends X509CRLEntry +{ + private TBSCertList.CRLEntry c; + + private X500Name certificateIssuer; + private int hashValue; + private boolean isHashValueSet; + + public X509CRLEntryObject(TBSCertList.CRLEntry c) + { + this.c = c; + this.certificateIssuer = null; + } + + /** + * Constructor for CRLEntries of indirect CRLs. If <code>isIndirect</code> + * is <code>false</code> {@link #getCertificateIssuer()} will always + * return <code>null</code>, <code>previousCertificateIssuer</code> is + * ignored. If this <code>isIndirect</code> is specified and this CRLEntry + * has no certificate issuer CRL entry extension + * <code>previousCertificateIssuer</code> is returned by + * {@link #getCertificateIssuer()}. + * + * @param c + * TBSCertList.CRLEntry object. + * @param isIndirect + * <code>true</code> if the corresponding CRL is a indirect + * CRL. + * @param previousCertificateIssuer + * Certificate issuer of the previous CRLEntry. + */ + public X509CRLEntryObject( + TBSCertList.CRLEntry c, + boolean isIndirect, + X500Name previousCertificateIssuer) + { + this.c = c; + this.certificateIssuer = loadCertificateIssuer(isIndirect, previousCertificateIssuer); + } + + /** + * Will return true if any extensions are present and marked as critical as + * we currently don't handle any extensions! + */ + public boolean hasUnsupportedCriticalExtension() + { + Set extns = getCriticalExtensionOIDs(); + + return extns != null && !extns.isEmpty(); + } + + private X500Name loadCertificateIssuer(boolean isIndirect, X500Name previousCertificateIssuer) + { + if (!isIndirect) + { + return null; + } + + byte[] ext = getExtensionValue(X509Extension.certificateIssuer.getId()); + if (ext == null) + { + return previousCertificateIssuer; + } + + try + { + GeneralName[] names = GeneralNames.getInstance( + X509ExtensionUtil.fromExtensionValue(ext)).getNames(); + for (int i = 0; i < names.length; i++) + { + if (names[i].getTagNo() == GeneralName.directoryName) + { + return X500Name.getInstance(names[i].getName()); + } + } + return null; + } + catch (IOException e) + { + return null; + } + } + + X509Principal getCertificateIssuer() + { + if (certificateIssuer == null) + { + return null; + } + try + { + return new X509Principal(certificateIssuer.getEncoded()); + } + catch (Exception e) + { + throw new IllegalStateException(e.toString()); + } + } + private Set getExtensionOIDs(boolean critical) + { + Extensions extensions = c.getExtensions(); + + if (extensions != null) + { + Set set = new HashSet(); + Enumeration e = extensions.oids(); + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement(); + Extension ext = extensions.getExtension(oid); + + if (critical == ext.isCritical()) + { + set.add(oid.getId()); + } + } + + return set; + } + + return null; + } + + public Set getCriticalExtensionOIDs() + { + return getExtensionOIDs(true); + } + + public Set getNonCriticalExtensionOIDs() + { + return getExtensionOIDs(false); + } + + public byte[] getExtensionValue(String oid) + { + Extensions exts = c.getExtensions(); + + if (exts != null) + { + Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); + + if (ext != null) + { + try + { + return ext.getExtnValue().getEncoded(); + } + catch (Exception e) + { + throw new RuntimeException("error encoding " + e.toString()); + } + } + } + + return null; + } + + /** + * Cache the hashCode value - calculating it with the standard method. + * @return calculated hashCode. + */ + public int hashCode() + { + if (!isHashValueSet) + { + hashValue = super.hashCode(); + isHashValueSet = true; + } + + return hashValue; + } + + public byte[] getEncoded() + throws CRLException + { + try + { + return c.getEncoded(ASN1Encoding.DER); + } + catch (IOException e) + { + throw new CRLException(e.toString()); + } + } + + public BigInteger getSerialNumber() + { + return c.getUserCertificate().getValue(); + } + + public Date getRevocationDate() + { + return c.getRevocationDate().getDate(); + } + + public boolean hasExtensions() + { + return c.getExtensions() != null; + } + + public String toString() + { + StringBuffer buf = new StringBuffer(); + String nl = System.getProperty("line.separator"); + + buf.append(" userCertificate: ").append(this.getSerialNumber()).append(nl); + buf.append(" revocationDate: ").append(this.getRevocationDate()).append(nl); + + Extensions extensions = c.getExtensions(); + + if (extensions != null) + { + Enumeration e = extensions.oids(); + if (e.hasMoreElements()) + { + buf.append(" crlEntryExtensions:").append(nl); + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + Extension ext = extensions.getExtension(oid); + if (ext.getExtnValue() != null) + { + byte[] octs = ext.getExtnValue().getOctets(); + ASN1InputStream dIn = new ASN1InputStream(octs); + buf.append(" critical(").append(ext.isCritical()).append(") "); + try + { + if (oid.equals(X509Extension.reasonCode)) + { + buf.append(CRLReason.getInstance(ASN1Enumerated.getInstance(dIn.readObject()))).append(nl); + } + else if (oid.equals(X509Extension.certificateIssuer)) + { + buf.append("Certificate issuer: ").append(GeneralNames.getInstance(dIn.readObject())).append(nl); + } + else + { + buf.append(oid.getId()); + buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl); + } + } + catch (Exception ex) + { + buf.append(oid.getId()); + buf.append(" value = ").append("*****").append(nl); + } + } + else + { + buf.append(nl); + } + } + } + } + + return buf.toString(); + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CRLObject.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CRLObject.java new file mode 100644 index 00000000..46f9dab5 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CRLObject.java @@ -0,0 +1,556 @@ +package org.spongycastle.jce.provider; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Principal; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.cert.CRLException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509CRL; +import java.security.cert.X509CRLEntry; +import java.security.cert.X509Certificate; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.util.ASN1Dump; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.CRLDistPoint; +import org.spongycastle.asn1.x509.CRLNumber; +import org.spongycastle.asn1.x509.CertificateList; +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.asn1.x509.Extensions; +import org.spongycastle.asn1.x509.GeneralNames; +import org.spongycastle.asn1.x509.IssuingDistributionPoint; +import org.spongycastle.asn1.x509.TBSCertList; +import org.spongycastle.jce.X509Principal; +import org.spongycastle.jce.provider.RFC3280CertPathUtilities; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.x509.extension.X509ExtensionUtil; + +/** + * The following extensions are listed in RFC 2459 as relevant to CRLs + * + * Authority Key Identifier + * Issuer Alternative Name + * CRL Number + * Delta CRL Indicator (critical) + * Issuing Distribution Point (critical) + */ +public class X509CRLObject + extends X509CRL +{ + private CertificateList c; + private String sigAlgName; + private byte[] sigAlgParams; + private boolean isIndirect; + + static boolean isIndirectCRL(X509CRL crl) + throws CRLException + { + try + { + byte[] idp = crl.getExtensionValue(Extension.issuingDistributionPoint.getId()); + return idp != null + && IssuingDistributionPoint.getInstance(X509ExtensionUtil.fromExtensionValue(idp)).isIndirectCRL(); + } + catch (Exception e) + { + throw new ExtCRLException( + "Exception reading IssuingDistributionPoint", e); + } + } + + public X509CRLObject( + CertificateList c) + throws CRLException + { + this.c = c; + + try + { + this.sigAlgName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm()); + + if (c.getSignatureAlgorithm().getParameters() != null) + { + this.sigAlgParams = ((ASN1Encodable)c.getSignatureAlgorithm().getParameters()).toASN1Primitive().getEncoded(ASN1Encoding.DER); + } + else + { + this.sigAlgParams = null; + } + + this.isIndirect = isIndirectCRL(this); + } + catch (Exception e) + { + throw new CRLException("CRL contents invalid: " + e); + } + } + + /** + * Will return true if any extensions are present and marked + * as critical as we currently dont handle any extensions! + */ + public boolean hasUnsupportedCriticalExtension() + { + Set extns = getCriticalExtensionOIDs(); + + if (extns == null) + { + return false; + } + + extns.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT); + extns.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR); + + return !extns.isEmpty(); + } + + private Set getExtensionOIDs(boolean critical) + { + if (this.getVersion() == 2) + { + Extensions extensions = c.getTBSCertList().getExtensions(); + + if (extensions != null) + { + Set set = new HashSet(); + Enumeration e = extensions.oids(); + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + Extension ext = extensions.getExtension(oid); + + if (critical == ext.isCritical()) + { + set.add(oid.getId()); + } + } + + return set; + } + } + + return null; + } + + public Set getCriticalExtensionOIDs() + { + return getExtensionOIDs(true); + } + + public Set getNonCriticalExtensionOIDs() + { + return getExtensionOIDs(false); + } + + public byte[] getExtensionValue(String oid) + { + Extensions exts = c.getTBSCertList().getExtensions(); + + if (exts != null) + { + Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); + + if (ext != null) + { + try + { + return ext.getExtnValue().getEncoded(); + } + catch (Exception e) + { + throw new IllegalStateException("error parsing " + e.toString()); + } + } + } + + return null; + } + + public byte[] getEncoded() + throws CRLException + { + try + { + return c.getEncoded(ASN1Encoding.DER); + } + catch (IOException e) + { + throw new CRLException(e.toString()); + } + } + + public void verify(PublicKey key) + throws CRLException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException + { + verify(key, BouncyCastleProvider.PROVIDER_NAME); + } + + public void verify(PublicKey key, String sigProvider) + throws CRLException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException + { + if (!c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature())) + { + throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList."); + } + + Signature sig; + + if (sigProvider != null) + { + sig = Signature.getInstance(getSigAlgName(), sigProvider); + } + else + { + sig = Signature.getInstance(getSigAlgName()); + } + + sig.initVerify(key); + sig.update(this.getTBSCertList()); + + if (!sig.verify(this.getSignature())) + { + throw new SignatureException("CRL does not verify with supplied public key."); + } + } + + public int getVersion() + { + return c.getVersionNumber(); + } + + public Principal getIssuerDN() + { + return new X509Principal(X500Name.getInstance(c.getIssuer().toASN1Primitive())); + } + + public Date getThisUpdate() + { + return c.getThisUpdate().getDate(); + } + + public Date getNextUpdate() + { + if (c.getNextUpdate() != null) + { + return c.getNextUpdate().getDate(); + } + + return null; + } + + private Set loadCRLEntries() + { + Set entrySet = new HashSet(); + Enumeration certs = c.getRevokedCertificateEnumeration(); + + X500Name previousCertificateIssuer = c.getIssuer(); + while (certs.hasMoreElements()) + { + TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement(); + X509CRLEntryObject crlEntry = new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer); + entrySet.add(crlEntry); + if (isIndirect && entry.hasExtensions()) + { + Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer); + + if (currentCaName != null) + { + previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName()); + } + } + } + + return entrySet; + } + + public X509CRLEntry getRevokedCertificate(BigInteger serialNumber) + { + Enumeration certs = c.getRevokedCertificateEnumeration(); + + X500Name previousCertificateIssuer = c.getIssuer(); + while (certs.hasMoreElements()) + { + TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement(); + + if (serialNumber.equals(entry.getUserCertificate().getValue())) + { + return new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer); + } + + if (isIndirect && entry.hasExtensions()) + { + Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer); + + if (currentCaName != null) + { + previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName()); + } + } + } + + return null; + } + + public Set getRevokedCertificates() + { + Set entrySet = loadCRLEntries(); + + if (!entrySet.isEmpty()) + { + return Collections.unmodifiableSet(entrySet); + } + + return null; + } + + public byte[] getTBSCertList() + throws CRLException + { + try + { + return c.getTBSCertList().getEncoded("DER"); + } + catch (IOException e) + { + throw new CRLException(e.toString()); + } + } + + public byte[] getSignature() + { + return c.getSignature().getBytes(); + } + + public String getSigAlgName() + { + return sigAlgName; + } + + public String getSigAlgOID() + { + return c.getSignatureAlgorithm().getAlgorithm().getId(); + } + + public byte[] getSigAlgParams() + { + if (sigAlgParams != null) + { + byte[] tmp = new byte[sigAlgParams.length]; + + System.arraycopy(sigAlgParams, 0, tmp, 0, tmp.length); + + return tmp; + } + + return null; + } + + /** + * Returns a string representation of this CRL. + * + * @return a string representation of this CRL. + */ + public String toString() + { + StringBuffer buf = new StringBuffer(); + String nl = System.getProperty("line.separator"); + + buf.append(" Version: ").append(this.getVersion()).append( + nl); + buf.append(" IssuerDN: ").append(this.getIssuerDN()) + .append(nl); + buf.append(" This update: ").append(this.getThisUpdate()) + .append(nl); + buf.append(" Next update: ").append(this.getNextUpdate()) + .append(nl); + buf.append(" Signature Algorithm: ").append(this.getSigAlgName()) + .append(nl); + + byte[] sig = this.getSignature(); + + buf.append(" Signature: ").append( + new String(Hex.encode(sig, 0, 20))).append(nl); + for (int i = 20; i < sig.length; i += 20) + { + if (i < sig.length - 20) + { + buf.append(" ").append( + new String(Hex.encode(sig, i, 20))).append(nl); + } + else + { + buf.append(" ").append( + new String(Hex.encode(sig, i, sig.length - i))).append(nl); + } + } + + Extensions extensions = c.getTBSCertList().getExtensions(); + + if (extensions != null) + { + Enumeration e = extensions.oids(); + + if (e.hasMoreElements()) + { + buf.append(" Extensions: ").append(nl); + } + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement(); + Extension ext = extensions.getExtension(oid); + + if (ext.getExtnValue() != null) + { + byte[] octs = ext.getExtnValue().getOctets(); + ASN1InputStream dIn = new ASN1InputStream(octs); + buf.append(" critical(").append( + ext.isCritical()).append(") "); + try + { + if (oid.equals(Extension.cRLNumber)) + { + buf.append( + new CRLNumber(ASN1Integer.getInstance( + dIn.readObject()).getPositiveValue())) + .append(nl); + } + else if (oid.equals(Extension.deltaCRLIndicator)) + { + buf.append( + "Base CRL: " + + new CRLNumber(ASN1Integer.getInstance( + dIn.readObject()).getPositiveValue())) + .append(nl); + } + else if (oid + .equals(Extension.issuingDistributionPoint)) + { + buf.append( + IssuingDistributionPoint.getInstance(dIn.readObject())).append(nl); + } + else if (oid + .equals(Extension.cRLDistributionPoints)) + { + buf.append( + CRLDistPoint.getInstance(dIn.readObject())).append(nl); + } + else if (oid.equals(Extension.freshestCRL)) + { + buf.append( + CRLDistPoint.getInstance(dIn.readObject())).append(nl); + } + else + { + buf.append(oid.getId()); + buf.append(" value = ").append( + ASN1Dump.dumpAsString(dIn.readObject())) + .append(nl); + } + } + catch (Exception ex) + { + buf.append(oid.getId()); + buf.append(" value = ").append("*****").append(nl); + } + } + else + { + buf.append(nl); + } + } + } + Set set = getRevokedCertificates(); + if (set != null) + { + Iterator it = set.iterator(); + while (it.hasNext()) + { + buf.append(it.next()); + buf.append(nl); + } + } + return buf.toString(); + } + + /** + * Checks whether the given certificate is on this CRL. + * + * @param cert the certificate to check for. + * @return true if the given certificate is on this CRL, + * false otherwise. + */ + public boolean isRevoked(Certificate cert) + { + if (!cert.getType().equals("X.509")) + { + throw new RuntimeException("X.509 CRL used with non X.509 Cert"); + } + + TBSCertList.CRLEntry[] certs = c.getRevokedCertificates(); + + X500Name caName = c.getIssuer(); + + if (certs != null) + { + BigInteger serial = ((X509Certificate)cert).getSerialNumber(); + + for (int i = 0; i < certs.length; i++) + { + if (isIndirect && certs[i].hasExtensions()) + { + Extension currentCaName = certs[i].getExtensions().getExtension(Extension.certificateIssuer); + + if (currentCaName != null) + { + caName = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName()); + } + } + + if (certs[i].getUserCertificate().getValue().equals(serial)) + { + X500Name issuer; + + try + { + issuer = org.spongycastle.asn1.x509.Certificate.getInstance(cert.getEncoded()).getIssuer(); + } + catch (CertificateEncodingException e) + { + throw new RuntimeException("Cannot process certificate"); + } + + if (!caName.equals(issuer)) + { + return false; + } + + return true; + } + } + } + + return false; + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CertificateObject.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CertificateObject.java new file mode 100644 index 00000000..74b9c611 --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CertificateObject.java @@ -0,0 +1,858 @@ +package org.spongycastle.jce.provider; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Principal; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Security; +import java.security.Signature; +import java.security.SignatureException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OutputStream; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.ASN1String; +import org.spongycastle.asn1.DERBitString; +import org.spongycastle.asn1.DERIA5String; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.misc.MiscObjectIdentifiers; +import org.spongycastle.asn1.misc.NetscapeCertType; +import org.spongycastle.asn1.misc.NetscapeRevocationURL; +import org.spongycastle.asn1.misc.VerisignCzagExtension; +import org.spongycastle.asn1.util.ASN1Dump; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x500.style.RFC4519Style; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.BasicConstraints; +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.asn1.x509.Extensions; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.asn1.x509.KeyUsage; +import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl; +import org.spongycastle.jce.X509Principal; +import org.spongycastle.jce.provider.RFC3280CertPathUtilities; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.Integers; +import org.spongycastle.util.encoders.Hex; + +public class X509CertificateObject + extends X509Certificate + implements PKCS12BagAttributeCarrier +{ + private org.spongycastle.asn1.x509.Certificate c; + private BasicConstraints basicConstraints; + private boolean[] keyUsage; + private boolean hashValueSet; + private int hashValue; + + private PKCS12BagAttributeCarrier attrCarrier = new PKCS12BagAttributeCarrierImpl(); + + public X509CertificateObject( + org.spongycastle.asn1.x509.Certificate c) + throws CertificateParsingException + { + this.c = c; + + try + { + byte[] bytes = this.getExtensionBytes("2.5.29.19"); + + if (bytes != null) + { + basicConstraints = BasicConstraints.getInstance(ASN1Primitive.fromByteArray(bytes)); + } + } + catch (Exception e) + { + throw new CertificateParsingException("cannot construct BasicConstraints: " + e); + } + + try + { + byte[] bytes = this.getExtensionBytes("2.5.29.15"); + if (bytes != null) + { + DERBitString bits = DERBitString.getInstance(ASN1Primitive.fromByteArray(bytes)); + + bytes = bits.getBytes(); + int length = (bytes.length * 8) - bits.getPadBits(); + + keyUsage = new boolean[(length < 9) ? 9 : length]; + + for (int i = 0; i != length; i++) + { + keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0; + } + } + else + { + keyUsage = null; + } + } + catch (Exception e) + { + throw new CertificateParsingException("cannot construct KeyUsage: " + e); + } + } + + public void checkValidity() + throws CertificateExpiredException, CertificateNotYetValidException + { + this.checkValidity(new Date()); + } + + public void checkValidity( + Date date) + throws CertificateExpiredException, CertificateNotYetValidException + { + if (date.getTime() > this.getNotAfter().getTime()) // for other VM compatibility + { + throw new CertificateExpiredException("certificate expired on " + c.getEndDate().getTime()); + } + + if (date.getTime() < this.getNotBefore().getTime()) + { + throw new CertificateNotYetValidException("certificate not valid till " + c.getStartDate().getTime()); + } + } + + public int getVersion() + { + return c.getVersionNumber(); + } + + public BigInteger getSerialNumber() + { + return c.getSerialNumber().getValue(); + } + + public Principal getIssuerDN() + { + try + { + return new X509Principal(X500Name.getInstance(c.getIssuer().getEncoded())); + } + catch (IOException e) + { + return null; + } + } + + public Principal getSubjectDN() + { + return new X509Principal(X500Name.getInstance(c.getSubject().toASN1Primitive())); + } + + public Date getNotBefore() + { + return c.getStartDate().getDate(); + } + + public Date getNotAfter() + { + return c.getEndDate().getDate(); + } + + public byte[] getTBSCertificate() + throws CertificateEncodingException + { + try + { + return c.getTBSCertificate().getEncoded(ASN1Encoding.DER); + } + catch (IOException e) + { + throw new CertificateEncodingException(e.toString()); + } + } + + public byte[] getSignature() + { + return c.getSignature().getBytes(); + } + + /** + * return a more "meaningful" representation for the signature algorithm used in + * the certficate. + */ + public String getSigAlgName() + { + Provider prov = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME); + + if (prov != null) + { + String algName = prov.getProperty("Alg.Alias.Signature." + this.getSigAlgOID()); + + if (algName != null) + { + return algName; + } + } + + Provider[] provs = Security.getProviders(); + + // + // search every provider looking for a real algorithm + // + for (int i = 0; i != provs.length; i++) + { + String algName = provs[i].getProperty("Alg.Alias.Signature." + this.getSigAlgOID()); + if (algName != null) + { + return algName; + } + } + + return this.getSigAlgOID(); + } + + /** + * return the object identifier for the signature. + */ + public String getSigAlgOID() + { + return c.getSignatureAlgorithm().getAlgorithm().getId(); + } + + /** + * return the signature parameters, or null if there aren't any. + */ + public byte[] getSigAlgParams() + { + if (c.getSignatureAlgorithm().getParameters() != null) + { + try + { + return c.getSignatureAlgorithm().getParameters().toASN1Primitive().getEncoded(ASN1Encoding.DER); + } + catch (IOException e) + { + return null; + } + } + else + { + return null; + } + } + + public boolean[] getIssuerUniqueID() + { + DERBitString id = c.getTBSCertificate().getIssuerUniqueId(); + + if (id != null) + { + byte[] bytes = id.getBytes(); + boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()]; + + for (int i = 0; i != boolId.length; i++) + { + boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0; + } + + return boolId; + } + + return null; + } + + public boolean[] getSubjectUniqueID() + { + DERBitString id = c.getTBSCertificate().getSubjectUniqueId(); + + if (id != null) + { + byte[] bytes = id.getBytes(); + boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()]; + + for (int i = 0; i != boolId.length; i++) + { + boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0; + } + + return boolId; + } + + return null; + } + + public boolean[] getKeyUsage() + { + return keyUsage; + } + + public List getExtendedKeyUsage() + throws CertificateParsingException + { + byte[] bytes = this.getExtensionBytes("2.5.29.37"); + + if (bytes != null) + { + try + { + ASN1InputStream dIn = new ASN1InputStream(bytes); + ASN1Sequence seq = (ASN1Sequence)dIn.readObject(); + List list = new ArrayList(); + + for (int i = 0; i != seq.size(); i++) + { + list.add(((ASN1ObjectIdentifier)seq.getObjectAt(i)).getId()); + } + + return Collections.unmodifiableList(list); + } + catch (Exception e) + { + throw new CertificateParsingException("error processing extended key usage extension"); + } + } + + return null; + } + + public int getBasicConstraints() + { + if (basicConstraints != null) + { + if (basicConstraints.isCA()) + { + if (basicConstraints.getPathLenConstraint() == null) + { + return Integer.MAX_VALUE; + } + else + { + return basicConstraints.getPathLenConstraint().intValue(); + } + } + else + { + return -1; + } + } + + return -1; + } + + public Collection getSubjectAlternativeNames() + throws CertificateParsingException + { + return getAlternativeNames(getExtensionBytes(Extension.subjectAlternativeName.getId())); + } + + public Collection getIssuerAlternativeNames() + throws CertificateParsingException + { + return getAlternativeNames(getExtensionBytes(Extension.issuerAlternativeName.getId())); + } + + public Set getCriticalExtensionOIDs() + { + if (this.getVersion() == 3) + { + Set set = new HashSet(); + Extensions extensions = c.getTBSCertificate().getExtensions(); + + if (extensions != null) + { + Enumeration e = extensions.oids(); + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + Extension ext = extensions.getExtension(oid); + + if (ext.isCritical()) + { + set.add(oid.getId()); + } + } + + return set; + } + } + + return null; + } + + private byte[] getExtensionBytes(String oid) + { + Extensions exts = c.getTBSCertificate().getExtensions(); + + if (exts != null) + { + Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); + if (ext != null) + { + return ext.getExtnValue().getOctets(); + } + } + + return null; + } + + public byte[] getExtensionValue(String oid) + { + Extensions exts = c.getTBSCertificate().getExtensions(); + + if (exts != null) + { + Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); + + if (ext != null) + { + try + { + return ext.getExtnValue().getEncoded(); + } + catch (Exception e) + { + throw new IllegalStateException("error parsing " + e.toString()); + } + } + } + + return null; + } + + public Set getNonCriticalExtensionOIDs() + { + if (this.getVersion() == 3) + { + Set set = new HashSet(); + Extensions extensions = c.getTBSCertificate().getExtensions(); + + if (extensions != null) + { + Enumeration e = extensions.oids(); + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + Extension ext = extensions.getExtension(oid); + + if (!ext.isCritical()) + { + set.add(oid.getId()); + } + } + + return set; + } + } + + return null; + } + + public boolean hasUnsupportedCriticalExtension() + { + if (this.getVersion() == 3) + { + Extensions extensions = c.getTBSCertificate().getExtensions(); + + if (extensions != null) + { + Enumeration e = extensions.oids(); + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + String oidId = oid.getId(); + + if (oidId.equals(RFC3280CertPathUtilities.KEY_USAGE) + || oidId.equals(RFC3280CertPathUtilities.CERTIFICATE_POLICIES) + || oidId.equals(RFC3280CertPathUtilities.POLICY_MAPPINGS) + || oidId.equals(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY) + || oidId.equals(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS) + || oidId.equals(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT) + || oidId.equals(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR) + || oidId.equals(RFC3280CertPathUtilities.POLICY_CONSTRAINTS) + || oidId.equals(RFC3280CertPathUtilities.BASIC_CONSTRAINTS) + || oidId.equals(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME) + || oidId.equals(RFC3280CertPathUtilities.NAME_CONSTRAINTS)) + { + continue; + } + + Extension ext = extensions.getExtension(oid); + + if (ext.isCritical()) + { + return true; + } + } + } + } + + return false; + } + + public PublicKey getPublicKey() + { + try + { + return BouncyCastleProvider.getPublicKey(c.getSubjectPublicKeyInfo()); + } + catch (IOException e) + { + return null; // should never happen... + } + } + + public byte[] getEncoded() + throws CertificateEncodingException + { + try + { + return c.getEncoded(ASN1Encoding.DER); + } + catch (IOException e) + { + throw new CertificateEncodingException(e.toString()); + } + } + + public boolean equals( + Object o) + { + if (o == this) + { + return true; + } + + if (!(o instanceof Certificate)) + { + return false; + } + + Certificate other = (Certificate)o; + + try + { + byte[] b1 = this.getEncoded(); + byte[] b2 = other.getEncoded(); + + return Arrays.areEqual(b1, b2); + } + catch (CertificateEncodingException e) + { + return false; + } + } + + public synchronized int hashCode() + { + if (!hashValueSet) + { + hashValue = calculateHashCode(); + hashValueSet = true; + } + + return hashValue; + } + + private int calculateHashCode() + { + try + { + int hashCode = 0; + byte[] certData = this.getEncoded(); + for (int i = 1; i < certData.length; i++) + { + hashCode += certData[i] * i; + } + return hashCode; + } + catch (CertificateEncodingException e) + { + return 0; + } + } + + public void setBagAttribute( + ASN1ObjectIdentifier oid, + ASN1Encodable attribute) + { + attrCarrier.setBagAttribute(oid, attribute); + } + + public ASN1Encodable getBagAttribute( + ASN1ObjectIdentifier oid) + { + return attrCarrier.getBagAttribute(oid); + } + + public Enumeration getBagAttributeKeys() + { + return attrCarrier.getBagAttributeKeys(); + } + + public String toString() + { + StringBuffer buf = new StringBuffer(); + String nl = System.getProperty("line.separator"); + + buf.append(" [0] Version: ").append(this.getVersion()).append(nl); + buf.append(" SerialNumber: ").append(this.getSerialNumber()).append(nl); + buf.append(" IssuerDN: ").append(this.getIssuerDN()).append(nl); + buf.append(" Start Date: ").append(this.getNotBefore()).append(nl); + buf.append(" Final Date: ").append(this.getNotAfter()).append(nl); + buf.append(" SubjectDN: ").append(this.getSubjectDN()).append(nl); + buf.append(" Public Key: ").append(this.getPublicKey()).append(nl); + buf.append(" Signature Algorithm: ").append(this.getSigAlgName()).append(nl); + + byte[] sig = this.getSignature(); + + buf.append(" Signature: ").append(new String(Hex.encode(sig, 0, 20))).append(nl); + for (int i = 20; i < sig.length; i += 20) + { + if (i < sig.length - 20) + { + buf.append(" ").append(new String(Hex.encode(sig, i, 20))).append(nl); + } + else + { + buf.append(" ").append(new String(Hex.encode(sig, i, sig.length - i))).append(nl); + } + } + + Extensions extensions = c.getTBSCertificate().getExtensions(); + + if (extensions != null) + { + Enumeration e = extensions.oids(); + + if (e.hasMoreElements()) + { + buf.append(" Extensions: \n"); + } + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + Extension ext = extensions.getExtension(oid); + + if (ext.getExtnValue() != null) + { + byte[] octs = ext.getExtnValue().getOctets(); + ASN1InputStream dIn = new ASN1InputStream(octs); + buf.append(" critical(").append(ext.isCritical()).append(") "); + try + { + if (oid.equals(Extension.basicConstraints)) + { + buf.append(BasicConstraints.getInstance(dIn.readObject())).append(nl); + } + else if (oid.equals(Extension.keyUsage)) + { + buf.append(KeyUsage.getInstance(dIn.readObject())).append(nl); + } + else if (oid.equals(MiscObjectIdentifiers.netscapeCertType)) + { + buf.append(new NetscapeCertType((DERBitString)dIn.readObject())).append(nl); + } + else if (oid.equals(MiscObjectIdentifiers.netscapeRevocationURL)) + { + buf.append(new NetscapeRevocationURL((DERIA5String)dIn.readObject())).append(nl); + } + else if (oid.equals(MiscObjectIdentifiers.verisignCzagExtension)) + { + buf.append(new VerisignCzagExtension((DERIA5String)dIn.readObject())).append(nl); + } + else + { + buf.append(oid.getId()); + buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl); + //buf.append(" value = ").append("*****").append(nl); + } + } + catch (Exception ex) + { + buf.append(oid.getId()); + // buf.append(" value = ").append(new String(Hex.encode(ext.getExtnValue().getOctets()))).append(nl); + buf.append(" value = ").append("*****").append(nl); + } + } + else + { + buf.append(nl); + } + } + } + + return buf.toString(); + } + + public final void verify( + PublicKey key) + throws CertificateException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException + { + Signature signature; + String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm()); + + try + { + signature = Signature.getInstance(sigName, BouncyCastleProvider.PROVIDER_NAME); + } + catch (Exception e) + { + signature = Signature.getInstance(sigName); + } + + checkSignature(key, signature); + } + + public final void verify( + PublicKey key, + String sigProvider) + throws CertificateException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException + { + String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm()); + Signature signature = Signature.getInstance(sigName, sigProvider); + + checkSignature(key, signature); + } + + private void checkSignature( + PublicKey key, + Signature signature) + throws CertificateException, NoSuchAlgorithmException, + SignatureException, InvalidKeyException + { + if (!isAlgIdEqual(c.getSignatureAlgorithm(), c.getTBSCertificate().getSignature())) + { + throw new CertificateException("signature algorithm in TBS cert not same as outer cert"); + } + + ASN1Encodable params = c.getSignatureAlgorithm().getParameters(); + + // TODO This should go after the initVerify? + X509SignatureUtil.setSignatureParameters(signature, params); + + signature.initVerify(key); + + signature.update(this.getTBSCertificate()); + + if (!signature.verify(this.getSignature())) + { + throw new SignatureException("certificate does not verify with supplied key"); + } + } + + private boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2) + { + if (!id1.getAlgorithm().equals(id2.getAlgorithm())) + { + return false; + } + + if (id1.getParameters() == null) + { + if (id2.getParameters() != null && !id2.getParameters().equals(DERNull.INSTANCE)) + { + return false; + } + + return true; + } + + if (id2.getParameters() == null) + { + if (id1.getParameters() != null && !id1.getParameters().equals(DERNull.INSTANCE)) + { + return false; + } + + return true; + } + + return id1.getParameters().equals(id2.getParameters()); + } + + private static Collection getAlternativeNames(byte[] extVal) + throws CertificateParsingException + { + if (extVal == null) + { + return null; + } + try + { + Collection temp = new ArrayList(); + Enumeration it = ASN1Sequence.getInstance(extVal).getObjects(); + while (it.hasMoreElements()) + { + GeneralName genName = GeneralName.getInstance(it.nextElement()); + List list = new ArrayList(); + list.add(Integers.valueOf(genName.getTagNo())); + switch (genName.getTagNo()) + { + case GeneralName.ediPartyName: + case GeneralName.x400Address: + case GeneralName.otherName: + list.add(genName.getEncoded()); + break; + case GeneralName.directoryName: + list.add(X500Name.getInstance(RFC4519Style.INSTANCE, genName.getName()).toString()); + break; + case GeneralName.dNSName: + case GeneralName.rfc822Name: + case GeneralName.uniformResourceIdentifier: + list.add(((ASN1String)genName.getName()).getString()); + break; + case GeneralName.registeredID: + list.add(ASN1ObjectIdentifier.getInstance(genName.getName()).getId()); + break; + case GeneralName.iPAddress: + byte[] addrBytes = DEROctetString.getInstance(genName.getName()).getOctets(); + list.add(addrBytes); + break; + default: + throw new IOException("Bad tag number: " + genName.getTagNo()); + } + + temp.add(list); + } + if (temp.size() == 0) + { + return null; + } + return Collections.unmodifiableCollection(temp); + } + catch (Exception e) + { + throw new CertificateParsingException(e.getMessage()); + } + } +} diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/spec/PSSParameterSpec.java b/prov/src/main/jdk1.3/org/spongycastle/jce/spec/PSSParameterSpec.java new file mode 100644 index 00000000..0711e29c --- /dev/null +++ b/prov/src/main/jdk1.3/org/spongycastle/jce/spec/PSSParameterSpec.java @@ -0,0 +1,44 @@ +package org.spongycastle.jce.spec; + +/** + * This class specifies a parameter spec for RSA PSS encoding scheme, + * as defined in the PKCS#1 v2.1. + * + * @see java.security.spec.AlgorithmParameterSpec + * @see java.security.Signature + */ +public class PSSParameterSpec + extends Object + implements java.security.spec.AlgorithmParameterSpec +{ + private int saltLen; + + /** + * Creates a new PSSParameterSpec given the salt length as defined + * in PKCS#1. + * + * @param saltLen - the length of salt in bits to be used in PKCS#1 + * PSS encoding. + * @throws IllegalArgumentException - if saltLen is less than 0. + */ + public PSSParameterSpec(int saltLen) + { + if (saltLen < 0) + { + throw new IllegalArgumentException("Salt length must be >= 0"); + } + + this.saltLen = saltLen; + } + + /** + * Returns the salt length in bits. + * + * @returns the salt length. + */ + public int getSaltLength() + { + return saltLen; + } +} + |