diff options
Diffstat (limited to 'bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric')
20 files changed, 2036 insertions, 35 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java index ba7dd80..28a1a6a 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java @@ -37,7 +37,6 @@ public class DH // provider.addAlgorithm("Cipher.DHIESwithAES", PREFIX + "IESCipher$IESwithAES"); // provider.addAlgorithm("Cipher.DHIESWITHAES", PREFIX + "IESCipher$IESwithAES"); // provider.addAlgorithm("Cipher.DHIESWITHDESEDE", PREFIX + "IESCipher$IESwithDESede"); - // provider.addAlgorithm("KeyPairGenerator.IES", PREFIX + "KeyPairGeneratorSpi"); // END android-removed } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java index 8f93a68..8d50a54 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java @@ -99,6 +99,8 @@ public class EC // addSignatureAlgorithm(provider, "SHA1", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1); // addSignatureAlgorithm(provider, "SHA224", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA224", EACObjectIdentifiers.id_TA_ECDSA_SHA_224); // addSignatureAlgorithm(provider, "SHA256", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA256", EACObjectIdentifiers.id_TA_ECDSA_SHA_256); + // addSignatureAlgorithm(provider, "SHA384", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA384", EACObjectIdentifiers.id_TA_ECDSA_SHA_384); + // addSignatureAlgorithm(provider, "SHA512", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA512", EACObjectIdentifiers.id_TA_ECDSA_SHA_512); // END android-removed } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java index 2e5ee56..d850e5d 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java @@ -7,25 +7,36 @@ import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.DSAParameterSpec; +import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.generators.DSAParametersGenerator; +import org.bouncycastle.crypto.params.DSAParameterGenerationParameters; import org.bouncycastle.crypto.params.DSAParameters; import org.bouncycastle.jce.provider.BouncyCastleProvider; -//import org.bouncycastle.jce.spec.GOST3410ParameterSpec; -//import org.bouncycastle.jce.spec.GOST3410PublicKeyParameterSetSpec; public class AlgorithmParameterGeneratorSpi extends java.security.AlgorithmParameterGeneratorSpi { protected SecureRandom random; protected int strength = 1024; + protected DSAParameterGenerationParameters params; protected void engineInit( int strength, SecureRandom random) { - if (strength < 512 || strength > 1024 || strength % 64 != 0) + if (strength < 512 || strength > 3072) { - throw new InvalidParameterException("strength must be from 512 - 1024 and a multiple of 64"); + throw new InvalidParameterException("strength must be from 512 - 3072"); + } + + if (strength <= 1024 && strength % 64 != 0) + { + throw new InvalidParameterException("strength must be a multiple of 64 below 1024 bits."); + } + + if (strength > 1024 && strength % 1024 != 0) + { + throw new InvalidParameterException("strength must be a multiple of 1024 above 1024 bits."); } this.strength = strength; @@ -42,15 +53,35 @@ public class AlgorithmParameterGeneratorSpi protected AlgorithmParameters engineGenerateParameters() { - DSAParametersGenerator pGen = new DSAParametersGenerator(); + DSAParametersGenerator pGen; - if (random != null) + if (strength <= 1024) { - pGen.init(strength, 20, random); + pGen = new DSAParametersGenerator(); } else { - pGen.init(strength, 20, new SecureRandom()); + pGen = new DSAParametersGenerator(new SHA256Digest()); + } + + if (random == null) + { + random = new SecureRandom(); + } + + if (strength == 1024) + { + params = new DSAParameterGenerationParameters(1024, 160, 80, random); + pGen.init(params); + } + else if (strength > 1024) + { + params = new DSAParameterGenerationParameters(strength, 256, 80, random); + pGen.init(params); + } + else + { + pGen.init(strength, 20, random); } DSAParameters p = pGen.generateParameters(); diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParametersSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParametersSpi.java index 1ddb815..61fa33c 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParametersSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParametersSpi.java @@ -7,7 +7,6 @@ import java.security.spec.InvalidParameterSpecException; import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.x509.DSAParameter; public class AlgorithmParametersSpi diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java index d9d5857..c8b326f 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java @@ -57,11 +57,6 @@ public class DSASigner { CipherParameters param; -// if (publicKey instanceof GOST3410Key) -// { -// param = GOST3410Util.generatePublicKeyParameter(publicKey); -// } -// else if (publicKey instanceof DSAKey) if (publicKey instanceof DSAKey) { param = DSAUtil.generatePublicKeyParameter(publicKey); @@ -108,14 +103,7 @@ public class DSASigner { CipherParameters param; -// if (privateKey instanceof GOST3410Key) -// { -// param = GOST3410Util.generatePrivateKeyParameter(privateKey); -// } -// else -// { - param = DSAUtil.generatePrivateKeyParameter(privateKey); -// } + param = DSAUtil.generatePrivateKeyParameter(privateKey); if (random != null) { diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java index f34f482..3d64c83 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java @@ -31,6 +31,8 @@ import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; +import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl; import org.bouncycastle.jcajce.provider.config.ProviderConfiguration; import org.bouncycastle.jce.interfaces.ECPointEncoder; diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java index 14cc9dc..2b61727 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java @@ -26,6 +26,8 @@ import org.bouncycastle.asn1.x9.X9IntegerConverter; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; +import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; import org.bouncycastle.jcajce.provider.config.ProviderConfiguration; import org.bouncycastle.jce.interfaces.ECPointEncoder; diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java index cade228..35a804c 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java @@ -37,6 +37,7 @@ import org.bouncycastle.crypto.params.ECPublicKeyParameters; // import org.bouncycastle.crypto.params.MQVPrivateParameters; // import org.bouncycastle.crypto.params.MQVPublicParameters; // END android-removed +import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; import org.bouncycastle.jce.interfaces.ECPrivateKey; import org.bouncycastle.jce.interfaces.ECPublicKey; // BEGIN android-removed diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java index 156b1d0..5769bac 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java @@ -15,6 +15,7 @@ import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi; +import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; import org.bouncycastle.jcajce.provider.config.ProviderConfiguration; import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; import org.bouncycastle.jce.provider.BouncyCastleProvider; diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java index 4cbefb6..c0c825c 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java @@ -23,6 +23,7 @@ import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECKeyGenerationParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; import org.bouncycastle.jcajce.provider.config.ProviderConfiguration; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec; diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java index 86a407c..c6b4bce 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java @@ -8,9 +8,9 @@ import java.security.PublicKey; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DERInteger; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DSA; @@ -34,6 +34,7 @@ import org.bouncycastle.crypto.signers.ECDSASigner; // END android-removed import org.bouncycastle.jcajce.provider.asymmetric.util.DSABase; import org.bouncycastle.jcajce.provider.asymmetric.util.DSAEncoder; +import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; public class SignatureSpi extends DSABase @@ -215,6 +216,24 @@ public class SignatureSpi // super(new SHA256Digest(), new ECDSASigner(), new CVCDSAEncoder()); // } // } + // + // static public class ecCVCDSA384 + // extends SignatureSpi + // { + // public ecCVCDSA384() + // { + // super(new SHA384Digest(), new ECDSASigner(), new CVCDSAEncoder()); + // } + // } + // + // static public class ecCVCDSA512 + // extends SignatureSpi + // { + // public ecCVCDSA512() + // { + // super(new SHA512Digest(), new ECDSASigner(), new CVCDSAEncoder()); + // } + // } // END android-removed private static class StdDSAEncoder @@ -227,8 +246,8 @@ public class SignatureSpi { ASN1EncodableVector v = new ASN1EncodableVector(); - v.add(new DERInteger(r)); - v.add(new DERInteger(s)); + v.add(new ASN1Integer(r)); + v.add(new ASN1Integer(s)); return new DERSequence(v).getEncoded(ASN1Encoding.DER); } @@ -240,8 +259,8 @@ public class SignatureSpi ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding); BigInteger[] sig = new BigInteger[2]; - sig[0] = ((DERInteger)s.getObjectAt(0)).getValue(); - sig[1] = ((DERInteger)s.getObjectAt(1)).getValue(); + sig[0] = ASN1Integer.getInstance(s.getObjectAt(0)).getValue(); + sig[1] = ASN1Integer.getInstance(s.getObjectAt(1)).getValue(); return sig; } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/DHUtil.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DHUtil.java index 4bd7805..52c84ec 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/DHUtil.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DHUtil.java @@ -1,4 +1,4 @@ -package org.bouncycastle.jcajce.provider.asymmetric.dh; +package org.bouncycastle.jcajce.provider.asymmetric.util; import java.security.InvalidKeyException; import java.security.PrivateKey; diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/EC5Util.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java index 38025e7..d4065ac 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/EC5Util.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java @@ -1,4 +1,4 @@ -package org.bouncycastle.jcajce.provider.asymmetric.ec; +package org.bouncycastle.jcajce.provider.asymmetric.util; import java.math.BigInteger; import java.security.spec.ECField; diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtil.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java index 820bf4b..442b340 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtil.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java @@ -1,4 +1,4 @@ -package org.bouncycastle.jcajce.provider.asymmetric.ec; +package org.bouncycastle.jcajce.provider.asymmetric.util; import java.security.InvalidKeyException; import java.security.PrivateKey; @@ -21,6 +21,7 @@ import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; import org.bouncycastle.jce.interfaces.ECPrivateKey; import org.bouncycastle.jce.interfaces.ECPublicKey; import org.bouncycastle.jce.provider.BouncyCastleProvider; diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java index 5b79864..03a1fe8 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java @@ -24,8 +24,6 @@ import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.pkcs.SignedData; import org.bouncycastle.asn1.x509.Certificate; import org.bouncycastle.asn1.x509.CertificateList; -import org.bouncycastle.jce.provider.X509CRLObject; -import org.bouncycastle.jce.provider.X509CertificateObject; /** * class for dealing with X509 certificates. @@ -334,9 +332,7 @@ public class CertificateFactory public Iterator engineGetCertPathEncodings() { - // BEGIN android-changed return PKIXCertPath.certPathEncodings.iterator(); - // END android-changed } public CertPath engineGenerateCertPath( diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/ExtCRLException.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/ExtCRLException.java new file mode 100644 index 0000000..e27acfb --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/ExtCRLException.java @@ -0,0 +1,20 @@ +package org.bouncycastle.jcajce.provider.asymmetric.x509; + +import java.security.cert.CRLException; + +class ExtCRLException + extends CRLException +{ + Throwable cause; + + ExtCRLException(String message, Throwable cause) + { + super(message); + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java new file mode 100644 index 0000000..1888328 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java @@ -0,0 +1,301 @@ +package org.bouncycastle.jcajce.provider.asymmetric.x509; + +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 javax.security.auth.x500.X500Principal; + +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1Enumerated; +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.util.ASN1Dump; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.CRLReason; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.GeneralNames; +import org.bouncycastle.asn1.x509.TBSCertList; +import org.bouncycastle.asn1.x509.X509Extension; + +/** + * The following extensions are listed in RFC 2459 as relevant to CRL Entries + * + * ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer + * (critical) + */ +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; + } + + Extension ext = getExtension(Extension.certificateIssuer); + if (ext == null) + { + return previousCertificateIssuer; + } + + try + { + GeneralName[] names = GeneralNames.getInstance(ext.getParsedValue()).getNames(); + for (int i = 0; i < names.length; i++) + { + if (names[i].getTagNo() == GeneralName.directoryName) + { + return X500Name.getInstance(names[i].getName()); + } + } + return null; + } + catch (Exception e) + { + return null; + } + } + + public X500Principal getCertificateIssuer() + { + if (certificateIssuer == null) + { + return null; + } + try + { + return new X500Principal(certificateIssuer.getEncoded()); + } + catch (IOException e) + { + return null; + } + } + + 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); + } + + private Extension getExtension(ASN1ObjectIdentifier oid) + { + Extensions exts = c.getExtensions(); + + if (exts != null) + { + return exts.getExtension(oid); + } + + return null; + } + + public byte[] getExtensionValue(String oid) + { + Extension ext = 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); + buf.append(" certificateIssuer: ").append(this.getCertificateIssuer()).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/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java new file mode 100644 index 0000000..2fc0826 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java @@ -0,0 +1,578 @@ +package org.bouncycastle.jcajce.provider.asymmetric.x509; + +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 javax.security.auth.x500.X500Principal; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.util.ASN1Dump; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.CRLDistPoint; +import org.bouncycastle.asn1.x509.CRLNumber; +import org.bouncycastle.asn1.x509.CertificateList; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.GeneralNames; +import org.bouncycastle.asn1.x509.IssuingDistributionPoint; +import org.bouncycastle.asn1.x509.TBSCertList; +import org.bouncycastle.jce.X509Principal; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jce.provider.RFC3280CertPathUtilities; +import org.bouncycastle.util.encoders.Hex; + +/** + * 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) + */ +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(ASN1OctetString.getInstance(idp).getOctets()).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 X500Principal getIssuerX500Principal() + { + try + { + return new X500Principal(c.getIssuer().getEncoded()); + } + catch (IOException e) + { + throw new IllegalStateException("can't encode issuer DN"); + } + } + + 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 = null; // the issuer + 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 = null; // the issuer + 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; + + if (cert instanceof X509Certificate) + { + issuer = X500Name.getInstance(((X509Certificate)cert).getIssuerX500Principal().getEncoded()); + } + else + { + try + { + issuer = org.bouncycastle.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/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java new file mode 100644 index 0000000..6604b4a --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java @@ -0,0 +1,916 @@ +package org.bouncycastle.jcajce.provider.asymmetric.x509; + +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 javax.security.auth.x500.X500Principal; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OutputStream; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1String; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERIA5String; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.misc.MiscObjectIdentifiers; +import org.bouncycastle.asn1.misc.NetscapeCertType; +import org.bouncycastle.asn1.misc.NetscapeRevocationURL; +import org.bouncycastle.asn1.misc.VerisignCzagExtension; +import org.bouncycastle.asn1.util.ASN1Dump; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x500.style.RFC4519Style; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.BasicConstraints; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.KeyUsage; +// BEGIN android-added +import org.bouncycastle.asn1.x509.X509Name; +// END android-added +import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl; +import org.bouncycastle.jce.X509Principal; +import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jce.provider.RFC3280CertPathUtilities; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Integers; +import org.bouncycastle.util.encoders.Hex; + +class X509CertificateObject + extends X509Certificate + implements PKCS12BagAttributeCarrier +{ + private org.bouncycastle.asn1.x509.Certificate c; + private BasicConstraints basicConstraints; + private boolean[] keyUsage; + private boolean hashValueSet; + private int hashValue; + + private PKCS12BagAttributeCarrier attrCarrier = new PKCS12BagAttributeCarrierImpl(); + + public X509CertificateObject( + org.bouncycastle.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 X500Principal getIssuerX500Principal() + { + try + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ASN1OutputStream aOut = new ASN1OutputStream(bOut); + + aOut.writeObject(c.getIssuer()); + + return new X500Principal(bOut.toByteArray()); + } + catch (IOException e) + { + throw new IllegalStateException("can't encode issuer DN"); + } + } + + public Principal getSubjectDN() + { + return new X509Principal(X500Name.getInstance(c.getSubject().toASN1Primitive())); + } + + public X500Principal getSubjectX500Principal() + { + try + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ASN1OutputStream aOut = new ASN1OutputStream(bOut); + + aOut.writeObject(c.getSubject()); + + return new X500Principal(bOut.toByteArray()); + } + catch (IOException e) + { + throw new IllegalStateException("can't encode issuer DN"); + } + } + + 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... + } + } + + // BEGIN android-changed + private byte[] encoded; + // END android-changed + public byte[] getEncoded() + throws CertificateEncodingException + { + try + { + // BEGIN android-changed + if (encoded == null) { + encoded = c.getEncoded(ASN1Encoding.DER); + } + return encoded; + // END android-changed + } + 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: + // BEGIN android-changed + list.add(X509Name.getInstance(genName.getName()).toString(true, X509Name.DefaultSymbols)); + // END android-changed + 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(); + final String addr; + try + { + addr = InetAddress.getByAddress(addrBytes).getHostAddress(); + } + catch (UnknownHostException e) + { + continue; + } + list.add(addr); + break; + default: + throw new IOException("Bad tag number: " + genName.getTagNo()); + } + + temp.add(Collections.unmodifiableList(list)); + } + if (temp.size() == 0) + { + return null; + } + return Collections.unmodifiableCollection(temp); + } + catch (Exception e) + { + throw new CertificateParsingException(e.getMessage()); + } + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java new file mode 100644 index 0000000..4ca9e89 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java @@ -0,0 +1,144 @@ +package org.bouncycastle.jcajce.provider.asymmetric.x509; + +import java.io.IOException; +import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.Signature; +import java.security.SignatureException; +import java.security.spec.PSSParameterSpec; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Null; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.DERObjectIdentifier; +// BEGIN android-removed +// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +// END android-removed +import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.pkcs.RSASSAPSSparams; +// BEGIN android-removed +// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +// END android-removed +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; + +class X509SignatureUtil +{ + private static final ASN1Null derNull = DERNull.INSTANCE; + + static void setSignatureParameters( + Signature signature, + ASN1Encodable params) + throws NoSuchAlgorithmException, SignatureException, InvalidKeyException + { + if (params != null && !derNull.equals(params)) + { + AlgorithmParameters sigParams = AlgorithmParameters.getInstance(signature.getAlgorithm(), signature.getProvider()); + + try + { + sigParams.init(params.toASN1Primitive().getEncoded()); + } + catch (IOException e) + { + throw new SignatureException("IOException decoding parameters: " + e.getMessage()); + } + + if (signature.getAlgorithm().endsWith("MGF1")) + { + try + { + signature.setParameter(sigParams.getParameterSpec(PSSParameterSpec.class)); + } + catch (GeneralSecurityException e) + { + throw new SignatureException("Exception extracting parameters: " + e.getMessage()); + } + } + } + } + + static String getSignatureName( + AlgorithmIdentifier sigAlgId) + { + ASN1Encodable params = sigAlgId.getParameters(); + + if (params != null && !derNull.equals(params)) + { + if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS)) + { + RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params); + + return getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "withRSAandMGF1"; + } + if (sigAlgId.getAlgorithm().equals(X9ObjectIdentifiers.ecdsa_with_SHA2)) + { + ASN1Sequence ecDsaParams = ASN1Sequence.getInstance(params); + + return getDigestAlgName((DERObjectIdentifier)ecDsaParams.getObjectAt(0)) + "withECDSA"; + } + } + + return sigAlgId.getAlgorithm().getId(); + } + + /** + * Return the digest algorithm using one of the standard JCA string + * representations rather the the algorithm identifier (if possible). + */ + private static String getDigestAlgName( + DERObjectIdentifier 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"; + } + // BEGIN android-removed + // 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"; + // } + // END android-removed + else + { + return digestAlgOID.getId(); + } + } +} |