diff options
Diffstat (limited to 'android_bcpkix/src/main')
96 files changed, 11765 insertions, 0 deletions
diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/AttributeCertificateHolder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/AttributeCertificateHolder.java new file mode 100644 index 00000000..7d1ff368 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/AttributeCertificateHolder.java @@ -0,0 +1,374 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert; + +import java.io.OutputStream; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +import com.android.org.bouncycastle.asn1.ASN1Integer; +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.ASN1Sequence; +import com.android.org.bouncycastle.asn1.x500.X500Name; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.asn1.x509.GeneralName; +import com.android.org.bouncycastle.asn1.x509.GeneralNames; +import com.android.org.bouncycastle.asn1.x509.Holder; +import com.android.org.bouncycastle.asn1.x509.IssuerSerial; +import com.android.org.bouncycastle.asn1.x509.ObjectDigestInfo; +import com.android.org.bouncycastle.operator.DigestCalculator; +import com.android.org.bouncycastle.operator.DigestCalculatorProvider; +import com.android.org.bouncycastle.util.Arrays; +import com.android.org.bouncycastle.util.Selector; + +/** + * The Holder object. + * + * <pre> + * Holder ::= SEQUENCE { + * baseCertificateID [0] IssuerSerial OPTIONAL, + * -- the issuer and serial number of + * -- the holder's Public Key Certificate + * entityName [1] GeneralNames OPTIONAL, + * -- the name of the claimant or role + * objectDigestInfo [2] ObjectDigestInfo OPTIONAL + * -- used to directly authenticate the holder, + * -- for example, an executable + * } + * </pre> + * <p> + * <b>Note:</b> If objectDigestInfo comparisons are to be carried out the static + * method setDigestCalculatorProvider <b>must</b> be called once to configure the class + * to do the necessary calculations. + * </p> + */ +public class AttributeCertificateHolder + implements Selector +{ + private static DigestCalculatorProvider digestCalculatorProvider; + + final Holder holder; + + AttributeCertificateHolder(ASN1Sequence seq) + { + holder = Holder.getInstance(seq); + } + + /** + * Create a holder using the baseCertificateID element. + * + * @param issuerName name of associated certificate's issuer. + * @param serialNumber serial number of associated certificate. + */ + public AttributeCertificateHolder(X500Name issuerName, + BigInteger serialNumber) + { + holder = new Holder(new IssuerSerial( + generateGeneralNames(issuerName), + new ASN1Integer(serialNumber))); + } + + /** + * Create a holder using the baseCertificateID option based on the passed in associated certificate, + * + * @param cert the certificate to be associated with this holder. + */ + public AttributeCertificateHolder(X509CertificateHolder cert) + { + holder = new Holder(new IssuerSerial(generateGeneralNames(cert.getIssuer()), + new ASN1Integer(cert.getSerialNumber()))); + } + + /** + * Create a holder using the entityName option based on the passed in principal. + * + * @param principal the entityName to be associated with the attribute certificate. + */ + public AttributeCertificateHolder(X500Name principal) + { + holder = new Holder(generateGeneralNames(principal)); + } + + /** + * Constructs a holder for v2 attribute certificates with a hash value for + * some type of object. + * <p> + * <code>digestedObjectType</code> can be one of the following: + * <ul> + * <li>0 - publicKey - A hash of the public key of the holder must be + * passed. + * <li>1 - publicKeyCert - A hash of the public key certificate of the + * holder must be passed. + * <li>2 - otherObjectDigest - A hash of some other object type must be + * passed. <code>otherObjectTypeID</code> must not be empty. + * </ul> + * <p> + * This cannot be used if a v1 attribute certificate is used. + * + * @param digestedObjectType The digest object type. + * @param digestAlgorithm The algorithm identifier for the hash. + * @param otherObjectTypeID The object type ID if + * <code>digestedObjectType</code> is + * <code>otherObjectDigest</code>. + * @param objectDigest The hash value. + */ + public AttributeCertificateHolder(int digestedObjectType, + ASN1ObjectIdentifier digestAlgorithm, ASN1ObjectIdentifier otherObjectTypeID, byte[] objectDigest) + { + holder = new Holder(new ObjectDigestInfo(digestedObjectType, + otherObjectTypeID, new AlgorithmIdentifier(digestAlgorithm), Arrays + .clone(objectDigest))); + } + + /** + * Returns the digest object type if an object digest info is used. + * <p> + * <ul> + * <li>0 - publicKey - A hash of the public key of the holder must be + * passed. + * <li>1 - publicKeyCert - A hash of the public key certificate of the + * holder must be passed. + * <li>2 - otherObjectDigest - A hash of some other object type must be + * passed. <code>otherObjectTypeID</code> must not be empty. + * </ul> + * + * @return The digest object type or -1 if no object digest info is set. + */ + public int getDigestedObjectType() + { + if (holder.getObjectDigestInfo() != null) + { + return holder.getObjectDigestInfo().getDigestedObjectType() + .getValue().intValue(); + } + return -1; + } + + /** + * Returns algorithm identifier for the digest used if ObjectDigestInfo is present. + * + * @return digest AlgorithmIdentifier or <code>null</code> if ObjectDigestInfo is absent. + */ + public AlgorithmIdentifier getDigestAlgorithm() + { + if (holder.getObjectDigestInfo() != null) + { + return holder.getObjectDigestInfo().getDigestAlgorithm(); + } + return null; + } + + /** + * Returns the hash if an object digest info is used. + * + * @return The hash or <code>null</code> if ObjectDigestInfo is absent. + */ + public byte[] getObjectDigest() + { + if (holder.getObjectDigestInfo() != null) + { + return holder.getObjectDigestInfo().getObjectDigest().getBytes(); + } + return null; + } + + /** + * Returns the digest algorithm ID if an object digest info is used. + * + * @return The digest algorithm ID or <code>null</code> if no object + * digest info is set. + */ + public ASN1ObjectIdentifier getOtherObjectTypeID() + { + if (holder.getObjectDigestInfo() != null) + { + new ASN1ObjectIdentifier(holder.getObjectDigestInfo().getOtherObjectTypeID().getId()); + } + return null; + } + + private GeneralNames generateGeneralNames(X500Name principal) + { + return new GeneralNames(new GeneralName(principal)); + } + + private boolean matchesDN(X500Name subject, GeneralNames targets) + { + GeneralName[] names = targets.getNames(); + + for (int i = 0; i != names.length; i++) + { + GeneralName gn = names[i]; + + if (gn.getTagNo() == GeneralName.directoryName) + { + if (X500Name.getInstance(gn.getName()).equals(subject)) + { + return true; + } + } + } + + return false; + } + + private X500Name[] getPrincipals(GeneralName[] names) + { + List l = new ArrayList(names.length); + + for (int i = 0; i != names.length; i++) + { + if (names[i].getTagNo() == GeneralName.directoryName) + { + l.add(X500Name.getInstance(names[i].getName())); + } + } + + return (X500Name[])l.toArray(new X500Name[l.size()]); + } + + /** + * Return any principal objects inside the attribute certificate holder + * entity names field. + * + * @return an array of Principal objects (usually X500Principal), null if no + * entity names field is set. + */ + public X500Name[] getEntityNames() + { + if (holder.getEntityName() != null) + { + return getPrincipals(holder.getEntityName().getNames()); + } + + return null; + } + + /** + * Return the principals associated with the issuer attached to this holder + * + * @return an array of principals, null if no BaseCertificateID is set. + */ + public X500Name[] getIssuer() + { + if (holder.getBaseCertificateID() != null) + { + return getPrincipals(holder.getBaseCertificateID().getIssuer().getNames()); + } + + return null; + } + + /** + * Return the serial number associated with the issuer attached to this + * holder. + * + * @return the certificate serial number, null if no BaseCertificateID is + * set. + */ + public BigInteger getSerialNumber() + { + if (holder.getBaseCertificateID() != null) + { + return holder.getBaseCertificateID().getSerial().getValue(); + } + + return null; + } + + public Object clone() + { + return new AttributeCertificateHolder((ASN1Sequence)holder.toASN1Primitive()); + } + + public boolean match(Object obj) + { + if (!(obj instanceof X509CertificateHolder)) + { + return false; + } + + X509CertificateHolder x509Cert = (X509CertificateHolder)obj; + + if (holder.getBaseCertificateID() != null) + { + return holder.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber()) + && matchesDN(x509Cert.getIssuer(), holder.getBaseCertificateID().getIssuer()); + } + + if (holder.getEntityName() != null) + { + if (matchesDN(x509Cert.getSubject(), + holder.getEntityName())) + { + return true; + } + } + + if (holder.getObjectDigestInfo() != null) + { + try + { + DigestCalculator digCalc = digestCalculatorProvider.get(holder.getObjectDigestInfo().getDigestAlgorithm()); + OutputStream digOut = digCalc.getOutputStream(); + + switch (getDigestedObjectType()) + { + case ObjectDigestInfo.publicKey: + // TODO: DSA Dss-parms + digOut.write(x509Cert.getSubjectPublicKeyInfo().getEncoded()); + break; + case ObjectDigestInfo.publicKeyCert: + digOut.write(x509Cert.getEncoded()); + break; + } + + digOut.close(); + + if (!Arrays.areEqual(digCalc.getDigest(), getObjectDigest())) + { + return false; + } + } + catch (Exception e) + { + return false; + } + } + + return false; + } + + public boolean equals(Object obj) + { + if (obj == this) + { + return true; + } + + if (!(obj instanceof AttributeCertificateHolder)) + { + return false; + } + + AttributeCertificateHolder other = (AttributeCertificateHolder)obj; + + return this.holder.equals(other.holder); + } + + public int hashCode() + { + return this.holder.hashCode(); + } + + /** + * Set a digest calculator provider to be used if matches are attempted using + * ObjectDigestInfo, + * + * @param digCalcProvider a provider of digest calculators. + */ + public static void setDigestCalculatorProvider(DigestCalculatorProvider digCalcProvider) + { + digestCalculatorProvider = digCalcProvider; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/AttributeCertificateIssuer.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/AttributeCertificateIssuer.java new file mode 100644 index 00000000..0248fec8 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/AttributeCertificateIssuer.java @@ -0,0 +1,148 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert; + +import java.util.ArrayList; +import java.util.List; + +import com.android.org.bouncycastle.asn1.ASN1Encodable; +import com.android.org.bouncycastle.asn1.x500.X500Name; +import com.android.org.bouncycastle.asn1.x509.AttCertIssuer; +import com.android.org.bouncycastle.asn1.x509.GeneralName; +import com.android.org.bouncycastle.asn1.x509.GeneralNames; +import com.android.org.bouncycastle.asn1.x509.V2Form; +import com.android.org.bouncycastle.util.Selector; + +/** + * Carrying class for an attribute certificate issuer. + */ +public class AttributeCertificateIssuer + implements Selector +{ + final ASN1Encodable form; + + /** + * Set the issuer directly with the ASN.1 structure. + * + * @param issuer The issuer + */ + public AttributeCertificateIssuer(AttCertIssuer issuer) + { + form = issuer.getIssuer(); + } + + public AttributeCertificateIssuer(X500Name principal) + { + form = new V2Form(new GeneralNames(new GeneralName(principal))); + } + + public X500Name[] getNames() + { + GeneralNames name; + + if (form instanceof V2Form) + { + name = ((V2Form)form).getIssuerName(); + } + else + { + name = (GeneralNames)form; + } + + GeneralName[] names = name.getNames(); + + List l = new ArrayList(names.length); + + for (int i = 0; i != names.length; i++) + { + if (names[i].getTagNo() == GeneralName.directoryName) + { + l.add(X500Name.getInstance(names[i].getName())); + } + } + + return (X500Name[])l.toArray(new X500Name[l.size()]); + } + + private boolean matchesDN(X500Name subject, GeneralNames targets) + { + GeneralName[] names = targets.getNames(); + + for (int i = 0; i != names.length; i++) + { + GeneralName gn = names[i]; + + if (gn.getTagNo() == GeneralName.directoryName) + { + if (X500Name.getInstance(gn.getName()).equals(subject)) + { + return true; + } + } + } + + return false; + } + + public Object clone() + { + return new AttributeCertificateIssuer(AttCertIssuer.getInstance(form)); + } + + public boolean equals(Object obj) + { + if (obj == this) + { + return true; + } + + if (!(obj instanceof AttributeCertificateIssuer)) + { + return false; + } + + AttributeCertificateIssuer other = (AttributeCertificateIssuer)obj; + + return this.form.equals(other.form); + } + + public int hashCode() + { + return this.form.hashCode(); + } + + public boolean match(Object obj) + { + if (!(obj instanceof X509CertificateHolder)) + { + return false; + } + + X509CertificateHolder x509Cert = (X509CertificateHolder)obj; + + if (form instanceof V2Form) + { + V2Form issuer = (V2Form)form; + if (issuer.getBaseCertificateID() != null) + { + return issuer.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber()) + && matchesDN(x509Cert.getIssuer(), issuer.getBaseCertificateID().getIssuer()); + } + + GeneralNames name = issuer.getIssuerName(); + if (matchesDN(x509Cert.getSubject(), name)) + { + return true; + } + } + else + { + GeneralNames name = (GeneralNames)form; + if (matchesDN(x509Cert.getSubject(), name)) + { + return true; + } + } + + return false; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/CertException.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/CertException.java new file mode 100644 index 00000000..e1b73e0e --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/CertException.java @@ -0,0 +1,28 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert; + +/** + * General checked Exception thrown in the cert package and its sub-packages. + */ +public class CertException + extends Exception +{ + private Throwable cause; + + public CertException(String msg, Throwable cause) + { + super(msg); + + this.cause = cause; + } + + public CertException(String msg) + { + super(msg); + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/CertIOException.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/CertIOException.java new file mode 100644 index 00000000..76986259 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/CertIOException.java @@ -0,0 +1,30 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert; + +import java.io.IOException; + +/** + * General IOException thrown in the cert package and its sub-packages. + */ +public class CertIOException + extends IOException +{ + private Throwable cause; + + public CertIOException(String msg, Throwable cause) + { + super(msg); + + this.cause = cause; + } + + public CertIOException(String msg) + { + super(msg); + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/CertUtils.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/CertUtils.java new file mode 100644 index 00000000..254c8477 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/CertUtils.java @@ -0,0 +1,258 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert; + +import java.io.IOException; +import java.io.OutputStream; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.android.org.bouncycastle.asn1.ASN1Encodable; +import com.android.org.bouncycastle.asn1.ASN1EncodableVector; +import com.android.org.bouncycastle.asn1.ASN1GeneralizedTime; +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.ASN1Primitive; +import com.android.org.bouncycastle.asn1.DERBitString; +import com.android.org.bouncycastle.asn1.DERNull; +import com.android.org.bouncycastle.asn1.DEROutputStream; +import com.android.org.bouncycastle.asn1.DERSequence; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.asn1.x509.AttributeCertificate; +import com.android.org.bouncycastle.asn1.x509.AttributeCertificateInfo; +import com.android.org.bouncycastle.asn1.x509.Certificate; +import com.android.org.bouncycastle.asn1.x509.CertificateList; +import com.android.org.bouncycastle.asn1.x509.Extensions; +import com.android.org.bouncycastle.asn1.x509.ExtensionsGenerator; +import com.android.org.bouncycastle.asn1.x509.TBSCertList; +import com.android.org.bouncycastle.asn1.x509.TBSCertificate; +import com.android.org.bouncycastle.operator.ContentSigner; + +class CertUtils +{ + private static Set EMPTY_SET = Collections.unmodifiableSet(new HashSet()); + private static List EMPTY_LIST = Collections.unmodifiableList(new ArrayList()); + + static ASN1Primitive parseNonEmptyASN1(byte[] encoding) + throws IOException + { + ASN1Primitive p = ASN1Primitive.fromByteArray(encoding); + + if (p == null) + { + throw new IOException("no content found"); + } + return p; + } + + static X509CertificateHolder generateFullCert(ContentSigner signer, TBSCertificate tbsCert) + { + try + { + return new X509CertificateHolder(generateStructure(tbsCert, signer.getAlgorithmIdentifier(), generateSig(signer, tbsCert))); + } + catch (IOException e) + { + throw new IllegalStateException("cannot produce certificate signature"); + } + } + + static X509AttributeCertificateHolder generateFullAttrCert(ContentSigner signer, AttributeCertificateInfo attrInfo) + { + try + { + return new X509AttributeCertificateHolder(generateAttrStructure(attrInfo, signer.getAlgorithmIdentifier(), generateSig(signer, attrInfo))); + } + catch (IOException e) + { + throw new IllegalStateException("cannot produce attribute certificate signature"); + } + } + + static X509CRLHolder generateFullCRL(ContentSigner signer, TBSCertList tbsCertList) + { + try + { + return new X509CRLHolder(generateCRLStructure(tbsCertList, signer.getAlgorithmIdentifier(), generateSig(signer, tbsCertList))); + } + catch (IOException e) + { + throw new IllegalStateException("cannot produce certificate signature"); + } + } + + private static byte[] generateSig(ContentSigner signer, ASN1Encodable tbsObj) + throws IOException + { + OutputStream sOut = signer.getOutputStream(); + DEROutputStream dOut = new DEROutputStream(sOut); + + dOut.writeObject(tbsObj); + + sOut.close(); + + return signer.getSignature(); + } + + private static Certificate generateStructure(TBSCertificate tbsCert, AlgorithmIdentifier sigAlgId, byte[] signature) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(tbsCert); + v.add(sigAlgId); + v.add(new DERBitString(signature)); + + return Certificate.getInstance(new DERSequence(v)); + } + + private static AttributeCertificate generateAttrStructure(AttributeCertificateInfo attrInfo, AlgorithmIdentifier sigAlgId, byte[] signature) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(attrInfo); + v.add(sigAlgId); + v.add(new DERBitString(signature)); + + return AttributeCertificate.getInstance(new DERSequence(v)); + } + + private static CertificateList generateCRLStructure(TBSCertList tbsCertList, AlgorithmIdentifier sigAlgId, byte[] signature) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(tbsCertList); + v.add(sigAlgId); + v.add(new DERBitString(signature)); + + return CertificateList.getInstance(new DERSequence(v)); + } + + static Set getCriticalExtensionOIDs(Extensions extensions) + { + if (extensions == null) + { + return EMPTY_SET; + } + + return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getCriticalExtensionOIDs()))); + } + + static Set getNonCriticalExtensionOIDs(Extensions extensions) + { + if (extensions == null) + { + return EMPTY_SET; + } + + // TODO: should probably produce a set that imposes correct ordering + return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getNonCriticalExtensionOIDs()))); + } + + static List getExtensionOIDs(Extensions extensions) + { + if (extensions == null) + { + return EMPTY_LIST; + } + + return Collections.unmodifiableList(Arrays.asList(extensions.getExtensionOIDs())); + } + + static void addExtension(ExtensionsGenerator extGenerator, ASN1ObjectIdentifier oid, boolean isCritical, ASN1Encodable value) + throws CertIOException + { + try + { + extGenerator.addExtension(oid, isCritical, value); + } + catch (IOException e) + { + throw new CertIOException("cannot encode extension: " + e.getMessage(), e); + } + } + + static DERBitString booleanToBitString(boolean[] id) + { + byte[] bytes = new byte[(id.length + 7) / 8]; + + for (int i = 0; i != id.length; i++) + { + bytes[i / 8] |= (id[i]) ? (1 << ((7 - (i % 8)))) : 0; + } + + int pad = id.length % 8; + + if (pad == 0) + { + return new DERBitString(bytes); + } + else + { + return new DERBitString(bytes, 8 - pad); + } + } + + static boolean[] bitStringToBoolean(DERBitString bitString) + { + if (bitString != null) + { + byte[] bytes = bitString.getBytes(); + boolean[] boolId = new boolean[bytes.length * 8 - bitString.getPadBits()]; + + for (int i = 0; i != boolId.length; i++) + { + boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0; + } + + return boolId; + } + + return null; + } + + static Date recoverDate(ASN1GeneralizedTime time) + { + try + { + return time.getDate(); + } + catch (ParseException e) + { + throw new IllegalStateException("unable to recover date: " + e.getMessage()); + } + } + + static 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()); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/X509AttributeCertificateHolder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/X509AttributeCertificateHolder.java new file mode 100644 index 00000000..8bbcfbcb --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/X509AttributeCertificateHolder.java @@ -0,0 +1,368 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert; + +import java.io.IOException; +import java.io.OutputStream; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Set; + +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.ASN1Sequence; +import com.android.org.bouncycastle.asn1.DEROutputStream; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.asn1.x509.AttCertValidityPeriod; +import com.android.org.bouncycastle.asn1.x509.Attribute; +import com.android.org.bouncycastle.asn1.x509.AttributeCertificate; +import com.android.org.bouncycastle.asn1.x509.AttributeCertificateInfo; +import com.android.org.bouncycastle.asn1.x509.Extension; +import com.android.org.bouncycastle.asn1.x509.Extensions; +import com.android.org.bouncycastle.operator.ContentVerifier; +import com.android.org.bouncycastle.operator.ContentVerifierProvider; +import com.android.org.bouncycastle.util.Encodable; + +/** + * Holding class for an X.509 AttributeCertificate structure. + */ +public class X509AttributeCertificateHolder + implements Encodable +{ + private static Attribute[] EMPTY_ARRAY = new Attribute[0]; + + private AttributeCertificate attrCert; + private Extensions extensions; + + private static AttributeCertificate parseBytes(byte[] certEncoding) + throws IOException + { + try + { + return AttributeCertificate.getInstance(CertUtils.parseNonEmptyASN1(certEncoding)); + } + catch (ClassCastException e) + { + throw new CertIOException("malformed data: " + e.getMessage(), e); + } + catch (IllegalArgumentException e) + { + throw new CertIOException("malformed data: " + e.getMessage(), e); + } + } + + /** + * Create a X509AttributeCertificateHolder from the passed in bytes. + * + * @param certEncoding BER/DER encoding of the certificate. + * @throws IOException in the event of corrupted data, or an incorrect structure. + */ + public X509AttributeCertificateHolder(byte[] certEncoding) + throws IOException + { + this(parseBytes(certEncoding)); + } + + /** + * Create a X509AttributeCertificateHolder from the passed in ASN.1 structure. + * + * @param attrCert an ASN.1 AttributeCertificate structure. + */ + public X509AttributeCertificateHolder(AttributeCertificate attrCert) + { + this.attrCert = attrCert; + this.extensions = attrCert.getAcinfo().getExtensions(); + } + + /** + * Return the ASN.1 encoding of this holder's attribute certificate. + * + * @return a DER encoded byte array. + * @throws IOException if an encoding cannot be generated. + */ + public byte[] getEncoded() + throws IOException + { + return attrCert.getEncoded(); + } + + public int getVersion() + { + return attrCert.getAcinfo().getVersion().getValue().intValue() + 1; + } + + /** + * Return the serial number of this attribute certificate. + * + * @return the serial number. + */ + public BigInteger getSerialNumber() + { + return attrCert.getAcinfo().getSerialNumber().getValue(); + } + + /** + * Return the holder details for this attribute certificate. + * + * @return this attribute certificate's holder structure. + */ + public AttributeCertificateHolder getHolder() + { + return new AttributeCertificateHolder((ASN1Sequence)attrCert.getAcinfo().getHolder().toASN1Primitive()); + } + + /** + * Return the issuer details for this attribute certificate. + * + * @return this attribute certificate's issuer structure, + */ + public AttributeCertificateIssuer getIssuer() + { + return new AttributeCertificateIssuer(attrCert.getAcinfo().getIssuer()); + } + + /** + * Return the date before which this attribute certificate is not valid. + * + * @return the start date for the attribute certificate's validity period. + */ + public Date getNotBefore() + { + return CertUtils.recoverDate(attrCert.getAcinfo().getAttrCertValidityPeriod().getNotBeforeTime()); + } + + /** + * Return the date after which this attribute certificate is not valid. + * + * @return the final date for the attribute certificate's validity period. + */ + public Date getNotAfter() + { + return CertUtils.recoverDate(attrCert.getAcinfo().getAttrCertValidityPeriod().getNotAfterTime()); + } + + /** + * Return the attributes, if any associated with this request. + * + * @return an array of Attribute, zero length if none present. + */ + public Attribute[] getAttributes() + { + ASN1Sequence seq = attrCert.getAcinfo().getAttributes(); + Attribute[] attrs = new Attribute[seq.size()]; + + for (int i = 0; i != seq.size(); i++) + { + attrs[i] = Attribute.getInstance(seq.getObjectAt(i)); + } + + return attrs; + } + + /** + * Return an array of attributes matching the passed in type OID. + * + * @param type the type of the attribute being looked for. + * @return an array of Attribute of the requested type, zero length if none present. + */ + public Attribute[] getAttributes(ASN1ObjectIdentifier type) + { + ASN1Sequence seq = attrCert.getAcinfo().getAttributes(); + List list = new ArrayList(); + + for (int i = 0; i != seq.size(); i++) + { + Attribute attr = Attribute.getInstance(seq.getObjectAt(i)); + if (attr.getAttrType().equals(type)) + { + list.add(attr); + } + } + + if (list.size() == 0) + { + return EMPTY_ARRAY; + } + + return (Attribute[])list.toArray(new Attribute[list.size()]); + } + + /** + * Return whether or not the holder's attribute certificate contains extensions. + * + * @return true if extension are present, false otherwise. + */ + public boolean hasExtensions() + { + return extensions != null; + } + + /** + * Look up the extension associated with the passed in OID. + * + * @param oid the OID of the extension of interest. + * + * @return the extension if present, null otherwise. + */ + public Extension getExtension(ASN1ObjectIdentifier oid) + { + if (extensions != null) + { + return extensions.getExtension(oid); + } + + return null; + } + + /** + * Return the extensions block associated with this certificate if there is one. + * + * @return the extensions block, null otherwise. + */ + public Extensions getExtensions() + { + return extensions; + } + + /** + * Returns a list of ASN1ObjectIdentifier objects representing the OIDs of the + * extensions contained in this holder's attribute certificate. + * + * @return a list of extension OIDs. + */ + public List getExtensionOIDs() + { + return CertUtils.getExtensionOIDs(extensions); + } + + /** + * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the + * critical extensions contained in this holder's attribute certificate. + * + * @return a set of critical extension OIDs. + */ + public Set getCriticalExtensionOIDs() + { + return CertUtils.getCriticalExtensionOIDs(extensions); + } + + /** + * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the + * non-critical extensions contained in this holder's attribute certificate. + * + * @return a set of non-critical extension OIDs. + */ + public Set getNonCriticalExtensionOIDs() + { + return CertUtils.getNonCriticalExtensionOIDs(extensions); + } + + public boolean[] getIssuerUniqueID() + { + return CertUtils.bitStringToBoolean(attrCert.getAcinfo().getIssuerUniqueID()); + } + + /** + * Return the details of the signature algorithm used to create this attribute certificate. + * + * @return the AlgorithmIdentifier describing the signature algorithm used to create this attribute certificate. + */ + public AlgorithmIdentifier getSignatureAlgorithm() + { + return attrCert.getSignatureAlgorithm(); + } + + /** + * Return the bytes making up the signature associated with this attribute certificate. + * + * @return the attribute certificate signature bytes. + */ + public byte[] getSignature() + { + return attrCert.getSignatureValue().getOctets(); + } + + /** + * Return the underlying ASN.1 structure for the attribute certificate in this holder. + * + * @return a AttributeCertificate object. + */ + public AttributeCertificate toASN1Structure() + { + return attrCert; + } + + /** + * Return whether or not this attribute certificate is valid on a particular date. + * + * @param date the date of interest. + * @return true if the attribute certificate is valid, false otherwise. + */ + public boolean isValidOn(Date date) + { + AttCertValidityPeriod certValidityPeriod = attrCert.getAcinfo().getAttrCertValidityPeriod(); + + return !date.before(CertUtils.recoverDate(certValidityPeriod.getNotBeforeTime())) && !date.after(CertUtils.recoverDate(certValidityPeriod.getNotAfterTime())); + } + + /** + * Validate the signature on the attribute certificate in this holder. + * + * @param verifierProvider a ContentVerifierProvider that can generate a verifier for the signature. + * @return true if the signature is valid, false otherwise. + * @throws CertException if the signature cannot be processed or is inappropriate. + */ + public boolean isSignatureValid(ContentVerifierProvider verifierProvider) + throws CertException + { + AttributeCertificateInfo acinfo = attrCert.getAcinfo(); + + if (!CertUtils.isAlgIdEqual(acinfo.getSignature(), attrCert.getSignatureAlgorithm())) + { + throw new CertException("signature invalid - algorithm identifier mismatch"); + } + + ContentVerifier verifier; + + try + { + verifier = verifierProvider.get((acinfo.getSignature())); + + OutputStream sOut = verifier.getOutputStream(); + DEROutputStream dOut = new DEROutputStream(sOut); + + dOut.writeObject(acinfo); + + sOut.close(); + } + catch (Exception e) + { + throw new CertException("unable to process signature: " + e.getMessage(), e); + } + + return verifier.verify(this.getSignature()); + } + + public boolean equals( + Object o) + { + if (o == this) + { + return true; + } + + if (!(o instanceof X509AttributeCertificateHolder)) + { + return false; + } + + X509AttributeCertificateHolder other = (X509AttributeCertificateHolder)o; + + return this.attrCert.equals(other.attrCert); + } + + public int hashCode() + { + return this.attrCert.hashCode(); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/X509CRLEntryHolder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/X509CRLEntryHolder.java new file mode 100644 index 00000000..3e7e30cd --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/X509CRLEntryHolder.java @@ -0,0 +1,145 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert; + +import java.math.BigInteger; +import java.util.Date; +import java.util.List; +import java.util.Set; + +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.x509.Extension; +import com.android.org.bouncycastle.asn1.x509.Extensions; +import com.android.org.bouncycastle.asn1.x509.GeneralNames; +import com.android.org.bouncycastle.asn1.x509.TBSCertList; + +/** + * Holding class for an X.509 CRL Entry structure. + */ +public class X509CRLEntryHolder +{ + private TBSCertList.CRLEntry entry; + private GeneralNames ca; + + X509CRLEntryHolder(TBSCertList.CRLEntry entry, boolean isIndirect, GeneralNames previousCA) + { + this.entry = entry; + this.ca = previousCA; + + if (isIndirect && entry.hasExtensions()) + { + Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer); + + if (currentCaName != null) + { + ca = GeneralNames.getInstance(currentCaName.getParsedValue()); + } + } + } + + /** + * Return the serial number of the certificate associated with this CRLEntry. + * + * @return the revoked certificate's serial number. + */ + public BigInteger getSerialNumber() + { + return entry.getUserCertificate().getValue(); + } + + /** + * Return the date on which the certificate associated with this CRLEntry was revoked. + * + * @return the revocation date for the revoked certificate. + */ + public Date getRevocationDate() + { + return entry.getRevocationDate().getDate(); + } + + /** + * Return whether or not the holder's CRL entry contains extensions. + * + * @return true if extension are present, false otherwise. + */ + public boolean hasExtensions() + { + return entry.hasExtensions(); + } + + /** + * Return the available names for the certificate issuer for the certificate referred to by this CRL entry. + * <p> + * Note: this will be the issuer of the CRL unless it has been specified that the CRL is indirect + * in the IssuingDistributionPoint extension and either a previous entry, or the current one, + * has specified a different CA via the certificateIssuer extension. + * </p> + * + * @return the revoked certificate's issuer. + */ + public GeneralNames getCertificateIssuer() + { + return this.ca; + } + + /** + * Look up the extension associated with the passed in OID. + * + * @param oid the OID of the extension of interest. + * + * @return the extension if present, null otherwise. + */ + public Extension getExtension(ASN1ObjectIdentifier oid) + { + Extensions extensions = entry.getExtensions(); + + if (extensions != null) + { + return extensions.getExtension(oid); + } + + return null; + } + + /** + * Return the extensions block associated with this CRL entry if there is one. + * + * @return the extensions block, null otherwise. + */ + public Extensions getExtensions() + { + return entry.getExtensions(); + } + + /** + * Returns a list of ASN1ObjectIdentifier objects representing the OIDs of the + * extensions contained in this holder's CRL entry. + * + * @return a list of extension OIDs. + */ + public List getExtensionOIDs() + { + return CertUtils.getExtensionOIDs(entry.getExtensions()); + } + + /** + * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the + * critical extensions contained in this holder's CRL entry. + * + * @return a set of critical extension OIDs. + */ + public Set getCriticalExtensionOIDs() + { + return CertUtils.getCriticalExtensionOIDs(entry.getExtensions()); + } + + /** + * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the + * non-critical extensions contained in this holder's CRL entry. + * + * @return a set of non-critical extension OIDs. + */ + public Set getNonCriticalExtensionOIDs() + { + return CertUtils.getNonCriticalExtensionOIDs(entry.getExtensions()); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/X509CRLHolder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/X509CRLHolder.java new file mode 100644 index 00000000..bffa65a8 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/X509CRLHolder.java @@ -0,0 +1,326 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.List; +import java.util.Set; + +import com.android.org.bouncycastle.asn1.ASN1InputStream; +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.ASN1Primitive; +import com.android.org.bouncycastle.asn1.DEROutputStream; +import com.android.org.bouncycastle.asn1.x500.X500Name; +import com.android.org.bouncycastle.asn1.x509.CertificateList; +import com.android.org.bouncycastle.asn1.x509.Extension; +import com.android.org.bouncycastle.asn1.x509.Extensions; +import com.android.org.bouncycastle.asn1.x509.GeneralName; +import com.android.org.bouncycastle.asn1.x509.GeneralNames; +import com.android.org.bouncycastle.asn1.x509.IssuingDistributionPoint; +import com.android.org.bouncycastle.asn1.x509.TBSCertList; +import com.android.org.bouncycastle.operator.ContentVerifier; +import com.android.org.bouncycastle.operator.ContentVerifierProvider; +import com.android.org.bouncycastle.util.Encodable; + +/** + * Holding class for an X.509 CRL structure. + */ +public class X509CRLHolder + implements Encodable +{ + private CertificateList x509CRL; + private boolean isIndirect; + private Extensions extensions; + private GeneralNames issuerName; + + private static CertificateList parseStream(InputStream stream) + throws IOException + { + try + { + ASN1Primitive obj = new ASN1InputStream(stream, true).readObject(); + if (obj == null) + { + throw new IOException("no content found"); + } + return CertificateList.getInstance(obj); + } + catch (ClassCastException e) + { + throw new CertIOException("malformed data: " + e.getMessage(), e); + } + catch (IllegalArgumentException e) + { + throw new CertIOException("malformed data: " + e.getMessage(), e); + } + } + + private static boolean isIndirectCRL(Extensions extensions) + { + if (extensions == null) + { + return false; + } + + Extension ext = extensions.getExtension(Extension.issuingDistributionPoint); + + return ext != null && IssuingDistributionPoint.getInstance(ext.getParsedValue()).isIndirectCRL(); + } + + /** + * Create a X509CRLHolder from the passed in bytes. + * + * @param crlEncoding BER/DER encoding of the CRL + * @throws IOException in the event of corrupted data, or an incorrect structure. + */ + public X509CRLHolder(byte[] crlEncoding) + throws IOException + { + this(parseStream(new ByteArrayInputStream(crlEncoding))); + } + + /** + * Create a X509CRLHolder from the passed in InputStream. + * + * @param crlStream BER/DER encoded InputStream of the CRL + * @throws IOException in the event of corrupted data, or an incorrect structure. + */ + public X509CRLHolder(InputStream crlStream) + throws IOException + { + this(parseStream(crlStream)); + } + + /** + * Create a X509CRLHolder from the passed in ASN.1 structure. + * + * @param x509CRL an ASN.1 CertificateList structure. + */ + public X509CRLHolder(CertificateList x509CRL) + { + this.x509CRL = x509CRL; + this.extensions = x509CRL.getTBSCertList().getExtensions(); + this.isIndirect = isIndirectCRL(extensions); + this.issuerName = new GeneralNames(new GeneralName(x509CRL.getIssuer())); + } + + /** + * Return the ASN.1 encoding of this holder's CRL. + * + * @return a DER encoded byte array. + * @throws IOException if an encoding cannot be generated. + */ + public byte[] getEncoded() + throws IOException + { + return x509CRL.getEncoded(); + } + + /** + * Return the issuer of this holder's CRL. + * + * @return the CRL issuer. + */ + public X500Name getIssuer() + { + return X500Name.getInstance(x509CRL.getIssuer()); + } + + public X509CRLEntryHolder getRevokedCertificate(BigInteger serialNumber) + { + GeneralNames currentCA = issuerName; + for (Enumeration en = x509CRL.getRevokedCertificateEnumeration(); en.hasMoreElements();) + { + TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)en.nextElement(); + + if (entry.getUserCertificate().getValue().equals(serialNumber)) + { + return new X509CRLEntryHolder(entry, isIndirect, currentCA); + } + + if (isIndirect && entry.hasExtensions()) + { + Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer); + + if (currentCaName != null) + { + currentCA = GeneralNames.getInstance(currentCaName.getParsedValue()); + } + } + } + + return null; + } + + /** + * Return a collection of X509CRLEntryHolder objects, giving the details of the + * revoked certificates that appear on this CRL. + * + * @return the revoked certificates as a collection of X509CRLEntryHolder objects. + */ + public Collection getRevokedCertificates() + { + TBSCertList.CRLEntry[] entries = x509CRL.getRevokedCertificates(); + List l = new ArrayList(entries.length); + GeneralNames currentCA = issuerName; + + for (Enumeration en = x509CRL.getRevokedCertificateEnumeration(); en.hasMoreElements();) + { + TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)en.nextElement(); + X509CRLEntryHolder crlEntry = new X509CRLEntryHolder(entry, isIndirect, currentCA); + + l.add(crlEntry); + + currentCA = crlEntry.getCertificateIssuer(); + } + + return l; + } + + /** + * Return whether or not the holder's CRL contains extensions. + * + * @return true if extension are present, false otherwise. + */ + public boolean hasExtensions() + { + return extensions != null; + } + + /** + * Look up the extension associated with the passed in OID. + * + * @param oid the OID of the extension of interest. + * + * @return the extension if present, null otherwise. + */ + public Extension getExtension(ASN1ObjectIdentifier oid) + { + if (extensions != null) + { + return extensions.getExtension(oid); + } + + return null; + } + + /** + * Return the extensions block associated with this CRL if there is one. + * + * @return the extensions block, null otherwise. + */ + public Extensions getExtensions() + { + return extensions; + } + + /** + * Returns a list of ASN1ObjectIdentifier objects representing the OIDs of the + * extensions contained in this holder's CRL. + * + * @return a list of extension OIDs. + */ + public List getExtensionOIDs() + { + return CertUtils.getExtensionOIDs(extensions); + } + + /** + * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the + * critical extensions contained in this holder's CRL. + * + * @return a set of critical extension OIDs. + */ + public Set getCriticalExtensionOIDs() + { + return CertUtils.getCriticalExtensionOIDs(extensions); + } + + /** + * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the + * non-critical extensions contained in this holder's CRL. + * + * @return a set of non-critical extension OIDs. + */ + public Set getNonCriticalExtensionOIDs() + { + return CertUtils.getNonCriticalExtensionOIDs(extensions); + } + + /** + * Return the underlying ASN.1 structure for the CRL in this holder. + * + * @return a CertificateList object. + */ + public CertificateList toASN1Structure() + { + return x509CRL; + } + + /** + * Validate the signature on the CRL. + * + * @param verifierProvider a ContentVerifierProvider that can generate a verifier for the signature. + * @return true if the signature is valid, false otherwise. + * @throws CertException if the signature cannot be processed or is inappropriate. + */ + public boolean isSignatureValid(ContentVerifierProvider verifierProvider) + throws CertException + { + TBSCertList tbsCRL = x509CRL.getTBSCertList(); + + if (!CertUtils.isAlgIdEqual(tbsCRL.getSignature(), x509CRL.getSignatureAlgorithm())) + { + throw new CertException("signature invalid - algorithm identifier mismatch"); + } + + ContentVerifier verifier; + + try + { + verifier = verifierProvider.get((tbsCRL.getSignature())); + + OutputStream sOut = verifier.getOutputStream(); + DEROutputStream dOut = new DEROutputStream(sOut); + + dOut.writeObject(tbsCRL); + + sOut.close(); + } + catch (Exception e) + { + throw new CertException("unable to process signature: " + e.getMessage(), e); + } + + return verifier.verify(x509CRL.getSignature().getOctets()); + } + + public boolean equals( + Object o) + { + if (o == this) + { + return true; + } + + if (!(o instanceof X509CRLHolder)) + { + return false; + } + + X509CRLHolder other = (X509CRLHolder)o; + + return this.x509CRL.equals(other.x509CRL); + } + + public int hashCode() + { + return this.x509CRL.hashCode(); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/X509CertificateHolder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/X509CertificateHolder.java new file mode 100644 index 00000000..3eba54d8 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/X509CertificateHolder.java @@ -0,0 +1,329 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert; + +import java.io.IOException; +import java.io.OutputStream; +import java.math.BigInteger; +import java.util.Date; +import java.util.List; +import java.util.Set; + +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.DEROutputStream; +import com.android.org.bouncycastle.asn1.x500.X500Name; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.asn1.x509.Certificate; +import com.android.org.bouncycastle.asn1.x509.Extension; +import com.android.org.bouncycastle.asn1.x509.Extensions; +import com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.android.org.bouncycastle.asn1.x509.TBSCertificate; +import com.android.org.bouncycastle.operator.ContentVerifier; +import com.android.org.bouncycastle.operator.ContentVerifierProvider; +import com.android.org.bouncycastle.util.Encodable; + +/** + * Holding class for an X.509 Certificate structure. + */ +public class X509CertificateHolder + implements Encodable +{ + private Certificate x509Certificate; + private Extensions extensions; + + private static Certificate parseBytes(byte[] certEncoding) + throws IOException + { + try + { + return Certificate.getInstance(CertUtils.parseNonEmptyASN1(certEncoding)); + } + catch (ClassCastException e) + { + throw new CertIOException("malformed data: " + e.getMessage(), e); + } + catch (IllegalArgumentException e) + { + throw new CertIOException("malformed data: " + e.getMessage(), e); + } + } + + /** + * Create a X509CertificateHolder from the passed in bytes. + * + * @param certEncoding BER/DER encoding of the certificate. + * @throws IOException in the event of corrupted data, or an incorrect structure. + */ + public X509CertificateHolder(byte[] certEncoding) + throws IOException + { + this(parseBytes(certEncoding)); + } + + /** + * Create a X509CertificateHolder from the passed in ASN.1 structure. + * + * @param x509Certificate an ASN.1 Certificate structure. + */ + public X509CertificateHolder(Certificate x509Certificate) + { + this.x509Certificate = x509Certificate; + this.extensions = x509Certificate.getTBSCertificate().getExtensions(); + } + + public int getVersionNumber() + { + return x509Certificate.getVersionNumber(); + } + + /** + * @deprecated use getVersionNumber + */ + public int getVersion() + { + return x509Certificate.getVersionNumber(); + } + + /** + * Return whether or not the holder's certificate contains extensions. + * + * @return true if extension are present, false otherwise. + */ + public boolean hasExtensions() + { + return extensions != null; + } + + /** + * Look up the extension associated with the passed in OID. + * + * @param oid the OID of the extension of interest. + * + * @return the extension if present, null otherwise. + */ + public Extension getExtension(ASN1ObjectIdentifier oid) + { + if (extensions != null) + { + return extensions.getExtension(oid); + } + + return null; + } + + /** + * Return the extensions block associated with this certificate if there is one. + * + * @return the extensions block, null otherwise. + */ + public Extensions getExtensions() + { + return extensions; + } + + /** + * Returns a list of ASN1ObjectIdentifier objects representing the OIDs of the + * extensions contained in this holder's certificate. + * + * @return a list of extension OIDs. + */ + public List getExtensionOIDs() + { + return CertUtils.getExtensionOIDs(extensions); + } + + /** + * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the + * critical extensions contained in this holder's certificate. + * + * @return a set of critical extension OIDs. + */ + public Set getCriticalExtensionOIDs() + { + return CertUtils.getCriticalExtensionOIDs(extensions); + } + + /** + * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the + * non-critical extensions contained in this holder's certificate. + * + * @return a set of non-critical extension OIDs. + */ + public Set getNonCriticalExtensionOIDs() + { + return CertUtils.getNonCriticalExtensionOIDs(extensions); + } + + /** + * Return the serial number of this attribute certificate. + * + * @return the serial number. + */ + public BigInteger getSerialNumber() + { + return x509Certificate.getSerialNumber().getValue(); + } + + /** + * Return the issuer of this certificate. + * + * @return the certificate issuer. + */ + public X500Name getIssuer() + { + return X500Name.getInstance(x509Certificate.getIssuer()); + } + + /** + * Return the subject this certificate is for. + * + * @return the subject for the certificate. + */ + public X500Name getSubject() + { + return X500Name.getInstance(x509Certificate.getSubject()); + } + + /** + * Return the date before which this certificate is not valid. + * + * @return the start time for the certificate's validity period. + */ + public Date getNotBefore() + { + return x509Certificate.getStartDate().getDate(); + } + + /** + * Return the date after which this certificate is not valid. + * + * @return the final time for the certificate's validity period. + */ + public Date getNotAfter() + { + return x509Certificate.getEndDate().getDate(); + } + + /** + * Return the SubjectPublicKeyInfo describing the public key this certificate is carrying. + * + * @return the public key ASN.1 structure contained in the certificate. + */ + public SubjectPublicKeyInfo getSubjectPublicKeyInfo() + { + return x509Certificate.getSubjectPublicKeyInfo(); + } + + /** + * Return the underlying ASN.1 structure for the certificate in this holder. + * + * @return a Certificate object. + */ + public Certificate toASN1Structure() + { + return x509Certificate; + } + + /** + * Return the details of the signature algorithm used to create this attribute certificate. + * + * @return the AlgorithmIdentifier describing the signature algorithm used to create this attribute certificate. + */ + public AlgorithmIdentifier getSignatureAlgorithm() + { + return x509Certificate.getSignatureAlgorithm(); + } + + /** + * Return the bytes making up the signature associated with this attribute certificate. + * + * @return the attribute certificate signature bytes. + */ + public byte[] getSignature() + { + return x509Certificate.getSignature().getOctets(); + } + + /** + * Return whether or not this certificate is valid on a particular date. + * + * @param date the date of interest. + * @return true if the certificate is valid, false otherwise. + */ + public boolean isValidOn(Date date) + { + return !date.before(x509Certificate.getStartDate().getDate()) && !date.after(x509Certificate.getEndDate().getDate()); + } + + /** + * Validate the signature on the certificate in this holder. + * + * @param verifierProvider a ContentVerifierProvider that can generate a verifier for the signature. + * @return true if the signature is valid, false otherwise. + * @throws CertException if the signature cannot be processed or is inappropriate. + */ + public boolean isSignatureValid(ContentVerifierProvider verifierProvider) + throws CertException + { + TBSCertificate tbsCert = x509Certificate.getTBSCertificate(); + + if (!CertUtils.isAlgIdEqual(tbsCert.getSignature(), x509Certificate.getSignatureAlgorithm())) + { + throw new CertException("signature invalid - algorithm identifier mismatch"); + } + + ContentVerifier verifier; + + try + { + verifier = verifierProvider.get((tbsCert.getSignature())); + + OutputStream sOut = verifier.getOutputStream(); + DEROutputStream dOut = new DEROutputStream(sOut); + + dOut.writeObject(tbsCert); + + sOut.close(); + } + catch (Exception e) + { + throw new CertException("unable to process signature: " + e.getMessage(), e); + } + + return verifier.verify(this.getSignature()); + } + + public boolean equals( + Object o) + { + if (o == this) + { + return true; + } + + if (!(o instanceof X509CertificateHolder)) + { + return false; + } + + X509CertificateHolder other = (X509CertificateHolder)o; + + return this.x509Certificate.equals(other.x509Certificate); + } + + public int hashCode() + { + return this.x509Certificate.hashCode(); + } + + /** + * Return the ASN.1 encoding of this holder's certificate. + * + * @return a DER encoded byte array. + * @throws IOException if an encoding cannot be generated. + */ + public byte[] getEncoded() + throws IOException + { + return x509Certificate.getEncoded(); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/X509v3CertificateBuilder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/X509v3CertificateBuilder.java new file mode 100644 index 00000000..f386abd8 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/X509v3CertificateBuilder.java @@ -0,0 +1,211 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert; + +import java.math.BigInteger; +import java.util.Date; +import java.util.Locale; + +import com.android.org.bouncycastle.asn1.ASN1Encodable; +import com.android.org.bouncycastle.asn1.ASN1Integer; +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.x500.X500Name; +import com.android.org.bouncycastle.asn1.x509.Certificate; +import com.android.org.bouncycastle.asn1.x509.Extension; +import com.android.org.bouncycastle.asn1.x509.ExtensionsGenerator; +import com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.android.org.bouncycastle.asn1.x509.Time; +import com.android.org.bouncycastle.asn1.x509.V3TBSCertificateGenerator; +import com.android.org.bouncycastle.operator.ContentSigner; + + +/** + * class to produce an X.509 Version 3 certificate. + */ +public class X509v3CertificateBuilder +{ + private V3TBSCertificateGenerator tbsGen; + private ExtensionsGenerator extGenerator; + + /** + * Create a builder for a version 3 certificate. + * + * @param issuer the certificate issuer + * @param serial the certificate serial number + * @param notBefore the date before which the certificate is not valid + * @param notAfter the date after which the certificate is not valid + * @param subject the certificate subject + * @param publicKeyInfo the info structure for the public key to be associated with this certificate. + */ + public X509v3CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, SubjectPublicKeyInfo publicKeyInfo) + { + this(issuer, serial, new Time(notBefore), new Time(notAfter), subject, publicKeyInfo); + } + + /** + * Create a builder for a version 3 certificate. You may need to use this constructor if the default locale + * doesn't use a Gregorian calender so that the Time produced is compatible with other ASN.1 implementations. + * + * @param issuer the certificate issuer + * @param serial the certificate serial number + * @param notBefore the date before which the certificate is not valid + * @param notAfter the date after which the certificate is not valid + * @param dateLocale locale to be used for date interpretation. + * @param subject the certificate subject + * @param publicKeyInfo the info structure for the public key to be associated with this certificate. + */ + public X509v3CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, Locale dateLocale, X500Name subject, SubjectPublicKeyInfo publicKeyInfo) + { + this(issuer, serial, new Time(notBefore, dateLocale), new Time(notAfter, dateLocale), subject, publicKeyInfo); + } + + /** + * Create a builder for a version 3 certificate. + * + * @param issuer the certificate issuer + * @param serial the certificate serial number + * @param notBefore the Time before which the certificate is not valid + * @param notAfter the Time after which the certificate is not valid + * @param subject the certificate subject + * @param publicKeyInfo the info structure for the public key to be associated with this certificate. + */ + public X509v3CertificateBuilder(X500Name issuer, BigInteger serial, Time notBefore, Time notAfter, X500Name subject, SubjectPublicKeyInfo publicKeyInfo) + { + tbsGen = new V3TBSCertificateGenerator(); + tbsGen.setSerialNumber(new ASN1Integer(serial)); + tbsGen.setIssuer(issuer); + tbsGen.setStartDate(notBefore); + tbsGen.setEndDate(notAfter); + tbsGen.setSubject(subject); + tbsGen.setSubjectPublicKeyInfo(publicKeyInfo); + + extGenerator = new ExtensionsGenerator(); + } + + /** + * Set the subjectUniqueID - note: it is very rare that it is correct to do this. + * + * @param uniqueID a boolean array representing the bits making up the subjectUniqueID. + * @return this builder object. + */ + public X509v3CertificateBuilder setSubjectUniqueID(boolean[] uniqueID) + { + tbsGen.setSubjectUniqueID(CertUtils.booleanToBitString(uniqueID)); + + return this; + } + + /** + * Set the issuerUniqueID - note: it is very rare that it is correct to do this. + * + * @param uniqueID a boolean array representing the bits making up the issuerUniqueID. + * @return this builder object. + */ + public X509v3CertificateBuilder setIssuerUniqueID(boolean[] uniqueID) + { + tbsGen.setIssuerUniqueID(CertUtils.booleanToBitString(uniqueID)); + + return this; + } + + /** + * Add a given extension field for the standard extensions tag (tag 3) + * + * @param oid the OID defining the extension type. + * @param isCritical true if the extension is critical, false otherwise. + * @param value the ASN.1 structure that forms the extension's value. + * @return this builder object. + */ + public X509v3CertificateBuilder addExtension( + ASN1ObjectIdentifier oid, + boolean isCritical, + ASN1Encodable value) + throws CertIOException + { + CertUtils.addExtension(extGenerator, oid, isCritical, value); + + return this; + } + + /** + * Add a given extension field for the standard extensions tag (tag 3). + * + * @param extension the full extension value. + * @return this builder object. + */ + public X509v3CertificateBuilder addExtension( + Extension extension) + throws CertIOException + { + extGenerator.addExtension(extension); + + return this; + } + + /** + * Add a given extension field for the standard extensions tag (tag 3) using a byte encoding of the + * extension value. + * + * @param oid the OID defining the extension type. + * @param isCritical true if the extension is critical, false otherwise. + * @param encodedValue a byte array representing the encoding of the extension value. + * @return this builder object. + */ + public X509v3CertificateBuilder addExtension( + ASN1ObjectIdentifier oid, + boolean isCritical, + byte[] encodedValue) + throws CertIOException + { + extGenerator.addExtension(oid, isCritical, encodedValue); + + return this; + } + + /** + * Add a given extension field for the standard extensions tag (tag 3) + * copying the extension value from another certificate. + * + * @param oid the OID defining the extension type. + * @param isCritical true if the copied extension is to be marked as critical, false otherwise. + * @param certHolder the holder for the certificate that the extension is to be copied from. + * @return this builder object. + */ + public X509v3CertificateBuilder copyAndAddExtension( + ASN1ObjectIdentifier oid, + boolean isCritical, + X509CertificateHolder certHolder) + { + Certificate cert = certHolder.toASN1Structure(); + + Extension extension = cert.getTBSCertificate().getExtensions().getExtension(oid); + + if (extension == null) + { + throw new NullPointerException("extension " + oid + " not present"); + } + + extGenerator.addExtension(oid, isCritical, extension.getExtnValue().getOctets()); + + return this; + } + + /** + * Generate an X.509 certificate, based on the current issuer and subject + * using the passed in signer. + * + * @param signer the content signer to be used to generate the signature validating the certificate. + * @return a holder containing the resulting signed certificate. + */ + public X509CertificateHolder build( + ContentSigner signer) + { + tbsGen.setSignature(signer.getAlgorithmIdentifier()); + + if (!extGenerator.isEmpty()) + { + tbsGen.setExtensions(extGenerator.generate()); + } + + return CertUtils.generateFullCert(signer, tbsGen.generateTBSCertificate()); + } +}
\ No newline at end of file diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/jcajce/JcaCertStore.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/jcajce/JcaCertStore.java new file mode 100644 index 00000000..cc494cfa --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/jcajce/JcaCertStore.java @@ -0,0 +1,65 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.jcajce; + +import java.io.IOException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import com.android.org.bouncycastle.cert.X509CertificateHolder; +import com.android.org.bouncycastle.util.CollectionStore; + +/** + * Class for storing Certificates for later lookup. + * <p> + * The class will convert X509Certificate objects into X509CertificateHolder objects. + * </p> + */ +public class JcaCertStore + extends CollectionStore +{ + /** + * Basic constructor. + * + * @param collection - initial contents for the store, this is copied. + */ + public JcaCertStore(Collection collection) + throws CertificateEncodingException + { + super(convertCerts(collection)); + } + + private static Collection convertCerts(Collection collection) + throws CertificateEncodingException + { + List list = new ArrayList(collection.size()); + + for (Iterator it = collection.iterator(); it.hasNext();) + { + Object o = it.next(); + + if (o instanceof X509Certificate) + { + X509Certificate cert = (X509Certificate)o; + + try + { + list.add(new X509CertificateHolder(cert.getEncoded())); + } + catch (IOException e) + { + throw new CertificateEncodingException("unable to read encoding: " + e.getMessage()); + } + } + else + { + list.add((X509CertificateHolder)o); + } + } + + return list; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/jcajce/JcaX509CertificateHolder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/jcajce/JcaX509CertificateHolder.java new file mode 100644 index 00000000..5d6410f2 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/jcajce/JcaX509CertificateHolder.java @@ -0,0 +1,27 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.jcajce; + +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; + +import com.android.org.bouncycastle.asn1.x509.Certificate; +import com.android.org.bouncycastle.cert.X509CertificateHolder; + +/** + * JCA helper class for converting an X509Certificate into a X509CertificateHolder object. + */ +public class JcaX509CertificateHolder + extends X509CertificateHolder +{ + /** + * Base constructor. + * + * @param cert certificate to be used a the source for the holder creation. + * @throws CertificateEncodingException if there is a problem extracting the certificate information. + */ + public JcaX509CertificateHolder(X509Certificate cert) + throws CertificateEncodingException + { + super(Certificate.getInstance(cert.getEncoded())); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/BasicOCSPResp.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/BasicOCSPResp.java new file mode 100644 index 00000000..8aa1b205 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/BasicOCSPResp.java @@ -0,0 +1,226 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.ocsp; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Date; +import java.util.List; +import java.util.Set; + +import com.android.org.bouncycastle.asn1.ASN1Encoding; +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.ASN1Sequence; +import com.android.org.bouncycastle.asn1.ocsp.BasicOCSPResponse; +import com.android.org.bouncycastle.asn1.ocsp.ResponseData; +import com.android.org.bouncycastle.asn1.ocsp.SingleResponse; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.asn1.x509.Certificate; +import com.android.org.bouncycastle.asn1.x509.Extension; +import com.android.org.bouncycastle.asn1.x509.Extensions; +import com.android.org.bouncycastle.cert.X509CertificateHolder; +import com.android.org.bouncycastle.operator.ContentVerifier; +import com.android.org.bouncycastle.operator.ContentVerifierProvider; +import com.android.org.bouncycastle.util.Encodable; + +/** + * <pre> + * BasicOCSPResponse ::= SEQUENCE { + * tbsResponseData ResponseData, + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING, + * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } + * </pre> + */ +public class BasicOCSPResp + implements Encodable +{ + private BasicOCSPResponse resp; + private ResponseData data; + private Extensions extensions; + + public BasicOCSPResp( + BasicOCSPResponse resp) + { + this.resp = resp; + this.data = resp.getTbsResponseData(); + this.extensions = Extensions.getInstance(resp.getTbsResponseData().getResponseExtensions()); + } + + /** + * Return the DER encoding of the tbsResponseData field. + * @return DER encoding of tbsResponseData + */ + public byte[] getTBSResponseData() + { + try + { + return resp.getTbsResponseData().getEncoded(ASN1Encoding.DER); + } + catch (IOException e) + { + return null; + } + } + + /** + * Return the algorithm identifier describing the signature used in the response. + * + * @return an AlgorithmIdentifier + */ + public AlgorithmIdentifier getSignatureAlgorithmID() + { + return resp.getSignatureAlgorithm(); + } + + public int getVersion() + { + return data.getVersion().getValue().intValue() + 1; + } + + public RespID getResponderId() + { + return new RespID(data.getResponderID()); + } + + public Date getProducedAt() + { + return OCSPUtils.extractDate(data.getProducedAt()); + } + + public SingleResp[] getResponses() + { + ASN1Sequence s = data.getResponses(); + SingleResp[] rs = new SingleResp[s.size()]; + + for (int i = 0; i != rs.length; i++) + { + rs[i] = new SingleResp(SingleResponse.getInstance(s.getObjectAt(i))); + } + + return rs; + } + + public boolean hasExtensions() + { + return extensions != null; + } + + public Extension getExtension(ASN1ObjectIdentifier oid) + { + if (extensions != null) + { + return extensions.getExtension(oid); + } + + return null; + } + + public List getExtensionOIDs() + { + return OCSPUtils.getExtensionOIDs(extensions); + } + + public Set getCriticalExtensionOIDs() + { + return OCSPUtils.getCriticalExtensionOIDs(extensions); + } + + public Set getNonCriticalExtensionOIDs() + { + return OCSPUtils.getNonCriticalExtensionOIDs(extensions); + } + + + public ASN1ObjectIdentifier getSignatureAlgOID() + { + return resp.getSignatureAlgorithm().getAlgorithm(); + } + + public byte[] getSignature() + { + return resp.getSignature().getOctets(); + } + + public X509CertificateHolder[] getCerts() + { + // + // load the certificates if we have any + // + if (resp.getCerts() != null) + { + ASN1Sequence s = resp.getCerts(); + + if (s != null) + { + X509CertificateHolder[] certs = new X509CertificateHolder[s.size()]; + + for (int i = 0; i != certs.length; i++) + { + certs[i] = new X509CertificateHolder(Certificate.getInstance(s.getObjectAt(i))); + } + + return certs; + } + + return OCSPUtils.EMPTY_CERTS; + } + else + { + return OCSPUtils.EMPTY_CERTS; + } + } + + /** + * verify the signature against the tbsResponseData object we contain. + */ + public boolean isSignatureValid( + ContentVerifierProvider verifierProvider) + throws OCSPException + { + try + { + ContentVerifier verifier = verifierProvider.get(resp.getSignatureAlgorithm()); + OutputStream vOut = verifier.getOutputStream(); + + vOut.write(resp.getTbsResponseData().getEncoded(ASN1Encoding.DER)); + vOut.close(); + + return verifier.verify(this.getSignature()); + } + catch (Exception e) + { + throw new OCSPException("exception processing sig: " + e, e); + } + } + + /** + * return the ASN.1 encoded representation of this object. + */ + public byte[] getEncoded() + throws IOException + { + return resp.getEncoded(); + } + + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + + if (!(o instanceof BasicOCSPResp)) + { + return false; + } + + BasicOCSPResp r = (BasicOCSPResp)o; + + return resp.equals(r.resp); + } + + public int hashCode() + { + return resp.hashCode(); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/BasicOCSPRespBuilder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/BasicOCSPRespBuilder.java new file mode 100644 index 00000000..a9d1f33a --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/BasicOCSPRespBuilder.java @@ -0,0 +1,284 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.ocsp; + +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import com.android.org.bouncycastle.asn1.ASN1EncodableVector; +import com.android.org.bouncycastle.asn1.ASN1Encoding; +import com.android.org.bouncycastle.asn1.ASN1GeneralizedTime; +import com.android.org.bouncycastle.asn1.DERBitString; +import com.android.org.bouncycastle.asn1.DERGeneralizedTime; +import com.android.org.bouncycastle.asn1.DERNull; +import com.android.org.bouncycastle.asn1.DERSequence; +import com.android.org.bouncycastle.asn1.ocsp.BasicOCSPResponse; +import com.android.org.bouncycastle.asn1.ocsp.CertStatus; +import com.android.org.bouncycastle.asn1.ocsp.ResponseData; +import com.android.org.bouncycastle.asn1.ocsp.RevokedInfo; +import com.android.org.bouncycastle.asn1.ocsp.SingleResponse; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.asn1.x509.CRLReason; +import com.android.org.bouncycastle.asn1.x509.Extensions; +import com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.android.org.bouncycastle.cert.X509CertificateHolder; +import com.android.org.bouncycastle.operator.ContentSigner; +import com.android.org.bouncycastle.operator.DigestCalculator; + +/** + * Generator for basic OCSP response objects. + */ +public class BasicOCSPRespBuilder +{ + private List list = new ArrayList(); + private Extensions responseExtensions = null; + private RespID responderID; + + private class ResponseObject + { + CertificateID certId; + CertStatus certStatus; + ASN1GeneralizedTime thisUpdate; + ASN1GeneralizedTime nextUpdate; + Extensions extensions; + + public ResponseObject( + CertificateID certId, + CertificateStatus certStatus, + Date thisUpdate, + Date nextUpdate, + Extensions extensions) + { + this.certId = certId; + + if (certStatus == null) + { + this.certStatus = new CertStatus(); + } + else if (certStatus instanceof UnknownStatus) + { + this.certStatus = new CertStatus(2, DERNull.INSTANCE); + } + else + { + RevokedStatus rs = (RevokedStatus)certStatus; + + if (rs.hasRevocationReason()) + { + this.certStatus = new CertStatus( + new RevokedInfo(new ASN1GeneralizedTime(rs.getRevocationTime()), CRLReason.lookup(rs.getRevocationReason()))); + } + else + { + this.certStatus = new CertStatus( + new RevokedInfo(new ASN1GeneralizedTime(rs.getRevocationTime()), null)); + } + } + + this.thisUpdate = new DERGeneralizedTime(thisUpdate); + + if (nextUpdate != null) + { + this.nextUpdate = new DERGeneralizedTime(nextUpdate); + } + else + { + this.nextUpdate = null; + } + + this.extensions = extensions; + } + + public SingleResponse toResponse() + throws Exception + { + return new SingleResponse(certId.toASN1Primitive(), certStatus, thisUpdate, nextUpdate, extensions); + } + } + + /** + * basic constructor + */ + public BasicOCSPRespBuilder( + RespID responderID) + { + this.responderID = responderID; + } + + /** + * construct with the responderID to be the SHA-1 keyHash of the passed in public key. + * + * @param key the key info of the responder public key. + * @param digCalc a SHA-1 digest calculator + */ + public BasicOCSPRespBuilder( + SubjectPublicKeyInfo key, + DigestCalculator digCalc) + throws OCSPException + { + this.responderID = new RespID(key, digCalc); + } + + /** + * Add a response for a particular Certificate ID. + * + * @param certID certificate ID details + * @param certStatus status of the certificate - null if okay + */ + public BasicOCSPRespBuilder addResponse( + CertificateID certID, + CertificateStatus certStatus) + { + this.addResponse(certID, certStatus, new Date(), null, null); + + return this; + } + + /** + * Add a response for a particular Certificate ID. + * + * @param certID certificate ID details + * @param certStatus status of the certificate - null if okay + * @param singleExtensions optional extensions + */ + public BasicOCSPRespBuilder addResponse( + CertificateID certID, + CertificateStatus certStatus, + Extensions singleExtensions) + { + this.addResponse(certID, certStatus, new Date(), null, singleExtensions); + + return this; + } + + /** + * Add a response for a particular Certificate ID. + * + * @param certID certificate ID details + * @param nextUpdate date when next update should be requested + * @param certStatus status of the certificate - null if okay + * @param singleExtensions optional extensions + */ + public BasicOCSPRespBuilder addResponse( + CertificateID certID, + CertificateStatus certStatus, + Date nextUpdate, + Extensions singleExtensions) + { + this.addResponse(certID, certStatus, new Date(), nextUpdate, singleExtensions); + + return this; + } + + /** + * Add a response for a particular Certificate ID. + * + * @param certID certificate ID details + * @param thisUpdate date this response was valid on + * @param nextUpdate date when next update should be requested + * @param certStatus status of the certificate - null if okay + */ + public BasicOCSPRespBuilder addResponse( + CertificateID certID, + CertificateStatus certStatus, + Date thisUpdate, + Date nextUpdate) + { + this.addResponse(certID, certStatus, thisUpdate, nextUpdate, null); + + return this; + } + + /** + * Add a response for a particular Certificate ID. + * + * @param certID certificate ID details + * @param thisUpdate date this response was valid on + * @param nextUpdate date when next update should be requested + * @param certStatus status of the certificate - null if okay + * @param singleExtensions optional extensions + */ + public BasicOCSPRespBuilder addResponse( + CertificateID certID, + CertificateStatus certStatus, + Date thisUpdate, + Date nextUpdate, + Extensions singleExtensions) + { + list.add(new ResponseObject(certID, certStatus, thisUpdate, nextUpdate, singleExtensions)); + + return this; + } + + /** + * Set the extensions for the response. + * + * @param responseExtensions the extension object to carry. + */ + public BasicOCSPRespBuilder setResponseExtensions( + Extensions responseExtensions) + { + this.responseExtensions = responseExtensions; + + return this; + } + + public BasicOCSPResp build( + ContentSigner signer, + X509CertificateHolder[] chain, + Date producedAt) + throws OCSPException + { + Iterator it = list.iterator(); + + ASN1EncodableVector responses = new ASN1EncodableVector(); + + while (it.hasNext()) + { + try + { + responses.add(((ResponseObject)it.next()).toResponse()); + } + catch (Exception e) + { + throw new OCSPException("exception creating Request", e); + } + } + + ResponseData tbsResp = new ResponseData(responderID.toASN1Primitive(), new ASN1GeneralizedTime(producedAt), new DERSequence(responses), responseExtensions); + DERBitString bitSig; + + try + { + OutputStream sigOut = signer.getOutputStream(); + + sigOut.write(tbsResp.getEncoded(ASN1Encoding.DER)); + sigOut.close(); + + bitSig = new DERBitString(signer.getSignature()); + } + catch (Exception e) + { + throw new OCSPException("exception processing TBSRequest: " + e.getMessage(), e); + } + + AlgorithmIdentifier sigAlgId = signer.getAlgorithmIdentifier(); + + DERSequence chainSeq = null; + if (chain != null && chain.length > 0) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (int i = 0; i != chain.length; i++) + { + v.add(chain[i].toASN1Structure()); + } + + chainSeq = new DERSequence(v); + } + + return new BasicOCSPResp(new BasicOCSPResponse(tbsResp, sigAlgId, bitSig, chainSeq)); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/CertificateID.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/CertificateID.java new file mode 100644 index 00000000..a6dc592e --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/CertificateID.java @@ -0,0 +1,157 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.ocsp; + +import java.io.OutputStream; +import java.math.BigInteger; + +import com.android.org.bouncycastle.asn1.ASN1Encoding; +import com.android.org.bouncycastle.asn1.ASN1Integer; +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.ASN1OctetString; +import com.android.org.bouncycastle.asn1.DERNull; +import com.android.org.bouncycastle.asn1.DEROctetString; +import com.android.org.bouncycastle.asn1.ocsp.CertID; +import com.android.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.android.org.bouncycastle.cert.X509CertificateHolder; +import com.android.org.bouncycastle.operator.DigestCalculator; +import com.android.org.bouncycastle.operator.DigestCalculatorProvider; +import com.android.org.bouncycastle.operator.OperatorCreationException; + +public class CertificateID +{ + public static final AlgorithmIdentifier HASH_SHA1 = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE); + + private final CertID id; + + public CertificateID( + CertID id) + { + if (id == null) + { + throw new IllegalArgumentException("'id' cannot be null"); + } + this.id = id; + } + + /** + * create from an issuer certificate and the serial number of the + * certificate it signed. + * + * @param issuerCert issuing certificate + * @param number serial number + * + * @exception OCSPException if any problems occur creating the id fields. + */ + public CertificateID( + DigestCalculator digestCalculator, X509CertificateHolder issuerCert, + BigInteger number) + throws OCSPException + { + this.id = createCertID(digestCalculator, issuerCert, new ASN1Integer(number)); + } + + public ASN1ObjectIdentifier getHashAlgOID() + { + return id.getHashAlgorithm().getAlgorithm(); + } + + public byte[] getIssuerNameHash() + { + return id.getIssuerNameHash().getOctets(); + } + + public byte[] getIssuerKeyHash() + { + return id.getIssuerKeyHash().getOctets(); + } + + /** + * return the serial number for the certificate associated + * with this request. + */ + public BigInteger getSerialNumber() + { + return id.getSerialNumber().getValue(); + } + + public boolean matchesIssuer(X509CertificateHolder issuerCert, DigestCalculatorProvider digCalcProvider) + throws OCSPException + { + try + { + return createCertID(digCalcProvider.get(id.getHashAlgorithm()), issuerCert, id.getSerialNumber()).equals(id); + } + catch (OperatorCreationException e) + { + throw new OCSPException("unable to create digest calculator: " + e.getMessage(), e); + } + } + + public CertID toASN1Primitive() + { + return id; + } + + public boolean equals( + Object o) + { + if (!(o instanceof CertificateID)) + { + return false; + } + + CertificateID obj = (CertificateID)o; + + return id.toASN1Primitive().equals(obj.id.toASN1Primitive()); + } + + public int hashCode() + { + return id.toASN1Primitive().hashCode(); + } + + /** + * Create a new CertificateID for a new serial number derived from a previous one + * calculated for the same CA certificate. + * + * @param original the previously calculated CertificateID for the CA. + * @param newSerialNumber the serial number for the new certificate of interest. + * + * @return a new CertificateID for newSerialNumber + */ + public static CertificateID deriveCertificateID(CertificateID original, BigInteger newSerialNumber) + { + return new CertificateID(new CertID(original.id.getHashAlgorithm(), original.id.getIssuerNameHash(), original.id.getIssuerKeyHash(), new ASN1Integer(newSerialNumber))); + } + + private static CertID createCertID(DigestCalculator digCalc, X509CertificateHolder issuerCert, ASN1Integer serialNumber) + throws OCSPException + { + try + { + OutputStream dgOut = digCalc.getOutputStream(); + + dgOut.write(issuerCert.toASN1Structure().getSubject().getEncoded(ASN1Encoding.DER)); + dgOut.close(); + + ASN1OctetString issuerNameHash = new DEROctetString(digCalc.getDigest()); + + SubjectPublicKeyInfo info = issuerCert.getSubjectPublicKeyInfo(); + + dgOut = digCalc.getOutputStream(); + + dgOut.write(info.getPublicKeyData().getBytes()); + dgOut.close(); + + ASN1OctetString issuerKeyHash = new DEROctetString(digCalc.getDigest()); + + return new CertID(digCalc.getAlgorithmIdentifier(), issuerNameHash, issuerKeyHash, serialNumber); + } + catch (Exception e) + { + throw new OCSPException("problem creating ID: " + e, e); + } + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/CertificateStatus.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/CertificateStatus.java new file mode 100644 index 00000000..097d992e --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/CertificateStatus.java @@ -0,0 +1,7 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.ocsp; + +public interface CertificateStatus +{ + public static final CertificateStatus GOOD = null; +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/OCSPException.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/OCSPException.java new file mode 100644 index 00000000..d074aedd --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/OCSPException.java @@ -0,0 +1,28 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.ocsp; + +public class OCSPException + extends Exception +{ + private Throwable cause; + + public OCSPException( + String name) + { + super(name); + } + + public OCSPException( + String name, + Throwable cause) + { + super(name); + + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/OCSPReq.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/OCSPReq.java new file mode 100644 index 00000000..97284da7 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/OCSPReq.java @@ -0,0 +1,260 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.ocsp; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; +import java.util.Set; + +import com.android.org.bouncycastle.asn1.ASN1Encoding; +import com.android.org.bouncycastle.asn1.ASN1Exception; +import com.android.org.bouncycastle.asn1.ASN1InputStream; +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.ASN1OutputStream; +import com.android.org.bouncycastle.asn1.ASN1Sequence; +import com.android.org.bouncycastle.asn1.ocsp.OCSPRequest; +import com.android.org.bouncycastle.asn1.ocsp.Request; +import com.android.org.bouncycastle.asn1.x509.Certificate; +import com.android.org.bouncycastle.asn1.x509.Extension; +import com.android.org.bouncycastle.asn1.x509.Extensions; +import com.android.org.bouncycastle.asn1.x509.GeneralName; +import com.android.org.bouncycastle.cert.CertIOException; +import com.android.org.bouncycastle.cert.X509CertificateHolder; +import com.android.org.bouncycastle.operator.ContentVerifier; +import com.android.org.bouncycastle.operator.ContentVerifierProvider; + +/** + * <pre> + * OCSPRequest ::= SEQUENCE { + * tbsRequest TBSRequest, + * optionalSignature [0] EXPLICIT Signature OPTIONAL } + * + * TBSRequest ::= SEQUENCE { + * version [0] EXPLICIT Version DEFAULT v1, + * requestorName [1] EXPLICIT GeneralName OPTIONAL, + * requestList SEQUENCE OF Request, + * requestExtensions [2] EXPLICIT Extensions OPTIONAL } + * + * Signature ::= SEQUENCE { + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING, + * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL} + * + * Version ::= INTEGER { v1(0) } + * + * Request ::= SEQUENCE { + * reqCert CertID, + * singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL } + * + * CertID ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier, + * issuerNameHash OCTET STRING, -- Hash of Issuer's DN + * issuerKeyHash OCTET STRING, -- Hash of Issuers public key + * serialNumber CertificateSerialNumber } + * </pre> + */ +public class OCSPReq +{ + private static final X509CertificateHolder[] EMPTY_CERTS = new X509CertificateHolder[0]; + + private OCSPRequest req; + private Extensions extensions; + + public OCSPReq( + OCSPRequest req) + { + this.req = req; + this.extensions = req.getTbsRequest().getRequestExtensions(); + } + + public OCSPReq( + byte[] req) + throws IOException + { + this(new ASN1InputStream(req)); + } + + private OCSPReq( + ASN1InputStream aIn) + throws IOException + { + try + { + this.req = OCSPRequest.getInstance(aIn.readObject()); + if (req == null) + { + throw new CertIOException("malformed request: no request data found"); + } + this.extensions = req.getTbsRequest().getRequestExtensions(); + } + catch (IllegalArgumentException e) + { + throw new CertIOException("malformed request: " + e.getMessage(), e); + } + catch (ClassCastException e) + { + throw new CertIOException("malformed request: " + e.getMessage(), e); + } + catch (ASN1Exception e) + { + throw new CertIOException("malformed request: " + e.getMessage(), e); + } + } + + public int getVersionNumber() + { + return req.getTbsRequest().getVersion().getValue().intValue() + 1; + } + + public GeneralName getRequestorName() + { + return GeneralName.getInstance(req.getTbsRequest().getRequestorName()); + } + + public Req[] getRequestList() + { + ASN1Sequence seq = req.getTbsRequest().getRequestList(); + Req[] requests = new Req[seq.size()]; + + for (int i = 0; i != requests.length; i++) + { + requests[i] = new Req(Request.getInstance(seq.getObjectAt(i))); + } + + return requests; + } + + public boolean hasExtensions() + { + return extensions != null; + } + + public Extension getExtension(ASN1ObjectIdentifier oid) + { + if (extensions != null) + { + return extensions.getExtension(oid); + } + + return null; + } + + public List getExtensionOIDs() + { + return OCSPUtils.getExtensionOIDs(extensions); + } + + public Set getCriticalExtensionOIDs() + { + return OCSPUtils.getCriticalExtensionOIDs(extensions); + } + + public Set getNonCriticalExtensionOIDs() + { + return OCSPUtils.getNonCriticalExtensionOIDs(extensions); + } + + /** + * return the object identifier representing the signature algorithm + */ + public ASN1ObjectIdentifier getSignatureAlgOID() + { + if (!this.isSigned()) + { + return null; + } + + return req.getOptionalSignature().getSignatureAlgorithm().getAlgorithm(); + } + + public byte[] getSignature() + { + if (!this.isSigned()) + { + return null; + } + + return req.getOptionalSignature().getSignature().getOctets(); + } + + public X509CertificateHolder[] getCerts() + { + // + // load the certificates if we have any + // + if (req.getOptionalSignature() != null) + { + ASN1Sequence s = req.getOptionalSignature().getCerts(); + + if (s != null) + { + X509CertificateHolder[] certs = new X509CertificateHolder[s.size()]; + + for (int i = 0; i != certs.length; i++) + { + certs[i] = new X509CertificateHolder(Certificate.getInstance(s.getObjectAt(i))); + } + + return certs; + } + + return EMPTY_CERTS; + } + else + { + return EMPTY_CERTS; + } + } + + /** + * Return whether or not this request is signed. + * + * @return true if signed false otherwise. + */ + public boolean isSigned() + { + return req.getOptionalSignature() != null; + } + + /** + * verify the signature against the TBSRequest object we contain. + */ + public boolean isSignatureValid( + ContentVerifierProvider verifierProvider) + throws OCSPException + { + if (!this.isSigned()) + { + throw new OCSPException("attempt to verify signature on unsigned object"); + } + + try + { + ContentVerifier verifier = verifierProvider.get(req.getOptionalSignature().getSignatureAlgorithm()); + OutputStream sOut = verifier.getOutputStream(); + + sOut.write(req.getTbsRequest().getEncoded(ASN1Encoding.DER)); + + return verifier.verify(this.getSignature()); + } + catch (Exception e) + { + throw new OCSPException("exception processing signature: " + e, e); + } + } + + /** + * return the ASN.1 encoded representation of this object. + */ + public byte[] getEncoded() + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ASN1OutputStream aOut = new ASN1OutputStream(bOut); + + aOut.writeObject(req); + + return bOut.toByteArray(); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/OCSPReqBuilder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/OCSPReqBuilder.java new file mode 100644 index 00000000..429f6edd --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/OCSPReqBuilder.java @@ -0,0 +1,200 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.ocsp; + +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import com.android.org.bouncycastle.asn1.ASN1EncodableVector; +import com.android.org.bouncycastle.asn1.ASN1Encoding; +import com.android.org.bouncycastle.asn1.DERBitString; +import com.android.org.bouncycastle.asn1.DERSequence; +import com.android.org.bouncycastle.asn1.ocsp.OCSPRequest; +import com.android.org.bouncycastle.asn1.ocsp.Request; +import com.android.org.bouncycastle.asn1.ocsp.Signature; +import com.android.org.bouncycastle.asn1.ocsp.TBSRequest; +import com.android.org.bouncycastle.asn1.x500.X500Name; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.asn1.x509.Extensions; +import com.android.org.bouncycastle.asn1.x509.GeneralName; +import com.android.org.bouncycastle.cert.X509CertificateHolder; +import com.android.org.bouncycastle.operator.ContentSigner; + +public class OCSPReqBuilder +{ + private List list = new ArrayList(); + private GeneralName requestorName = null; + private Extensions requestExtensions = null; + + private class RequestObject + { + CertificateID certId; + Extensions extensions; + + public RequestObject( + CertificateID certId, + Extensions extensions) + { + this.certId = certId; + this.extensions = extensions; + } + + public Request toRequest() + throws Exception + { + return new Request(certId.toASN1Primitive(), extensions); + } + } + + /** + * Add a request for the given CertificateID. + * + * @param certId certificate ID of interest + */ + public OCSPReqBuilder addRequest( + CertificateID certId) + { + list.add(new RequestObject(certId, null)); + + return this; + } + + /** + * Add a request with extensions + * + * @param certId certificate ID of interest + * @param singleRequestExtensions the extensions to attach to the request + */ + public OCSPReqBuilder addRequest( + CertificateID certId, + Extensions singleRequestExtensions) + { + list.add(new RequestObject(certId, singleRequestExtensions)); + + return this; + } + + /** + * Set the requestor name to the passed in X500Name + * + * @param requestorName an X500Name representing the requestor name. + */ + public OCSPReqBuilder setRequestorName( + X500Name requestorName) + { + this.requestorName = new GeneralName(GeneralName.directoryName, requestorName); + + return this; + } + + public OCSPReqBuilder setRequestorName( + GeneralName requestorName) + { + this.requestorName = requestorName; + + return this; + } + + public OCSPReqBuilder setRequestExtensions( + Extensions requestExtensions) + { + this.requestExtensions = requestExtensions; + + return this; + } + + private OCSPReq generateRequest( + ContentSigner contentSigner, + X509CertificateHolder[] chain) + throws OCSPException + { + Iterator it = list.iterator(); + + ASN1EncodableVector requests = new ASN1EncodableVector(); + + while (it.hasNext()) + { + try + { + requests.add(((RequestObject)it.next()).toRequest()); + } + catch (Exception e) + { + throw new OCSPException("exception creating Request", e); + } + } + + TBSRequest tbsReq = new TBSRequest(requestorName, new DERSequence(requests), requestExtensions); + + Signature signature = null; + + if (contentSigner != null) + { + if (requestorName == null) + { + throw new OCSPException("requestorName must be specified if request is signed."); + } + + try + { + OutputStream sOut = contentSigner.getOutputStream(); + + sOut.write(tbsReq.getEncoded(ASN1Encoding.DER)); + + sOut.close(); + } + catch (Exception e) + { + throw new OCSPException("exception processing TBSRequest: " + e, e); + } + + DERBitString bitSig = new DERBitString(contentSigner.getSignature()); + + AlgorithmIdentifier sigAlgId = contentSigner.getAlgorithmIdentifier(); + + if (chain != null && chain.length > 0) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (int i = 0; i != chain.length; i++) + { + v.add(chain[i].toASN1Structure()); + } + + signature = new Signature(sigAlgId, bitSig, new DERSequence(v)); + } + else + { + signature = new Signature(sigAlgId, bitSig); + } + } + + return new OCSPReq(new OCSPRequest(tbsReq, signature)); + } + + /** + * Generate an unsigned request + * + * @return the OCSPReq + * @throws com.android.org.bouncycastle.cert.ocsp.OCSPException + */ + public OCSPReq build() + throws OCSPException + { + return generateRequest(null, null); + } + + public OCSPReq build( + ContentSigner signer, + X509CertificateHolder[] chain) + throws OCSPException, IllegalArgumentException + { + if (signer == null) + { + throw new IllegalArgumentException("no signer specified"); + } + + return generateRequest(signer, chain); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/OCSPResp.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/OCSPResp.java new file mode 100644 index 00000000..9e79bac8 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/OCSPResp.java @@ -0,0 +1,142 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.ocsp; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import com.android.org.bouncycastle.asn1.ASN1Exception; +import com.android.org.bouncycastle.asn1.ASN1InputStream; +import com.android.org.bouncycastle.asn1.ASN1Primitive; +import com.android.org.bouncycastle.asn1.ocsp.BasicOCSPResponse; +import com.android.org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers; +import com.android.org.bouncycastle.asn1.ocsp.OCSPResponse; +import com.android.org.bouncycastle.asn1.ocsp.ResponseBytes; +import com.android.org.bouncycastle.cert.CertIOException; + +public class OCSPResp +{ + public static final int SUCCESSFUL = 0; // Response has valid confirmations + public static final int MALFORMED_REQUEST = 1; // Illegal confirmation request + public static final int INTERNAL_ERROR = 2; // Internal error in issuer + public static final int TRY_LATER = 3; // Try again later + // (4) is not used + public static final int SIG_REQUIRED = 5; // Must sign the request + public static final int UNAUTHORIZED = 6; // Request unauthorized + + private OCSPResponse resp; + + public OCSPResp( + OCSPResponse resp) + { + this.resp = resp; + } + + public OCSPResp( + byte[] resp) + throws IOException + { + this(new ByteArrayInputStream(resp)); + } + + public OCSPResp( + InputStream resp) + throws IOException + { + this(new ASN1InputStream(resp)); + } + + private OCSPResp( + ASN1InputStream aIn) + throws IOException + { + try + { + this.resp = OCSPResponse.getInstance(aIn.readObject()); + } + catch (IllegalArgumentException e) + { + throw new CertIOException("malformed response: " + e.getMessage(), e); + } + catch (ClassCastException e) + { + throw new CertIOException("malformed response: " + e.getMessage(), e); + } + catch (ASN1Exception e) + { + throw new CertIOException("malformed response: " + e.getMessage(), e); + } + + if (resp == null) + { + throw new CertIOException("malformed response: no response data found"); + } + } + + public int getStatus() + { + return this.resp.getResponseStatus().getValue().intValue(); + } + + public Object getResponseObject() + throws OCSPException + { + ResponseBytes rb = this.resp.getResponseBytes(); + + if (rb == null) + { + return null; + } + + if (rb.getResponseType().equals(OCSPObjectIdentifiers.id_pkix_ocsp_basic)) + { + try + { + ASN1Primitive obj = ASN1Primitive.fromByteArray(rb.getResponse().getOctets()); + return new BasicOCSPResp(BasicOCSPResponse.getInstance(obj)); + } + catch (Exception e) + { + throw new OCSPException("problem decoding object: " + e, e); + } + } + + return rb.getResponse(); + } + + /** + * return the ASN.1 encoded representation of this object. + */ + public byte[] getEncoded() + throws IOException + { + return resp.getEncoded(); + } + + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + + if (!(o instanceof OCSPResp)) + { + return false; + } + + OCSPResp r = (OCSPResp)o; + + return resp.equals(r.resp); + } + + public int hashCode() + { + return resp.hashCode(); + } + + public OCSPResponse toASN1Structure() + { + return resp; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/OCSPRespBuilder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/OCSPRespBuilder.java new file mode 100644 index 00000000..c6e8263b --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/OCSPRespBuilder.java @@ -0,0 +1,60 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.ocsp; + +import java.io.IOException; + +import com.android.org.bouncycastle.asn1.ASN1OctetString; +import com.android.org.bouncycastle.asn1.DEROctetString; +import com.android.org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers; +import com.android.org.bouncycastle.asn1.ocsp.OCSPResponse; +import com.android.org.bouncycastle.asn1.ocsp.OCSPResponseStatus; +import com.android.org.bouncycastle.asn1.ocsp.ResponseBytes; + +/** + * base generator for an OCSP response - at the moment this only supports the + * generation of responses containing BasicOCSP responses. + */ +public class OCSPRespBuilder +{ + public static final int SUCCESSFUL = 0; // Response has valid confirmations + public static final int MALFORMED_REQUEST = 1; // Illegal confirmation request + public static final int INTERNAL_ERROR = 2; // Internal error in issuer + public static final int TRY_LATER = 3; // Try again later + // (4) is not used + public static final int SIG_REQUIRED = 5; // Must sign the request + public static final int UNAUTHORIZED = 6; // Request unauthorized + + public OCSPResp build( + int status, + Object response) + throws OCSPException + { + if (response == null) + { + return new OCSPResp(new OCSPResponse(new OCSPResponseStatus(status), null)); + } + + if (response instanceof BasicOCSPResp) + { + BasicOCSPResp r = (BasicOCSPResp)response; + ASN1OctetString octs; + + try + { + octs = new DEROctetString(r.getEncoded()); + } + catch (IOException e) + { + throw new OCSPException("can't encode object.", e); + } + + ResponseBytes rb = new ResponseBytes( + OCSPObjectIdentifiers.id_pkix_ocsp_basic, octs); + + return new OCSPResp(new OCSPResponse( + new OCSPResponseStatus(status), rb)); + } + + throw new OCSPException("unknown response object"); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/OCSPUtils.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/OCSPUtils.java new file mode 100644 index 00000000..c50bb274 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/OCSPUtils.java @@ -0,0 +1,65 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.ocsp; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.android.org.bouncycastle.asn1.ASN1GeneralizedTime; +import com.android.org.bouncycastle.asn1.x509.Extensions; +import com.android.org.bouncycastle.cert.X509CertificateHolder; + +class OCSPUtils +{ + static final X509CertificateHolder[] EMPTY_CERTS = new X509CertificateHolder[0]; + + static Set EMPTY_SET = Collections.unmodifiableSet(new HashSet()); + static List EMPTY_LIST = Collections.unmodifiableList(new ArrayList()); + + static Date extractDate(ASN1GeneralizedTime time) + { + try + { + return time.getDate(); + } + catch (Exception e) + { + throw new IllegalStateException("exception processing GeneralizedTime: " + e.getMessage()); + } + } + + static Set getCriticalExtensionOIDs(Extensions extensions) + { + if (extensions == null) + { + return EMPTY_SET; + } + + return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getCriticalExtensionOIDs()))); + } + + static Set getNonCriticalExtensionOIDs(Extensions extensions) + { + if (extensions == null) + { + return EMPTY_SET; + } + + // TODO: should probably produce a set that imposes correct ordering + return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getNonCriticalExtensionOIDs()))); + } + + static List getExtensionOIDs(Extensions extensions) + { + if (extensions == null) + { + return EMPTY_LIST; + } + + return Collections.unmodifiableList(Arrays.asList(extensions.getExtensionOIDs())); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/Req.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/Req.java new file mode 100644 index 00000000..9d826621 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/Req.java @@ -0,0 +1,26 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.ocsp; + +import com.android.org.bouncycastle.asn1.ocsp.Request; +import com.android.org.bouncycastle.asn1.x509.Extensions; + +public class Req +{ + private Request req; + + public Req( + Request req) + { + this.req = req; + } + + public CertificateID getCertID() + { + return new CertificateID(req.getReqCert()); + } + + public Extensions getSingleRequestExtensions() + { + return req.getSingleRequestExtensions(); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/RespData.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/RespData.java new file mode 100644 index 00000000..9a6df045 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/RespData.java @@ -0,0 +1,53 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.ocsp; + +import java.util.Date; + +import com.android.org.bouncycastle.asn1.ASN1Sequence; +import com.android.org.bouncycastle.asn1.ocsp.ResponseData; +import com.android.org.bouncycastle.asn1.ocsp.SingleResponse; +import com.android.org.bouncycastle.asn1.x509.Extensions; + +public class RespData +{ + private ResponseData data; + + public RespData( + ResponseData data) + { + this.data = data; + } + + public int getVersion() + { + return data.getVersion().getValue().intValue() + 1; + } + + public RespID getResponderId() + { + return new RespID(data.getResponderID()); + } + + public Date getProducedAt() + { + return OCSPUtils.extractDate(data.getProducedAt()); + } + + public SingleResp[] getResponses() + { + ASN1Sequence s = data.getResponses(); + SingleResp[] rs = new SingleResp[s.size()]; + + for (int i = 0; i != rs.length; i++) + { + rs[i] = new SingleResp(SingleResponse.getInstance(s.getObjectAt(i))); + } + + return rs; + } + + public Extensions getResponseExtensions() + { + return data.getResponseExtensions(); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/RespID.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/RespID.java new file mode 100644 index 00000000..1bf73a39 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/RespID.java @@ -0,0 +1,90 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.ocsp; + +import java.io.OutputStream; + +import com.android.org.bouncycastle.asn1.DERNull; +import com.android.org.bouncycastle.asn1.DEROctetString; +import com.android.org.bouncycastle.asn1.ocsp.ResponderID; +import com.android.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import com.android.org.bouncycastle.asn1.x500.X500Name; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.android.org.bouncycastle.operator.DigestCalculator; + +/** + * Carrier for a ResponderID. + */ +public class RespID +{ + public static final AlgorithmIdentifier HASH_SHA1 = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE); + + ResponderID id; + + public RespID( + ResponderID id) + { + this.id = id; + } + + public RespID( + X500Name name) + { + this.id = new ResponderID(name); + } + + /** + * Calculate a RespID based on the public key of the responder. + * + * @param subjectPublicKeyInfo the info structure for the responder public key. + * @param digCalc a SHA-1 digest calculator. + * @throws OCSPException on exception creating ID. + */ + public RespID( + SubjectPublicKeyInfo subjectPublicKeyInfo, + DigestCalculator digCalc) + throws OCSPException + { + try + { + if (!digCalc.getAlgorithmIdentifier().equals(HASH_SHA1)) + { + throw new IllegalArgumentException("only SHA-1 can be used with RespID - found: " + digCalc.getAlgorithmIdentifier().getAlgorithm()); + } + + OutputStream digOut = digCalc.getOutputStream(); + + digOut.write(subjectPublicKeyInfo.getPublicKeyData().getBytes()); + digOut.close(); + + this.id = new ResponderID(new DEROctetString(digCalc.getDigest())); + } + catch (Exception e) + { + throw new OCSPException("problem creating ID: " + e, e); + } + } + + public ResponderID toASN1Primitive() + { + return id; + } + + public boolean equals( + Object o) + { + if (!(o instanceof RespID)) + { + return false; + } + + RespID obj = (RespID)o; + + return id.equals(obj.id); + } + + public int hashCode() + { + return id.hashCode(); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/RevokedStatus.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/RevokedStatus.java new file mode 100644 index 00000000..14f7fb48 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/RevokedStatus.java @@ -0,0 +1,56 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.ocsp; + +import java.util.Date; + +import com.android.org.bouncycastle.asn1.ASN1GeneralizedTime; +import com.android.org.bouncycastle.asn1.ocsp.RevokedInfo; +import com.android.org.bouncycastle.asn1.x509.CRLReason; + +/** + * wrapper for the RevokedInfo object + */ +public class RevokedStatus + implements CertificateStatus +{ + RevokedInfo info; + + public RevokedStatus( + RevokedInfo info) + { + this.info = info; + } + + public RevokedStatus( + Date revocationDate, + int reason) + { + this.info = new RevokedInfo(new ASN1GeneralizedTime(revocationDate), CRLReason.lookup(reason)); + } + + public Date getRevocationTime() + { + return OCSPUtils.extractDate(info.getRevocationTime()); + } + + public boolean hasRevocationReason() + { + return (info.getRevocationReason() != null); + } + + /** + * return the revocation reason. Note: this field is optional, test for it + * with hasRevocationReason() first. + * @return the revocation reason value. + * @exception IllegalStateException if a reason is asked for and none is avaliable + */ + public int getRevocationReason() + { + if (info.getRevocationReason() == null) + { + throw new IllegalStateException("attempt to get a reason where none is available"); + } + + return info.getRevocationReason().getValue().intValue(); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/SingleResp.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/SingleResp.java new file mode 100644 index 00000000..d0bdd34c --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/SingleResp.java @@ -0,0 +1,103 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.ocsp; + +import java.util.Date; +import java.util.List; +import java.util.Set; + +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.ocsp.CertStatus; +import com.android.org.bouncycastle.asn1.ocsp.RevokedInfo; +import com.android.org.bouncycastle.asn1.ocsp.SingleResponse; +import com.android.org.bouncycastle.asn1.x509.Extension; +import com.android.org.bouncycastle.asn1.x509.Extensions; + +public class SingleResp +{ + private SingleResponse resp; + private Extensions extensions; + + public SingleResp( + SingleResponse resp) + { + this.resp = resp; + this.extensions = resp.getSingleExtensions(); + } + + public CertificateID getCertID() + { + return new CertificateID(resp.getCertID()); + } + + /** + * Return the status object for the response - null indicates good. + * + * @return the status object for the response, null if it is good. + */ + public CertificateStatus getCertStatus() + { + CertStatus s = resp.getCertStatus(); + + if (s.getTagNo() == 0) + { + return null; // good + } + else if (s.getTagNo() == 1) + { + return new RevokedStatus(RevokedInfo.getInstance(s.getStatus())); + } + + return new UnknownStatus(); + } + + public Date getThisUpdate() + { + return OCSPUtils.extractDate(resp.getThisUpdate()); + } + + /** + * return the NextUpdate value - note: this is an optional field so may + * be returned as null. + * + * @return nextUpdate, or null if not present. + */ + public Date getNextUpdate() + { + if (resp.getNextUpdate() == null) + { + return null; + } + + return OCSPUtils.extractDate(resp.getNextUpdate()); + } + + public boolean hasExtensions() + { + return extensions != null; + } + + public Extension getExtension(ASN1ObjectIdentifier oid) + { + if (extensions != null) + { + return extensions.getExtension(oid); + } + + return null; + } + + public List getExtensionOIDs() + { + return OCSPUtils.getExtensionOIDs(extensions); + } + + public Set getCriticalExtensionOIDs() + { + return OCSPUtils.getCriticalExtensionOIDs(extensions); + } + + public Set getNonCriticalExtensionOIDs() + { + return OCSPUtils.getNonCriticalExtensionOIDs(extensions); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/UnknownStatus.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/UnknownStatus.java new file mode 100644 index 00000000..8010cd2d --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/UnknownStatus.java @@ -0,0 +1,13 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.ocsp; + +/** + * wrapper for the UnknownInfo object + */ +public class UnknownStatus + implements CertificateStatus +{ + public UnknownStatus() + { + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/jcajce/JcaBasicOCSPRespBuilder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/jcajce/JcaBasicOCSPRespBuilder.java new file mode 100644 index 00000000..c4d9926d --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/jcajce/JcaBasicOCSPRespBuilder.java @@ -0,0 +1,19 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.ocsp.jcajce; + +import java.security.PublicKey; + +import com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.android.org.bouncycastle.cert.ocsp.BasicOCSPRespBuilder; +import com.android.org.bouncycastle.cert.ocsp.OCSPException; +import com.android.org.bouncycastle.operator.DigestCalculator; + +public class JcaBasicOCSPRespBuilder + extends BasicOCSPRespBuilder +{ + public JcaBasicOCSPRespBuilder(PublicKey key, DigestCalculator digCalc) + throws OCSPException + { + super(SubjectPublicKeyInfo.getInstance(key.getEncoded()), digCalc); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/jcajce/JcaCertificateID.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/jcajce/JcaCertificateID.java new file mode 100644 index 00000000..06f4ed0a --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/jcajce/JcaCertificateID.java @@ -0,0 +1,21 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.ocsp.jcajce; + +import java.math.BigInteger; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; + +import com.android.org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; +import com.android.org.bouncycastle.cert.ocsp.CertificateID; +import com.android.org.bouncycastle.cert.ocsp.OCSPException; +import com.android.org.bouncycastle.operator.DigestCalculator; + +public class JcaCertificateID + extends CertificateID +{ + public JcaCertificateID(DigestCalculator digestCalculator, X509Certificate issuerCert, BigInteger number) + throws OCSPException, CertificateEncodingException + { + super(digestCalculator, new JcaX509CertificateHolder(issuerCert), number); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/jcajce/JcaRespID.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/jcajce/JcaRespID.java new file mode 100644 index 00000000..2f4b85f5 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/ocsp/jcajce/JcaRespID.java @@ -0,0 +1,27 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.ocsp.jcajce; + +import java.security.PublicKey; + +import javax.security.auth.x500.X500Principal; + +import com.android.org.bouncycastle.asn1.x500.X500Name; +import com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.android.org.bouncycastle.cert.ocsp.OCSPException; +import com.android.org.bouncycastle.cert.ocsp.RespID; +import com.android.org.bouncycastle.operator.DigestCalculator; + +public class JcaRespID + extends RespID +{ + public JcaRespID(X500Principal name) + { + super(X500Name.getInstance(name.getEncoded())); + } + + public JcaRespID(PublicKey pubKey, DigestCalculator digCalc) + throws OCSPException + { + super(SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()), digCalc); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/selector/MSOutlookKeyIdCalculator.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/selector/MSOutlookKeyIdCalculator.java new file mode 100644 index 00000000..c3e54a5c --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/selector/MSOutlookKeyIdCalculator.java @@ -0,0 +1,423 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.selector; + +import java.io.IOException; + +import com.android.org.bouncycastle.asn1.ASN1Encoding; +import com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.android.org.bouncycastle.util.Pack; + +class MSOutlookKeyIdCalculator +{ + // This is less than ideal, but it seems to be the best way of supporting this without exposing SHA-1 + // as the class is only used to workout the MSOutlook Key ID, you can think of the fact it's SHA-1 as + // a coincidence... + static byte[] calculateKeyId(SubjectPublicKeyInfo info) + { + SHA1Digest dig = new SHA1Digest(); + byte[] hash = new byte[dig.getDigestSize()]; + byte[] spkiEnc = new byte[0]; + try + { + spkiEnc = info.getEncoded(ASN1Encoding.DER); + } + catch (IOException e) + { + return new byte[0]; + } + + // try the outlook 2010 calculation + dig.update(spkiEnc, 0, spkiEnc.length); + + dig.doFinal(hash, 0); + + return hash; + } + + private static abstract class GeneralDigest + { + private static final int BYTE_LENGTH = 64; + private byte[] xBuf; + private int xBufOff; + + private long byteCount; + + /** + * Standard constructor + */ + protected GeneralDigest() + { + xBuf = new byte[4]; + xBufOff = 0; + } + + /** + * Copy constructor. We are using copy constructors in place + * of the Object.clone() interface as this interface is not + * supported by J2ME. + */ + protected GeneralDigest(GeneralDigest t) + { + xBuf = new byte[t.xBuf.length]; + + copyIn(t); + } + + protected void copyIn(GeneralDigest t) + { + System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length); + + xBufOff = t.xBufOff; + byteCount = t.byteCount; + } + + public void update( + byte in) + { + xBuf[xBufOff++] = in; + + if (xBufOff == xBuf.length) + { + processWord(xBuf, 0); + xBufOff = 0; + } + + byteCount++; + } + + public void update( + byte[] in, + int inOff, + int len) + { + // + // fill the current word + // + while ((xBufOff != 0) && (len > 0)) + { + update(in[inOff]); + + inOff++; + len--; + } + + // + // process whole words. + // + while (len > xBuf.length) + { + processWord(in, inOff); + + inOff += xBuf.length; + len -= xBuf.length; + byteCount += xBuf.length; + } + + // + // load in the remainder. + // + while (len > 0) + { + update(in[inOff]); + + inOff++; + len--; + } + } + + public void finish() + { + long bitLength = (byteCount << 3); + + // + // add the pad bytes. + // + update((byte)128); + + while (xBufOff != 0) + { + update((byte)0); + } + + processLength(bitLength); + + processBlock(); + } + + public void reset() + { + byteCount = 0; + + xBufOff = 0; + for (int i = 0; i < xBuf.length; i++) + { + xBuf[i] = 0; + } + } + + protected abstract void processWord(byte[] in, int inOff); + + protected abstract void processLength(long bitLength); + + protected abstract void processBlock(); + } + + private static class SHA1Digest + extends GeneralDigest + { + private static final int DIGEST_LENGTH = 20; + + private int H1, H2, H3, H4, H5; + + private int[] X = new int[80]; + private int xOff; + + /** + * Standard constructor + */ + public SHA1Digest() + { + reset(); + } + + public String getAlgorithmName() + { + return "SHA-1"; + } + + public int getDigestSize() + { + return DIGEST_LENGTH; + } + + protected void processWord( + byte[] in, + int inOff) + { + // Note: Inlined for performance + // X[xOff] = Pack.bigEndianToInt(in, inOff); + int n = in[ inOff] << 24; + n |= (in[++inOff] & 0xff) << 16; + n |= (in[++inOff] & 0xff) << 8; + n |= (in[++inOff] & 0xff); + X[xOff] = n; + + if (++xOff == 16) + { + processBlock(); + } + } + + protected void processLength( + long bitLength) + { + if (xOff > 14) + { + processBlock(); + } + + X[14] = (int)(bitLength >>> 32); + X[15] = (int)(bitLength & 0xffffffff); + } + + public int doFinal( + byte[] out, + int outOff) + { + finish(); + + Pack.intToBigEndian(H1, out, outOff); + Pack.intToBigEndian(H2, out, outOff + 4); + Pack.intToBigEndian(H3, out, outOff + 8); + Pack.intToBigEndian(H4, out, outOff + 12); + Pack.intToBigEndian(H5, out, outOff + 16); + + reset(); + + return DIGEST_LENGTH; + } + + /** + * reset the chaining variables + */ + public void reset() + { + super.reset(); + + H1 = 0x67452301; + H2 = 0xefcdab89; + H3 = 0x98badcfe; + H4 = 0x10325476; + H5 = 0xc3d2e1f0; + + xOff = 0; + for (int i = 0; i != X.length; i++) + { + X[i] = 0; + } + } + + // + // Additive constants + // + private static final int Y1 = 0x5a827999; + private static final int Y2 = 0x6ed9eba1; + private static final int Y3 = 0x8f1bbcdc; + private static final int Y4 = 0xca62c1d6; + + private int f( + int u, + int v, + int w) + { + return ((u & v) | ((~u) & w)); + } + + private int h( + int u, + int v, + int w) + { + return (u ^ v ^ w); + } + + private int g( + int u, + int v, + int w) + { + return ((u & v) | (u & w) | (v & w)); + } + + protected void processBlock() + { + // + // expand 16 word block into 80 word block. + // + for (int i = 16; i < 80; i++) + { + int t = X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16]; + X[i] = t << 1 | t >>> 31; + } + + // + // set up working variables. + // + int A = H1; + int B = H2; + int C = H3; + int D = H4; + int E = H5; + + // + // round 1 + // + int idx = 0; + + for (int j = 0; j < 4; j++) + { + // E = rotateLeft(A, 5) + f(B, C, D) + E + X[idx++] + Y1 + // B = rotateLeft(B, 30) + E += (A << 5 | A >>> 27) + f(B, C, D) + X[idx++] + Y1; + B = B << 30 | B >>> 2; + + D += (E << 5 | E >>> 27) + f(A, B, C) + X[idx++] + Y1; + A = A << 30 | A >>> 2; + + C += (D << 5 | D >>> 27) + f(E, A, B) + X[idx++] + Y1; + E = E << 30 | E >>> 2; + + B += (C << 5 | C >>> 27) + f(D, E, A) + X[idx++] + Y1; + D = D << 30 | D >>> 2; + + A += (B << 5 | B >>> 27) + f(C, D, E) + X[idx++] + Y1; + C = C << 30 | C >>> 2; + } + + // + // round 2 + // + for (int j = 0; j < 4; j++) + { + // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y2 + // B = rotateLeft(B, 30) + E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y2; + B = B << 30 | B >>> 2; + + D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y2; + A = A << 30 | A >>> 2; + + C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y2; + E = E << 30 | E >>> 2; + + B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y2; + D = D << 30 | D >>> 2; + + A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y2; + C = C << 30 | C >>> 2; + } + + // + // round 3 + // + for (int j = 0; j < 4; j++) + { + // E = rotateLeft(A, 5) + g(B, C, D) + E + X[idx++] + Y3 + // B = rotateLeft(B, 30) + E += (A << 5 | A >>> 27) + g(B, C, D) + X[idx++] + Y3; + B = B << 30 | B >>> 2; + + D += (E << 5 | E >>> 27) + g(A, B, C) + X[idx++] + Y3; + A = A << 30 | A >>> 2; + + C += (D << 5 | D >>> 27) + g(E, A, B) + X[idx++] + Y3; + E = E << 30 | E >>> 2; + + B += (C << 5 | C >>> 27) + g(D, E, A) + X[idx++] + Y3; + D = D << 30 | D >>> 2; + + A += (B << 5 | B >>> 27) + g(C, D, E) + X[idx++] + Y3; + C = C << 30 | C >>> 2; + } + + // + // round 4 + // + for (int j = 0; j <= 3; j++) + { + // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y4 + // B = rotateLeft(B, 30) + E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y4; + B = B << 30 | B >>> 2; + + D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y4; + A = A << 30 | A >>> 2; + + C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y4; + E = E << 30 | E >>> 2; + + B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y4; + D = D << 30 | D >>> 2; + + A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y4; + C = C << 30 | C >>> 2; + } + + + H1 += A; + H2 += B; + H3 += C; + H4 += D; + H5 += E; + + // + // reset start of the buffer. + // + xOff = 0; + for (int i = 0; i < 16; i++) + { + X[i] = 0; + } + } + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/selector/X509CertificateHolderSelector.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/selector/X509CertificateHolderSelector.java new file mode 100644 index 00000000..f7f7cefd --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cert/selector/X509CertificateHolderSelector.java @@ -0,0 +1,153 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cert.selector; + +import java.math.BigInteger; + +import com.android.org.bouncycastle.asn1.ASN1OctetString; +import com.android.org.bouncycastle.asn1.cms.IssuerAndSerialNumber; +import com.android.org.bouncycastle.asn1.x500.X500Name; +import com.android.org.bouncycastle.asn1.x509.Extension; +import com.android.org.bouncycastle.cert.X509CertificateHolder; +import com.android.org.bouncycastle.util.Arrays; +import com.android.org.bouncycastle.util.Selector; + +/** + * a basic index for a X509CertificateHolder class + */ +public class X509CertificateHolderSelector + implements Selector +{ + private byte[] subjectKeyId; + + private X500Name issuer; + private BigInteger serialNumber; + + /** + * Construct a selector with the value of a public key's subjectKeyId. + * + * @param subjectKeyId a subjectKeyId + */ + public X509CertificateHolderSelector(byte[] subjectKeyId) + { + this(null, null, subjectKeyId); + } + + /** + * Construct a signer ID based on the issuer and serial number of the signer's associated + * certificate. + * + * @param issuer the issuer of the signer's associated certificate. + * @param serialNumber the serial number of the signer's associated certificate. + */ + public X509CertificateHolderSelector(X500Name issuer, BigInteger serialNumber) + { + this(issuer, serialNumber, null); + } + + /** + * Construct a signer ID based on the issuer and serial number of the signer's associated + * certificate. + * + * @param issuer the issuer of the signer's associated certificate. + * @param serialNumber the serial number of the signer's associated certificate. + * @param subjectKeyId the subject key identifier to use to match the signers associated certificate. + */ + public X509CertificateHolderSelector(X500Name issuer, BigInteger serialNumber, byte[] subjectKeyId) + { + this.issuer = issuer; + this.serialNumber = serialNumber; + this.subjectKeyId = subjectKeyId; + } + + public X500Name getIssuer() + { + return issuer; + } + + public BigInteger getSerialNumber() + { + return serialNumber; + } + + public byte[] getSubjectKeyIdentifier() + { + return Arrays.clone(subjectKeyId); + } + + public int hashCode() + { + int code = Arrays.hashCode(subjectKeyId); + + if (this.serialNumber != null) + { + code ^= this.serialNumber.hashCode(); + } + + if (this.issuer != null) + { + code ^= this.issuer.hashCode(); + } + + return code; + } + + public boolean equals( + Object o) + { + if (!(o instanceof X509CertificateHolderSelector)) + { + return false; + } + + X509CertificateHolderSelector id = (X509CertificateHolderSelector)o; + + return Arrays.areEqual(subjectKeyId, id.subjectKeyId) + && equalsObj(this.serialNumber, id.serialNumber) + && equalsObj(this.issuer, id.issuer); + } + + private boolean equalsObj(Object a, Object b) + { + return (a != null) ? a.equals(b) : b == null; + } + + public boolean match(Object obj) + { + if (obj instanceof X509CertificateHolder) + { + X509CertificateHolder certHldr = (X509CertificateHolder)obj; + + if (this.getSerialNumber() != null) + { + IssuerAndSerialNumber iAndS = new IssuerAndSerialNumber(certHldr.toASN1Structure()); + + return iAndS.getName().equals(this.issuer) + && iAndS.getSerialNumber().getValue().equals(this.serialNumber); + } + else if (subjectKeyId != null) + { + Extension ext = certHldr.getExtension(Extension.subjectKeyIdentifier); + + if (ext == null) + { + return Arrays.areEqual(subjectKeyId, MSOutlookKeyIdCalculator.calculateKeyId(certHldr.getSubjectPublicKeyInfo())); + } + + byte[] subKeyID = ASN1OctetString.getInstance(ext.getParsedValue()).getOctets(); + + return Arrays.areEqual(subjectKeyId, subKeyID); + } + } + else if (obj instanceof byte[]) + { + return Arrays.areEqual(subjectKeyId, (byte[])obj); + } + + return false; + } + + public Object clone() + { + return new X509CertificateHolderSelector(this.issuer, this.serialNumber, this.subjectKeyId); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cmc/CMCException.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cmc/CMCException.java new file mode 100644 index 00000000..fbacb97b --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cmc/CMCException.java @@ -0,0 +1,24 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cmc; + +public class CMCException + extends Exception +{ + private final Throwable cause; + + public CMCException(String msg) + { + this(msg, null); + } + + public CMCException(String msg, Throwable cause) + { + super(msg); + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cmc/SimplePKIResponse.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cmc/SimplePKIResponse.java new file mode 100644 index 00000000..3f758aac --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cmc/SimplePKIResponse.java @@ -0,0 +1,107 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cmc; + +import java.io.IOException; + +import com.android.org.bouncycastle.asn1.ASN1Primitive; +import com.android.org.bouncycastle.asn1.cms.ContentInfo; +import com.android.org.bouncycastle.cert.X509CRLHolder; +import com.android.org.bouncycastle.cert.X509CertificateHolder; +import com.android.org.bouncycastle.cms.CMSException; +import com.android.org.bouncycastle.cms.CMSSignedData; +import com.android.org.bouncycastle.util.Encodable; +import com.android.org.bouncycastle.util.Store; + +/** + * Carrier for a Simple PKI Response. + * <p> + * A Simple PKI Response is defined in RFC 5272 as a CMS SignedData object with no EncapsulatedContentInfo + * and no SignerInfos attached. + * </p> + */ +public class SimplePKIResponse + implements Encodable +{ + private final CMSSignedData certificateResponse; + + private static ContentInfo parseBytes(byte[] responseEncoding) + throws CMCException + { + try + { + return ContentInfo.getInstance(ASN1Primitive.fromByteArray(responseEncoding)); + } + catch (Exception e) + { + throw new CMCException("malformed data: " + e.getMessage(), e); + } + } + + /** + * Create a SimplePKIResponse from the passed in bytes. + * + * @param responseEncoding BER/DER encoding of the certificate. + * @throws IOException in the event of corrupted data, or an incorrect structure. + */ + public SimplePKIResponse(byte[] responseEncoding) + throws CMCException + { + this(parseBytes(responseEncoding)); + } + + /** + * Create a SimplePKIResponse from the passed in ASN.1 structure. + * + * @param signedData a ContentInfo containing a SignedData. + */ + public SimplePKIResponse(ContentInfo signedData) + throws CMCException + { + try + { + this.certificateResponse = new CMSSignedData(signedData); + } + catch (CMSException e) + { + throw new CMCException("malformed response: " + e.getMessage(), e); + } + + if (certificateResponse.getSignerInfos().size() != 0) + { + throw new CMCException("malformed response: SignerInfo structures found"); + } + if (certificateResponse.getSignedContent() != null) + { + throw new CMCException("malformed response: Signed Content found"); + } + } + + /** + * Return any X.509 certificate objects in this SimplePKIResponse structure as a Store of X509CertificateHolder objects. + * + * @return a Store of X509CertificateHolder objects. + */ + public Store<X509CertificateHolder> getCertificates() + { + return certificateResponse.getCertificates(); + } + + /** + * Return any X.509 CRL objects in this SimplePKIResponse structure as a Store of X509CRLHolder objects. + * + * @return a Store of X509CRLHolder objects. + */ + public Store<X509CRLHolder> getCRLs() + { + return certificateResponse.getCRLs(); + } + + /** + * return the ASN.1 encoded representation of this object. + */ + public byte[] getEncoded() + throws IOException + { + return certificateResponse.getEncoded(); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSAbsentContent.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSAbsentContent.java new file mode 100644 index 00000000..c8d68cab --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSAbsentContent.java @@ -0,0 +1,50 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.cms.CMSObjectIdentifiers; + +/** + * a class representing null or absent content. + */ +public class CMSAbsentContent + implements CMSTypedData, CMSReadable +{ + private final ASN1ObjectIdentifier type; + + public CMSAbsentContent() + { + this(CMSObjectIdentifiers.data); + } + + public CMSAbsentContent( + ASN1ObjectIdentifier type) + { + this.type = type; + } + + public InputStream getInputStream() + { + return null; + } + + public void write(OutputStream zOut) + throws IOException, CMSException + { + // do nothing + } + + public Object getContent() + { + return null; + } + + public ASN1ObjectIdentifier getContentType() + { + return type; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSAttributeTableGenerationException.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSAttributeTableGenerationException.java new file mode 100644 index 00000000..62a3dedb --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSAttributeTableGenerationException.java @@ -0,0 +1,33 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +public class CMSAttributeTableGenerationException + extends CMSRuntimeException +{ + Exception e; + + public CMSAttributeTableGenerationException( + String name) + { + super(name); + } + + public CMSAttributeTableGenerationException( + String name, + Exception e) + { + super(name); + + this.e = e; + } + + public Exception getUnderlyingException() + { + return e; + } + + public Throwable getCause() + { + return e; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSAttributeTableGenerator.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSAttributeTableGenerator.java new file mode 100644 index 00000000..899093e3 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSAttributeTableGenerator.java @@ -0,0 +1,22 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import java.util.Map; + +import com.android.org.bouncycastle.asn1.cms.AttributeTable; + +/** + * Note: The SIGNATURE parameter is only available when generating unsigned attributes. + */ +public interface CMSAttributeTableGenerator +{ + String CONTENT_TYPE = "contentType"; + String DIGEST = "digest"; + String SIGNATURE = "encryptedDigest"; + String DIGEST_ALGORITHM_IDENTIFIER = "digestAlgID"; + String MAC_ALGORITHM_IDENTIFIER = "macAlgID"; + String SIGNATURE_ALGORITHM_IDENTIFIER = "signatureAlgID"; + + AttributeTable getAttributes(Map parameters) + throws CMSAttributeTableGenerationException; +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSException.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSException.java new file mode 100644 index 00000000..11fc42db --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSException.java @@ -0,0 +1,33 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +public class CMSException + extends Exception +{ + Exception e; + + public CMSException( + String msg) + { + super(msg); + } + + public CMSException( + String msg, + Exception e) + { + super(msg); + + this.e = e; + } + + public Exception getUnderlyingException() + { + return e; + } + + public Throwable getCause() + { + return e; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSProcessable.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSProcessable.java new file mode 100644 index 00000000..ae2ecdf7 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSProcessable.java @@ -0,0 +1,22 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Use CMSTypedData instead of this. See CMSProcessableFile/ByteArray for defaults. + */ +public interface CMSProcessable +{ + /** + * generic routine to copy out the data we want processed - the OutputStream + * passed in will do the handling on it's own. + * <p> + * Note: this routine may be called multiple times. + */ + public void write(OutputStream out) + throws IOException, CMSException; + + public Object getContent(); +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSProcessableByteArray.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSProcessableByteArray.java new file mode 100644 index 00000000..d22c0607 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSProcessableByteArray.java @@ -0,0 +1,56 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.cms.CMSObjectIdentifiers; +import com.android.org.bouncycastle.util.Arrays; + +/** + * a holding class for a byte array of data to be processed. + */ +public class CMSProcessableByteArray + implements CMSTypedData, CMSReadable +{ + private final ASN1ObjectIdentifier type; + private final byte[] bytes; + + public CMSProcessableByteArray( + byte[] bytes) + { + this(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()), bytes); + } + + public CMSProcessableByteArray( + ASN1ObjectIdentifier type, + byte[] bytes) + { + this.type = type; + this.bytes = bytes; + } + + public InputStream getInputStream() + { + return new ByteArrayInputStream(bytes); + } + + public void write(OutputStream zOut) + throws IOException, CMSException + { + zOut.write(bytes); + } + + public Object getContent() + { + return Arrays.clone(bytes); + } + + public ASN1ObjectIdentifier getContentType() + { + return type; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSReadable.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSReadable.java new file mode 100644 index 00000000..24f60143 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSReadable.java @@ -0,0 +1,11 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import java.io.IOException; +import java.io.InputStream; + +interface CMSReadable +{ + public InputStream getInputStream() + throws IOException, CMSException; +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSRuntimeException.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSRuntimeException.java new file mode 100644 index 00000000..c6cabb51 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSRuntimeException.java @@ -0,0 +1,33 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +public class CMSRuntimeException + extends RuntimeException +{ + Exception e; + + public CMSRuntimeException( + String name) + { + super(name); + } + + public CMSRuntimeException( + String name, + Exception e) + { + super(name); + + this.e = e; + } + + public Exception getUnderlyingException() + { + return e; + } + + public Throwable getCause() + { + return e; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSSignatureAlgorithmNameGenerator.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSSignatureAlgorithmNameGenerator.java new file mode 100644 index 00000000..9919115e --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSSignatureAlgorithmNameGenerator.java @@ -0,0 +1,16 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public interface CMSSignatureAlgorithmNameGenerator +{ + /** + * Return the digest algorithm using one of the standard string + * representations rather than the algorithm object identifier (if possible). + * + * @param digestAlg the digest algorithm id. + * @param encryptionAlg the encryption, or signing, algorithm id. + */ + String getSignatureName(AlgorithmIdentifier digestAlg, AlgorithmIdentifier encryptionAlg); +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSSignatureEncryptionAlgorithmFinder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSSignatureEncryptionAlgorithmFinder.java new file mode 100644 index 00000000..77628b42 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSSignatureEncryptionAlgorithmFinder.java @@ -0,0 +1,18 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * Finder which is used to look up the algorithm identifiers representing the encryption algorithms that + * are associated with a particular signature algorithm. + */ +public interface CMSSignatureEncryptionAlgorithmFinder +{ + /** + * Return the encryption algorithm identifier associated with the passed in signatureAlgorithm + * @param signatureAlgorithm the algorithm identifier of the signature of interest + * @return the algorithm identifier to be associated with the encryption algorithm used in signature creation. + */ + AlgorithmIdentifier findEncryptionAlgorithm(AlgorithmIdentifier signatureAlgorithm); +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSSignedData.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSSignedData.java new file mode 100644 index 00000000..b5f61489 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSSignedData.java @@ -0,0 +1,623 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +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 com.android.org.bouncycastle.asn1.ASN1Encodable; +import com.android.org.bouncycastle.asn1.ASN1EncodableVector; +import com.android.org.bouncycastle.asn1.ASN1InputStream; +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.ASN1OctetString; +import com.android.org.bouncycastle.asn1.ASN1Sequence; +import com.android.org.bouncycastle.asn1.ASN1Set; +import com.android.org.bouncycastle.asn1.BERSequence; +import com.android.org.bouncycastle.asn1.DERSet; +import com.android.org.bouncycastle.asn1.cms.ContentInfo; +import com.android.org.bouncycastle.asn1.cms.SignedData; +import com.android.org.bouncycastle.asn1.cms.SignerInfo; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.cert.X509AttributeCertificateHolder; +import com.android.org.bouncycastle.cert.X509CRLHolder; +import com.android.org.bouncycastle.cert.X509CertificateHolder; +import com.android.org.bouncycastle.operator.OperatorCreationException; +import com.android.org.bouncycastle.util.Encodable; +import com.android.org.bouncycastle.util.Store; + +/** + * general class for handling a pkcs7-signature message. + * + * A simple example of usage - note, in the example below the validity of + * the certificate isn't verified, just the fact that one of the certs + * matches the given signer... + * + * <pre> + * Store certStore = s.getCertificates(); + * SignerInformationStore signers = s.getSignerInfos(); + * Collection c = signers.getSigners(); + * Iterator it = c.iterator(); + * + * while (it.hasNext()) + * { + * SignerInformation signer = (SignerInformation)it.next(); + * Collection certCollection = certStore.getMatches(signer.getSID()); + * + * Iterator certIt = certCollection.iterator(); + * X509CertificateHolder cert = (X509CertificateHolder)certIt.next(); + * + * if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert))) + * { + * verified++; + * } + * } + * </pre> + */ +public class CMSSignedData + implements Encodable +{ + private static final CMSSignedHelper HELPER = CMSSignedHelper.INSTANCE; + + SignedData signedData; + ContentInfo contentInfo; + CMSTypedData signedContent; + SignerInformationStore signerInfoStore; + + private Map hashes; + + private CMSSignedData( + CMSSignedData c) + { + this.signedData = c.signedData; + this.contentInfo = c.contentInfo; + this.signedContent = c.signedContent; + this.signerInfoStore = c.signerInfoStore; + } + + public CMSSignedData( + byte[] sigBlock) + throws CMSException + { + this(CMSUtils.readContentInfo(sigBlock)); + } + + public CMSSignedData( + CMSProcessable signedContent, + byte[] sigBlock) + throws CMSException + { + this(signedContent, CMSUtils.readContentInfo(sigBlock)); + } + + /** + * Content with detached signature, digests precomputed + * + * @param hashes a map of precomputed digests for content indexed by name of hash. + * @param sigBlock the signature object. + */ + public CMSSignedData( + Map hashes, + byte[] sigBlock) + throws CMSException + { + this(hashes, CMSUtils.readContentInfo(sigBlock)); + } + + /** + * base constructor - content with detached signature. + * + * @param signedContent the content that was signed. + * @param sigData the signature object. + */ + public CMSSignedData( + CMSProcessable signedContent, + InputStream sigData) + throws CMSException + { + this(signedContent, CMSUtils.readContentInfo(new ASN1InputStream(sigData))); + } + + /** + * base constructor - with encapsulated content + */ + public CMSSignedData( + InputStream sigData) + throws CMSException + { + this(CMSUtils.readContentInfo(sigData)); + } + + public CMSSignedData( + final CMSProcessable signedContent, + ContentInfo sigData) + throws CMSException + { + if (signedContent instanceof CMSTypedData) + { + this.signedContent = (CMSTypedData)signedContent; + } + else + { + this.signedContent = new CMSTypedData() + { + public ASN1ObjectIdentifier getContentType() + { + return signedData.getEncapContentInfo().getContentType(); + } + + public void write(OutputStream out) + throws IOException, CMSException + { + signedContent.write(out); + } + + public Object getContent() + { + return signedContent.getContent(); + } + }; + } + + this.contentInfo = sigData; + this.signedData = getSignedData(); + } + + public CMSSignedData( + Map hashes, + ContentInfo sigData) + throws CMSException + { + this.hashes = hashes; + this.contentInfo = sigData; + this.signedData = getSignedData(); + } + + public CMSSignedData( + ContentInfo sigData) + throws CMSException + { + this.contentInfo = sigData; + this.signedData = getSignedData(); + + // + // this can happen if the signed message is sent simply to send a + // certificate chain. + // + ASN1Encodable content = signedData.getEncapContentInfo().getContent(); + if (content != null) + { + if (content instanceof ASN1OctetString) + { + this.signedContent = new CMSProcessableByteArray(signedData.getEncapContentInfo().getContentType(), + ((ASN1OctetString)content).getOctets()); + } + else + { + this.signedContent = new PKCS7ProcessableObject(signedData.getEncapContentInfo().getContentType(), content); + } + } + else + { + this.signedContent = null; + } + } + + private SignedData getSignedData() + throws CMSException + { + try + { + return SignedData.getInstance(contentInfo.getContent()); + } + catch (ClassCastException e) + { + throw new CMSException("Malformed content.", e); + } + catch (IllegalArgumentException e) + { + throw new CMSException("Malformed content.", e); + } + } + + /** + * Return the version number for this object + */ + public int getVersion() + { + return signedData.getVersion().getValue().intValue(); + } + + /** + * return the collection of signers that are associated with the + * signatures for the message. + */ + public SignerInformationStore getSignerInfos() + { + if (signerInfoStore == null) + { + ASN1Set s = signedData.getSignerInfos(); + List signerInfos = new ArrayList(); + + for (int i = 0; i != s.size(); i++) + { + SignerInfo info = SignerInfo.getInstance(s.getObjectAt(i)); + ASN1ObjectIdentifier contentType = signedData.getEncapContentInfo().getContentType(); + + if (hashes == null) + { + signerInfos.add(new SignerInformation(info, contentType, signedContent, null)); + } + else + { + Object obj = hashes.keySet().iterator().next(); + byte[] hash = (obj instanceof String) ? (byte[])hashes.get(info.getDigestAlgorithm().getAlgorithm().getId()) : (byte[])hashes.get(info.getDigestAlgorithm().getAlgorithm()); + + signerInfos.add(new SignerInformation(info, contentType, null, hash)); + } + } + + signerInfoStore = new SignerInformationStore(signerInfos); + } + + return signerInfoStore; + } + + /** + * Return if this is object represents a detached signature. + * + * @return true if this message represents a detached signature, false otherwise. + */ + public boolean isDetachedSignature() + { + return signedData.getEncapContentInfo().getContent() == null && signedData.getSignerInfos().size() > 0; + } + + /** + * Return if this is object represents a certificate management message. + * + * @return true if the message has no signers or content, false otherwise. + */ + public boolean isCertificateManagementMessage() + { + return signedData.getEncapContentInfo().getContent() == null && signedData.getSignerInfos().size() == 0; + } + + /** + * Return any X.509 certificate objects in this SignedData structure as a Store of X509CertificateHolder objects. + * + * @return a Store of X509CertificateHolder objects. + */ + public Store<X509CertificateHolder> getCertificates() + { + return HELPER.getCertificates(signedData.getCertificates()); + } + + /** + * Return any X.509 CRL objects in this SignedData structure as a Store of X509CRLHolder objects. + * + * @return a Store of X509CRLHolder objects. + */ + public Store<X509CRLHolder> getCRLs() + { + return HELPER.getCRLs(signedData.getCRLs()); + } + + /** + * Return any X.509 attribute certificate objects in this SignedData structure as a Store of X509AttributeCertificateHolder objects. + * + * @return a Store of X509AttributeCertificateHolder objects. + */ + public Store<X509AttributeCertificateHolder> getAttributeCertificates() + { + return HELPER.getAttributeCertificates(signedData.getCertificates()); + } + + // BEGIN Android-removed: OtherRevocationInfoFormat isn't supported + /* + /** + * Return any OtherRevocationInfo OtherRevInfo objects of the type indicated by otherRevocationInfoFormat in + * this SignedData structure. + * + * @param otherRevocationInfoFormat OID of the format type been looked for. + * + * @return a Store of ASN1Encodable objects representing any objects of otherRevocationInfoFormat found. + * + public Store getOtherRevocationInfo(ASN1ObjectIdentifier otherRevocationInfoFormat) + { + return HELPER.getOtherRevocationInfo(otherRevocationInfoFormat, signedData.getCRLs()); + } + */ + // END Android-removed: OtherRevocationInfoFormat isn't supported + + /** + * Return the digest algorithm identifiers for the SignedData object + * + * @return the set of digest algorithm identifiers + */ + public Set<AlgorithmIdentifier> getDigestAlgorithmIDs() + { + Set<AlgorithmIdentifier> digests = new HashSet<AlgorithmIdentifier>(signedData.getDigestAlgorithms().size()); + + for (Enumeration en = signedData.getDigestAlgorithms().getObjects(); en.hasMoreElements();) + { + digests.add(AlgorithmIdentifier.getInstance(en.nextElement())); + } + + return Collections.unmodifiableSet(digests); + } + + /** + * Return the a string representation of the OID associated with the + * encapsulated content info structure carried in the signed data. + * + * @return the OID for the content type. + */ + public String getSignedContentTypeOID() + { + return signedData.getEncapContentInfo().getContentType().getId(); + } + + public CMSTypedData getSignedContent() + { + return signedContent; + } + + /** + * return the ContentInfo + */ + public ContentInfo toASN1Structure() + { + return contentInfo; + } + + /** + * return the ASN.1 encoded representation of this object. + */ + public byte[] getEncoded() + throws IOException + { + return contentInfo.getEncoded(); + } + + // BEGIN Android-removed: Unknown reason + /* + /** + * Verify all the SignerInformation objects and their associated counter signatures attached + * to this CMS SignedData object. + * + * @param verifierProvider a provider of SignerInformationVerifier objects. + * @return true if all verify, false otherwise. + * @throws CMSException if an exception occurs during the verification process. + * + public boolean verifySignatures(SignerInformationVerifierProvider verifierProvider) + throws CMSException + { + return verifySignatures(verifierProvider, false); + } + + /** + * Verify all the SignerInformation objects and optionally their associated counter signatures attached + * to this CMS SignedData object. + * + * @param verifierProvider a provider of SignerInformationVerifier objects. + * @param ignoreCounterSignatures if true don't check counter signatures. If false check counter signatures as well. + * @return true if all verify, false otherwise. + * @throws CMSException if an exception occurs during the verification process. + * + public boolean verifySignatures(SignerInformationVerifierProvider verifierProvider, boolean ignoreCounterSignatures) + throws CMSException + { + Collection signers = this.getSignerInfos().getSigners(); + + for (Iterator it = signers.iterator(); it.hasNext();) + { + SignerInformation signer = (SignerInformation)it.next(); + + try + { + SignerInformationVerifier verifier = verifierProvider.get(signer.getSID()); + + if (!signer.verify(verifier)) + { + return false; + } + + if (!ignoreCounterSignatures) + { + Collection counterSigners = signer.getCounterSignatures().getSigners(); + + for (Iterator cIt = counterSigners.iterator(); cIt.hasNext();) + { + if (!verifyCounterSignature((SignerInformation)cIt.next(), verifierProvider)) + { + return false; + } + } + } + } + catch (OperatorCreationException e) + { + throw new CMSException("failure in verifier provider: " + e.getMessage(), e); + } + } + + return true; + } + + private boolean verifyCounterSignature(SignerInformation counterSigner, SignerInformationVerifierProvider verifierProvider) + throws OperatorCreationException, CMSException + { + SignerInformationVerifier counterVerifier = verifierProvider.get(counterSigner.getSID()); + + if (!counterSigner.verify(counterVerifier)) + { + return false; + } + + Collection counterSigners = counterSigner.getCounterSignatures().getSigners(); + for (Iterator cIt = counterSigners.iterator(); cIt.hasNext();) + { + if (!verifyCounterSignature((SignerInformation)cIt.next(), verifierProvider)) + { + return false; + } + } + + return true; + } + */ + // END Android-removed: Unknown reason + + /** + * Replace the SignerInformation store associated with this + * CMSSignedData object with the new one passed in. You would + * probably only want to do this if you wanted to change the unsigned + * attributes associated with a signer, or perhaps delete one. + * + * @param signedData the signed data object to be used as a base. + * @param signerInformationStore the new signer information store to use. + * @return a new signed data object. + */ + public static CMSSignedData replaceSigners( + CMSSignedData signedData, + SignerInformationStore signerInformationStore) + { + // + // copy + // + CMSSignedData cms = new CMSSignedData(signedData); + + // + // replace the store + // + cms.signerInfoStore = signerInformationStore; + + // + // replace the signers in the SignedData object + // + ASN1EncodableVector digestAlgs = new ASN1EncodableVector(); + ASN1EncodableVector vec = new ASN1EncodableVector(); + + Iterator it = signerInformationStore.getSigners().iterator(); + while (it.hasNext()) + { + SignerInformation signer = (SignerInformation)it.next(); + digestAlgs.add(CMSSignedHelper.INSTANCE.fixAlgID(signer.getDigestAlgorithmID())); + vec.add(signer.toASN1Structure()); + } + + ASN1Set digests = new DERSet(digestAlgs); + ASN1Set signers = new DERSet(vec); + ASN1Sequence sD = (ASN1Sequence)signedData.signedData.toASN1Primitive(); + + vec = new ASN1EncodableVector(); + + // + // signers are the last item in the sequence. + // + vec.add(sD.getObjectAt(0)); // version + vec.add(digests); + + for (int i = 2; i != sD.size() - 1; i++) + { + vec.add(sD.getObjectAt(i)); + } + + vec.add(signers); + + cms.signedData = SignedData.getInstance(new BERSequence(vec)); + + // + // replace the contentInfo with the new one + // + cms.contentInfo = new ContentInfo(cms.contentInfo.getContentType(), cms.signedData); + + return cms; + } + + /** + * Replace the certificate and CRL information associated with this + * CMSSignedData object with the new one passed in. + * + * @param signedData the signed data object to be used as a base. + * @param certificates the new certificates to be used. + * @param attrCerts the new attribute certificates to be used. + * @param revocations the new CRLs to be used - a collection of X509CRLHolder objects, OtherRevocationInfoFormat, or both. + * @return a new signed data object. + * @exception CMSException if there is an error processing the CertStore + */ + public static CMSSignedData replaceCertificatesAndCRLs( + CMSSignedData signedData, + Store certificates, + Store attrCerts, + Store revocations) + throws CMSException + { + // + // copy + // + CMSSignedData cms = new CMSSignedData(signedData); + + // + // replace the certs and revocations in the SignedData object + // + ASN1Set certSet = null; + ASN1Set crlSet = null; + + if (certificates != null || attrCerts != null) + { + List certs = new ArrayList(); + + if (certificates != null) + { + certs.addAll(CMSUtils.getCertificatesFromStore(certificates)); + } + if (attrCerts != null) + { + certs.addAll(CMSUtils.getAttributeCertificatesFromStore(attrCerts)); + } + + ASN1Set set = CMSUtils.createBerSetFromList(certs); + + if (set.size() != 0) + { + certSet = set; + } + } + + if (revocations != null) + { + ASN1Set set = CMSUtils.createBerSetFromList(CMSUtils.getCRLsFromStore(revocations)); + + if (set.size() != 0) + { + crlSet = set; + } + } + + // + // replace the CMS structure. + // + cms.signedData = new SignedData(signedData.signedData.getDigestAlgorithms(), + signedData.signedData.getEncapContentInfo(), + certSet, + crlSet, + signedData.signedData.getSignerInfos()); + + // + // replace the contentInfo with the new one + // + cms.contentInfo = new ContentInfo(cms.contentInfo.getContentType(), cms.signedData); + + return cms; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSSignedDataGenerator.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSSignedDataGenerator.java new file mode 100644 index 00000000..0dd59aad --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSSignedDataGenerator.java @@ -0,0 +1,233 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import com.android.org.bouncycastle.asn1.ASN1EncodableVector; +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.ASN1OctetString; +import com.android.org.bouncycastle.asn1.ASN1Set; +import com.android.org.bouncycastle.asn1.BEROctetString; +import com.android.org.bouncycastle.asn1.DERSet; +import com.android.org.bouncycastle.asn1.cms.CMSObjectIdentifiers; +import com.android.org.bouncycastle.asn1.cms.ContentInfo; +import com.android.org.bouncycastle.asn1.cms.SignedData; +import com.android.org.bouncycastle.asn1.cms.SignerInfo; + +/** + * general class for generating a pkcs7-signature message. + * <p> + * A simple example of usage, generating a detached signature. + * + * <pre> + * List certList = new ArrayList(); + * CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes()); + * + * certList.add(signCert); + * + * Store certs = new JcaCertStore(certList); + * + * CMSSignedDataGenerator gen = new CMSSignedDataGenerator(); + * ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(signKP.getPrivate()); + * + * gen.addSignerInfoGenerator( + * new JcaSignerInfoGeneratorBuilder( + * new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()) + * .build(sha1Signer, signCert)); + * + * gen.addCertificates(certs); + * + * CMSSignedData sigData = gen.generate(msg, false); + * </pre> + */ +public class CMSSignedDataGenerator + extends CMSSignedGenerator +{ + private List signerInfs = new ArrayList(); + + /** + * base constructor + */ + public CMSSignedDataGenerator() + { + } + + /** + * Generate a CMS Signed Data object carrying a detached CMS signature. + * + * @param content the content to be signed. + */ + public CMSSignedData generate( + CMSTypedData content) + throws CMSException + { + return generate(content, false); + } + + /** + * Generate a CMS Signed Data object which can be carrying a detached CMS signature, or have encapsulated data, depending on the value + * of the encapsulated parameter. + * + * @param content the content to be signed. + * @param encapsulate true if the content should be encapsulated in the signature, false otherwise. + */ + public CMSSignedData generate( + // FIXME Avoid accessing more than once to support CMSProcessableInputStream + CMSTypedData content, + boolean encapsulate) + throws CMSException + { + if (!signerInfs.isEmpty()) + { + throw new IllegalStateException("this method can only be used with SignerInfoGenerator"); + } + + // TODO +// if (signerInfs.isEmpty()) +// { +// /* RFC 3852 5.2 +// * "In the degenerate case where there are no signers, the +// * EncapsulatedContentInfo value being "signed" is irrelevant. In this +// * case, the content type within the EncapsulatedContentInfo value being +// * "signed" MUST be id-data (as defined in section 4), and the content +// * field of the EncapsulatedContentInfo value MUST be omitted." +// */ +// if (encapsulate) +// { +// throw new IllegalArgumentException("no signers, encapsulate must be false"); +// } +// if (!DATA.equals(eContentType)) +// { +// throw new IllegalArgumentException("no signers, eContentType must be id-data"); +// } +// } +// +// if (!DATA.equals(eContentType)) +// { +// /* RFC 3852 5.3 +// * [The 'signedAttrs']... +// * field is optional, but it MUST be present if the content type of +// * the EncapsulatedContentInfo value being signed is not id-data. +// */ +// // TODO signedAttrs must be present for all signers +// } + + ASN1EncodableVector digestAlgs = new ASN1EncodableVector(); + ASN1EncodableVector signerInfos = new ASN1EncodableVector(); + + digests.clear(); // clear the current preserved digest state + + // + // add the precalculated SignerInfo objects. + // + for (Iterator it = _signers.iterator(); it.hasNext();) + { + SignerInformation signer = (SignerInformation)it.next(); + digestAlgs.add(CMSSignedHelper.INSTANCE.fixAlgID(signer.getDigestAlgorithmID())); + + // TODO Verify the content type and calculated digest match the precalculated SignerInfo + signerInfos.add(signer.toASN1Structure()); + } + + // + // add the SignerInfo objects + // + ASN1ObjectIdentifier contentTypeOID = content.getContentType(); + + ASN1OctetString octs = null; + + if (content.getContent() != null) + { + ByteArrayOutputStream bOut = null; + + if (encapsulate) + { + bOut = new ByteArrayOutputStream(); + } + + OutputStream cOut = CMSUtils.attachSignersToOutputStream(signerGens, bOut); + + // Just in case it's unencapsulated and there are no signers! + cOut = CMSUtils.getSafeOutputStream(cOut); + + try + { + content.write(cOut); + + cOut.close(); + } + catch (IOException e) + { + throw new CMSException("data processing exception: " + e.getMessage(), e); + } + + if (encapsulate) + { + octs = new BEROctetString(bOut.toByteArray()); + } + } + + for (Iterator it = signerGens.iterator(); it.hasNext();) + { + SignerInfoGenerator sGen = (SignerInfoGenerator)it.next(); + SignerInfo inf = sGen.generate(contentTypeOID); + + digestAlgs.add(inf.getDigestAlgorithm()); + signerInfos.add(inf); + + byte[] calcDigest = sGen.getCalculatedDigest(); + + if (calcDigest != null) + { + digests.put(inf.getDigestAlgorithm().getAlgorithm().getId(), calcDigest); + } + } + + ASN1Set certificates = null; + + if (certs.size() != 0) + { + certificates = CMSUtils.createBerSetFromList(certs); + } + + ASN1Set certrevlist = null; + + if (crls.size() != 0) + { + certrevlist = CMSUtils.createBerSetFromList(crls); + } + + ContentInfo encInfo = new ContentInfo(contentTypeOID, octs); + + SignedData sd = new SignedData( + new DERSet(digestAlgs), + encInfo, + certificates, + certrevlist, + new DERSet(signerInfos)); + + ContentInfo contentInfo = new ContentInfo( + CMSObjectIdentifiers.signedData, sd); + + return new CMSSignedData(content, contentInfo); + } + + /** + * generate a set of one or more SignerInformation objects representing counter signatures on + * the passed in SignerInformation object. + * + * @param signer the signer to be countersigned + * @return a store containing the signers. + */ + public SignerInformationStore generateCounterSigners(SignerInformation signer) + throws CMSException + { + return this.generate(new CMSProcessableByteArray(null, signer.getSignature()), false).getSignerInfos(); + } +} + diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSSignedGenerator.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSSignedGenerator.java new file mode 100644 index 00000000..4214fca5 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSSignedGenerator.java @@ -0,0 +1,249 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import java.util.ArrayList; +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 com.android.org.bouncycastle.asn1.ASN1Encodable; +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.DERTaggedObject; +import com.android.org.bouncycastle.asn1.cms.CMSObjectIdentifiers; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.asn1.cms.OtherRevocationInfoFormat; +// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import com.android.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import com.android.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import com.android.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.android.org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +import com.android.org.bouncycastle.cert.X509AttributeCertificateHolder; +import com.android.org.bouncycastle.cert.X509CRLHolder; +import com.android.org.bouncycastle.cert.X509CertificateHolder; +import com.android.org.bouncycastle.util.Arrays; +import com.android.org.bouncycastle.util.Store; + +public class CMSSignedGenerator +{ + /** + * Default type for the signed data. + */ + public static final String DATA = CMSObjectIdentifiers.data.getId(); + + public static final String DIGEST_SHA1 = OIWObjectIdentifiers.idSHA1.getId(); + public static final String DIGEST_SHA224 = NISTObjectIdentifiers.id_sha224.getId(); + public static final String DIGEST_SHA256 = NISTObjectIdentifiers.id_sha256.getId(); + public static final String DIGEST_SHA384 = NISTObjectIdentifiers.id_sha384.getId(); + public static final String DIGEST_SHA512 = NISTObjectIdentifiers.id_sha512.getId(); + public static final String DIGEST_MD5 = PKCSObjectIdentifiers.md5.getId(); + // BEGIN Android-removed: Unsupported algorithms + // public static final String DIGEST_GOST3411 = CryptoProObjectIdentifiers.gostR3411.getId(); + // public static final String DIGEST_RIPEMD128 = TeleTrusTObjectIdentifiers.ripemd128.getId(); + // public static final String DIGEST_RIPEMD160 = TeleTrusTObjectIdentifiers.ripemd160.getId(); + // public static final String DIGEST_RIPEMD256 = TeleTrusTObjectIdentifiers.ripemd256.getId(); + // END Android-removed: Unsupported algorithms + + public static final String ENCRYPTION_RSA = PKCSObjectIdentifiers.rsaEncryption.getId(); + public static final String ENCRYPTION_DSA = X9ObjectIdentifiers.id_dsa_with_sha1.getId(); + public static final String ENCRYPTION_ECDSA = X9ObjectIdentifiers.ecdsa_with_SHA1.getId(); + public static final String ENCRYPTION_RSA_PSS = PKCSObjectIdentifiers.id_RSASSA_PSS.getId(); + // BEGIN Android-removed: Unsupported algorithms + // public static final String ENCRYPTION_GOST3410 = CryptoProObjectIdentifiers.gostR3410_94.getId(); + // public static final String ENCRYPTION_ECGOST3410 = CryptoProObjectIdentifiers.gostR3410_2001.getId(); + // END Android-removed: Unsupported algorithms + + private static final String ENCRYPTION_ECDSA_WITH_SHA1 = X9ObjectIdentifiers.ecdsa_with_SHA1.getId(); + private static final String ENCRYPTION_ECDSA_WITH_SHA224 = X9ObjectIdentifiers.ecdsa_with_SHA224.getId(); + private static final String ENCRYPTION_ECDSA_WITH_SHA256 = X9ObjectIdentifiers.ecdsa_with_SHA256.getId(); + private static final String ENCRYPTION_ECDSA_WITH_SHA384 = X9ObjectIdentifiers.ecdsa_with_SHA384.getId(); + private static final String ENCRYPTION_ECDSA_WITH_SHA512 = X9ObjectIdentifiers.ecdsa_with_SHA512.getId(); + + private static final Set NO_PARAMS = new HashSet(); + private static final Map EC_ALGORITHMS = new HashMap(); + + static + { + NO_PARAMS.add(ENCRYPTION_DSA); + NO_PARAMS.add(ENCRYPTION_ECDSA); + NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA1); + NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA224); + NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA256); + NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA384); + NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA512); + + EC_ALGORITHMS.put(DIGEST_SHA1, ENCRYPTION_ECDSA_WITH_SHA1); + EC_ALGORITHMS.put(DIGEST_SHA224, ENCRYPTION_ECDSA_WITH_SHA224); + EC_ALGORITHMS.put(DIGEST_SHA256, ENCRYPTION_ECDSA_WITH_SHA256); + EC_ALGORITHMS.put(DIGEST_SHA384, ENCRYPTION_ECDSA_WITH_SHA384); + EC_ALGORITHMS.put(DIGEST_SHA512, ENCRYPTION_ECDSA_WITH_SHA512); + } + + protected List certs = new ArrayList(); + protected List crls = new ArrayList(); + protected List _signers = new ArrayList(); + protected List signerGens = new ArrayList(); + protected Map digests = new HashMap(); + + /** + * base constructor + */ + protected CMSSignedGenerator() + { + } + + protected Map getBaseParameters(ASN1ObjectIdentifier contentType, AlgorithmIdentifier digAlgId, byte[] hash) + { + Map param = new HashMap(); + param.put(CMSAttributeTableGenerator.CONTENT_TYPE, contentType); + param.put(CMSAttributeTableGenerator.DIGEST_ALGORITHM_IDENTIFIER, digAlgId); + param.put(CMSAttributeTableGenerator.DIGEST, Arrays.clone(hash)); + return param; + } + + /** + * Add a certificate to the certificate set to be included with the generated SignedData message. + * + * @param certificate the certificate to be included. + * @throws CMSException if the certificate cannot be encoded for adding. + */ + public void addCertificate( + X509CertificateHolder certificate) + throws CMSException + { + certs.add(certificate.toASN1Structure()); + } + + /** + * Add the certificates in certStore to the certificate set to be included with the generated SignedData message. + * + * @param certStore the store containing the certificates to be included. + * @throws CMSException if the certificates cannot be encoded for adding. + */ + public void addCertificates( + Store certStore) + throws CMSException + { + certs.addAll(CMSUtils.getCertificatesFromStore(certStore)); + } + + /** + * Add a CRL to the CRL set to be included with the generated SignedData message. + * + * @param crl the CRL to be included. + */ + public void addCRL(X509CRLHolder crl) + { + crls.add(crl.toASN1Structure()); + } + + /** + * Add the CRLs in crlStore to the CRL set to be included with the generated SignedData message. + * + * @param crlStore the store containing the CRLs to be included. + * @throws CMSException if the CRLs cannot be encoded for adding. + */ + public void addCRLs( + Store crlStore) + throws CMSException + { + crls.addAll(CMSUtils.getCRLsFromStore(crlStore)); + } + + /** + * Add the attribute certificates in attrStore to the certificate set to be included with the generated SignedData message. + * + * @param attrCert the store containing the certificates to be included. + * @throws CMSException if the attribute certificate cannot be encoded for adding. + */ + public void addAttributeCertificate( + X509AttributeCertificateHolder attrCert) + throws CMSException + { + certs.add(new DERTaggedObject(false, 2, attrCert.toASN1Structure())); + } + + /** + * Add the attribute certificates in attrStore to the certificate set to be included with the generated SignedData message. + * + * @param attrStore the store containing the certificates to be included. + * @throws CMSException if the attribute certificate cannot be encoded for adding. + */ + public void addAttributeCertificates( + Store attrStore) + throws CMSException + { + certs.addAll(CMSUtils.getAttributeCertificatesFromStore(attrStore)); + } + + // BEGIN Android-removed: OtherRevocationInfoFormat isn't supported + /* + /** + * Add a single instance of otherRevocationData to the CRL set to be included with the generated SignedData message. + * + * @param otherRevocationInfoFormat the OID specifying the format of the otherRevocationInfo data. + * @param otherRevocationInfo the otherRevocationInfo ASN.1 structure. + * + public void addOtherRevocationInfo( + ASN1ObjectIdentifier otherRevocationInfoFormat, + ASN1Encodable otherRevocationInfo) + { + crls.add(new DERTaggedObject(false, 1, new OtherRevocationInfoFormat(otherRevocationInfoFormat, otherRevocationInfo))); + } + + /** + * Add a Store of otherRevocationData to the CRL set to be included with the generated SignedData message. + * + * @param otherRevocationInfoFormat the OID specifying the format of the otherRevocationInfo data. + * @param otherRevocationInfos a Store of otherRevocationInfo data to add. + * + public void addOtherRevocationInfo( + ASN1ObjectIdentifier otherRevocationInfoFormat, + Store otherRevocationInfos) + { + crls.addAll(CMSUtils.getOthersFromStore(otherRevocationInfoFormat, otherRevocationInfos)); + } + */ + // END Android-removed: OtherRevocationInfoFormat isn't supported + + /** + * Add a store of pre-calculated signers to the generator. + * + * @param signerStore store of signers + */ + public void addSigners( + SignerInformationStore signerStore) + { + Iterator it = signerStore.getSigners().iterator(); + + while (it.hasNext()) + { + _signers.add(it.next()); + } + } + + /** + * Add a generator for a particular signer to this CMS SignedData generator. + * + * @param infoGen the generator representing the particular signer. + */ + public void addSignerInfoGenerator(SignerInfoGenerator infoGen) + { + signerGens.add(infoGen); + } + + /** + * Return a map of oids and byte arrays representing the digests calculated on the content during + * the last generate. + * + * @return a map of oids (as String objects) and byte[] representing digests. + */ + public Map getGeneratedDigests() + { + return new HashMap(digests); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSSignedHelper.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSSignedHelper.java new file mode 100644 index 00000000..9a90224f --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSSignedHelper.java @@ -0,0 +1,269 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.android.org.bouncycastle.asn1.ASN1Encodable; +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.ASN1Primitive; +import com.android.org.bouncycastle.asn1.ASN1Sequence; +import com.android.org.bouncycastle.asn1.ASN1Set; +import com.android.org.bouncycastle.asn1.ASN1TaggedObject; +import com.android.org.bouncycastle.asn1.DERNull; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.asn1.cms.OtherRevocationInfoFormat; +// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import com.android.org.bouncycastle.asn1.eac.EACObjectIdentifiers; +import com.android.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import com.android.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import com.android.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.android.org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.asn1.x509.AttributeCertificate; +import com.android.org.bouncycastle.asn1.x509.Certificate; +import com.android.org.bouncycastle.asn1.x509.CertificateList; +import com.android.org.bouncycastle.asn1.x509.X509ObjectIdentifiers; +import com.android.org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +import com.android.org.bouncycastle.cert.X509AttributeCertificateHolder; +import com.android.org.bouncycastle.cert.X509CRLHolder; +import com.android.org.bouncycastle.cert.X509CertificateHolder; +import com.android.org.bouncycastle.util.CollectionStore; +import com.android.org.bouncycastle.util.Store; + +class CMSSignedHelper +{ + static final CMSSignedHelper INSTANCE = new CMSSignedHelper(); + + private static final Map encryptionAlgs = new HashMap(); + private static final Map digestAlgs = new HashMap(); + private static final Map digestAliases = new HashMap(); + + private static void addEntries(ASN1ObjectIdentifier alias, String digest, String encryption) + { + digestAlgs.put(alias.getId(), digest); + encryptionAlgs.put(alias.getId(), encryption); + } + + static + { + addEntries(NISTObjectIdentifiers.dsa_with_sha224, "SHA224", "DSA"); + addEntries(NISTObjectIdentifiers.dsa_with_sha256, "SHA256", "DSA"); + addEntries(NISTObjectIdentifiers.dsa_with_sha384, "SHA384", "DSA"); + addEntries(NISTObjectIdentifiers.dsa_with_sha512, "SHA512", "DSA"); + addEntries(OIWObjectIdentifiers.dsaWithSHA1, "SHA1", "DSA"); + // BEGIN Android-removed: Unsupported algorithms + // addEntries(OIWObjectIdentifiers.md4WithRSA, "MD4", "RSA"); + // addEntries(OIWObjectIdentifiers.md4WithRSAEncryption, "MD4", "RSA"); + // END Android-removed: Unsupported algorithms + addEntries(OIWObjectIdentifiers.md5WithRSA, "MD5", "RSA"); + addEntries(OIWObjectIdentifiers.sha1WithRSA, "SHA1", "RSA"); + // BEGIN Android-removed: Unsupported algorithms + // addEntries(PKCSObjectIdentifiers.md2WithRSAEncryption, "MD2", "RSA"); + // addEntries(PKCSObjectIdentifiers.md4WithRSAEncryption, "MD4", "RSA"); + // END Android-removed: Unsupported algorithms + addEntries(PKCSObjectIdentifiers.md5WithRSAEncryption, "MD5", "RSA"); + addEntries(PKCSObjectIdentifiers.sha1WithRSAEncryption, "SHA1", "RSA"); + addEntries(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224", "RSA"); + addEntries(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256", "RSA"); + addEntries(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384", "RSA"); + addEntries(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512", "RSA"); + addEntries(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1", "ECDSA"); + addEntries(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224", "ECDSA"); + addEntries(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256", "ECDSA"); + addEntries(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384", "ECDSA"); + addEntries(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512", "ECDSA"); + addEntries(X9ObjectIdentifiers.id_dsa_with_sha1, "SHA1", "DSA"); + addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_1, "SHA1", "ECDSA"); + addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224", "ECDSA"); + addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_256, "SHA256", "ECDSA"); + addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_384, "SHA384", "ECDSA"); + addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_512, "SHA512", "ECDSA"); + addEntries(EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_1, "SHA1", "RSA"); + addEntries(EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_256, "SHA256", "RSA"); + addEntries(EACObjectIdentifiers.id_TA_RSA_PSS_SHA_1, "SHA1", "RSAandMGF1"); + addEntries(EACObjectIdentifiers.id_TA_RSA_PSS_SHA_256, "SHA256", "RSAandMGF1"); + + encryptionAlgs.put(X9ObjectIdentifiers.id_dsa.getId(), "DSA"); + encryptionAlgs.put(PKCSObjectIdentifiers.rsaEncryption.getId(), "RSA"); + encryptionAlgs.put(TeleTrusTObjectIdentifiers.teleTrusTRSAsignatureAlgorithm, "RSA"); + encryptionAlgs.put(X509ObjectIdentifiers.id_ea_rsa.getId(), "RSA"); + // BEGIN Android-removed: Unsupported algorithms + /* + encryptionAlgs.put(CMSSignedDataGenerator.ENCRYPTION_RSA_PSS, "RSAandMGF1"); + encryptionAlgs.put(CryptoProObjectIdentifiers.gostR3410_94.getId(), "GOST3410"); + encryptionAlgs.put(CryptoProObjectIdentifiers.gostR3410_2001.getId(), "ECGOST3410"); + encryptionAlgs.put("1.3.6.1.4.1.5849.1.6.2", "ECGOST3410"); + encryptionAlgs.put("1.3.6.1.4.1.5849.1.1.5", "GOST3410"); + encryptionAlgs.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001.getId(), "ECGOST3410"); + encryptionAlgs.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94.getId(), "GOST3410"); + + digestAlgs.put(PKCSObjectIdentifiers.md2.getId(), "MD2"); + digestAlgs.put(PKCSObjectIdentifiers.md4.getId(), "MD4"); + */ + // END Android-removed: Unsupported algorithms + digestAlgs.put(PKCSObjectIdentifiers.md5.getId(), "MD5"); + digestAlgs.put(OIWObjectIdentifiers.idSHA1.getId(), "SHA1"); + digestAlgs.put(NISTObjectIdentifiers.id_sha224.getId(), "SHA224"); + digestAlgs.put(NISTObjectIdentifiers.id_sha256.getId(), "SHA256"); + digestAlgs.put(NISTObjectIdentifiers.id_sha384.getId(), "SHA384"); + digestAlgs.put(NISTObjectIdentifiers.id_sha512.getId(), "SHA512"); + // BEGIN Android-removed: Unsupported algorithms + // digestAlgs.put(TeleTrusTObjectIdentifiers.ripemd128.getId(), "RIPEMD128"); + // digestAlgs.put(TeleTrusTObjectIdentifiers.ripemd160.getId(), "RIPEMD160"); + // digestAlgs.put(TeleTrusTObjectIdentifiers.ripemd256.getId(), "RIPEMD256"); + // digestAlgs.put(CryptoProObjectIdentifiers.gostR3411.getId(), "GOST3411"); + // digestAlgs.put("1.3.6.1.4.1.5849.1.2.1", "GOST3411"); + // END Android-removed: Unsupported algorithms + + digestAliases.put("SHA1", new String[] { "SHA-1" }); + digestAliases.put("SHA224", new String[] { "SHA-224" }); + digestAliases.put("SHA256", new String[] { "SHA-256" }); + digestAliases.put("SHA384", new String[] { "SHA-384" }); + digestAliases.put("SHA512", new String[] { "SHA-512" }); + } + + + /** + * Return the digest encryption algorithm using one of the standard + * JCA string representations rather the the algorithm identifier (if + * possible). + */ + String getEncryptionAlgName( + String encryptionAlgOID) + { + String algName = (String)encryptionAlgs.get(encryptionAlgOID); + + if (algName != null) + { + return algName; + } + + return encryptionAlgOID; + } + + AlgorithmIdentifier fixAlgID(AlgorithmIdentifier algId) + { + if (algId.getParameters() == null) + { + return new AlgorithmIdentifier(algId.getAlgorithm(), DERNull.INSTANCE); + } + + return algId; + } + + void setSigningEncryptionAlgorithmMapping(ASN1ObjectIdentifier oid, String algorithmName) + { + encryptionAlgs.put(oid.getId(), algorithmName); + } + + void setSigningDigestAlgorithmMapping(ASN1ObjectIdentifier oid, String algorithmName) + { + digestAlgs.put(oid.getId(), algorithmName); + } + + Store getCertificates(ASN1Set certSet) + { + if (certSet != null) + { + List certList = new ArrayList(certSet.size()); + + for (Enumeration en = certSet.getObjects(); en.hasMoreElements();) + { + ASN1Primitive obj = ((ASN1Encodable)en.nextElement()).toASN1Primitive(); + + if (obj instanceof ASN1Sequence) + { + certList.add(new X509CertificateHolder(Certificate.getInstance(obj))); + } + } + + return new CollectionStore(certList); + } + + return new CollectionStore(new ArrayList()); + } + + Store getAttributeCertificates(ASN1Set certSet) + { + if (certSet != null) + { + List certList = new ArrayList(certSet.size()); + + for (Enumeration en = certSet.getObjects(); en.hasMoreElements();) + { + ASN1Primitive obj = ((ASN1Encodable)en.nextElement()).toASN1Primitive(); + + if (obj instanceof ASN1TaggedObject) + { + certList.add(new X509AttributeCertificateHolder(AttributeCertificate.getInstance(((ASN1TaggedObject)obj).getObject()))); + } + } + + return new CollectionStore(certList); + } + + return new CollectionStore(new ArrayList()); + } + + Store getCRLs(ASN1Set crlSet) + { + if (crlSet != null) + { + List crlList = new ArrayList(crlSet.size()); + + for (Enumeration en = crlSet.getObjects(); en.hasMoreElements();) + { + ASN1Primitive obj = ((ASN1Encodable)en.nextElement()).toASN1Primitive(); + + if (obj instanceof ASN1Sequence) + { + crlList.add(new X509CRLHolder(CertificateList.getInstance(obj))); + } + } + + return new CollectionStore(crlList); + } + + return new CollectionStore(new ArrayList()); + } + + // BEGIN Android-removed: OtherRevocationInfoFormat isn't supported + /* + Store getOtherRevocationInfo(ASN1ObjectIdentifier otherRevocationInfoFormat, ASN1Set crlSet) + { + if (crlSet != null) + { + List crlList = new ArrayList(crlSet.size()); + + for (Enumeration en = crlSet.getObjects(); en.hasMoreElements();) + { + ASN1Primitive obj = ((ASN1Encodable)en.nextElement()).toASN1Primitive(); + + if (obj instanceof ASN1TaggedObject) + { + ASN1TaggedObject tObj = ASN1TaggedObject.getInstance(obj); + + if (tObj.getTagNo() == 1) + { + OtherRevocationInfoFormat other = OtherRevocationInfoFormat.getInstance(tObj, false); + + if (otherRevocationInfoFormat.equals(other.getInfoFormat())) + { + crlList.add(other.getInfo()); + } + } + } + } + + return new CollectionStore(crlList); + } + + return new CollectionStore(new ArrayList()); + } + */ + // END Android-removed: OtherRevocationInfoFormat isn't supported +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSSignerDigestMismatchException.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSSignerDigestMismatchException.java new file mode 100644 index 00000000..7c03b099 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSSignerDigestMismatchException.java @@ -0,0 +1,12 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +public class CMSSignerDigestMismatchException + extends CMSException +{ + public CMSSignerDigestMismatchException( + String msg) + { + super(msg); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSTypedData.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSTypedData.java new file mode 100644 index 00000000..781a6bcd --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSTypedData.java @@ -0,0 +1,10 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface CMSTypedData + extends CMSProcessable +{ + ASN1ObjectIdentifier getContentType(); +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSUtils.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSUtils.java new file mode 100644 index 00000000..9ee355ae --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSUtils.java @@ -0,0 +1,341 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +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 com.android.org.bouncycastle.asn1.ASN1Encodable; +import com.android.org.bouncycastle.asn1.ASN1EncodableVector; +import com.android.org.bouncycastle.asn1.ASN1InputStream; +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.ASN1Set; +import com.android.org.bouncycastle.asn1.ASN1TaggedObject; +import com.android.org.bouncycastle.asn1.BEROctetStringGenerator; +import com.android.org.bouncycastle.asn1.BERSet; +import com.android.org.bouncycastle.asn1.DERNull; +import com.android.org.bouncycastle.asn1.DERSet; +import com.android.org.bouncycastle.asn1.DERTaggedObject; +import com.android.org.bouncycastle.asn1.cms.CMSObjectIdentifiers; +import com.android.org.bouncycastle.asn1.cms.ContentInfo; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.asn1.cms.OtherRevocationInfoFormat; +// import org.bouncycastle.asn1.ocsp.OCSPResponse; +// import org.bouncycastle.asn1.ocsp.OCSPResponseStatus; +// import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +// import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.cert.X509AttributeCertificateHolder; +import com.android.org.bouncycastle.cert.X509CRLHolder; +import com.android.org.bouncycastle.cert.X509CertificateHolder; +import com.android.org.bouncycastle.operator.DigestCalculator; +import com.android.org.bouncycastle.util.Store; +import com.android.org.bouncycastle.util.Strings; +import com.android.org.bouncycastle.util.io.Streams; +import com.android.org.bouncycastle.util.io.TeeInputStream; +import com.android.org.bouncycastle.util.io.TeeOutputStream; + +class CMSUtils +{ + private static final Set<String> des = new HashSet<String>(); + + static + { + des.add("DES"); + des.add("DESEDE"); + // BEGIN Android-removed: Unsupported algorithms + // des.add(OIWObjectIdentifiers.desCBC.getId()); + // des.add(PKCSObjectIdentifiers.des_EDE3_CBC.getId()); + // des.add(PKCSObjectIdentifiers.des_EDE3_CBC.getId()); + // des.add(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId()); + // END Android-removed: Unsupported algorithms + } + + static boolean isDES(String algorithmID) + { + String name = Strings.toUpperCase(algorithmID); + + return des.contains(name); + } + + static boolean isEquivalent(AlgorithmIdentifier algId1, AlgorithmIdentifier algId2) + { + if (algId1 == null || algId2 == null) + { + return false; + } + + if (!algId1.getAlgorithm().equals(algId2.getAlgorithm())) + { + return false; + } + + ASN1Encodable params1 = algId1.getParameters(); + ASN1Encodable params2 = algId2.getParameters(); + if (params1 != null) + { + return params1.equals(params2) || (params1.equals(DERNull.INSTANCE) && params2 == null); + } + + return params2 == null || params2.equals(DERNull.INSTANCE); + } + + static ContentInfo readContentInfo( + byte[] input) + throws CMSException + { + // enforce limit checking as from a byte array + return readContentInfo(new ASN1InputStream(input)); + } + + static ContentInfo readContentInfo( + InputStream input) + throws CMSException + { + // enforce some limit checking + return readContentInfo(new ASN1InputStream(input)); + } + + static List getCertificatesFromStore(Store certStore) + throws CMSException + { + List certs = new ArrayList(); + + try + { + for (Iterator it = certStore.getMatches(null).iterator(); it.hasNext();) + { + X509CertificateHolder c = (X509CertificateHolder)it.next(); + + certs.add(c.toASN1Structure()); + } + + return certs; + } + catch (ClassCastException e) + { + throw new CMSException("error processing certs", e); + } + } + + static List getAttributeCertificatesFromStore(Store attrStore) + throws CMSException + { + List certs = new ArrayList(); + + try + { + for (Iterator it = attrStore.getMatches(null).iterator(); it.hasNext();) + { + X509AttributeCertificateHolder attrCert = (X509AttributeCertificateHolder)it.next(); + + certs.add(new DERTaggedObject(false, 2, attrCert.toASN1Structure())); + } + + return certs; + } + catch (ClassCastException e) + { + throw new CMSException("error processing certs", e); + } + } + + + static List getCRLsFromStore(Store crlStore) + throws CMSException + { + List crls = new ArrayList(); + + try + { + for (Iterator it = crlStore.getMatches(null).iterator(); it.hasNext();) + { + Object rev = it.next(); + + if (rev instanceof X509CRLHolder) + { + X509CRLHolder c = (X509CRLHolder)rev; + + crls.add(c.toASN1Structure()); + } + // BEGIN Android-removed: OtherRevocationInfoFormat isn't supported + // else if (rev instanceof OtherRevocationInfoFormat) + // { + // OtherRevocationInfoFormat infoFormat = OtherRevocationInfoFormat.getInstance(rev); + // + // validateInfoFormat(infoFormat); + // + // crls.add(new DERTaggedObject(false, 1, infoFormat)); + // } + // END Android-removed: OtherRevocationInfoFormat isn't supported + else if (rev instanceof ASN1TaggedObject) + { + crls.add(rev); + } + } + + return crls; + } + catch (ClassCastException e) + { + throw new CMSException("error processing certs", e); + } + } + + // BEGIN Android-removed: OtherRevocationInfoFormat isn't supported + /* + private static void validateInfoFormat(OtherRevocationInfoFormat infoFormat) + { + if (CMSObjectIdentifiers.id_ri_ocsp_response.equals(infoFormat.getInfoFormat())) + { + OCSPResponse resp = OCSPResponse.getInstance(infoFormat.getInfo()); + + if (resp.getResponseStatus().getValue().intValue() != OCSPResponseStatus.SUCCESSFUL) + { + throw new IllegalArgumentException("cannot add unsuccessful OCSP response to CMS SignedData"); + } + } + } + + static Collection getOthersFromStore(ASN1ObjectIdentifier otherRevocationInfoFormat, Store otherRevocationInfos) + { + List others = new ArrayList(); + + for (Iterator it = otherRevocationInfos.getMatches(null).iterator(); it.hasNext();) + { + ASN1Encodable info = (ASN1Encodable)it.next(); + OtherRevocationInfoFormat infoFormat = new OtherRevocationInfoFormat(otherRevocationInfoFormat, info); + + validateInfoFormat(infoFormat); + + others.add(new DERTaggedObject(false, 1, infoFormat)); + } + + return others; + } + */ + // END Android-removed: OtherRevocationInfoFormat isn't supported + + static ASN1Set createBerSetFromList(List derObjects) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (Iterator it = derObjects.iterator(); it.hasNext();) + { + v.add((ASN1Encodable)it.next()); + } + + return new BERSet(v); + } + + static ASN1Set createDerSetFromList(List derObjects) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (Iterator it = derObjects.iterator(); it.hasNext();) + { + v.add((ASN1Encodable)it.next()); + } + + return new DERSet(v); + } + + static OutputStream createBEROctetOutputStream(OutputStream s, + int tagNo, boolean isExplicit, int bufferSize) throws IOException + { + BEROctetStringGenerator octGen = new BEROctetStringGenerator(s, tagNo, isExplicit); + + if (bufferSize != 0) + { + return octGen.getOctetOutputStream(new byte[bufferSize]); + } + + return octGen.getOctetOutputStream(); + } + + private static ContentInfo readContentInfo( + ASN1InputStream in) + throws CMSException + { + try + { + ContentInfo info = ContentInfo.getInstance(in.readObject()); + if (info == null) + { + throw new CMSException("No content found."); + } + + return info; + } + catch (IOException e) + { + throw new CMSException("IOException reading content.", e); + } + catch (ClassCastException e) + { + throw new CMSException("Malformed content.", e); + } + catch (IllegalArgumentException e) + { + throw new CMSException("Malformed content.", e); + } + } + + public static byte[] streamToByteArray( + InputStream in) + throws IOException + { + return Streams.readAll(in); + } + + public static byte[] streamToByteArray( + InputStream in, + int limit) + throws IOException + { + return Streams.readAllLimited(in, limit); + } + + static InputStream attachDigestsToInputStream(Collection digests, InputStream s) + { + InputStream result = s; + Iterator it = digests.iterator(); + while (it.hasNext()) + { + DigestCalculator digest = (DigestCalculator)it.next(); + result = new TeeInputStream(result, digest.getOutputStream()); + } + return result; + } + + static OutputStream attachSignersToOutputStream(Collection signers, OutputStream s) + { + OutputStream result = s; + Iterator it = signers.iterator(); + while (it.hasNext()) + { + SignerInfoGenerator signerGen = (SignerInfoGenerator)it.next(); + result = getSafeTeeOutputStream(result, signerGen.getCalculatingOutputStream()); + } + return result; + } + + static OutputStream getSafeOutputStream(OutputStream s) + { + return s == null ? new NullOutputStream() : s; + } + + static OutputStream getSafeTeeOutputStream(OutputStream s1, + OutputStream s2) + { + return s1 == null ? getSafeOutputStream(s2) + : s2 == null ? getSafeOutputStream(s1) : new TeeOutputStream( + s1, s2); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSVerifierCertificateNotValidException.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSVerifierCertificateNotValidException.java new file mode 100644 index 00000000..b422478a --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/CMSVerifierCertificateNotValidException.java @@ -0,0 +1,12 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +public class CMSVerifierCertificateNotValidException + extends CMSException +{ + public CMSVerifierCertificateNotValidException( + String msg) + { + super(msg); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java new file mode 100644 index 00000000..955c798e --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java @@ -0,0 +1,185 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import java.util.HashMap; +import java.util.Map; + +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.asn1.bsi.BSIObjectIdentifiers; +// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import com.android.org.bouncycastle.asn1.eac.EACObjectIdentifiers; +import com.android.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import com.android.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import com.android.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.android.org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.asn1.x509.X509ObjectIdentifiers; +import com.android.org.bouncycastle.asn1.x9.X9ObjectIdentifiers; + +public class DefaultCMSSignatureAlgorithmNameGenerator + implements CMSSignatureAlgorithmNameGenerator +{ + private final Map encryptionAlgs = new HashMap(); + private final Map digestAlgs = new HashMap(); + + private void addEntries(ASN1ObjectIdentifier alias, String digest, String encryption) + { + digestAlgs.put(alias, digest); + encryptionAlgs.put(alias, encryption); + } + + public DefaultCMSSignatureAlgorithmNameGenerator() + { + addEntries(NISTObjectIdentifiers.dsa_with_sha224, "SHA224", "DSA"); + addEntries(NISTObjectIdentifiers.dsa_with_sha256, "SHA256", "DSA"); + addEntries(NISTObjectIdentifiers.dsa_with_sha384, "SHA384", "DSA"); + addEntries(NISTObjectIdentifiers.dsa_with_sha512, "SHA512", "DSA"); + addEntries(OIWObjectIdentifiers.dsaWithSHA1, "SHA1", "DSA"); + // BEGIN Android-removed: Unsupported algorithms + // addEntries(OIWObjectIdentifiers.md4WithRSA, "MD4", "RSA"); + // addEntries(OIWObjectIdentifiers.md4WithRSAEncryption, "MD4", "RSA"); + // END Android-removed: Unsupported algorithms + addEntries(OIWObjectIdentifiers.md5WithRSA, "MD5", "RSA"); + addEntries(OIWObjectIdentifiers.sha1WithRSA, "SHA1", "RSA"); + // BEGIN Android-removed: Unsupported algorithms + // addEntries(PKCSObjectIdentifiers.md2WithRSAEncryption, "MD2", "RSA"); + // addEntries(PKCSObjectIdentifiers.md4WithRSAEncryption, "MD4", "RSA"); + // END Android-removed: Unsupported algorithms + addEntries(PKCSObjectIdentifiers.md5WithRSAEncryption, "MD5", "RSA"); + addEntries(PKCSObjectIdentifiers.sha1WithRSAEncryption, "SHA1", "RSA"); + addEntries(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224", "RSA"); + addEntries(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256", "RSA"); + addEntries(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384", "RSA"); + addEntries(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512", "RSA"); + + addEntries(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128, "RIPEMD128", "RSA"); + addEntries(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160, "RIPEMD160", "RSA"); + addEntries(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256, "RIPEMD256", "RSA"); + + addEntries(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1", "ECDSA"); + addEntries(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224", "ECDSA"); + addEntries(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256", "ECDSA"); + addEntries(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384", "ECDSA"); + addEntries(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512", "ECDSA"); + addEntries(X9ObjectIdentifiers.id_dsa_with_sha1, "SHA1", "DSA"); + addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_1, "SHA1", "ECDSA"); + addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224", "ECDSA"); + addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_256, "SHA256", "ECDSA"); + addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_384, "SHA384", "ECDSA"); + addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_512, "SHA512", "ECDSA"); + addEntries(EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_1, "SHA1", "RSA"); + addEntries(EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_256, "SHA256", "RSA"); + addEntries(EACObjectIdentifiers.id_TA_RSA_PSS_SHA_1, "SHA1", "RSAandMGF1"); + addEntries(EACObjectIdentifiers.id_TA_RSA_PSS_SHA_256, "SHA256", "RSAandMGF1"); + // BEGIN Android-removed: Unsupported algorithms + // addEntries(BSIObjectIdentifiers.ecdsa_plain_SHA1, "SHA1", "PLAIN-ECDSA"); + // addEntries(BSIObjectIdentifiers.ecdsa_plain_SHA224, "SHA224", "PLAIN-ECDSA"); + // addEntries(BSIObjectIdentifiers.ecdsa_plain_SHA256, "SHA256", "PLAIN-ECDSA"); + // addEntries(BSIObjectIdentifiers.ecdsa_plain_SHA384, "SHA384", "PLAIN-ECDSA"); + // addEntries(BSIObjectIdentifiers.ecdsa_plain_SHA512, "SHA512", "PLAIN-ECDSA"); + // addEntries(BSIObjectIdentifiers.ecdsa_plain_RIPEMD160, "RIPEMD160", "PLAIN-ECDSA"); + // END Android-removed: Unsupported algorithms + + encryptionAlgs.put(X9ObjectIdentifiers.id_dsa, "DSA"); + encryptionAlgs.put(PKCSObjectIdentifiers.rsaEncryption, "RSA"); + encryptionAlgs.put(TeleTrusTObjectIdentifiers.teleTrusTRSAsignatureAlgorithm, "RSA"); + encryptionAlgs.put(X509ObjectIdentifiers.id_ea_rsa, "RSA"); + encryptionAlgs.put(PKCSObjectIdentifiers.id_RSASSA_PSS, "RSAandMGF1"); + // BEGIN Android-removed: Unsupported algorithms + // encryptionAlgs.put(CryptoProObjectIdentifiers.gostR3410_94, "GOST3410"); + // encryptionAlgs.put(CryptoProObjectIdentifiers.gostR3410_2001, "ECGOST3410"); + // encryptionAlgs.put(new ASN1ObjectIdentifier("1.3.6.1.4.1.5849.1.6.2"), "ECGOST3410"); + // encryptionAlgs.put(new ASN1ObjectIdentifier("1.3.6.1.4.1.5849.1.1.5"), "GOST3410"); + // encryptionAlgs.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "ECGOST3410"); + // encryptionAlgs.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3410"); + // + // digestAlgs.put(PKCSObjectIdentifiers.md2, "MD2"); + // digestAlgs.put(PKCSObjectIdentifiers.md4, "MD4"); + // END Android-removed: Unsupported algorithms + digestAlgs.put(PKCSObjectIdentifiers.md5, "MD5"); + digestAlgs.put(OIWObjectIdentifiers.idSHA1, "SHA1"); + digestAlgs.put(NISTObjectIdentifiers.id_sha224, "SHA224"); + digestAlgs.put(NISTObjectIdentifiers.id_sha256, "SHA256"); + digestAlgs.put(NISTObjectIdentifiers.id_sha384, "SHA384"); + digestAlgs.put(NISTObjectIdentifiers.id_sha512, "SHA512"); + // BEGIN Android-removed: Unsupported algorithms + // digestAlgs.put(TeleTrusTObjectIdentifiers.ripemd128, "RIPEMD128"); + // digestAlgs.put(TeleTrusTObjectIdentifiers.ripemd160, "RIPEMD160"); + // digestAlgs.put(TeleTrusTObjectIdentifiers.ripemd256, "RIPEMD256"); + // digestAlgs.put(CryptoProObjectIdentifiers.gostR3411, "GOST3411"); + // digestAlgs.put(new ASN1ObjectIdentifier("1.3.6.1.4.1.5849.1.2.1"), "GOST3411"); + // END Android-removed: Unsupported algorithms + } + + /** + * Return the digest algorithm using one of the standard JCA string + * representations rather than the algorithm identifier (if possible). + */ + private String getDigestAlgName( + ASN1ObjectIdentifier digestAlgOID) + { + String algName = (String)digestAlgs.get(digestAlgOID); + + if (algName != null) + { + return algName; + } + + return digestAlgOID.getId(); + } + + /** + * Return the digest encryption algorithm using one of the standard + * JCA string representations rather the the algorithm identifier (if + * possible). + */ + private String getEncryptionAlgName( + ASN1ObjectIdentifier encryptionAlgOID) + { + String algName = (String)encryptionAlgs.get(encryptionAlgOID); + + if (algName != null) + { + return algName; + } + + return encryptionAlgOID.getId(); + } + + /** + * Set the mapping for the encryption algorithm used in association with a SignedData generation + * or interpretation. + * + * @param oid object identifier to map. + * @param algorithmName algorithm name to use. + */ + protected void setSigningEncryptionAlgorithmMapping(ASN1ObjectIdentifier oid, String algorithmName) + { + encryptionAlgs.put(oid, algorithmName); + } + + /** + * Set the mapping for the digest algorithm to use in conjunction with a SignedData generation + * or interpretation. + * + * @param oid object identifier to map. + * @param algorithmName algorithm name to use. + */ + protected void setSigningDigestAlgorithmMapping(ASN1ObjectIdentifier oid, String algorithmName) + { + digestAlgs.put(oid, algorithmName); + } + + public String getSignatureName(AlgorithmIdentifier digestAlg, AlgorithmIdentifier encryptionAlg) + { + String digestName = getDigestAlgName(encryptionAlg.getAlgorithm()); + + if (!digestName.equals(encryptionAlg.getAlgorithm().getId())) + { + return digestName + "with" + getEncryptionAlgName(encryptionAlg.getAlgorithm()); + } + + return getDigestAlgName(digestAlg.getAlgorithm()) + "with" + getEncryptionAlgName(encryptionAlg.getAlgorithm()); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java new file mode 100644 index 00000000..2def4bfd --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java @@ -0,0 +1,55 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import java.util.HashSet; +import java.util.Set; + +import com.android.org.bouncycastle.asn1.DERNull; +import com.android.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import com.android.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.android.org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class DefaultCMSSignatureEncryptionAlgorithmFinder + implements CMSSignatureEncryptionAlgorithmFinder +{ + private static final Set RSA_PKCS1d5 = new HashSet(); + + static + { + // BEGIN Android-removed: Unsupported algorithms + // RSA_PKCS1d5.add(PKCSObjectIdentifiers.md2WithRSAEncryption); + // RSA_PKCS1d5.add(PKCSObjectIdentifiers.md4WithRSAEncryption); + // END Android-removed: Unsupported algorithms + RSA_PKCS1d5.add(PKCSObjectIdentifiers.md5WithRSAEncryption); + RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha1WithRSAEncryption); + // BEGIN Android-added: Add support for SHA-2 family signatures + RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha224WithRSAEncryption); + RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha256WithRSAEncryption); + RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha384WithRSAEncryption); + RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha512WithRSAEncryption); + // END Android-added: Add support for SHA-2 family signatures + // BEGIN Android-removed: Unsupported algorithms + // RSA_PKCS1d5.add(OIWObjectIdentifiers.md4WithRSAEncryption); + // RSA_PKCS1d5.add(OIWObjectIdentifiers.md4WithRSA); + // END Android-removed: Unsupported algorithms + RSA_PKCS1d5.add(OIWObjectIdentifiers.md5WithRSA); + RSA_PKCS1d5.add(OIWObjectIdentifiers.sha1WithRSA); + // BEGIN Android-removed: Unsupported algorithms + // RSA_PKCS1d5.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128); + // RSA_PKCS1d5.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160); + // RSA_PKCS1d5.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256); + // END Android-removed: Unsupported algorithms + } + + public AlgorithmIdentifier findEncryptionAlgorithm(AlgorithmIdentifier signatureAlgorithm) + { + // RFC3370 section 3.2 with RFC 5754 update + if (RSA_PKCS1d5.contains(signatureAlgorithm.getAlgorithm())) + { + return new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE); + } + + return signatureAlgorithm; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java new file mode 100644 index 00000000..5931a2ea --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java @@ -0,0 +1,132 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import java.util.Date; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Map; + +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.DEROctetString; +import com.android.org.bouncycastle.asn1.DERSet; +import com.android.org.bouncycastle.asn1.cms.Attribute; +import com.android.org.bouncycastle.asn1.cms.AttributeTable; +import com.android.org.bouncycastle.asn1.cms.CMSAlgorithmProtection; +import com.android.org.bouncycastle.asn1.cms.CMSAttributes; +import com.android.org.bouncycastle.asn1.cms.Time; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * Default signed attributes generator. + */ +public class DefaultSignedAttributeTableGenerator + implements CMSAttributeTableGenerator +{ + private final Hashtable table; + + /** + * Initialise to use all defaults + */ + public DefaultSignedAttributeTableGenerator() + { + table = new Hashtable(); + } + + /** + * Initialise with some extra attributes or overrides. + * + * @param attributeTable initial attribute table to use. + */ + public DefaultSignedAttributeTableGenerator( + AttributeTable attributeTable) + { + if (attributeTable != null) + { + table = attributeTable.toHashtable(); + } + else + { + table = new Hashtable(); + } + } + + /** + * Create a standard attribute table from the passed in parameters - this will + * normally include contentType, signingTime, messageDigest, and CMS algorithm protection. + * If the constructor using an AttributeTable was used, entries in it for contentType, signingTime, and + * messageDigest will override the generated ones. + * + * @param parameters source parameters for table generation. + * + * @return a filled in Hashtable of attributes. + */ + protected Hashtable createStandardAttributeTable( + Map parameters) + { + Hashtable std = copyHashTable(table); + + if (!std.containsKey(CMSAttributes.contentType)) + { + ASN1ObjectIdentifier contentType = ASN1ObjectIdentifier.getInstance( + parameters.get(CMSAttributeTableGenerator.CONTENT_TYPE)); + + // contentType will be null if we're trying to generate a counter signature. + if (contentType != null) + { + Attribute attr = new Attribute(CMSAttributes.contentType, + new DERSet(contentType)); + std.put(attr.getAttrType(), attr); + } + } + + if (!std.containsKey(CMSAttributes.signingTime)) + { + Date signingTime = new Date(); + Attribute attr = new Attribute(CMSAttributes.signingTime, + new DERSet(new Time(signingTime))); + std.put(attr.getAttrType(), attr); + } + + if (!std.containsKey(CMSAttributes.messageDigest)) + { + byte[] messageDigest = (byte[])parameters.get( + CMSAttributeTableGenerator.DIGEST); + Attribute attr = new Attribute(CMSAttributes.messageDigest, + new DERSet(new DEROctetString(messageDigest))); + std.put(attr.getAttrType(), attr); + } + + if (!std.contains(CMSAttributes.cmsAlgorithmProtect)) + { + Attribute attr = new Attribute(CMSAttributes.cmsAlgorithmProtect, new DERSet(new CMSAlgorithmProtection( + (AlgorithmIdentifier)parameters.get(CMSAttributeTableGenerator.DIGEST_ALGORITHM_IDENTIFIER), + CMSAlgorithmProtection.SIGNATURE, (AlgorithmIdentifier)parameters.get(CMSAttributeTableGenerator.SIGNATURE_ALGORITHM_IDENTIFIER)))); + std.put(attr.getAttrType(), attr); + } + + return std; + } + + /** + * @param parameters source parameters + * @return the populated attribute table + */ + public AttributeTable getAttributes(Map parameters) + { + return new AttributeTable(createStandardAttributeTable(parameters)); + } + + private static Hashtable copyHashTable(Hashtable paramsMap) + { + Hashtable newTable = new Hashtable(); + + Enumeration keys = paramsMap.keys(); + while (keys.hasMoreElements()) + { + Object key = keys.nextElement(); + newTable.put(key, paramsMap.get(key)); + } + + return newTable; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/NullOutputStream.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/NullOutputStream.java new file mode 100644 index 00000000..b862f08c --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/NullOutputStream.java @@ -0,0 +1,29 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +/** + * + */ +package com.android.org.bouncycastle.cms; + +import java.io.IOException; +import java.io.OutputStream; + +class NullOutputStream + extends OutputStream +{ + public void write(byte[] buf) + throws IOException + { + // do nothing + } + + public void write(byte[] buf, int off, int len) + throws IOException + { + // do nothing + } + + public void write(int b) throws IOException + { + // do nothing + } +}
\ No newline at end of file diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/PKCS7ProcessableObject.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/PKCS7ProcessableObject.java new file mode 100644 index 00000000..cb99eaf0 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/PKCS7ProcessableObject.java @@ -0,0 +1,66 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Iterator; + +import com.android.org.bouncycastle.asn1.ASN1Encodable; +import com.android.org.bouncycastle.asn1.ASN1Encoding; +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.ASN1Sequence; + +public class PKCS7ProcessableObject + implements CMSTypedData +{ + private final ASN1ObjectIdentifier type; + private final ASN1Encodable structure; + + public PKCS7ProcessableObject( + ASN1ObjectIdentifier type, + ASN1Encodable structure) + { + this.type = type; + this.structure = structure; + } + + public ASN1ObjectIdentifier getContentType() + { + return type; + } + + public void write(OutputStream cOut) + throws IOException, CMSException + { + if (structure instanceof ASN1Sequence) + { + ASN1Sequence s = ASN1Sequence.getInstance(structure); + + for (Iterator it = s.iterator(); it.hasNext();) + { + ASN1Encodable enc = (ASN1Encodable)it.next(); + + cOut.write(enc.toASN1Primitive().getEncoded(ASN1Encoding.DER)); + } + } + else + { + byte[] encoded = structure.toASN1Primitive().getEncoded(ASN1Encoding.DER); + int index = 1; + + while ((encoded[index] & 0xff) > 127) + { + index++; + } + + index++; + + cOut.write(encoded, index, encoded.length - index); + } + } + + public Object getContent() + { + return structure; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/PasswordRecipient.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/PasswordRecipient.java new file mode 100644 index 00000000..737518df --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/PasswordRecipient.java @@ -0,0 +1,51 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import com.android.org.bouncycastle.asn1.DERNull; +import com.android.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public interface PasswordRecipient + extends Recipient +{ + public static final int PKCS5_SCHEME2 = 0; + public static final int PKCS5_SCHEME2_UTF8 = 1; + + static final class PRF + { + public static final PRF HMacSHA1 = new PRF("HMacSHA1", new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA1, DERNull.INSTANCE)); + public static final PRF HMacSHA224 = new PRF("HMacSHA224", new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA224, DERNull.INSTANCE)); + public static final PRF HMacSHA256 = new PRF("HMacSHA256", new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA256, DERNull.INSTANCE)); + public static final PRF HMacSHA384 = new PRF("HMacSHA384", new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA384, DERNull.INSTANCE)); + public static final PRF HMacSHA512 = new PRF("HMacSHA512", new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA512, DERNull.INSTANCE)); + + private final String hmac; + final AlgorithmIdentifier prfAlgID; + + private PRF(String hmac, AlgorithmIdentifier prfAlgID) + { + this.hmac = hmac; + this.prfAlgID = prfAlgID; + } + + public String getName() + { + return hmac; + } + + public AlgorithmIdentifier getAlgorithmID() + { + return prfAlgID; + } + } + + byte[] calculateDerivedKey(int schemeID, AlgorithmIdentifier derivationAlgorithm, int keySize) + throws CMSException; + + RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] derivedKey, byte[] encryptedEncryptedContentKey) + throws CMSException; + + int getPasswordConversionScheme(); + + char[] getPassword(); +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/Recipient.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/Recipient.java new file mode 100644 index 00000000..b22e6e5a --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/Recipient.java @@ -0,0 +1,6 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +public interface Recipient +{ +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/RecipientOperator.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/RecipientOperator.java new file mode 100644 index 00000000..257728fe --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/RecipientOperator.java @@ -0,0 +1,49 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import java.io.InputStream; + +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.operator.InputDecryptor; +import com.android.org.bouncycastle.operator.MacCalculator; +import com.android.org.bouncycastle.util.io.TeeInputStream; + +public class RecipientOperator +{ + private final AlgorithmIdentifier algorithmIdentifier; + private final Object operator; + + public RecipientOperator(InputDecryptor decryptor) + { + this.algorithmIdentifier = decryptor.getAlgorithmIdentifier(); + this.operator = decryptor; + } + + public RecipientOperator(MacCalculator macCalculator) + { + this.algorithmIdentifier = macCalculator.getAlgorithmIdentifier(); + this.operator = macCalculator; + } + + public InputStream getInputStream(InputStream dataIn) + { + if (operator instanceof InputDecryptor) + { + return ((InputDecryptor)operator).getInputStream(dataIn); + } + else + { + return new TeeInputStream(dataIn, ((MacCalculator)operator).getOutputStream()); + } + } + + public boolean isMacBased() + { + return operator instanceof MacCalculator; + } + + public byte[] getMac() + { + return ((MacCalculator)operator).getMac(); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/SignerId.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/SignerId.java new file mode 100644 index 00000000..d4cc0dc4 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/SignerId.java @@ -0,0 +1,105 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import java.math.BigInteger; + +import com.android.org.bouncycastle.asn1.x500.X500Name; +import com.android.org.bouncycastle.cert.selector.X509CertificateHolderSelector; +import com.android.org.bouncycastle.util.Selector; + +/** + * a basic index for a signer. + */ +public class SignerId + implements Selector +{ + private X509CertificateHolderSelector baseSelector; + + private SignerId(X509CertificateHolderSelector baseSelector) + { + this.baseSelector = baseSelector; + } + + /** + * Construct a signer ID with the value of a public key's subjectKeyId. + * + * @param subjectKeyId a subjectKeyId + */ + public SignerId(byte[] subjectKeyId) + { + this(null, null, subjectKeyId); + } + + /** + * Construct a signer ID based on the issuer and serial number of the signer's associated + * certificate. + * + * @param issuer the issuer of the signer's associated certificate. + * @param serialNumber the serial number of the signer's associated certificate. + */ + public SignerId(X500Name issuer, BigInteger serialNumber) + { + this(issuer, serialNumber, null); + } + + /** + * Construct a signer ID based on the issuer and serial number of the signer's associated + * certificate. + * + * @param issuer the issuer of the signer's associated certificate. + * @param serialNumber the serial number of the signer's associated certificate. + * @param subjectKeyId the subject key identifier to use to match the signers associated certificate. + */ + public SignerId(X500Name issuer, BigInteger serialNumber, byte[] subjectKeyId) + { + this(new X509CertificateHolderSelector(issuer, serialNumber, subjectKeyId)); + } + + public X500Name getIssuer() + { + return baseSelector.getIssuer(); + } + + public BigInteger getSerialNumber() + { + return baseSelector.getSerialNumber(); + } + + public byte[] getSubjectKeyIdentifier() + { + return baseSelector.getSubjectKeyIdentifier(); + } + + public int hashCode() + { + return baseSelector.hashCode(); + } + + public boolean equals( + Object o) + { + if (!(o instanceof SignerId)) + { + return false; + } + + SignerId id = (SignerId)o; + + return this.baseSelector.equals(id.baseSelector); + } + + public boolean match(Object obj) + { + if (obj instanceof SignerInformation) + { + return ((SignerInformation)obj).getSID().equals(this); + } + + return baseSelector.match(obj); + } + + public Object clone() + { + return new SignerId(this.baseSelector); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/SignerInfoGenerator.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/SignerInfoGenerator.java new file mode 100644 index 00000000..d3877b6f --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/SignerInfoGenerator.java @@ -0,0 +1,294 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import com.android.org.bouncycastle.asn1.ASN1Encoding; +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.ASN1Set; +import com.android.org.bouncycastle.asn1.DEROctetString; +import com.android.org.bouncycastle.asn1.DERSet; +import com.android.org.bouncycastle.asn1.cms.AttributeTable; +import com.android.org.bouncycastle.asn1.cms.SignerIdentifier; +import com.android.org.bouncycastle.asn1.cms.SignerInfo; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.cert.X509CertificateHolder; +import com.android.org.bouncycastle.operator.ContentSigner; +import com.android.org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder; +import com.android.org.bouncycastle.operator.DigestAlgorithmIdentifierFinder; +import com.android.org.bouncycastle.operator.DigestCalculator; +import com.android.org.bouncycastle.operator.DigestCalculatorProvider; +import com.android.org.bouncycastle.operator.OperatorCreationException; +import com.android.org.bouncycastle.util.Arrays; +import com.android.org.bouncycastle.util.io.TeeOutputStream; + +public class SignerInfoGenerator +{ + private final SignerIdentifier signerIdentifier; + private final CMSAttributeTableGenerator sAttrGen; + private final CMSAttributeTableGenerator unsAttrGen; + private final ContentSigner signer; + private final DigestCalculator digester; + private final DigestAlgorithmIdentifierFinder digAlgFinder = new DefaultDigestAlgorithmIdentifierFinder(); + private final CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder; + + private byte[] calculatedDigest = null; + private X509CertificateHolder certHolder; + + SignerInfoGenerator( + SignerIdentifier signerIdentifier, + ContentSigner signer, + DigestCalculatorProvider digesterProvider, + CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder) + throws OperatorCreationException + { + this(signerIdentifier, signer, digesterProvider, sigEncAlgFinder, false); + } + + SignerInfoGenerator( + SignerIdentifier signerIdentifier, + ContentSigner signer, + DigestCalculatorProvider digesterProvider, + CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder, + boolean isDirectSignature) + throws OperatorCreationException + { + this.signerIdentifier = signerIdentifier; + this.signer = signer; + + if (digesterProvider != null) + { + this.digester = digesterProvider.get(digAlgFinder.find(signer.getAlgorithmIdentifier())); + } + else + { + this.digester = null; + } + + if (isDirectSignature) + { + this.sAttrGen = null; + this.unsAttrGen = null; + } + else + { + this.sAttrGen = new DefaultSignedAttributeTableGenerator(); + this.unsAttrGen = null; + } + + this.sigEncAlgFinder = sigEncAlgFinder; + } + + public SignerInfoGenerator( + SignerInfoGenerator original, + CMSAttributeTableGenerator sAttrGen, + CMSAttributeTableGenerator unsAttrGen) + { + this.signerIdentifier = original.signerIdentifier; + this.signer = original.signer; + this.digester = original.digester; + this.sigEncAlgFinder = original.sigEncAlgFinder; + this.sAttrGen = sAttrGen; + this.unsAttrGen = unsAttrGen; + } + + SignerInfoGenerator( + SignerIdentifier signerIdentifier, + ContentSigner signer, + DigestCalculatorProvider digesterProvider, + CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder, + CMSAttributeTableGenerator sAttrGen, + CMSAttributeTableGenerator unsAttrGen) + throws OperatorCreationException + { + this.signerIdentifier = signerIdentifier; + this.signer = signer; + + if (digesterProvider != null) + { + this.digester = digesterProvider.get(digAlgFinder.find(signer.getAlgorithmIdentifier())); + } + else + { + this.digester = null; + } + + this.sAttrGen = sAttrGen; + this.unsAttrGen = unsAttrGen; + this.sigEncAlgFinder = sigEncAlgFinder; + } + + public SignerIdentifier getSID() + { + return signerIdentifier; + } + + public int getGeneratedVersion() + { + return signerIdentifier.isTagged() ? 3 : 1; + } + + public boolean hasAssociatedCertificate() + { + return certHolder != null; + } + + public X509CertificateHolder getAssociatedCertificate() + { + return certHolder; + } + + public AlgorithmIdentifier getDigestAlgorithm() + { + if (digester != null) + { + return digester.getAlgorithmIdentifier(); + } + + return digAlgFinder.find(signer.getAlgorithmIdentifier()); + } + + public OutputStream getCalculatingOutputStream() + { + if (digester != null) + { + if (sAttrGen == null) + { + return new TeeOutputStream(digester.getOutputStream(), signer.getOutputStream()); + } + return digester.getOutputStream(); + } + else + { + return signer.getOutputStream(); + } + } + + public SignerInfo generate(ASN1ObjectIdentifier contentType) + throws CMSException + { + try + { + /* RFC 3852 5.4 + * The result of the message digest calculation process depends on + * whether the signedAttrs field is present. When the field is absent, + * the result is just the message digest of the content as described + * + * above. When the field is present, however, the result is the message + * digest of the complete DER encoding of the SignedAttrs value + * contained in the signedAttrs field. + */ + ASN1Set signedAttr = null; + + AlgorithmIdentifier digestEncryptionAlgorithm = sigEncAlgFinder.findEncryptionAlgorithm(signer.getAlgorithmIdentifier()); + + AlgorithmIdentifier digestAlg = null; + + if (sAttrGen != null) + { + digestAlg = digester.getAlgorithmIdentifier(); + calculatedDigest = digester.getDigest(); + Map parameters = getBaseParameters(contentType, digester.getAlgorithmIdentifier(), digestEncryptionAlgorithm, calculatedDigest); + AttributeTable signed = sAttrGen.getAttributes(Collections.unmodifiableMap(parameters)); + + signedAttr = getAttributeSet(signed); + + // sig must be composed from the DER encoding. + OutputStream sOut = signer.getOutputStream(); + + sOut.write(signedAttr.getEncoded(ASN1Encoding.DER)); + + sOut.close(); + } + else + { + if (digester != null) + { + digestAlg = digester.getAlgorithmIdentifier(); + calculatedDigest = digester.getDigest(); + } + else + { + digestAlg = digAlgFinder.find(signer.getAlgorithmIdentifier()); + calculatedDigest = null; + } + } + + byte[] sigBytes = signer.getSignature(); + + ASN1Set unsignedAttr = null; + if (unsAttrGen != null) + { + Map parameters = getBaseParameters(contentType, digestAlg, digestEncryptionAlgorithm, calculatedDigest); + parameters.put(CMSAttributeTableGenerator.SIGNATURE, Arrays.clone(sigBytes)); + + AttributeTable unsigned = unsAttrGen.getAttributes(Collections.unmodifiableMap(parameters)); + + unsignedAttr = getAttributeSet(unsigned); + } + + return new SignerInfo(signerIdentifier, digestAlg, + signedAttr, digestEncryptionAlgorithm, new DEROctetString(sigBytes), unsignedAttr); + } + catch (IOException e) + { + throw new CMSException("encoding error.", e); + } + } + + void setAssociatedCertificate(X509CertificateHolder certHolder) + { + this.certHolder = certHolder; + } + + private ASN1Set getAttributeSet( + AttributeTable attr) + { + if (attr != null) + { + return new DERSet(attr.toASN1EncodableVector()); + } + + return null; + } + + private Map getBaseParameters(ASN1ObjectIdentifier contentType, AlgorithmIdentifier digAlgId, AlgorithmIdentifier sigAlgId, byte[] hash) + { + Map param = new HashMap(); + + if (contentType != null) + { + param.put(CMSAttributeTableGenerator.CONTENT_TYPE, contentType); + } + + param.put(CMSAttributeTableGenerator.DIGEST_ALGORITHM_IDENTIFIER, digAlgId); + param.put(CMSAttributeTableGenerator.SIGNATURE_ALGORITHM_IDENTIFIER, sigAlgId); + param.put(CMSAttributeTableGenerator.DIGEST, Arrays.clone(hash)); + + return param; + } + + public byte[] getCalculatedDigest() + { + if (calculatedDigest != null) + { + return Arrays.clone(calculatedDigest); + } + + return null; + } + + public CMSAttributeTableGenerator getSignedAttributeTableGenerator() + { + return sAttrGen; + } + + public CMSAttributeTableGenerator getUnsignedAttributeTableGenerator() + { + return unsAttrGen; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/SignerInfoGeneratorBuilder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/SignerInfoGeneratorBuilder.java new file mode 100644 index 00000000..6ec98717 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/SignerInfoGeneratorBuilder.java @@ -0,0 +1,141 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import com.android.org.bouncycastle.asn1.DEROctetString; +import com.android.org.bouncycastle.asn1.cms.IssuerAndSerialNumber; +import com.android.org.bouncycastle.asn1.cms.SignerIdentifier; +import com.android.org.bouncycastle.cert.X509CertificateHolder; +import com.android.org.bouncycastle.operator.ContentSigner; +import com.android.org.bouncycastle.operator.DigestCalculatorProvider; +import com.android.org.bouncycastle.operator.OperatorCreationException; + +/** + * Builder for SignerInfo generator objects. + */ +public class SignerInfoGeneratorBuilder +{ + private DigestCalculatorProvider digestProvider; + private boolean directSignature; + private CMSAttributeTableGenerator signedGen; + private CMSAttributeTableGenerator unsignedGen; + private CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder; + + /** + * Base constructor. + * + * @param digestProvider a provider of digest calculators for the algorithms required in the signature and attribute calculations. + */ + public SignerInfoGeneratorBuilder(DigestCalculatorProvider digestProvider) + { + this(digestProvider, new DefaultCMSSignatureEncryptionAlgorithmFinder()); + } + + /** + * Base constructor with a particular finder for signature algorithms. + * + * @param digestProvider a provider of digest calculators for the algorithms required in the signature and attribute calculations. + * @param sigEncAlgFinder finder for algorithm IDs to store for the signature encryption/signature algorithm field. + */ + public SignerInfoGeneratorBuilder(DigestCalculatorProvider digestProvider, CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder) + { + this.digestProvider = digestProvider; + this.sigEncAlgFinder = sigEncAlgFinder; + } + + /** + * If the passed in flag is true, the signer signature will be based on the data, not + * a collection of signed attributes, and no signed attributes will be included. + * + * @return the builder object + */ + public SignerInfoGeneratorBuilder setDirectSignature(boolean hasNoSignedAttributes) + { + this.directSignature = hasNoSignedAttributes; + + return this; + } + + /** + * Provide a custom signed attribute generator. + * + * @param signedGen a generator of signed attributes. + * @return the builder object + */ + public SignerInfoGeneratorBuilder setSignedAttributeGenerator(CMSAttributeTableGenerator signedGen) + { + this.signedGen = signedGen; + + return this; + } + + /** + * Provide a generator of unsigned attributes. + * + * @param unsignedGen a generator for signed attributes. + * @return the builder object + */ + public SignerInfoGeneratorBuilder setUnsignedAttributeGenerator(CMSAttributeTableGenerator unsignedGen) + { + this.unsignedGen = unsignedGen; + + return this; + } + + /** + * Build a generator with the passed in certHolder issuer and serial number as the signerIdentifier. + * + * @param contentSigner operator for generating the final signature in the SignerInfo with. + * @param certHolder carrier for the X.509 certificate related to the contentSigner. + * @return a SignerInfoGenerator + * @throws OperatorCreationException if the generator cannot be built. + */ + public SignerInfoGenerator build(ContentSigner contentSigner, X509CertificateHolder certHolder) + throws OperatorCreationException + { + SignerIdentifier sigId = new SignerIdentifier(new IssuerAndSerialNumber(certHolder.toASN1Structure())); + + SignerInfoGenerator sigInfoGen = createGenerator(contentSigner, sigId); + + sigInfoGen.setAssociatedCertificate(certHolder); + + return sigInfoGen; + } + + /** + * Build a generator with the passed in subjectKeyIdentifier as the signerIdentifier. If used you should + * try to follow the calculation described in RFC 5280 section 4.2.1.2. + * + * @param contentSigner operator for generating the final signature in the SignerInfo with. + * @param subjectKeyIdentifier key identifier to identify the public key for verifying the signature. + * @return a SignerInfoGenerator + * @throws OperatorCreationException if the generator cannot be built. + */ + public SignerInfoGenerator build(ContentSigner contentSigner, byte[] subjectKeyIdentifier) + throws OperatorCreationException + { + SignerIdentifier sigId = new SignerIdentifier(new DEROctetString(subjectKeyIdentifier)); + + return createGenerator(contentSigner, sigId); + } + + private SignerInfoGenerator createGenerator(ContentSigner contentSigner, SignerIdentifier sigId) + throws OperatorCreationException + { + if (directSignature) + { + return new SignerInfoGenerator(sigId, contentSigner, digestProvider, sigEncAlgFinder, true); + } + + if (signedGen != null || unsignedGen != null) + { + if (signedGen == null) + { + signedGen = new DefaultSignedAttributeTableGenerator(); + } + + return new SignerInfoGenerator(sigId, contentSigner, digestProvider, sigEncAlgFinder, signedGen, unsignedGen); + } + + return new SignerInfoGenerator(sigId, contentSigner, digestProvider, sigEncAlgFinder); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/SignerInformation.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/SignerInformation.java new file mode 100644 index 00000000..2e78a1cf --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/SignerInformation.java @@ -0,0 +1,744 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; + +import com.android.org.bouncycastle.asn1.ASN1Encodable; +import com.android.org.bouncycastle.asn1.ASN1EncodableVector; +import com.android.org.bouncycastle.asn1.ASN1Encoding; +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.ASN1OctetString; +import com.android.org.bouncycastle.asn1.ASN1Primitive; +import com.android.org.bouncycastle.asn1.ASN1Set; +import com.android.org.bouncycastle.asn1.DERNull; +import com.android.org.bouncycastle.asn1.DERSet; +import com.android.org.bouncycastle.asn1.cms.Attribute; +import com.android.org.bouncycastle.asn1.cms.AttributeTable; +import com.android.org.bouncycastle.asn1.cms.CMSAlgorithmProtection; +import com.android.org.bouncycastle.asn1.cms.CMSAttributes; +import com.android.org.bouncycastle.asn1.cms.IssuerAndSerialNumber; +import com.android.org.bouncycastle.asn1.cms.SignerIdentifier; +import com.android.org.bouncycastle.asn1.cms.SignerInfo; +import com.android.org.bouncycastle.asn1.cms.Time; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.asn1.x509.DigestInfo; +import com.android.org.bouncycastle.cert.X509CertificateHolder; +import com.android.org.bouncycastle.operator.ContentVerifier; +import com.android.org.bouncycastle.operator.DigestCalculator; +import com.android.org.bouncycastle.operator.OperatorCreationException; +import com.android.org.bouncycastle.operator.RawContentVerifier; +import com.android.org.bouncycastle.util.Arrays; +import com.android.org.bouncycastle.util.io.TeeOutputStream; + +/** + * an expanded SignerInfo block from a CMS Signed message + */ +public class SignerInformation +{ + private final SignerId sid; + private final CMSProcessable content; + private final byte[] signature; + private final ASN1ObjectIdentifier contentType; + private final boolean isCounterSignature; + + // Derived + private AttributeTable signedAttributeValues; + private AttributeTable unsignedAttributeValues; + private byte[] resultDigest; + + protected final SignerInfo info; + protected final AlgorithmIdentifier digestAlgorithm; + protected final AlgorithmIdentifier encryptionAlgorithm; + protected final ASN1Set signedAttributeSet; + protected final ASN1Set unsignedAttributeSet; + + SignerInformation( + SignerInfo info, + ASN1ObjectIdentifier contentType, + CMSProcessable content, + byte[] resultDigest) + { + this.info = info; + this.contentType = contentType; + this.isCounterSignature = contentType == null; + + SignerIdentifier s = info.getSID(); + + if (s.isTagged()) + { + ASN1OctetString octs = ASN1OctetString.getInstance(s.getId()); + + sid = new SignerId(octs.getOctets()); + } + else + { + IssuerAndSerialNumber iAnds = IssuerAndSerialNumber.getInstance(s.getId()); + + sid = new SignerId(iAnds.getName(), iAnds.getSerialNumber().getValue()); + } + + this.digestAlgorithm = info.getDigestAlgorithm(); + this.signedAttributeSet = info.getAuthenticatedAttributes(); + this.unsignedAttributeSet = info.getUnauthenticatedAttributes(); + this.encryptionAlgorithm = info.getDigestEncryptionAlgorithm(); + this.signature = info.getEncryptedDigest().getOctets(); + + this.content = content; + this.resultDigest = resultDigest; + } + + /** + * Protected constructor. In some cases clients have their own idea about how to encode + * the signed attributes and calculate the signature. This constructor is to allow developers + * to deal with that by extending off the class and overridng methods like getSignedAttributes(). + * + * @param baseInfo the SignerInformation to base this one on. + */ + protected SignerInformation(SignerInformation baseInfo) + { + this.info = baseInfo.info; + this.contentType = baseInfo.contentType; + this.isCounterSignature = baseInfo.isCounterSignature(); + this.sid = baseInfo.getSID(); + this.digestAlgorithm = info.getDigestAlgorithm(); + this.signedAttributeSet = info.getAuthenticatedAttributes(); + this.unsignedAttributeSet = info.getUnauthenticatedAttributes(); + this.encryptionAlgorithm = info.getDigestEncryptionAlgorithm(); + this.signature = info.getEncryptedDigest().getOctets(); + this.content = baseInfo.content; + this.resultDigest = baseInfo.resultDigest; + } + + public boolean isCounterSignature() + { + return isCounterSignature; + } + + public ASN1ObjectIdentifier getContentType() + { + return this.contentType; + } + + private byte[] encodeObj( + ASN1Encodable obj) + throws IOException + { + if (obj != null) + { + return obj.toASN1Primitive().getEncoded(); + } + + return null; + } + + public SignerId getSID() + { + return sid; + } + + /** + * return the version number for this objects underlying SignerInfo structure. + */ + public int getVersion() + { + return info.getVersion().getValue().intValue(); + } + + public AlgorithmIdentifier getDigestAlgorithmID() + { + return digestAlgorithm; + } + + /** + * return the object identifier for the signature. + */ + public String getDigestAlgOID() + { + return digestAlgorithm.getAlgorithm().getId(); + } + + /** + * return the signature parameters, or null if there aren't any. + */ + public byte[] getDigestAlgParams() + { + try + { + return encodeObj(digestAlgorithm.getParameters()); + } + catch (Exception e) + { + throw new RuntimeException("exception getting digest parameters " + e); + } + } + + /** + * return the content digest that was calculated during verification. + */ + public byte[] getContentDigest() + { + if (resultDigest == null) + { + throw new IllegalStateException("method can only be called after verify."); + } + + return Arrays.clone(resultDigest); + } + + /** + * return the object identifier for the signature. + */ + public String getEncryptionAlgOID() + { + return encryptionAlgorithm.getAlgorithm().getId(); + } + + /** + * return the signature/encryption algorithm parameters, or null if + * there aren't any. + */ + public byte[] getEncryptionAlgParams() + { + try + { + return encodeObj(encryptionAlgorithm.getParameters()); + } + catch (Exception e) + { + throw new RuntimeException("exception getting encryption parameters " + e); + } + } + + /** + * return a table of the signed attributes - indexed by + * the OID of the attribute. + */ + public AttributeTable getSignedAttributes() + { + if (signedAttributeSet != null && signedAttributeValues == null) + { + signedAttributeValues = new AttributeTable(signedAttributeSet); + } + + return signedAttributeValues; + } + + /** + * return a table of the unsigned attributes indexed by + * the OID of the attribute. + */ + public AttributeTable getUnsignedAttributes() + { + if (unsignedAttributeSet != null && unsignedAttributeValues == null) + { + unsignedAttributeValues = new AttributeTable(unsignedAttributeSet); + } + + return unsignedAttributeValues; + } + + /** + * return the encoded signature + */ + public byte[] getSignature() + { + return Arrays.clone(signature); + } + + /** + * Return a SignerInformationStore containing the counter signatures attached to this + * signer. If no counter signatures are present an empty store is returned. + */ + public SignerInformationStore getCounterSignatures() + { + // TODO There are several checks implied by the RFC3852 comments that are missing + + /* + The countersignature attribute MUST be an unsigned attribute; it MUST + NOT be a signed attribute, an authenticated attribute, an + unauthenticated attribute, or an unprotected attribute. + */ + AttributeTable unsignedAttributeTable = getUnsignedAttributes(); + if (unsignedAttributeTable == null) + { + return new SignerInformationStore(new ArrayList(0)); + } + + List counterSignatures = new ArrayList(); + + /* + The UnsignedAttributes syntax is defined as a SET OF Attributes. The + UnsignedAttributes in a signerInfo may include multiple instances of + the countersignature attribute. + */ + ASN1EncodableVector allCSAttrs = unsignedAttributeTable.getAll(CMSAttributes.counterSignature); + + for (int i = 0; i < allCSAttrs.size(); ++i) + { + Attribute counterSignatureAttribute = (Attribute)allCSAttrs.get(i); + + /* + A countersignature attribute can have multiple attribute values. The + syntax is defined as a SET OF AttributeValue, and there MUST be one + or more instances of AttributeValue present. + */ + ASN1Set values = counterSignatureAttribute.getAttrValues(); + if (values.size() < 1) + { + // TODO Throw an appropriate exception? + } + + for (Enumeration en = values.getObjects(); en.hasMoreElements();) + { + /* + Countersignature values have the same meaning as SignerInfo values + for ordinary signatures, except that: + + 1. The signedAttributes field MUST NOT contain a content-type + attribute; there is no content type for countersignatures. + + 2. The signedAttributes field MUST contain a message-digest + attribute if it contains any other attributes. + + 3. The input to the message-digesting process is the contents + octets of the DER encoding of the signatureValue field of the + SignerInfo value with which the attribute is associated. + */ + SignerInfo si = SignerInfo.getInstance(en.nextElement()); + + counterSignatures.add(new SignerInformation(si, null, new CMSProcessableByteArray(getSignature()), null)); + } + } + + return new SignerInformationStore(counterSignatures); + } + + /** + * return the DER encoding of the signed attributes. + * @throws IOException if an encoding error occurs. + */ + public byte[] getEncodedSignedAttributes() + throws IOException + { + if (signedAttributeSet != null) + { + return signedAttributeSet.getEncoded(ASN1Encoding.DER); + } + + return null; + } + + private boolean doVerify( + SignerInformationVerifier verifier) + throws CMSException + { + String encName = CMSSignedHelper.INSTANCE.getEncryptionAlgName(this.getEncryptionAlgOID()); + ContentVerifier contentVerifier; + + try + { + contentVerifier = verifier.getContentVerifier(encryptionAlgorithm, info.getDigestAlgorithm()); + } + catch (OperatorCreationException e) + { + throw new CMSException("can't create content verifier: " + e.getMessage(), e); + } + + try + { + OutputStream sigOut = contentVerifier.getOutputStream(); + + if (resultDigest == null) + { + DigestCalculator calc = verifier.getDigestCalculator(this.getDigestAlgorithmID()); + if (content != null) + { + OutputStream digOut = calc.getOutputStream(); + + if (signedAttributeSet == null) + { + if (contentVerifier instanceof RawContentVerifier) + { + content.write(digOut); + } + else + { + OutputStream cOut = new TeeOutputStream(digOut, sigOut); + + content.write(cOut); + + cOut.close(); + } + } + else + { + content.write(digOut); + sigOut.write(this.getEncodedSignedAttributes()); + } + + digOut.close(); + } + else if (signedAttributeSet != null) + { + sigOut.write(this.getEncodedSignedAttributes()); + } + else + { + // TODO Get rid of this exception and just treat content==null as empty not missing? + throw new CMSException("data not encapsulated in signature - use detached constructor."); + } + + resultDigest = calc.getDigest(); + } + else + { + if (signedAttributeSet == null) + { + if (content != null) + { + content.write(sigOut); + } + } + else + { + sigOut.write(this.getEncodedSignedAttributes()); + } + } + + sigOut.close(); + } + catch (IOException e) + { + throw new CMSException("can't process mime object to create signature.", e); + } + catch (OperatorCreationException e) + { + throw new CMSException("can't create digest calculator: " + e.getMessage(), e); + } + + // RFC 3852 11.1 Check the content-type attribute is correct + { + ASN1Primitive validContentType = getSingleValuedSignedAttribute( + CMSAttributes.contentType, "content-type"); + if (validContentType == null) + { + if (!isCounterSignature && signedAttributeSet != null) + { + throw new CMSException("The content-type attribute type MUST be present whenever signed attributes are present in signed-data"); + } + } + else + { + if (isCounterSignature) + { + throw new CMSException("[For counter signatures,] the signedAttributes field MUST NOT contain a content-type attribute"); + } + + if (!(validContentType instanceof ASN1ObjectIdentifier)) + { + throw new CMSException("content-type attribute value not of ASN.1 type 'OBJECT IDENTIFIER'"); + } + + ASN1ObjectIdentifier signedContentType = (ASN1ObjectIdentifier)validContentType; + + if (!signedContentType.equals(contentType)) + { + throw new CMSException("content-type attribute value does not match eContentType"); + } + } + } + + AttributeTable signedAttrTable = this.getSignedAttributes(); + + // RFC 6211 Validate Algorithm Identifier protection attribute if present + { + AttributeTable unsignedAttrTable = this.getUnsignedAttributes(); + if (unsignedAttrTable != null && unsignedAttrTable.getAll(CMSAttributes.cmsAlgorithmProtect).size() > 0) + { + throw new CMSException("A cmsAlgorithmProtect attribute MUST be a signed attribute"); + } + if (signedAttrTable != null) + { + ASN1EncodableVector protectionAttributes = signedAttrTable.getAll(CMSAttributes.cmsAlgorithmProtect); + if (protectionAttributes.size() > 1) + { + throw new CMSException("Only one instance of a cmsAlgorithmProtect attribute can be present"); + } + + if (protectionAttributes.size() > 0) + { + Attribute attr = Attribute.getInstance(protectionAttributes.get(0)); + if (attr.getAttrValues().size() != 1) + { + throw new CMSException("A cmsAlgorithmProtect attribute MUST contain exactly one value"); + } + + CMSAlgorithmProtection algorithmProtection = CMSAlgorithmProtection.getInstance(attr.getAttributeValues()[0]); + + if (!CMSUtils.isEquivalent(algorithmProtection.getDigestAlgorithm(), info.getDigestAlgorithm())) + { + throw new CMSException("CMS Algorithm Identifier Protection check failed for digestAlgorithm"); + } + + if (!CMSUtils.isEquivalent(algorithmProtection.getSignatureAlgorithm(), info.getDigestEncryptionAlgorithm())) + { + throw new CMSException("CMS Algorithm Identifier Protection check failed for signatureAlgorithm"); + } + } + } + } + + // RFC 3852 11.2 Check the message-digest attribute is correct + { + ASN1Primitive validMessageDigest = getSingleValuedSignedAttribute( + CMSAttributes.messageDigest, "message-digest"); + if (validMessageDigest == null) + { + if (signedAttributeSet != null) + { + throw new CMSException("the message-digest signed attribute type MUST be present when there are any signed attributes present"); + } + } + else + { + if (!(validMessageDigest instanceof ASN1OctetString)) + { + throw new CMSException("message-digest attribute value not of ASN.1 type 'OCTET STRING'"); + } + + ASN1OctetString signedMessageDigest = (ASN1OctetString)validMessageDigest; + + if (!Arrays.constantTimeAreEqual(resultDigest, signedMessageDigest.getOctets())) + { + throw new CMSSignerDigestMismatchException("message-digest attribute value does not match calculated value"); + } + } + } + + // RFC 3852 11.4 Validate countersignature attribute(s) + { + if (signedAttrTable != null + && signedAttrTable.getAll(CMSAttributes.counterSignature).size() > 0) + { + throw new CMSException("A countersignature attribute MUST NOT be a signed attribute"); + } + + AttributeTable unsignedAttrTable = this.getUnsignedAttributes(); + if (unsignedAttrTable != null) + { + ASN1EncodableVector csAttrs = unsignedAttrTable.getAll(CMSAttributes.counterSignature); + for (int i = 0; i < csAttrs.size(); ++i) + { + Attribute csAttr = Attribute.getInstance(csAttrs.get(i)); + if (csAttr.getAttrValues().size() < 1) + { + throw new CMSException("A countersignature attribute MUST contain at least one AttributeValue"); + } + + // Note: We don't recursively validate the countersignature value + } + } + } + + try + { + if (signedAttributeSet == null && resultDigest != null) + { + if (contentVerifier instanceof RawContentVerifier) + { + RawContentVerifier rawVerifier = (RawContentVerifier)contentVerifier; + + if (encName.equals("RSA")) + { + DigestInfo digInfo = new DigestInfo(new AlgorithmIdentifier(digestAlgorithm.getAlgorithm(), DERNull.INSTANCE), resultDigest); + + return rawVerifier.verify(digInfo.getEncoded(ASN1Encoding.DER), this.getSignature()); + } + + return rawVerifier.verify(resultDigest, this.getSignature()); + } + } + + return contentVerifier.verify(this.getSignature()); + } + catch (IOException e) + { + throw new CMSException("can't process mime object to create signature.", e); + } + } + + /** + * Verify that the given verifier can successfully verify the signature on + * this SignerInformation object. + * + * @param verifier a suitably configured SignerInformationVerifier. + * @return true if the signer information is verified, false otherwise. + * @throws com.android.org.bouncycastle.cms.CMSVerifierCertificateNotValidException if the provider has an associated certificate and the certificate is not valid at the time given as the SignerInfo's signing time. + * @throws com.android.org.bouncycastle.cms.CMSException if the verifier is unable to create a ContentVerifiers or DigestCalculators. + */ + public boolean verify(SignerInformationVerifier verifier) + throws CMSException + { + Time signingTime = getSigningTime(); // has to be validated if present. + + if (verifier.hasAssociatedCertificate()) + { + if (signingTime != null) + { + X509CertificateHolder dcv = verifier.getAssociatedCertificate(); + + if (!dcv.isValidOn(signingTime.getDate())) + { + throw new CMSVerifierCertificateNotValidException("verifier not valid at signingTime"); + } + } + } + + return doVerify(verifier); + } + + /** + * Return the underlying ASN.1 object defining this SignerInformation object. + * + * @return a SignerInfo. + */ + public SignerInfo toASN1Structure() + { + return info; + } + + private ASN1Primitive getSingleValuedSignedAttribute( + ASN1ObjectIdentifier attrOID, String printableName) + throws CMSException + { + AttributeTable unsignedAttrTable = this.getUnsignedAttributes(); + if (unsignedAttrTable != null + && unsignedAttrTable.getAll(attrOID).size() > 0) + { + throw new CMSException("The " + printableName + + " attribute MUST NOT be an unsigned attribute"); + } + + AttributeTable signedAttrTable = this.getSignedAttributes(); + if (signedAttrTable == null) + { + return null; + } + + ASN1EncodableVector v = signedAttrTable.getAll(attrOID); + switch (v.size()) + { + case 0: + return null; + case 1: + { + Attribute t = (Attribute)v.get(0); + ASN1Set attrValues = t.getAttrValues(); + if (attrValues.size() != 1) + { + throw new CMSException("A " + printableName + + " attribute MUST have a single attribute value"); + } + + return attrValues.getObjectAt(0).toASN1Primitive(); + } + default: + throw new CMSException("The SignedAttributes in a signerInfo MUST NOT include multiple instances of the " + + printableName + " attribute"); + } + } + + private Time getSigningTime() throws CMSException + { + ASN1Primitive validSigningTime = getSingleValuedSignedAttribute( + CMSAttributes.signingTime, "signing-time"); + + if (validSigningTime == null) + { + return null; + } + + try + { + return Time.getInstance(validSigningTime); + } + catch (IllegalArgumentException e) + { + throw new CMSException("signing-time attribute value not a valid 'Time' structure"); + } + } + + /** + * Return a signer information object with the passed in unsigned + * attributes replacing the ones that are current associated with + * the object passed in. + * + * @param signerInformation the signerInfo to be used as the basis. + * @param unsignedAttributes the unsigned attributes to add. + * @return a copy of the original SignerInformationObject with the changed attributes. + */ + public static SignerInformation replaceUnsignedAttributes( + SignerInformation signerInformation, + AttributeTable unsignedAttributes) + { + SignerInfo sInfo = signerInformation.info; + ASN1Set unsignedAttr = null; + + if (unsignedAttributes != null) + { + unsignedAttr = new DERSet(unsignedAttributes.toASN1EncodableVector()); + } + + return new SignerInformation( + new SignerInfo(sInfo.getSID(), sInfo.getDigestAlgorithm(), + sInfo.getAuthenticatedAttributes(), sInfo.getDigestEncryptionAlgorithm(), sInfo.getEncryptedDigest(), unsignedAttr), + signerInformation.contentType, signerInformation.content, null); + } + + /** + * Return a signer information object with passed in SignerInformationStore representing counter + * signatures attached as an unsigned attribute. + * + * @param signerInformation the signerInfo to be used as the basis. + * @param counterSigners signer info objects carrying counter signature. + * @return a copy of the original SignerInformationObject with the changed attributes. + */ + public static SignerInformation addCounterSigners( + SignerInformation signerInformation, + SignerInformationStore counterSigners) + { + // TODO Perform checks from RFC 3852 11.4 + + SignerInfo sInfo = signerInformation.info; + AttributeTable unsignedAttr = signerInformation.getUnsignedAttributes(); + ASN1EncodableVector v; + + if (unsignedAttr != null) + { + v = unsignedAttr.toASN1EncodableVector(); + } + else + { + v = new ASN1EncodableVector(); + } + + ASN1EncodableVector sigs = new ASN1EncodableVector(); + + for (Iterator it = counterSigners.getSigners().iterator(); it.hasNext();) + { + sigs.add(((SignerInformation)it.next()).toASN1Structure()); + } + + v.add(new Attribute(CMSAttributes.counterSignature, new DERSet(sigs))); + + return new SignerInformation( + new SignerInfo(sInfo.getSID(), sInfo.getDigestAlgorithm(), + sInfo.getAuthenticatedAttributes(), sInfo.getDigestEncryptionAlgorithm(), sInfo.getEncryptedDigest(), new DERSet(v)), + signerInformation.contentType, signerInformation.content, null); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/SignerInformationStore.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/SignerInformationStore.java new file mode 100644 index 00000000..80d164b9 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/SignerInformationStore.java @@ -0,0 +1,142 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import com.android.org.bouncycastle.util.Iterable; + +public class SignerInformationStore + implements Iterable<SignerInformation> +{ + private List all = new ArrayList(); + private Map table = new HashMap(); + + /** + * Create a store containing a single SignerInformation object. + * + * @param signerInfo the signer information to contain. + */ + public SignerInformationStore( + SignerInformation signerInfo) + { + this.all = new ArrayList(1); + this.all.add(signerInfo); + + SignerId sid = signerInfo.getSID(); + + table.put(sid, all); + } + + /** + * Create a store containing a collection of SignerInformation objects. + * + * @param signerInfos a collection signer information objects to contain. + */ + public SignerInformationStore( + Collection<SignerInformation> signerInfos) + { + Iterator it = signerInfos.iterator(); + + while (it.hasNext()) + { + SignerInformation signer = (SignerInformation)it.next(); + SignerId sid = signer.getSID(); + + List list = (ArrayList)table.get(sid); + if (list == null) + { + list = new ArrayList(1); + table.put(sid, list); + } + + list.add(signer); + } + + this.all = new ArrayList(signerInfos); + } + + /** + * Return the first SignerInformation object that matches the + * passed in selector. Null if there are no matches. + * + * @param selector to identify a signer + * @return a single SignerInformation object. Null if none matches. + */ + public SignerInformation get( + SignerId selector) + { + Collection list = getSigners(selector); + + return list.size() == 0 ? null : (SignerInformation) list.iterator().next(); + } + + /** + * Return the number of signers in the collection. + * + * @return number of signers identified. + */ + public int size() + { + return all.size(); + } + + /** + * Return all signers in the collection + * + * @return a collection of signers. + */ + public Collection<SignerInformation> getSigners() + { + return new ArrayList(all); + } + + /** + * Return possible empty collection with signers matching the passed in SignerId + * + * @param selector a signer id to select against. + * @return a collection of SignerInformation objects. + */ + public Collection<SignerInformation> getSigners( + SignerId selector) + { + if (selector.getIssuer() != null && selector.getSubjectKeyIdentifier() != null) + { + List results = new ArrayList(); + + Collection match1 = getSigners(new SignerId(selector.getIssuer(), selector.getSerialNumber())); + + if (match1 != null) + { + results.addAll(match1); + } + + Collection match2 = getSigners(new SignerId(selector.getSubjectKeyIdentifier())); + + if (match2 != null) + { + results.addAll(match2); + } + + return results; + } + else + { + List list = (ArrayList)table.get(selector); + + return list == null ? new ArrayList() : new ArrayList(list); + } + } + + /** + * Support method for Iterable where available. + */ + public Iterator<SignerInformation> iterator() + { + return getSigners().iterator(); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/SignerInformationVerifier.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/SignerInformationVerifier.java new file mode 100644 index 00000000..5d554f8b --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/SignerInformationVerifier.java @@ -0,0 +1,52 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.cert.X509CertificateHolder; +import com.android.org.bouncycastle.operator.ContentVerifier; +import com.android.org.bouncycastle.operator.ContentVerifierProvider; +import com.android.org.bouncycastle.operator.DigestCalculator; +import com.android.org.bouncycastle.operator.DigestCalculatorProvider; +import com.android.org.bouncycastle.operator.OperatorCreationException; +import com.android.org.bouncycastle.operator.SignatureAlgorithmIdentifierFinder; + +public class SignerInformationVerifier +{ + private ContentVerifierProvider verifierProvider; + private DigestCalculatorProvider digestProvider; + private SignatureAlgorithmIdentifierFinder sigAlgorithmFinder; + private CMSSignatureAlgorithmNameGenerator sigNameGenerator; + + public SignerInformationVerifier(CMSSignatureAlgorithmNameGenerator sigNameGenerator, SignatureAlgorithmIdentifierFinder sigAlgorithmFinder, ContentVerifierProvider verifierProvider, DigestCalculatorProvider digestProvider) + { + this.sigNameGenerator = sigNameGenerator; + this.sigAlgorithmFinder = sigAlgorithmFinder; + this.verifierProvider = verifierProvider; + this.digestProvider = digestProvider; + } + + public boolean hasAssociatedCertificate() + { + return verifierProvider.hasAssociatedCertificate(); + } + + public X509CertificateHolder getAssociatedCertificate() + { + return verifierProvider.getAssociatedCertificate(); + } + + public ContentVerifier getContentVerifier(AlgorithmIdentifier signingAlgorithm, AlgorithmIdentifier digestAlgorithm) + throws OperatorCreationException + { + String signatureName = sigNameGenerator.getSignatureName(digestAlgorithm, signingAlgorithm); + AlgorithmIdentifier baseAlgID = sigAlgorithmFinder.find(signatureName); + + return verifierProvider.get(new AlgorithmIdentifier(baseAlgID.getAlgorithm(), signingAlgorithm.getParameters())); + } + + public DigestCalculator getDigestCalculator(AlgorithmIdentifier algorithmIdentifier) + throws OperatorCreationException + { + return digestProvider.get(algorithmIdentifier); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/SimpleAttributeTableGenerator.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/SimpleAttributeTableGenerator.java new file mode 100644 index 00000000..633ea163 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/SimpleAttributeTableGenerator.java @@ -0,0 +1,26 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms; + +import com.android.org.bouncycastle.asn1.cms.AttributeTable; + +import java.util.Map; + +/** + * Basic generator that just returns a preconstructed attribute table + */ +public class SimpleAttributeTableGenerator + implements CMSAttributeTableGenerator +{ + private final AttributeTable attributes; + + public SimpleAttributeTableGenerator( + AttributeTable attributes) + { + this.attributes = attributes; + } + + public AttributeTable getAttributes(Map parameters) + { + return attributes; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/jcajce/JcaSignerInfoGeneratorBuilder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/jcajce/JcaSignerInfoGeneratorBuilder.java new file mode 100644 index 00000000..70176bfa --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/jcajce/JcaSignerInfoGeneratorBuilder.java @@ -0,0 +1,87 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms.jcajce; + +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; + +import com.android.org.bouncycastle.cert.X509CertificateHolder; +import com.android.org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; +import com.android.org.bouncycastle.cms.CMSAttributeTableGenerator; +import com.android.org.bouncycastle.cms.CMSSignatureEncryptionAlgorithmFinder; +import com.android.org.bouncycastle.cms.DefaultCMSSignatureEncryptionAlgorithmFinder; +import com.android.org.bouncycastle.cms.SignerInfoGenerator; +import com.android.org.bouncycastle.cms.SignerInfoGeneratorBuilder; +import com.android.org.bouncycastle.operator.ContentSigner; +import com.android.org.bouncycastle.operator.DigestCalculatorProvider; +import com.android.org.bouncycastle.operator.OperatorCreationException; + +public class JcaSignerInfoGeneratorBuilder +{ + private SignerInfoGeneratorBuilder builder; + + /** + * Base constructor. + * + * @param digestProvider a provider of digest calculators for the algorithms required in the signature and attribute calculations. + */ + public JcaSignerInfoGeneratorBuilder(DigestCalculatorProvider digestProvider) + { + this(digestProvider, new DefaultCMSSignatureEncryptionAlgorithmFinder()); + } + + /** + * Base constructor with a particular finder for signature algorithms. + * + * @param digestProvider a provider of digest calculators for the algorithms required in the signature and attribute calculations. + * @param sigEncAlgFinder finder for algorithm IDs to store for the signature encryption/signature algorithm field. + */ + public JcaSignerInfoGeneratorBuilder(DigestCalculatorProvider digestProvider, CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder) + { + builder = new SignerInfoGeneratorBuilder(digestProvider, sigEncAlgFinder); + } + + /** + * If the passed in flag is true, the signer signature will be based on the data, not + * a collection of signed attributes, and no signed attributes will be included. + * + * @return the builder object + */ + public JcaSignerInfoGeneratorBuilder setDirectSignature(boolean hasNoSignedAttributes) + { + builder.setDirectSignature(hasNoSignedAttributes); + + return this; + } + + public JcaSignerInfoGeneratorBuilder setSignedAttributeGenerator(CMSAttributeTableGenerator signedGen) + { + builder.setSignedAttributeGenerator(signedGen); + + return this; + } + + public JcaSignerInfoGeneratorBuilder setUnsignedAttributeGenerator(CMSAttributeTableGenerator unsignedGen) + { + builder.setUnsignedAttributeGenerator(unsignedGen); + + return this; + } + + public SignerInfoGenerator build(ContentSigner contentSigner, X509CertificateHolder certHolder) + throws OperatorCreationException + { + return builder.build(contentSigner, certHolder); + } + + public SignerInfoGenerator build(ContentSigner contentSigner, byte[] keyIdentifier) + throws OperatorCreationException + { + return builder.build(contentSigner, keyIdentifier); + } + + public SignerInfoGenerator build(ContentSigner contentSigner, X509Certificate certificate) + throws OperatorCreationException, CertificateEncodingException + { + return this.build(contentSigner, new JcaX509CertificateHolder(certificate)); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/jcajce/JcaSignerInfoVerifierBuilder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/jcajce/JcaSignerInfoVerifierBuilder.java new file mode 100644 index 00000000..26610852 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/jcajce/JcaSignerInfoVerifierBuilder.java @@ -0,0 +1,181 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms.jcajce; + +import java.security.Provider; +import java.security.PublicKey; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import com.android.org.bouncycastle.cert.X509CertificateHolder; +import com.android.org.bouncycastle.cms.CMSSignatureAlgorithmNameGenerator; +import com.android.org.bouncycastle.cms.DefaultCMSSignatureAlgorithmNameGenerator; +import com.android.org.bouncycastle.cms.SignerInformationVerifier; +import com.android.org.bouncycastle.operator.ContentVerifierProvider; +import com.android.org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; +import com.android.org.bouncycastle.operator.DigestCalculatorProvider; +import com.android.org.bouncycastle.operator.OperatorCreationException; +import com.android.org.bouncycastle.operator.SignatureAlgorithmIdentifierFinder; +import com.android.org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder; +import com.android.org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; + +public class JcaSignerInfoVerifierBuilder +{ + private Helper helper = new Helper(); + private DigestCalculatorProvider digestProvider; + private CMSSignatureAlgorithmNameGenerator sigAlgNameGen = new DefaultCMSSignatureAlgorithmNameGenerator(); + private SignatureAlgorithmIdentifierFinder sigAlgIDFinder = new DefaultSignatureAlgorithmIdentifierFinder(); + + public JcaSignerInfoVerifierBuilder(DigestCalculatorProvider digestProvider) + { + this.digestProvider = digestProvider; + } + + public JcaSignerInfoVerifierBuilder setProvider(Provider provider) + { + this.helper = new ProviderHelper(provider); + + return this; + } + + public JcaSignerInfoVerifierBuilder setProvider(String providerName) + { + this.helper = new NamedHelper(providerName); + + return this; + } + + /** + * Override the default signature algorithm name generator. + * + * @param sigAlgNameGen the algorithm name generator to use. + * @return the current builder. + */ + public JcaSignerInfoVerifierBuilder setSignatureAlgorithmNameGenerator(CMSSignatureAlgorithmNameGenerator sigAlgNameGen) + { + this.sigAlgNameGen = sigAlgNameGen; + + return this; + } + + public JcaSignerInfoVerifierBuilder setSignatureAlgorithmFinder(SignatureAlgorithmIdentifierFinder sigAlgIDFinder) + { + this.sigAlgIDFinder = sigAlgIDFinder; + + return this; + } + + public SignerInformationVerifier build(X509CertificateHolder certHolder) + throws OperatorCreationException, CertificateException + { + return new SignerInformationVerifier(sigAlgNameGen, sigAlgIDFinder, helper.createContentVerifierProvider(certHolder), digestProvider); + } + + public SignerInformationVerifier build(X509Certificate certificate) + throws OperatorCreationException + { + return new SignerInformationVerifier(sigAlgNameGen, sigAlgIDFinder, helper.createContentVerifierProvider(certificate), digestProvider); + } + + public SignerInformationVerifier build(PublicKey pubKey) + throws OperatorCreationException + { + return new SignerInformationVerifier(sigAlgNameGen, sigAlgIDFinder, helper.createContentVerifierProvider(pubKey), digestProvider); + } + + private class Helper + { + ContentVerifierProvider createContentVerifierProvider(PublicKey publicKey) + throws OperatorCreationException + { + return new JcaContentVerifierProviderBuilder().build(publicKey); + } + + ContentVerifierProvider createContentVerifierProvider(X509Certificate certificate) + throws OperatorCreationException + { + return new JcaContentVerifierProviderBuilder().build(certificate); + } + + ContentVerifierProvider createContentVerifierProvider(X509CertificateHolder certHolder) + throws OperatorCreationException, CertificateException + { + return new JcaContentVerifierProviderBuilder().build(certHolder); + } + + DigestCalculatorProvider createDigestCalculatorProvider() + throws OperatorCreationException + { + return new JcaDigestCalculatorProviderBuilder().build(); + } + } + + private class NamedHelper + extends Helper + { + private final String providerName; + + public NamedHelper(String providerName) + { + this.providerName = providerName; + } + + ContentVerifierProvider createContentVerifierProvider(PublicKey publicKey) + throws OperatorCreationException + { + return new JcaContentVerifierProviderBuilder().setProvider(providerName).build(publicKey); + } + + ContentVerifierProvider createContentVerifierProvider(X509Certificate certificate) + throws OperatorCreationException + { + return new JcaContentVerifierProviderBuilder().setProvider(providerName).build(certificate); + } + + DigestCalculatorProvider createDigestCalculatorProvider() + throws OperatorCreationException + { + return new JcaDigestCalculatorProviderBuilder().setProvider(providerName).build(); + } + + ContentVerifierProvider createContentVerifierProvider(X509CertificateHolder certHolder) + throws OperatorCreationException, CertificateException + { + return new JcaContentVerifierProviderBuilder().setProvider(providerName).build(certHolder); + } + } + + private class ProviderHelper + extends Helper + { + private final Provider provider; + + public ProviderHelper(Provider provider) + { + this.provider = provider; + } + + ContentVerifierProvider createContentVerifierProvider(PublicKey publicKey) + throws OperatorCreationException + { + return new JcaContentVerifierProviderBuilder().setProvider(provider).build(publicKey); + } + + ContentVerifierProvider createContentVerifierProvider(X509Certificate certificate) + throws OperatorCreationException + { + return new JcaContentVerifierProviderBuilder().setProvider(provider).build(certificate); + } + + DigestCalculatorProvider createDigestCalculatorProvider() + throws OperatorCreationException + { + return new JcaDigestCalculatorProviderBuilder().setProvider(provider).build(); + } + + ContentVerifierProvider createContentVerifierProvider(X509CertificateHolder certHolder) + throws OperatorCreationException, CertificateException + { + return new JcaContentVerifierProviderBuilder().setProvider(provider).build(certHolder); + } + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/jcajce/JcaSimpleSignerInfoVerifierBuilder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/jcajce/JcaSimpleSignerInfoVerifierBuilder.java new file mode 100644 index 00000000..0e06a689 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/cms/jcajce/JcaSimpleSignerInfoVerifierBuilder.java @@ -0,0 +1,151 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.cms.jcajce; + +import java.security.Provider; +import java.security.PublicKey; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import com.android.org.bouncycastle.cert.X509CertificateHolder; +import com.android.org.bouncycastle.cms.DefaultCMSSignatureAlgorithmNameGenerator; +import com.android.org.bouncycastle.cms.SignerInformationVerifier; +import com.android.org.bouncycastle.operator.ContentVerifierProvider; +import com.android.org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; +import com.android.org.bouncycastle.operator.DigestCalculatorProvider; +import com.android.org.bouncycastle.operator.OperatorCreationException; +import com.android.org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder; +import com.android.org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; + +public class JcaSimpleSignerInfoVerifierBuilder +{ + private Helper helper = new Helper(); + + public JcaSimpleSignerInfoVerifierBuilder setProvider(Provider provider) + { + this.helper = new ProviderHelper(provider); + + return this; + } + + public JcaSimpleSignerInfoVerifierBuilder setProvider(String providerName) + { + this.helper = new NamedHelper(providerName); + + return this; + } + + public SignerInformationVerifier build(X509CertificateHolder certHolder) + throws OperatorCreationException, CertificateException + { + return new SignerInformationVerifier(new DefaultCMSSignatureAlgorithmNameGenerator(), new DefaultSignatureAlgorithmIdentifierFinder(), helper.createContentVerifierProvider(certHolder), helper.createDigestCalculatorProvider()); + } + + public SignerInformationVerifier build(X509Certificate certificate) + throws OperatorCreationException + { + return new SignerInformationVerifier(new DefaultCMSSignatureAlgorithmNameGenerator(), new DefaultSignatureAlgorithmIdentifierFinder(), helper.createContentVerifierProvider(certificate), helper.createDigestCalculatorProvider()); + } + + public SignerInformationVerifier build(PublicKey pubKey) + throws OperatorCreationException + { + return new SignerInformationVerifier(new DefaultCMSSignatureAlgorithmNameGenerator(), new DefaultSignatureAlgorithmIdentifierFinder(), helper.createContentVerifierProvider(pubKey), helper.createDigestCalculatorProvider()); + } + + private class Helper + { + ContentVerifierProvider createContentVerifierProvider(PublicKey publicKey) + throws OperatorCreationException + { + return new JcaContentVerifierProviderBuilder().build(publicKey); + } + + ContentVerifierProvider createContentVerifierProvider(X509Certificate certificate) + throws OperatorCreationException + { + return new JcaContentVerifierProviderBuilder().build(certificate); + } + + ContentVerifierProvider createContentVerifierProvider(X509CertificateHolder certHolder) + throws OperatorCreationException, CertificateException + { + return new JcaContentVerifierProviderBuilder().build(certHolder); + } + + DigestCalculatorProvider createDigestCalculatorProvider() + throws OperatorCreationException + { + return new JcaDigestCalculatorProviderBuilder().build(); + } + } + + private class NamedHelper + extends Helper + { + private final String providerName; + + public NamedHelper(String providerName) + { + this.providerName = providerName; + } + + ContentVerifierProvider createContentVerifierProvider(PublicKey publicKey) + throws OperatorCreationException + { + return new JcaContentVerifierProviderBuilder().setProvider(providerName).build(publicKey); + } + + ContentVerifierProvider createContentVerifierProvider(X509Certificate certificate) + throws OperatorCreationException + { + return new JcaContentVerifierProviderBuilder().setProvider(providerName).build(certificate); + } + + DigestCalculatorProvider createDigestCalculatorProvider() + throws OperatorCreationException + { + return new JcaDigestCalculatorProviderBuilder().setProvider(providerName).build(); + } + + ContentVerifierProvider createContentVerifierProvider(X509CertificateHolder certHolder) + throws OperatorCreationException, CertificateException + { + return new JcaContentVerifierProviderBuilder().setProvider(providerName).build(certHolder); + } + } + + private class ProviderHelper + extends Helper + { + private final Provider provider; + + public ProviderHelper(Provider provider) + { + this.provider = provider; + } + + ContentVerifierProvider createContentVerifierProvider(PublicKey publicKey) + throws OperatorCreationException + { + return new JcaContentVerifierProviderBuilder().setProvider(provider).build(publicKey); + } + + ContentVerifierProvider createContentVerifierProvider(X509Certificate certificate) + throws OperatorCreationException + { + return new JcaContentVerifierProviderBuilder().setProvider(provider).build(certificate); + } + + DigestCalculatorProvider createDigestCalculatorProvider() + throws OperatorCreationException + { + return new JcaDigestCalculatorProviderBuilder().setProvider(provider).build(); + } + + ContentVerifierProvider createContentVerifierProvider(X509CertificateHolder certHolder) + throws OperatorCreationException, CertificateException + { + return new JcaContentVerifierProviderBuilder().setProvider(provider).build(certHolder); + } + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/openssl/CertificateTrustBlock.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/openssl/CertificateTrustBlock.java new file mode 100644 index 00000000..5cf0a300 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/openssl/CertificateTrustBlock.java @@ -0,0 +1,133 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.openssl; + +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import com.android.org.bouncycastle.asn1.ASN1Encodable; +import com.android.org.bouncycastle.asn1.ASN1EncodableVector; +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.ASN1Sequence; +import com.android.org.bouncycastle.asn1.ASN1TaggedObject; +import com.android.org.bouncycastle.asn1.DERSequence; +import com.android.org.bouncycastle.asn1.DERTaggedObject; +import com.android.org.bouncycastle.asn1.DERUTF8String; + +public class CertificateTrustBlock +{ + private ASN1Sequence uses; + private ASN1Sequence prohibitions; + private String alias; + + public CertificateTrustBlock(Set<ASN1ObjectIdentifier> uses) + { + this(null, uses, null); + } + + public CertificateTrustBlock(String alias, Set<ASN1ObjectIdentifier> uses) + { + this(alias, uses, null); + } + + public CertificateTrustBlock(String alias, Set<ASN1ObjectIdentifier> uses, Set<ASN1ObjectIdentifier> prohibitions) + { + this.alias = alias; + this.uses = toSequence(uses); + this.prohibitions = toSequence(prohibitions); + } + + CertificateTrustBlock(byte[] encoded) + { + ASN1Sequence seq = ASN1Sequence.getInstance(encoded); + + for (Enumeration en = seq.getObjects(); en.hasMoreElements();) + { + ASN1Encodable obj = (ASN1Encodable)en.nextElement(); + + if (obj instanceof ASN1Sequence) + { + this.uses = ASN1Sequence.getInstance(obj); + } + else if (obj instanceof ASN1TaggedObject) + { + this.prohibitions = ASN1Sequence.getInstance((ASN1TaggedObject)obj, false); + } + else if (obj instanceof DERUTF8String) + { + this.alias = DERUTF8String.getInstance(obj).getString(); + } + } + } + + public String getAlias() + { + return alias; + } + + public Set<ASN1ObjectIdentifier> getUses() + { + return toSet(uses); + } + + public Set<ASN1ObjectIdentifier> getProhibitions() + { + return toSet(prohibitions); + } + + private Set<ASN1ObjectIdentifier> toSet(ASN1Sequence seq) + { + if (seq != null) + { + Set<ASN1ObjectIdentifier> oids = new HashSet<ASN1ObjectIdentifier>(seq.size()); + + for (Enumeration en = seq.getObjects(); en.hasMoreElements(); ) + { + oids.add(ASN1ObjectIdentifier.getInstance(en.nextElement())); + } + + return oids; + } + + return Collections.EMPTY_SET; + } + + private ASN1Sequence toSequence(Set<ASN1ObjectIdentifier> oids) + { + if (oids == null || oids.isEmpty()) + { + return null; + } + + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (Iterator it = oids.iterator(); it.hasNext();) + { + v.add((ASN1Encodable)it.next()); + } + + return new DERSequence(v); + } + + ASN1Sequence toASN1Sequence() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (uses != null) + { + v.add(uses); + } + if (prohibitions != null) + { + v.add(new DERTaggedObject(false, 0, prohibitions)); + } + if (alias != null) + { + v.add(new DERUTF8String(alias)); + } + + return new DERSequence(v); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/ContentSigner.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/ContentSigner.java new file mode 100644 index 00000000..7a68219c --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/ContentSigner.java @@ -0,0 +1,28 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator; + +import java.io.OutputStream; + +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public interface ContentSigner +{ + AlgorithmIdentifier getAlgorithmIdentifier(); + + /** + * Returns a stream that will accept data for the purpose of calculating + * a signature. Use org.bouncycastle.util.io.TeeOutputStream if you want to accumulate + * the data on the fly as well. + * + * @return an OutputStream + */ + OutputStream getOutputStream(); + + /** + * Returns a signature based on the current data written to the stream, since the + * start or the last call to getSignature(). + * + * @return bytes representing the signature. + */ + byte[] getSignature(); +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/ContentVerifier.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/ContentVerifier.java new file mode 100644 index 00000000..5c7ce115 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/ContentVerifier.java @@ -0,0 +1,32 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator; + +import java.io.OutputStream; + +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public interface ContentVerifier +{ + /** + * Return the algorithm identifier describing the signature + * algorithm and parameters this expander supports. + * + * @return algorithm oid and parameters. + */ + AlgorithmIdentifier getAlgorithmIdentifier(); + + /** + * Returns a stream that will accept data for the purpose of calculating + * a signature for later verification. Use org.bouncycastle.util.io.TeeOutputStream if you want to accumulate + * the data on the fly as well. + * + * @return an OutputStream + */ + OutputStream getOutputStream(); + + /** + * @param expected expected value of the signature on the data. + * @return true if the signature verifies, false otherwise + */ + boolean verify(byte[] expected); +}
\ No newline at end of file diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/ContentVerifierProvider.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/ContentVerifierProvider.java new file mode 100644 index 00000000..5ab15417 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/ContentVerifierProvider.java @@ -0,0 +1,35 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator; + +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.cert.X509CertificateHolder; + +/** + * General interface for providers of ContentVerifier objects. + */ +public interface ContentVerifierProvider +{ + /** + * Return whether or not this verifier has a certificate associated with it. + * + * @return true if there is an associated certificate, false otherwise. + */ + boolean hasAssociatedCertificate(); + + /** + * Return the associated certificate if there is one. + * + * @return a holder containing the associated certificate if there is one, null if there is not. + */ + X509CertificateHolder getAssociatedCertificate(); + + /** + * Return a ContentVerifier that matches the passed in algorithm identifier, + * + * @param verifierAlgorithmIdentifier the algorithm and parameters required. + * @return a matching ContentVerifier + * @throws OperatorCreationException if the required ContentVerifier cannot be created. + */ + ContentVerifier get(AlgorithmIdentifier verifierAlgorithmIdentifier) + throws OperatorCreationException; +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java new file mode 100644 index 00000000..62993d7c --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java @@ -0,0 +1,158 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator; + +import java.util.HashMap; +import java.util.Map; + +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.DERNull; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.asn1.bc.BCObjectIdentifiers; +// import org.bouncycastle.asn1.bsi.BSIObjectIdentifiers; +// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import com.android.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import com.android.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import com.android.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.android.org.bouncycastle.asn1.pkcs.RSASSAPSSparams; +import com.android.org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.asn1.x9.X9ObjectIdentifiers; + +public class DefaultDigestAlgorithmIdentifierFinder + implements DigestAlgorithmIdentifierFinder +{ + private static Map digestOids = new HashMap(); + private static Map digestNameToOids = new HashMap(); + + static + { + // + // digests + // + // BEGIN Android-removed: Unsupported algorithms + // digestOids.put(OIWObjectIdentifiers.md4WithRSAEncryption, PKCSObjectIdentifiers.md4); + // digestOids.put(OIWObjectIdentifiers.md4WithRSA, PKCSObjectIdentifiers.md4); + // END Android-removed: Unsupported algorithms + digestOids.put(OIWObjectIdentifiers.sha1WithRSA, OIWObjectIdentifiers.idSHA1); + + digestOids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, NISTObjectIdentifiers.id_sha224); + digestOids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, NISTObjectIdentifiers.id_sha256); + digestOids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, NISTObjectIdentifiers.id_sha384); + digestOids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, NISTObjectIdentifiers.id_sha512); + // BEGIN Android-removed: Unsupported algorithms + // digestOids.put(PKCSObjectIdentifiers.md2WithRSAEncryption, PKCSObjectIdentifiers.md2); + // digestOids.put(PKCSObjectIdentifiers.md4WithRSAEncryption, PKCSObjectIdentifiers.md4); + // END Android-removed: Unsupported algorithms + digestOids.put(PKCSObjectIdentifiers.md5WithRSAEncryption, PKCSObjectIdentifiers.md5); + digestOids.put(PKCSObjectIdentifiers.sha1WithRSAEncryption, OIWObjectIdentifiers.idSHA1); + + digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, OIWObjectIdentifiers.idSHA1); + digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, NISTObjectIdentifiers.id_sha224); + digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, NISTObjectIdentifiers.id_sha256); + digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, NISTObjectIdentifiers.id_sha384); + digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, NISTObjectIdentifiers.id_sha512); + digestOids.put(X9ObjectIdentifiers.id_dsa_with_sha1, OIWObjectIdentifiers.idSHA1); + + // BEGIN Android-removed: Unsupported algorithms + // digestOids.put(BSIObjectIdentifiers.ecdsa_plain_SHA1, OIWObjectIdentifiers.idSHA1); + // digestOids.put(BSIObjectIdentifiers.ecdsa_plain_SHA224, NISTObjectIdentifiers.id_sha224); + // digestOids.put(BSIObjectIdentifiers.ecdsa_plain_SHA256, NISTObjectIdentifiers.id_sha256); + // digestOids.put(BSIObjectIdentifiers.ecdsa_plain_SHA384, NISTObjectIdentifiers.id_sha384); + // digestOids.put(BSIObjectIdentifiers.ecdsa_plain_SHA512, NISTObjectIdentifiers.id_sha512); + // END Android-removed: Unsupported algorithms + + digestOids.put(NISTObjectIdentifiers.dsa_with_sha224, NISTObjectIdentifiers.id_sha224); + digestOids.put(NISTObjectIdentifiers.dsa_with_sha256, NISTObjectIdentifiers.id_sha256); + digestOids.put(NISTObjectIdentifiers.dsa_with_sha384, NISTObjectIdentifiers.id_sha384); + digestOids.put(NISTObjectIdentifiers.dsa_with_sha512, NISTObjectIdentifiers.id_sha512); + + // BEGIN Android-removed: Unsupported algorithms + /* + digestOids.put(NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_224, NISTObjectIdentifiers.id_sha3_224); + digestOids.put(NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_256, NISTObjectIdentifiers.id_sha3_256); + digestOids.put(NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_384, NISTObjectIdentifiers.id_sha3_384); + digestOids.put(NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_512, NISTObjectIdentifiers.id_sha3_512); + digestOids.put(NISTObjectIdentifiers.id_dsa_with_sha3_224, NISTObjectIdentifiers.id_sha3_224); + digestOids.put(NISTObjectIdentifiers.id_dsa_with_sha3_256, NISTObjectIdentifiers.id_sha3_256); + digestOids.put(NISTObjectIdentifiers.id_dsa_with_sha3_384, NISTObjectIdentifiers.id_sha3_384); + digestOids.put(NISTObjectIdentifiers.id_dsa_with_sha3_512, NISTObjectIdentifiers.id_sha3_512); + digestOids.put(NISTObjectIdentifiers.id_ecdsa_with_sha3_224, NISTObjectIdentifiers.id_sha3_224); + digestOids.put(NISTObjectIdentifiers.id_ecdsa_with_sha3_256, NISTObjectIdentifiers.id_sha3_256); + digestOids.put(NISTObjectIdentifiers.id_ecdsa_with_sha3_384, NISTObjectIdentifiers.id_sha3_384); + digestOids.put(NISTObjectIdentifiers.id_ecdsa_with_sha3_512, NISTObjectIdentifiers.id_sha3_512); + + digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128, TeleTrusTObjectIdentifiers.ripemd128); + digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160, TeleTrusTObjectIdentifiers.ripemd160); + digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256, TeleTrusTObjectIdentifiers.ripemd256); + + digestOids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, CryptoProObjectIdentifiers.gostR3411); + digestOids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, CryptoProObjectIdentifiers.gostR3411); + + digestOids.put(BCObjectIdentifiers.sphincs256_with_SHA3_512, NISTObjectIdentifiers.id_sha3_512); + digestOids.put(BCObjectIdentifiers.sphincs256_with_SHA512, NISTObjectIdentifiers.id_sha512); + */ + // END Android-removed: Unsupported algorithms + + + digestNameToOids.put("SHA-1", OIWObjectIdentifiers.idSHA1); + digestNameToOids.put("SHA-224", NISTObjectIdentifiers.id_sha224); + digestNameToOids.put("SHA-256", NISTObjectIdentifiers.id_sha256); + digestNameToOids.put("SHA-384", NISTObjectIdentifiers.id_sha384); + digestNameToOids.put("SHA-512", NISTObjectIdentifiers.id_sha512); + // BEGIN Android-removed: Unsupported algorithms + /* + digestNameToOids.put("SHA-512-224", NISTObjectIdentifiers.id_sha512_224); + digestNameToOids.put("SHA-512-256", NISTObjectIdentifiers.id_sha512_256); + + digestNameToOids.put("SHA1", OIWObjectIdentifiers.idSHA1); + digestNameToOids.put("SHA224", NISTObjectIdentifiers.id_sha224); + digestNameToOids.put("SHA256", NISTObjectIdentifiers.id_sha256); + digestNameToOids.put("SHA384", NISTObjectIdentifiers.id_sha384); + digestNameToOids.put("SHA512", NISTObjectIdentifiers.id_sha512); + digestNameToOids.put("SHA512-224", NISTObjectIdentifiers.id_sha512_224); + digestNameToOids.put("SHA512-256", NISTObjectIdentifiers.id_sha512_256); + + digestNameToOids.put("SHA3-224", NISTObjectIdentifiers.id_sha3_224); + digestNameToOids.put("SHA3-256", NISTObjectIdentifiers.id_sha3_256); + digestNameToOids.put("SHA3-384", NISTObjectIdentifiers.id_sha3_384); + digestNameToOids.put("SHA3-512", NISTObjectIdentifiers.id_sha3_512); + + digestNameToOids.put("SHAKE-128", NISTObjectIdentifiers.id_shake128); + digestNameToOids.put("SHAKE-256", NISTObjectIdentifiers.id_shake256); + + digestNameToOids.put("GOST3411", CryptoProObjectIdentifiers.gostR3411); + + digestNameToOids.put("MD2", PKCSObjectIdentifiers.md2); + digestNameToOids.put("MD4", PKCSObjectIdentifiers.md4); + */ + // END Android-removed: Unsupported algorithms + digestNameToOids.put("MD5", PKCSObjectIdentifiers.md5); + + // BEGIN Android-removed: Unsupported algorithms + // digestNameToOids.put("RIPEMD128", TeleTrusTObjectIdentifiers.ripemd128); + // digestNameToOids.put("RIPEMD160", TeleTrusTObjectIdentifiers.ripemd160); + // digestNameToOids.put("RIPEMD256", TeleTrusTObjectIdentifiers.ripemd256); + // END Android-removed: Unsupported algorithms + } + + public AlgorithmIdentifier find(AlgorithmIdentifier sigAlgId) + { + AlgorithmIdentifier digAlgId; + + if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS)) + { + digAlgId = RSASSAPSSparams.getInstance(sigAlgId.getParameters()).getHashAlgorithm(); + } + else + { + digAlgId = new AlgorithmIdentifier((ASN1ObjectIdentifier)digestOids.get(sigAlgId.getAlgorithm()), DERNull.INSTANCE); + } + + return digAlgId; + } + + public AlgorithmIdentifier find(String digAlgName) + { + return new AlgorithmIdentifier((ASN1ObjectIdentifier)digestNameToOids.get(digAlgName), DERNull.INSTANCE); + } +}
\ No newline at end of file diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java new file mode 100644 index 00000000..04676238 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java @@ -0,0 +1,264 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import com.android.org.bouncycastle.asn1.ASN1Encodable; +import com.android.org.bouncycastle.asn1.ASN1Integer; +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.DERNull; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.asn1.bc.BCObjectIdentifiers; +// import org.bouncycastle.asn1.bsi.BSIObjectIdentifiers; +// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +// import org.bouncycastle.asn1.eac.EACObjectIdentifiers; +// import org.bouncycastle.asn1.gm.GMObjectIdentifiers; +import com.android.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import com.android.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import com.android.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.android.org.bouncycastle.asn1.pkcs.RSASSAPSSparams; +import com.android.org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +import com.android.org.bouncycastle.util.Strings; + +public class DefaultSignatureAlgorithmIdentifierFinder + implements SignatureAlgorithmIdentifierFinder +{ + private static Map algorithms = new HashMap(); + private static Set noParams = new HashSet(); + private static Map params = new HashMap(); + private static Set pkcs15RsaEncryption = new HashSet(); + private static Map digestOids = new HashMap(); + + private static final ASN1ObjectIdentifier ENCRYPTION_RSA = PKCSObjectIdentifiers.rsaEncryption; + private static final ASN1ObjectIdentifier ENCRYPTION_DSA = X9ObjectIdentifiers.id_dsa_with_sha1; + private static final ASN1ObjectIdentifier ENCRYPTION_ECDSA = X9ObjectIdentifiers.ecdsa_with_SHA1; + private static final ASN1ObjectIdentifier ENCRYPTION_RSA_PSS = PKCSObjectIdentifiers.id_RSASSA_PSS; + // BEGIN Android-removed: Unsupported algorithms + // private static final ASN1ObjectIdentifier ENCRYPTION_GOST3410 = CryptoProObjectIdentifiers.gostR3410_94; + // private static final ASN1ObjectIdentifier ENCRYPTION_ECGOST3410 = CryptoProObjectIdentifiers.gostR3410_2001; + // END Android-removed: Unsupported algorithms + + static + { + // BEGIN Android-removed: Unsupported algorithms + // algorithms.put("MD2WITHRSAENCRYPTION", PKCSObjectIdentifiers.md2WithRSAEncryption); + // algorithms.put("MD2WITHRSA", PKCSObjectIdentifiers.md2WithRSAEncryption); + // END Android-removed: Unsupported algorithms + algorithms.put("MD5WITHRSAENCRYPTION", PKCSObjectIdentifiers.md5WithRSAEncryption); + algorithms.put("MD5WITHRSA", PKCSObjectIdentifiers.md5WithRSAEncryption); + algorithms.put("SHA1WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha1WithRSAEncryption); + algorithms.put("SHA1WITHRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption); + 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); + // BEGIN Android-removed: Unsupported algorithms + // algorithms.put("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160); + // algorithms.put("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160); + // algorithms.put("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128); + // algorithms.put("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128); + // algorithms.put("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256); + // algorithms.put("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256); + // END Android-removed: Unsupported algorithms + algorithms.put("SHA1WITHDSA", X9ObjectIdentifiers.id_dsa_with_sha1); + algorithms.put("DSAWITHSHA1", X9ObjectIdentifiers.id_dsa_with_sha1); + 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("ECDSAWITHSHA1", 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); + + // BEGIN Android-removed: Unsupported algorithms + /* + algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94); + algorithms.put("GOST3411WITHGOST3410-94", 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); + algorithms.put("SHA1WITHPLAIN-ECDSA", BSIObjectIdentifiers.ecdsa_plain_SHA1); + algorithms.put("SHA224WITHPLAIN-ECDSA", BSIObjectIdentifiers.ecdsa_plain_SHA224); + algorithms.put("SHA256WITHPLAIN-ECDSA", BSIObjectIdentifiers.ecdsa_plain_SHA256); + algorithms.put("SHA384WITHPLAIN-ECDSA", BSIObjectIdentifiers.ecdsa_plain_SHA384); + algorithms.put("SHA512WITHPLAIN-ECDSA", BSIObjectIdentifiers.ecdsa_plain_SHA512); + algorithms.put("RIPEMD160WITHPLAIN-ECDSA", BSIObjectIdentifiers.ecdsa_plain_RIPEMD160); + algorithms.put("SHA1WITHCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1); + algorithms.put("SHA224WITHCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_224); + algorithms.put("SHA256WITHCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_256); + algorithms.put("SHA384WITHCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_384); + algorithms.put("SHA512WITHCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_512); + algorithms.put("SHA3-512WITHSPHINCS256", BCObjectIdentifiers.sphincs256_with_SHA3_512); + algorithms.put("SHA512WITHSPHINCS256", BCObjectIdentifiers.sphincs256_with_SHA512); + algorithms.put("SM3WITHSM2", GMObjectIdentifiers.sm2sign_with_sm3); + */ + // END Android-removed: Unsupported algorithms + + // + // 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); + noParams.add(NISTObjectIdentifiers.dsa_with_sha384); + noParams.add(NISTObjectIdentifiers.dsa_with_sha512); + + // BEGIN Android-removed: Unsupported algorithms + /* + // + // RFC 4491 + // + noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94); + noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001); + + // + // SPHINCS-256 + // + noParams.add(BCObjectIdentifiers.sphincs256_with_SHA512); + noParams.add(BCObjectIdentifiers.sphincs256_with_SHA3_512); + + // + // SM2 + // + noParams.add(GMObjectIdentifiers.sm2sign_with_sm3); + */ + // END Android-removed: Unsupported algorithms + + // + // PKCS 1.5 encrypted algorithms + // + pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha1WithRSAEncryption); + pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha224WithRSAEncryption); + pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha256WithRSAEncryption); + pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha384WithRSAEncryption); + pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha512WithRSAEncryption); + // BEGIN Android-removed: Unsupported algorithms + // pkcs15RsaEncryption.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128); + // pkcs15RsaEncryption.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160); + // pkcs15RsaEncryption.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256); + // END Android-removed: Unsupported algorithms + + // + // explicit params + // + AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE); + params.put("SHA1WITHRSAANDMGF1", createPSSParams(sha1AlgId, 20)); + + AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE); + params.put("SHA224WITHRSAANDMGF1", createPSSParams(sha224AlgId, 28)); + + AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE); + params.put("SHA256WITHRSAANDMGF1", createPSSParams(sha256AlgId, 32)); + + AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, DERNull.INSTANCE); + params.put("SHA384WITHRSAANDMGF1", createPSSParams(sha384AlgId, 48)); + + AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512, DERNull.INSTANCE); + params.put("SHA512WITHRSAANDMGF1", createPSSParams(sha512AlgId, 64)); + + // + // digests + // + digestOids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, NISTObjectIdentifiers.id_sha224); + digestOids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, NISTObjectIdentifiers.id_sha256); + digestOids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, NISTObjectIdentifiers.id_sha384); + digestOids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, NISTObjectIdentifiers.id_sha512); + // BEGIN Android-removed: Unsupported algorithms + // digestOids.put(PKCSObjectIdentifiers.md2WithRSAEncryption, PKCSObjectIdentifiers.md2); + // digestOids.put(PKCSObjectIdentifiers.md4WithRSAEncryption, PKCSObjectIdentifiers.md4); + // END Android-removed: Unsupported algorithms + digestOids.put(PKCSObjectIdentifiers.md5WithRSAEncryption, PKCSObjectIdentifiers.md5); + digestOids.put(PKCSObjectIdentifiers.sha1WithRSAEncryption, OIWObjectIdentifiers.idSHA1); + // BEGIN Android-removed: Unsupported algorithms + // digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128, TeleTrusTObjectIdentifiers.ripemd128); + // digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160, TeleTrusTObjectIdentifiers.ripemd160); + // digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256, TeleTrusTObjectIdentifiers.ripemd256); + // digestOids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, CryptoProObjectIdentifiers.gostR3411); + // digestOids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, CryptoProObjectIdentifiers.gostR3411); + // END Android-removed: Unsupported algorithms + } + + private static AlgorithmIdentifier generate(String signatureAlgorithm) + { + AlgorithmIdentifier sigAlgId; + AlgorithmIdentifier encAlgId; + AlgorithmIdentifier digAlgId; + + String algorithmName = Strings.toUpperCase(signatureAlgorithm); + ASN1ObjectIdentifier sigOID = (ASN1ObjectIdentifier)algorithms.get(algorithmName); + if (sigOID == null) + { + throw new IllegalArgumentException("Unknown signature type requested: " + algorithmName); + } + + if (noParams.contains(sigOID)) + { + sigAlgId = new AlgorithmIdentifier(sigOID); + } + else if (params.containsKey(algorithmName)) + { + sigAlgId = new AlgorithmIdentifier(sigOID, (ASN1Encodable)params.get(algorithmName)); + } + else + { + sigAlgId = new AlgorithmIdentifier(sigOID, DERNull.INSTANCE); + } + + if (pkcs15RsaEncryption.contains(sigOID)) + { + encAlgId = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE); + } + else + { + encAlgId = sigAlgId; + } + + if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS)) + { + digAlgId = ((RSASSAPSSparams)sigAlgId.getParameters()).getHashAlgorithm(); + } + else + { + digAlgId = new AlgorithmIdentifier((ASN1ObjectIdentifier)digestOids.get(sigOID), DERNull.INSTANCE); + } + + return sigAlgId; + } + + private static RSASSAPSSparams createPSSParams(AlgorithmIdentifier hashAlgId, int saltSize) + { + return new RSASSAPSSparams( + hashAlgId, + new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId), + new ASN1Integer(saltSize), + new ASN1Integer(1)); + } + + public AlgorithmIdentifier find(String sigAlgName) + { + return generate(sigAlgName); + } +}
\ No newline at end of file diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/DigestAlgorithmIdentifierFinder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/DigestAlgorithmIdentifierFinder.java new file mode 100644 index 00000000..fefa30a8 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/DigestAlgorithmIdentifierFinder.java @@ -0,0 +1,25 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator; + +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public interface DigestAlgorithmIdentifierFinder +{ + /** + * Find the digest algorithm identifier that matches with + * the passed in signature algorithm identifier. + * + * @param sigAlgId the signature algorithm of interest. + * @return an algorithm identifier for the corresponding digest. + */ + AlgorithmIdentifier find(AlgorithmIdentifier sigAlgId); + + /** + * Find the algorithm identifier that matches with + * the passed in digest name. + * + * @param digAlgName the name of the digest algorithm of interest. + * @return an algorithm identifier for the digest signature. + */ + AlgorithmIdentifier find(String digAlgName); +}
\ No newline at end of file diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/DigestCalculator.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/DigestCalculator.java new file mode 100644 index 00000000..1a9d12be --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/DigestCalculator.java @@ -0,0 +1,37 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator; + +import java.io.OutputStream; + +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * General interface for an operator that is able to calculate a digest from + * a stream of output. + */ +public interface DigestCalculator +{ + /** + * Return the algorithm identifier representing the digest implemented by + * this calculator. + * + * @return algorithm id and parameters. + */ + AlgorithmIdentifier getAlgorithmIdentifier(); + + /** + * Returns a stream that will accept data for the purpose of calculating + * a digest. Use org.bouncycastle.util.io.TeeOutputStream if you want to accumulate + * the data on the fly as well. + * + * @return an OutputStream + */ + OutputStream getOutputStream(); + + /** + * Return the digest calculated on what has been written to the calculator's output stream. + * + * @return a digest. + */ + byte[] getDigest(); +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/DigestCalculatorProvider.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/DigestCalculatorProvider.java new file mode 100644 index 00000000..6c74f1b0 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/DigestCalculatorProvider.java @@ -0,0 +1,10 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator; + +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public interface DigestCalculatorProvider +{ + DigestCalculator get(AlgorithmIdentifier digestAlgorithmIdentifier) + throws OperatorCreationException; +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/GenericKey.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/GenericKey.java new file mode 100644 index 00000000..f4e2850d --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/GenericKey.java @@ -0,0 +1,42 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator; + +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class GenericKey +{ + private AlgorithmIdentifier algorithmIdentifier; + private Object representation; + + /** + * @deprecated provide an AlgorithmIdentifier. + * @param representation key data + */ + public GenericKey(Object representation) + { + this.algorithmIdentifier = null; + this.representation = representation; + } + + public GenericKey(AlgorithmIdentifier algorithmIdentifier, byte[] representation) + { + this.algorithmIdentifier = algorithmIdentifier; + this.representation = representation; + } + + protected GenericKey(AlgorithmIdentifier algorithmIdentifier, Object representation) + { + this.algorithmIdentifier = algorithmIdentifier; + this.representation = representation; + } + + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return algorithmIdentifier; + } + + public Object getRepresentation() + { + return representation; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/InputDecryptor.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/InputDecryptor.java new file mode 100644 index 00000000..47df91f3 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/InputDecryptor.java @@ -0,0 +1,30 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator; + +import java.io.InputStream; + +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * General interface for an operator that is able to produce + * an InputStream that will decrypt a stream of encrypted data. + */ +public interface InputDecryptor +{ + /** + * Return the algorithm identifier describing the encryption + * algorithm and parameters this decryptor can process. + * + * @return algorithm oid and parameters. + */ + AlgorithmIdentifier getAlgorithmIdentifier(); + + /** + * Wrap the passed in input stream encIn, returning an input stream + * that decrypts what it reads from encIn before returning it. + * + * @param encIn InputStream containing encrypted input. + * @return an decrypting InputStream + */ + InputStream getInputStream(InputStream encIn); +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/MacCalculator.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/MacCalculator.java new file mode 100644 index 00000000..8c1399f7 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/MacCalculator.java @@ -0,0 +1,35 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator; + +import java.io.OutputStream; + +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public interface MacCalculator +{ + AlgorithmIdentifier getAlgorithmIdentifier(); + + /** + * Returns a stream that will accept data for the purpose of calculating + * the MAC for later verification. Use org.bouncycastle.util.io.TeeOutputStream if you want to accumulate + * the data on the fly as well. + * + * @return an OutputStream + */ + OutputStream getOutputStream(); + + /** + * Return the calculated MAC based on what has been written to the stream. + * + * @return calculated MAC. + */ + byte[] getMac(); + + + /** + * Return the key used for calculating the MAC. + * + * @return the MAC key. + */ + GenericKey getKey(); +}
\ No newline at end of file diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/OperatorCreationException.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/OperatorCreationException.java new file mode 100644 index 00000000..398098b4 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/OperatorCreationException.java @@ -0,0 +1,16 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator; + +public class OperatorCreationException + extends OperatorException +{ + public OperatorCreationException(String msg, Throwable cause) + { + super(msg, cause); + } + + public OperatorCreationException(String msg) + { + super(msg); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/OperatorException.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/OperatorException.java new file mode 100644 index 00000000..5d5d96f6 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/OperatorException.java @@ -0,0 +1,25 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator; + +public class OperatorException + extends Exception +{ + private Throwable cause; + + public OperatorException(String msg, Throwable cause) + { + super(msg); + + this.cause = cause; + } + + public OperatorException(String msg) + { + super(msg); + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/OperatorStreamException.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/OperatorStreamException.java new file mode 100644 index 00000000..923db04a --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/OperatorStreamException.java @@ -0,0 +1,22 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator; + +import java.io.IOException; + +public class OperatorStreamException + extends IOException +{ + private Throwable cause; + + public OperatorStreamException(String msg, Throwable cause) + { + super(msg); + + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/RawContentVerifier.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/RawContentVerifier.java new file mode 100644 index 00000000..5933f104 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/RawContentVerifier.java @@ -0,0 +1,18 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator; + +/** + * Interface for ContentVerifiers that also support raw signatures that can be + * verified using the digest of the calculated data. + */ +public interface RawContentVerifier +{ + /** + * Verify that the expected signature value was derived from the passed in digest. + * + * @param digest digest calculated from the content. + * @param expected expected value of the signature + * @return true if the expected signature is derived from the digest, false otherwise. + */ + boolean verify(byte[] digest, byte[] expected); +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/RuntimeOperatorException.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/RuntimeOperatorException.java new file mode 100644 index 00000000..30367263 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/RuntimeOperatorException.java @@ -0,0 +1,25 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator; + +public class RuntimeOperatorException + extends RuntimeException +{ + private Throwable cause; + + public RuntimeOperatorException(String msg) + { + super(msg); + } + + public RuntimeOperatorException(String msg, Throwable cause) + { + super(msg); + + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/SignatureAlgorithmIdentifierFinder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/SignatureAlgorithmIdentifierFinder.java new file mode 100644 index 00000000..135dfd72 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/SignatureAlgorithmIdentifierFinder.java @@ -0,0 +1,16 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator; + +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public interface SignatureAlgorithmIdentifierFinder +{ + /** + * Find the signature algorithm identifier that matches with + * the passed in signature algorithm name. + * + * @param sigAlgName the name of the signature algorithm of interest. + * @return an algorithm identifier for the corresponding signature. + */ + AlgorithmIdentifier find(String sigAlgName); +}
\ No newline at end of file diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java new file mode 100644 index 00000000..29469ab0 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java @@ -0,0 +1,182 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator.bc; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +// Android-removed: Unsupported algorithms +// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import com.android.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import com.android.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import com.android.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.android.org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.crypto.ExtendedDigest; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.crypto.digests.GOST3411Digest; +// import org.bouncycastle.crypto.digests.MD2Digest; +// import org.bouncycastle.crypto.digests.MD4Digest; +import com.android.org.bouncycastle.crypto.digests.MD5Digest; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.crypto.digests.RIPEMD128Digest; +// import org.bouncycastle.crypto.digests.RIPEMD160Digest; +// import org.bouncycastle.crypto.digests.RIPEMD256Digest; +import com.android.org.bouncycastle.crypto.digests.SHA1Digest; +import com.android.org.bouncycastle.crypto.digests.SHA224Digest; +import com.android.org.bouncycastle.crypto.digests.SHA256Digest; +import com.android.org.bouncycastle.crypto.digests.SHA384Digest; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.crypto.digests.SHA3Digest; +import com.android.org.bouncycastle.crypto.digests.SHA512Digest; +import com.android.org.bouncycastle.operator.OperatorCreationException; + +public class BcDefaultDigestProvider + implements BcDigestProvider +{ + private static final Map lookup = createTable(); + + private static Map createTable() + { + Map table = new HashMap(); + + table.put(OIWObjectIdentifiers.idSHA1, new BcDigestProvider() + { + public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + { + return new SHA1Digest(); + } + }); + table.put(NISTObjectIdentifiers.id_sha224, new BcDigestProvider() + { + public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + { + return new SHA224Digest(); + } + }); + table.put(NISTObjectIdentifiers.id_sha256, new BcDigestProvider() + { + public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + { + return new SHA256Digest(); + } + }); + table.put(NISTObjectIdentifiers.id_sha384, new BcDigestProvider() + { + public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + { + return new SHA384Digest(); + } + }); + table.put(NISTObjectIdentifiers.id_sha512, new BcDigestProvider() + { + public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + { + return new SHA512Digest(); + } + }); + // BEGIN Android-removed: Unsupported algorithms + /* + table.put(NISTObjectIdentifiers.id_sha3_224, new BcDigestProvider() + { + public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + { + return new SHA3Digest(224); + } + }); + table.put(NISTObjectIdentifiers.id_sha3_256, new BcDigestProvider() + { + public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + { + return new SHA3Digest(256); + } + }); + table.put(NISTObjectIdentifiers.id_sha3_384, new BcDigestProvider() + { + public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + { + return new SHA3Digest(384); + } + }); + table.put(NISTObjectIdentifiers.id_sha3_512, new BcDigestProvider() + { + public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + { + return new SHA3Digest(512); + } + }); + table.put(PKCSObjectIdentifiers.md5, new BcDigestProvider() + { + public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + { + return new MD5Digest(); + } + }); + table.put(PKCSObjectIdentifiers.md4, new BcDigestProvider() + { + public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + { + return new MD4Digest(); + } + }); + table.put(PKCSObjectIdentifiers.md2, new BcDigestProvider() + { + public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + { + return new MD2Digest(); + } + }); + table.put(CryptoProObjectIdentifiers.gostR3411, new BcDigestProvider() + { + public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + { + return new GOST3411Digest(); + } + }); + table.put(TeleTrusTObjectIdentifiers.ripemd128, new BcDigestProvider() + { + public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + { + return new RIPEMD128Digest(); + } + }); + table.put(TeleTrusTObjectIdentifiers.ripemd160, new BcDigestProvider() + { + public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + { + return new RIPEMD160Digest(); + } + }); + table.put(TeleTrusTObjectIdentifiers.ripemd256, new BcDigestProvider() + { + public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + { + return new RIPEMD256Digest(); + } + }); + */ + // END Android-removed: Unsupported algorithms + + return Collections.unmodifiableMap(table); + } + + public static final BcDigestProvider INSTANCE = new BcDefaultDigestProvider(); + + private BcDefaultDigestProvider() + { + + } + + public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + throws OperatorCreationException + { + BcDigestProvider extProv = (BcDigestProvider)lookup.get(digestAlgorithmIdentifier.getAlgorithm()); + + if (extProv == null) + { + throw new OperatorCreationException("cannot recognise digest"); + } + + return extProv.get(digestAlgorithmIdentifier); + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/bc/BcDigestCalculatorProvider.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/bc/BcDigestCalculatorProvider.java new file mode 100644 index 00000000..0d9c50c2 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/bc/BcDigestCalculatorProvider.java @@ -0,0 +1,83 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator.bc; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Map; + +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.crypto.Digest; +import com.android.org.bouncycastle.crypto.ExtendedDigest; +import com.android.org.bouncycastle.operator.DigestCalculator; +import com.android.org.bouncycastle.operator.DigestCalculatorProvider; +import com.android.org.bouncycastle.operator.OperatorCreationException; + +public class BcDigestCalculatorProvider + implements DigestCalculatorProvider +{ + private BcDigestProvider digestProvider = BcDefaultDigestProvider.INSTANCE; + + public DigestCalculator get(final AlgorithmIdentifier algorithm) + throws OperatorCreationException + { + Digest dig = digestProvider.get(algorithm); + + final DigestOutputStream stream = new DigestOutputStream(dig); + + return new DigestCalculator() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return algorithm; + } + + public OutputStream getOutputStream() + { + return stream; + } + + public byte[] getDigest() + { + return stream.getDigest(); + } + }; + } + + private class DigestOutputStream + extends OutputStream + { + private Digest dig; + + DigestOutputStream(Digest dig) + { + this.dig = dig; + } + + public void write(byte[] bytes, int off, int len) + throws IOException + { + dig.update(bytes, off, len); + } + + public void write(byte[] bytes) + throws IOException + { + dig.update(bytes, 0, bytes.length); + } + + public void write(int b) + throws IOException + { + dig.update((byte)b); + } + + byte[] getDigest() + { + byte[] d = new byte[dig.getDigestSize()]; + + dig.doFinal(d, 0); + + return d; + } + } +}
\ No newline at end of file diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/bc/BcDigestProvider.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/bc/BcDigestProvider.java new file mode 100644 index 00000000..3b9be0bf --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/bc/BcDigestProvider.java @@ -0,0 +1,12 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator.bc; + +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.crypto.ExtendedDigest; +import com.android.org.bouncycastle.operator.OperatorCreationException; + +public interface BcDigestProvider +{ + ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + throws OperatorCreationException; +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java new file mode 100644 index 00000000..24b5e8cb --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java @@ -0,0 +1,162 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator.jcajce; + +import java.io.IOException; +import java.io.OutputStream; +import java.security.GeneralSecurityException; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.Signature; +import java.security.SignatureException; + +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.jcajce.util.DefaultJcaJceHelper; +import com.android.org.bouncycastle.jcajce.util.NamedJcaJceHelper; +import com.android.org.bouncycastle.jcajce.util.ProviderJcaJceHelper; +import com.android.org.bouncycastle.operator.ContentSigner; +import com.android.org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; +import com.android.org.bouncycastle.operator.OperatorCreationException; +import com.android.org.bouncycastle.operator.OperatorStreamException; +import com.android.org.bouncycastle.operator.RuntimeOperatorException; + +public class JcaContentSignerBuilder +{ + private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper()); + private SecureRandom random; + private String signatureAlgorithm; + private AlgorithmIdentifier sigAlgId; + + public JcaContentSignerBuilder(String signatureAlgorithm) + { + this.signatureAlgorithm = signatureAlgorithm; + this.sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find(signatureAlgorithm); + } + + public JcaContentSignerBuilder setProvider(Provider provider) + { + this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider)); + + return this; + } + + public JcaContentSignerBuilder setProvider(String providerName) + { + this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName)); + + return this; + } + + public JcaContentSignerBuilder setSecureRandom(SecureRandom random) + { + this.random = random; + + return this; + } + + public ContentSigner build(PrivateKey privateKey) + throws OperatorCreationException + { + try + { + final Signature sig = helper.createSignature(sigAlgId); + final AlgorithmIdentifier signatureAlgId = sigAlgId; + + if (random != null) + { + sig.initSign(privateKey, random); + } + else + { + sig.initSign(privateKey); + } + + return new ContentSigner() + { + private SignatureOutputStream stream = new SignatureOutputStream(sig); + + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return signatureAlgId; + } + + public OutputStream getOutputStream() + { + return stream; + } + + public byte[] getSignature() + { + try + { + return stream.getSignature(); + } + catch (SignatureException e) + { + throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e); + } + } + }; + } + catch (GeneralSecurityException e) + { + throw new OperatorCreationException("cannot create signer: " + e.getMessage(), e); + } + } + + private class SignatureOutputStream + extends OutputStream + { + private Signature sig; + + SignatureOutputStream(Signature sig) + { + this.sig = sig; + } + + public void write(byte[] bytes, int off, int len) + throws IOException + { + try + { + sig.update(bytes, off, len); + } + catch (SignatureException e) + { + throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e); + } + } + + public void write(byte[] bytes) + throws IOException + { + try + { + sig.update(bytes); + } + catch (SignatureException e) + { + throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e); + } + } + + public void write(int b) + throws IOException + { + try + { + sig.update((byte)b); + } + catch (SignatureException e) + { + throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e); + } + } + + byte[] getSignature() + throws SignatureException + { + return sig.sign(); + } + } +} diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java new file mode 100644 index 00000000..00772083 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java @@ -0,0 +1,348 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator.jcajce; + +import java.io.IOException; +import java.io.OutputStream; +import java.security.GeneralSecurityException; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.android.org.bouncycastle.cert.X509CertificateHolder; +import com.android.org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; +import com.android.org.bouncycastle.jcajce.util.DefaultJcaJceHelper; +import com.android.org.bouncycastle.jcajce.util.NamedJcaJceHelper; +import com.android.org.bouncycastle.jcajce.util.ProviderJcaJceHelper; +import com.android.org.bouncycastle.operator.ContentVerifier; +import com.android.org.bouncycastle.operator.ContentVerifierProvider; +import com.android.org.bouncycastle.operator.OperatorCreationException; +import com.android.org.bouncycastle.operator.OperatorStreamException; +import com.android.org.bouncycastle.operator.RawContentVerifier; +import com.android.org.bouncycastle.operator.RuntimeOperatorException; + +public class JcaContentVerifierProviderBuilder +{ + private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper()); + + public JcaContentVerifierProviderBuilder() + { + } + + public JcaContentVerifierProviderBuilder setProvider(Provider provider) + { + this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider)); + + return this; + } + + public JcaContentVerifierProviderBuilder setProvider(String providerName) + { + this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName)); + + return this; + } + + public ContentVerifierProvider build(X509CertificateHolder certHolder) + throws OperatorCreationException, CertificateException + { + return build(helper.convertCertificate(certHolder)); + } + + public ContentVerifierProvider build(final X509Certificate certificate) + throws OperatorCreationException + { + final X509CertificateHolder certHolder; + + try + { + certHolder = new JcaX509CertificateHolder(certificate); + } + catch (CertificateEncodingException e) + { + throw new OperatorCreationException("cannot process certificate: " + e.getMessage(), e); + } + + return new ContentVerifierProvider() + { + private SignatureOutputStream stream; + + public boolean hasAssociatedCertificate() + { + return true; + } + + public X509CertificateHolder getAssociatedCertificate() + { + return certHolder; + } + + public ContentVerifier get(AlgorithmIdentifier algorithm) + throws OperatorCreationException + { + try + { + Signature sig = helper.createSignature(algorithm); + + sig.initVerify(certificate.getPublicKey()); + + stream = new SignatureOutputStream(sig); + } + catch (GeneralSecurityException e) + { + throw new OperatorCreationException("exception on setup: " + e, e); + } + + Signature rawSig = createRawSig(algorithm, certificate.getPublicKey()); + + if (rawSig != null) + { + return new RawSigVerifier(algorithm, stream, rawSig); + } + else + { + return new SigVerifier(algorithm, stream); + } + } + }; + } + + public ContentVerifierProvider build(final PublicKey publicKey) + throws OperatorCreationException + { + return new ContentVerifierProvider() + { + public boolean hasAssociatedCertificate() + { + return false; + } + + public X509CertificateHolder getAssociatedCertificate() + { + return null; + } + + public ContentVerifier get(AlgorithmIdentifier algorithm) + throws OperatorCreationException + { + SignatureOutputStream stream = createSignatureStream(algorithm, publicKey); + + Signature rawSig = createRawSig(algorithm, publicKey); + + if (rawSig != null) + { + return new RawSigVerifier(algorithm, stream, rawSig); + } + else + { + return new SigVerifier(algorithm, stream); + } + } + }; + } + + public ContentVerifierProvider build(SubjectPublicKeyInfo publicKey) + throws OperatorCreationException + { + return this.build(helper.convertPublicKey(publicKey)); + } + + private SignatureOutputStream createSignatureStream(AlgorithmIdentifier algorithm, PublicKey publicKey) + throws OperatorCreationException + { + try + { + Signature sig = helper.createSignature(algorithm); + + sig.initVerify(publicKey); + + return new SignatureOutputStream(sig); + } + catch (GeneralSecurityException e) + { + throw new OperatorCreationException("exception on setup: " + e, e); + } + } + + private Signature createRawSig(AlgorithmIdentifier algorithm, PublicKey publicKey) + { + Signature rawSig; + try + { + rawSig = helper.createRawSignature(algorithm); + + if (rawSig != null) + { + rawSig.initVerify(publicKey); + } + } + catch (Exception e) + { + rawSig = null; + } + return rawSig; + } + + private class SigVerifier + implements ContentVerifier + { + private AlgorithmIdentifier algorithm; + + protected SignatureOutputStream stream; + + SigVerifier(AlgorithmIdentifier algorithm, SignatureOutputStream stream) + { + this.algorithm = algorithm; + this.stream = stream; + } + + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return algorithm; + } + + public OutputStream getOutputStream() + { + if (stream == null) + { + throw new IllegalStateException("verifier not initialised"); + } + + return stream; + } + + public boolean verify(byte[] expected) + { + try + { + return stream.verify(expected); + } + catch (SignatureException e) + { + throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e); + } + } + } + + private class RawSigVerifier + extends SigVerifier + implements RawContentVerifier + { + private Signature rawSignature; + + RawSigVerifier(AlgorithmIdentifier algorithm, SignatureOutputStream stream, Signature rawSignature) + { + super(algorithm, stream); + this.rawSignature = rawSignature; + } + + public boolean verify(byte[] expected) + { + try + { + return super.verify(expected); + } + finally + { + // we need to do this as in some PKCS11 implementations the session associated with the init of the + // raw signature will not be freed if verify is not called on it. + try + { + rawSignature.verify(expected); + } + catch (Exception e) + { + // ignore + } + } + } + + public boolean verify(byte[] digest, byte[] expected) + { + try + { + rawSignature.update(digest); + + return rawSignature.verify(expected); + } + catch (SignatureException e) + { + throw new RuntimeOperatorException("exception obtaining raw signature: " + e.getMessage(), e); + } + finally + { + // we need to do this as in some PKCS11 implementations the session associated with the init of the + // standard signature will not be freed if verify is not called on it. + try + { + stream.verify(expected); + } + catch (Exception e) + { + // ignore + } + } + } + } + + private class SignatureOutputStream + extends OutputStream + { + private Signature sig; + + SignatureOutputStream(Signature sig) + { + this.sig = sig; + } + + public void write(byte[] bytes, int off, int len) + throws IOException + { + try + { + sig.update(bytes, off, len); + } + catch (SignatureException e) + { + throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e); + } + } + + public void write(byte[] bytes) + throws IOException + { + try + { + sig.update(bytes); + } + catch (SignatureException e) + { + throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e); + } + } + + public void write(int b) + throws IOException + { + try + { + sig.update((byte)b); + } + catch (SignatureException e) + { + throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e); + } + } + + boolean verify(byte[] expected) + throws SignatureException + { + return sig.verify(expected); + } + } +}
\ No newline at end of file diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/jcajce/JcaDigestCalculatorProviderBuilder.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/jcajce/JcaDigestCalculatorProviderBuilder.java new file mode 100644 index 00000000..6195c012 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/jcajce/JcaDigestCalculatorProviderBuilder.java @@ -0,0 +1,115 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator.jcajce; + +import java.io.IOException; +import java.io.OutputStream; +import java.security.GeneralSecurityException; +import java.security.MessageDigest; +import java.security.Provider; + +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.jcajce.util.DefaultJcaJceHelper; +import com.android.org.bouncycastle.jcajce.util.NamedJcaJceHelper; +import com.android.org.bouncycastle.jcajce.util.ProviderJcaJceHelper; +import com.android.org.bouncycastle.operator.DigestCalculator; +import com.android.org.bouncycastle.operator.DigestCalculatorProvider; +import com.android.org.bouncycastle.operator.OperatorCreationException; + +public class JcaDigestCalculatorProviderBuilder +{ + private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper()); + + public JcaDigestCalculatorProviderBuilder() + { + } + + public JcaDigestCalculatorProviderBuilder setProvider(Provider provider) + { + this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider)); + + return this; + } + + public JcaDigestCalculatorProviderBuilder setProvider(String providerName) + { + this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName)); + + return this; + } + + public DigestCalculatorProvider build() + throws OperatorCreationException + { + return new DigestCalculatorProvider() + { + public DigestCalculator get(final AlgorithmIdentifier algorithm) + throws OperatorCreationException + { + final DigestOutputStream stream; + + try + { + MessageDigest dig = helper.createDigest(algorithm); + + stream = new DigestOutputStream(dig); + } + catch (GeneralSecurityException e) + { + throw new OperatorCreationException("exception on setup: " + e, e); + } + + return new DigestCalculator() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return algorithm; + } + + public OutputStream getOutputStream() + { + return stream; + } + + public byte[] getDigest() + { + return stream.getDigest(); + } + }; + } + }; + } + + private class DigestOutputStream + extends OutputStream + { + private MessageDigest dig; + + DigestOutputStream(MessageDigest dig) + { + this.dig = dig; + } + + public void write(byte[] bytes, int off, int len) + throws IOException + { + dig.update(bytes, off, len); + } + + public void write(byte[] bytes) + throws IOException + { + dig.update(bytes); + } + + public void write(int b) + throws IOException + { + dig.update((byte)b); + } + + byte[] getDigest() + { + return dig.digest(); + } + } +}
\ No newline at end of file diff --git a/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/jcajce/OperatorHelper.java b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/jcajce/OperatorHelper.java new file mode 100644 index 00000000..874a78b9 --- /dev/null +++ b/android_bcpkix/src/main/java/com/android/org/bouncycastle/operator/jcajce/OperatorHelper.java @@ -0,0 +1,520 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.operator.jcajce; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PublicKey; +import java.security.Signature; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PSSParameterSpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.HashMap; +import java.util.Map; + +import javax.crypto.Cipher; + +import com.android.org.bouncycastle.asn1.ASN1Encodable; +import com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.org.bouncycastle.asn1.ASN1Sequence; +import com.android.org.bouncycastle.asn1.DERNull; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.asn1.bsi.BSIObjectIdentifiers; +// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +// import org.bouncycastle.asn1.eac.EACObjectIdentifiers; +import com.android.org.bouncycastle.asn1.kisa.KISAObjectIdentifiers; +import com.android.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import com.android.org.bouncycastle.asn1.ntt.NTTObjectIdentifiers; +import com.android.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import com.android.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.android.org.bouncycastle.asn1.pkcs.RSASSAPSSparams; +import com.android.org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.android.org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +import com.android.org.bouncycastle.cert.X509CertificateHolder; +import com.android.org.bouncycastle.jcajce.util.AlgorithmParametersUtils; +import com.android.org.bouncycastle.jcajce.util.JcaJceHelper; +import com.android.org.bouncycastle.jcajce.util.MessageDigestUtils; +import com.android.org.bouncycastle.operator.OperatorCreationException; +import com.android.org.bouncycastle.util.Integers; + +class OperatorHelper +{ + private static final Map oids = new HashMap(); + private static final Map asymmetricWrapperAlgNames = new HashMap(); + private static final Map symmetricWrapperAlgNames = new HashMap(); + private static final Map symmetricKeyAlgNames = new HashMap(); + private static final Map symmetricWrapperKeySizes = new HashMap(); + + static + { + // + // 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"); + // BEGIN Android-removed: Unsupported algorithms + // oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3411WITHGOST3410"); + // oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "GOST3411WITHECGOST3410"); + // oids.put(BSIObjectIdentifiers.ecdsa_plain_SHA1, "SHA1WITHPLAIN-ECDSA"); + // oids.put(BSIObjectIdentifiers.ecdsa_plain_SHA224, "SHA224WITHPLAIN-ECDSA"); + // oids.put(BSIObjectIdentifiers.ecdsa_plain_SHA256, "SHA256WITHPLAIN-ECDSA"); + // oids.put(BSIObjectIdentifiers.ecdsa_plain_SHA384, "SHA384WITHPLAIN-ECDSA"); + // oids.put(BSIObjectIdentifiers.ecdsa_plain_SHA512, "SHA512WITHPLAIN-ECDSA"); + // oids.put(BSIObjectIdentifiers.ecdsa_plain_RIPEMD160, "RIPEMD160WITHPLAIN-ECDSA"); + // oids.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_1, "SHA1WITHCVC-ECDSA"); + // oids.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224WITHCVC-ECDSA"); + // oids.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_256, "SHA256WITHCVC-ECDSA"); + // oids.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_384, "SHA384WITHCVC-ECDSA"); + // oids.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_512, "SHA512WITHCVC-ECDSA"); + // END Android-removed: Unsupported algorithms + + oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA"); + // BEGIN Android-removed: Unsupported algorithms + // oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA"); + // END Android-removed: Unsupported algorithms + 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"); + + oids.put(OIWObjectIdentifiers.idSHA1, "SHA-1"); + oids.put(NISTObjectIdentifiers.id_sha224, "SHA-224"); + oids.put(NISTObjectIdentifiers.id_sha256, "SHA-256"); + oids.put(NISTObjectIdentifiers.id_sha384, "SHA-384"); + oids.put(NISTObjectIdentifiers.id_sha512, "SHA-512"); + oids.put(TeleTrusTObjectIdentifiers.ripemd128, "RIPEMD128"); + oids.put(TeleTrusTObjectIdentifiers.ripemd160, "RIPEMD160"); + oids.put(TeleTrusTObjectIdentifiers.ripemd256, "RIPEMD256"); + + asymmetricWrapperAlgNames.put(PKCSObjectIdentifiers.rsaEncryption, "RSA/ECB/PKCS1Padding"); + + symmetricWrapperAlgNames.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap, "DESEDEWrap"); + symmetricWrapperAlgNames.put(PKCSObjectIdentifiers.id_alg_CMSRC2wrap, "RC2Wrap"); + symmetricWrapperAlgNames.put(NISTObjectIdentifiers.id_aes128_wrap, "AESWrap"); + symmetricWrapperAlgNames.put(NISTObjectIdentifiers.id_aes192_wrap, "AESWrap"); + symmetricWrapperAlgNames.put(NISTObjectIdentifiers.id_aes256_wrap, "AESWrap"); + symmetricWrapperAlgNames.put(NTTObjectIdentifiers.id_camellia128_wrap, "CamelliaWrap"); + symmetricWrapperAlgNames.put(NTTObjectIdentifiers.id_camellia192_wrap, "CamelliaWrap"); + symmetricWrapperAlgNames.put(NTTObjectIdentifiers.id_camellia256_wrap, "CamelliaWrap"); + symmetricWrapperAlgNames.put(KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap, "SEEDWrap"); + symmetricWrapperAlgNames.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESede"); + + symmetricWrapperKeySizes.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap, Integers.valueOf(192)); + symmetricWrapperKeySizes.put(NISTObjectIdentifiers.id_aes128_wrap, Integers.valueOf(128)); + symmetricWrapperKeySizes.put(NISTObjectIdentifiers.id_aes192_wrap, Integers.valueOf(192)); + symmetricWrapperKeySizes.put(NISTObjectIdentifiers.id_aes256_wrap, Integers.valueOf(256)); + symmetricWrapperKeySizes.put(NTTObjectIdentifiers.id_camellia128_wrap, Integers.valueOf(128)); + symmetricWrapperKeySizes.put(NTTObjectIdentifiers.id_camellia192_wrap, Integers.valueOf(192)); + symmetricWrapperKeySizes.put(NTTObjectIdentifiers.id_camellia256_wrap, Integers.valueOf(256)); + symmetricWrapperKeySizes.put(KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap, Integers.valueOf(128)); + symmetricWrapperKeySizes.put(PKCSObjectIdentifiers.des_EDE3_CBC, Integers.valueOf(192)); + + symmetricKeyAlgNames.put(NISTObjectIdentifiers.aes, "AES"); + symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes128_CBC, "AES"); + symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes192_CBC, "AES"); + symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes256_CBC, "AES"); + symmetricKeyAlgNames.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESede"); + symmetricKeyAlgNames.put(PKCSObjectIdentifiers.RC2_CBC, "RC2"); + } + + private JcaJceHelper helper; + + OperatorHelper(JcaJceHelper helper) + { + this.helper = helper; + } + + String getWrappingAlgorithmName(ASN1ObjectIdentifier algOid) + { + return (String)symmetricWrapperAlgNames.get(algOid); + } + + int getKeySizeInBits(ASN1ObjectIdentifier algOid) + { + return ((Integer)symmetricWrapperKeySizes.get(algOid)).intValue(); + } + + Cipher createAsymmetricWrapper(ASN1ObjectIdentifier algorithm, Map extraAlgNames) + throws OperatorCreationException + { + try + { + String cipherName = null; + + if (!extraAlgNames.isEmpty()) + { + cipherName = (String)extraAlgNames.get(algorithm); + } + + if (cipherName == null) + { + cipherName = (String)asymmetricWrapperAlgNames.get(algorithm); + } + + if (cipherName != null) + { + try + { + // this is reversed as the Sun policy files now allow unlimited strength RSA + return helper.createCipher(cipherName); + } + catch (NoSuchAlgorithmException e) + { + // try alternate for RSA + if (cipherName.equals("RSA/ECB/PKCS1Padding")) + { + try + { + return helper.createCipher("RSA/NONE/PKCS1Padding"); + } + catch (NoSuchAlgorithmException ex) + { + // Ignore + } + } + // Ignore + } + } + + return helper.createCipher(algorithm.getId()); + } + catch (GeneralSecurityException e) + { + throw new OperatorCreationException("cannot create cipher: " + e.getMessage(), e); + } + } + + Cipher createSymmetricWrapper(ASN1ObjectIdentifier algorithm) + throws OperatorCreationException + { + try + { + String cipherName = (String)symmetricWrapperAlgNames.get(algorithm); + + if (cipherName != null) + { + try + { + // this is reversed as the Sun policy files now allow unlimited strength RSA + return helper.createCipher(cipherName); + } + catch (NoSuchAlgorithmException e) + { + // Ignore + } + } + return helper.createCipher(algorithm.getId()); + } + catch (GeneralSecurityException e) + { + throw new OperatorCreationException("cannot create cipher: " + e.getMessage(), e); + } + } + + AlgorithmParameters createAlgorithmParameters(AlgorithmIdentifier cipherAlgId) + throws OperatorCreationException + { + AlgorithmParameters parameters; + + if (cipherAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.rsaEncryption)) + { + return null; + } + + try + { + parameters = helper.createAlgorithmParameters(cipherAlgId.getAlgorithm().getId()); + } + catch (NoSuchAlgorithmException e) + { + return null; // There's a good chance there aren't any! + } + catch (NoSuchProviderException e) + { + throw new OperatorCreationException("cannot create algorithm parameters: " + e.getMessage(), e); + } + + try + { + parameters.init(cipherAlgId.getParameters().toASN1Primitive().getEncoded()); + } + catch (IOException e) + { + throw new OperatorCreationException("cannot initialise algorithm parameters: " + e.getMessage(), e); + } + + return parameters; + } + + MessageDigest createDigest(AlgorithmIdentifier digAlgId) + throws GeneralSecurityException + { + MessageDigest dig; + + try + { + dig = helper.createDigest(MessageDigestUtils.getDigestName(digAlgId.getAlgorithm())); + } + catch (NoSuchAlgorithmException e) + { + // + // try an alternate + // + if (oids.get(digAlgId.getAlgorithm()) != null) + { + String digestAlgorithm = (String)oids.get(digAlgId.getAlgorithm()); + + dig = helper.createDigest(digestAlgorithm); + } + else + { + throw e; + } + } + + return dig; + } + + Signature createSignature(AlgorithmIdentifier sigAlgId) + throws GeneralSecurityException + { + Signature sig; + + try + { + sig = helper.createSignature(getSignatureName(sigAlgId)); + } + catch (NoSuchAlgorithmException e) + { + // + // try an alternate + // + if (oids.get(sigAlgId.getAlgorithm()) != null) + { + String signatureAlgorithm = (String)oids.get(sigAlgId.getAlgorithm()); + + sig = helper.createSignature(signatureAlgorithm); + } + else + { + throw e; + } + } + + if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS)) + { + ASN1Sequence seq = ASN1Sequence.getInstance(sigAlgId.getParameters()); + + if (notDefaultPSSParams(seq)) + { + try + { + AlgorithmParameters algParams = helper.createAlgorithmParameters("PSS"); + + algParams.init(seq.getEncoded()); + + sig.setParameter(algParams.getParameterSpec(PSSParameterSpec.class)); + } + catch (IOException e) + { + throw new GeneralSecurityException("unable to process PSS parameters: " + e.getMessage()); + } + } + } + + return sig; + } + + public Signature createRawSignature(AlgorithmIdentifier algorithm) + { + Signature sig; + + try + { + String algName = getSignatureName(algorithm); + + algName = "NONE" + algName.substring(algName.indexOf("WITH")); + + sig = helper.createSignature(algName); + + // RFC 4056 + // When the id-RSASSA-PSS algorithm identifier is used for a signature, + // the AlgorithmIdentifier parameters field MUST contain RSASSA-PSS-params. + if (algorithm.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS)) + { + AlgorithmParameters params = helper.createAlgorithmParameters(algName); + + AlgorithmParametersUtils.loadParameters(params, algorithm.getParameters()); + + PSSParameterSpec spec = (PSSParameterSpec)params.getParameterSpec(PSSParameterSpec.class); + sig.setParameter(spec); + } + } + catch (Exception e) + { + return null; + } + + return sig; + } + + private static String getSignatureName( + AlgorithmIdentifier sigAlgId) + { + ASN1Encodable params = sigAlgId.getParameters(); + + if (params != null && !DERNull.INSTANCE.equals(params)) + { + if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS)) + { + RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params); + return getDigestName(rsaParams.getHashAlgorithm().getAlgorithm()) + "WITHRSAANDMGF1"; + } + } + + if (oids.containsKey(sigAlgId.getAlgorithm())) + { + return (String)oids.get(sigAlgId.getAlgorithm()); + } + + return sigAlgId.getAlgorithm().getId(); + } + + // we need to remove the - to create a correct signature name + private static String getDigestName(ASN1ObjectIdentifier oid) + { + String name = MessageDigestUtils.getDigestName(oid); + + int dIndex = name.indexOf('-'); + if (dIndex > 0 && !name.startsWith("SHA3")) + { + return name.substring(0, dIndex) + name.substring(dIndex + 1); + } + + return MessageDigestUtils.getDigestName(oid); + } + + public X509Certificate convertCertificate(X509CertificateHolder certHolder) + throws CertificateException + { + try + { + CertificateFactory certFact = helper.createCertificateFactory("X.509"); + + return (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(certHolder.getEncoded())); + } + catch (IOException e) + { + throw new OpCertificateException("cannot get encoded form of certificate: " + e.getMessage(), e); + } + catch (NoSuchProviderException e) + { + throw new OpCertificateException("cannot find factory provider: " + e.getMessage(), e); + } + } + + public PublicKey convertPublicKey(SubjectPublicKeyInfo publicKeyInfo) + throws OperatorCreationException + { + try + { + KeyFactory keyFact = helper.createKeyFactory(publicKeyInfo.getAlgorithm().getAlgorithm().getId()); + + return keyFact.generatePublic(new X509EncodedKeySpec(publicKeyInfo.getEncoded())); + } + catch (IOException e) + { + throw new OperatorCreationException("cannot get encoded form of key: " + e.getMessage(), e); + } + catch (NoSuchAlgorithmException e) + { + throw new OperatorCreationException("cannot create key factory: " + e.getMessage(), e); + } + catch (NoSuchProviderException e) + { + throw new OperatorCreationException("cannot find factory provider: " + e.getMessage(), e); + } + catch (InvalidKeySpecException e) + { + throw new OperatorCreationException("cannot create key factory: " + e.getMessage(), e); + } + } + + // TODO: put somewhere public so cause easily accessed + private static class OpCertificateException + extends CertificateException + { + private Throwable cause; + + public OpCertificateException(String msg, Throwable cause) + { + super(msg); + + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } + } + + String getKeyAlgorithmName(ASN1ObjectIdentifier oid) + { + + String name = (String)symmetricKeyAlgNames.get(oid); + + if (name != null) + { + return name; + } + + return oid.getId(); + } + + // for our purposes default includes varient digest with salt the same size as digest + private boolean notDefaultPSSParams(ASN1Sequence seq) + throws GeneralSecurityException + { + if (seq == null || seq.size() == 0) + { + return false; + } + + RSASSAPSSparams pssParams = RSASSAPSSparams.getInstance(seq); + + if (!pssParams.getMaskGenAlgorithm().getAlgorithm().equals(PKCSObjectIdentifiers.id_mgf1)) + { + return true; + } + + // same digest for sig and MGF1 + if (!pssParams.getHashAlgorithm().equals(AlgorithmIdentifier.getInstance(pssParams.getMaskGenAlgorithm().getParameters()))) + { + return true; + } + + MessageDigest digest = createDigest(pssParams.getHashAlgorithm()); + + return pssParams.getSaltLength().intValue() != digest.getDigestLength(); + } +} |