diff options
Diffstat (limited to 'pkix/src/main/java')
872 files changed, 40584 insertions, 40584 deletions
diff --git a/pkix/src/main/java/org/bouncycastle/cert/AttributeCertificateHolder.java b/pkix/src/main/java/org/bouncycastle/cert/AttributeCertificateHolder.java deleted file mode 100644 index 074d3fc3..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/AttributeCertificateHolder.java +++ /dev/null @@ -1,357 +0,0 @@ -package org.bouncycastle.cert; - -import java.io.OutputStream; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; - -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.asn1.x509.GeneralNames; -import org.bouncycastle.asn1.x509.Holder; -import org.bouncycastle.asn1.x509.IssuerSerial; -import org.bouncycastle.asn1.x509.ObjectDigestInfo; -import org.bouncycastle.operator.DigestCalculator; -import org.bouncycastle.operator.DigestCalculatorProvider; -import org.bouncycastle.util.Arrays; -import 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); - } - - public AttributeCertificateHolder(X500Name issuerName, - BigInteger serialNumber) - { - holder = new Holder(new IssuerSerial( - new GeneralNames(new GeneralName(issuerName)), - new ASN1Integer(serialNumber))); - } - - public AttributeCertificateHolder(X509CertificateHolder cert) - { - holder = new Holder(new IssuerSerial(generateGeneralNames(cert.getIssuer()), - new ASN1Integer(cert.getSerialNumber()))); - } - - 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/pkix/src/main/java/org/bouncycastle/cert/AttributeCertificateIssuer.java b/pkix/src/main/java/org/bouncycastle/cert/AttributeCertificateIssuer.java deleted file mode 100644 index b5084c94..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/AttributeCertificateIssuer.java +++ /dev/null @@ -1,147 +0,0 @@ -package org.bouncycastle.cert; - -import java.util.ArrayList; -import java.util.List; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.AttCertIssuer; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.asn1.x509.GeneralNames; -import org.bouncycastle.asn1.x509.V2Form; -import 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/pkix/src/main/java/org/bouncycastle/cert/CertException.java b/pkix/src/main/java/org/bouncycastle/cert/CertException.java deleted file mode 100644 index eb67a5d9..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/CertException.java +++ /dev/null @@ -1,27 +0,0 @@ -package 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/pkix/src/main/java/org/bouncycastle/cert/CertIOException.java b/pkix/src/main/java/org/bouncycastle/cert/CertIOException.java deleted file mode 100644 index 929d95e8..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/CertIOException.java +++ /dev/null @@ -1,29 +0,0 @@ -package 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/pkix/src/main/java/org/bouncycastle/cert/CertRuntimeException.java b/pkix/src/main/java/org/bouncycastle/cert/CertRuntimeException.java deleted file mode 100644 index 5384148a..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/CertRuntimeException.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.bouncycastle.cert; - -public class CertRuntimeException - extends RuntimeException -{ - private Throwable cause; - - public CertRuntimeException(String msg, Throwable cause) - { - super(msg); - - this.cause = cause; - } - - public Throwable getCause() - { - return cause; - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cert/CertUtils.java b/pkix/src/main/java/org/bouncycastle/cert/CertUtils.java deleted file mode 100644 index 9e2e488d..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/CertUtils.java +++ /dev/null @@ -1,244 +0,0 @@ -package 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 org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1GeneralizedTime; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.DEROutputStream; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.AttributeCertificate; -import org.bouncycastle.asn1.x509.AttributeCertificateInfo; -import org.bouncycastle.asn1.x509.Certificate; -import org.bouncycastle.asn1.x509.CertificateList; -import org.bouncycastle.asn1.x509.Extensions; -import org.bouncycastle.asn1.x509.ExtensionsGenerator; -import org.bouncycastle.asn1.x509.TBSCertList; -import org.bouncycastle.asn1.x509.TBSCertificate; -import 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 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/pkix/src/main/java/org/bouncycastle/cert/X509AttributeCertificateHolder.java b/pkix/src/main/java/org/bouncycastle/cert/X509AttributeCertificateHolder.java deleted file mode 100644 index a34b3b34..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/X509AttributeCertificateHolder.java +++ /dev/null @@ -1,366 +0,0 @@ -package 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 org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DEROutputStream; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.AttCertValidityPeriod; -import org.bouncycastle.asn1.x509.Attribute; -import org.bouncycastle.asn1.x509.AttributeCertificate; -import org.bouncycastle.asn1.x509.AttributeCertificateInfo; -import org.bouncycastle.asn1.x509.Extension; -import org.bouncycastle.asn1.x509.Extensions; -import org.bouncycastle.operator.ContentVerifier; -import org.bouncycastle.operator.ContentVerifierProvider; - -/** - * Holding class for an X.509 AttributeCertificate structure. - */ -public class X509AttributeCertificateHolder -{ - 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(ASN1Primitive.fromByteArray(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().getBytes(); - } - - /** - * 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(attrCert.getSignatureValue().getBytes()); - } - - 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/pkix/src/main/java/org/bouncycastle/cert/X509CRLEntryHolder.java b/pkix/src/main/java/org/bouncycastle/cert/X509CRLEntryHolder.java deleted file mode 100644 index a10f0143..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/X509CRLEntryHolder.java +++ /dev/null @@ -1,144 +0,0 @@ -package org.bouncycastle.cert; - -import java.math.BigInteger; -import java.util.Date; -import java.util.List; -import java.util.Set; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x509.Extension; -import org.bouncycastle.asn1.x509.Extensions; -import org.bouncycastle.asn1.x509.GeneralNames; -import 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/pkix/src/main/java/org/bouncycastle/cert/X509CRLHolder.java b/pkix/src/main/java/org/bouncycastle/cert/X509CRLHolder.java deleted file mode 100644 index b3723f38..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/X509CRLHolder.java +++ /dev/null @@ -1,317 +0,0 @@ -package 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 org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DEROutputStream; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.CertificateList; -import org.bouncycastle.asn1.x509.Extension; -import org.bouncycastle.asn1.x509.Extensions; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.asn1.x509.GeneralNames; -import org.bouncycastle.asn1.x509.IssuingDistributionPoint; -import org.bouncycastle.asn1.x509.TBSCertList; -import org.bouncycastle.operator.ContentVerifier; -import org.bouncycastle.operator.ContentVerifierProvider; - -/** - * Holding class for an X.509 CRL structure. - */ -public class X509CRLHolder -{ - private CertificateList x509CRL; - private boolean isIndirect; - private Extensions extensions; - private GeneralNames issuerName; - - private static CertificateList parseStream(InputStream stream) - throws IOException - { - try - { - return CertificateList.getInstance(new ASN1InputStream(stream, true).readObject()); - } - 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().getBytes()); - } - - 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/pkix/src/main/java/org/bouncycastle/cert/X509CertificateHolder.java b/pkix/src/main/java/org/bouncycastle/cert/X509CertificateHolder.java deleted file mode 100644 index 1081d937..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/X509CertificateHolder.java +++ /dev/null @@ -1,327 +0,0 @@ -package 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 org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.DEROutputStream; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.Certificate; -import org.bouncycastle.asn1.x509.Extension; -import org.bouncycastle.asn1.x509.Extensions; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.asn1.x509.TBSCertificate; -import org.bouncycastle.operator.ContentVerifier; -import org.bouncycastle.operator.ContentVerifierProvider; - -/** - * Holding class for an X.509 Certificate structure. - */ -public class X509CertificateHolder -{ - private Certificate x509Certificate; - private Extensions extensions; - - private static Certificate parseBytes(byte[] certEncoding) - throws IOException - { - try - { - return Certificate.getInstance(ASN1Primitive.fromByteArray(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 X509CertificateStructure 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().getBytes(); - } - - /** - * 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(x509Certificate.getSignature().getBytes()); - } - - 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/pkix/src/main/java/org/bouncycastle/cert/X509ContentVerifierProviderBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/X509ContentVerifierProviderBuilder.java deleted file mode 100644 index af3bd09c..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/X509ContentVerifierProviderBuilder.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.bouncycastle.cert; - -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.operator.ContentVerifierProvider; -import org.bouncycastle.operator.OperatorCreationException; - -public interface X509ContentVerifierProviderBuilder -{ - ContentVerifierProvider build(SubjectPublicKeyInfo validatingKeyInfo) - throws OperatorCreationException; - - ContentVerifierProvider build(X509CertificateHolder validatingKeyInfo) - throws OperatorCreationException; -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/X509ExtensionUtils.java b/pkix/src/main/java/org/bouncycastle/cert/X509ExtensionUtils.java deleted file mode 100644 index aa371381..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/X509ExtensionUtils.java +++ /dev/null @@ -1,132 +0,0 @@ -package org.bouncycastle.cert; - -import java.io.IOException; -import java.io.OutputStream; -import java.math.BigInteger; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; -import org.bouncycastle.asn1.x509.Extension; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.asn1.x509.GeneralNames; -import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.operator.DigestCalculator; - -/** - * General utility class for creating calculated extensions using the standard methods. - * <p> - * <b>Note:</b> This class is not thread safe! - * </p> - */ -public class X509ExtensionUtils -{ - private DigestCalculator calculator; - - public X509ExtensionUtils(DigestCalculator calculator) - { - this.calculator = calculator; - } - - public AuthorityKeyIdentifier createAuthorityKeyIdentifier( - X509CertificateHolder certHolder) - { - if (certHolder.getVersionNumber() != 3) - { - GeneralName genName = new GeneralName(certHolder.getIssuer()); - SubjectPublicKeyInfo info = certHolder.getSubjectPublicKeyInfo(); - - return new AuthorityKeyIdentifier( - calculateIdentifier(info), new GeneralNames(genName), certHolder.getSerialNumber()); - } - else - { - GeneralName genName = new GeneralName(certHolder.getIssuer()); - Extension ext = certHolder.getExtension(Extension.subjectKeyIdentifier); - - if (ext != null) - { - ASN1OctetString str = ASN1OctetString.getInstance(ext.getParsedValue()); - - return new AuthorityKeyIdentifier( - str.getOctets(), new GeneralNames(genName), certHolder.getSerialNumber()); - } - else - { - SubjectPublicKeyInfo info = certHolder.getSubjectPublicKeyInfo(); - - return new AuthorityKeyIdentifier( - calculateIdentifier(info), new GeneralNames(genName), certHolder.getSerialNumber()); - } - } - } - - public AuthorityKeyIdentifier createAuthorityKeyIdentifier(SubjectPublicKeyInfo publicKeyInfo) - { - return new AuthorityKeyIdentifier(calculateIdentifier(publicKeyInfo)); - } - - public AuthorityKeyIdentifier createAuthorityKeyIdentifier(SubjectPublicKeyInfo publicKeyInfo, GeneralNames generalNames, BigInteger serial) - { - return new AuthorityKeyIdentifier(calculateIdentifier(publicKeyInfo), generalNames, serial); - } - - /** - * Return a RFC 3280 type 1 key identifier. As in: - * <pre> - * (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the - * value of the BIT STRING subjectPublicKey (excluding the tag, - * length, and number of unused bits). - * </pre> - * @param publicKeyInfo the key info object containing the subjectPublicKey field. - * @return the key identifier. - */ - public SubjectKeyIdentifier createSubjectKeyIdentifier( - SubjectPublicKeyInfo publicKeyInfo) - { - return new SubjectKeyIdentifier(calculateIdentifier(publicKeyInfo)); - } - - /** - * Return a RFC 3280 type 2 key identifier. As in: - * <pre> - * (2) The keyIdentifier is composed of a four bit type field with - * the value 0100 followed by the least significant 60 bits of the - * SHA-1 hash of the value of the BIT STRING subjectPublicKey. - * </pre> - * @param publicKeyInfo the key info object containing the subjectPublicKey field. - * @return the key identifier. - */ - public SubjectKeyIdentifier createTruncatedSubjectKeyIdentifier(SubjectPublicKeyInfo publicKeyInfo) - { - byte[] digest = calculateIdentifier(publicKeyInfo); - byte[] id = new byte[8]; - - System.arraycopy(digest, digest.length - 8, id, 0, id.length); - - id[0] &= 0x0f; - id[0] |= 0x40; - - return new SubjectKeyIdentifier(id); - } - - private byte[] calculateIdentifier(SubjectPublicKeyInfo publicKeyInfo) - { - byte[] bytes = publicKeyInfo.getPublicKeyData().getBytes(); - - OutputStream cOut = calculator.getOutputStream(); - - try - { - cOut.write(bytes); - - cOut.close(); - } - catch (IOException e) - { // it's hard to imagine this happening, but yes it does! - throw new CertRuntimeException("unable to calculate identifier: " + e.getMessage(), e); - } - - return calculator.getDigest(); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/X509v1CertificateBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/X509v1CertificateBuilder.java deleted file mode 100644 index 3652ba9e..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/X509v1CertificateBuilder.java +++ /dev/null @@ -1,101 +0,0 @@ -package org.bouncycastle.cert; - -import java.math.BigInteger; -import java.util.Date; -import java.util.Locale; - -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.ExtensionsGenerator; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.asn1.x509.Time; -import org.bouncycastle.asn1.x509.V1TBSCertificateGenerator; -import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator; -import org.bouncycastle.operator.ContentSigner; - - -/** - * class to produce an X.509 Version 1 certificate. - */ -public class X509v1CertificateBuilder -{ - private V1TBSCertificateGenerator tbsGen; - - /** - * Create a builder for a version 1 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 X509v1CertificateBuilder(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 1 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 X509v1CertificateBuilder(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 1 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 X509v1CertificateBuilder(X500Name issuer, BigInteger serial, Time notBefore, Time notAfter, X500Name subject, SubjectPublicKeyInfo publicKeyInfo) - { - if (issuer == null) - { - throw new IllegalArgumentException("issuer must not be null"); - } - - if (publicKeyInfo == null) - { - throw new IllegalArgumentException("publicKeyInfo must not be null"); - } - - tbsGen = new V1TBSCertificateGenerator(); - tbsGen.setSerialNumber(new ASN1Integer(serial)); - tbsGen.setIssuer(issuer); - tbsGen.setStartDate(notBefore); - tbsGen.setEndDate(notAfter); - tbsGen.setSubject(subject); - tbsGen.setSubjectPublicKeyInfo(publicKeyInfo); - } - - /** - * Generate an X509 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()); - - return CertUtils.generateFullCert(signer, tbsGen.generateTBSCertificate()); - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cert/X509v2AttributeCertificateBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/X509v2AttributeCertificateBuilder.java deleted file mode 100644 index 4cd10a3f..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/X509v2AttributeCertificateBuilder.java +++ /dev/null @@ -1,162 +0,0 @@ -package org.bouncycastle.cert; - -import java.math.BigInteger; -import java.util.Date; -import java.util.Locale; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1GeneralizedTime; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.x509.AttCertIssuer; -import org.bouncycastle.asn1.x509.Attribute; -import org.bouncycastle.asn1.x509.ExtensionsGenerator; -import org.bouncycastle.asn1.x509.V2AttributeCertificateInfoGenerator; -import org.bouncycastle.operator.ContentSigner; - -/** - * class to produce an X.509 Version 2 AttributeCertificate. - */ -public class X509v2AttributeCertificateBuilder -{ - private V2AttributeCertificateInfoGenerator acInfoGen; - private ExtensionsGenerator extGenerator; - - /** - * Base constructor. - * - * @param holder holder certificate details - * @param issuer issuer of this attribute certificate. - * @param serialNumber serial number of this attribute certificate. - * @param notBefore the date before which the certificate is not valid. - * @param notAfter the date after which the certificate is not valid. - */ - public X509v2AttributeCertificateBuilder(AttributeCertificateHolder holder, AttributeCertificateIssuer issuer, BigInteger serialNumber, Date notBefore, Date notAfter) - { - acInfoGen = new V2AttributeCertificateInfoGenerator(); - extGenerator = new ExtensionsGenerator(); - - acInfoGen.setHolder(holder.holder); - acInfoGen.setIssuer(AttCertIssuer.getInstance(issuer.form)); - acInfoGen.setSerialNumber(new ASN1Integer(serialNumber)); - acInfoGen.setStartDate(new ASN1GeneralizedTime(notBefore)); - acInfoGen.setEndDate(new ASN1GeneralizedTime(notAfter)); - } - - /** - * Base constructor with locale for interpreting dates. You may need to use this constructor if the default locale - * doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations. - * - * @param holder holder certificate details - * @param issuer issuer of this attribute certificate. - * @param serialNumber serial number of this attribute certificate. - * @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. - */ - public X509v2AttributeCertificateBuilder(AttributeCertificateHolder holder, AttributeCertificateIssuer issuer, BigInteger serialNumber, Date notBefore, Date notAfter, Locale dateLocale) - { - acInfoGen = new V2AttributeCertificateInfoGenerator(); - extGenerator = new ExtensionsGenerator(); - - acInfoGen.setHolder(holder.holder); - acInfoGen.setIssuer(AttCertIssuer.getInstance(issuer.form)); - acInfoGen.setSerialNumber(new ASN1Integer(serialNumber)); - acInfoGen.setStartDate(new ASN1GeneralizedTime(notBefore, dateLocale)); - acInfoGen.setEndDate(new ASN1GeneralizedTime(notAfter, dateLocale)); - } - - /** - * Add an attribute to the certification request we are building. - * - * @param attrType the OID giving the type of the attribute. - * @param attrValue the ASN.1 structure that forms the value of the attribute. - * @return this builder object. - */ - public X509v2AttributeCertificateBuilder addAttribute(ASN1ObjectIdentifier attrType, ASN1Encodable attrValue) - { - acInfoGen.addAttribute(new Attribute(attrType, new DERSet(attrValue))); - - return this; - } - - /** - * Add an attribute with multiple values to the certification request we are building. - * - * @param attrType the OID giving the type of the attribute. - * @param attrValues an array of ASN.1 structures that form the value of the attribute. - * @return this builder object. - */ - public X509v2AttributeCertificateBuilder addAttribute(ASN1ObjectIdentifier attrType, ASN1Encodable[] attrValues) - { - acInfoGen.addAttribute(new Attribute(attrType, new DERSet(attrValues))); - - return this; - } - - public void setIssuerUniqueId( - boolean[] iui) - { - acInfoGen.setIssuerUniqueID(CertUtils.booleanToBitString(iui)); - } - - /** - * Add a given extension field for the standard extensions tag - * - * @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 X509v2AttributeCertificateBuilder 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) 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 X509v2AttributeCertificateBuilder addExtension( - ASN1ObjectIdentifier oid, - boolean isCritical, - byte[] encodedValue) - throws CertIOException - { - extGenerator.addExtension(oid, isCritical, encodedValue); - - return this; - } - - /** - * Generate an X509 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 X509AttributeCertificateHolder build( - ContentSigner signer) - { - acInfoGen.setSignature(signer.getAlgorithmIdentifier()); - - if (!extGenerator.isEmpty()) - { - acInfoGen.setExtensions(extGenerator.generate()); - } - - return CertUtils.generateFullAttrCert(signer, acInfoGen.generateAttributeCertificateInfo()); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/X509v2CRLBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/X509v2CRLBuilder.java deleted file mode 100644 index 896f55be..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/X509v2CRLBuilder.java +++ /dev/null @@ -1,266 +0,0 @@ -package org.bouncycastle.cert; - -import java.math.BigInteger; -import java.util.Date; -import java.util.Enumeration; -import java.util.Locale; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1GeneralizedTime; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.Extensions; -import org.bouncycastle.asn1.x509.ExtensionsGenerator; -import org.bouncycastle.asn1.x509.TBSCertList; -import org.bouncycastle.asn1.x509.Time; -import org.bouncycastle.asn1.x509.V2TBSCertListGenerator; -import org.bouncycastle.asn1.x509.X509Extensions; -import org.bouncycastle.operator.ContentSigner; - -/** - * class to produce an X.509 Version 2 CRL. - */ -public class X509v2CRLBuilder -{ - private V2TBSCertListGenerator tbsGen; - private ExtensionsGenerator extGenerator; - - /** - * Basic constructor. - * - * @param issuer the issuer this CRL is associated with. - * @param thisUpdate the date of this update. - */ - public X509v2CRLBuilder( - X500Name issuer, - Date thisUpdate) - { - tbsGen = new V2TBSCertListGenerator(); - extGenerator = new ExtensionsGenerator(); - - tbsGen.setIssuer(issuer); - tbsGen.setThisUpdate(new Time(thisUpdate)); - } - - /** - * Basic constructor with Locale. 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 issuer this CRL is associated with. - * @param thisUpdate the date of this update. - * @param dateLocale locale to be used for date interpretation. - */ - public X509v2CRLBuilder( - X500Name issuer, - Date thisUpdate, - Locale dateLocale) - { - tbsGen = new V2TBSCertListGenerator(); - extGenerator = new ExtensionsGenerator(); - - tbsGen.setIssuer(issuer); - tbsGen.setThisUpdate(new Time(thisUpdate, dateLocale)); - } - - /** - * Basic constructor. - * - * @param issuer the issuer this CRL is associated with. - * @param thisUpdate the Time of this update. - */ - public X509v2CRLBuilder( - X500Name issuer, - Time thisUpdate) - { - tbsGen = new V2TBSCertListGenerator(); - extGenerator = new ExtensionsGenerator(); - - tbsGen.setIssuer(issuer); - tbsGen.setThisUpdate(thisUpdate); - } - - /** - * Set the date by which the next CRL will become available. - * - * @param date date of next CRL update. - * @return the current builder. - */ - public X509v2CRLBuilder setNextUpdate( - Date date) - { - return this.setNextUpdate(new Time(date)); - } - - /** - * Set the date by which the next CRL will become available. - * - * @param date date of next CRL update. - * @param dateLocale locale to be used for date interpretation. - * @return the current builder. - */ - public X509v2CRLBuilder setNextUpdate( - Date date, - Locale dateLocale) - { - return this.setNextUpdate(new Time(date, dateLocale)); - } - - /** - * Set the date by which the next CRL will become available. - * - * @param date date of next CRL update. - * @return the current builder. - */ - public X509v2CRLBuilder setNextUpdate( - Time date) - { - tbsGen.setNextUpdate(date); - - return this; - } - - /** - * Add a CRL entry with the just reasonCode extension. - * - * @param userCertificateSerial serial number of revoked certificate. - * @param revocationDate date of certificate revocation. - * @param reason the reason code, as indicated in CRLReason, i.e CRLReason.keyCompromise, or 0 if not to be used. - * @return the current builder. - */ - public X509v2CRLBuilder addCRLEntry(BigInteger userCertificateSerial, Date revocationDate, int reason) - { - tbsGen.addCRLEntry(new ASN1Integer(userCertificateSerial), new Time(revocationDate), reason); - - return this; - } - - /** - * Add a CRL entry with an invalidityDate extension as well as a reasonCode extension. This is used - * where the date of revocation might be after issues with the certificate may have occurred. - * - * @param userCertificateSerial serial number of revoked certificate. - * @param revocationDate date of certificate revocation. - * @param reason the reason code, as indicated in CRLReason, i.e CRLReason.keyCompromise, or 0 if not to be used. - * @param invalidityDate the date on which the private key for the certificate became compromised or the certificate otherwise became invalid. - * @return the current builder. - */ - public X509v2CRLBuilder addCRLEntry(BigInteger userCertificateSerial, Date revocationDate, int reason, Date invalidityDate) - { - tbsGen.addCRLEntry(new ASN1Integer(userCertificateSerial), new Time(revocationDate), reason, new ASN1GeneralizedTime(invalidityDate)); - - return this; - } - - /** - * Add a CRL entry with extensions. - * - * @param userCertificateSerial serial number of revoked certificate. - * @param revocationDate date of certificate revocation. - * @param extensions extension set to be associated with this CRLEntry. - * @return the current builder. - * @deprecated use method taking Extensions - */ - public X509v2CRLBuilder addCRLEntry(BigInteger userCertificateSerial, Date revocationDate, X509Extensions extensions) - { - tbsGen.addCRLEntry(new ASN1Integer(userCertificateSerial), new Time(revocationDate), Extensions.getInstance(extensions)); - - return this; - } - - /** - * Add a CRL entry with extensions. - * - * @param userCertificateSerial serial number of revoked certificate. - * @param revocationDate date of certificate revocation. - * @param extensions extension set to be associated with this CRLEntry. - * @return the current builder. - */ - public X509v2CRLBuilder addCRLEntry(BigInteger userCertificateSerial, Date revocationDate, Extensions extensions) - { - tbsGen.addCRLEntry(new ASN1Integer(userCertificateSerial), new Time(revocationDate), extensions); - - return this; - } - - /** - * Add the CRLEntry objects contained in a previous CRL. - * - * @param other the X509CRLHolder to source the other entries from. - * @return the current builder. - */ - public X509v2CRLBuilder addCRL(X509CRLHolder other) - { - TBSCertList revocations = other.toASN1Structure().getTBSCertList(); - - if (revocations != null) - { - for (Enumeration en = revocations.getRevokedCertificateEnumeration(); en.hasMoreElements();) - { - tbsGen.addCRLEntry(ASN1Sequence.getInstance(((ASN1Encodable)en.nextElement()).toASN1Primitive())); - } - } - - 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 X509v2CRLBuilder 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) 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 X509v2CRLBuilder addExtension( - ASN1ObjectIdentifier oid, - boolean isCritical, - byte[] encodedValue) - throws CertIOException - { - extGenerator.addExtension(oid, isCritical, encodedValue); - - return this; - } - - /** - * Generate an X.509 CRL, 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 X509CRLHolder build( - ContentSigner signer) - { - tbsGen.setSignature(signer.getAlgorithmIdentifier()); - - if (!extGenerator.isEmpty()) - { - tbsGen.setExtensions(extGenerator.generate()); - } - - return CertUtils.generateFullCRL(signer, tbsGen.generateTBSCertList()); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/X509v3CertificateBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/X509v3CertificateBuilder.java deleted file mode 100644 index 22905b97..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/X509v3CertificateBuilder.java +++ /dev/null @@ -1,195 +0,0 @@ -package org.bouncycastle.cert; - -import java.math.BigInteger; -import java.util.Date; -import java.util.Locale; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.Certificate; -import org.bouncycastle.asn1.x509.Extension; -import org.bouncycastle.asn1.x509.ExtensionsGenerator; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.asn1.x509.Time; -import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator; -import 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) 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/pkix/src/main/java/org/bouncycastle/cert/bc/BcX509ExtensionUtils.java b/pkix/src/main/java/org/bouncycastle/cert/bc/BcX509ExtensionUtils.java deleted file mode 100644 index c5a09536..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/bc/BcX509ExtensionUtils.java +++ /dev/null @@ -1,91 +0,0 @@ -package org.bouncycastle.cert.bc; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; -import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; -import org.bouncycastle.cert.X509ExtensionUtils; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory; -import org.bouncycastle.operator.DigestCalculator; - -public class BcX509ExtensionUtils - extends X509ExtensionUtils -{ - /** - * Create a utility class pre-configured with a SHA-1 digest calculator based on the - * BC implementation. - */ - public BcX509ExtensionUtils() - { - super(new SHA1DigestCalculator()); - } - - public BcX509ExtensionUtils(DigestCalculator calculator) - { - super(calculator); - } - - public AuthorityKeyIdentifier createAuthorityKeyIdentifier( - AsymmetricKeyParameter publicKey) - throws IOException - { - return super.createAuthorityKeyIdentifier(SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKey)); - } - - /** - * Return a RFC 3280 type 1 key identifier. As in: - * <pre> - * (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the - * value of the BIT STRING subjectPublicKey (excluding the tag, - * length, and number of unused bits). - * </pre> - * @param publicKey the key object containing the key identifier is to be based on. - * @return the key identifier. - */ - public SubjectKeyIdentifier createSubjectKeyIdentifier( - AsymmetricKeyParameter publicKey) - throws IOException - { - return super.createSubjectKeyIdentifier(SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKey)); - } - - private static class SHA1DigestCalculator - implements DigestCalculator - { - private ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1); - } - - public OutputStream getOutputStream() - { - return bOut; - } - - public byte[] getDigest() - { - byte[] bytes = bOut.toByteArray(); - - bOut.reset(); - - Digest sha1 = new SHA1Digest(); - - sha1.update(bytes, 0, bytes.length); - - byte[] digest = new byte[sha1.getDigestSize()]; - - sha1.doFinal(digest, 0); - - return digest; - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/bc/BcX509v1CertificateBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/bc/BcX509v1CertificateBuilder.java deleted file mode 100644 index 5120030c..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/bc/BcX509v1CertificateBuilder.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.bouncycastle.cert.bc; - -import java.io.IOException; -import java.math.BigInteger; -import java.util.Date; - -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.cert.X509v1CertificateBuilder; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory; - -/** - * JCA helper class to allow BC lightweight objects to be used in the construction of a Version 1 certificate. - */ -public class BcX509v1CertificateBuilder - extends X509v1CertificateBuilder -{ - /** - * Initialise the builder using an AsymmetricKeyParameter. - * - * @param issuer X500Name representing the issuer of this certificate. - * @param serial the serial number for the certificate. - * @param notBefore date before which the certificate is not valid. - * @param notAfter date after which the certificate is not valid. - * @param subject X500Name representing the subject of this certificate. - * @param publicKey the public key to be associated with the certificate. - */ - public BcX509v1CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, AsymmetricKeyParameter publicKey) - throws IOException - { - super(issuer, serial, notBefore, notAfter, subject, SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKey)); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/bc/BcX509v3CertificateBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/bc/BcX509v3CertificateBuilder.java deleted file mode 100644 index e85fce1b..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/bc/BcX509v3CertificateBuilder.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.bouncycastle.cert.bc; - -import java.io.IOException; -import java.math.BigInteger; -import java.util.Date; - -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cert.X509v3CertificateBuilder; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory; - -/** - * JCA helper class to allow BC lightweight objects to be used in the construction of a Version 3 certificate. - */ -public class BcX509v3CertificateBuilder - extends X509v3CertificateBuilder -{ - /** - * Initialise the builder using a PublicKey. - * - * @param issuer X500Name representing the issuer of this certificate. - * @param serial the serial number for the certificate. - * @param notBefore date before which the certificate is not valid. - * @param notAfter date after which the certificate is not valid. - * @param subject X500Name representing the subject of this certificate. - * @param publicKey the public key to be associated with the certificate. - */ - public BcX509v3CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, AsymmetricKeyParameter publicKey) - throws IOException - { - super(issuer, serial, notBefore, notAfter, subject, SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKey)); - } - - /** - * Initialise the builder using the subject from the passed in issuerCert as the issuer, as well as - * passing through and converting the other objects provided. - * - * @param issuerCert holder for certificate who's subject is the issuer of the certificate we are building. - * @param serial the serial number for the certificate. - * @param notBefore date before which the certificate is not valid. - * @param notAfter date after which the certificate is not valid. - * @param subject principal representing the subject of this certificate. - * @param publicKey the public key to be associated with the certificate. - */ - public BcX509v3CertificateBuilder(X509CertificateHolder issuerCert, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, AsymmetricKeyParameter publicKey) - throws IOException - { - super(issuerCert.getSubject(), serial, notBefore, notAfter, subject, SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKey)); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/cmp/CMPException.java b/pkix/src/main/java/org/bouncycastle/cert/cmp/CMPException.java deleted file mode 100644 index 2a1cc865..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/cmp/CMPException.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.bouncycastle.cert.cmp; - -public class CMPException - extends Exception -{ - private Throwable cause; - - public CMPException(String msg, Throwable cause) - { - super(msg); - - this.cause = cause; - } - - public CMPException(String msg) - { - super(msg); - } - - public Throwable getCause() - { - return cause; - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cert/cmp/CMPRuntimeException.java b/pkix/src/main/java/org/bouncycastle/cert/cmp/CMPRuntimeException.java deleted file mode 100644 index 35b2d3fa..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/cmp/CMPRuntimeException.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.bouncycastle.cert.cmp; - -public class CMPRuntimeException - extends RuntimeException -{ - private Throwable cause; - - public CMPRuntimeException(String msg, Throwable cause) - { - super(msg); - - this.cause = cause; - } - - public Throwable getCause() - { - return cause; - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cert/cmp/CMPUtil.java b/pkix/src/main/java/org/bouncycastle/cert/cmp/CMPUtil.java deleted file mode 100644 index cc2ef04a..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/cmp/CMPUtil.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.bouncycastle.cert.cmp; - -import java.io.IOException; -import java.io.OutputStream; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.DEROutputStream; - -class CMPUtil -{ - static void derEncodeToStream(ASN1Encodable obj, OutputStream stream) - { - DEROutputStream dOut = new DEROutputStream(stream); - - try - { - dOut.writeObject(obj); - - dOut.close(); - } - catch (IOException e) - { - throw new CMPRuntimeException("unable to DER encode object: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/cmp/CertificateConfirmationContent.java b/pkix/src/main/java/org/bouncycastle/cert/cmp/CertificateConfirmationContent.java deleted file mode 100644 index d1a2e643..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/cmp/CertificateConfirmationContent.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.bouncycastle.cert.cmp; - -import org.bouncycastle.asn1.cmp.CertConfirmContent; -import org.bouncycastle.asn1.cmp.CertStatus; -import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder; -import org.bouncycastle.operator.DigestAlgorithmIdentifierFinder; - -public class CertificateConfirmationContent -{ - private DigestAlgorithmIdentifierFinder digestAlgFinder; - private CertConfirmContent content; - - public CertificateConfirmationContent(CertConfirmContent content) - { - this(content, new DefaultDigestAlgorithmIdentifierFinder()); - } - - public CertificateConfirmationContent(CertConfirmContent content, DigestAlgorithmIdentifierFinder digestAlgFinder) - { - this.digestAlgFinder = digestAlgFinder; - this.content = content; - } - - public CertConfirmContent toASN1Structure() - { - return content; - } - - public CertificateStatus[] getStatusMessages() - { - CertStatus[] statusArray = content.toCertStatusArray(); - CertificateStatus[] ret = new CertificateStatus[statusArray.length]; - - for (int i = 0; i != ret.length; i++) - { - ret[i] = new CertificateStatus(digestAlgFinder, statusArray[i]); - } - - return ret; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/cmp/CertificateConfirmationContentBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/cmp/CertificateConfirmationContentBuilder.java deleted file mode 100644 index 578ae148..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/cmp/CertificateConfirmationContentBuilder.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.bouncycastle.cert.cmp; - -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.cmp.CertConfirmContent; -import org.bouncycastle.asn1.cmp.CertStatus; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder; -import org.bouncycastle.operator.DigestAlgorithmIdentifierFinder; -import org.bouncycastle.operator.DigestCalculator; -import org.bouncycastle.operator.DigestCalculatorProvider; -import org.bouncycastle.operator.OperatorCreationException; - -public class CertificateConfirmationContentBuilder -{ - private DigestAlgorithmIdentifierFinder digestAlgFinder; - private List acceptedCerts = new ArrayList(); - private List acceptedReqIds = new ArrayList(); - - public CertificateConfirmationContentBuilder() - { - this(new DefaultDigestAlgorithmIdentifierFinder()); - } - - public CertificateConfirmationContentBuilder(DigestAlgorithmIdentifierFinder digestAlgFinder) - { - this.digestAlgFinder = digestAlgFinder; - } - - public CertificateConfirmationContentBuilder addAcceptedCertificate(X509CertificateHolder certHolder, BigInteger certReqID) - { - acceptedCerts.add(certHolder); - acceptedReqIds.add(certReqID); - - return this; - } - - public CertificateConfirmationContent build(DigestCalculatorProvider digesterProvider) - throws CMPException - { - ASN1EncodableVector v = new ASN1EncodableVector(); - - for (int i = 0; i != acceptedCerts.size(); i++) - { - X509CertificateHolder certHolder = (X509CertificateHolder)acceptedCerts.get(i); - BigInteger reqID = (BigInteger)acceptedReqIds.get(i); - - AlgorithmIdentifier digAlg = digestAlgFinder.find(certHolder.toASN1Structure().getSignatureAlgorithm()); - if (digAlg == null) - { - throw new CMPException("cannot find algorithm for digest from signature"); - } - - DigestCalculator digester; - - try - { - digester = digesterProvider.get(digAlg); - } - catch (OperatorCreationException e) - { - throw new CMPException("unable to create digest: " + e.getMessage(), e); - } - - CMPUtil.derEncodeToStream(certHolder.toASN1Structure(), digester.getOutputStream()); - - v.add(new CertStatus(digester.getDigest(), reqID)); - } - - return new CertificateConfirmationContent(CertConfirmContent.getInstance(new DERSequence(v)), digestAlgFinder); - } - -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/cmp/CertificateStatus.java b/pkix/src/main/java/org/bouncycastle/cert/cmp/CertificateStatus.java deleted file mode 100644 index 50df835f..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/cmp/CertificateStatus.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.bouncycastle.cert.cmp; - -import java.math.BigInteger; - -import org.bouncycastle.asn1.cmp.CertStatus; -import org.bouncycastle.asn1.cmp.PKIStatusInfo; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.operator.DigestAlgorithmIdentifierFinder; -import org.bouncycastle.operator.DigestCalculator; -import org.bouncycastle.operator.DigestCalculatorProvider; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.util.Arrays; - -public class CertificateStatus -{ - private DigestAlgorithmIdentifierFinder digestAlgFinder; - private CertStatus certStatus; - - CertificateStatus(DigestAlgorithmIdentifierFinder digestAlgFinder, CertStatus certStatus) - { - this.digestAlgFinder = digestAlgFinder; - this.certStatus = certStatus; - } - - public PKIStatusInfo getStatusInfo() - { - return certStatus.getStatusInfo(); - } - - public BigInteger getCertRequestID() - { - return certStatus.getCertReqId().getValue(); - } - - public boolean isVerified(X509CertificateHolder certHolder, DigestCalculatorProvider digesterProvider) - throws CMPException - { - AlgorithmIdentifier digAlg = digestAlgFinder.find(certHolder.toASN1Structure().getSignatureAlgorithm()); - if (digAlg == null) - { - throw new CMPException("cannot find algorithm for digest from signature"); - } - - DigestCalculator digester; - - try - { - digester = digesterProvider.get(digAlg); - } - catch (OperatorCreationException e) - { - throw new CMPException("unable to create digester: " + e.getMessage(), e); - } - - CMPUtil.derEncodeToStream(certHolder.toASN1Structure(), digester.getOutputStream()); - - return Arrays.areEqual(certStatus.getCertHash().getOctets(), digester.getDigest()); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/cmp/GeneralPKIMessage.java b/pkix/src/main/java/org/bouncycastle/cert/cmp/GeneralPKIMessage.java deleted file mode 100644 index a928623f..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/cmp/GeneralPKIMessage.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.bouncycastle.cert.cmp; - -import java.io.IOException; - -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.cmp.PKIBody; -import org.bouncycastle.asn1.cmp.PKIHeader; -import org.bouncycastle.asn1.cmp.PKIMessage; -import org.bouncycastle.cert.CertIOException; - -/** - * General wrapper for a generic PKIMessage - */ -public class GeneralPKIMessage -{ - private final PKIMessage pkiMessage; - - private static PKIMessage parseBytes(byte[] encoding) - throws IOException - { - try - { - return PKIMessage.getInstance(ASN1Primitive.fromByteArray(encoding)); - } - catch (ClassCastException e) - { - throw new CertIOException("malformed data: " + e.getMessage(), e); - } - catch (IllegalArgumentException e) - { - throw new CertIOException("malformed data: " + e.getMessage(), e); - } - } - - /** - * Create a PKIMessage from the passed in bytes. - * - * @param encoding BER/DER encoding of the PKIMessage - * @throws IOException in the event of corrupted data, or an incorrect structure. - */ - public GeneralPKIMessage(byte[] encoding) - throws IOException - { - this(parseBytes(encoding)); - } - - /** - * Wrap a PKIMessage ASN.1 structure. - * - * @param pkiMessage base PKI message. - */ - public GeneralPKIMessage(PKIMessage pkiMessage) - { - this.pkiMessage = pkiMessage; - } - - public PKIHeader getHeader() - { - return pkiMessage.getHeader(); - } - - public PKIBody getBody() - { - return pkiMessage.getBody(); - } - - /** - * Return true if this message has protection bits on it. A return value of true - * indicates the message can be used to construct a ProtectedPKIMessage. - * - * @return true if message has protection, false otherwise. - */ - public boolean hasProtection() - { - return pkiMessage.getHeader().getProtectionAlg() != null; - } - - public PKIMessage toASN1Structure() - { - return pkiMessage; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/cmp/ProtectedPKIMessage.java b/pkix/src/main/java/org/bouncycastle/cert/cmp/ProtectedPKIMessage.java deleted file mode 100644 index 2749d908..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/cmp/ProtectedPKIMessage.java +++ /dev/null @@ -1,198 +0,0 @@ -package org.bouncycastle.cert.cmp; - -import java.io.IOException; -import java.io.OutputStream; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.cmp.CMPCertificate; -import org.bouncycastle.asn1.cmp.CMPObjectIdentifiers; -import org.bouncycastle.asn1.cmp.PBMParameter; -import org.bouncycastle.asn1.cmp.PKIBody; -import org.bouncycastle.asn1.cmp.PKIHeader; -import org.bouncycastle.asn1.cmp.PKIMessage; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cert.crmf.PKMACBuilder; -import org.bouncycastle.operator.ContentVerifier; -import org.bouncycastle.operator.ContentVerifierProvider; -import org.bouncycastle.operator.MacCalculator; -import org.bouncycastle.util.Arrays; - -/** - * Wrapper for a PKIMessage with protection attached to it. - */ -public class ProtectedPKIMessage -{ - private PKIMessage pkiMessage; - - /** - * Base constructor. - * - * @param pkiMessage a GeneralPKIMessage with - */ - public ProtectedPKIMessage(GeneralPKIMessage pkiMessage) - { - if (!pkiMessage.hasProtection()) - { - throw new IllegalArgumentException("PKIMessage not protected"); - } - - this.pkiMessage = pkiMessage.toASN1Structure(); - } - - ProtectedPKIMessage(PKIMessage pkiMessage) - { - if (pkiMessage.getHeader().getProtectionAlg() == null) - { - throw new IllegalArgumentException("PKIMessage not protected"); - } - - this.pkiMessage = pkiMessage; - } - - /** - * Return the message header. - * - * @return the message's PKIHeader structure. - */ - public PKIHeader getHeader() - { - return pkiMessage.getHeader(); - } - - /** - * Return the message body. - * - * @return the message's PKIBody structure. - */ - public PKIBody getBody() - { - return pkiMessage.getBody(); - } - - /** - * Return the underlying ASN.1 structure contained in this object. - * - * @return a PKIMessage structure. - */ - public PKIMessage toASN1Structure() - { - return pkiMessage; - } - - /** - * Determine whether the message is protected by a password based MAC. Use verify(PKMACBuilder, char[]) - * to verify the message if this method returns true. - * - * @return true if protection MAC PBE based, false otherwise. - */ - public boolean hasPasswordBasedMacProtection() - { - return pkiMessage.getHeader().getProtectionAlg().getAlgorithm().equals(CMPObjectIdentifiers.passwordBasedMac); - } - - /** - * Return the extra certificates associated with this message. - * - * @return an array of extra certificates, zero length if none present. - */ - public X509CertificateHolder[] getCertificates() - { - CMPCertificate[] certs = pkiMessage.getExtraCerts(); - - if (certs == null) - { - return new X509CertificateHolder[0]; - } - - X509CertificateHolder[] res = new X509CertificateHolder[certs.length]; - for (int i = 0; i != certs.length; i++) - { - res[i] = new X509CertificateHolder(certs[i].getX509v3PKCert()); - } - - return res; - } - - /** - * Verify a message with a public key based signature attached. - * - * @param verifierProvider a provider of signature verifiers. - * @return true if the provider is able to create a verifier that validates - * the signature, false otherwise. - * @throws CMPException if an exception is thrown trying to verify the signature. - */ - public boolean verify(ContentVerifierProvider verifierProvider) - throws CMPException - { - ContentVerifier verifier; - try - { - verifier = verifierProvider.get(pkiMessage.getHeader().getProtectionAlg()); - - return verifySignature(pkiMessage.getProtection().getBytes(), verifier); - } - catch (Exception e) - { - throw new CMPException("unable to verify signature: " + e.getMessage(), e); - } - } - - /** - * Verify a message with password based MAC protection. - * - * @param pkMacBuilder MAC builder that can be used to construct the appropriate MacCalculator - * @param password the MAC password - * @return true if the passed in password and MAC builder verify the message, false otherwise. - * @throws CMPException if algorithm not MAC based, or an exception is thrown verifying the MAC. - */ - public boolean verify(PKMACBuilder pkMacBuilder, char[] password) - throws CMPException - { - if (!CMPObjectIdentifiers.passwordBasedMac.equals(pkiMessage.getHeader().getProtectionAlg().getAlgorithm())) - { - throw new CMPException("protection algorithm not mac based"); - } - - try - { - pkMacBuilder.setParameters(PBMParameter.getInstance(pkiMessage.getHeader().getProtectionAlg().getParameters())); - MacCalculator calculator = pkMacBuilder.build(password); - - OutputStream macOut = calculator.getOutputStream(); - - ASN1EncodableVector v = new ASN1EncodableVector(); - - v.add(pkiMessage.getHeader()); - v.add(pkiMessage.getBody()); - - macOut.write(new DERSequence(v).getEncoded(ASN1Encoding.DER)); - - macOut.close(); - - return Arrays.areEqual(calculator.getMac(), pkiMessage.getProtection().getBytes()); - } - catch (Exception e) - { - throw new CMPException("unable to verify MAC: " + e.getMessage(), e); - } - } - - private boolean verifySignature(byte[] signature, ContentVerifier verifier) - throws IOException - { - ASN1EncodableVector v = new ASN1EncodableVector(); - - v.add(pkiMessage.getHeader()); - v.add(pkiMessage.getBody()); - - OutputStream sOut = verifier.getOutputStream(); - - sOut.write(new DERSequence(v).getEncoded(ASN1Encoding.DER)); - - sOut.close(); - - return verifier.verify(signature); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/cmp/ProtectedPKIMessageBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/cmp/ProtectedPKIMessageBuilder.java deleted file mode 100644 index 29191567..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/cmp/ProtectedPKIMessageBuilder.java +++ /dev/null @@ -1,306 +0,0 @@ -package org.bouncycastle.cert.cmp; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.ASN1GeneralizedTime; -import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.cmp.CMPCertificate; -import org.bouncycastle.asn1.cmp.InfoTypeAndValue; -import org.bouncycastle.asn1.cmp.PKIBody; -import org.bouncycastle.asn1.cmp.PKIFreeText; -import org.bouncycastle.asn1.cmp.PKIHeader; -import org.bouncycastle.asn1.cmp.PKIHeaderBuilder; -import org.bouncycastle.asn1.cmp.PKIMessage; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.operator.ContentSigner; -import org.bouncycastle.operator.MacCalculator; - -/** - * Builder for creating a protected PKI message. - */ -public class ProtectedPKIMessageBuilder -{ - private PKIHeaderBuilder hdrBuilder; - private PKIBody body; - private List generalInfos = new ArrayList(); - private List extraCerts = new ArrayList(); - - /** - * Commence a message with the header version CMP_2000. - * - * @param sender message sender. - * @param recipient intended recipient. - */ - public ProtectedPKIMessageBuilder(GeneralName sender, GeneralName recipient) - { - this(PKIHeader.CMP_2000, sender, recipient); - } - - /** - * Commence a message with a specific header type. - * - * @param pvno the version CMP_1999 or CMP_2000. - * @param sender message sender. - * @param recipient intended recipient. - */ - public ProtectedPKIMessageBuilder(int pvno, GeneralName sender, GeneralName recipient) - { - hdrBuilder = new PKIHeaderBuilder(pvno, sender, recipient); - } - - /** - * Set the identifier for the transaction the new message will belong to. - * - * @param tid the transaction ID. - * @return the current builder instance. - */ - public ProtectedPKIMessageBuilder setTransactionID(byte[] tid) - { - hdrBuilder.setTransactionID(tid); - - return this; - } - - /** - * Include a human-readable message in the new message. - * - * @param freeText the contents of the human readable message, - * @return the current builder instance. - */ - public ProtectedPKIMessageBuilder setFreeText(PKIFreeText freeText) - { - hdrBuilder.setFreeText(freeText); - - return this; - } - - /** - * Add a generalInfo data record to the header of the new message. - * - * @param genInfo the generalInfo data to be added. - * @return the current builder instance. - */ - public ProtectedPKIMessageBuilder addGeneralInfo(InfoTypeAndValue genInfo) - { - generalInfos.add(genInfo); - - return this; - } - - /** - * Set the creation time for the new message. - * - * @param time the message creation time. - * @return the current builder instance. - */ - public ProtectedPKIMessageBuilder setMessageTime(Date time) - { - hdrBuilder.setMessageTime(new ASN1GeneralizedTime(time)); - - return this; - } - - /** - * Set the recipient key identifier for the key to be used to verify the new message. - * - * @param kid a key identifier. - * @return the current builder instance. - */ - public ProtectedPKIMessageBuilder setRecipKID(byte[] kid) - { - hdrBuilder.setRecipKID(kid); - - return this; - } - - /** - * Set the recipient nonce field on the new message. - * - * @param nonce a NONCE, typically copied from the sender nonce of the previous message. - * @return the current builder instance. - */ - public ProtectedPKIMessageBuilder setRecipNonce(byte[] nonce) - { - hdrBuilder.setRecipNonce(nonce); - - return this; - } - - /** - * Set the sender key identifier for the key used to protect the new message. - * - * @param kid a key identifier. - * @return the current builder instance. - */ - public ProtectedPKIMessageBuilder setSenderKID(byte[] kid) - { - hdrBuilder.setSenderKID(kid); - - return this; - } - - /** - * Set the sender nonce field on the new message. - * - * @param nonce a NONCE, typically 128 bits of random data. - * @return the current builder instance. - */ - public ProtectedPKIMessageBuilder setSenderNonce(byte[] nonce) - { - hdrBuilder.setSenderNonce(nonce); - - return this; - } - - /** - * Set the body for the new message - * - * @param body the message body. - * @return the current builder instance. - */ - public ProtectedPKIMessageBuilder setBody(PKIBody body) - { - this.body = body; - - return this; - } - - /** - * Add an "extra certificate" to the message. - * - * @param extraCert the extra certificate to add. - * @return the current builder instance. - */ - public ProtectedPKIMessageBuilder addCMPCertificate(X509CertificateHolder extraCert) - { - extraCerts.add(extraCert); - - return this; - } - - /** - * Build a protected PKI message which has MAC based integrity protection. - * - * @param macCalculator MAC calculator. - * @return the resulting protected PKI message. - * @throws CMPException if the protection MAC cannot be calculated. - */ - public ProtectedPKIMessage build(MacCalculator macCalculator) - throws CMPException - { - finaliseHeader(macCalculator.getAlgorithmIdentifier()); - - PKIHeader header = hdrBuilder.build(); - - try - { - DERBitString protection = new DERBitString(calculateMac(macCalculator, header, body)); - - return finaliseMessage(header, protection); - } - catch (IOException e) - { - throw new CMPException("unable to encode MAC input: " + e.getMessage(), e); - } - } - - /** - * Build a protected PKI message which has MAC based integrity protection. - * - * @param signer the ContentSigner to be used to calculate the signature. - * @return the resulting protected PKI message. - * @throws CMPException if the protection signature cannot be calculated. - */ - public ProtectedPKIMessage build(ContentSigner signer) - throws CMPException - { - finaliseHeader(signer.getAlgorithmIdentifier()); - - PKIHeader header = hdrBuilder.build(); - - try - { - DERBitString protection = new DERBitString(calculateSignature(signer, header, body)); - - return finaliseMessage(header, protection); - } - catch (IOException e) - { - throw new CMPException("unable to encode signature input: " + e.getMessage(), e); - } - } - - private void finaliseHeader(AlgorithmIdentifier algorithmIdentifier) - { - hdrBuilder.setProtectionAlg(algorithmIdentifier); - - if (!generalInfos.isEmpty()) - { - InfoTypeAndValue[] genInfos = new InfoTypeAndValue[generalInfos.size()]; - - hdrBuilder.setGeneralInfo((InfoTypeAndValue[])generalInfos.toArray(genInfos)); - } - } - - private ProtectedPKIMessage finaliseMessage(PKIHeader header, DERBitString protection) - { - if (!extraCerts.isEmpty()) - { - CMPCertificate[] cmpCerts = new CMPCertificate[extraCerts.size()]; - - for (int i = 0; i != cmpCerts.length; i++) - { - cmpCerts[i] = new CMPCertificate(((X509CertificateHolder)extraCerts.get(i)).toASN1Structure()); - } - - return new ProtectedPKIMessage(new PKIMessage(header, body, protection, cmpCerts)); - } - else - { - return new ProtectedPKIMessage(new PKIMessage(header, body, protection)); - } - } - - private byte[] calculateSignature(ContentSigner signer, PKIHeader header, PKIBody body) - throws IOException - { - ASN1EncodableVector v = new ASN1EncodableVector(); - - v.add(header); - v.add(body); - - OutputStream sOut = signer.getOutputStream(); - - sOut.write(new DERSequence(v).getEncoded(ASN1Encoding.DER)); - - sOut.close(); - - return signer.getSignature(); - } - - private byte[] calculateMac(MacCalculator macCalculator, PKIHeader header, PKIBody body) - throws IOException - { - ASN1EncodableVector v = new ASN1EncodableVector(); - - v.add(header); - v.add(body); - - OutputStream sOut = macCalculator.getOutputStream(); - - sOut.write(new DERSequence(v).getEncoded(ASN1Encoding.DER)); - - sOut.close(); - - return macCalculator.getMac(); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/cmp/RevocationDetails.java b/pkix/src/main/java/org/bouncycastle/cert/cmp/RevocationDetails.java deleted file mode 100644 index f382c69c..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/cmp/RevocationDetails.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.bouncycastle.cert.cmp; - -import java.math.BigInteger; - -import org.bouncycastle.asn1.cmp.RevDetails; -import org.bouncycastle.asn1.x500.X500Name; - -public class RevocationDetails -{ - private RevDetails revDetails; - - public RevocationDetails(RevDetails revDetails) - { - this.revDetails = revDetails; - } - - public X500Name getSubject() - { - return revDetails.getCertDetails().getSubject(); - } - - public X500Name getIssuer() - { - return revDetails.getCertDetails().getIssuer(); - } - - public BigInteger getSerialNumber() - { - return revDetails.getCertDetails().getSerialNumber().getValue(); - } - - public RevDetails toASN1Structure() - { - return revDetails; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/cmp/RevocationDetailsBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/cmp/RevocationDetailsBuilder.java deleted file mode 100644 index e662d28e..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/cmp/RevocationDetailsBuilder.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.bouncycastle.cert.cmp; - -import java.math.BigInteger; - -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.cmp.RevDetails; -import org.bouncycastle.asn1.crmf.CertTemplateBuilder; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; - -public class RevocationDetailsBuilder -{ - private CertTemplateBuilder templateBuilder = new CertTemplateBuilder(); - - public RevocationDetailsBuilder setPublicKey(SubjectPublicKeyInfo publicKey) - { - if (publicKey != null) - { - templateBuilder.setPublicKey(publicKey); - } - - return this; - } - - public RevocationDetailsBuilder setIssuer(X500Name issuer) - { - if (issuer != null) - { - templateBuilder.setIssuer(issuer); - } - - return this; - } - - public RevocationDetailsBuilder setSerialNumber(BigInteger serialNumber) - { - if (serialNumber != null) - { - templateBuilder.setSerialNumber(new ASN1Integer(serialNumber)); - } - - return this; - } - - public RevocationDetailsBuilder setSubject(X500Name subject) - { - if (subject != null) - { - templateBuilder.setSubject(subject); - } - - return this; - } - - public RevocationDetails build() - { - return new RevocationDetails(new RevDetails(templateBuilder.build())); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/AuthenticatorControl.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/AuthenticatorControl.java deleted file mode 100644 index 3cb7f470..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/AuthenticatorControl.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.bouncycastle.cert.crmf; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DERUTF8String; -import org.bouncycastle.asn1.crmf.CRMFObjectIdentifiers; - -/** - * Carrier for an authenticator control. - */ -public class AuthenticatorControl - implements Control -{ - private static final ASN1ObjectIdentifier type = CRMFObjectIdentifiers.id_regCtrl_authenticator; - - private final DERUTF8String token; - - /** - * Basic constructor - build from a UTF-8 string representing the token. - * - * @param token UTF-8 string representing the token. - */ - public AuthenticatorControl(DERUTF8String token) - { - this.token = token; - } - - /** - * Basic constructor - build from a string representing the token. - * - * @param token string representing the token. - */ - public AuthenticatorControl(String token) - { - this.token = new DERUTF8String(token); - } - - /** - * Return the type of this control. - * - * @return CRMFObjectIdentifiers.id_regCtrl_authenticator - */ - public ASN1ObjectIdentifier getType() - { - return type; - } - - /** - * Return the token associated with this control (a UTF8String). - * - * @return a UTF8String. - */ - public ASN1Encodable getValue() - { - return token; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/CRMFException.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/CRMFException.java deleted file mode 100644 index 8ea6ecdc..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/CRMFException.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.bouncycastle.cert.crmf; - -public class CRMFException - extends Exception -{ - private Throwable cause; - - public CRMFException(String msg, Throwable cause) - { - super(msg); - - this.cause = cause; - } - - public Throwable getCause() - { - return cause; - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/CRMFRuntimeException.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/CRMFRuntimeException.java deleted file mode 100644 index 89d6a537..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/CRMFRuntimeException.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.bouncycastle.cert.crmf; - -public class CRMFRuntimeException - extends RuntimeException -{ - private Throwable cause; - - public CRMFRuntimeException(String msg, Throwable cause) - { - super(msg); - - this.cause = cause; - } - - public Throwable getCause() - { - return cause; - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/CRMFUtil.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/CRMFUtil.java deleted file mode 100644 index f314a950..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/CRMFUtil.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.bouncycastle.cert.crmf; - -import java.io.IOException; -import java.io.OutputStream; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DEROutputStream; -import org.bouncycastle.asn1.x509.ExtensionsGenerator; -import org.bouncycastle.cert.CertIOException; - -class CRMFUtil -{ - static void derEncodeToStream(ASN1Encodable obj, OutputStream stream) - { - DEROutputStream dOut = new DEROutputStream(stream); - - try - { - dOut.writeObject(obj); - - dOut.close(); - } - catch (IOException e) - { - throw new CRMFRuntimeException("unable to DER encode object: " + e.getMessage(), e); - } - } - - 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); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/CertificateRequestMessage.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/CertificateRequestMessage.java deleted file mode 100644 index e532c2b5..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/CertificateRequestMessage.java +++ /dev/null @@ -1,309 +0,0 @@ -package org.bouncycastle.cert.crmf; - -import java.io.IOException; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.DERUTF8String; -import org.bouncycastle.asn1.crmf.AttributeTypeAndValue; -import org.bouncycastle.asn1.crmf.CRMFObjectIdentifiers; -import org.bouncycastle.asn1.crmf.CertReqMsg; -import org.bouncycastle.asn1.crmf.CertTemplate; -import org.bouncycastle.asn1.crmf.Controls; -import org.bouncycastle.asn1.crmf.PKIArchiveOptions; -import org.bouncycastle.asn1.crmf.PKMACValue; -import org.bouncycastle.asn1.crmf.POPOSigningKey; -import org.bouncycastle.asn1.crmf.ProofOfPossession; -import org.bouncycastle.cert.CertIOException; -import org.bouncycastle.operator.ContentVerifier; -import org.bouncycastle.operator.ContentVerifierProvider; -import org.bouncycastle.operator.OperatorCreationException; - -/** - * Carrier for a CRMF CertReqMsg. - */ -public class CertificateRequestMessage -{ - public static final int popRaVerified = ProofOfPossession.TYPE_RA_VERIFIED; - public static final int popSigningKey = ProofOfPossession.TYPE_SIGNING_KEY; - public static final int popKeyEncipherment = ProofOfPossession.TYPE_KEY_ENCIPHERMENT; - public static final int popKeyAgreement = ProofOfPossession.TYPE_KEY_AGREEMENT; - - private final CertReqMsg certReqMsg; - private final Controls controls; - - private static CertReqMsg parseBytes(byte[] encoding) - throws IOException - { - try - { - return CertReqMsg.getInstance(ASN1Primitive.fromByteArray(encoding)); - } - catch (ClassCastException e) - { - throw new CertIOException("malformed data: " + e.getMessage(), e); - } - catch (IllegalArgumentException e) - { - throw new CertIOException("malformed data: " + e.getMessage(), e); - } - } - - /** - * Create a CertificateRequestMessage from the passed in bytes. - * - * @param certReqMsg BER/DER encoding of the CertReqMsg structure. - * @throws IOException in the event of corrupted data, or an incorrect structure. - */ - public CertificateRequestMessage(byte[] certReqMsg) - throws IOException - { - this(parseBytes(certReqMsg)); - } - - public CertificateRequestMessage(CertReqMsg certReqMsg) - { - this.certReqMsg = certReqMsg; - this.controls = certReqMsg.getCertReq().getControls(); - } - - /** - * Return the underlying ASN.1 object defining this CertificateRequestMessage object. - * - * @return a CertReqMsg. - */ - public CertReqMsg toASN1Structure() - { - return certReqMsg; - } - - /** - * Return the certificate template contained in this message. - * - * @return a CertTemplate structure. - */ - public CertTemplate getCertTemplate() - { - return this.certReqMsg.getCertReq().getCertTemplate(); - } - - /** - * Return whether or not this request has control values associated with it. - * - * @return true if there are control values present, false otherwise. - */ - public boolean hasControls() - { - return controls != null; - } - - /** - * Return whether or not this request has a specific type of control value. - * - * @param type the type OID for the control value we are checking for. - * @return true if a control value of type is present, false otherwise. - */ - public boolean hasControl(ASN1ObjectIdentifier type) - { - return findControl(type) != null; - } - - /** - * Return a control value of the specified type. - * - * @param type the type OID for the control value we are checking for. - * @return the control value if present, null otherwise. - */ - public Control getControl(ASN1ObjectIdentifier type) - { - AttributeTypeAndValue found = findControl(type); - - if (found != null) - { - if (found.getType().equals(CRMFObjectIdentifiers.id_regCtrl_pkiArchiveOptions)) - { - return new PKIArchiveControl(PKIArchiveOptions.getInstance(found.getValue())); - } - if (found.getType().equals(CRMFObjectIdentifiers.id_regCtrl_regToken)) - { - return new RegTokenControl(DERUTF8String.getInstance(found.getValue())); - } - if (found.getType().equals(CRMFObjectIdentifiers.id_regCtrl_authenticator)) - { - return new AuthenticatorControl(DERUTF8String.getInstance(found.getValue())); - } - } - - return null; - } - - private AttributeTypeAndValue findControl(ASN1ObjectIdentifier type) - { - if (controls == null) - { - return null; - } - - AttributeTypeAndValue[] tAndVs = controls.toAttributeTypeAndValueArray(); - AttributeTypeAndValue found = null; - - for (int i = 0; i != tAndVs.length; i++) - { - if (tAndVs[i].getType().equals(type)) - { - found = tAndVs[i]; - break; - } - } - - return found; - } - - /** - * Return whether or not this request message has a proof-of-possession field in it. - * - * @return true if proof-of-possession is present, false otherwise. - */ - public boolean hasProofOfPossession() - { - return this.certReqMsg.getPopo() != null; - } - - /** - * Return the type of the proof-of-possession this request message provides. - * - * @return one of: popRaVerified, popSigningKey, popKeyEncipherment, popKeyAgreement - */ - public int getProofOfPossessionType() - { - return this.certReqMsg.getPopo().getType(); - } - - /** - * Return whether or not the proof-of-possession (POP) is of the type popSigningKey and - * it has a public key MAC associated with it. - * - * @return true if POP is popSigningKey and a PKMAC is present, false otherwise. - */ - public boolean hasSigningKeyProofOfPossessionWithPKMAC() - { - ProofOfPossession pop = certReqMsg.getPopo(); - - if (pop.getType() == popSigningKey) - { - POPOSigningKey popoSign = POPOSigningKey.getInstance(pop.getObject()); - - return popoSign.getPoposkInput().getPublicKeyMAC() != null; - } - - return false; - } - - /** - * Return whether or not a signing key proof-of-possession (POP) is valid. - * - * @param verifierProvider a provider that can produce content verifiers for the signature contained in this POP. - * @return true if the POP is valid, false otherwise. - * @throws CRMFException if there is a problem in verification or content verifier creation. - * @throws IllegalStateException if POP not appropriate. - */ - public boolean isValidSigningKeyPOP(ContentVerifierProvider verifierProvider) - throws CRMFException, IllegalStateException - { - ProofOfPossession pop = certReqMsg.getPopo(); - - if (pop.getType() == popSigningKey) - { - POPOSigningKey popoSign = POPOSigningKey.getInstance(pop.getObject()); - - if (popoSign.getPoposkInput() != null && popoSign.getPoposkInput().getPublicKeyMAC() != null) - { - throw new IllegalStateException("verification requires password check"); - } - - return verifySignature(verifierProvider, popoSign); - } - else - { - throw new IllegalStateException("not Signing Key type of proof of possession"); - } - } - - /** - * Return whether or not a signing key proof-of-possession (POP), with an associated PKMAC, is valid. - * - * @param verifierProvider a provider that can produce content verifiers for the signature contained in this POP. - * @param macBuilder a suitable PKMACBuilder to create the MAC verifier. - * @param password the password used to key the MAC calculation. - * @return true if the POP is valid, false otherwise. - * @throws CRMFException if there is a problem in verification or content verifier creation. - * @throws IllegalStateException if POP not appropriate. - */ - public boolean isValidSigningKeyPOP(ContentVerifierProvider verifierProvider, PKMACBuilder macBuilder, char[] password) - throws CRMFException, IllegalStateException - { - ProofOfPossession pop = certReqMsg.getPopo(); - - if (pop.getType() == popSigningKey) - { - POPOSigningKey popoSign = POPOSigningKey.getInstance(pop.getObject()); - - if (popoSign.getPoposkInput() == null || popoSign.getPoposkInput().getSender() != null) - { - throw new IllegalStateException("no PKMAC present in proof of possession"); - } - - PKMACValue pkMAC = popoSign.getPoposkInput().getPublicKeyMAC(); - PKMACValueVerifier macVerifier = new PKMACValueVerifier(macBuilder); - - if (macVerifier.isValid(pkMAC, password, this.getCertTemplate().getPublicKey())) - { - return verifySignature(verifierProvider, popoSign); - } - - return false; - } - else - { - throw new IllegalStateException("not Signing Key type of proof of possession"); - } - } - - private boolean verifySignature(ContentVerifierProvider verifierProvider, POPOSigningKey popoSign) - throws CRMFException - { - ContentVerifier verifier; - - try - { - verifier = verifierProvider.get(popoSign.getAlgorithmIdentifier()); - } - catch (OperatorCreationException e) - { - throw new CRMFException("unable to create verifier: " + e.getMessage(), e); - } - - if (popoSign.getPoposkInput() != null) - { - CRMFUtil.derEncodeToStream(popoSign.getPoposkInput(), verifier.getOutputStream()); - } - else - { - CRMFUtil.derEncodeToStream(certReqMsg.getCertReq(), verifier.getOutputStream()); - } - - return verifier.verify(popoSign.getSignature().getBytes()); - } - - /** - * Return the ASN.1 encoding of the certReqMsg we wrap. - * - * @return a byte array containing the binary encoding of the certReqMsg. - * @throws IOException if there is an exception creating the encoding. - */ - public byte[] getEncoded() - throws IOException - { - return certReqMsg.getEncoded(); - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/CertificateRequestMessageBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/CertificateRequestMessageBuilder.java deleted file mode 100644 index aa482357..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/CertificateRequestMessageBuilder.java +++ /dev/null @@ -1,279 +0,0 @@ -package org.bouncycastle.cert.crmf; - -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Date; -import java.util.Iterator; -import java.util.List; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1Null; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.crmf.AttributeTypeAndValue; -import org.bouncycastle.asn1.crmf.CertReqMsg; -import org.bouncycastle.asn1.crmf.CertRequest; -import org.bouncycastle.asn1.crmf.CertTemplate; -import org.bouncycastle.asn1.crmf.CertTemplateBuilder; -import org.bouncycastle.asn1.crmf.OptionalValidity; -import org.bouncycastle.asn1.crmf.POPOPrivKey; -import org.bouncycastle.asn1.crmf.ProofOfPossession; -import org.bouncycastle.asn1.crmf.SubsequentMessage; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.ExtensionsGenerator; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.asn1.x509.Time; -import org.bouncycastle.cert.CertIOException; -import org.bouncycastle.operator.ContentSigner; - -public class CertificateRequestMessageBuilder -{ - private final BigInteger certReqId; - - private ExtensionsGenerator extGenerator; - private CertTemplateBuilder templateBuilder; - private List controls; - private ContentSigner popSigner; - private PKMACBuilder pkmacBuilder; - private char[] password; - private GeneralName sender; - private POPOPrivKey popoPrivKey; - private ASN1Null popRaVerified; - - public CertificateRequestMessageBuilder(BigInteger certReqId) - { - this.certReqId = certReqId; - - this.extGenerator = new ExtensionsGenerator(); - this.templateBuilder = new CertTemplateBuilder(); - this.controls = new ArrayList(); - } - - public CertificateRequestMessageBuilder setPublicKey(SubjectPublicKeyInfo publicKey) - { - if (publicKey != null) - { - templateBuilder.setPublicKey(publicKey); - } - - return this; - } - - public CertificateRequestMessageBuilder setIssuer(X500Name issuer) - { - if (issuer != null) - { - templateBuilder.setIssuer(issuer); - } - - return this; - } - - public CertificateRequestMessageBuilder setSubject(X500Name subject) - { - if (subject != null) - { - templateBuilder.setSubject(subject); - } - - return this; - } - - public CertificateRequestMessageBuilder setSerialNumber(BigInteger serialNumber) - { - if (serialNumber != null) - { - templateBuilder.setSerialNumber(new ASN1Integer(serialNumber)); - } - - return this; - } - - /** - * Request a validity period for the certificate. Either, but not both, of the date parameters may be null. - * - * @param notBeforeDate not before date for certificate requested. - * @param notAfterDate not after date for the certificate requested. - * - * @return the current builder. - */ - public CertificateRequestMessageBuilder setValidity(Date notBeforeDate, Date notAfterDate) - { - templateBuilder.setValidity(new OptionalValidity(createTime(notBeforeDate), createTime(notAfterDate))); - - return this; - } - - private Time createTime(Date date) - { - if (date != null) - { - return new Time(date); - } - - return null; - } - - public CertificateRequestMessageBuilder addExtension( - ASN1ObjectIdentifier oid, - boolean critical, - ASN1Encodable value) - throws CertIOException - { - CRMFUtil.addExtension(extGenerator, oid, critical, value); - - return this; - } - - public CertificateRequestMessageBuilder addExtension( - ASN1ObjectIdentifier oid, - boolean critical, - byte[] value) - { - extGenerator.addExtension(oid, critical, value); - - return this; - } - - public CertificateRequestMessageBuilder addControl(Control control) - { - controls.add(control); - - return this; - } - - public CertificateRequestMessageBuilder setProofOfPossessionSigningKeySigner(ContentSigner popSigner) - { - if (popoPrivKey != null || popRaVerified != null) - { - throw new IllegalStateException("only one proof of possession allowed"); - } - - this.popSigner = popSigner; - - return this; - } - - public CertificateRequestMessageBuilder setProofOfPossessionSubsequentMessage(SubsequentMessage msg) - { - if (popSigner != null || popRaVerified != null) - { - throw new IllegalStateException("only one proof of possession allowed"); - } - - this.popoPrivKey = new POPOPrivKey(msg); - - return this; - } - - public CertificateRequestMessageBuilder setProofOfPossessionRaVerified() - { - if (popSigner != null || popoPrivKey != null) - { - throw new IllegalStateException("only one proof of possession allowed"); - } - - this.popRaVerified = DERNull.INSTANCE; - - return this; - } - - public CertificateRequestMessageBuilder setAuthInfoPKMAC(PKMACBuilder pkmacBuilder, char[] password) - { - this.pkmacBuilder = pkmacBuilder; - this.password = password; - - return this; - } - - public CertificateRequestMessageBuilder setAuthInfoSender(X500Name sender) - { - return setAuthInfoSender(new GeneralName(sender)); - } - - public CertificateRequestMessageBuilder setAuthInfoSender(GeneralName sender) - { - this.sender = sender; - - return this; - } - - public CertificateRequestMessage build() - throws CRMFException - { - ASN1EncodableVector v = new ASN1EncodableVector(); - - v.add(new ASN1Integer(certReqId)); - - if (!extGenerator.isEmpty()) - { - templateBuilder.setExtensions(extGenerator.generate()); - } - - v.add(templateBuilder.build()); - - if (!controls.isEmpty()) - { - ASN1EncodableVector controlV = new ASN1EncodableVector(); - - for (Iterator it = controls.iterator(); it.hasNext();) - { - Control control = (Control)it.next(); - - controlV.add(new AttributeTypeAndValue(control.getType(), control.getValue())); - } - - v.add(new DERSequence(controlV)); - } - - CertRequest request = CertRequest.getInstance(new DERSequence(v)); - - v = new ASN1EncodableVector(); - - v.add(request); - - if (popSigner != null) - { - CertTemplate template = request.getCertTemplate(); - - if (template.getSubject() == null || template.getPublicKey() == null) - { - SubjectPublicKeyInfo pubKeyInfo = request.getCertTemplate().getPublicKey(); - ProofOfPossessionSigningKeyBuilder builder = new ProofOfPossessionSigningKeyBuilder(pubKeyInfo); - - if (sender != null) - { - builder.setSender(sender); - } - else - { - PKMACValueGenerator pkmacGenerator = new PKMACValueGenerator(pkmacBuilder); - - builder.setPublicKeyMac(pkmacGenerator, password); - } - - v.add(new ProofOfPossession(builder.build(popSigner))); - } - else - { - ProofOfPossessionSigningKeyBuilder builder = new ProofOfPossessionSigningKeyBuilder(request); - - v.add(new ProofOfPossession(builder.build(popSigner))); - } - } - else if (popoPrivKey != null) - { - v.add(new ProofOfPossession(ProofOfPossession.TYPE_KEY_ENCIPHERMENT, popoPrivKey)); - } - else if (popRaVerified != null) - { - v.add(new ProofOfPossession()); - } - - return new CertificateRequestMessage(CertReqMsg.getInstance(new DERSequence(v))); - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/Control.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/Control.java deleted file mode 100644 index f86f8a0f..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/Control.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.bouncycastle.cert.crmf; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; - -/** - * Generic interface for a CertificateRequestMessage control value. - */ -public interface Control -{ - /** - * Return the type of this control. - * - * @return an ASN1ObjectIdentifier representing the type. - */ - ASN1ObjectIdentifier getType(); - - /** - * Return the value contained in this control object. - * - * @return the value of the control. - */ - ASN1Encodable getValue(); -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/EncryptedValueBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/EncryptedValueBuilder.java deleted file mode 100644 index 55187b5b..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/EncryptedValueBuilder.java +++ /dev/null @@ -1,133 +0,0 @@ -package org.bouncycastle.cert.crmf; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.crmf.EncryptedValue; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.operator.KeyWrapper; -import org.bouncycastle.operator.OperatorException; -import org.bouncycastle.operator.OutputEncryptor; -import org.bouncycastle.util.Strings; - -/** - * Builder for EncryptedValue structures. - */ -public class EncryptedValueBuilder -{ - private KeyWrapper wrapper; - private OutputEncryptor encryptor; - private EncryptedValuePadder padder; - - /** - * Create a builder that makes EncryptedValue structures. - * - * @param wrapper a wrapper for key used to encrypt the actual data contained in the EncryptedValue. - * @param encryptor an output encryptor to encrypt the actual data contained in the EncryptedValue. - */ - public EncryptedValueBuilder(KeyWrapper wrapper, OutputEncryptor encryptor) - { - this(wrapper, encryptor, null); - } - - /** - * Create a builder that makes EncryptedValue structures with fixed length blocks padded using the passed in padder. - * - * @param wrapper a wrapper for key used to encrypt the actual data contained in the EncryptedValue. - * @param encryptor an output encryptor to encrypt the actual data contained in the EncryptedValue. - * @param padder a padder to ensure that the EncryptedValue created will always be a constant length. - */ - public EncryptedValueBuilder(KeyWrapper wrapper, OutputEncryptor encryptor, EncryptedValuePadder padder) - { - this.wrapper = wrapper; - this.encryptor = encryptor; - this.padder = padder; - } - - /** - * Build an EncryptedValue structure containing the passed in pass phrase. - * - * @param revocationPassphrase a revocation pass phrase. - * @return an EncryptedValue containing the encrypted pass phrase. - * @throws CRMFException on a failure to encrypt the data, or wrap the symmetric key for this value. - */ - public EncryptedValue build(char[] revocationPassphrase) - throws CRMFException - { - return encryptData(padData(Strings.toUTF8ByteArray(revocationPassphrase))); - } - - /** - * Build an EncryptedValue structure containing the certificate contained in - * the passed in holder. - * - * @param holder a holder containing a certificate. - * @return an EncryptedValue containing the encrypted certificate. - * @throws CRMFException on a failure to encrypt the data, or wrap the symmetric key for this value. - */ - public EncryptedValue build(X509CertificateHolder holder) - throws CRMFException - { - try - { - return encryptData(padData(holder.getEncoded())); - } - catch (IOException e) - { - throw new CRMFException("cannot encode certificate: " + e.getMessage(), e); - } - } - - private EncryptedValue encryptData(byte[] data) - throws CRMFException - { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - - OutputStream eOut = encryptor.getOutputStream(bOut); - - try - { - eOut.write(data); - - eOut.close(); - } - catch (IOException e) - { - throw new CRMFException("cannot process data: " + e.getMessage(), e); - } - - AlgorithmIdentifier intendedAlg = null; - AlgorithmIdentifier symmAlg = encryptor.getAlgorithmIdentifier(); - DERBitString encSymmKey; - - try - { - wrapper.generateWrappedKey(encryptor.getKey()); - encSymmKey = new DERBitString(wrapper.generateWrappedKey(encryptor.getKey())); - } - catch (OperatorException e) - { - throw new CRMFException("cannot wrap key: " + e.getMessage(), e); - } - - AlgorithmIdentifier keyAlg = wrapper.getAlgorithmIdentifier(); - ASN1OctetString valueHint = null; - DERBitString encValue = new DERBitString(bOut.toByteArray()); - - return new EncryptedValue(intendedAlg, symmAlg, encSymmKey, keyAlg, valueHint, encValue); - } - - private byte[] padData(byte[] data) - { - if (padder != null) - { - return padder.getPaddedData(data); - } - - return data; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/EncryptedValuePadder.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/EncryptedValuePadder.java deleted file mode 100644 index 41ca8668..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/EncryptedValuePadder.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.bouncycastle.cert.crmf; - -/** - * An encrypted value padder is used to make sure that prior to a value been - * encrypted the data is padded to a standard length. - */ -public interface EncryptedValuePadder -{ - /** - * Return a byte array of padded data. - * - * @param data the data to be padded. - * @return a padded byte array containing data. - */ - byte[] getPaddedData(byte[] data); - - /** - * Return a byte array of with padding removed. - * - * @param paddedData the data to be padded. - * @return an array containing the original unpadded data. - */ - byte[] getUnpaddedData(byte[] paddedData); -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/EncryptedValueParser.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/EncryptedValueParser.java deleted file mode 100644 index 6c0aa877..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/EncryptedValueParser.java +++ /dev/null @@ -1,103 +0,0 @@ -package org.bouncycastle.cert.crmf; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; - -import org.bouncycastle.asn1.crmf.EncryptedValue; -import org.bouncycastle.asn1.x509.Certificate; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.operator.InputDecryptor; -import org.bouncycastle.util.Strings; -import org.bouncycastle.util.io.Streams; - -/** - * Parser for EncryptedValue structures. - */ -public class EncryptedValueParser -{ - private EncryptedValue value; - private EncryptedValuePadder padder; - - /** - * Basic constructor - create a parser to read the passed in value. - * - * @param value the value to be parsed. - */ - public EncryptedValueParser(EncryptedValue value) - { - this.value = value; - } - - /** - * Create a parser to read the passed in value, assuming the padder was - * applied to the data prior to encryption. - * - * @param value the value to be parsed. - * @param padder the padder to be used to remove padding from the decrypted value.. - */ - public EncryptedValueParser(EncryptedValue value, EncryptedValuePadder padder) - { - this.value = value; - this.padder = padder; - } - - private byte[] decryptValue(ValueDecryptorGenerator decGen) - throws CRMFException - { - if (value.getIntendedAlg() != null) - { - throw new UnsupportedOperationException(); - } - if (value.getValueHint() != null) - { - throw new UnsupportedOperationException(); - } - - InputDecryptor decryptor = decGen.getValueDecryptor(value.getKeyAlg(), - value.getSymmAlg(), value.getEncSymmKey().getBytes()); - InputStream dataIn = decryptor.getInputStream(new ByteArrayInputStream( - value.getEncValue().getBytes())); - try - { - byte[] data = Streams.readAll(dataIn); - - if (padder != null) - { - return padder.getUnpaddedData(data); - } - - return data; - } - catch (IOException e) - { - throw new CRMFException("Cannot parse decrypted data: " + e.getMessage(), e); - } - } - - /** - * Read a X.509 certificate. - * - * @param decGen the decryptor generator to decrypt the encrypted value. - * @return an X509CertificateHolder containing the certificate read. - * @throws CRMFException if the decrypted data cannot be parsed, or a decryptor cannot be generated. - */ - public X509CertificateHolder readCertificateHolder(ValueDecryptorGenerator decGen) - throws CRMFException - { - return new X509CertificateHolder(Certificate.getInstance(decryptValue(decGen))); - } - - /** - * Read a pass phrase. - * - * @param decGen the decryptor generator to decrypt the encrypted value. - * @return a pass phrase as recovered from the encrypted value. - * @throws CRMFException if the decrypted data cannot be parsed, or a decryptor cannot be generated. - */ - public char[] readPassphrase(ValueDecryptorGenerator decGen) - throws CRMFException - { - return Strings.fromUTF8ByteArray(decryptValue(decGen)).toCharArray(); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/PKIArchiveControl.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/PKIArchiveControl.java deleted file mode 100644 index 7bc99579..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/PKIArchiveControl.java +++ /dev/null @@ -1,104 +0,0 @@ -package org.bouncycastle.cert.crmf; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.cms.EnvelopedData; -import org.bouncycastle.asn1.crmf.CRMFObjectIdentifiers; -import org.bouncycastle.asn1.crmf.EncryptedKey; -import org.bouncycastle.asn1.crmf.PKIArchiveOptions; -import org.bouncycastle.cms.CMSEnvelopedData; -import org.bouncycastle.cms.CMSException; - -/** - * Carrier for a PKIArchiveOptions structure. - */ -public class PKIArchiveControl - implements Control -{ - public static final int encryptedPrivKey = PKIArchiveOptions.encryptedPrivKey; - public static final int keyGenParameters = PKIArchiveOptions.keyGenParameters; - public static final int archiveRemGenPrivKey = PKIArchiveOptions.archiveRemGenPrivKey; - - private static final ASN1ObjectIdentifier type = CRMFObjectIdentifiers.id_regCtrl_pkiArchiveOptions; - - private final PKIArchiveOptions pkiArchiveOptions; - - /** - * Basic constructor - build from an PKIArchiveOptions structure. - * - * @param pkiArchiveOptions the ASN.1 structure that will underlie this control. - */ - public PKIArchiveControl(PKIArchiveOptions pkiArchiveOptions) - { - this.pkiArchiveOptions = pkiArchiveOptions; - } - - /** - * Return the type of this control. - * - * @return CRMFObjectIdentifiers.id_regCtrl_pkiArchiveOptions - */ - public ASN1ObjectIdentifier getType() - { - return type; - } - - /** - * Return the underlying ASN.1 object. - * - * @return a PKIArchiveOptions structure. - */ - public ASN1Encodable getValue() - { - return pkiArchiveOptions; - } - - /** - * Return the archive control type, one of: encryptedPrivKey,keyGenParameters,or archiveRemGenPrivKey. - * - * @return the archive control type. - */ - public int getArchiveType() - { - return pkiArchiveOptions.getType(); - } - - /** - * Return whether this control contains enveloped data. - * - * @return true if the control contains enveloped data, false otherwise. - */ - public boolean isEnvelopedData() - { - EncryptedKey encKey = EncryptedKey.getInstance(pkiArchiveOptions.getValue()); - - return !encKey.isEncryptedValue(); - } - - /** - * Return the enveloped data structure contained in this control. - * - * @return a CMSEnvelopedData object. - */ - public CMSEnvelopedData getEnvelopedData() - throws CRMFException - { - try - { - EncryptedKey encKey = EncryptedKey.getInstance(pkiArchiveOptions.getValue()); - EnvelopedData data = EnvelopedData.getInstance(encKey.getValue()); - - return new CMSEnvelopedData(new ContentInfo(CMSObjectIdentifiers.envelopedData, data)); - } - catch (CMSException e) - { - throw new CRMFException("CMS parsing error: " + e.getMessage(), e.getCause()); - } - catch (Exception e) - { - throw new CRMFException("CRMF parsing error: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/PKIArchiveControlBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/PKIArchiveControlBuilder.java deleted file mode 100644 index 9edf75c7..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/PKIArchiveControlBuilder.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.bouncycastle.cert.crmf; - -import java.io.IOException; - -import org.bouncycastle.asn1.cms.EnvelopedData; -import org.bouncycastle.asn1.crmf.CRMFObjectIdentifiers; -import org.bouncycastle.asn1.crmf.EncKeyWithID; -import org.bouncycastle.asn1.crmf.EncryptedKey; -import org.bouncycastle.asn1.crmf.PKIArchiveOptions; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.cms.CMSEnvelopedData; -import org.bouncycastle.cms.CMSEnvelopedDataGenerator; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.CMSProcessableByteArray; -import org.bouncycastle.cms.RecipientInfoGenerator; -import org.bouncycastle.operator.OutputEncryptor; - -/** - * Builder for a PKIArchiveControl structure. - */ -public class PKIArchiveControlBuilder -{ - private CMSEnvelopedDataGenerator envGen; - private CMSProcessableByteArray keyContent; - - /** - * Basic constructor - specify the contents of the PKIArchiveControl structure. - * - * @param privateKeyInfo the private key to be archived. - * @param generalName the general name to be associated with the private key. - */ - public PKIArchiveControlBuilder(PrivateKeyInfo privateKeyInfo, GeneralName generalName) - { - EncKeyWithID encKeyWithID = new EncKeyWithID(privateKeyInfo, generalName); - - try - { - this.keyContent = new CMSProcessableByteArray(CRMFObjectIdentifiers.id_ct_encKeyWithID, encKeyWithID.getEncoded()); - } - catch (IOException e) - { - throw new IllegalStateException("unable to encode key and general name info"); - } - - this.envGen = new CMSEnvelopedDataGenerator(); - } - - /** - * Add a recipient generator to this control. - * - * @param recipientGen recipient generator created for a specific recipient. - * @return this builder object. - */ - public PKIArchiveControlBuilder addRecipientGenerator(RecipientInfoGenerator recipientGen) - { - envGen.addRecipientInfoGenerator(recipientGen); - - return this; - } - - /** - * Build the PKIArchiveControl using the passed in encryptor to encrypt its contents. - * - * @param contentEncryptor a suitable content encryptor. - * @return a PKIArchiveControl object. - * @throws CMSException in the event the build fails. - */ - public PKIArchiveControl build(OutputEncryptor contentEncryptor) - throws CMSException - { - CMSEnvelopedData envContent = envGen.generate(keyContent, contentEncryptor); - - EnvelopedData envD = EnvelopedData.getInstance(envContent.toASN1Structure().getContent()); - - return new PKIArchiveControl(new PKIArchiveOptions(new EncryptedKey(envD))); - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/PKMACBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/PKMACBuilder.java deleted file mode 100644 index abbdaed8..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/PKMACBuilder.java +++ /dev/null @@ -1,199 +0,0 @@ -package org.bouncycastle.cert.crmf; - -import java.io.ByteArrayOutputStream; -import java.io.OutputStream; -import java.security.SecureRandom; - -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.cmp.CMPObjectIdentifiers; -import org.bouncycastle.asn1.cmp.PBMParameter; -import org.bouncycastle.asn1.iana.IANAObjectIdentifiers; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.MacCalculator; -import org.bouncycastle.operator.RuntimeOperatorException; -import org.bouncycastle.util.Strings; - -public class PKMACBuilder -{ - private AlgorithmIdentifier owf; - private int iterationCount; - private AlgorithmIdentifier mac; - private int saltLength = 20; - private SecureRandom random; - private PKMACValuesCalculator calculator; - private PBMParameter parameters; - private int maxIterations; - - public PKMACBuilder(PKMACValuesCalculator calculator) - { - this(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1), 1000, new AlgorithmIdentifier(IANAObjectIdentifiers.hmacSHA1, DERNull.INSTANCE), calculator); - } - - /** - * Create a PKMAC builder enforcing a ceiling on the maximum iteration count. - * - * @param calculator supporting calculator - * @param maxIterations max allowable value for iteration count. - */ - public PKMACBuilder(PKMACValuesCalculator calculator, int maxIterations) - { - this.maxIterations = maxIterations; - this.calculator = calculator; - } - - private PKMACBuilder(AlgorithmIdentifier hashAlgorithm, int iterationCount, AlgorithmIdentifier macAlgorithm, PKMACValuesCalculator calculator) - { - this.owf = hashAlgorithm; - this.iterationCount = iterationCount; - this.mac = macAlgorithm; - this.calculator = calculator; - } - - /** - * Set the salt length in octets. - * - * @param saltLength length in octets of the salt to be generated. - * @return the generator - */ - public PKMACBuilder setSaltLength(int saltLength) - { - if (saltLength < 8) - { - throw new IllegalArgumentException("salt length must be at least 8 bytes"); - } - - this.saltLength = saltLength; - - return this; - } - - public PKMACBuilder setIterationCount(int iterationCount) - { - if (iterationCount < 100) - { - throw new IllegalArgumentException("iteration count must be at least 100"); - } - checkIterationCountCeiling(iterationCount); - - this.iterationCount = iterationCount; - - return this; - } - - public PKMACBuilder setSecureRandom(SecureRandom random) - { - this.random = random; - - return this; - } - - public PKMACBuilder setParameters(PBMParameter parameters) - { - checkIterationCountCeiling(parameters.getIterationCount().getValue().intValue()); - - this.parameters = parameters; - - return this; - } - - public MacCalculator build(char[] password) - throws CRMFException - { - if (parameters != null) - { - return genCalculator(parameters, password); - } - else - { - byte[] salt = new byte[saltLength]; - - if (random == null) - { - this.random = new SecureRandom(); - } - - random.nextBytes(salt); - - return genCalculator(new PBMParameter(salt, owf, iterationCount, mac), password); - } - } - - private void checkIterationCountCeiling(int iterationCount) - { - if (maxIterations > 0 && iterationCount > maxIterations) - { - throw new IllegalArgumentException("iteration count exceeds limit (" + iterationCount + " > " + maxIterations + ")"); - } - } - - private MacCalculator genCalculator(final PBMParameter params, char[] password) - throws CRMFException - { - // From RFC 4211 - // - // 1. Generate a random salt value S - // - // 2. Append the salt to the pw. K = pw || salt. - // - // 3. Hash the value of K. K = HASH(K) - // - // 4. Iter = Iter - 1. If Iter is greater than zero. Goto step 3. - // - // 5. Compute an HMAC as documented in [HMAC]. - // - // MAC = HASH( K XOR opad, HASH( K XOR ipad, data) ) - // - // Where opad and ipad are defined in [HMAC]. - byte[] pw = Strings.toUTF8ByteArray(password); - byte[] salt = params.getSalt().getOctets(); - byte[] K = new byte[pw.length + salt.length]; - - System.arraycopy(pw, 0, K, 0, pw.length); - System.arraycopy(salt, 0, K, pw.length, salt.length); - - calculator.setup(params.getOwf(), params.getMac()); - - int iter = params.getIterationCount().getValue().intValue(); - do - { - K = calculator.calculateDigest(K); - } - while (--iter > 0); - - final byte[] key = K; - - return new MacCalculator() - { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return new AlgorithmIdentifier(CMPObjectIdentifiers.passwordBasedMac, params); - } - - public GenericKey getKey() - { - return new GenericKey(getAlgorithmIdentifier(), key); - } - - public OutputStream getOutputStream() - { - return bOut; - } - - public byte[] getMac() - { - try - { - return calculator.calculateMac(key, bOut.toByteArray()); - } - catch (CRMFException e) - { - throw new RuntimeOperatorException("exception calculating mac: " + e.getMessage(), e); - } - } - }; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/PKMACValueGenerator.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/PKMACValueGenerator.java deleted file mode 100644 index 2457687d..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/PKMACValueGenerator.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.bouncycastle.cert.crmf; - -import java.io.IOException; -import java.io.OutputStream; - -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.crmf.PKMACValue; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.operator.MacCalculator; - -class PKMACValueGenerator -{ - private PKMACBuilder builder; - - public PKMACValueGenerator(PKMACBuilder builder) - { - this.builder = builder; - } - - public PKMACValue generate(char[] password, SubjectPublicKeyInfo keyInfo) - throws CRMFException - { - MacCalculator calculator = builder.build(password); - - OutputStream macOut = calculator.getOutputStream(); - - try - { - macOut.write(keyInfo.getEncoded(ASN1Encoding.DER)); - - macOut.close(); - } - catch (IOException e) - { - throw new CRMFException("exception encoding mac input: " + e.getMessage(), e); - } - - return new PKMACValue(calculator.getAlgorithmIdentifier(), new DERBitString(calculator.getMac())); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/PKMACValueVerifier.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/PKMACValueVerifier.java deleted file mode 100644 index 1d8c3692..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/PKMACValueVerifier.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.bouncycastle.cert.crmf; - -import java.io.IOException; -import java.io.OutputStream; - -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.cmp.PBMParameter; -import org.bouncycastle.asn1.crmf.PKMACValue; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.operator.MacCalculator; -import org.bouncycastle.util.Arrays; - -class PKMACValueVerifier -{ - private final PKMACBuilder builder; - - public PKMACValueVerifier(PKMACBuilder builder) - { - this.builder = builder; - } - - public boolean isValid(PKMACValue value, char[] password, SubjectPublicKeyInfo keyInfo) - throws CRMFException - { - builder.setParameters(PBMParameter.getInstance(value.getAlgId().getParameters())); - MacCalculator calculator = builder.build(password); - - OutputStream macOut = calculator.getOutputStream(); - - try - { - macOut.write(keyInfo.getEncoded(ASN1Encoding.DER)); - - macOut.close(); - } - catch (IOException e) - { - throw new CRMFException("exception encoding mac input: " + e.getMessage(), e); - } - - return Arrays.areEqual(calculator.getMac(), value.getValue().getBytes()); - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/PKMACValuesCalculator.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/PKMACValuesCalculator.java deleted file mode 100644 index 2813b6c0..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/PKMACValuesCalculator.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.bouncycastle.cert.crmf; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -public interface PKMACValuesCalculator -{ - void setup(AlgorithmIdentifier digestAlg, AlgorithmIdentifier macAlg) - throws CRMFException; - - byte[] calculateDigest(byte[] data) - throws CRMFException; - - byte[] calculateMac(byte[] pwd, byte[] data) - throws CRMFException; -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/ProofOfPossessionSigningKeyBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/ProofOfPossessionSigningKeyBuilder.java deleted file mode 100644 index 72979801..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/ProofOfPossessionSigningKeyBuilder.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.bouncycastle.cert.crmf; - -import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.crmf.CertRequest; -import org.bouncycastle.asn1.crmf.PKMACValue; -import org.bouncycastle.asn1.crmf.POPOSigningKey; -import org.bouncycastle.asn1.crmf.POPOSigningKeyInput; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.operator.ContentSigner; - -public class ProofOfPossessionSigningKeyBuilder -{ - private CertRequest certRequest; - private SubjectPublicKeyInfo pubKeyInfo; - private GeneralName name; - private PKMACValue publicKeyMAC; - - public ProofOfPossessionSigningKeyBuilder(CertRequest certRequest) - { - this.certRequest = certRequest; - } - - - public ProofOfPossessionSigningKeyBuilder(SubjectPublicKeyInfo pubKeyInfo) - { - this.pubKeyInfo = pubKeyInfo; - } - - public ProofOfPossessionSigningKeyBuilder setSender(GeneralName name) - { - this.name = name; - - return this; - } - - public ProofOfPossessionSigningKeyBuilder setPublicKeyMac(PKMACValueGenerator generator, char[] password) - throws CRMFException - { - this.publicKeyMAC = generator.generate(password, pubKeyInfo); - - return this; - } - - public POPOSigningKey build(ContentSigner signer) - { - if (name != null && publicKeyMAC != null) - { - throw new IllegalStateException("name and publicKeyMAC cannot both be set."); - } - - POPOSigningKeyInput popo; - - if (certRequest != null) - { - popo = null; - - CRMFUtil.derEncodeToStream(certRequest, signer.getOutputStream()); - } - else if (name != null) - { - popo = new POPOSigningKeyInput(name, pubKeyInfo); - - CRMFUtil.derEncodeToStream(popo, signer.getOutputStream()); - } - else - { - popo = new POPOSigningKeyInput(publicKeyMAC, pubKeyInfo); - - CRMFUtil.derEncodeToStream(popo, signer.getOutputStream()); - } - - return new POPOSigningKey(popo, signer.getAlgorithmIdentifier(), new DERBitString(signer.getSignature())); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/RegTokenControl.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/RegTokenControl.java deleted file mode 100644 index 81af172c..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/RegTokenControl.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.bouncycastle.cert.crmf; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DERUTF8String; -import org.bouncycastle.asn1.crmf.CRMFObjectIdentifiers; - -/** - * Carrier for a registration token control. - */ -public class RegTokenControl - implements Control -{ - private static final ASN1ObjectIdentifier type = CRMFObjectIdentifiers.id_regCtrl_regToken; - - private final DERUTF8String token; - - /** - * Basic constructor - build from a UTF-8 string representing the token. - * - * @param token UTF-8 string representing the token. - */ - public RegTokenControl(DERUTF8String token) - { - this.token = token; - } - - /** - * Basic constructor - build from a string representing the token. - * - * @param token string representing the token. - */ - public RegTokenControl(String token) - { - this.token = new DERUTF8String(token); - } - - /** - * Return the type of this control. - * - * @return CRMFObjectIdentifiers.id_regCtrl_regToken - */ - public ASN1ObjectIdentifier getType() - { - return type; - } - - /** - * Return the token associated with this control (a UTF8String). - * - * @return a UTF8String. - */ - public ASN1Encodable getValue() - { - return token; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/ValueDecryptorGenerator.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/ValueDecryptorGenerator.java deleted file mode 100644 index 7125f56f..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/ValueDecryptorGenerator.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.bouncycastle.cert.crmf; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.operator.InputDecryptor; - -public interface ValueDecryptorGenerator -{ - InputDecryptor getValueDecryptor(AlgorithmIdentifier keyAlg, AlgorithmIdentifier symmAlg, byte[] encKey) - throws CRMFException; -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/bc/BcFixedLengthMGF1Padder.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/bc/BcFixedLengthMGF1Padder.java deleted file mode 100644 index 9fa53d62..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/bc/BcFixedLengthMGF1Padder.java +++ /dev/null @@ -1,121 +0,0 @@ -package org.bouncycastle.cert.crmf.bc; - -import java.security.SecureRandom; - -import org.bouncycastle.cert.crmf.EncryptedValuePadder; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.generators.MGF1BytesGenerator; -import org.bouncycastle.crypto.params.MGFParameters; - -/** - * An encrypted value padder that uses MGF1 as the basis of the padding. - */ -public class BcFixedLengthMGF1Padder - implements EncryptedValuePadder -{ - private int length; - private SecureRandom random; - private Digest dig = new SHA1Digest(); - - /** - * Create a padder to so that padded output will always be at least - * length bytes long. - * - * @param length fixed length for padded output. - */ - public BcFixedLengthMGF1Padder(int length) - { - this(length, null); - } - - /** - * Create a padder to so that padded output will always be at least - * length bytes long, using the passed in source of randomness to - * provide the random material for the padder. - * - * @param length fixed length for padded output. - * @param random a source of randomness. - */ - public BcFixedLengthMGF1Padder(int length, SecureRandom random) - { - this.length = length; - this.random = random; - } - - public byte[] getPaddedData(byte[] data) - { - byte[] bytes = new byte[length]; - byte[] seed = new byte[dig.getDigestSize()]; - byte[] mask = new byte[length - dig.getDigestSize()]; - - if (random == null) - { - random = new SecureRandom(); - } - - random.nextBytes(seed); - - MGF1BytesGenerator maskGen = new MGF1BytesGenerator(dig); - - maskGen.init(new MGFParameters(seed)); - - maskGen.generateBytes(mask, 0, mask.length); - - System.arraycopy(seed, 0, bytes, 0, seed.length); - System.arraycopy(data, 0, bytes, seed.length, data.length); - - for (int i = seed.length + data.length + 1; i != bytes.length; i++) - { - bytes[i] = (byte)(1 + random.nextInt(255)); - } - - for (int i = 0; i != mask.length; i++) - { - bytes[i + seed.length] ^= mask[i]; - } - - return bytes; - } - - public byte[] getUnpaddedData(byte[] paddedData) - { - byte[] seed = new byte[dig.getDigestSize()]; - byte[] mask = new byte[length - dig.getDigestSize()]; - - System.arraycopy(paddedData, 0, seed, 0, seed.length); - - MGF1BytesGenerator maskGen = new MGF1BytesGenerator(dig); - - maskGen.init(new MGFParameters(seed)); - - maskGen.generateBytes(mask, 0, mask.length); - - for (int i = 0; i != mask.length; i++) - { - paddedData[i + seed.length] ^= mask[i]; - } - - int end = 0; - - for (int i = paddedData.length - 1; i != seed.length; i--) - { - if (paddedData[i] == 0) - { - end = i; - break; - } - } - - if (end == 0) - { - throw new IllegalStateException("bad padding in encoding"); - } - - byte[] data = new byte[end - seed.length]; - - System.arraycopy(paddedData, seed.length, data, 0, data.length); - - return data; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/CRMFHelper.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/CRMFHelper.java deleted file mode 100644 index 4878615b..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/CRMFHelper.java +++ /dev/null @@ -1,450 +0,0 @@ -package org.bouncycastle.cert.crmf.jcajce; - -import java.io.IOException; -import java.security.AlgorithmParameterGenerator; -import java.security.AlgorithmParameters; -import java.security.GeneralSecurityException; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.KeyFactory; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.spec.InvalidParameterSpecException; -import java.security.spec.X509EncodedKeySpec; -import java.util.HashMap; -import java.util.Map; - -import javax.crypto.Cipher; -import javax.crypto.KeyGenerator; -import javax.crypto.Mac; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.SecretKey; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.RC2ParameterSpec; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1Null; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.iana.IANAObjectIdentifiers; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; -import org.bouncycastle.cert.crmf.CRMFException; -import org.bouncycastle.cms.CMSAlgorithm; -import org.bouncycastle.jcajce.util.JcaJceHelper; -import org.bouncycastle.jcajce.util.JcaJceUtils; - -class CRMFHelper -{ - protected static final Map BASE_CIPHER_NAMES = new HashMap(); - protected static final Map CIPHER_ALG_NAMES = new HashMap(); - protected static final Map DIGEST_ALG_NAMES = new HashMap(); - protected static final Map KEY_ALG_NAMES = new HashMap(); - protected static final Map MAC_ALG_NAMES = new HashMap(); - - static - { - BASE_CIPHER_NAMES.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESEDE"); - BASE_CIPHER_NAMES.put(NISTObjectIdentifiers.id_aes128_CBC, "AES"); - BASE_CIPHER_NAMES.put(NISTObjectIdentifiers.id_aes192_CBC, "AES"); - BASE_CIPHER_NAMES.put(NISTObjectIdentifiers.id_aes256_CBC, "AES"); - - CIPHER_ALG_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDE/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(CMSAlgorithm.AES128_CBC, "AES/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(CMSAlgorithm.AES192_CBC, "AES/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(CMSAlgorithm.AES256_CBC, "AES/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(new ASN1ObjectIdentifier(PKCSObjectIdentifiers.rsaEncryption.getId()), "RSA/ECB/PKCS1Padding"); - - DIGEST_ALG_NAMES.put(OIWObjectIdentifiers.idSHA1, "SHA1"); - DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha224, "SHA224"); - DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha256, "SHA256"); - DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha384, "SHA384"); - DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha512, "SHA512"); - - MAC_ALG_NAMES.put(IANAObjectIdentifiers.hmacSHA1, "HMACSHA1"); - MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA1, "HMACSHA1"); - MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA224, "HMACSHA224"); - MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA256, "HMACSHA256"); - MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA384, "HMACSHA384"); - MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA512, "HMACSHA512"); - - KEY_ALG_NAMES.put(PKCSObjectIdentifiers.rsaEncryption, "RSA"); - KEY_ALG_NAMES.put(X9ObjectIdentifiers.id_dsa, "DSA"); - } - - private JcaJceHelper helper; - - CRMFHelper(JcaJceHelper helper) - { - this.helper = helper; - } - - PublicKey toPublicKey(SubjectPublicKeyInfo subjectPublicKeyInfo) - throws CRMFException - { - try - { - X509EncodedKeySpec xspec = new X509EncodedKeySpec(subjectPublicKeyInfo.getEncoded()); - AlgorithmIdentifier keyAlg = subjectPublicKeyInfo.getAlgorithm(); - - return createKeyFactory(keyAlg.getAlgorithm()).generatePublic(xspec); - } - catch (Exception e) - { - throw new CRMFException("invalid key: " + e.getMessage(), e); - } - } - - Cipher createCipher(ASN1ObjectIdentifier algorithm) - throws CRMFException - { - try - { - String cipherName = (String)CIPHER_ALG_NAMES.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 CRMFException("cannot create cipher: " + e.getMessage(), e); - } - } - - public KeyGenerator createKeyGenerator(ASN1ObjectIdentifier algorithm) - throws CRMFException - { - try - { - String cipherName = (String)BASE_CIPHER_NAMES.get(algorithm); - - if (cipherName != null) - { - try - { - // this is reversed as the Sun policy files now allow unlimited strength RSA - return helper.createKeyGenerator(cipherName); - } - catch (NoSuchAlgorithmException e) - { - // Ignore - } - } - return helper.createKeyGenerator(algorithm.getId()); - } - catch (GeneralSecurityException e) - { - throw new CRMFException("cannot create key generator: " + e.getMessage(), e); - } - } - - - - Cipher createContentCipher(final Key sKey, final AlgorithmIdentifier encryptionAlgID) - throws CRMFException - { - return (Cipher)execute(new JCECallback() - { - public Object doInJCE() - throws CRMFException, InvalidAlgorithmParameterException, - InvalidKeyException, InvalidParameterSpecException, NoSuchAlgorithmException, - NoSuchPaddingException, NoSuchProviderException - { - Cipher cipher = createCipher(encryptionAlgID.getAlgorithm()); - ASN1Primitive sParams = (ASN1Primitive)encryptionAlgID.getParameters(); - ASN1ObjectIdentifier encAlg = encryptionAlgID.getAlgorithm(); - - if (sParams != null && !(sParams instanceof ASN1Null)) - { - try - { - AlgorithmParameters params = createAlgorithmParameters(encryptionAlgID.getAlgorithm()); - - try - { - JcaJceUtils.loadParameters(params, sParams); - } - catch (IOException e) - { - throw new CRMFException("error decoding algorithm parameters.", e); - } - - cipher.init(Cipher.DECRYPT_MODE, sKey, params); - } - catch (NoSuchAlgorithmException e) - { - if (encAlg.equals(CMSAlgorithm.DES_EDE3_CBC) - || encAlg.equals(CMSAlgorithm.IDEA_CBC) - || encAlg.equals(CMSAlgorithm.AES128_CBC) - || encAlg.equals(CMSAlgorithm.AES192_CBC) - || encAlg.equals(CMSAlgorithm.AES256_CBC)) - { - cipher.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec( - ASN1OctetString.getInstance(sParams).getOctets())); - } - else - { - throw e; - } - } - } - else - { - if (encAlg.equals(CMSAlgorithm.DES_EDE3_CBC) - || encAlg.equals(CMSAlgorithm.IDEA_CBC) - || encAlg.equals(CMSAlgorithm.CAST5_CBC)) - { - cipher.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec(new byte[8])); - } - else - { - cipher.init(Cipher.DECRYPT_MODE, sKey); - } - } - - return cipher; - } - }); - } - - AlgorithmParameters createAlgorithmParameters(ASN1ObjectIdentifier algorithm) - throws NoSuchAlgorithmException, NoSuchProviderException - { - String algorithmName = (String)BASE_CIPHER_NAMES.get(algorithm); - - if (algorithmName != null) - { - try - { - // this is reversed as the Sun policy files now allow unlimited strength RSA - return helper.createAlgorithmParameters(algorithmName); - } - catch (NoSuchAlgorithmException e) - { - // Ignore - } - } - return helper.createAlgorithmParameters(algorithm.getId()); - } - - KeyFactory createKeyFactory(ASN1ObjectIdentifier algorithm) - throws CRMFException - { - try - { - String algName = (String)KEY_ALG_NAMES.get(algorithm); - - if (algName != null) - { - try - { - // this is reversed as the Sun policy files now allow unlimited strength RSA - return helper.createKeyFactory(algName); - } - catch (NoSuchAlgorithmException e) - { - // Ignore - } - } - return helper.createKeyFactory(algorithm.getId()); - } - catch (GeneralSecurityException e) - { - throw new CRMFException("cannot create cipher: " + e.getMessage(), e); - } - } - - MessageDigest createDigest(ASN1ObjectIdentifier algorithm) - throws CRMFException - { - try - { - String digestName = (String)DIGEST_ALG_NAMES.get(algorithm); - - if (digestName != null) - { - try - { - // this is reversed as the Sun policy files now allow unlimited strength RSA - return helper.createDigest(digestName); - } - catch (NoSuchAlgorithmException e) - { - // Ignore - } - } - return helper.createDigest(algorithm.getId()); - } - catch (GeneralSecurityException e) - { - throw new CRMFException("cannot create cipher: " + e.getMessage(), e); - } - } - - Mac createMac(ASN1ObjectIdentifier algorithm) - throws CRMFException - { - try - { - String macName = (String)MAC_ALG_NAMES.get(algorithm); - - if (macName != null) - { - try - { - // this is reversed as the Sun policy files now allow unlimited strength RSA - return helper.createMac(macName); - } - catch (NoSuchAlgorithmException e) - { - // Ignore - } - } - return helper.createMac(algorithm.getId()); - } - catch (GeneralSecurityException e) - { - throw new CRMFException("cannot create mac: " + e.getMessage(), e); - } - } - - AlgorithmParameterGenerator createAlgorithmParameterGenerator(ASN1ObjectIdentifier algorithm) - throws GeneralSecurityException - { - String algorithmName = (String)BASE_CIPHER_NAMES.get(algorithm); - - if (algorithmName != null) - { - try - { - // this is reversed as the Sun policy files now allow unlimited strength RSA - return helper.createAlgorithmParameterGenerator(algorithmName); - } - catch (NoSuchAlgorithmException e) - { - // Ignore - } - } - return helper.createAlgorithmParameterGenerator(algorithm.getId()); - } - - AlgorithmParameters generateParameters(ASN1ObjectIdentifier encryptionOID, SecretKey encKey, SecureRandom rand) - throws CRMFException - { - try - { - AlgorithmParameterGenerator pGen = createAlgorithmParameterGenerator(encryptionOID); - - if (encryptionOID.equals(CMSAlgorithm.RC2_CBC)) - { - byte[] iv = new byte[8]; - - rand.nextBytes(iv); - - try - { - pGen.init(new RC2ParameterSpec(encKey.getEncoded().length * 8, iv), rand); - } - catch (InvalidAlgorithmParameterException e) - { - throw new CRMFException("parameters generation error: " + e, e); - } - } - - return pGen.generateParameters(); - } - catch (NoSuchAlgorithmException e) - { - return null; - } - catch (GeneralSecurityException e) - { - throw new CRMFException("exception creating algorithm parameter generator: " + e, e); - } - } - - AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier encryptionOID, AlgorithmParameters params) - throws CRMFException - { - ASN1Encodable asn1Params; - if (params != null) - { - try - { - asn1Params = JcaJceUtils.extractParameters(params); - } - catch (IOException e) - { - throw new CRMFException("cannot encode parameters: " + e.getMessage(), e); - } - } - else - { - asn1Params = DERNull.INSTANCE; - } - - return new AlgorithmIdentifier( - encryptionOID, - asn1Params); - } - - static Object execute(JCECallback callback) throws CRMFException - { - try - { - return callback.doInJCE(); - } - catch (NoSuchAlgorithmException e) - { - throw new CRMFException("can't find algorithm.", e); - } - catch (InvalidKeyException e) - { - throw new CRMFException("key invalid in message.", e); - } - catch (NoSuchProviderException e) - { - throw new CRMFException("can't find provider.", e); - } - catch (NoSuchPaddingException e) - { - throw new CRMFException("required padding not supported.", e); - } - catch (InvalidAlgorithmParameterException e) - { - throw new CRMFException("algorithm parameters invalid.", e); - } - catch (InvalidParameterSpecException e) - { - throw new CRMFException("MAC algorithm parameter spec invalid.", e); - } - } - - static interface JCECallback - { - Object doInJCE() - throws CRMFException, InvalidAlgorithmParameterException, InvalidKeyException, InvalidParameterSpecException, - NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JcaCertificateRequestMessage.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JcaCertificateRequestMessage.java deleted file mode 100644 index 7f33d17a..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JcaCertificateRequestMessage.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.bouncycastle.cert.crmf.jcajce; - -import java.io.IOException; -import java.security.Provider; -import java.security.PublicKey; - -import javax.security.auth.x500.X500Principal; - -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.crmf.CertReqMsg; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.cert.crmf.CRMFException; -import org.bouncycastle.cert.crmf.CertificateRequestMessage; -import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.util.NamedJcaJceHelper; -import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; - -public class JcaCertificateRequestMessage - extends CertificateRequestMessage -{ - private CRMFHelper helper = new CRMFHelper(new DefaultJcaJceHelper()); - - public JcaCertificateRequestMessage(byte[] certReqMsg) - { - this(CertReqMsg.getInstance(certReqMsg)); - } - - public JcaCertificateRequestMessage(CertificateRequestMessage certReqMsg) - { - this(certReqMsg.toASN1Structure()); - } - - public JcaCertificateRequestMessage(CertReqMsg certReqMsg) - { - super(certReqMsg); - } - - public JcaCertificateRequestMessage setProvider(String providerName) - { - this.helper = new CRMFHelper(new NamedJcaJceHelper(providerName)); - - return this; - } - - public JcaCertificateRequestMessage setProvider(Provider provider) - { - this.helper = new CRMFHelper(new ProviderJcaJceHelper(provider)); - - return this; - } - - public X500Principal getSubjectX500Principal() - { - X500Name subject = this.getCertTemplate().getSubject(); - - if (subject != null) - { - try - { - return new X500Principal(subject.getEncoded(ASN1Encoding.DER)); - } - catch (IOException e) - { - throw new IllegalStateException("unable to construct DER encoding of name: " + e.getMessage()); - } - } - - return null; - } - - public PublicKey getPublicKey() - throws CRMFException - { - SubjectPublicKeyInfo subjectPublicKeyInfo = getCertTemplate().getPublicKey(); - - if (subjectPublicKeyInfo != null) - { - return helper.toPublicKey(subjectPublicKeyInfo); - } - - return null; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JcaCertificateRequestMessageBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JcaCertificateRequestMessageBuilder.java deleted file mode 100644 index 63eea67f..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JcaCertificateRequestMessageBuilder.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.bouncycastle.cert.crmf.jcajce; - -import java.math.BigInteger; -import java.security.PublicKey; - -import javax.security.auth.x500.X500Principal; - -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.cert.crmf.CertificateRequestMessageBuilder; - -public class JcaCertificateRequestMessageBuilder - extends CertificateRequestMessageBuilder -{ - public JcaCertificateRequestMessageBuilder(BigInteger certReqId) - { - super(certReqId); - } - - public JcaCertificateRequestMessageBuilder setIssuer(X500Principal issuer) - { - if (issuer != null) - { - setIssuer(X500Name.getInstance(issuer.getEncoded())); - } - - return this; - } - - public JcaCertificateRequestMessageBuilder setSubject(X500Principal subject) - { - if (subject != null) - { - setSubject(X500Name.getInstance(subject.getEncoded())); - } - - return this; - } - - public JcaCertificateRequestMessageBuilder setAuthInfoSender(X500Principal sender) - { - if (sender != null) - { - setAuthInfoSender(new GeneralName(X500Name.getInstance(sender.getEncoded()))); - } - - return this; - } - - public JcaCertificateRequestMessageBuilder setPublicKey(PublicKey publicKey) - { - setPublicKey(SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); - - return this; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JcaEncryptedValueBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JcaEncryptedValueBuilder.java deleted file mode 100644 index 91d22a0e..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JcaEncryptedValueBuilder.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.bouncycastle.cert.crmf.jcajce; - -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; - -import org.bouncycastle.asn1.crmf.EncryptedValue; -import org.bouncycastle.cert.crmf.CRMFException; -import org.bouncycastle.cert.crmf.EncryptedValueBuilder; -import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; -import org.bouncycastle.operator.KeyWrapper; -import org.bouncycastle.operator.OutputEncryptor; - -public class JcaEncryptedValueBuilder - extends EncryptedValueBuilder -{ - public JcaEncryptedValueBuilder(KeyWrapper wrapper, OutputEncryptor encryptor) - { - super(wrapper, encryptor); - } - - public EncryptedValue build(X509Certificate certificate) - throws CertificateEncodingException, CRMFException - { - return build(new JcaX509CertificateHolder(certificate)); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JcaPKIArchiveControlBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JcaPKIArchiveControlBuilder.java deleted file mode 100644 index ab892416..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JcaPKIArchiveControlBuilder.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.bouncycastle.cert.crmf.jcajce; - -import java.security.PrivateKey; - -import javax.security.auth.x500.X500Principal; - -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.cert.crmf.PKIArchiveControlBuilder; - -public class JcaPKIArchiveControlBuilder - extends PKIArchiveControlBuilder -{ - public JcaPKIArchiveControlBuilder(PrivateKey privateKey, X500Name name) - { - this(privateKey, new GeneralName(name)); - } - - public JcaPKIArchiveControlBuilder(PrivateKey privateKey, X500Principal name) - { - this(privateKey, X500Name.getInstance(name.getEncoded())); - } - - public JcaPKIArchiveControlBuilder(PrivateKey privateKey, GeneralName generalName) - { - super(PrivateKeyInfo.getInstance(privateKey.getEncoded()), generalName); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JceAsymmetricValueDecryptorGenerator.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JceAsymmetricValueDecryptorGenerator.java deleted file mode 100644 index ff1158e9..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JceAsymmetricValueDecryptorGenerator.java +++ /dev/null @@ -1,120 +0,0 @@ -package org.bouncycastle.cert.crmf.jcajce; - -import java.io.InputStream; -import java.security.GeneralSecurityException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.PrivateKey; -import java.security.Provider; -import java.security.ProviderException; - -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.CipherInputStream; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.spec.SecretKeySpec; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cert.crmf.CRMFException; -import org.bouncycastle.cert.crmf.ValueDecryptorGenerator; -import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.util.NamedJcaJceHelper; -import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; -import org.bouncycastle.operator.InputDecryptor; - -public class JceAsymmetricValueDecryptorGenerator - implements ValueDecryptorGenerator -{ - private PrivateKey recipientKey; - private CRMFHelper helper = new CRMFHelper(new DefaultJcaJceHelper()); - - public JceAsymmetricValueDecryptorGenerator(PrivateKey recipientKey) - { - this.recipientKey = recipientKey; - } - - public JceAsymmetricValueDecryptorGenerator setProvider(Provider provider) - { - this.helper = new CRMFHelper(new ProviderJcaJceHelper(provider)); - - return this; - } - - public JceAsymmetricValueDecryptorGenerator setProvider(String providerName) - { - this.helper = new CRMFHelper(new NamedJcaJceHelper(providerName)); - - return this; - } - - private Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey) - throws CRMFException - { - try - { - Key sKey = null; - - Cipher keyCipher = helper.createCipher(keyEncryptionAlgorithm.getAlgorithm()); - - try - { - keyCipher.init(Cipher.UNWRAP_MODE, recipientKey); - sKey = keyCipher.unwrap(encryptedContentEncryptionKey, contentEncryptionAlgorithm.getAlgorithm().getId(), Cipher.SECRET_KEY); - } - catch (GeneralSecurityException e) - { - } - catch (IllegalStateException e) - { - } - catch (UnsupportedOperationException e) - { - } - catch (ProviderException e) - { - } - - // some providers do not support UNWRAP (this appears to be only for asymmetric algorithms) - if (sKey == null) - { - keyCipher.init(Cipher.DECRYPT_MODE, recipientKey); - sKey = new SecretKeySpec(keyCipher.doFinal(encryptedContentEncryptionKey), contentEncryptionAlgorithm.getAlgorithm().getId()); - } - - return sKey; - } - catch (InvalidKeyException e) - { - throw new CRMFException("key invalid in message.", e); - } - catch (IllegalBlockSizeException e) - { - throw new CRMFException("illegal blocksize in message.", e); - } - catch (BadPaddingException e) - { - throw new CRMFException("bad padding in message.", e); - } - } - - public InputDecryptor getValueDecryptor(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey) - throws CRMFException - { - Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, encryptedContentEncryptionKey); - - final Cipher dataCipher = helper.createContentCipher(secretKey, contentEncryptionAlgorithm); - - return new InputDecryptor() - { - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return contentEncryptionAlgorithm; - } - - public InputStream getInputStream(InputStream dataIn) - { - return new CipherInputStream(dataIn, dataCipher); - } - }; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JceCRMFEncryptorBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JceCRMFEncryptorBuilder.java deleted file mode 100644 index 701d36ea..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JceCRMFEncryptorBuilder.java +++ /dev/null @@ -1,136 +0,0 @@ -package org.bouncycastle.cert.crmf.jcajce; - -import java.io.OutputStream; -import java.security.AlgorithmParameters; -import java.security.GeneralSecurityException; -import java.security.Provider; -import java.security.SecureRandom; - -import javax.crypto.Cipher; -import javax.crypto.CipherOutputStream; -import javax.crypto.KeyGenerator; -import javax.crypto.SecretKey; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cert.crmf.CRMFException; -import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.util.NamedJcaJceHelper; -import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.OutputEncryptor; -import org.bouncycastle.operator.jcajce.JceGenericKey; - -public class JceCRMFEncryptorBuilder -{ - private final ASN1ObjectIdentifier encryptionOID; - private final int keySize; - - private CRMFHelper helper = new CRMFHelper(new DefaultJcaJceHelper()); - private SecureRandom random; - - public JceCRMFEncryptorBuilder(ASN1ObjectIdentifier encryptionOID) - { - this(encryptionOID, -1); - } - - public JceCRMFEncryptorBuilder(ASN1ObjectIdentifier encryptionOID, int keySize) - { - this.encryptionOID = encryptionOID; - this.keySize = keySize; - } - - public JceCRMFEncryptorBuilder setProvider(Provider provider) - { - this.helper = new CRMFHelper(new ProviderJcaJceHelper(provider)); - - return this; - } - - public JceCRMFEncryptorBuilder setProvider(String providerName) - { - this.helper = new CRMFHelper(new NamedJcaJceHelper(providerName)); - - return this; - } - - public JceCRMFEncryptorBuilder setSecureRandom(SecureRandom random) - { - this.random = random; - - return this; - } - - public OutputEncryptor build() - throws CRMFException - { - return new CRMFOutputEncryptor(encryptionOID, keySize, random); - } - - private class CRMFOutputEncryptor - implements OutputEncryptor - { - private SecretKey encKey; - private AlgorithmIdentifier algorithmIdentifier; - private Cipher cipher; - - CRMFOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, SecureRandom random) - throws CRMFException - { - KeyGenerator keyGen = helper.createKeyGenerator(encryptionOID); - - if (random == null) - { - random = new SecureRandom(); - } - - if (keySize < 0) - { - keyGen.init(random); - } - else - { - keyGen.init(keySize, random); - } - - cipher = helper.createCipher(encryptionOID); - encKey = keyGen.generateKey(); - AlgorithmParameters params = helper.generateParameters(encryptionOID, encKey, random); - - try - { - cipher.init(Cipher.ENCRYPT_MODE, encKey, params, random); - } - catch (GeneralSecurityException e) - { - throw new CRMFException("unable to initialize cipher: " + e.getMessage(), e); - } - - // - // If params are null we try and second guess on them as some providers don't provide - // algorithm parameter generation explicity but instead generate them under the hood. - // - if (params == null) - { - params = cipher.getParameters(); - } - - algorithmIdentifier = helper.getAlgorithmIdentifier(encryptionOID, params); - } - - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return algorithmIdentifier; - } - - public OutputStream getOutputStream(OutputStream dOut) - { - return new CipherOutputStream(dOut, cipher); - } - - public GenericKey getKey() - { - return new JceGenericKey(algorithmIdentifier, encKey); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JcePKMACValuesCalculator.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JcePKMACValuesCalculator.java deleted file mode 100644 index 30423db5..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/jcajce/JcePKMACValuesCalculator.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.bouncycastle.cert.crmf.jcajce; - -import java.security.GeneralSecurityException; -import java.security.MessageDigest; -import java.security.Provider; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cert.crmf.CRMFException; -import org.bouncycastle.cert.crmf.PKMACValuesCalculator; -import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.util.NamedJcaJceHelper; -import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; - -public class JcePKMACValuesCalculator - implements PKMACValuesCalculator -{ - private MessageDigest digest; - private Mac mac; - private CRMFHelper helper; - - public JcePKMACValuesCalculator() - { - this.helper = new CRMFHelper(new DefaultJcaJceHelper()); - } - - public JcePKMACValuesCalculator setProvider(Provider provider) - { - this.helper = new CRMFHelper(new ProviderJcaJceHelper(provider)); - - return this; - } - - public JcePKMACValuesCalculator setProvider(String providerName) - { - this.helper = new CRMFHelper(new NamedJcaJceHelper(providerName)); - - return this; - } - - public void setup(AlgorithmIdentifier digAlg, AlgorithmIdentifier macAlg) - throws CRMFException - { - digest = helper.createDigest(digAlg.getAlgorithm()); - mac = helper.createMac(macAlg.getAlgorithm()); - } - - public byte[] calculateDigest(byte[] data) - { - return digest.digest(data); - } - - public byte[] calculateMac(byte[] pwd, byte[] data) - throws CRMFException - { - try - { - mac.init(new SecretKeySpec(pwd, mac.getAlgorithm())); - - return mac.doFinal(data); - } - catch (GeneralSecurityException e) - { - throw new CRMFException("failure in setup: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/jcajce/CertHelper.java b/pkix/src/main/java/org/bouncycastle/cert/jcajce/CertHelper.java deleted file mode 100644 index dee69967..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/jcajce/CertHelper.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.bouncycastle.cert.jcajce; - -import java.security.NoSuchProviderException; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; - -abstract class CertHelper -{ - public CertificateFactory getCertificateFactory(String type) - throws NoSuchProviderException, CertificateException - { - return createCertificateFactory(type); - } - - protected abstract CertificateFactory createCertificateFactory(String type) - throws CertificateException, NoSuchProviderException; -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/jcajce/DefaultCertHelper.java b/pkix/src/main/java/org/bouncycastle/cert/jcajce/DefaultCertHelper.java deleted file mode 100644 index 3966b493..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/jcajce/DefaultCertHelper.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.bouncycastle.cert.jcajce; - -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; - -class DefaultCertHelper - extends CertHelper -{ - protected CertificateFactory createCertificateFactory(String type) - throws CertificateException - { - return CertificateFactory.getInstance(type); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaAttrCertStore.java b/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaAttrCertStore.java deleted file mode 100644 index b857d966..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaAttrCertStore.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.bouncycastle.cert.jcajce; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -import org.bouncycastle.util.CollectionStore; -import org.bouncycastle.x509.X509AttributeCertificate; - -/** - * Class for storing Attribute Certificates for later lookup. - * <p> - * The class will convert X509AttributeCertificate objects into X509AttributeCertificateHolder objects. - * </p> - */ -public class JcaAttrCertStore - extends CollectionStore -{ - /** - * Basic constructor. - * - * @param collection - initial contents for the store, this is copied. - */ - public JcaAttrCertStore(Collection collection) - throws IOException - { - super(convertCerts(collection)); - } - - public JcaAttrCertStore(X509AttributeCertificate attrCert) - throws IOException - { - this(Collections.singletonList(attrCert)); - } - - private static Collection convertCerts(Collection collection) - throws IOException - { - List list = new ArrayList(collection.size()); - - for (Iterator it = collection.iterator(); it.hasNext();) - { - Object o = it.next(); - - if (o instanceof X509AttributeCertificate) - { - X509AttributeCertificate cert = (X509AttributeCertificate)o; - - list.add(new JcaX509AttributeCertificateHolder(cert)); - } - else - { - list.add(o); - } - } - - return list; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaAttributeCertificateIssuer.java b/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaAttributeCertificateIssuer.java deleted file mode 100644 index f5bfa68d..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaAttributeCertificateIssuer.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.bouncycastle.cert.jcajce; - -import java.security.cert.X509Certificate; - -import javax.security.auth.x500.X500Principal; - -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.cert.AttributeCertificateIssuer; - -public class JcaAttributeCertificateIssuer - extends AttributeCertificateIssuer -{ - /** - * Base constructor. - * - * @param issuerCert certificate for the issuer of the attribute certificate. - */ - public JcaAttributeCertificateIssuer(X509Certificate issuerCert) - { - this(issuerCert.getIssuerX500Principal()); - } - - /** - * Base constructor. - * - * @param issuerDN X.500 DN for the issuer of the attribute certificate. - */ - public JcaAttributeCertificateIssuer(X500Principal issuerDN) - { - super(X500Name.getInstance(issuerDN.getEncoded())); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaCRLStore.java b/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaCRLStore.java deleted file mode 100644 index 2e8209e9..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaCRLStore.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.bouncycastle.cert.jcajce; - -import java.io.IOException; -import java.security.cert.CRLException; -import java.security.cert.X509CRL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; - -import org.bouncycastle.cert.X509CRLHolder; -import org.bouncycastle.util.CollectionStore; - -/** - * Class for storing CRLs for later lookup. - * <p> - * The class will convert X509CRL objects into X509CRLHolder objects. - * </p> - */ -public class JcaCRLStore - extends CollectionStore -{ - /** - * Basic constructor. - * - * @param collection - initial contents for the store, this is copied. - */ - public JcaCRLStore(Collection collection) - throws CRLException - { - super(convertCRLs(collection)); - } - - private static Collection convertCRLs(Collection collection) - throws CRLException - { - List list = new ArrayList(collection.size()); - - for (Iterator it = collection.iterator(); it.hasNext();) - { - Object crl = it.next(); - - if (crl instanceof X509CRL) - { - try - { - list.add(new X509CRLHolder(((X509CRL)crl).getEncoded())); - } - catch (IOException e) - { - throw new CRLException("cannot read encoding: " + e.getMessage()); - - } - } - else - { - list.add((X509CRLHolder)crl); - } - } - - return list; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaCertStore.java b/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaCertStore.java deleted file mode 100644 index e7433642..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaCertStore.java +++ /dev/null @@ -1,64 +0,0 @@ -package 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 org.bouncycastle.cert.X509CertificateHolder; -import 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/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaCertStoreBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaCertStoreBuilder.java deleted file mode 100644 index 3051a455..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaCertStoreBuilder.java +++ /dev/null @@ -1,148 +0,0 @@ -package org.bouncycastle.cert.jcajce; - -import java.security.GeneralSecurityException; -import java.security.Provider; -import java.security.cert.CRLException; -import java.security.cert.CertStore; -import java.security.cert.CertificateException; -import java.security.cert.CollectionCertStoreParameters; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.bouncycastle.cert.X509CRLHolder; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.util.Store; - -/** - * Builder to create a CertStore from certificate and CRL stores. - */ -public class JcaCertStoreBuilder -{ - private List certs = new ArrayList(); - private List crls = new ArrayList(); - private Object provider; - private JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter(); - private JcaX509CRLConverter crlConverter = new JcaX509CRLConverter(); - private String type = "Collection"; - - /** - * Add a store full of X509CertificateHolder objects. - * - * @param certStore a store of X509CertificateHolder objects. - */ - public JcaCertStoreBuilder addCertificates(Store certStore) - { - certs.addAll(certStore.getMatches(null)); - - return this; - } - - /** - * Add a single certificate. - * - * @param cert the X509 certificate holder containing the certificate. - */ - public JcaCertStoreBuilder addCertificate(X509CertificateHolder cert) - { - certs.add(cert); - - return this; - } - - /** - * Add a store full of X509CRLHolder objects. - * @param crlStore a store of X509CRLHolder objects. - */ - public JcaCertStoreBuilder addCRLs(Store crlStore) - { - crls.addAll(crlStore.getMatches(null)); - - return this; - } - - /** - * Add a single CRL. - * - * @param crl the X509 CRL holder containing the CRL. - */ - public JcaCertStoreBuilder addCRL(X509CRLHolder crl) - { - crls.add(crl); - - return this; - } - - public JcaCertStoreBuilder setProvider(String providerName) - { - certificateConverter.setProvider(providerName); - crlConverter.setProvider(providerName); - this.provider = providerName; - - return this; - } - - public JcaCertStoreBuilder setProvider(Provider provider) - { - certificateConverter.setProvider(provider); - crlConverter.setProvider(provider); - this.provider = provider; - - return this; - } - - /** - * Set the type of the CertStore generated. By default it is "Collection". - * - * @param type type of CertStore passed to CertStore.getInstance(). - * @return the current builder. - */ - public JcaCertStoreBuilder setType(String type) - { - this.type = type; - - return this; - } - - /** - * Build the CertStore from the current inputs. - * - * @return a CertStore. - * @throws GeneralSecurityException - */ - public CertStore build() - throws GeneralSecurityException - { - CollectionCertStoreParameters params = convertHolders(certificateConverter, crlConverter); - - if (provider instanceof String) - { - return CertStore.getInstance(type, params, (String)provider); - } - - if (provider instanceof Provider) - { - return CertStore.getInstance(type, params, (Provider)provider); - } - - return CertStore.getInstance(type, params); - } - - private CollectionCertStoreParameters convertHolders(JcaX509CertificateConverter certificateConverter, JcaX509CRLConverter crlConverter) - throws CertificateException, CRLException - { - List jcaObjs = new ArrayList(certs.size() + crls.size()); - - for (Iterator it = certs.iterator(); it.hasNext();) - { - jcaObjs.add(certificateConverter.getCertificate((X509CertificateHolder)it.next())); - } - - for (Iterator it = crls.iterator(); it.hasNext();) - { - jcaObjs.add(crlConverter.getCRL((X509CRLHolder)it.next())); - } - - return new CollectionCertStoreParameters(jcaObjs); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX500NameUtil.java b/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX500NameUtil.java deleted file mode 100644 index 2b64340e..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX500NameUtil.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.bouncycastle.cert.jcajce; - -import java.security.cert.X509Certificate; - -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x500.X500NameStyle; - -public class JcaX500NameUtil -{ - public static X500Name getIssuer(X509Certificate certificate) - { - return X500Name.getInstance(certificate.getIssuerX500Principal().getEncoded()); - } - - public static X500Name getSubject(X509Certificate certificate) - { - return X500Name.getInstance(certificate.getSubjectX500Principal().getEncoded()); - } - - public static X500Name getIssuer(X500NameStyle style, X509Certificate certificate) - { - return X500Name.getInstance(style, certificate.getIssuerX500Principal().getEncoded()); - } - - public static X500Name getSubject(X500NameStyle style, X509Certificate certificate) - { - return X500Name.getInstance(style, certificate.getSubjectX500Principal().getEncoded()); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509AttributeCertificateHolder.java b/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509AttributeCertificateHolder.java deleted file mode 100644 index 1ceafce0..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509AttributeCertificateHolder.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.bouncycastle.cert.jcajce; - -import java.io.IOException; - -import org.bouncycastle.asn1.x509.AttributeCertificate; -import org.bouncycastle.cert.X509AttributeCertificateHolder; -import org.bouncycastle.x509.X509AttributeCertificate; - -/** - * JCA helper class for converting an old style X509AttributeCertificate into a X509AttributeCertificateHolder object. - */ -public class JcaX509AttributeCertificateHolder - extends X509AttributeCertificateHolder -{ - /** - * Base constructor. - * - * @param cert AttributeCertificate to be used a the source for the holder creation. - * @throws IOException if there is a problem extracting the attribute certificate information. - */ - public JcaX509AttributeCertificateHolder(X509AttributeCertificate cert) - throws IOException - { - super(AttributeCertificate.getInstance(cert.getEncoded())); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509CRLConverter.java b/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509CRLConverter.java deleted file mode 100644 index ae06334f..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509CRLConverter.java +++ /dev/null @@ -1,103 +0,0 @@ -package org.bouncycastle.cert.jcajce; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.security.NoSuchProviderException; -import java.security.Provider; -import java.security.cert.CRLException; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509CRL; - -import org.bouncycastle.cert.X509CRLHolder; - -/** - * Class for converting an X509CRLHolder into a corresponding X509CRL object tied to a - * particular JCA provider. - */ -public class JcaX509CRLConverter -{ - private CertHelper helper = new DefaultCertHelper(); - - /** - * Base constructor, configure with the default provider. - */ - public JcaX509CRLConverter() - { - this.helper = new DefaultCertHelper(); - } - - /** - * Set the provider to use from a Provider object. - * - * @param provider the provider to use. - * @return the converter instance. - */ - public JcaX509CRLConverter setProvider(Provider provider) - { - this.helper = new ProviderCertHelper(provider); - - return this; - } - - /** - * Set the provider to use by name. - * - * @param providerName name of the provider to use. - * @return the converter instance. - */ - public JcaX509CRLConverter setProvider(String providerName) - { - this.helper = new NamedCertHelper(providerName); - - return this; - } - - /** - * Use the configured converter to produce a X509CRL object from a X509CRLHolder object. - * - * @param crlHolder the holder to be converted - * @return a X509CRL object - * @throws CRLException if the conversion is unable to be made. - */ - public X509CRL getCRL(X509CRLHolder crlHolder) - throws CRLException - { - try - { - CertificateFactory cFact = helper.getCertificateFactory("X.509"); - - return (X509CRL)cFact.generateCRL(new ByteArrayInputStream(crlHolder.getEncoded())); - } - catch (IOException e) - { - throw new ExCRLException("exception parsing certificate: " + e.getMessage(), e); - } - catch (NoSuchProviderException e) - { - throw new ExCRLException("cannot find required provider:" + e.getMessage(), e); - } - catch (CertificateException e) - { - throw new ExCRLException("cannot create factory: " + e.getMessage(), e); - } - } - - private class ExCRLException - extends CRLException - { - private Throwable cause; - - public ExCRLException(String msg, Throwable cause) - { - super(msg); - - this.cause = cause; - } - - public Throwable getCause() - { - return cause; - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509CRLHolder.java b/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509CRLHolder.java deleted file mode 100644 index 43665c02..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509CRLHolder.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.bouncycastle.cert.jcajce; - -import java.security.cert.CRLException; -import java.security.cert.X509CRL; - -import org.bouncycastle.asn1.x509.CertificateList; -import org.bouncycastle.cert.X509CRLHolder; - -/** - * JCA helper class for converting an X509CRL into a X509CRLHolder object. - */ -public class JcaX509CRLHolder - extends X509CRLHolder -{ - /** - * Base constructor. - * - * @param crl CRL to be used a the source for the holder creation. - * @throws CRLException if there is a problem extracting the CRL information. - */ - public JcaX509CRLHolder(X509CRL crl) - throws CRLException - { - super(CertificateList.getInstance(crl.getEncoded())); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509CertificateConverter.java b/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509CertificateConverter.java deleted file mode 100644 index 39e63aa4..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509CertificateConverter.java +++ /dev/null @@ -1,116 +0,0 @@ -package org.bouncycastle.cert.jcajce; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.security.NoSuchProviderException; -import java.security.Provider; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.CertificateParsingException; -import java.security.cert.X509Certificate; - -import org.bouncycastle.cert.X509CertificateHolder; - -/** - * Converter for producing X509Certificate objects tied to a specific provider from X509CertificateHolder objects. - */ -public class JcaX509CertificateConverter -{ - private CertHelper helper = new DefaultCertHelper(); - - /** - * Base constructor, configure with the default provider. - */ - public JcaX509CertificateConverter() - { - this.helper = new DefaultCertHelper(); - } - - /** - * Set the provider to use from a Provider object. - * - * @param provider the provider to use. - * @return the converter instance. - */ - public JcaX509CertificateConverter setProvider(Provider provider) - { - this.helper = new ProviderCertHelper(provider); - - return this; - } - - /** - * Set the provider to use by name. - * - * @param providerName name of the provider to use. - * @return the converter instance. - */ - public JcaX509CertificateConverter setProvider(String providerName) - { - this.helper = new NamedCertHelper(providerName); - - return this; - } - - /** - * Use the configured converter to produce a X509Certificate object from a X509CertificateHolder object. - * - * @param certHolder the holder to be converted - * @return a X509Certificate object - * @throws CertificateException if the conversion is unable to be made. - */ - public X509Certificate getCertificate(X509CertificateHolder certHolder) - throws CertificateException - { - try - { - CertificateFactory cFact = helper.getCertificateFactory("X.509"); - - return (X509Certificate)cFact.generateCertificate(new ByteArrayInputStream(certHolder.getEncoded())); - } - catch (IOException e) - { - throw new ExCertificateParsingException("exception parsing certificate: " + e.getMessage(), e); - } - catch (NoSuchProviderException e) - { - throw new ExCertificateException("cannot find required provider:" + e.getMessage(), e); - } - } - - private class ExCertificateParsingException - extends CertificateParsingException - { - private Throwable cause; - - public ExCertificateParsingException(String msg, Throwable cause) - { - super(msg); - - this.cause = cause; - } - - public Throwable getCause() - { - return cause; - } - } - - private class ExCertificateException - extends CertificateException - { - private Throwable cause; - - public ExCertificateException(String msg, Throwable cause) - { - super(msg); - - this.cause = cause; - } - - public Throwable getCause() - { - return cause; - } - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509CertificateHolder.java b/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509CertificateHolder.java deleted file mode 100644 index d0611843..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509CertificateHolder.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.bouncycastle.cert.jcajce; - -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; - -import org.bouncycastle.asn1.x509.Certificate; -import 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/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509ContentVerifierProviderBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509ContentVerifierProviderBuilder.java deleted file mode 100644 index 5f4c530f..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509ContentVerifierProviderBuilder.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.bouncycastle.cert.jcajce; - -import java.security.Provider; -import java.security.cert.CertificateException; - -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cert.X509ContentVerifierProviderBuilder; -import org.bouncycastle.operator.ContentVerifierProvider; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder; - -public class JcaX509ContentVerifierProviderBuilder - implements X509ContentVerifierProviderBuilder -{ - private JcaContentVerifierProviderBuilder builder = new JcaContentVerifierProviderBuilder(); - - public JcaX509ContentVerifierProviderBuilder setProvider(Provider provider) - { - this.builder.setProvider(provider); - - return this; - } - - public JcaX509ContentVerifierProviderBuilder setProvider(String providerName) - { - this.builder.setProvider(providerName); - - return this; - } - - public ContentVerifierProvider build(SubjectPublicKeyInfo validatingKeyInfo) - throws OperatorCreationException - { - return builder.build(validatingKeyInfo); - } - - public ContentVerifierProvider build(X509CertificateHolder validatingKeyInfo) - throws OperatorCreationException - { - try - { - return builder.build(validatingKeyInfo); - } - catch (CertificateException e) - { - throw new OperatorCreationException("Unable to process certificate: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509ExtensionUtils.java b/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509ExtensionUtils.java deleted file mode 100644 index 162c94f1..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509ExtensionUtils.java +++ /dev/null @@ -1,145 +0,0 @@ -package org.bouncycastle.cert.jcajce; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.math.BigInteger; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.PublicKey; -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; - -import javax.security.auth.x500.X500Principal; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.asn1.x509.GeneralNames; -import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.cert.X509ExtensionUtils; -import org.bouncycastle.operator.DigestCalculator; - -public class JcaX509ExtensionUtils - extends X509ExtensionUtils -{ - /** - * Create a utility class pre-configured with a SHA-1 digest calculator based on the - * default implementation. - * - * @throws NoSuchAlgorithmException - */ - public JcaX509ExtensionUtils() - throws NoSuchAlgorithmException - { - super(new SHA1DigestCalculator(MessageDigest.getInstance("SHA1"))); - } - - public JcaX509ExtensionUtils(DigestCalculator calculator) - { - super(calculator); - } - - public AuthorityKeyIdentifier createAuthorityKeyIdentifier( - X509Certificate cert) - throws CertificateEncodingException - { - return super.createAuthorityKeyIdentifier(new JcaX509CertificateHolder(cert)); - } - - public AuthorityKeyIdentifier createAuthorityKeyIdentifier( - PublicKey pubKey) - { - return super.createAuthorityKeyIdentifier(SubjectPublicKeyInfo.getInstance(pubKey.getEncoded())); - } - - public AuthorityKeyIdentifier createAuthorityKeyIdentifier(PublicKey pubKey, X500Principal name, BigInteger serial) - { - return super.createAuthorityKeyIdentifier(SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()), new GeneralNames(new GeneralName(X500Name.getInstance(name.getEncoded()))), serial); - } - - public AuthorityKeyIdentifier createAuthorityKeyIdentifier(PublicKey pubKey, GeneralNames generalNames, BigInteger serial) - { - return super.createAuthorityKeyIdentifier(SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()), generalNames, serial); - } - - /** - * Return a RFC 3280 type 1 key identifier. As in: - * <pre> - * (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the - * value of the BIT STRING subjectPublicKey (excluding the tag, - * length, and number of unused bits). - * </pre> - * @param publicKey the key object containing the key identifier is to be based on. - * @return the key identifier. - */ - public SubjectKeyIdentifier createSubjectKeyIdentifier( - PublicKey publicKey) - { - return super.createSubjectKeyIdentifier(SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); - } - - /** - * Return a RFC 3280 type 2 key identifier. As in: - * <pre> - * (2) The keyIdentifier is composed of a four bit type field with - * the value 0100 followed by the least significant 60 bits of the - * SHA-1 hash of the value of the BIT STRING subjectPublicKey. - * </pre> - * @param publicKey the key object of interest. - * @return the key identifier. - */ - public SubjectKeyIdentifier createTruncatedSubjectKeyIdentifier(PublicKey publicKey) - { - return super.createSubjectKeyIdentifier(SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); - } - - /** - * Return the ASN.1 object contained in a byte[] returned by a getExtensionValue() call. - * - * @param encExtValue DER encoded OCTET STRING containing the DER encoded extension object. - * @return an ASN.1 object - * @throws java.io.IOException on a parsing error. - */ - public static ASN1Primitive parseExtensionValue(byte[] encExtValue) - throws IOException - { - return ASN1Primitive.fromByteArray(ASN1OctetString.getInstance(encExtValue).getOctets()); - } - - private static class SHA1DigestCalculator - implements DigestCalculator - { - private ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - private MessageDigest digest; - - public SHA1DigestCalculator(MessageDigest digest) - { - this.digest = digest; - } - - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1); - } - - public OutputStream getOutputStream() - { - return bOut; - } - - public byte[] getDigest() - { - byte[] bytes = digest.digest(bOut.toByteArray()); - - bOut.reset(); - - return bytes; - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509v1CertificateBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509v1CertificateBuilder.java deleted file mode 100644 index e453fc71..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509v1CertificateBuilder.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.bouncycastle.cert.jcajce; - -import java.math.BigInteger; -import java.security.PublicKey; -import java.util.Date; - -import javax.security.auth.x500.X500Principal; - -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.cert.X509v1CertificateBuilder; - -/** - * JCA helper class to allow JCA objects to be used in the construction of a Version 1 certificate. - */ -public class JcaX509v1CertificateBuilder - extends X509v1CertificateBuilder -{ - /** - * Initialise the builder using a PublicKey. - * - * @param issuer X500Name representing the issuer of this certificate. - * @param serial the serial number for the certificate. - * @param notBefore date before which the certificate is not valid. - * @param notAfter date after which the certificate is not valid. - * @param subject X500Name representing the subject of this certificate. - * @param publicKey the public key to be associated with the certificate. - */ - public JcaX509v1CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, PublicKey publicKey) - { - super(issuer, serial, notBefore, notAfter, subject, SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); - } - - /** - * Initialise the builder using X500Principal objects and a PublicKey. - * - * @param issuer principal representing the issuer of this certificate. - * @param serial the serial number for the certificate. - * @param notBefore date before which the certificate is not valid. - * @param notAfter date after which the certificate is not valid. - * @param subject principal representing the subject of this certificate. - * @param publicKey the public key to be associated with the certificate. - */ - public JcaX509v1CertificateBuilder(X500Principal issuer, BigInteger serial, Date notBefore, Date notAfter, X500Principal subject, PublicKey publicKey) - { - super(X500Name.getInstance(issuer.getEncoded()), serial, notBefore, notAfter, X500Name.getInstance(subject.getEncoded()), SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509v2CRLBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509v2CRLBuilder.java deleted file mode 100644 index 43c39184..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509v2CRLBuilder.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.bouncycastle.cert.jcajce; - -import java.security.cert.X509Certificate; -import java.util.Date; - -import javax.security.auth.x500.X500Principal; - -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.cert.X509v2CRLBuilder; - -public class JcaX509v2CRLBuilder - extends X509v2CRLBuilder -{ - public JcaX509v2CRLBuilder(X500Principal issuer, Date now) - { - super(X500Name.getInstance(issuer.getEncoded()), now); - } - - public JcaX509v2CRLBuilder(X509Certificate issuerCert, Date now) - { - this(issuerCert.getSubjectX500Principal(), now); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509v3CertificateBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509v3CertificateBuilder.java deleted file mode 100644 index ae33009c..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509v3CertificateBuilder.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.bouncycastle.cert.jcajce; - -import java.math.BigInteger; -import java.security.PublicKey; -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; -import java.util.Date; - -import javax.security.auth.x500.X500Principal; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.asn1.x509.Time; -import org.bouncycastle.cert.X509v3CertificateBuilder; - -/** - * JCA helper class to allow JCA objects to be used in the construction of a Version 3 certificate. - */ -public class JcaX509v3CertificateBuilder - extends X509v3CertificateBuilder -{ - /** - * Initialise the builder using a PublicKey. - * - * @param issuer X500Name representing the issuer of this certificate. - * @param serial the serial number for the certificate. - * @param notBefore date before which the certificate is not valid. - * @param notAfter date after which the certificate is not valid. - * @param subject X500Name representing the subject of this certificate. - * @param publicKey the public key to be associated with the certificate. - */ - public JcaX509v3CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, PublicKey publicKey) - { - super(issuer, serial, notBefore, notAfter, subject, SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); - } - - /** - * Initialise the builder using a PublicKey. - * - * @param issuer X500Name representing the issuer of this certificate. - * @param serial the serial number for the certificate. - * @param notBefore Time before which the certificate is not valid. - * @param notAfter Time after which the certificate is not valid. - * @param subject X500Name representing the subject of this certificate. - * @param publicKey the public key to be associated with the certificate. - */ - public JcaX509v3CertificateBuilder(X500Name issuer, BigInteger serial, Time notBefore, Time notAfter, X500Name subject, PublicKey publicKey) - { - super(issuer, serial, notBefore, notAfter, subject, SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); - } - - /** - * Initialise the builder using X500Principal objects and a PublicKey. - * - * @param issuer principal representing the issuer of this certificate. - * @param serial the serial number for the certificate. - * @param notBefore date before which the certificate is not valid. - * @param notAfter date after which the certificate is not valid. - * @param subject principal representing the subject of this certificate. - * @param publicKey the public key to be associated with the certificate. - */ - public JcaX509v3CertificateBuilder(X500Principal issuer, BigInteger serial, Date notBefore, Date notAfter, X500Principal subject, PublicKey publicKey) - { - super(X500Name.getInstance(issuer.getEncoded()), serial, notBefore, notAfter, X500Name.getInstance(subject.getEncoded()), SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); - } - - /** - * Initialise the builder using the subject from the passed in issuerCert as the issuer, as well as - * passing through and converting the other objects provided. - * - * @param issuerCert certificate who's subject is the issuer of the certificate we are building. - * @param serial the serial number for the certificate. - * @param notBefore date before which the certificate is not valid. - * @param notAfter date after which the certificate is not valid. - * @param subject principal representing the subject of this certificate. - * @param publicKey the public key to be associated with the certificate. - */ - public JcaX509v3CertificateBuilder(X509Certificate issuerCert, BigInteger serial, Date notBefore, Date notAfter, X500Principal subject, PublicKey publicKey) - { - this(issuerCert.getSubjectX500Principal(), serial, notBefore, notAfter, subject, publicKey); - } - - /** - * Initialise the builder using the subject from the passed in issuerCert as the issuer, as well as - * passing through and converting the other objects provided. - * - * @param issuerCert certificate who's subject is the issuer of the certificate we are building. - * @param serial the serial number for the certificate. - * @param notBefore date before which the certificate is not valid. - * @param notAfter date after which the certificate is not valid. - * @param subject principal representing the subject of this certificate. - * @param publicKey the public key to be associated with the certificate. - */ - public JcaX509v3CertificateBuilder(X509Certificate issuerCert, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, PublicKey publicKey) - { - this(X500Name.getInstance(issuerCert.getSubjectX500Principal().getEncoded()), serial, notBefore, notAfter, subject, publicKey); - } - - /** - * Add a given extension field for the standard extensions tag (tag 3) - * copying the extension value from another certificate. - * - * @param oid the type of the extension to be copied. - * @param critical true if the extension is to be marked critical, false otherwise. - * @param certificate the source of the extension to be copied. - * @return the builder instance. - */ - public JcaX509v3CertificateBuilder copyAndAddExtension( - ASN1ObjectIdentifier oid, - boolean critical, - X509Certificate certificate) - throws CertificateEncodingException - { - this.copyAndAddExtension(oid, critical, new JcaX509CertificateHolder(certificate)); - - return this; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/jcajce/NamedCertHelper.java b/pkix/src/main/java/org/bouncycastle/cert/jcajce/NamedCertHelper.java deleted file mode 100644 index 5cd2feb4..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/jcajce/NamedCertHelper.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.bouncycastle.cert.jcajce; - -import java.security.NoSuchProviderException; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; - -class NamedCertHelper - extends CertHelper -{ - private final String providerName; - - NamedCertHelper(String providerName) - { - this.providerName = providerName; - } - - protected CertificateFactory createCertificateFactory(String type) - throws CertificateException, NoSuchProviderException - { - return CertificateFactory.getInstance(type, providerName); - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cert/jcajce/ProviderCertHelper.java b/pkix/src/main/java/org/bouncycastle/cert/jcajce/ProviderCertHelper.java deleted file mode 100644 index 15c9e729..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/jcajce/ProviderCertHelper.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.bouncycastle.cert.jcajce; - -import java.security.Provider; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; - -class ProviderCertHelper - extends CertHelper -{ - private final Provider provider; - - ProviderCertHelper(Provider provider) - { - this.provider = provider; - } - - protected CertificateFactory createCertificateFactory(String type) - throws CertificateException - { - return CertificateFactory.getInstance(type, provider); - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cert/ocsp/BasicOCSPResp.java b/pkix/src/main/java/org/bouncycastle/cert/ocsp/BasicOCSPResp.java deleted file mode 100644 index 82b9f232..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/ocsp/BasicOCSPResp.java +++ /dev/null @@ -1,212 +0,0 @@ -package 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 org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.ocsp.BasicOCSPResponse; -import org.bouncycastle.asn1.ocsp.ResponseData; -import org.bouncycastle.asn1.ocsp.SingleResponse; -import org.bouncycastle.asn1.x509.Certificate; -import org.bouncycastle.asn1.x509.Extension; -import org.bouncycastle.asn1.x509.Extensions; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.operator.ContentVerifier; -import org.bouncycastle.operator.ContentVerifierProvider; - -/** - * <pre> - * BasicOCSPResponse ::= SEQUENCE { - * tbsResponseData ResponseData, - * signatureAlgorithm AlgorithmIdentifier, - * signature BIT STRING, - * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } - * </pre> - */ -public class BasicOCSPResp -{ - 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; - } - } - - 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().getBytes(); - } - - 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/pkix/src/main/java/org/bouncycastle/cert/ocsp/BasicOCSPRespBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/ocsp/BasicOCSPRespBuilder.java deleted file mode 100644 index d06dcfca..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/ocsp/BasicOCSPRespBuilder.java +++ /dev/null @@ -1,264 +0,0 @@ -package 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 org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.ASN1GeneralizedTime; -import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.DERGeneralizedTime; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.ocsp.BasicOCSPResponse; -import org.bouncycastle.asn1.ocsp.CertStatus; -import org.bouncycastle.asn1.ocsp.ResponseData; -import org.bouncycastle.asn1.ocsp.RevokedInfo; -import org.bouncycastle.asn1.ocsp.SingleResponse; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.CRLReason; -import org.bouncycastle.asn1.x509.Extensions; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.operator.ContentSigner; -import 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.toASN1Object(), 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) - { - list.add(new ResponseObject(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) - { - list.add(new ResponseObject(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) - { - list.add(new ResponseObject(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 - * @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.toASN1Object(), 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/pkix/src/main/java/org/bouncycastle/cert/ocsp/CertificateID.java b/pkix/src/main/java/org/bouncycastle/cert/ocsp/CertificateID.java deleted file mode 100644 index c6b09ad8..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/ocsp/CertificateID.java +++ /dev/null @@ -1,156 +0,0 @@ -package org.bouncycastle.cert.ocsp; - -import java.io.OutputStream; -import java.math.BigInteger; - -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.ocsp.CertID; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.operator.DigestCalculator; -import org.bouncycastle.operator.DigestCalculatorProvider; -import 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 toASN1Object() - { - 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/pkix/src/main/java/org/bouncycastle/cert/ocsp/CertificateStatus.java b/pkix/src/main/java/org/bouncycastle/cert/ocsp/CertificateStatus.java deleted file mode 100644 index 3aa117df..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/ocsp/CertificateStatus.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.bouncycastle.cert.ocsp; - -public interface CertificateStatus -{ - public static final CertificateStatus GOOD = null; -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPException.java b/pkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPException.java deleted file mode 100644 index 6489788c..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPException.java +++ /dev/null @@ -1,27 +0,0 @@ -package 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/pkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPReq.java b/pkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPReq.java deleted file mode 100644 index 2706c401..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPReq.java +++ /dev/null @@ -1,259 +0,0 @@ -package 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 org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.ASN1Exception; -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OutputStream; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.ocsp.OCSPRequest; -import org.bouncycastle.asn1.ocsp.Request; -import org.bouncycastle.asn1.x509.Certificate; -import org.bouncycastle.asn1.x509.Extension; -import org.bouncycastle.asn1.x509.Extensions; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.cert.CertIOException; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.operator.ContentVerifier; -import 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().getBytes(); - } - - 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/pkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPReqBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPReqBuilder.java deleted file mode 100644 index e7e8e0f5..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPReqBuilder.java +++ /dev/null @@ -1,199 +0,0 @@ -package org.bouncycastle.cert.ocsp; - -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.ocsp.OCSPRequest; -import org.bouncycastle.asn1.ocsp.Request; -import org.bouncycastle.asn1.ocsp.Signature; -import org.bouncycastle.asn1.ocsp.TBSRequest; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.Extensions; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.cert.X509CertificateHolder; -import 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.toASN1Object(), 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 X500Principal - * - * @param requestorName a X500Principal 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 org.bouncycastle.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/pkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPResp.java b/pkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPResp.java deleted file mode 100644 index ed3918ac..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPResp.java +++ /dev/null @@ -1,141 +0,0 @@ -package org.bouncycastle.cert.ocsp; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; - -import org.bouncycastle.asn1.ASN1Exception; -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ocsp.BasicOCSPResponse; -import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers; -import org.bouncycastle.asn1.ocsp.OCSPResponse; -import org.bouncycastle.asn1.ocsp.ResponseBytes; -import 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/pkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPRespBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPRespBuilder.java deleted file mode 100644 index c372ebff..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPRespBuilder.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.bouncycastle.cert.ocsp; - -import java.io.IOException; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers; -import org.bouncycastle.asn1.ocsp.OCSPResponse; -import org.bouncycastle.asn1.ocsp.OCSPResponseStatus; -import 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/pkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPUtils.java b/pkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPUtils.java deleted file mode 100644 index a84f409c..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPUtils.java +++ /dev/null @@ -1,64 +0,0 @@ -package 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 org.bouncycastle.asn1.ASN1GeneralizedTime; -import org.bouncycastle.asn1.x509.Extensions; -import 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/pkix/src/main/java/org/bouncycastle/cert/ocsp/Req.java b/pkix/src/main/java/org/bouncycastle/cert/ocsp/Req.java deleted file mode 100644 index 6df083c5..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/ocsp/Req.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.bouncycastle.cert.ocsp; - -import org.bouncycastle.asn1.ocsp.Request; -import 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/pkix/src/main/java/org/bouncycastle/cert/ocsp/RespData.java b/pkix/src/main/java/org/bouncycastle/cert/ocsp/RespData.java deleted file mode 100644 index 6960fa8f..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/ocsp/RespData.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.bouncycastle.cert.ocsp; - -import java.util.Date; - -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.ocsp.ResponseData; -import org.bouncycastle.asn1.ocsp.SingleResponse; -import 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/pkix/src/main/java/org/bouncycastle/cert/ocsp/RespID.java b/pkix/src/main/java/org/bouncycastle/cert/ocsp/RespID.java deleted file mode 100644 index 4322ab5b..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/ocsp/RespID.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.bouncycastle.cert.ocsp; - -import java.io.OutputStream; - -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.ocsp.ResponderID; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import 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"); - } - - 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 toASN1Object() - { - 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/pkix/src/main/java/org/bouncycastle/cert/ocsp/RevokedStatus.java b/pkix/src/main/java/org/bouncycastle/cert/ocsp/RevokedStatus.java deleted file mode 100644 index d349f076..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/ocsp/RevokedStatus.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.bouncycastle.cert.ocsp; - -import java.util.Date; - -import org.bouncycastle.asn1.ASN1GeneralizedTime; -import org.bouncycastle.asn1.ocsp.RevokedInfo; -import 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/pkix/src/main/java/org/bouncycastle/cert/ocsp/SingleResp.java b/pkix/src/main/java/org/bouncycastle/cert/ocsp/SingleResp.java deleted file mode 100644 index ece7ea2e..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/ocsp/SingleResp.java +++ /dev/null @@ -1,102 +0,0 @@ -package org.bouncycastle.cert.ocsp; - -import java.util.Date; -import java.util.List; -import java.util.Set; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ocsp.CertStatus; -import org.bouncycastle.asn1.ocsp.RevokedInfo; -import org.bouncycastle.asn1.ocsp.SingleResponse; -import org.bouncycastle.asn1.x509.Extension; -import 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/pkix/src/main/java/org/bouncycastle/cert/ocsp/UnknownStatus.java b/pkix/src/main/java/org/bouncycastle/cert/ocsp/UnknownStatus.java deleted file mode 100644 index 8d60e2ba..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/ocsp/UnknownStatus.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.bouncycastle.cert.ocsp; - -/** - * wrapper for the UnknownInfo object - */ -public class UnknownStatus - implements CertificateStatus -{ - public UnknownStatus() - { - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/ocsp/jcajce/JcaBasicOCSPRespBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/ocsp/jcajce/JcaBasicOCSPRespBuilder.java deleted file mode 100644 index 94bf52f0..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/ocsp/jcajce/JcaBasicOCSPRespBuilder.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.bouncycastle.cert.ocsp.jcajce; - -import java.security.PublicKey; - -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.cert.ocsp.BasicOCSPRespBuilder; -import org.bouncycastle.cert.ocsp.OCSPException; -import 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/pkix/src/main/java/org/bouncycastle/cert/ocsp/jcajce/JcaCertificateID.java b/pkix/src/main/java/org/bouncycastle/cert/ocsp/jcajce/JcaCertificateID.java deleted file mode 100644 index 446b38bb..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/ocsp/jcajce/JcaCertificateID.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.bouncycastle.cert.ocsp.jcajce; - -import java.math.BigInteger; -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; - -import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; -import org.bouncycastle.cert.ocsp.CertificateID; -import org.bouncycastle.cert.ocsp.OCSPException; -import 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/pkix/src/main/java/org/bouncycastle/cert/ocsp/jcajce/JcaRespID.java b/pkix/src/main/java/org/bouncycastle/cert/ocsp/jcajce/JcaRespID.java deleted file mode 100644 index 8bc9edbd..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/ocsp/jcajce/JcaRespID.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.bouncycastle.cert.ocsp.jcajce; - -import java.security.PublicKey; - -import javax.security.auth.x500.X500Principal; - -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.cert.ocsp.OCSPException; -import org.bouncycastle.cert.ocsp.RespID; -import 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/pkix/src/main/java/org/bouncycastle/cert/path/CertPath.java b/pkix/src/main/java/org/bouncycastle/cert/path/CertPath.java deleted file mode 100644 index f91b3a81..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/path/CertPath.java +++ /dev/null @@ -1,80 +0,0 @@ -package org.bouncycastle.cert.path; - -import org.bouncycastle.cert.X509CertificateHolder; - -public class CertPath -{ - private final X509CertificateHolder[] certificates; - - public CertPath(X509CertificateHolder[] certificates) - { - this.certificates = copyArray(certificates); - } - - public X509CertificateHolder[] getCertificates() - { - return copyArray(certificates); - } - - public CertPathValidationResult validate(CertPathValidation[] ruleSet) - { - CertPathValidationContext context = new CertPathValidationContext(CertPathUtils.getCriticalExtensionsOIDs(certificates)); - - for (int i = 0; i != ruleSet.length; i++) - { - for (int j = certificates.length - 1; j >= 0; j--) - { - try - { - context.setIsEndEntity(j == 0); - ruleSet[i].validate(context, certificates[j]); - } - catch (CertPathValidationException e) - { // TODO: introduce object to hold (i and e) - return new CertPathValidationResult(context, j, i, e); - } - } - } - - return new CertPathValidationResult(context); - } - - public CertPathValidationResult evaluate(CertPathValidation[] ruleSet) - { - CertPathValidationContext context = new CertPathValidationContext(CertPathUtils.getCriticalExtensionsOIDs(certificates)); - - CertPathValidationResultBuilder builder = new CertPathValidationResultBuilder(); - - for (int i = 0; i != ruleSet.length; i++) - { - for (int j = certificates.length - 1; j >= 0; j--) - { - try - { - context.setIsEndEntity(j == 0); - ruleSet[i].validate(context, certificates[j]); - } - catch (CertPathValidationException e) - { - builder.addException(e); - } - } - } - - return builder.build(); - } - - private X509CertificateHolder[] copyArray(X509CertificateHolder[] array) - { - X509CertificateHolder[] rv = new X509CertificateHolder[array.length]; - - System.arraycopy(array, 0, rv, 0, rv.length); - - return rv; - } - - public int length() - { - return certificates.length; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/path/CertPathUtils.java b/pkix/src/main/java/org/bouncycastle/cert/path/CertPathUtils.java deleted file mode 100644 index 4811a3d8..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/path/CertPathUtils.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.bouncycastle.cert.path; - -import java.util.HashSet; -import java.util.Set; - -import org.bouncycastle.cert.X509CertificateHolder; - -class CertPathUtils -{ - static Set getCriticalExtensionsOIDs(X509CertificateHolder[] certificates) - { - Set criticalExtensions = new HashSet(); - - for (int i = 0; i != certificates.length; i++) - { - criticalExtensions.addAll(certificates[i].getCriticalExtensionOIDs()); - } - - return criticalExtensions; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/path/CertPathValidation.java b/pkix/src/main/java/org/bouncycastle/cert/path/CertPathValidation.java deleted file mode 100644 index 2704fe64..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/path/CertPathValidation.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.bouncycastle.cert.path; - -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.util.Memoable; - -public interface CertPathValidation - extends Memoable -{ - public void validate(CertPathValidationContext context, X509CertificateHolder certificate) - throws CertPathValidationException; -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/path/CertPathValidationContext.java b/pkix/src/main/java/org/bouncycastle/cert/path/CertPathValidationContext.java deleted file mode 100644 index 6a4b0ec2..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/path/CertPathValidationContext.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.bouncycastle.cert.path; - -import java.util.HashSet; -import java.util.Set; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.util.Memoable; - -public class CertPathValidationContext - implements Memoable -{ - private Set criticalExtensions; - - private Set handledExtensions = new HashSet(); - private boolean endEntity; - private int index; - - public CertPathValidationContext(Set criticalExtensionsOIDs) - { - this.criticalExtensions = criticalExtensionsOIDs; - } - - public void addHandledExtension(ASN1ObjectIdentifier extensionIdentifier) - { - this.handledExtensions.add(extensionIdentifier); - } - - public void setIsEndEntity(boolean isEndEntity) - { - this.endEntity = isEndEntity; - } - - public Set getUnhandledCriticalExtensionOIDs() - { - Set rv = new HashSet(criticalExtensions); - - rv.removeAll(handledExtensions); - - return rv; - } - - /** - * Returns true if the current certificate is the end-entity certificate. - * - * @return if current cert end-entity, false otherwise. - */ - public boolean isEndEntity() - { - return endEntity; - } - - public Memoable copy() - { - return null; //To change body of implemented methods use File | Settings | File Templates. - } - - public void reset(Memoable other) - { - //To change body of implemented methods use File | Settings | File Templates. - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/path/CertPathValidationException.java b/pkix/src/main/java/org/bouncycastle/cert/path/CertPathValidationException.java deleted file mode 100644 index 958f2d0c..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/path/CertPathValidationException.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.bouncycastle.cert.path; - -public class CertPathValidationException - extends Exception -{ - private final Exception cause; - - public CertPathValidationException(String msg) - { - this(msg, null); - } - - public CertPathValidationException(String msg, Exception cause) - { - super(msg); - - this.cause = cause; - } - - public Throwable getCause() - { - return cause; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/path/CertPathValidationResult.java b/pkix/src/main/java/org/bouncycastle/cert/path/CertPathValidationResult.java deleted file mode 100644 index facefb45..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/path/CertPathValidationResult.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.bouncycastle.cert.path; - -import java.util.Collections; -import java.util.Set; - -public class CertPathValidationResult -{ - private final boolean isValid; - private final CertPathValidationException cause; - private final Set unhandledCriticalExtensionOIDs; - - private int[] certIndexes; - - public CertPathValidationResult(CertPathValidationContext context) - { - this.unhandledCriticalExtensionOIDs = Collections.unmodifiableSet(context.getUnhandledCriticalExtensionOIDs()); - this.isValid = this.unhandledCriticalExtensionOIDs.isEmpty(); - cause = null; - } - - public CertPathValidationResult(CertPathValidationContext context, int certIndex, int ruleIndex, CertPathValidationException cause) - { - this.unhandledCriticalExtensionOIDs = Collections.unmodifiableSet(context.getUnhandledCriticalExtensionOIDs()); - this.isValid = false; - this.cause = cause; - } - - public CertPathValidationResult(CertPathValidationContext context, int[] certIndexes, int[] ruleIndexes, CertPathValidationException[] cause) - { - // TODO - this.unhandledCriticalExtensionOIDs = Collections.unmodifiableSet(context.getUnhandledCriticalExtensionOIDs()); - this.isValid = false; - this.cause = cause[0]; - this.certIndexes = certIndexes; - } - - public boolean isValid() - { - return isValid; - } - - public Exception getCause() - { - if (cause != null) - { - return cause; - } - - if (!unhandledCriticalExtensionOIDs.isEmpty()) - { - return new CertPathValidationException("Unhandled Critical Extensions"); - } - - return null; - } - - public Set getUnhandledCriticalExtensionOIDs() - { - return unhandledCriticalExtensionOIDs; - } - - public boolean isDetailed() - { - return this.certIndexes != null; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/path/CertPathValidationResultBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/path/CertPathValidationResultBuilder.java deleted file mode 100644 index 9e813396..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/path/CertPathValidationResultBuilder.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.bouncycastle.cert.path; - -class CertPathValidationResultBuilder -{ - public CertPathValidationResult build() - { - return new CertPathValidationResult(null, 0, 0, null); - } - - public void addException(CertPathValidationException exception) - { - //To change body of created methods use File | Settings | File Templates. - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/path/validations/BasicConstraintsValidation.java b/pkix/src/main/java/org/bouncycastle/cert/path/validations/BasicConstraintsValidation.java deleted file mode 100644 index db4f8527..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/path/validations/BasicConstraintsValidation.java +++ /dev/null @@ -1,103 +0,0 @@ -package org.bouncycastle.cert.path.validations; - -import java.math.BigInteger; - -import org.bouncycastle.asn1.x509.BasicConstraints; -import org.bouncycastle.asn1.x509.Extension; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cert.path.CertPathValidation; -import org.bouncycastle.cert.path.CertPathValidationContext; -import org.bouncycastle.cert.path.CertPathValidationException; -import org.bouncycastle.util.Memoable; - -public class BasicConstraintsValidation - implements CertPathValidation -{ - private boolean isMandatory; - private BasicConstraints bc; - private int maxPathLength; - - public BasicConstraintsValidation() - { - this(true); - } - - public BasicConstraintsValidation(boolean isMandatory) - { - this.isMandatory = isMandatory; - } - - public void validate(CertPathValidationContext context, X509CertificateHolder certificate) - throws CertPathValidationException - { - if (maxPathLength < 0) - { - throw new CertPathValidationException("BasicConstraints path length exceeded"); - } - - context.addHandledExtension(Extension.basicConstraints); - - BasicConstraints certBC = BasicConstraints.fromExtensions(certificate.getExtensions()); - - if (certBC != null) - { - if (bc != null) - { - if (certBC.isCA()) - { - BigInteger pathLengthConstraint = certBC.getPathLenConstraint(); - - if (pathLengthConstraint != null) - { - int plc = pathLengthConstraint.intValue(); - - if (plc < maxPathLength) - { - maxPathLength = plc; - bc = certBC; - } - } - } - } - else - { - bc = certBC; - if (certBC.isCA()) - { - maxPathLength = certBC.getPathLenConstraint().intValue(); - } - } - } - else - { - if (bc != null) - { - maxPathLength--; - } - } - - if (isMandatory && bc == null) - { - throw new CertPathValidationException("BasicConstraints not present in path"); - } - } - - public Memoable copy() - { - BasicConstraintsValidation v = new BasicConstraintsValidation(isMandatory); - - v.bc = this.bc; - v.maxPathLength = this.maxPathLength; - - return v; - } - - public void reset(Memoable other) - { - BasicConstraintsValidation v = (BasicConstraintsValidation)other; - - this.isMandatory = v.isMandatory; - this.bc = v.bc; - this.maxPathLength = v.maxPathLength; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/path/validations/CRLValidation.java b/pkix/src/main/java/org/bouncycastle/cert/path/validations/CRLValidation.java deleted file mode 100644 index c44b7c0d..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/path/validations/CRLValidation.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.bouncycastle.cert.path.validations; - -import java.util.Collection; -import java.util.Iterator; - -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.cert.X509CRLHolder; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cert.path.CertPathValidation; -import org.bouncycastle.cert.path.CertPathValidationContext; -import org.bouncycastle.cert.path.CertPathValidationException; -import org.bouncycastle.util.Memoable; -import org.bouncycastle.util.Selector; -import org.bouncycastle.util.Store; - -public class CRLValidation - implements CertPathValidation -{ - private Store crls; - private X500Name workingIssuerName; - - public CRLValidation(X500Name trustAnchorName, Store crls) - { - this.workingIssuerName = trustAnchorName; - this.crls = crls; - } - - public void validate(CertPathValidationContext context, X509CertificateHolder certificate) - throws CertPathValidationException - { - // TODO: add handling of delta CRLs - Collection matches = crls.getMatches(new Selector() - { - public boolean match(Object obj) - { - X509CRLHolder crl = (X509CRLHolder)obj; - - return (crl.getIssuer().equals(workingIssuerName)); - } - - public Object clone() - { - return this; - } - }); - - if (matches.isEmpty()) - { - throw new CertPathValidationException("CRL for " + workingIssuerName + " not found"); - } - - for (Iterator it = matches.iterator(); it.hasNext();) - { - X509CRLHolder crl = (X509CRLHolder)it.next(); - - // TODO: not quite right! - if (crl.getRevokedCertificate(certificate.getSerialNumber()) != null) - { - throw new CertPathValidationException("Certificate revoked"); - } - } - - this.workingIssuerName = certificate.getSubject(); - } - - public Memoable copy() - { - return new CRLValidation(workingIssuerName, crls); - } - - public void reset(Memoable other) - { - CRLValidation v = (CRLValidation)other; - - this.workingIssuerName = v.workingIssuerName; - this.crls = v.crls; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/path/validations/CertificatePoliciesValidation.java b/pkix/src/main/java/org/bouncycastle/cert/path/validations/CertificatePoliciesValidation.java deleted file mode 100644 index ebaf9897..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/path/validations/CertificatePoliciesValidation.java +++ /dev/null @@ -1,146 +0,0 @@ -package org.bouncycastle.cert.path.validations; - -import java.math.BigInteger; - -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.x509.Extension; -import org.bouncycastle.asn1.x509.PolicyConstraints; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cert.path.CertPathValidation; -import org.bouncycastle.cert.path.CertPathValidationContext; -import org.bouncycastle.cert.path.CertPathValidationException; -import org.bouncycastle.util.Memoable; - -public class CertificatePoliciesValidation - implements CertPathValidation -{ - private int explicitPolicy; - private int policyMapping; - private int inhibitAnyPolicy; - - CertificatePoliciesValidation(int pathLength) - { - this(pathLength, false, false, false); - } - - CertificatePoliciesValidation(int pathLength, boolean isExplicitPolicyRequired, boolean isAnyPolicyInhibited, boolean isPolicyMappingInhibited) - { - // - // (d) - // - - if (isExplicitPolicyRequired) - { - explicitPolicy = 0; - } - else - { - explicitPolicy = pathLength + 1; - } - - // - // (e) - // - if (isAnyPolicyInhibited) - { - inhibitAnyPolicy = 0; - } - else - { - inhibitAnyPolicy = pathLength + 1; - } - - // - // (f) - // - if (isPolicyMappingInhibited) - { - policyMapping = 0; - } - else - { - policyMapping = pathLength + 1; - } - } - - public void validate(CertPathValidationContext context, X509CertificateHolder certificate) - throws CertPathValidationException - { - context.addHandledExtension(Extension.policyConstraints); - context.addHandledExtension(Extension.inhibitAnyPolicy); - - if (!context.isEndEntity()) - { - if (!ValidationUtils.isSelfIssued(certificate)) - { - // - // H (1), (2), (3) - // - explicitPolicy = countDown(explicitPolicy); - policyMapping = countDown(policyMapping); - inhibitAnyPolicy = countDown(inhibitAnyPolicy); - - // - // I (1), (2) - // - PolicyConstraints policyConstraints = PolicyConstraints.fromExtensions(certificate.getExtensions()); - - if (policyConstraints != null) - { - BigInteger requireExplicitPolicyMapping = policyConstraints.getRequireExplicitPolicyMapping(); - if (requireExplicitPolicyMapping != null) - { - if (requireExplicitPolicyMapping.intValue() < explicitPolicy) - { - explicitPolicy = requireExplicitPolicyMapping.intValue(); - } - } - - BigInteger inhibitPolicyMapping = policyConstraints.getInhibitPolicyMapping(); - if (inhibitPolicyMapping != null) - { - if (inhibitPolicyMapping.intValue() < policyMapping) - { - policyMapping = inhibitPolicyMapping.intValue(); - } - } - } - - // - // J - // - Extension ext = certificate.getExtension(Extension.inhibitAnyPolicy); - - if (ext != null) - { - int extValue = ASN1Integer.getInstance(ext.getParsedValue()).getValue().intValue(); - - if (extValue < inhibitAnyPolicy) - { - inhibitAnyPolicy = extValue; - } - } - } - } - } - - private int countDown(int policyCounter) - { - if (policyCounter != 0) - { - return policyCounter - 1; - } - - return 0; - } - - public Memoable copy() - { - return new CertificatePoliciesValidation(0); // TODO: - } - - public void reset(Memoable other) - { - CertificatePoliciesValidation v = (CertificatePoliciesValidation)other; // TODO: - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/path/validations/CertificatePoliciesValidationBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/path/validations/CertificatePoliciesValidationBuilder.java deleted file mode 100644 index 74b622e1..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/path/validations/CertificatePoliciesValidationBuilder.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.bouncycastle.cert.path.validations; - -import org.bouncycastle.cert.path.CertPath; - -public class CertificatePoliciesValidationBuilder -{ - private boolean isExplicitPolicyRequired; - private boolean isAnyPolicyInhibited; - private boolean isPolicyMappingInhibited; - - public void setAnyPolicyInhibited(boolean anyPolicyInhibited) - { - isAnyPolicyInhibited = anyPolicyInhibited; - } - - public void setExplicitPolicyRequired(boolean explicitPolicyRequired) - { - isExplicitPolicyRequired = explicitPolicyRequired; - } - - public void setPolicyMappingInhibited(boolean policyMappingInhibited) - { - isPolicyMappingInhibited = policyMappingInhibited; - } - - public CertificatePoliciesValidation build(int pathLen) - { - return new CertificatePoliciesValidation(pathLen, isExplicitPolicyRequired, isAnyPolicyInhibited, isPolicyMappingInhibited); - } - - public CertificatePoliciesValidation build(CertPath path) - { - return build(path.length()); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/path/validations/KeyUsageValidation.java b/pkix/src/main/java/org/bouncycastle/cert/path/validations/KeyUsageValidation.java deleted file mode 100644 index 5d9adc82..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/path/validations/KeyUsageValidation.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.bouncycastle.cert.path.validations; - -import org.bouncycastle.asn1.x509.Extension; -import org.bouncycastle.asn1.x509.KeyUsage; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cert.path.CertPathValidation; -import org.bouncycastle.cert.path.CertPathValidationContext; -import org.bouncycastle.cert.path.CertPathValidationException; -import org.bouncycastle.util.Memoable; - -public class KeyUsageValidation - implements CertPathValidation -{ - private boolean isMandatory; - - public KeyUsageValidation() - { - this(true); - } - - public KeyUsageValidation(boolean isMandatory) - { - this.isMandatory = isMandatory; - } - - public void validate(CertPathValidationContext context, X509CertificateHolder certificate) - throws CertPathValidationException - { - context.addHandledExtension(Extension.keyUsage); - - if (!context.isEndEntity()) - { - KeyUsage usage = KeyUsage.fromExtensions(certificate.getExtensions()); - - if (usage != null) - { - if (!usage.hasUsages(KeyUsage.keyCertSign)) - { - throw new CertPathValidationException("Issuer certificate KeyUsage extension does not permit key signing"); - } - } - else - { - if (isMandatory) - { - throw new CertPathValidationException("KeyUsage extension not present in CA certificate"); - } - } - } - } - - public Memoable copy() - { - return new KeyUsageValidation(isMandatory); - } - - public void reset(Memoable other) - { - KeyUsageValidation v = (KeyUsageValidation)other; - - this.isMandatory = v.isMandatory; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/path/validations/ParentCertIssuedValidation.java b/pkix/src/main/java/org/bouncycastle/cert/path/validations/ParentCertIssuedValidation.java deleted file mode 100644 index a21ad1c4..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/path/validations/ParentCertIssuedValidation.java +++ /dev/null @@ -1,127 +0,0 @@ -package org.bouncycastle.cert.path.validations; - -import java.io.IOException; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1Null; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.cert.CertException; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cert.X509ContentVerifierProviderBuilder; -import org.bouncycastle.cert.path.CertPathValidation; -import org.bouncycastle.cert.path.CertPathValidationContext; -import org.bouncycastle.cert.path.CertPathValidationException; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.util.Memoable; - -public class ParentCertIssuedValidation - implements CertPathValidation -{ - private X509ContentVerifierProviderBuilder contentVerifierProvider; - - private X500Name workingIssuerName; - private SubjectPublicKeyInfo workingPublicKey; - private AlgorithmIdentifier workingAlgId; - - public ParentCertIssuedValidation(X509ContentVerifierProviderBuilder contentVerifierProvider) - { - this.contentVerifierProvider = contentVerifierProvider; - } - - public void validate(CertPathValidationContext context, X509CertificateHolder certificate) - throws CertPathValidationException - { - if (workingIssuerName != null) - { - if (!workingIssuerName.equals(certificate.getIssuer())) - { - throw new CertPathValidationException("Certificate issue does not match parent"); - } - } - - if (workingPublicKey != null) - { - try - { - SubjectPublicKeyInfo validatingKeyInfo; - - if (workingPublicKey.getAlgorithm().equals(workingAlgId)) - { - validatingKeyInfo = workingPublicKey; - } - else - { - validatingKeyInfo = new SubjectPublicKeyInfo(workingAlgId, workingPublicKey.parsePublicKey()); - } - - if (!certificate.isSignatureValid(contentVerifierProvider.build(validatingKeyInfo))) - { - throw new CertPathValidationException("Certificate signature not for public key in parent"); - } - } - catch (OperatorCreationException e) - { - throw new CertPathValidationException("Unable to create verifier: " + e.getMessage(), e); - } - catch (CertException e) - { - throw new CertPathValidationException("Unable to validate signature: " + e.getMessage(), e); - } - catch (IOException e) - { - throw new CertPathValidationException("Unable to build public key: " + e.getMessage(), e); - } - } - - workingIssuerName = certificate.getSubject(); - workingPublicKey = certificate.getSubjectPublicKeyInfo(); - - if (workingAlgId != null) - { - // check for inherited parameters - if (workingPublicKey.getAlgorithm().getAlgorithm().equals(workingAlgId.getAlgorithm())) - { - if (!isNull(workingPublicKey.getAlgorithm().getParameters())) - { - workingAlgId = workingPublicKey.getAlgorithm(); - } - } - else - { - workingAlgId = workingPublicKey.getAlgorithm(); - } - } - else - { - workingAlgId = workingPublicKey.getAlgorithm(); - } - } - - private boolean isNull(ASN1Encodable obj) - { - return obj == null || obj instanceof ASN1Null; - } - - public Memoable copy() - { - ParentCertIssuedValidation v = new ParentCertIssuedValidation(contentVerifierProvider); - - v.workingAlgId = this.workingAlgId; - v.workingIssuerName = this.workingIssuerName; - v.workingPublicKey = this.workingPublicKey; - - return v; - } - - public void reset(Memoable other) - { - ParentCertIssuedValidation v = (ParentCertIssuedValidation)other; - - this.contentVerifierProvider = v.contentVerifierProvider; - this.workingAlgId = v.workingAlgId; - this.workingIssuerName = v.workingIssuerName; - this.workingPublicKey = v.workingPublicKey; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/path/validations/ValidationUtils.java b/pkix/src/main/java/org/bouncycastle/cert/path/validations/ValidationUtils.java deleted file mode 100644 index 2a587065..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/path/validations/ValidationUtils.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.bouncycastle.cert.path.validations; - -import org.bouncycastle.cert.X509CertificateHolder; - -class ValidationUtils -{ - static boolean isSelfIssued(X509CertificateHolder cert) - { - return cert.getSubject().equals(cert.getIssuer()); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/selector/MSOutlookKeyIdCalculator.java b/pkix/src/main/java/org/bouncycastle/cert/selector/MSOutlookKeyIdCalculator.java deleted file mode 100644 index 8f6d119c..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/selector/MSOutlookKeyIdCalculator.java +++ /dev/null @@ -1,422 +0,0 @@ -package org.bouncycastle.cert.selector; - -import java.io.IOException; - -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import 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/pkix/src/main/java/org/bouncycastle/cert/selector/X509AttributeCertificateHolderSelector.java b/pkix/src/main/java/org/bouncycastle/cert/selector/X509AttributeCertificateHolderSelector.java deleted file mode 100644 index c325fbad..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/selector/X509AttributeCertificateHolderSelector.java +++ /dev/null @@ -1,268 +0,0 @@ -package org.bouncycastle.cert.selector; - -import java.math.BigInteger; -import java.util.Collection; -import java.util.Date; - -import org.bouncycastle.asn1.x509.Extension; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.asn1.x509.Target; -import org.bouncycastle.asn1.x509.TargetInformation; -import org.bouncycastle.asn1.x509.Targets; -import org.bouncycastle.cert.AttributeCertificateHolder; -import org.bouncycastle.cert.AttributeCertificateIssuer; -import org.bouncycastle.cert.X509AttributeCertificateHolder; -import org.bouncycastle.util.Selector; - -/** - * This class is an <code>Selector</code> like implementation to select - * attribute certificates from a given set of criteria. - */ -public class X509AttributeCertificateHolderSelector - implements Selector -{ - - // TODO: name constraints??? - - private final AttributeCertificateHolder holder; - - private final AttributeCertificateIssuer issuer; - - private final BigInteger serialNumber; - - private final Date attributeCertificateValid; - - private final X509AttributeCertificateHolder attributeCert; - - private final Collection targetNames; - - private final Collection targetGroups; - - X509AttributeCertificateHolderSelector( - AttributeCertificateHolder holder, - AttributeCertificateIssuer issuer, - BigInteger serialNumber, - Date attributeCertificateValid, - X509AttributeCertificateHolder attributeCert, - Collection targetNames, - Collection targetGroups) - { - this.holder = holder; - this.issuer = issuer; - this.serialNumber = serialNumber; - this.attributeCertificateValid = attributeCertificateValid; - this.attributeCert = attributeCert; - this.targetNames = targetNames; - this.targetGroups = targetGroups; - } - - /** - * Decides if the given attribute certificate should be selected. - * - * @param obj The X509AttributeCertificateHolder which should be checked. - * @return <code>true</code> if the attribute certificate is a match - * <code>false</code> otherwise. - */ - public boolean match(Object obj) - { - if (!(obj instanceof X509AttributeCertificateHolder)) - { - return false; - } - - X509AttributeCertificateHolder attrCert = (X509AttributeCertificateHolder)obj; - - if (this.attributeCert != null) - { - if (!this.attributeCert.equals(attrCert)) - { - return false; - } - } - if (serialNumber != null) - { - if (!attrCert.getSerialNumber().equals(serialNumber)) - { - return false; - } - } - if (holder != null) - { - if (!attrCert.getHolder().equals(holder)) - { - return false; - } - } - if (issuer != null) - { - if (!attrCert.getIssuer().equals(issuer)) - { - return false; - } - } - - if (attributeCertificateValid != null) - { - if (!attrCert.isValidOn(attributeCertificateValid)) - { - return false; - } - } - if (!targetNames.isEmpty() || !targetGroups.isEmpty()) - { - Extension targetInfoExt = attrCert.getExtension(Extension.targetInformation); - if (targetInfoExt != null) - { - TargetInformation targetinfo; - try - { - targetinfo = TargetInformation.getInstance(targetInfoExt.getParsedValue()); - } - catch (IllegalArgumentException e) - { - return false; - } - Targets[] targetss = targetinfo.getTargetsObjects(); - if (!targetNames.isEmpty()) - { - boolean found = false; - - for (int i=0; i<targetss.length; i++) - { - Targets t = targetss[i]; - Target[] targets = t.getTargets(); - for (int j=0; j<targets.length; j++) - { - if (targetNames.contains(GeneralName.getInstance(targets[j] - .getTargetName()))) - { - found = true; - break; - } - } - } - if (!found) - { - return false; - } - } - if (!targetGroups.isEmpty()) - { - boolean found = false; - - for (int i=0; i<targetss.length; i++) - { - Targets t = targetss[i]; - Target[] targets = t.getTargets(); - for (int j=0; j<targets.length; j++) - { - if (targetGroups.contains(GeneralName.getInstance(targets[j] - .getTargetGroup()))) - { - found = true; - break; - } - } - } - if (!found) - { - return false; - } - } - } - } - return true; - } - - /** - * Returns a clone of this object. - * - * @return the clone. - */ - public Object clone() - { - X509AttributeCertificateHolderSelector sel = new X509AttributeCertificateHolderSelector( - holder, issuer, serialNumber, attributeCertificateValid, attributeCert, targetNames, targetGroups); - - return sel; - } - - /** - * Returns the attribute certificate holder which must be matched. - * - * @return Returns an X509AttributeCertificateHolder - */ - public X509AttributeCertificateHolder getAttributeCert() - { - return attributeCert; - } - - /** - * Get the criteria for the validity. - * - * @return Returns the attributeCertificateValid. - */ - public Date getAttributeCertificateValid() - { - if (attributeCertificateValid != null) - { - return new Date(attributeCertificateValid.getTime()); - } - - return null; - } - - /** - * Gets the holder. - * - * @return Returns the holder. - */ - public AttributeCertificateHolder getHolder() - { - return holder; - } - - /** - * Returns the issuer criterion. - * - * @return Returns the issuer. - */ - public AttributeCertificateIssuer getIssuer() - { - return issuer; - } - - /** - * Gets the serial number the attribute certificate must have. - * - * @return Returns the serialNumber. - */ - public BigInteger getSerialNumber() - { - return serialNumber; - } - - /** - * Gets the target names. The collection consists of GeneralName objects. - * <p> - * The returned collection is immutable. - * - * @return The collection of target names - */ - public Collection getTargetNames() - { - return targetNames; - } - - /** - * Gets the target groups. The collection consists of GeneralName objects. - * <p> - * The returned collection is immutable. - * - * @return The collection of target groups. - */ - public Collection getTargetGroups() - { - return targetGroups; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/selector/X509AttributeCertificateHolderSelectorBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/selector/X509AttributeCertificateHolderSelectorBuilder.java deleted file mode 100644 index f9707340..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/selector/X509AttributeCertificateHolderSelectorBuilder.java +++ /dev/null @@ -1,194 +0,0 @@ -package org.bouncycastle.cert.selector; - -import java.io.IOException; -import java.math.BigInteger; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.cert.AttributeCertificateHolder; -import org.bouncycastle.cert.AttributeCertificateIssuer; -import org.bouncycastle.cert.X509AttributeCertificateHolder; - -/** - * This class builds selectors according to the set criteria. - */ -public class X509AttributeCertificateHolderSelectorBuilder -{ - - // TODO: name constraints??? - - private AttributeCertificateHolder holder; - - private AttributeCertificateIssuer issuer; - - private BigInteger serialNumber; - - private Date attributeCertificateValid; - - private X509AttributeCertificateHolder attributeCert; - - private Collection targetNames = new HashSet(); - - private Collection targetGroups = new HashSet(); - - public X509AttributeCertificateHolderSelectorBuilder() - { - } - - /** - * Set the attribute certificate to be matched. If <code>null</code> is - * given any will do. - * - * @param attributeCert The attribute certificate holder to set. - */ - public void setAttributeCert(X509AttributeCertificateHolder attributeCert) - { - this.attributeCert = attributeCert; - } - - /** - * Set the time, when the certificate must be valid. If <code>null</code> - * is given any will do. - * - * @param attributeCertificateValid The attribute certificate validation - * time to set. - */ - public void setAttributeCertificateValid(Date attributeCertificateValid) - { - if (attributeCertificateValid != null) - { - this.attributeCertificateValid = new Date(attributeCertificateValid - .getTime()); - } - else - { - this.attributeCertificateValid = null; - } - } - - /** - * Sets the holder. If <code>null</code> is given any will do. - * - * @param holder The holder to set. - */ - public void setHolder(AttributeCertificateHolder holder) - { - this.holder = holder; - } - - /** - * Sets the issuer the attribute certificate must have. If <code>null</code> - * is given any will do. - * - * @param issuer The issuer to set. - */ - public void setIssuer(AttributeCertificateIssuer issuer) - { - this.issuer = issuer; - } - - /** - * Sets the serial number the attribute certificate must have. If - * <code>null</code> is given any will do. - * - * @param serialNumber The serialNumber to set. - */ - public void setSerialNumber(BigInteger serialNumber) - { - this.serialNumber = serialNumber; - } - - /** - * Adds a target name criterion for the attribute certificate to the target - * information extension criteria. The <code>X509AttributeCertificateHolder</code> - * must contain at least one of the specified target names. - * <p> - * Each attribute certificate may contain a target information extension - * limiting the servers where this attribute certificate can be used. If - * this extension is not present, the attribute certificate is not targeted - * and may be accepted by any server. - * - * @param name The name as a GeneralName (not <code>null</code>) - */ - public void addTargetName(GeneralName name) - { - targetNames.add(name); - } - - /** - * Adds a collection with target names criteria. If <code>null</code> is - * given any will do. - * <p> - * The collection consists of either GeneralName objects or byte[] arrays representing - * DER encoded GeneralName structures. - * - * @param names A collection of target names. - * @throws java.io.IOException if a parsing error occurs. - * @see #addTargetName(org.bouncycastle.asn1.x509.GeneralName) - */ - public void setTargetNames(Collection names) throws IOException - { - targetNames = extractGeneralNames(names); - } - - /** - * Adds a target group criterion for the attribute certificate to the target - * information extension criteria. The <code>X509AttributeCertificateHolder</code> - * must contain at least one of the specified target groups. - * <p> - * Each attribute certificate may contain a target information extension - * limiting the servers where this attribute certificate can be used. If - * this extension is not present, the attribute certificate is not targeted - * and may be accepted by any server. - * - * @param group The group as GeneralName form (not <code>null</code>) - */ - public void addTargetGroup(GeneralName group) - { - targetGroups.add(group); - } - - /** - * Adds a collection with target groups criteria. If <code>null</code> is - * given any will do. - * <p> - * The collection consists of <code>GeneralName</code> objects or <code>byte[]</code representing DER - * encoded GeneralNames. - * - * @param names A collection of target groups. - * @throws java.io.IOException if a parsing error occurs. - * @see #addTargetGroup(org.bouncycastle.asn1.x509.GeneralName) - */ - public void setTargetGroups(Collection names) throws IOException - { - targetGroups = extractGeneralNames(names); - } - - private Set extractGeneralNames(Collection names) - throws IOException - { - if (names == null || names.isEmpty()) - { - return new HashSet(); - } - Set temp = new HashSet(); - for (Iterator it = names.iterator(); it.hasNext();) - { - temp.add(GeneralName.getInstance(it.next())); - } - return temp; - } - - public X509AttributeCertificateHolderSelector build() - { - X509AttributeCertificateHolderSelector sel = new X509AttributeCertificateHolderSelector( - holder, issuer, serialNumber, attributeCertificateValid, attributeCert, Collections.unmodifiableCollection(new HashSet(targetNames)), Collections.unmodifiableCollection(new HashSet(targetGroups))); - - return sel; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/selector/X509CertificateHolderSelector.java b/pkix/src/main/java/org/bouncycastle/cert/selector/X509CertificateHolderSelector.java deleted file mode 100644 index 5af58606..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/selector/X509CertificateHolderSelector.java +++ /dev/null @@ -1,152 +0,0 @@ -package org.bouncycastle.cert.selector; - -import java.math.BigInteger; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.cms.IssuerAndSerialNumber; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.Extension; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.util.Arrays; -import 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/pkix/src/main/java/org/bouncycastle/cert/selector/jcajce/JcaSelectorConverter.java b/pkix/src/main/java/org/bouncycastle/cert/selector/jcajce/JcaSelectorConverter.java deleted file mode 100644 index 13e9e6b4..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/selector/jcajce/JcaSelectorConverter.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.bouncycastle.cert.selector.jcajce; - -import java.io.IOException; -import java.security.cert.X509CertSelector; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.cert.selector.X509CertificateHolderSelector; - -public class JcaSelectorConverter -{ - public JcaSelectorConverter() - { - - } - - public X509CertificateHolderSelector getCertificateHolderSelector(X509CertSelector certSelector) - { - try - { - if (certSelector.getSubjectKeyIdentifier() != null) - { - return new X509CertificateHolderSelector(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber(), ASN1OctetString.getInstance(certSelector.getSubjectKeyIdentifier()).getOctets()); - } - else - { - return new X509CertificateHolderSelector(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber()); - } - } - catch (IOException e) - { - throw new IllegalArgumentException("unable to convert issuer: " + e.getMessage()); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/selector/jcajce/JcaX509CertSelectorConverter.java b/pkix/src/main/java/org/bouncycastle/cert/selector/jcajce/JcaX509CertSelectorConverter.java deleted file mode 100644 index 22a35371..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/selector/jcajce/JcaX509CertSelectorConverter.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.bouncycastle.cert.selector.jcajce; - -import java.io.IOException; -import java.math.BigInteger; -import java.security.cert.X509CertSelector; - -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.cert.selector.X509CertificateHolderSelector; - -public class JcaX509CertSelectorConverter -{ - public JcaX509CertSelectorConverter() - { - } - - protected X509CertSelector doConversion(X500Name issuer, BigInteger serialNumber, byte[] subjectKeyIdentifier) - { - X509CertSelector selector = new X509CertSelector(); - - if (issuer != null) - { - try - { - selector.setIssuer(issuer.getEncoded()); - } - catch (IOException e) - { - throw new IllegalArgumentException("unable to convert issuer: " + e.getMessage()); - } - } - - if (serialNumber != null) - { - selector.setSerialNumber(serialNumber); - } - - if (subjectKeyIdentifier != null) - { - try - { - selector.setSubjectKeyIdentifier(new DEROctetString(subjectKeyIdentifier).getEncoded()); - } - catch (IOException e) - { - throw new IllegalArgumentException("unable to convert issuer: " + e.getMessage()); - } - } - - return selector; - } - - public X509CertSelector getCertSelector(X509CertificateHolderSelector holderSelector) - { - return doConversion(holderSelector.getIssuer(), holderSelector.getSerialNumber(), holderSelector.getSubjectKeyIdentifier()); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cert/selector/jcajce/JcaX509CertificateHolderSelector.java b/pkix/src/main/java/org/bouncycastle/cert/selector/jcajce/JcaX509CertificateHolderSelector.java deleted file mode 100644 index b1c2b49a..00000000 --- a/pkix/src/main/java/org/bouncycastle/cert/selector/jcajce/JcaX509CertificateHolderSelector.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.bouncycastle.cert.selector.jcajce; - -import java.math.BigInteger; -import java.security.cert.X509Certificate; - -import javax.security.auth.x500.X500Principal; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.Extension; -import org.bouncycastle.cert.selector.X509CertificateHolderSelector; - -public class JcaX509CertificateHolderSelector - extends X509CertificateHolderSelector -{ - /** - * Construct a signer identifier based on the issuer, serial number and subject key identifier (if present) of the passed in - * certificate. - * - * @param certificate certificate providing the issue and serial number and subject key identifier. - */ - public JcaX509CertificateHolderSelector(X509Certificate certificate) - { - super(convertPrincipal(certificate.getIssuerX500Principal()), certificate.getSerialNumber(), getSubjectKeyId(certificate)); - } - - /** - * Construct a signer identifier based on the provided issuer and serial number.. - * - * @param issuer the issuer to use. - * @param serialNumber the serial number to use. - */ - public JcaX509CertificateHolderSelector(X500Principal issuer, BigInteger serialNumber) - { - super(convertPrincipal(issuer), serialNumber); - } - - /** - * Construct a signer identifier based on the provided issuer, serial number, and subjectKeyId.. - * - * @param issuer the issuer to use. - * @param serialNumber the serial number to use. - * @param subjectKeyId the subject key ID to use. - */ - public JcaX509CertificateHolderSelector(X500Principal issuer, BigInteger serialNumber, byte[] subjectKeyId) - { - super(convertPrincipal(issuer), serialNumber, subjectKeyId); - } - - private static X500Name convertPrincipal(X500Principal issuer) - { - if (issuer == null) - { - return null; - } - return X500Name.getInstance(issuer.getEncoded()); - } - - private static byte[] getSubjectKeyId(X509Certificate cert) - { - byte[] ext = cert.getExtensionValue(Extension.subjectKeyIdentifier.getId()); - - if (ext != null) - { - return ASN1OctetString.getInstance(ASN1OctetString.getInstance(ext).getOctets()).getOctets(); - } - else - { - return null; - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/AuthAttributesProvider.java b/pkix/src/main/java/org/bouncycastle/cms/AuthAttributesProvider.java deleted file mode 100644 index a17325bd..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/AuthAttributesProvider.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.bouncycastle.cms; - -import org.bouncycastle.asn1.ASN1Set; - -interface AuthAttributesProvider -{ - ASN1Set getAuthAttributes(); -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSAbsentContent.java b/pkix/src/main/java/org/bouncycastle/cms/CMSAbsentContent.java deleted file mode 100644 index f256e2a2..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSAbsentContent.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import 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(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId())); - } - - 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/pkix/src/main/java/org/bouncycastle/cms/CMSAlgorithm.java b/pkix/src/main/java/org/bouncycastle/cms/CMSAlgorithm.java deleted file mode 100644 index 70484c87..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSAlgorithm.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.bouncycastle.cms; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; -import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; -import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; - -public class CMSAlgorithm -{ - public static final ASN1ObjectIdentifier DES_CBC = OIWObjectIdentifiers.desCBC; - public static final ASN1ObjectIdentifier DES_EDE3_CBC = PKCSObjectIdentifiers.des_EDE3_CBC; - public static final ASN1ObjectIdentifier RC2_CBC = PKCSObjectIdentifiers.RC2_CBC; - public static final ASN1ObjectIdentifier IDEA_CBC = new ASN1ObjectIdentifier("1.3.6.1.4.1.188.7.1.1.2"); - public static final ASN1ObjectIdentifier CAST5_CBC = new ASN1ObjectIdentifier("1.2.840.113533.7.66.10"); - public static final ASN1ObjectIdentifier AES128_CBC = NISTObjectIdentifiers.id_aes128_CBC; - public static final ASN1ObjectIdentifier AES192_CBC = NISTObjectIdentifiers.id_aes192_CBC; - public static final ASN1ObjectIdentifier AES256_CBC = NISTObjectIdentifiers.id_aes256_CBC; - public static final ASN1ObjectIdentifier CAMELLIA128_CBC = NTTObjectIdentifiers.id_camellia128_cbc; - public static final ASN1ObjectIdentifier CAMELLIA192_CBC = NTTObjectIdentifiers.id_camellia192_cbc; - public static final ASN1ObjectIdentifier CAMELLIA256_CBC = NTTObjectIdentifiers.id_camellia256_cbc; - public static final ASN1ObjectIdentifier SEED_CBC = KISAObjectIdentifiers.id_seedCBC; - - public static final ASN1ObjectIdentifier DES_EDE3_WRAP = PKCSObjectIdentifiers.id_alg_CMS3DESwrap; - public static final ASN1ObjectIdentifier AES128_WRAP = NISTObjectIdentifiers.id_aes128_wrap; - public static final ASN1ObjectIdentifier AES192_WRAP = NISTObjectIdentifiers.id_aes192_wrap; - public static final ASN1ObjectIdentifier AES256_WRAP = NISTObjectIdentifiers.id_aes256_wrap; - public static final ASN1ObjectIdentifier CAMELLIA128_WRAP = NTTObjectIdentifiers.id_camellia128_wrap; - public static final ASN1ObjectIdentifier CAMELLIA192_WRAP = NTTObjectIdentifiers.id_camellia192_wrap; - public static final ASN1ObjectIdentifier CAMELLIA256_WRAP = NTTObjectIdentifiers.id_camellia256_wrap; - public static final ASN1ObjectIdentifier SEED_WRAP = KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap; - - public static final ASN1ObjectIdentifier ECDH_SHA1KDF = X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme; - public static final ASN1ObjectIdentifier ECMQV_SHA1KDF = X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme; - - public static final ASN1ObjectIdentifier SHA1 = OIWObjectIdentifiers.idSHA1; - public static final ASN1ObjectIdentifier SHA224 = NISTObjectIdentifiers.id_sha224; - public static final ASN1ObjectIdentifier SHA256 = NISTObjectIdentifiers.id_sha256; - public static final ASN1ObjectIdentifier SHA384 = NISTObjectIdentifiers.id_sha384; - public static final ASN1ObjectIdentifier SHA512 = NISTObjectIdentifiers.id_sha512; - public static final ASN1ObjectIdentifier MD5 = PKCSObjectIdentifiers.md5; - public static final ASN1ObjectIdentifier GOST3411 = CryptoProObjectIdentifiers.gostR3411; - public static final ASN1ObjectIdentifier RIPEMD128 = TeleTrusTObjectIdentifiers.ripemd128; - public static final ASN1ObjectIdentifier RIPEMD160 = TeleTrusTObjectIdentifiers.ripemd160; - public static final ASN1ObjectIdentifier RIPEMD256 = TeleTrusTObjectIdentifiers.ripemd256; - -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSAttributeTableGenerationException.java b/pkix/src/main/java/org/bouncycastle/cms/CMSAttributeTableGenerationException.java deleted file mode 100644 index e3cab8a5..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSAttributeTableGenerationException.java +++ /dev/null @@ -1,32 +0,0 @@ -package 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/pkix/src/main/java/org/bouncycastle/cms/CMSAttributeTableGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSAttributeTableGenerator.java deleted file mode 100644 index 528c738b..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSAttributeTableGenerator.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.bouncycastle.cms; - -import org.bouncycastle.asn1.cms.AttributeTable; - -import java.util.Map; - -/** - * Note: The SIGNATURE parameter is only available when generating unsigned attributes. - */ -public interface CMSAttributeTableGenerator -{ - static final String CONTENT_TYPE = "contentType"; - static final String DIGEST = "digest"; - static final String SIGNATURE = "encryptedDigest"; - static final String DIGEST_ALGORITHM_IDENTIFIER = "digestAlgID"; - - AttributeTable getAttributes(Map parameters) - throws CMSAttributeTableGenerationException; -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthEnvelopedData.java b/pkix/src/main/java/org/bouncycastle/cms/CMSAuthEnvelopedData.java deleted file mode 100644 index 010e12c2..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthEnvelopedData.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.IOException; -import java.io.InputStream; - -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.cms.AuthEnvelopedData; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.cms.EncryptedContentInfo; -import org.bouncycastle.asn1.cms.OriginatorInfo; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -/** - * containing class for an CMS AuthEnveloped Data object - */ -class CMSAuthEnvelopedData -{ - RecipientInformationStore recipientInfoStore; - ContentInfo contentInfo; - - private OriginatorInfo originator; - private AlgorithmIdentifier authEncAlg; - private ASN1Set authAttrs; - private byte[] mac; - private ASN1Set unauthAttrs; - - public CMSAuthEnvelopedData(byte[] authEnvData) throws CMSException - { - this(CMSUtils.readContentInfo(authEnvData)); - } - - public CMSAuthEnvelopedData(InputStream authEnvData) throws CMSException - { - this(CMSUtils.readContentInfo(authEnvData)); - } - - public CMSAuthEnvelopedData(ContentInfo contentInfo) throws CMSException - { - this.contentInfo = contentInfo; - - AuthEnvelopedData authEnvData = AuthEnvelopedData.getInstance(contentInfo.getContent()); - - this.originator = authEnvData.getOriginatorInfo(); - - // - // read the recipients - // - ASN1Set recipientInfos = authEnvData.getRecipientInfos(); - - // - // read the auth-encrypted content info - // - EncryptedContentInfo authEncInfo = authEnvData.getAuthEncryptedContentInfo(); - this.authEncAlg = authEncInfo.getContentEncryptionAlgorithm(); -// final CMSProcessable processable = new CMSProcessableByteArray( -// authEncInfo.getEncryptedContent().getOctets()); - CMSSecureReadable secureReadable = new CMSSecureReadable() - { - - public InputStream getInputStream() - throws IOException, CMSException - { - return null; - } - }; - - // - // build the RecipientInformationStore - // - this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore( - recipientInfos, this.authEncAlg, secureReadable); - - // FIXME These need to be passed to the AEAD cipher as AAD (Additional Authenticated Data) - this.authAttrs = authEnvData.getAuthAttrs(); - this.mac = authEnvData.getMac().getOctets(); - this.unauthAttrs = authEnvData.getUnauthAttrs(); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthEnvelopedGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSAuthEnvelopedGenerator.java deleted file mode 100644 index 90658574..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthEnvelopedGenerator.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.bouncycastle.cms; - -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; - -class CMSAuthEnvelopedGenerator -{ - public static final String AES128_CCM = NISTObjectIdentifiers.id_aes128_CCM.getId(); - public static final String AES192_CCM = NISTObjectIdentifiers.id_aes192_CCM.getId(); - public static final String AES256_CCM = NISTObjectIdentifiers.id_aes256_CCM.getId(); - public static final String AES128_GCM = NISTObjectIdentifiers.id_aes128_GCM.getId(); - public static final String AES192_GCM = NISTObjectIdentifiers.id_aes192_GCM.getId(); - public static final String AES256_GCM = NISTObjectIdentifiers.id_aes256_GCM.getId(); -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthenticatedData.java b/pkix/src/main/java/org/bouncycastle/cms/CMSAuthenticatedData.java deleted file mode 100644 index bd9d5444..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthenticatedData.java +++ /dev/null @@ -1,260 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.IOException; -import java.io.InputStream; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.cms.AttributeTable; -import org.bouncycastle.asn1.cms.AuthenticatedData; -import org.bouncycastle.asn1.cms.CMSAttributes; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.operator.DigestCalculatorProvider; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.util.Arrays; - -/** - * containing class for an CMS Authenticated Data object - */ -public class CMSAuthenticatedData -{ - RecipientInformationStore recipientInfoStore; - ContentInfo contentInfo; - - private AlgorithmIdentifier macAlg; - private ASN1Set authAttrs; - private ASN1Set unauthAttrs; - private byte[] mac; - private OriginatorInformation originatorInfo; - - public CMSAuthenticatedData( - byte[] authData) - throws CMSException - { - this(CMSUtils.readContentInfo(authData)); - } - - public CMSAuthenticatedData( - byte[] authData, - DigestCalculatorProvider digestCalculatorProvider) - throws CMSException - { - this(CMSUtils.readContentInfo(authData), digestCalculatorProvider); - } - - public CMSAuthenticatedData( - InputStream authData) - throws CMSException - { - this(CMSUtils.readContentInfo(authData)); - } - - public CMSAuthenticatedData( - InputStream authData, - DigestCalculatorProvider digestCalculatorProvider) - throws CMSException - { - this(CMSUtils.readContentInfo(authData), digestCalculatorProvider); - } - - public CMSAuthenticatedData( - ContentInfo contentInfo) - throws CMSException - { - this(contentInfo, null); - } - - public CMSAuthenticatedData( - ContentInfo contentInfo, - DigestCalculatorProvider digestCalculatorProvider) - throws CMSException - { - this.contentInfo = contentInfo; - - AuthenticatedData authData = AuthenticatedData.getInstance(contentInfo.getContent()); - - if (authData.getOriginatorInfo() != null) - { - this.originatorInfo = new OriginatorInformation(authData.getOriginatorInfo()); - } - - // - // read the recipients - // - ASN1Set recipientInfos = authData.getRecipientInfos(); - - this.macAlg = authData.getMacAlgorithm(); - - - this.authAttrs = authData.getAuthAttrs(); - this.mac = authData.getMac().getOctets(); - this.unauthAttrs = authData.getUnauthAttrs(); - - // - // read the authenticated content info - // - ContentInfo encInfo = authData.getEncapsulatedContentInfo(); - CMSReadable readable = new CMSProcessableByteArray( - ASN1OctetString.getInstance(encInfo.getContent()).getOctets()); - - // - // build the RecipientInformationStore - // - if (authAttrs != null) - { - if (digestCalculatorProvider == null) - { - throw new CMSException("a digest calculator provider is required if authenticated attributes are present"); - } - - try - { - CMSSecureReadable secureReadable = new CMSEnvelopedHelper.CMSDigestAuthenticatedSecureReadable(digestCalculatorProvider.get(authData.getDigestAlgorithm()), readable); - - this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore(recipientInfos, this.macAlg, secureReadable, new AuthAttributesProvider() - { - public ASN1Set getAuthAttributes() - { - return authAttrs; - } - }); - } - catch (OperatorCreationException e) - { - throw new CMSException("unable to create digest calculator: " + e.getMessage(), e); - } - } - else - { - CMSSecureReadable secureReadable = new CMSEnvelopedHelper.CMSAuthenticatedSecureReadable(this.macAlg, readable); - - this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore(recipientInfos, this.macAlg, secureReadable); - } - } - - /** - * Return the originator information associated with this message if present. - * - * @return OriginatorInformation, null if not present. - */ - public OriginatorInformation getOriginatorInfo() - { - return originatorInfo; - } - - public byte[] getMac() - { - return Arrays.clone(mac); - } - - private byte[] encodeObj( - ASN1Encodable obj) - throws IOException - { - if (obj != null) - { - return obj.toASN1Primitive().getEncoded(); - } - - return null; - } - - /** - * Return the MAC algorithm details for the MAC associated with the data in this object. - * - * @return AlgorithmIdentifier representing the MAC algorithm. - */ - public AlgorithmIdentifier getMacAlgorithm() - { - return macAlg; - } - - /** - * return the object identifier for the content MAC algorithm. - */ - public String getMacAlgOID() - { - return macAlg.getAlgorithm().getId(); - } - - /** - * return the ASN.1 encoded MAC algorithm parameters, or null if - * there aren't any. - */ - public byte[] getMacAlgParams() - { - try - { - return encodeObj(macAlg.getParameters()); - } - catch (Exception e) - { - throw new RuntimeException("exception getting encryption parameters " + e); - } - } - - /** - * return a store of the intended recipients for this message - */ - public RecipientInformationStore getRecipientInfos() - { - return recipientInfoStore; - } - - /** - * return the ContentInfo - */ - public ContentInfo getContentInfo() - { - return contentInfo; - } - - /** - * return a table of the digested attributes indexed by - * the OID of the attribute. - */ - public AttributeTable getAuthAttrs() - { - if (authAttrs == null) - { - return null; - } - - return new AttributeTable(authAttrs); - } - - /** - * return a table of the undigested attributes indexed by - * the OID of the attribute. - */ - public AttributeTable getUnauthAttrs() - { - if (unauthAttrs == null) - { - return null; - } - - return new AttributeTable(unauthAttrs); - } - - /** - * return the ASN.1 encoded representation of this object. - */ - public byte[] getEncoded() - throws IOException - { - return contentInfo.getEncoded(); - } - - public byte[] getContentDigest() - { - if (authAttrs != null) - { - return ASN1OctetString.getInstance(getAuthAttrs().get(CMSAttributes.messageDigest).getAttrValues().getObjectAt(0)).getOctets(); - } - - return null; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthenticatedDataGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSAuthenticatedDataGenerator.java deleted file mode 100644 index 82f8294c..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthenticatedDataGenerator.java +++ /dev/null @@ -1,181 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.BEROctetString; -import org.bouncycastle.asn1.BERSet; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.cms.AuthenticatedData; -import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.operator.DigestCalculator; -import org.bouncycastle.operator.DigestCalculatorProvider; -import org.bouncycastle.operator.MacCalculator; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.util.io.TeeOutputStream; - -/** - * General class for generating a CMS authenticated-data message. - * - * A simple example of usage. - * - * <pre> - * CMSAuthenticatedDataGenerator fact = new CMSAuthenticatedDataGenerator(); - * - * adGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(recipientCert).setProvider("BC")); - * - * CMSAuthenticatedData data = fact.generate(new CMSProcessableByteArray(data), - * new JceCMSMacCalculatorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build())); - * </pre> - */ -public class CMSAuthenticatedDataGenerator - extends CMSAuthenticatedGenerator -{ - /** - * base constructor - */ - public CMSAuthenticatedDataGenerator() - { - } - - /** - * Generate an authenticated data object from the passed in typedData and MacCalculator. - * - * @param typedData the data to have a MAC attached. - * @param macCalculator the calculator of the MAC to be attached. - * @return the resulting CMSAuthenticatedData object. - * @throws CMSException on failure in encoding data or processing recipients. - */ - public CMSAuthenticatedData generate(CMSTypedData typedData, MacCalculator macCalculator) - throws CMSException - { - return generate(typedData, macCalculator, null); - } - - /** - * Generate an authenticated data object from the passed in typedData and MacCalculator. - * - * @param typedData the data to have a MAC attached. - * @param macCalculator the calculator of the MAC to be attached. - * @param digestCalculator calculator for computing digest of the encapsulated data. - * @return the resulting CMSAuthenticatedData object. - * @throws CMSException on failure in encoding data or processing recipients. - */ - public CMSAuthenticatedData generate(CMSTypedData typedData, MacCalculator macCalculator, final DigestCalculator digestCalculator) - throws CMSException - { - ASN1EncodableVector recipientInfos = new ASN1EncodableVector(); - ASN1OctetString encContent; - ASN1OctetString macResult; - - for (Iterator it = recipientInfoGenerators.iterator(); it.hasNext();) - { - RecipientInfoGenerator recipient = (RecipientInfoGenerator)it.next(); - - recipientInfos.add(recipient.generate(macCalculator.getKey())); - } - - AuthenticatedData authData; - - if (digestCalculator != null) - { - try - { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - OutputStream out = new TeeOutputStream(digestCalculator.getOutputStream(), bOut); - - typedData.write(out); - - out.close(); - - encContent = new BEROctetString(bOut.toByteArray()); - } - catch (IOException e) - { - throw new CMSException("unable to perform digest calculation: " + e.getMessage(), e); - } - - Map parameters = getBaseParameters(typedData.getContentType(), digestCalculator.getAlgorithmIdentifier(), digestCalculator.getDigest()); - - if (authGen == null) - { - authGen = new DefaultAuthenticatedAttributeTableGenerator(); - } - ASN1Set authed = new DERSet(authGen.getAttributes(Collections.unmodifiableMap(parameters)).toASN1EncodableVector()); - - try - { - OutputStream mOut = macCalculator.getOutputStream(); - - mOut.write(authed.getEncoded(ASN1Encoding.DER)); - - mOut.close(); - - macResult = new DEROctetString(macCalculator.getMac()); - } - catch (IOException e) - { - throw new CMSException("exception decoding algorithm parameters.", e); - } - ASN1Set unauthed = (unauthGen != null) ? new BERSet(unauthGen.getAttributes(Collections.unmodifiableMap(parameters)).toASN1EncodableVector()) : null; - - ContentInfo eci = new ContentInfo( - CMSObjectIdentifiers.data, - encContent); - - authData = new AuthenticatedData(originatorInfo, new DERSet(recipientInfos), macCalculator.getAlgorithmIdentifier(), digestCalculator.getAlgorithmIdentifier(), eci, authed, macResult, unauthed); - } - else - { - try - { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - OutputStream mOut = new TeeOutputStream(bOut, macCalculator.getOutputStream()); - - typedData.write(mOut); - - mOut.close(); - - encContent = new BEROctetString(bOut.toByteArray()); - - macResult = new DEROctetString(macCalculator.getMac()); - } - catch (IOException e) - { - throw new CMSException("exception decoding algorithm parameters.", e); - } - - ASN1Set unauthed = (unauthGen != null) ? new BERSet(unauthGen.getAttributes(new HashMap()).toASN1EncodableVector()) : null; - - ContentInfo eci = new ContentInfo( - CMSObjectIdentifiers.data, - encContent); - - authData = new AuthenticatedData(originatorInfo, new DERSet(recipientInfos), macCalculator.getAlgorithmIdentifier(), null, eci, null, macResult, unauthed); - } - - ContentInfo contentInfo = new ContentInfo( - CMSObjectIdentifiers.authenticatedData, authData); - - return new CMSAuthenticatedData(contentInfo, new DigestCalculatorProvider() - { - public DigestCalculator get(AlgorithmIdentifier digestAlgorithmIdentifier) - throws OperatorCreationException - { - return digestCalculator; - } - }); - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthenticatedDataParser.java b/pkix/src/main/java/org/bouncycastle/cms/CMSAuthenticatedDataParser.java deleted file mode 100644 index 11c90c67..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthenticatedDataParser.java +++ /dev/null @@ -1,348 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1OctetStringParser; -import org.bouncycastle.asn1.ASN1SequenceParser; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.ASN1SetParser; -import org.bouncycastle.asn1.BERTags; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.cms.AttributeTable; -import org.bouncycastle.asn1.cms.AuthenticatedDataParser; -import org.bouncycastle.asn1.cms.CMSAttributes; -import org.bouncycastle.asn1.cms.ContentInfoParser; -import org.bouncycastle.asn1.cms.OriginatorInfo; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.operator.DigestCalculatorProvider; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.util.Arrays; - -/** - * Parsing class for an CMS Authenticated Data object from an input stream. - * <p> - * Note: that because we are in a streaming mode only one recipient can be tried and it is important - * that the methods on the parser are called in the appropriate order. - * </p> - * <p> - * Example of use - assuming the first recipient matches the private key we have. - * <pre> - * CMSAuthenticatedDataParser ad = new CMSAuthenticatedDataParser(inputStream); - * - * RecipientInformationStore recipients = ad.getRecipientInfos(); - * - * Collection c = recipients.getRecipients(); - * Iterator it = c.iterator(); - * - * if (it.hasNext()) - * { - * RecipientInformation recipient = (RecipientInformation)it.next(); - * - * CMSTypedStream recData = recipient.getContentStream(new JceKeyTransAuthenticatedRecipient(privateKey).setProvider("BC")); - * - * processDataStream(recData.getContentStream()); - * - * if (!Arrays.equals(ad.getMac(), recipient.getMac()) - * { - * System.err.println("Data corrupted!!!!"); - * } - * } - * </pre> - * Note: this class does not introduce buffering - if you are processing large files you should create - * the parser with: - * <pre> - * CMSAuthenticatedDataParser ep = new CMSAuthenticatedDataParser(new BufferedInputStream(inputStream, bufSize)); - * </pre> - * where bufSize is a suitably large buffer size. - */ -public class CMSAuthenticatedDataParser - extends CMSContentInfoParser -{ - RecipientInformationStore recipientInfoStore; - AuthenticatedDataParser authData; - - private AlgorithmIdentifier macAlg; - private byte[] mac; - private AttributeTable authAttrs; - private ASN1Set authAttrSet; - private AttributeTable unauthAttrs; - - private boolean authAttrNotRead; - private boolean unauthAttrNotRead; - private OriginatorInformation originatorInfo; - - public CMSAuthenticatedDataParser( - byte[] envelopedData) - throws CMSException, IOException - { - this(new ByteArrayInputStream(envelopedData)); - } - - public CMSAuthenticatedDataParser( - byte[] envelopedData, - DigestCalculatorProvider digestCalculatorProvider) - throws CMSException, IOException - { - this(new ByteArrayInputStream(envelopedData), digestCalculatorProvider); - } - - public CMSAuthenticatedDataParser( - InputStream envelopedData) - throws CMSException, IOException - { - this(envelopedData, null); - } - - public CMSAuthenticatedDataParser( - InputStream envelopedData, - DigestCalculatorProvider digestCalculatorProvider) - throws CMSException, IOException - { - super(envelopedData); - - this.authAttrNotRead = true; - this.authData = new AuthenticatedDataParser((ASN1SequenceParser)_contentInfo.getContent(BERTags.SEQUENCE)); - - // TODO Validate version? - //ASN1Integer version = this.authData.getVersion(); - - OriginatorInfo info = authData.getOriginatorInfo(); - - if (info != null) - { - this.originatorInfo = new OriginatorInformation(info); - } - // - // read the recipients - // - ASN1Set recipientInfos = ASN1Set.getInstance(authData.getRecipientInfos().toASN1Primitive()); - - this.macAlg = authData.getMacAlgorithm(); - - // - // build the RecipientInformationStore - // - AlgorithmIdentifier digestAlgorithm = authData.getDigestAlgorithm(); - - if (digestAlgorithm != null) - { - if (digestCalculatorProvider == null) - { - throw new CMSException("a digest calculator provider is required if authenticated attributes are present"); - } - - // - // read the authenticated content info - // - ContentInfoParser data = authData.getEncapsulatedContentInfo(); - CMSReadable readable = new CMSProcessableInputStream( - ((ASN1OctetStringParser)data.getContent(BERTags.OCTET_STRING)).getOctetStream()); - - try - { - CMSSecureReadable secureReadable = new CMSEnvelopedHelper.CMSDigestAuthenticatedSecureReadable(digestCalculatorProvider.get(digestAlgorithm), readable); - - this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore(recipientInfos, this.macAlg, secureReadable, new AuthAttributesProvider() - { - public ASN1Set getAuthAttributes() - { - try - { - return getAuthAttrSet(); - } - catch (IOException e) - { - throw new IllegalStateException("can't parse authenticated attributes!"); - } - } - }); - } - catch (OperatorCreationException e) - { - throw new CMSException("unable to create digest calculator: " + e.getMessage(), e); - } - } - else - { - // - // read the authenticated content info - // - ContentInfoParser data = authData.getEncapsulatedContentInfo(); - CMSReadable readable = new CMSProcessableInputStream( - ((ASN1OctetStringParser)data.getContent(BERTags.OCTET_STRING)).getOctetStream()); - - CMSSecureReadable secureReadable = new CMSEnvelopedHelper.CMSAuthenticatedSecureReadable(this.macAlg, readable); - - this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore(recipientInfos, this.macAlg, secureReadable); - } - - - } - - /** - * Return the originator information associated with this message if present. - * - * @return OriginatorInformation, null if not present. - */ - public OriginatorInformation getOriginatorInfo() - { - return originatorInfo; - } - - /** - * Return the MAC algorithm details for the MAC associated with the data in this object. - * - * @return AlgorithmIdentifier representing the MAC algorithm. - */ - public AlgorithmIdentifier getMacAlgorithm() - { - return macAlg; - } - - /** - * return the object identifier for the mac algorithm. - */ - public String getMacAlgOID() - { - return macAlg.getAlgorithm().toString(); - } - - /** - * return the ASN.1 encoded encryption algorithm parameters, or null if - * there aren't any. - */ - public byte[] getMacAlgParams() - { - try - { - return encodeObj(macAlg.getParameters()); - } - catch (Exception e) - { - throw new RuntimeException("exception getting encryption parameters " + e); - } - } - - /** - * return a store of the intended recipients for this message - */ - public RecipientInformationStore getRecipientInfos() - { - return recipientInfoStore; - } - - public byte[] getMac() - throws IOException - { - if (mac == null) - { - getAuthAttrs(); - mac = authData.getMac().getOctets(); - } - return Arrays.clone(mac); - } - - private ASN1Set getAuthAttrSet() - throws IOException - { - if (authAttrs == null && authAttrNotRead) - { - ASN1SetParser set = authData.getAuthAttrs(); - - if (set != null) - { - authAttrSet = (ASN1Set)set.toASN1Primitive(); - } - - authAttrNotRead = false; - } - - return authAttrSet; - } - - /** - * return a table of the unauthenticated attributes indexed by - * the OID of the attribute. - * @exception java.io.IOException - */ - public AttributeTable getAuthAttrs() - throws IOException - { - if (authAttrs == null && authAttrNotRead) - { - ASN1Set set = getAuthAttrSet(); - - if (set != null) - { - authAttrs = new AttributeTable(set); - } - } - - return authAttrs; - } - - /** - * return a table of the unauthenticated attributes indexed by - * the OID of the attribute. - * @exception java.io.IOException - */ - public AttributeTable getUnauthAttrs() - throws IOException - { - if (unauthAttrs == null && unauthAttrNotRead) - { - ASN1SetParser set = authData.getUnauthAttrs(); - - unauthAttrNotRead = false; - - if (set != null) - { - ASN1EncodableVector v = new ASN1EncodableVector(); - ASN1Encodable o; - - while ((o = set.readObject()) != null) - { - ASN1SequenceParser seq = (ASN1SequenceParser)o; - - v.add(seq.toASN1Primitive()); - } - - unauthAttrs = new AttributeTable(new DERSet(v)); - } - } - - return unauthAttrs; - } - - private byte[] encodeObj( - ASN1Encodable obj) - throws IOException - { - if (obj != null) - { - return obj.toASN1Primitive().getEncoded(); - } - - return null; - } - - /** - * This will only be valid after the content has been read. - * - * @return the contents of the messageDigest attribute, if available. Null if not present. - */ - public byte[] getContentDigest() - { - if (authAttrs != null) - { - return ASN1OctetString.getInstance(authAttrs.get(CMSAttributes.messageDigest).getAttrValues().getObjectAt(0)).getOctets(); - } - - return null; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthenticatedDataStreamGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSAuthenticatedDataStreamGenerator.java deleted file mode 100644 index f32666d1..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthenticatedDataStreamGenerator.java +++ /dev/null @@ -1,310 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.BERSequenceGenerator; -import org.bouncycastle.asn1.BERSet; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.DERTaggedObject; -import org.bouncycastle.asn1.cms.AuthenticatedData; -import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.operator.DigestCalculator; -import org.bouncycastle.operator.MacCalculator; -import org.bouncycastle.util.io.TeeOutputStream; - -/** - * General class for generating a CMS authenticated-data message stream. - * <p> - * A simple example of usage. - * <pre> - * CMSAuthenticatedDataStreamGenerator edGen = new CMSAuthenticatedDataStreamGenerator(); - * - * edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(cert).setProvider("BC")); - * - * ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - * - * OutputStream out = edGen.open( - * bOut, new JceCMSMacCalculatorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider("BC").build());* - * out.write(data); - * - * out.close(); - * </pre> - */ -public class CMSAuthenticatedDataStreamGenerator - extends CMSAuthenticatedGenerator -{ - // Currently not handled -// private Object _originatorInfo = null; -// private Object _unprotectedAttributes = null; - private int bufferSize; - private boolean berEncodeRecipientSet; - private MacCalculator macCalculator; - - /** - * base constructor - */ - public CMSAuthenticatedDataStreamGenerator() - { - } - - /** - * Set the underlying string size for encapsulated data - * - * @param bufferSize length of octet strings to buffer the data. - */ - public void setBufferSize( - int bufferSize) - { - this.bufferSize = bufferSize; - } - - /** - * Use a BER Set to store the recipient information. By default recipients are - * stored in a DER encoding. - * - * @param useBerEncodingForRecipients true if a BER set should be used, false if DER. - */ - public void setBEREncodeRecipients( - boolean useBerEncodingForRecipients) - { - berEncodeRecipientSet = useBerEncodingForRecipients; - } - - /** - * generate an authenticated data structure with the encapsulated bytes marked as DATA. - * - * @param out the stream to store the authenticated structure in. - * @param macCalculator calculator for the MAC to be attached to the data. - */ - public OutputStream open( - OutputStream out, - MacCalculator macCalculator) - throws CMSException - { - return open(CMSObjectIdentifiers.data, out, macCalculator); - } - - public OutputStream open( - OutputStream out, - MacCalculator macCalculator, - DigestCalculator digestCalculator) - throws CMSException - { - return open(CMSObjectIdentifiers.data, out, macCalculator, digestCalculator); - } - - /** - * generate an authenticated data structure with the encapsulated bytes marked as type dataType. - * - * @param dataType the type of the data been written to the object. - * @param out the stream to store the authenticated structure in. - * @param macCalculator calculator for the MAC to be attached to the data. - */ - public OutputStream open( - ASN1ObjectIdentifier dataType, - OutputStream out, - MacCalculator macCalculator) - throws CMSException - { - return open(dataType, out, macCalculator, null); - } - - /** - * generate an authenticated data structure with the encapsulated bytes marked as type dataType. - * - * @param dataType the type of the data been written to the object. - * @param out the stream to store the authenticated structure in. - * @param macCalculator calculator for the MAC to be attached to the data. - * @param digestCalculator calculator for computing digest of the encapsulated data. - */ - public OutputStream open( - ASN1ObjectIdentifier dataType, - OutputStream out, - MacCalculator macCalculator, - DigestCalculator digestCalculator) - throws CMSException - { - this.macCalculator = macCalculator; - - try - { - ASN1EncodableVector recipientInfos = new ASN1EncodableVector(); - - for (Iterator it = recipientInfoGenerators.iterator(); it.hasNext();) - { - RecipientInfoGenerator recipient = (RecipientInfoGenerator)it.next(); - - recipientInfos.add(recipient.generate(macCalculator.getKey())); - } - - // - // ContentInfo - // - BERSequenceGenerator cGen = new BERSequenceGenerator(out); - - cGen.addObject(CMSObjectIdentifiers.authenticatedData); - - // - // Authenticated Data - // - BERSequenceGenerator authGen = new BERSequenceGenerator(cGen.getRawOutputStream(), 0, true); - - authGen.addObject(new ASN1Integer(AuthenticatedData.calculateVersion(originatorInfo))); - - if (originatorInfo != null) - { - authGen.addObject(new DERTaggedObject(false, 0, originatorInfo)); - } - - if (berEncodeRecipientSet) - { - authGen.getRawOutputStream().write(new BERSet(recipientInfos).getEncoded()); - } - else - { - authGen.getRawOutputStream().write(new DERSet(recipientInfos).getEncoded()); - } - - AlgorithmIdentifier macAlgId = macCalculator.getAlgorithmIdentifier(); - - authGen.getRawOutputStream().write(macAlgId.getEncoded()); - - if (digestCalculator != null) - { - authGen.addObject(new DERTaggedObject(false, 1, digestCalculator.getAlgorithmIdentifier())); - } - - BERSequenceGenerator eiGen = new BERSequenceGenerator(authGen.getRawOutputStream()); - - eiGen.addObject(dataType); - - OutputStream octetStream = CMSUtils.createBEROctetOutputStream( - eiGen.getRawOutputStream(), 0, false, bufferSize); - - OutputStream mOut; - - if (digestCalculator != null) - { - mOut = new TeeOutputStream(octetStream, digestCalculator.getOutputStream()); - } - else - { - mOut = new TeeOutputStream(octetStream, macCalculator.getOutputStream()); - } - - return new CmsAuthenticatedDataOutputStream(macCalculator, digestCalculator, dataType, mOut, cGen, authGen, eiGen); - } - catch (IOException e) - { - throw new CMSException("exception decoding algorithm parameters.", e); - } - } - - private class CmsAuthenticatedDataOutputStream - extends OutputStream - { - private OutputStream dataStream; - private BERSequenceGenerator cGen; - private BERSequenceGenerator envGen; - private BERSequenceGenerator eiGen; - private MacCalculator macCalculator; - private DigestCalculator digestCalculator; - private ASN1ObjectIdentifier contentType; - - public CmsAuthenticatedDataOutputStream( - MacCalculator macCalculator, - DigestCalculator digestCalculator, - ASN1ObjectIdentifier contentType, - OutputStream dataStream, - BERSequenceGenerator cGen, - BERSequenceGenerator envGen, - BERSequenceGenerator eiGen) - { - this.macCalculator = macCalculator; - this.digestCalculator = digestCalculator; - this.contentType = contentType; - this.dataStream = dataStream; - this.cGen = cGen; - this.envGen = envGen; - this.eiGen = eiGen; - } - - public void write( - int b) - throws IOException - { - dataStream.write(b); - } - - public void write( - byte[] bytes, - int off, - int len) - throws IOException - { - dataStream.write(bytes, off, len); - } - - public void write( - byte[] bytes) - throws IOException - { - dataStream.write(bytes); - } - - public void close() - throws IOException - { - dataStream.close(); - eiGen.close(); - - Map parameters; - - if (digestCalculator != null) - { - parameters = Collections.unmodifiableMap(getBaseParameters(contentType, digestCalculator.getAlgorithmIdentifier(), digestCalculator.getDigest())); - - if (authGen == null) - { - authGen = new DefaultAuthenticatedAttributeTableGenerator(); - } - - ASN1Set authed = new DERSet(authGen.getAttributes(parameters).toASN1EncodableVector()); - - OutputStream mOut = macCalculator.getOutputStream(); - - mOut.write(authed.getEncoded(ASN1Encoding.DER)); - - mOut.close(); - - envGen.addObject(new DERTaggedObject(false, 2, authed)); - } - else - { - parameters = Collections.unmodifiableMap(new HashMap()); - } - - envGen.addObject(new DEROctetString(macCalculator.getMac())); - - if (unauthGen != null) - { - envGen.addObject(new DERTaggedObject(false, 3, new BERSet(unauthGen.getAttributes(parameters).toASN1EncodableVector()))); - } - - envGen.close(); - cGen.close(); - } - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthenticatedGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSAuthenticatedGenerator.java deleted file mode 100644 index 6aadf1ec..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthenticatedGenerator.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.bouncycastle.cms; - -import java.util.HashMap; -import java.util.Map; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.util.Arrays; - -public class CMSAuthenticatedGenerator - extends CMSEnvelopedGenerator -{ - protected CMSAttributeTableGenerator authGen; - protected CMSAttributeTableGenerator unauthGen; - - /** - * base constructor - */ - public CMSAuthenticatedGenerator() - { - } - - public void setAuthenticatedAttributeGenerator(CMSAttributeTableGenerator authGen) - { - this.authGen = authGen; - } - - public void setUnauthenticatedAttributeGenerator(CMSAttributeTableGenerator unauthGen) - { - this.unauthGen = unauthGen; - } - - 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; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSCompressedData.java b/pkix/src/main/java/org/bouncycastle/cms/CMSCompressedData.java deleted file mode 100644 index 3e44908d..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSCompressedData.java +++ /dev/null @@ -1,107 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.IOException; -import java.io.InputStream; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.cms.CompressedData; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.operator.InputExpander; -import org.bouncycastle.operator.InputExpanderProvider; - -/** - * containing class for an CMS Compressed Data object - * <pre> - * CMSCompressedData cd = new CMSCompressedData(inputStream); - * - * process(cd.getContent(new ZlibExpanderProvider())); - * </pre> - */ -public class CMSCompressedData -{ - ContentInfo contentInfo; - CompressedData comData; - - public CMSCompressedData( - byte[] compressedData) - throws CMSException - { - this(CMSUtils.readContentInfo(compressedData)); - } - - public CMSCompressedData( - InputStream compressedData) - throws CMSException - { - this(CMSUtils.readContentInfo(compressedData)); - } - - public CMSCompressedData( - ContentInfo contentInfo) - throws CMSException - { - this.contentInfo = contentInfo; - - try - { - this.comData = CompressedData.getInstance(contentInfo.getContent()); - } - catch (ClassCastException e) - { - throw new CMSException("Malformed content.", e); - } - catch (IllegalArgumentException e) - { - throw new CMSException("Malformed content.", e); - } - } - - public ASN1ObjectIdentifier getContentType() - { - return contentInfo.getContentType(); - } - - /** - * Return the uncompressed content. - * - * @param expanderProvider a provider of expander algorithm implementations. - * @return the uncompressed content - * @throws CMSException if there is an exception un-compressing the data. - */ - public byte[] getContent(InputExpanderProvider expanderProvider) - throws CMSException - { - ContentInfo content = comData.getEncapContentInfo(); - - ASN1OctetString bytes = (ASN1OctetString)content.getContent(); - InputExpander expander = expanderProvider.get(comData.getCompressionAlgorithmIdentifier()); - InputStream zIn = expander.getInputStream(bytes.getOctetStream()); - - try - { - return CMSUtils.streamToByteArray(zIn); - } - catch (IOException e) - { - throw new CMSException("exception reading compressed stream.", e); - } - } - - /** - * 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(); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSCompressedDataGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSCompressedDataGenerator.java deleted file mode 100644 index d50391a1..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSCompressedDataGenerator.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.BEROctetString; -import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; -import org.bouncycastle.asn1.cms.CompressedData; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.operator.OutputCompressor; - -/** - * General class for generating a compressed CMS message. - * <p> - * A simple example of usage. - * <p> - * <pre> - * CMSCompressedDataGenerator fact = new CMSCompressedDataGenerator(); - * - * CMSCompressedData data = fact.generate(content, new ZlibCompressor()); - * </pre> - */ -public class CMSCompressedDataGenerator -{ - public static final String ZLIB = "1.2.840.113549.1.9.16.3.8"; - - /** - * base constructor - */ - public CMSCompressedDataGenerator() - { - } - - /** - * generate an object that contains an CMS Compressed Data - */ - public CMSCompressedData generate( - CMSTypedData content, - OutputCompressor compressor) - throws CMSException - { - AlgorithmIdentifier comAlgId; - ASN1OctetString comOcts; - - try - { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - OutputStream zOut = compressor.getOutputStream(bOut); - - content.write(zOut); - - zOut.close(); - - comAlgId = compressor.getAlgorithmIdentifier(); - comOcts = new BEROctetString(bOut.toByteArray()); - } - catch (IOException e) - { - throw new CMSException("exception encoding data.", e); - } - - ContentInfo comContent = new ContentInfo( - content.getContentType(), comOcts); - - ContentInfo contentInfo = new ContentInfo( - CMSObjectIdentifiers.compressedData, - new CompressedData(comAlgId, comContent)); - - return new CMSCompressedData(contentInfo); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSCompressedDataParser.java b/pkix/src/main/java/org/bouncycastle/cms/CMSCompressedDataParser.java deleted file mode 100644 index c3da87b7..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSCompressedDataParser.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; - -import org.bouncycastle.asn1.ASN1OctetStringParser; -import org.bouncycastle.asn1.ASN1SequenceParser; -import org.bouncycastle.asn1.BERTags; -import org.bouncycastle.asn1.cms.CompressedDataParser; -import org.bouncycastle.asn1.cms.ContentInfoParser; -import org.bouncycastle.operator.InputExpander; -import org.bouncycastle.operator.InputExpanderProvider; - -/** - * Class for reading a CMS Compressed Data stream. - * <pre> - * CMSCompressedDataParser cp = new CMSCompressedDataParser(inputStream); - * - * process(cp.getContent(new ZlibExpanderProvider()).getContentStream()); - * </pre> - * Note: this class does not introduce buffering - if you are processing large files you should create - * the parser with: - * <pre> - * CMSCompressedDataParser ep = new CMSCompressedDataParser(new BufferedInputStream(inputStream, bufSize)); - * </pre> - * where bufSize is a suitably large buffer size. - */ -public class CMSCompressedDataParser - extends CMSContentInfoParser -{ - public CMSCompressedDataParser( - byte[] compressedData) - throws CMSException - { - this(new ByteArrayInputStream(compressedData)); - } - - public CMSCompressedDataParser( - InputStream compressedData) - throws CMSException - { - super(compressedData); - } - - /** - * Return a typed stream which will allow the reading of the compressed content in - * expanded form. - * - * @param expanderProvider a provider of expander algorithm implementations. - * @return a type stream which will yield the un-compressed content. - * @throws CMSException if there is an exception parsing the CompressedData object. - */ - public CMSTypedStream getContent(InputExpanderProvider expanderProvider) - throws CMSException - { - try - { - CompressedDataParser comData = new CompressedDataParser((ASN1SequenceParser)_contentInfo.getContent(BERTags.SEQUENCE)); - ContentInfoParser content = comData.getEncapContentInfo(); - InputExpander expander = expanderProvider.get(comData.getCompressionAlgorithmIdentifier()); - - ASN1OctetStringParser bytes = (ASN1OctetStringParser)content.getContent(BERTags.OCTET_STRING); - - return new CMSTypedStream(content.getContentType().getId(), expander.getInputStream(bytes.getOctetStream())); - } - catch (IOException e) - { - throw new CMSException("IOException reading compressed content.", e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSCompressedDataStreamGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSCompressedDataStreamGenerator.java deleted file mode 100644 index 8a34eb01..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSCompressedDataStreamGenerator.java +++ /dev/null @@ -1,165 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.IOException; -import java.io.OutputStream; - -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.BERSequenceGenerator; -import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; -import org.bouncycastle.operator.OutputCompressor; - -/** - * General class for generating a compressed CMS message stream. - * <p> - * A simple example of usage. - * </p> - * <pre> - * CMSCompressedDataStreamGenerator gen = new CMSCompressedDataStreamGenerator(); - * - * OutputStream cOut = gen.open(outputStream, new ZlibCompressor()); - * - * cOut.write(data); - * - * cOut.close(); - * </pre> - */ -public class CMSCompressedDataStreamGenerator -{ - public static final String ZLIB = "1.2.840.113549.1.9.16.3.8"; - - private int _bufferSize; - - /** - * base constructor - */ - public CMSCompressedDataStreamGenerator() - { - } - - /** - * Set the underlying string size for encapsulated data - * - * @param bufferSize length of octet strings to buffer the data. - */ - public void setBufferSize( - int bufferSize) - { - _bufferSize = bufferSize; - } - - /** - * Open a compressing output stream with the PKCS#7 content type OID of "data". - * - * @param out the stream to encode to. - * @param compressor the type of compressor to use. - * @return an output stream to write the data be compressed to. - * @throws IOException - */ - public OutputStream open( - OutputStream out, - OutputCompressor compressor) - throws IOException - { - return open(CMSObjectIdentifiers.data, out, compressor); - } - - /** - * Open a compressing output stream. - * - * @param contentOID the content type OID. - * @param out the stream to encode to. - * @param compressor the type of compressor to use. - * @return an output stream to write the data be compressed to. - * @throws IOException - */ - public OutputStream open( - ASN1ObjectIdentifier contentOID, - OutputStream out, - OutputCompressor compressor) - throws IOException - { - BERSequenceGenerator sGen = new BERSequenceGenerator(out); - - sGen.addObject(CMSObjectIdentifiers.compressedData); - - // - // Compressed Data - // - BERSequenceGenerator cGen = new BERSequenceGenerator(sGen.getRawOutputStream(), 0, true); - - cGen.addObject(new ASN1Integer(0)); - - // - // AlgorithmIdentifier - // - cGen.addObject(compressor.getAlgorithmIdentifier()); - - // - // Encapsulated ContentInfo - // - BERSequenceGenerator eiGen = new BERSequenceGenerator(cGen.getRawOutputStream()); - - eiGen.addObject(contentOID); - - OutputStream octetStream = CMSUtils.createBEROctetOutputStream( - eiGen.getRawOutputStream(), 0, true, _bufferSize); - - return new CmsCompressedOutputStream( - compressor.getOutputStream(octetStream), sGen, cGen, eiGen); - } - - private class CmsCompressedOutputStream - extends OutputStream - { - private OutputStream _out; - private BERSequenceGenerator _sGen; - private BERSequenceGenerator _cGen; - private BERSequenceGenerator _eiGen; - - CmsCompressedOutputStream( - OutputStream out, - BERSequenceGenerator sGen, - BERSequenceGenerator cGen, - BERSequenceGenerator eiGen) - { - _out = out; - _sGen = sGen; - _cGen = cGen; - _eiGen = eiGen; - } - - public void write( - int b) - throws IOException - { - _out.write(b); - } - - - public void write( - byte[] bytes, - int off, - int len) - throws IOException - { - _out.write(bytes, off, len); - } - - public void write( - byte[] bytes) - throws IOException - { - _out.write(bytes); - } - - public void close() - throws IOException - { - _out.close(); - _eiGen.close(); - _cGen.close(); - _sGen.close(); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSConfig.java b/pkix/src/main/java/org/bouncycastle/cms/CMSConfig.java deleted file mode 100644 index fd6782dc..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSConfig.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.bouncycastle.cms; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; - -public class CMSConfig -{ - /** - * 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. - */ - public static void setSigningEncryptionAlgorithmMapping(String oid, String algorithmName) - { - ASN1ObjectIdentifier id = new ASN1ObjectIdentifier(oid); - - CMSSignedHelper.INSTANCE.setSigningEncryptionAlgorithmMapping(id, 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. - */ - public static void setSigningDigestAlgorithmMapping(String oid, String algorithmName) - { - ASN1ObjectIdentifier id = new ASN1ObjectIdentifier(oid); - - CMSSignedHelper.INSTANCE.setSigningDigestAlgorithmMapping(id, algorithmName); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSContentInfoParser.java b/pkix/src/main/java/org/bouncycastle/cms/CMSContentInfoParser.java deleted file mode 100644 index a8e5a8da..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSContentInfoParser.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.IOException; -import java.io.InputStream; - -import org.bouncycastle.asn1.ASN1SequenceParser; -import org.bouncycastle.asn1.ASN1StreamParser; -import org.bouncycastle.asn1.cms.ContentInfoParser; - -public class CMSContentInfoParser -{ - protected ContentInfoParser _contentInfo; - protected InputStream _data; - - protected CMSContentInfoParser( - InputStream data) - throws CMSException - { - _data = data; - - try - { - ASN1StreamParser in = new ASN1StreamParser(data); - - _contentInfo = new ContentInfoParser((ASN1SequenceParser)in.readObject()); - } - catch (IOException e) - { - throw new CMSException("IOException reading content.", e); - } - catch (ClassCastException e) - { - throw new CMSException("Unexpected object reading content.", e); - } - } - - /** - * Close the underlying data stream. - * @throws IOException if the close fails. - */ - public void close() throws IOException - { - _data.close(); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSDigestedData.java b/pkix/src/main/java/org/bouncycastle/cms/CMSDigestedData.java deleted file mode 100644 index af486923..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSDigestedData.java +++ /dev/null @@ -1,136 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.cms.DigestedData; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.operator.DigestCalculator; -import org.bouncycastle.operator.DigestCalculatorProvider; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.util.Arrays; - -/** - * containing class for an CMS Digested Data object - * <pre> - * CMSDigestedData cd = new CMSDigestedData(inputStream); - * - * - * process(cd.getContent()); - * </pre> - */ -public class CMSDigestedData -{ - private ContentInfo contentInfo; - private DigestedData digestedData; - - public CMSDigestedData( - byte[] compressedData) - throws CMSException - { - this(CMSUtils.readContentInfo(compressedData)); - } - - public CMSDigestedData( - InputStream compressedData) - throws CMSException - { - this(CMSUtils.readContentInfo(compressedData)); - } - - public CMSDigestedData( - ContentInfo contentInfo) - throws CMSException - { - this.contentInfo = contentInfo; - - try - { - this.digestedData = DigestedData.getInstance(contentInfo.getContent()); - } - catch (ClassCastException e) - { - throw new CMSException("Malformed content.", e); - } - catch (IllegalArgumentException e) - { - throw new CMSException("Malformed content.", e); - } - } - - public ASN1ObjectIdentifier getContentType() - { - return contentInfo.getContentType(); - } - - public AlgorithmIdentifier getDigestAlgorithm() - { - return digestedData.getDigestAlgorithm(); - } - - /** - * Return the digested content - * - * @return the digested content - * @throws CMSException if there is an exception un-compressing the data. - */ - public CMSProcessable getDigestedContent() - throws CMSException - { - ContentInfo content = digestedData.getEncapContentInfo(); - - try - { - return new CMSProcessableByteArray(content.getContentType(), ((ASN1OctetString)content.getContent()).getOctets()); - } - catch (Exception e) - { - throw new CMSException("exception reading digested stream.", e); - } - } - - /** - * 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(); - } - - public boolean verify(DigestCalculatorProvider calculatorProvider) - throws CMSException - { - try - { - ContentInfo content = digestedData.getEncapContentInfo(); - DigestCalculator calc = calculatorProvider.get(digestedData.getDigestAlgorithm()); - - OutputStream dOut = calc.getOutputStream(); - - dOut.write(((ASN1OctetString)content.getContent()).getOctets()); - - return Arrays.areEqual(digestedData.getDigest(), calc.getDigest()); - } - catch (OperatorCreationException e) - { - throw new CMSException("unable to create digest calculator: " + e.getMessage(), e); - } - catch (IOException e) - { - throw new CMSException("unable process content: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSEncryptedData.java b/pkix/src/main/java/org/bouncycastle/cms/CMSEncryptedData.java deleted file mode 100644 index f96e7560..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSEncryptedData.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.ByteArrayInputStream; -import java.io.IOException; - -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.cms.EncryptedContentInfo; -import org.bouncycastle.asn1.cms.EncryptedData; -import org.bouncycastle.operator.InputDecryptor; -import org.bouncycastle.operator.InputDecryptorProvider; - -public class CMSEncryptedData -{ - private ContentInfo contentInfo; - private EncryptedData encryptedData; - - public CMSEncryptedData(ContentInfo contentInfo) - { - this.contentInfo = contentInfo; - - this.encryptedData = EncryptedData.getInstance(contentInfo.getContent()); - } - - public byte[] getContent(InputDecryptorProvider inputDecryptorProvider) - throws CMSException - { - try - { - return CMSUtils.streamToByteArray(getContentStream(inputDecryptorProvider).getContentStream()); - } - catch (IOException e) - { - throw new CMSException("unable to parse internal stream: " + e.getMessage(), e); - } - } - - public CMSTypedStream getContentStream(InputDecryptorProvider inputDecryptorProvider) - throws CMSException - { - try - { - EncryptedContentInfo encContentInfo = encryptedData.getEncryptedContentInfo(); - InputDecryptor decrytor = inputDecryptorProvider.get(encContentInfo.getContentEncryptionAlgorithm()); - - ByteArrayInputStream encIn = new ByteArrayInputStream(encContentInfo.getEncryptedContent().getOctets()); - - return new CMSTypedStream(encContentInfo.getContentType(), decrytor.getInputStream(encIn)); - } - catch (Exception e) - { - throw new CMSException("unable to create stream: " + e.getMessage(), e); - } - } - - /** - * return the ContentInfo - */ - public ContentInfo toASN1Structure() - { - return contentInfo; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSEncryptedDataGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSEncryptedDataGenerator.java deleted file mode 100644 index d12097ee..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSEncryptedDataGenerator.java +++ /dev/null @@ -1,109 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.HashMap; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.BEROctetString; -import org.bouncycastle.asn1.BERSet; -import org.bouncycastle.asn1.cms.AttributeTable; -import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.cms.EncryptedContentInfo; -import org.bouncycastle.asn1.cms.EncryptedData; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.operator.OutputEncryptor; - -/** - * General class for generating a CMS enveloped-data message. - * - * A simple example of usage. - * - * <pre> - * CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes()); - * - * CMSEncryptedDataGenerator edGen = new CMSEnvelopedDataGenerator(); - * - * CMSEncryptedData ed = edGen.generate( - * msg, - * new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC) - * .setProvider("BC").build()); - * - * </pre> - */ -public class CMSEncryptedDataGenerator - extends CMSEncryptedGenerator -{ - /** - * base constructor - */ - public CMSEncryptedDataGenerator() - { - } - - private CMSEncryptedData doGenerate( - CMSTypedData content, - OutputEncryptor contentEncryptor) - throws CMSException - { - AlgorithmIdentifier encAlgId; - ASN1OctetString encContent; - - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - - try - { - OutputStream cOut = contentEncryptor.getOutputStream(bOut); - - content.write(cOut); - - cOut.close(); - } - catch (IOException e) - { - throw new CMSException(""); - } - - byte[] encryptedContent = bOut.toByteArray(); - - encAlgId = contentEncryptor.getAlgorithmIdentifier(); - - encContent = new BEROctetString(encryptedContent); - - EncryptedContentInfo eci = new EncryptedContentInfo( - content.getContentType(), - encAlgId, - encContent); - - ASN1Set unprotectedAttrSet = null; - if (unprotectedAttributeGenerator != null) - { - AttributeTable attrTable = unprotectedAttributeGenerator.getAttributes(new HashMap()); - - unprotectedAttrSet = new BERSet(attrTable.toASN1EncodableVector()); - } - - ContentInfo contentInfo = new ContentInfo( - CMSObjectIdentifiers.encryptedData, - new EncryptedData(eci, unprotectedAttrSet)); - - return new CMSEncryptedData(contentInfo); - } - - /** - * generate an encrypted object that contains an CMS Encrypted Data structure. - * - * @param content the content to be encrypted - * @param contentEncryptor the symmetric key based encryptor to encrypt the content with. - */ - public CMSEncryptedData generate( - CMSTypedData content, - OutputEncryptor contentEncryptor) - throws CMSException - { - return doGenerate(content, contentEncryptor); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSEncryptedGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSEncryptedGenerator.java deleted file mode 100644 index eece6808..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSEncryptedGenerator.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.bouncycastle.cms; - -/** - * General class for generating a CMS encrypted-data message. - */ -public class CMSEncryptedGenerator -{ - protected CMSAttributeTableGenerator unprotectedAttributeGenerator = null; - - /** - * base constructor - */ - protected CMSEncryptedGenerator() - { - } - - public void setUnprotectedAttributeGenerator(CMSAttributeTableGenerator unprotectedAttributeGenerator) - { - this.unprotectedAttributeGenerator = unprotectedAttributeGenerator; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedData.java b/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedData.java deleted file mode 100644 index 56b96635..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedData.java +++ /dev/null @@ -1,206 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.IOException; -import java.io.InputStream; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.cms.AttributeTable; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.cms.EncryptedContentInfo; -import org.bouncycastle.asn1.cms.EnvelopedData; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -/** - * containing class for an CMS Enveloped Data object - * <p> - * Example of use - assuming the first recipient matches the private key we have. - * <pre> - * CMSEnvelopedData ed = new CMSEnvelopedData(inputStream); - * - * RecipientInformationStore recipients = ed.getRecipientInfos(); - * - * Collection c = recipients.getRecipients(); - * Iterator it = c.iterator(); - * - * if (it.hasNext()) - * { - * RecipientInformation recipient = (RecipientInformation)it.next(); - * - * byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(privateKey).setProvider("BC")); - * - * processData(recData); - * } - * </pre> - */ -public class CMSEnvelopedData -{ - RecipientInformationStore recipientInfoStore; - ContentInfo contentInfo; - - private AlgorithmIdentifier encAlg; - private ASN1Set unprotectedAttributes; - private OriginatorInformation originatorInfo; - - public CMSEnvelopedData( - byte[] envelopedData) - throws CMSException - { - this(CMSUtils.readContentInfo(envelopedData)); - } - - public CMSEnvelopedData( - InputStream envelopedData) - throws CMSException - { - this(CMSUtils.readContentInfo(envelopedData)); - } - - /** - * Construct a CMSEnvelopedData object from a content info object. - * - * @param contentInfo the contentInfo containing the CMS EnvelopedData object. - * @throws CMSException in the case where malformed content is encountered. - */ - public CMSEnvelopedData( - ContentInfo contentInfo) - throws CMSException - { - this.contentInfo = contentInfo; - - try - { - EnvelopedData envData = EnvelopedData.getInstance(contentInfo.getContent()); - - if (envData.getOriginatorInfo() != null) - { - originatorInfo = new OriginatorInformation(envData.getOriginatorInfo()); - } - - // - // read the recipients - // - ASN1Set recipientInfos = envData.getRecipientInfos(); - - // - // read the encrypted content info - // - EncryptedContentInfo encInfo = envData.getEncryptedContentInfo(); - this.encAlg = encInfo.getContentEncryptionAlgorithm(); - CMSReadable readable = new CMSProcessableByteArray(encInfo.getEncryptedContent().getOctets()); - CMSSecureReadable secureReadable = new CMSEnvelopedHelper.CMSEnvelopedSecureReadable( - this.encAlg, readable); - - // - // build the RecipientInformationStore - // - this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore( - recipientInfos, this.encAlg, secureReadable); - - this.unprotectedAttributes = envData.getUnprotectedAttrs(); - } - catch (ClassCastException e) - { - throw new CMSException("Malformed content.", e); - } - catch (IllegalArgumentException e) - { - throw new CMSException("Malformed content.", e); - } - } - - private byte[] encodeObj( - ASN1Encodable obj) - throws IOException - { - if (obj != null) - { - return obj.toASN1Primitive().getEncoded(); - } - - return null; - } - - /** - * Return the originator information associated with this message if present. - * - * @return OriginatorInformation, null if not present. - */ - public OriginatorInformation getOriginatorInfo() - { - return originatorInfo; - } - - /** - * Return the content encryption algorithm details for the data in this object. - * - * @return AlgorithmIdentifier representing the content encryption algorithm. - */ - public AlgorithmIdentifier getContentEncryptionAlgorithm() - { - return encAlg; - } - - /** - * return the object identifier for the content encryption algorithm. - */ - public String getEncryptionAlgOID() - { - return encAlg.getAlgorithm().getId(); - } - - /** - * return the ASN.1 encoded encryption algorithm parameters, or null if - * there aren't any. - */ - public byte[] getEncryptionAlgParams() - { - try - { - return encodeObj(encAlg.getParameters()); - } - catch (Exception e) - { - throw new RuntimeException("exception getting encryption parameters " + e); - } - } - - /** - * return a store of the intended recipients for this message - */ - public RecipientInformationStore getRecipientInfos() - { - return recipientInfoStore; - } - - /** - * return the ContentInfo - */ - public ContentInfo toASN1Structure() - { - return contentInfo; - } - - /** - * return a table of the unprotected attributes indexed by - * the OID of the attribute. - */ - public AttributeTable getUnprotectedAttributes() - { - if (unprotectedAttributes == null) - { - return null; - } - - return new AttributeTable(unprotectedAttributes); - } - - /** - * return the ASN.1 encoded representation of this object. - */ - public byte[] getEncoded() - throws IOException - { - return contentInfo.getEncoded(); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedDataGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedDataGenerator.java deleted file mode 100644 index 0038f90f..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedDataGenerator.java +++ /dev/null @@ -1,131 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.HashMap; -import java.util.Iterator; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.BEROctetString; -import org.bouncycastle.asn1.BERSet; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.cms.AttributeTable; -import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.cms.EncryptedContentInfo; -import org.bouncycastle.asn1.cms.EnvelopedData; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.OutputEncryptor; - -/** - * General class for generating a CMS enveloped-data message. - * - * A simple example of usage. - * - * <pre> - * CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes()); - * - * CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator(); - * - * edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(recipientCert).setProvider("BC")); - * - * CMSEnvelopedData ed = edGen.generate( - * msg, - * new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC) - * .setProvider("BC").build()); - * - * </pre> - */ -public class CMSEnvelopedDataGenerator - extends CMSEnvelopedGenerator -{ - /** - * base constructor - */ - public CMSEnvelopedDataGenerator() - { - } - - private CMSEnvelopedData doGenerate( - CMSTypedData content, - OutputEncryptor contentEncryptor) - throws CMSException - { - if (!oldRecipientInfoGenerators.isEmpty()) - { - throw new IllegalStateException("can only use addRecipientGenerator() with this method"); - } - - ASN1EncodableVector recipientInfos = new ASN1EncodableVector(); - AlgorithmIdentifier encAlgId; - ASN1OctetString encContent; - - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - - try - { - OutputStream cOut = contentEncryptor.getOutputStream(bOut); - - content.write(cOut); - - cOut.close(); - } - catch (IOException e) - { - throw new CMSException(""); - } - - byte[] encryptedContent = bOut.toByteArray(); - - encAlgId = contentEncryptor.getAlgorithmIdentifier(); - - encContent = new BEROctetString(encryptedContent); - - GenericKey encKey = contentEncryptor.getKey(); - - for (Iterator it = recipientInfoGenerators.iterator(); it.hasNext();) - { - RecipientInfoGenerator recipient = (RecipientInfoGenerator)it.next(); - - recipientInfos.add(recipient.generate(encKey)); - } - - EncryptedContentInfo eci = new EncryptedContentInfo( - content.getContentType(), - encAlgId, - encContent); - - ASN1Set unprotectedAttrSet = null; - if (unprotectedAttributeGenerator != null) - { - AttributeTable attrTable = unprotectedAttributeGenerator.getAttributes(new HashMap()); - - unprotectedAttrSet = new BERSet(attrTable.toASN1EncodableVector()); - } - - ContentInfo contentInfo = new ContentInfo( - CMSObjectIdentifiers.envelopedData, - new EnvelopedData(originatorInfo, new DERSet(recipientInfos), eci, unprotectedAttrSet)); - - return new CMSEnvelopedData(contentInfo); - } - - /** - * generate an enveloped object that contains an CMS Enveloped Data - * object using the given provider. - * - * @param content the content to be encrypted - * @param contentEncryptor the symmetric key based encryptor to encrypt the content with. - */ - public CMSEnvelopedData generate( - CMSTypedData content, - OutputEncryptor contentEncryptor) - throws CMSException - { - return doGenerate(content, contentEncryptor); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedDataParser.java b/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedDataParser.java deleted file mode 100644 index 67c9d913..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedDataParser.java +++ /dev/null @@ -1,208 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1OctetStringParser; -import org.bouncycastle.asn1.ASN1SequenceParser; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.ASN1SetParser; -import org.bouncycastle.asn1.BERTags; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.cms.AttributeTable; -import org.bouncycastle.asn1.cms.EncryptedContentInfoParser; -import org.bouncycastle.asn1.cms.EnvelopedDataParser; -import org.bouncycastle.asn1.cms.OriginatorInfo; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -/** - * Parsing class for an CMS Enveloped Data object from an input stream. - * <p> - * Note: that because we are in a streaming mode only one recipient can be tried and it is important - * that the methods on the parser are called in the appropriate order. - * </p> - * <p> - * Example of use - assuming the first recipient matches the private key we have. - * <pre> - * CMSEnvelopedDataParser ep = new CMSEnvelopedDataParser(inputStream); - * - * RecipientInformationStore recipients = ep.getRecipientInfos(); - * - * Collection c = recipients.getRecipients(); - * Iterator it = c.iterator(); - * - * if (it.hasNext()) - * { - * RecipientInformation recipient = (RecipientInformation)it.next(); - * - * CMSTypedStream recData = recipient.getContentStream(new JceKeyTransEnvelopedRecipient(privateKey).setProvider("BC")); - * - * processDataStream(recData.getContentStream()); - * } - * </pre> - * Note: this class does not introduce buffering - if you are processing large files you should create - * the parser with: - * <pre> - * CMSEnvelopedDataParser ep = new CMSEnvelopedDataParser(new BufferedInputStream(inputStream, bufSize)); - * </pre> - * where bufSize is a suitably large buffer size. - */ -public class CMSEnvelopedDataParser - extends CMSContentInfoParser -{ - RecipientInformationStore recipientInfoStore; - EnvelopedDataParser envelopedData; - - private AlgorithmIdentifier encAlg; - private AttributeTable unprotectedAttributes; - private boolean attrNotRead; - private OriginatorInformation originatorInfo; - - public CMSEnvelopedDataParser( - byte[] envelopedData) - throws CMSException, IOException - { - this(new ByteArrayInputStream(envelopedData)); - } - - public CMSEnvelopedDataParser( - InputStream envelopedData) - throws CMSException, IOException - { - super(envelopedData); - - this.attrNotRead = true; - this.envelopedData = new EnvelopedDataParser((ASN1SequenceParser)_contentInfo.getContent(BERTags.SEQUENCE)); - - // TODO Validate version? - //ASN1Integer version = this._envelopedData.getVersion(); - - OriginatorInfo info = this.envelopedData.getOriginatorInfo(); - - if (info != null) - { - this.originatorInfo = new OriginatorInformation(info); - } - - // - // read the recipients - // - ASN1Set recipientInfos = ASN1Set.getInstance(this.envelopedData.getRecipientInfos().toASN1Primitive()); - - // - // read the encrypted content info - // - EncryptedContentInfoParser encInfo = this.envelopedData.getEncryptedContentInfo(); - this.encAlg = encInfo.getContentEncryptionAlgorithm(); - CMSReadable readable = new CMSProcessableInputStream( - ((ASN1OctetStringParser)encInfo.getEncryptedContent(BERTags.OCTET_STRING)).getOctetStream()); - CMSSecureReadable secureReadable = new CMSEnvelopedHelper.CMSEnvelopedSecureReadable( - this.encAlg, readable); - - // - // build the RecipientInformationStore - // - this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore( - recipientInfos, this.encAlg, secureReadable); - } - - /** - * return the object identifier for the content encryption algorithm. - */ - public String getEncryptionAlgOID() - { - return encAlg.getAlgorithm().toString(); - } - - /** - * return the ASN.1 encoded encryption algorithm parameters, or null if - * there aren't any. - */ - public byte[] getEncryptionAlgParams() - { - try - { - return encodeObj(encAlg.getParameters()); - } - catch (Exception e) - { - throw new RuntimeException("exception getting encryption parameters " + e); - } - } - - /** - * Return the content encryption algorithm details for the data in this object. - * - * @return AlgorithmIdentifier representing the content encryption algorithm. - */ - public AlgorithmIdentifier getContentEncryptionAlgorithm() - { - return encAlg; - } - - /** - * Return the originator information associated with this message if present. - * - * @return OriginatorInformation, null if not present. - */ - public OriginatorInformation getOriginatorInfo() - { - return originatorInfo; - } - - /** - * return a store of the intended recipients for this message - */ - public RecipientInformationStore getRecipientInfos() - { - return recipientInfoStore; - } - - /** - * return a table of the unprotected attributes indexed by - * the OID of the attribute. - * @exception IOException - */ - public AttributeTable getUnprotectedAttributes() - throws IOException - { - if (unprotectedAttributes == null && attrNotRead) - { - ASN1SetParser set = envelopedData.getUnprotectedAttrs(); - - attrNotRead = false; - - if (set != null) - { - ASN1EncodableVector v = new ASN1EncodableVector(); - ASN1Encodable o; - - while ((o = set.readObject()) != null) - { - ASN1SequenceParser seq = (ASN1SequenceParser)o; - - v.add(seq.toASN1Primitive()); - } - - unprotectedAttributes = new AttributeTable(new DERSet(v)); - } - } - - return unprotectedAttributes; - } - - private byte[] encodeObj( - ASN1Encodable obj) - throws IOException - { - if (obj != null) - { - return obj.toASN1Primitive().getEncoded(); - } - - return null; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedDataStreamGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedDataStreamGenerator.java deleted file mode 100644 index 92abca00..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedDataStreamGenerator.java +++ /dev/null @@ -1,305 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.HashMap; -import java.util.Iterator; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.BERSequenceGenerator; -import org.bouncycastle.asn1.BERSet; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.DERTaggedObject; -import org.bouncycastle.asn1.cms.AttributeTable; -import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; -import org.bouncycastle.asn1.cms.EnvelopedData; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.OutputEncryptor; - -/** - * General class for generating a CMS enveloped-data message stream. - * <p> - * A simple example of usage. - * <pre> - * CMSEnvelopedDataStreamGenerator edGen = new CMSEnvelopedDataStreamGenerator(); - * - * edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(recipientCert).setProvider("BC")); - * - * ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - * - * OutputStream out = edGen.open( - * bOut, new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC) - * .setProvider("BC").build()); - * out.write(data); - * - * out.close(); - * </pre> - */ -public class CMSEnvelopedDataStreamGenerator - extends CMSEnvelopedGenerator -{ - private ASN1Set _unprotectedAttributes = null; - private int _bufferSize; - private boolean _berEncodeRecipientSet; - - /** - * base constructor - */ - public CMSEnvelopedDataStreamGenerator() - { - } - - /** - * Set the underlying string size for encapsulated data - * - * @param bufferSize length of octet strings to buffer the data. - */ - public void setBufferSize( - int bufferSize) - { - _bufferSize = bufferSize; - } - - /** - * Use a BER Set to store the recipient information - */ - public void setBEREncodeRecipients( - boolean berEncodeRecipientSet) - { - _berEncodeRecipientSet = berEncodeRecipientSet; - } - - private ASN1Integer getVersion() - { - if (originatorInfo != null || _unprotectedAttributes != null) - { - return new ASN1Integer(2); - } - else - { - return new ASN1Integer(0); - } - } - - private OutputStream doOpen( - ASN1ObjectIdentifier dataType, - OutputStream out, - OutputEncryptor encryptor) - throws IOException, CMSException - { - ASN1EncodableVector recipientInfos = new ASN1EncodableVector(); - GenericKey encKey = encryptor.getKey(); - Iterator it = recipientInfoGenerators.iterator(); - - while (it.hasNext()) - { - RecipientInfoGenerator recipient = (RecipientInfoGenerator)it.next(); - - recipientInfos.add(recipient.generate(encKey)); - } - - return open(dataType, out, recipientInfos, encryptor); - } - - protected OutputStream open( - ASN1ObjectIdentifier dataType, - OutputStream out, - ASN1EncodableVector recipientInfos, - OutputEncryptor encryptor) - throws IOException - { - // - // ContentInfo - // - BERSequenceGenerator cGen = new BERSequenceGenerator(out); - - cGen.addObject(CMSObjectIdentifiers.envelopedData); - - // - // Encrypted Data - // - BERSequenceGenerator envGen = new BERSequenceGenerator(cGen.getRawOutputStream(), 0, true); - - envGen.addObject(getVersion()); - - if (originatorInfo != null) - { - envGen.addObject(new DERTaggedObject(false, 0, originatorInfo)); - } - - if (_berEncodeRecipientSet) - { - envGen.getRawOutputStream().write(new BERSet(recipientInfos).getEncoded()); - } - else - { - envGen.getRawOutputStream().write(new DERSet(recipientInfos).getEncoded()); - } - - BERSequenceGenerator eiGen = new BERSequenceGenerator(envGen.getRawOutputStream()); - - eiGen.addObject(dataType); - - AlgorithmIdentifier encAlgId = encryptor.getAlgorithmIdentifier(); - - eiGen.getRawOutputStream().write(encAlgId.getEncoded()); - - OutputStream octetStream = CMSUtils.createBEROctetOutputStream( - eiGen.getRawOutputStream(), 0, false, _bufferSize); - - OutputStream cOut = encryptor.getOutputStream(octetStream); - - return new CmsEnvelopedDataOutputStream(cOut, cGen, envGen, eiGen); - } - - protected OutputStream open( - OutputStream out, - ASN1EncodableVector recipientInfos, - OutputEncryptor encryptor) - throws CMSException - { - try - { - // - // ContentInfo - // - BERSequenceGenerator cGen = new BERSequenceGenerator(out); - - cGen.addObject(CMSObjectIdentifiers.envelopedData); - - // - // Encrypted Data - // - BERSequenceGenerator envGen = new BERSequenceGenerator(cGen.getRawOutputStream(), 0, true); - - ASN1Set recipients; - if (_berEncodeRecipientSet) - { - recipients = new BERSet(recipientInfos); - } - else - { - recipients = new DERSet(recipientInfos); - } - - envGen.addObject(new ASN1Integer(EnvelopedData.calculateVersion(originatorInfo, recipients, _unprotectedAttributes))); - - if (originatorInfo != null) - { - envGen.addObject(new DERTaggedObject(false, 0, originatorInfo)); - } - - envGen.getRawOutputStream().write(recipients.getEncoded()); - - BERSequenceGenerator eiGen = new BERSequenceGenerator(envGen.getRawOutputStream()); - - eiGen.addObject(CMSObjectIdentifiers.data); - - AlgorithmIdentifier encAlgId = encryptor.getAlgorithmIdentifier(); - - eiGen.getRawOutputStream().write(encAlgId.getEncoded()); - - OutputStream octetStream = CMSUtils.createBEROctetOutputStream( - eiGen.getRawOutputStream(), 0, false, _bufferSize); - - return new CmsEnvelopedDataOutputStream(encryptor.getOutputStream(octetStream), cGen, envGen, eiGen); - } - catch (IOException e) - { - throw new CMSException("exception decoding algorithm parameters.", e); - } - } - - /** - * generate an enveloped object that contains an CMS Enveloped Data - * object using the given encryptor. - */ - public OutputStream open( - OutputStream out, - OutputEncryptor encryptor) - throws CMSException, IOException - { - return doOpen(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()), out, encryptor); - } - - /** - * generate an enveloped object that contains an CMS Enveloped Data - * object using the given encryptor and marking the data as being of the passed - * in type. - */ - public OutputStream open( - ASN1ObjectIdentifier dataType, - OutputStream out, - OutputEncryptor encryptor) - throws CMSException, IOException - { - return doOpen(dataType, out, encryptor); - } - - private class CmsEnvelopedDataOutputStream - extends OutputStream - { - private OutputStream _out; - private BERSequenceGenerator _cGen; - private BERSequenceGenerator _envGen; - private BERSequenceGenerator _eiGen; - - public CmsEnvelopedDataOutputStream( - OutputStream out, - BERSequenceGenerator cGen, - BERSequenceGenerator envGen, - BERSequenceGenerator eiGen) - { - _out = out; - _cGen = cGen; - _envGen = envGen; - _eiGen = eiGen; - } - - public void write( - int b) - throws IOException - { - _out.write(b); - } - - public void write( - byte[] bytes, - int off, - int len) - throws IOException - { - _out.write(bytes, off, len); - } - - public void write( - byte[] bytes) - throws IOException - { - _out.write(bytes); - } - - public void close() - throws IOException - { - _out.close(); - _eiGen.close(); - - if (unprotectedAttributeGenerator != null) - { - AttributeTable attrTable = unprotectedAttributeGenerator.getAttributes(new HashMap()); - - ASN1Set unprotectedAttrs = new BERSet(attrTable.toASN1EncodableVector()); - - _envGen.addObject(new DERTaggedObject(false, 1, unprotectedAttrs)); - } - - _envGen.close(); - _cGen.close(); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedGenerator.java deleted file mode 100644 index 012b440a..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedGenerator.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.bouncycastle.cms; - -import java.util.ArrayList; -import java.util.List; - -import org.bouncycastle.asn1.cms.OriginatorInfo; -import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; - -/** - * General class for generating a CMS enveloped-data message. - */ -public class CMSEnvelopedGenerator -{ - public static final String DES_EDE3_CBC = PKCSObjectIdentifiers.des_EDE3_CBC.getId(); - public static final String RC2_CBC = PKCSObjectIdentifiers.RC2_CBC.getId(); - public static final String IDEA_CBC = "1.3.6.1.4.1.188.7.1.1.2"; - public static final String CAST5_CBC = "1.2.840.113533.7.66.10"; - public static final String AES128_CBC = NISTObjectIdentifiers.id_aes128_CBC.getId(); - public static final String AES192_CBC = NISTObjectIdentifiers.id_aes192_CBC.getId(); - public static final String AES256_CBC = NISTObjectIdentifiers.id_aes256_CBC.getId(); - public static final String CAMELLIA128_CBC = NTTObjectIdentifiers.id_camellia128_cbc.getId(); - public static final String CAMELLIA192_CBC = NTTObjectIdentifiers.id_camellia192_cbc.getId(); - public static final String CAMELLIA256_CBC = NTTObjectIdentifiers.id_camellia256_cbc.getId(); - public static final String SEED_CBC = KISAObjectIdentifiers.id_seedCBC.getId(); - - public static final String DES_EDE3_WRAP = PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId(); - public static final String AES128_WRAP = NISTObjectIdentifiers.id_aes128_wrap.getId(); - public static final String AES192_WRAP = NISTObjectIdentifiers.id_aes192_wrap.getId(); - public static final String AES256_WRAP = NISTObjectIdentifiers.id_aes256_wrap.getId(); - public static final String CAMELLIA128_WRAP = NTTObjectIdentifiers.id_camellia128_wrap.getId(); - public static final String CAMELLIA192_WRAP = NTTObjectIdentifiers.id_camellia192_wrap.getId(); - public static final String CAMELLIA256_WRAP = NTTObjectIdentifiers.id_camellia256_wrap.getId(); - public static final String SEED_WRAP = KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap.getId(); - - public static final String ECDH_SHA1KDF = X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme.getId(); - public static final String ECMQV_SHA1KDF = X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme.getId(); - - final List oldRecipientInfoGenerators = new ArrayList(); - final List recipientInfoGenerators = new ArrayList(); - - protected CMSAttributeTableGenerator unprotectedAttributeGenerator = null; - - protected OriginatorInfo originatorInfo; - - /** - * base constructor - */ - public CMSEnvelopedGenerator() - { - } - - public void setUnprotectedAttributeGenerator(CMSAttributeTableGenerator unprotectedAttributeGenerator) - { - this.unprotectedAttributeGenerator = unprotectedAttributeGenerator; - } - - public void setOriginatorInfo(OriginatorInformation originatorInfo) - { - this.originatorInfo = originatorInfo.toASN1Structure(); - } - - /** - * Add a generator to produce the recipient info required. - * - * @param recipientGenerator a generator of a recipient info object. - */ - public void addRecipientInfoGenerator(RecipientInfoGenerator recipientGenerator) - { - recipientInfoGenerators.add(recipientGenerator); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedHelper.java b/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedHelper.java deleted file mode 100644 index 91727062..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedHelper.java +++ /dev/null @@ -1,203 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.cms.KEKRecipientInfo; -import org.bouncycastle.asn1.cms.KeyAgreeRecipientInfo; -import org.bouncycastle.asn1.cms.KeyTransRecipientInfo; -import org.bouncycastle.asn1.cms.PasswordRecipientInfo; -import org.bouncycastle.asn1.cms.RecipientInfo; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.operator.DigestCalculator; -import org.bouncycastle.util.Integers; - -class CMSEnvelopedHelper -{ - static final CMSEnvelopedHelper INSTANCE = new CMSEnvelopedHelper(); - - private static final Map KEYSIZES = new HashMap(); - private static final Map BASE_CIPHER_NAMES = new HashMap(); - private static final Map CIPHER_ALG_NAMES = new HashMap(); - private static final Map MAC_ALG_NAMES = new HashMap(); - - static - { - KEYSIZES.put(CMSEnvelopedGenerator.DES_EDE3_CBC, Integers.valueOf(192)); - KEYSIZES.put(CMSEnvelopedGenerator.AES128_CBC, Integers.valueOf(128)); - KEYSIZES.put(CMSEnvelopedGenerator.AES192_CBC, Integers.valueOf(192)); - KEYSIZES.put(CMSEnvelopedGenerator.AES256_CBC, Integers.valueOf(256)); - - BASE_CIPHER_NAMES.put(CMSEnvelopedGenerator.DES_EDE3_CBC, "DESEDE"); - BASE_CIPHER_NAMES.put(CMSEnvelopedGenerator.AES128_CBC, "AES"); - BASE_CIPHER_NAMES.put(CMSEnvelopedGenerator.AES192_CBC, "AES"); - BASE_CIPHER_NAMES.put(CMSEnvelopedGenerator.AES256_CBC, "AES"); - - CIPHER_ALG_NAMES.put(CMSEnvelopedGenerator.DES_EDE3_CBC, "DESEDE/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(CMSEnvelopedGenerator.AES128_CBC, "AES/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(CMSEnvelopedGenerator.AES192_CBC, "AES/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(CMSEnvelopedGenerator.AES256_CBC, "AES/CBC/PKCS5Padding"); - - MAC_ALG_NAMES.put(CMSEnvelopedGenerator.DES_EDE3_CBC, "DESEDEMac"); - MAC_ALG_NAMES.put(CMSEnvelopedGenerator.AES128_CBC, "AESMac"); - MAC_ALG_NAMES.put(CMSEnvelopedGenerator.AES192_CBC, "AESMac"); - MAC_ALG_NAMES.put(CMSEnvelopedGenerator.AES256_CBC, "AESMac"); - } - - - - int getKeySize(String oid) - { - Integer keySize = (Integer)KEYSIZES.get(oid); - - if (keySize == null) - { - throw new IllegalArgumentException("no keysize for " + oid); - } - - return keySize.intValue(); - } - - - - static RecipientInformationStore buildRecipientInformationStore( - ASN1Set recipientInfos, AlgorithmIdentifier messageAlgorithm, CMSSecureReadable secureReadable) - { - return buildRecipientInformationStore(recipientInfos, messageAlgorithm, secureReadable, null); - } - - static RecipientInformationStore buildRecipientInformationStore( - ASN1Set recipientInfos, AlgorithmIdentifier messageAlgorithm, CMSSecureReadable secureReadable, AuthAttributesProvider additionalData) - { - List infos = new ArrayList(); - for (int i = 0; i != recipientInfos.size(); i++) - { - RecipientInfo info = RecipientInfo.getInstance(recipientInfos.getObjectAt(i)); - - readRecipientInfo(infos, info, messageAlgorithm, secureReadable, additionalData); - } - return new RecipientInformationStore(infos); - } - - private static void readRecipientInfo( - List infos, RecipientInfo info, AlgorithmIdentifier messageAlgorithm, CMSSecureReadable secureReadable, AuthAttributesProvider additionalData) - { - ASN1Encodable recipInfo = info.getInfo(); - if (recipInfo instanceof KeyTransRecipientInfo) - { - infos.add(new KeyTransRecipientInformation( - (KeyTransRecipientInfo)recipInfo, messageAlgorithm, secureReadable, additionalData)); - } - else if (recipInfo instanceof KEKRecipientInfo) - { - infos.add(new KEKRecipientInformation( - (KEKRecipientInfo)recipInfo, messageAlgorithm, secureReadable, additionalData)); - } - else if (recipInfo instanceof KeyAgreeRecipientInfo) - { - KeyAgreeRecipientInformation.readRecipientInfo(infos, - (KeyAgreeRecipientInfo)recipInfo, messageAlgorithm, secureReadable, additionalData); - } - else if (recipInfo instanceof PasswordRecipientInfo) - { - infos.add(new PasswordRecipientInformation( - (PasswordRecipientInfo)recipInfo, messageAlgorithm, secureReadable, additionalData)); - } - } - - static class CMSDigestAuthenticatedSecureReadable - implements CMSSecureReadable - { - private DigestCalculator digestCalculator; - private CMSReadable readable; - - public CMSDigestAuthenticatedSecureReadable(DigestCalculator digestCalculator, CMSReadable readable) - { - this.digestCalculator = digestCalculator; - this.readable = readable; - } - - public InputStream getInputStream() - throws IOException, CMSException - { - return new FilterInputStream(readable.getInputStream()) - { - public int read() - throws IOException - { - int b = in.read(); - - if (b >= 0) - { - digestCalculator.getOutputStream().write(b); - } - - return b; - } - - public int read(byte[] inBuf, int inOff, int inLen) - throws IOException - { - int n = in.read(inBuf, inOff, inLen); - - if (n >= 0) - { - digestCalculator.getOutputStream().write(inBuf, inOff, n); - } - - return n; - } - }; - } - - public byte[] getDigest() - { - return digestCalculator.getDigest(); - } - } - - static class CMSAuthenticatedSecureReadable implements CMSSecureReadable - { - private AlgorithmIdentifier algorithm; - private CMSReadable readable; - - CMSAuthenticatedSecureReadable(AlgorithmIdentifier algorithm, CMSReadable readable) - { - this.algorithm = algorithm; - this.readable = readable; - } - - public InputStream getInputStream() - throws IOException, CMSException - { - return readable.getInputStream(); - } - - } - - static class CMSEnvelopedSecureReadable implements CMSSecureReadable - { - private AlgorithmIdentifier algorithm; - private CMSReadable readable; - - CMSEnvelopedSecureReadable(AlgorithmIdentifier algorithm, CMSReadable readable) - { - this.algorithm = algorithm; - this.readable = readable; - } - - public InputStream getInputStream() - throws IOException, CMSException - { - return readable.getInputStream(); - } - - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSException.java b/pkix/src/main/java/org/bouncycastle/cms/CMSException.java deleted file mode 100644 index 04bbd69c..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSException.java +++ /dev/null @@ -1,32 +0,0 @@ -package 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/pkix/src/main/java/org/bouncycastle/cms/CMSProcessable.java b/pkix/src/main/java/org/bouncycastle/cms/CMSProcessable.java deleted file mode 100644 index 9f34b9a1..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSProcessable.java +++ /dev/null @@ -1,21 +0,0 @@ -package 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/pkix/src/main/java/org/bouncycastle/cms/CMSProcessableByteArray.java b/pkix/src/main/java/org/bouncycastle/cms/CMSProcessableByteArray.java deleted file mode 100644 index 1c79a941..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSProcessableByteArray.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; -import 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/pkix/src/main/java/org/bouncycastle/cms/CMSProcessableFile.java b/pkix/src/main/java/org/bouncycastle/cms/CMSProcessableFile.java deleted file mode 100644 index b1e45277..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSProcessableFile.java +++ /dev/null @@ -1,80 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; - -/** - * a holding class for a file of data to be processed. - */ -public class CMSProcessableFile - implements CMSTypedData, CMSReadable -{ - private static final int DEFAULT_BUF_SIZE = 32 * 1024; - - private final ASN1ObjectIdentifier type; - private final File file; - private final byte[] buf; - - public CMSProcessableFile( - File file) - { - this(file, DEFAULT_BUF_SIZE); - } - - public CMSProcessableFile( - File file, - int bufSize) - { - this(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()), file, bufSize); - } - - public CMSProcessableFile( - ASN1ObjectIdentifier type, - File file, - int bufSize) - { - this.type = type; - this.file = file; - buf = new byte[bufSize]; - } - - public InputStream getInputStream() - throws IOException, CMSException - { - return new BufferedInputStream(new FileInputStream(file), DEFAULT_BUF_SIZE); - } - - public void write(OutputStream zOut) - throws IOException, CMSException - { - FileInputStream fIn = new FileInputStream(file); - int len; - - while ((len = fIn.read(buf, 0, buf.length)) > 0) - { - zOut.write(buf, 0, len); - } - - fIn.close(); - } - - /** - * Return the file handle. - */ - public Object getContent() - { - return file; - } - - public ASN1ObjectIdentifier getContentType() - { - return type; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSProcessableInputStream.java b/pkix/src/main/java/org/bouncycastle/cms/CMSProcessableInputStream.java deleted file mode 100644 index a73e2329..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSProcessableInputStream.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import org.bouncycastle.util.io.Streams; - -class CMSProcessableInputStream implements CMSProcessable, CMSReadable -{ - private InputStream input; - private boolean used = false; - - public CMSProcessableInputStream( - InputStream input) - { - this.input = input; - } - - public InputStream getInputStream() - { - checkSingleUsage(); - - return input; - } - - public void write(OutputStream zOut) - throws IOException, CMSException - { - checkSingleUsage(); - - Streams.pipeAll(input, zOut); - input.close(); - } - - public Object getContent() - { - return getInputStream(); - } - - private synchronized void checkSingleUsage() - { - if (used) - { - throw new IllegalStateException("CMSProcessableInputStream can only be used once"); - } - - used = true; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSReadable.java b/pkix/src/main/java/org/bouncycastle/cms/CMSReadable.java deleted file mode 100644 index ca867666..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSReadable.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.IOException; -import java.io.InputStream; - -interface CMSReadable -{ - public InputStream getInputStream() - throws IOException, CMSException; -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSRuntimeException.java b/pkix/src/main/java/org/bouncycastle/cms/CMSRuntimeException.java deleted file mode 100644 index d9f8acc0..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSRuntimeException.java +++ /dev/null @@ -1,32 +0,0 @@ -package 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/pkix/src/main/java/org/bouncycastle/cms/CMSSecureReadable.java b/pkix/src/main/java/org/bouncycastle/cms/CMSSecureReadable.java deleted file mode 100644 index 620d1236..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSSecureReadable.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.IOException; -import java.io.InputStream; - -interface CMSSecureReadable -{ - InputStream getInputStream() - throws IOException, CMSException; -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSSignatureAlgorithmNameGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSSignatureAlgorithmNameGenerator.java deleted file mode 100644 index 59d6ce8b..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSSignatureAlgorithmNameGenerator.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.bouncycastle.cms; - -import 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/pkix/src/main/java/org/bouncycastle/cms/CMSSignatureEncryptionAlgorithmFinder.java b/pkix/src/main/java/org/bouncycastle/cms/CMSSignatureEncryptionAlgorithmFinder.java deleted file mode 100644 index b1cd91fd..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSSignatureEncryptionAlgorithmFinder.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.bouncycastle.cms; - -import 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/pkix/src/main/java/org/bouncycastle/cms/CMSSignedData.java b/pkix/src/main/java/org/bouncycastle/cms/CMSSignedData.java deleted file mode 100644 index a17d7909..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSSignedData.java +++ /dev/null @@ -1,543 +0,0 @@ -package 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.Iterator; -import java.util.List; -import java.util.Map; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.BERSequence; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.cms.SignedData; -import org.bouncycastle.asn1.cms.SignerInfo; -import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.operator.SignatureAlgorithmIdentifierFinder; -import 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 -{ - 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. - // - if (signedData.getEncapContentInfo().getContent() != null) - { - this.signedContent = new CMSProcessableByteArray(signedData.getEncapContentInfo().getContentType(), - ((ASN1OctetString)(signedData.getEncapContentInfo() - .getContent())).getOctets()); - } - 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(); - SignatureAlgorithmIdentifierFinder sigAlgFinder = new DefaultSignatureAlgorithmIdentifierFinder(); - - 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 any X.509 certificate objects in this SignedData structure as a Store of X509CertificateHolder objects. - * - * @return a Store of X509CertificateHolder objects. - */ - public Store 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 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 getAttributeCertificates() - { - return HELPER.getAttributeCertificates(signedData.getCertificates()); - } - - /** - * 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()); - } - - /** - * 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(); - } - - /** - * 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();) - { - SignerInformation counterSigner = (SignerInformation)cIt.next(); - SignerInformationVerifier counterVerifier = verifierProvider.get(signer.getSID()); - - if (!counterSigner.verify(counterVerifier)) - { - return false; - } - } - } - } - catch (OperatorCreationException e) - { - throw new CMSException("failure in verifier provider: " + e.getMessage(), e); - } - } - - return true; - } - - /** - * 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/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataGenerator.java deleted file mode 100644 index 5417ce4d..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataGenerator.java +++ /dev/null @@ -1,232 +0,0 @@ -package 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 org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.BEROctetString; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.cms.SignedData; -import 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/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataParser.java b/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataParser.java deleted file mode 100644 index 329f089b..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataParser.java +++ /dev/null @@ -1,624 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Generator; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetStringParser; -import org.bouncycastle.asn1.ASN1SequenceParser; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.ASN1SetParser; -import org.bouncycastle.asn1.ASN1StreamParser; -import org.bouncycastle.asn1.BERSequenceGenerator; -import org.bouncycastle.asn1.BERSetParser; -import org.bouncycastle.asn1.BERTaggedObject; -import org.bouncycastle.asn1.BERTags; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.DERTaggedObject; -import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; -import org.bouncycastle.asn1.cms.ContentInfoParser; -import org.bouncycastle.asn1.cms.SignedDataParser; -import org.bouncycastle.asn1.cms.SignerInfo; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.operator.DigestCalculator; -import org.bouncycastle.operator.DigestCalculatorProvider; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.util.Store; -import org.bouncycastle.util.io.Streams; - -/** - * Parsing class for an CMS Signed Data object from an input stream. - * <p> - * Note: that because we are in a streaming mode only one signer can be tried and it is important - * that the methods on the parser are called in the appropriate order. - * </p> - * <p> - * A simple example of usage for an encapsulated signature. - * </p> - * <p> - * Two notes: first, in the example below the validity of - * the certificate isn't verified, just the fact that one of the certs - * matches the given signer, and, second, because we are in a streaming - * mode the order of the operations is important. - * </p> - * <pre> - * CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build(), encapSigData); - * - * sp.getSignedContent().drain(); - * - * Store certStore = sp.getCertificates(); - * SignerInformationStore signers = sp.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(); - * - * System.out.println("verify returns: " + signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert))); - * } - * </pre> - * Note also: this class does not introduce buffering - if you are processing large files you should create - * the parser with: - * <pre> - * CMSSignedDataParser ep = new CMSSignedDataParser(new BufferedInputStream(encapSigData, bufSize)); - * </pre> - * where bufSize is a suitably large buffer size. - */ -public class CMSSignedDataParser - extends CMSContentInfoParser -{ - private static final CMSSignedHelper HELPER = CMSSignedHelper.INSTANCE; - - private SignedDataParser _signedData; - private ASN1ObjectIdentifier _signedContentType; - private CMSTypedStream _signedContent; - private Map digests; - - private SignerInformationStore _signerInfoStore; - private ASN1Set _certSet, _crlSet; - private boolean _isCertCrlParsed; - - public CMSSignedDataParser( - DigestCalculatorProvider digestCalculatorProvider, - byte[] sigBlock) - throws CMSException - { - this(digestCalculatorProvider, new ByteArrayInputStream(sigBlock)); - } - - public CMSSignedDataParser( - DigestCalculatorProvider digestCalculatorProvider, - CMSTypedStream signedContent, - byte[] sigBlock) - throws CMSException - { - this(digestCalculatorProvider, signedContent, new ByteArrayInputStream(sigBlock)); - } - - /** - * base constructor - with encapsulated content - */ - public CMSSignedDataParser( - DigestCalculatorProvider digestCalculatorProvider, - InputStream sigData) - throws CMSException - { - this(digestCalculatorProvider, null, sigData); - } - - /** - * base constructor - * - * @param digestCalculatorProvider for generating accumulating digests - * @param signedContent the content that was signed. - * @param sigData the signature object stream. - */ - public CMSSignedDataParser( - DigestCalculatorProvider digestCalculatorProvider, - CMSTypedStream signedContent, - InputStream sigData) - throws CMSException - { - super(sigData); - - try - { - _signedContent = signedContent; - _signedData = SignedDataParser.getInstance(_contentInfo.getContent(BERTags.SEQUENCE)); - digests = new HashMap(); - - ASN1SetParser digAlgs = _signedData.getDigestAlgorithms(); - ASN1Encodable o; - - while ((o = digAlgs.readObject()) != null) - { - AlgorithmIdentifier algId = AlgorithmIdentifier.getInstance(o); - try - { - DigestCalculator calculator = digestCalculatorProvider.get(algId); - - if (calculator != null) - { - this.digests.put(algId.getAlgorithm(), calculator); - } - } - catch (OperatorCreationException e) - { - // ignore - } - } - - // - // If the message is simply a certificate chain message getContent() may return null. - // - ContentInfoParser cont = _signedData.getEncapContentInfo(); - ASN1OctetStringParser octs = (ASN1OctetStringParser) - cont.getContent(BERTags.OCTET_STRING); - - if (octs != null) - { - CMSTypedStream ctStr = new CMSTypedStream( - cont.getContentType().getId(), octs.getOctetStream()); - - if (_signedContent == null) - { - _signedContent = ctStr; - } - else - { - // - // content passed in, need to read past empty encapsulated content info object if present - // - ctStr.drain(); - } - } - - if (signedContent == null) - { - _signedContentType = cont.getContentType(); - } - else - { - _signedContentType = _signedContent.getContentType(); - } - } - catch (IOException e) - { - throw new CMSException("io exception: " + e.getMessage(), e); - } - } - - /** - * Return the version number for the SignedData object - * - * @return the version number - */ - public int getVersion() - { - return _signedData.getVersion().getValue().intValue(); - } - - /** - * return the collection of signers that are associated with the - * signatures for the message. - * @throws CMSException - */ - public SignerInformationStore getSignerInfos() - throws CMSException - { - if (_signerInfoStore == null) - { - populateCertCrlSets(); - - List signerInfos = new ArrayList(); - Map hashes = new HashMap(); - - Iterator it = digests.keySet().iterator(); - while (it.hasNext()) - { - Object digestKey = it.next(); - - hashes.put(digestKey, ((DigestCalculator)digests.get(digestKey)).getDigest()); - } - - try - { - ASN1SetParser s = _signedData.getSignerInfos(); - ASN1Encodable o; - - while ((o = s.readObject()) != null) - { - SignerInfo info = SignerInfo.getInstance(o.toASN1Primitive()); - - byte[] hash = (byte[])hashes.get(info.getDigestAlgorithm().getAlgorithm()); - - signerInfos.add(new SignerInformation(info, _signedContentType, null, hash)); - } - } - catch (IOException e) - { - throw new CMSException("io exception: " + e.getMessage(), e); - } - - _signerInfoStore = new SignerInformationStore(signerInfos); - } - - return _signerInfoStore; - } - - /** - * Return any X.509 certificate objects in this SignedData structure as a Store of X509CertificateHolder objects. - * - * @return a Store of X509CertificateHolder objects. - */ - public Store getCertificates() - throws CMSException - { - populateCertCrlSets(); - - return HELPER.getCertificates(_certSet); - } - - /** - * Return any X.509 CRL objects in this SignedData structure as a Store of X509CRLHolder objects. - * - * @return a Store of X509CRLHolder objects. - */ - public Store getCRLs() - throws CMSException - { - populateCertCrlSets(); - - return HELPER.getCRLs(_crlSet); - } - - /** - * 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 getAttributeCertificates() - throws CMSException - { - populateCertCrlSets(); - - return HELPER.getAttributeCertificates(_certSet); - } - - /** - * 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) - throws CMSException - { - populateCertCrlSets(); - - return HELPER.getOtherRevocationInfo(otherRevocationInfoFormat, _crlSet); - } - - private void populateCertCrlSets() - throws CMSException - { - if (_isCertCrlParsed) - { - return; - } - - _isCertCrlParsed = true; - - try - { - // care! Streaming - these must be done in exactly this order. - _certSet = getASN1Set(_signedData.getCertificates()); - _crlSet = getASN1Set(_signedData.getCrls()); - } - catch (IOException e) - { - throw new CMSException("problem parsing cert/crl sets", e); - } - } - - /** - * 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 _signedContentType.getId(); - } - - public CMSTypedStream getSignedContent() - { - if (_signedContent == null) - { - return null; - } - - InputStream digStream = CMSUtils.attachDigestsToInputStream( - digests.values(), _signedContent.getContentStream()); - - return new CMSTypedStream(_signedContent.getContentType(), digStream); - } - - /** - * Replace the signerinformation store associated with the passed - * in message contained in the stream original 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. - * <p> - * The output stream is returned unclosed. - * </p> - * @param original the signed data stream to be used as a base. - * @param signerInformationStore the new signer information store to use. - * @param out the stream to write the new signed data object to. - * @return out. - */ - public static OutputStream replaceSigners( - InputStream original, - SignerInformationStore signerInformationStore, - OutputStream out) - throws CMSException, IOException - { - ASN1StreamParser in = new ASN1StreamParser(original); - ContentInfoParser contentInfo = new ContentInfoParser((ASN1SequenceParser)in.readObject()); - SignedDataParser signedData = SignedDataParser.getInstance(contentInfo.getContent(BERTags.SEQUENCE)); - - BERSequenceGenerator sGen = new BERSequenceGenerator(out); - - sGen.addObject(CMSObjectIdentifiers.signedData); - - BERSequenceGenerator sigGen = new BERSequenceGenerator(sGen.getRawOutputStream(), 0, true); - - // version number - sigGen.addObject(signedData.getVersion()); - - // digests - signedData.getDigestAlgorithms().toASN1Primitive(); // skip old ones - - ASN1EncodableVector digestAlgs = new ASN1EncodableVector(); - - for (Iterator it = signerInformationStore.getSigners().iterator(); it.hasNext();) - { - SignerInformation signer = (SignerInformation)it.next(); - digestAlgs.add(CMSSignedHelper.INSTANCE.fixAlgID(signer.getDigestAlgorithmID())); - } - - sigGen.getRawOutputStream().write(new DERSet(digestAlgs).getEncoded()); - - // encap content info - ContentInfoParser encapContentInfo = signedData.getEncapContentInfo(); - - BERSequenceGenerator eiGen = new BERSequenceGenerator(sigGen.getRawOutputStream()); - - eiGen.addObject(encapContentInfo.getContentType()); - - pipeEncapsulatedOctetString(encapContentInfo, eiGen.getRawOutputStream()); - - eiGen.close(); - - - writeSetToGeneratorTagged(sigGen, signedData.getCertificates(), 0); - writeSetToGeneratorTagged(sigGen, signedData.getCrls(), 1); - - - ASN1EncodableVector signerInfos = new ASN1EncodableVector(); - for (Iterator it = signerInformationStore.getSigners().iterator(); it.hasNext();) - { - SignerInformation signer = (SignerInformation)it.next(); - - signerInfos.add(signer.toASN1Structure()); - } - - sigGen.getRawOutputStream().write(new DERSet(signerInfos).getEncoded()); - - sigGen.close(); - - sGen.close(); - - return out; - } - - /** - * Replace the certificate and CRL information associated with this - * CMSSignedData object with the new one passed in. - * <p> - * The output stream is returned unclosed. - * </p> - * @param original the signed data stream to be used as a base. - * @param certs new certificates to be used, if any. - * @param crls new CRLs to be used, if any. - * @param attrCerts new attribute certificates to be used, if any. - * @param out the stream to write the new signed data object to. - * @return out. - * @exception CMSException if there is an error processing the CertStore - */ - public static OutputStream replaceCertificatesAndCRLs( - InputStream original, - Store certs, - Store crls, - Store attrCerts, - OutputStream out) - throws CMSException, IOException - { - ASN1StreamParser in = new ASN1StreamParser(original); - ContentInfoParser contentInfo = new ContentInfoParser((ASN1SequenceParser)in.readObject()); - SignedDataParser signedData = SignedDataParser.getInstance(contentInfo.getContent(BERTags.SEQUENCE)); - - BERSequenceGenerator sGen = new BERSequenceGenerator(out); - - sGen.addObject(CMSObjectIdentifiers.signedData); - - BERSequenceGenerator sigGen = new BERSequenceGenerator(sGen.getRawOutputStream(), 0, true); - - // version number - sigGen.addObject(signedData.getVersion()); - - // digests - sigGen.getRawOutputStream().write(signedData.getDigestAlgorithms().toASN1Primitive().getEncoded()); - - // encap content info - ContentInfoParser encapContentInfo = signedData.getEncapContentInfo(); - - BERSequenceGenerator eiGen = new BERSequenceGenerator(sigGen.getRawOutputStream()); - - eiGen.addObject(encapContentInfo.getContentType()); - - pipeEncapsulatedOctetString(encapContentInfo, eiGen.getRawOutputStream()); - - eiGen.close(); - - // - // skip existing certs and CRLs - // - getASN1Set(signedData.getCertificates()); - getASN1Set(signedData.getCrls()); - - // - // replace the certs and crls in the SignedData object - // - if (certs != null || attrCerts != null) - { - List certificates = new ArrayList(); - - if (certs != null) - { - certificates.addAll(CMSUtils.getCertificatesFromStore(certs)); - } - if (attrCerts != null) - { - certificates.addAll(CMSUtils.getAttributeCertificatesFromStore(attrCerts)); - } - - ASN1Set asn1Certs = CMSUtils.createBerSetFromList(certificates); - - if (asn1Certs.size() > 0) - { - sigGen.getRawOutputStream().write(new DERTaggedObject(false, 0, asn1Certs).getEncoded()); - } - } - - if (crls != null) - { - ASN1Set asn1Crls = CMSUtils.createBerSetFromList(CMSUtils.getCRLsFromStore(crls)); - - if (asn1Crls.size() > 0) - { - sigGen.getRawOutputStream().write(new DERTaggedObject(false, 1, asn1Crls).getEncoded()); - } - } - - sigGen.getRawOutputStream().write(signedData.getSignerInfos().toASN1Primitive().getEncoded()); - - sigGen.close(); - - sGen.close(); - - return out; - } - - private static void writeSetToGeneratorTagged( - ASN1Generator asn1Gen, - ASN1SetParser asn1SetParser, - int tagNo) - throws IOException - { - ASN1Set asn1Set = getASN1Set(asn1SetParser); - - if (asn1Set != null) - { - if (asn1SetParser instanceof BERSetParser) - { - asn1Gen.getRawOutputStream().write(new BERTaggedObject(false, tagNo, asn1Set).getEncoded()); - } - else - { - asn1Gen.getRawOutputStream().write(new DERTaggedObject(false, tagNo, asn1Set).getEncoded()); - } - } - } - - private static ASN1Set getASN1Set( - ASN1SetParser asn1SetParser) - { - return asn1SetParser == null - ? null - : ASN1Set.getInstance(asn1SetParser.toASN1Primitive()); - } - - private static void pipeEncapsulatedOctetString(ContentInfoParser encapContentInfo, - OutputStream rawOutputStream) throws IOException - { - ASN1OctetStringParser octs = (ASN1OctetStringParser) - encapContentInfo.getContent(BERTags.OCTET_STRING); - - if (octs != null) - { - pipeOctetString(octs, rawOutputStream); - } - -// BERTaggedObjectParser contentObject = (BERTaggedObjectParser)encapContentInfo.getContentObject(); -// if (contentObject != null) -// { -// // Handle IndefiniteLengthInputStream safely -// InputStream input = ASN1StreamParser.getSafeRawInputStream(contentObject.getContentStream(true)); -// -// // TODO BerTaggedObjectGenerator? -// BEROutputStream berOut = new BEROutputStream(rawOutputStream); -// berOut.write(DERTags.CONSTRUCTED | DERTags.TAGGED | 0); -// berOut.write(0x80); -// -// pipeRawOctetString(input, rawOutputStream); -// -// berOut.write(0x00); -// berOut.write(0x00); -// -// input.close(); -// } - } - - private static void pipeOctetString( - ASN1OctetStringParser octs, - OutputStream output) - throws IOException - { - // TODO Allow specification of a specific fragment size? - OutputStream outOctets = CMSUtils.createBEROctetOutputStream( - output, 0, true, 0); - Streams.pipeAll(octs.getOctetStream(), outOctets); - outOctets.close(); - } - -// private static void pipeRawOctetString( -// InputStream rawInput, -// OutputStream rawOutput) -// throws IOException -// { -// InputStream tee = new TeeInputStream(rawInput, rawOutput); -// ASN1StreamParser sp = new ASN1StreamParser(tee); -// ASN1OctetStringParser octs = (ASN1OctetStringParser)sp.readObject(); -// Streams.drain(octs.getOctetStream()); -// } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataStreamGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataStreamGenerator.java deleted file mode 100644 index 1e09b481..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataStreamGenerator.java +++ /dev/null @@ -1,486 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.Iterator; -import java.util.List; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERSequenceGenerator; -import org.bouncycastle.asn1.BERTaggedObject; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; -import org.bouncycastle.asn1.cms.SignerInfo; - -/** - * General class for generating a pkcs7-signature message stream. - * <p> - * A simple example of usage. - * </p> - * <pre> - * X509Certificate signCert = ... - * certList.add(signCert); - * - * Store certs = new JcaCertStore(certList); - * ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(signKP.getPrivate()); - * - * CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator(); - * - * gen.addSignerInfoGenerator( - * new JcaSignerInfoGeneratorBuilder( - * new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()) - * .build(sha1Signer, signCert)); - * - * gen.addCertificates(certs); - * - * OutputStream sigOut = gen.open(bOut); - * - * sigOut.write("Hello World!".getBytes()); - * - * sigOut.close(); - * </pre> - */ -public class CMSSignedDataStreamGenerator - extends CMSSignedGenerator -{ - private int _bufferSize; - - /** - * base constructor - */ - public CMSSignedDataStreamGenerator() - { - } - - /** - * Set the underlying string size for encapsulated data - * - * @param bufferSize length of octet strings to buffer the data. - */ - public void setBufferSize( - int bufferSize) - { - _bufferSize = bufferSize; - } - - /** - * generate a signed object that for a CMS Signed Data - * object using the given provider. - */ - public OutputStream open( - OutputStream out) - throws IOException - { - return open(out, false); - } - - /** - * generate a signed object that for a CMS Signed Data - * object using the given provider - if encapsulate is true a copy - * of the message will be included in the signature with the - * default content type "data". - */ - public OutputStream open( - OutputStream out, - boolean encapsulate) - throws IOException - { - return open(CMSObjectIdentifiers.data, out, encapsulate); - } - - /** - * generate a signed object that for a CMS Signed Data - * object using the given provider - if encapsulate is true a copy - * of the message will be included in the signature with the - * default content type "data". If dataOutputStream is non null the data - * being signed will be written to the stream as it is processed. - * @param out stream the CMS object is to be written to. - * @param encapsulate true if data should be encapsulated. - * @param dataOutputStream output stream to copy the data being signed to. - */ - public OutputStream open( - OutputStream out, - boolean encapsulate, - OutputStream dataOutputStream) - throws IOException - { - return open(CMSObjectIdentifiers.data, out, encapsulate, dataOutputStream); - } - - /** - * generate a signed object that for a CMS Signed Data - * object using the given provider - if encapsulate is true a copy - * of the message will be included in the signature. The content type - * is set according to the OID represented by the string signedContentType. - */ - public OutputStream open( - ASN1ObjectIdentifier eContentType, - OutputStream out, - boolean encapsulate) - throws IOException - { - return open(eContentType, out, encapsulate, null); - } - - /** - * generate a signed object that for a CMS Signed Data - * object using the given provider - if encapsulate is true a copy - * of the message will be included in the signature. The content type - * is set according to the OID represented by the string signedContentType. - * @param eContentType OID for data to be signed. - * @param out stream the CMS object is to be written to. - * @param encapsulate true if data should be encapsulated. - * @param dataOutputStream output stream to copy the data being signed to. - */ - public OutputStream open( - ASN1ObjectIdentifier eContentType, - OutputStream out, - boolean encapsulate, - OutputStream dataOutputStream) - throws IOException - { - // 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 -// } - - // - // ContentInfo - // - BERSequenceGenerator sGen = new BERSequenceGenerator(out); - - sGen.addObject(CMSObjectIdentifiers.signedData); - - // - // Signed Data - // - BERSequenceGenerator sigGen = new BERSequenceGenerator(sGen.getRawOutputStream(), 0, true); - - sigGen.addObject(calculateVersion(eContentType)); - - ASN1EncodableVector digestAlgs = new ASN1EncodableVector(); - - // - // add the precalculated SignerInfo digest algorithms. - // - for (Iterator it = _signers.iterator(); it.hasNext();) - { - SignerInformation signer = (SignerInformation)it.next(); - digestAlgs.add(CMSSignedHelper.INSTANCE.fixAlgID(signer.getDigestAlgorithmID())); - } - - // - // add the new digests - // - - for (Iterator it = signerGens.iterator(); it.hasNext();) - { - SignerInfoGenerator signerGen = (SignerInfoGenerator)it.next(); - - digestAlgs.add(signerGen.getDigestAlgorithm()); - } - - sigGen.getRawOutputStream().write(new DERSet(digestAlgs).getEncoded()); - - BERSequenceGenerator eiGen = new BERSequenceGenerator(sigGen.getRawOutputStream()); - eiGen.addObject(eContentType); - - // If encapsulating, add the data as an octet string in the sequence - OutputStream encapStream = encapsulate - ? CMSUtils.createBEROctetOutputStream(eiGen.getRawOutputStream(), 0, true, _bufferSize) - : null; - - // Also send the data to 'dataOutputStream' if necessary - OutputStream contentStream = CMSUtils.getSafeTeeOutputStream(dataOutputStream, encapStream); - - // Let all the signers see the data as it is written - OutputStream sigStream = CMSUtils.attachSignersToOutputStream(signerGens, contentStream); - - return new CmsSignedDataOutputStream(sigStream, eContentType, sGen, sigGen, eiGen); - } - - // RFC3852, section 5.1: - // IF ((certificates is present) AND - // (any certificates with a type of other are present)) OR - // ((crls is present) AND - // (any crls with a type of other are present)) - // THEN version MUST be 5 - // ELSE - // IF (certificates is present) AND - // (any version 2 attribute certificates are present) - // THEN version MUST be 4 - // ELSE - // IF ((certificates is present) AND - // (any version 1 attribute certificates are present)) OR - // (any SignerInfo structures are version 3) OR - // (encapContentInfo eContentType is other than id-data) - // THEN version MUST be 3 - // ELSE version MUST be 1 - // - private ASN1Integer calculateVersion( - ASN1ObjectIdentifier contentOid) - { - boolean otherCert = false; - boolean otherCrl = false; - boolean attrCertV1Found = false; - boolean attrCertV2Found = false; - - if (certs != null) - { - for (Iterator it = certs.iterator(); it.hasNext();) - { - Object obj = it.next(); - if (obj instanceof ASN1TaggedObject) - { - ASN1TaggedObject tagged = (ASN1TaggedObject)obj; - - if (tagged.getTagNo() == 1) - { - attrCertV1Found = true; - } - else if (tagged.getTagNo() == 2) - { - attrCertV2Found = true; - } - else if (tagged.getTagNo() == 3) - { - otherCert = true; - } - } - } - } - - if (otherCert) - { - return new ASN1Integer(5); - } - - if (crls != null) // no need to check if otherCert is true - { - for (Iterator it = crls.iterator(); it.hasNext();) - { - Object obj = it.next(); - if (obj instanceof ASN1TaggedObject) - { - otherCrl = true; - } - } - } - - if (otherCrl) - { - return new ASN1Integer(5); - } - - if (attrCertV2Found) - { - return new ASN1Integer(4); - } - - if (attrCertV1Found) - { - return new ASN1Integer(3); - } - - if (checkForVersion3(_signers, signerGens)) - { - return new ASN1Integer(3); - } - - if (!CMSObjectIdentifiers.data.equals(contentOid)) - { - return new ASN1Integer(3); - } - - return new ASN1Integer(1); - } - - private boolean checkForVersion3(List signerInfos, List signerInfoGens) - { - for (Iterator it = signerInfos.iterator(); it.hasNext();) - { - SignerInfo s = SignerInfo.getInstance(((SignerInformation)it.next()).toASN1Structure()); - - if (s.getVersion().getValue().intValue() == 3) - { - return true; - } - } - - for (Iterator it = signerInfoGens.iterator(); it.hasNext();) - { - SignerInfoGenerator s = (SignerInfoGenerator)it.next(); - - if (s.getGeneratedVersion() == 3) - { - return true; - } - } - - return false; - } - - private class CmsSignedDataOutputStream - extends OutputStream - { - private OutputStream _out; - private ASN1ObjectIdentifier _contentOID; - private BERSequenceGenerator _sGen; - private BERSequenceGenerator _sigGen; - private BERSequenceGenerator _eiGen; - - public CmsSignedDataOutputStream( - OutputStream out, - ASN1ObjectIdentifier contentOID, - BERSequenceGenerator sGen, - BERSequenceGenerator sigGen, - BERSequenceGenerator eiGen) - { - _out = out; - _contentOID = contentOID; - _sGen = sGen; - _sigGen = sigGen; - _eiGen = eiGen; - } - - public void write( - int b) - throws IOException - { - _out.write(b); - } - - public void write( - byte[] bytes, - int off, - int len) - throws IOException - { - _out.write(bytes, off, len); - } - - public void write( - byte[] bytes) - throws IOException - { - _out.write(bytes); - } - - public void close() - throws IOException - { - _out.close(); - _eiGen.close(); - - digests.clear(); // clear the current preserved digest state - - if (certs.size() != 0) - { - ASN1Set certSet = CMSUtils.createBerSetFromList(certs); - - _sigGen.getRawOutputStream().write(new BERTaggedObject(false, 0, certSet).getEncoded()); - } - - if (crls.size() != 0) - { - ASN1Set crlSet = CMSUtils.createBerSetFromList(crls); - - _sigGen.getRawOutputStream().write(new BERTaggedObject(false, 1, crlSet).getEncoded()); - } - - // - // collect all the SignerInfo objects - // - ASN1EncodableVector signerInfos = new ASN1EncodableVector(); - - // - // add the generated SignerInfo objects - // - - for (Iterator it = signerGens.iterator(); it.hasNext();) - { - SignerInfoGenerator sigGen = (SignerInfoGenerator)it.next(); - - - try - { - signerInfos.add(sigGen.generate(_contentOID)); - - byte[] calculatedDigest = sigGen.getCalculatedDigest(); - - digests.put(sigGen.getDigestAlgorithm().getAlgorithm().getId(), calculatedDigest); - } - catch (CMSException e) - { - throw new CMSStreamException("exception generating signers: " + e.getMessage(), e); - } - } - - // - // add the precalculated SignerInfo objects - // - { - Iterator it = _signers.iterator(); - while (it.hasNext()) - { - SignerInformation signer = (SignerInformation)it.next(); - - // TODO Verify the content type and calculated digest match the precalculated SignerInfo -// if (!signer.getContentType().equals(_contentOID)) -// { -// // TODO The precalculated content type did not match - error? -// } -// -// byte[] calculatedDigest = (byte[])_digests.get(signer.getDigestAlgOID()); -// if (calculatedDigest == null) -// { -// // TODO We can't confirm this digest because we didn't calculate it - error? -// } -// else -// { -// if (!Arrays.areEqual(signer.getContentDigest(), calculatedDigest)) -// { -// // TODO The precalculated digest did not match - error? -// } -// } - - signerInfos.add(signer.toASN1Structure()); - } - } - - _sigGen.getRawOutputStream().write(new DERSet(signerInfos).getEncoded()); - - _sigGen.close(); - _sGen.close(); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSSignedGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSSignedGenerator.java deleted file mode 100644 index 9fe67790..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSSignedGenerator.java +++ /dev/null @@ -1,239 +0,0 @@ -package 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 org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DERTaggedObject; -import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; -import org.bouncycastle.asn1.cms.OtherRevocationInfoFormat; -import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; -import org.bouncycastle.cert.X509AttributeCertificateHolder; -import org.bouncycastle.cert.X509CRLHolder; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.util.Arrays; -import 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(); - 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(); - - 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(); - public static final String ENCRYPTION_GOST3410 = CryptoProObjectIdentifiers.gostR3410_94.getId(); - public static final String ENCRYPTION_ECGOST3410 = CryptoProObjectIdentifiers.gostR3410_2001.getId(); - - 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)); - } - - /** - * 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)); - } - - /** - * 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/pkix/src/main/java/org/bouncycastle/cms/CMSSignedHelper.java b/pkix/src/main/java/org/bouncycastle/cms/CMSSignedHelper.java deleted file mode 100644 index 2f98e69f..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSSignedHelper.java +++ /dev/null @@ -1,253 +0,0 @@ -package org.bouncycastle.cms; - -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.cms.OtherRevocationInfoFormat; -import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; -import org.bouncycastle.asn1.eac.EACObjectIdentifiers; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.AttributeCertificate; -import org.bouncycastle.asn1.x509.Certificate; -import org.bouncycastle.asn1.x509.CertificateList; -import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; -import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; -import org.bouncycastle.cert.X509AttributeCertificateHolder; -import org.bouncycastle.cert.X509CRLHolder; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.util.CollectionStore; -import 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"); - addEntries(OIWObjectIdentifiers.md4WithRSA, "MD4", "RSA"); - addEntries(OIWObjectIdentifiers.md4WithRSAEncryption, "MD4", "RSA"); - addEntries(OIWObjectIdentifiers.md5WithRSA, "MD5", "RSA"); - addEntries(OIWObjectIdentifiers.sha1WithRSA, "SHA1", "RSA"); - addEntries(PKCSObjectIdentifiers.md2WithRSAEncryption, "MD2", "RSA"); - addEntries(PKCSObjectIdentifiers.md4WithRSAEncryption, "MD4", "RSA"); - 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"); - 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"); - 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"); - 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"); - - 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()); - } - - 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()); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSSignerDigestMismatchException.java b/pkix/src/main/java/org/bouncycastle/cms/CMSSignerDigestMismatchException.java deleted file mode 100644 index 0db54bcb..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSSignerDigestMismatchException.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.bouncycastle.cms; - -public class CMSSignerDigestMismatchException - extends CMSException -{ - public CMSSignerDigestMismatchException( - String msg) - { - super(msg); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSStreamException.java b/pkix/src/main/java/org/bouncycastle/cms/CMSStreamException.java deleted file mode 100644 index fff00489..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSStreamException.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.IOException; - -public class CMSStreamException - extends IOException -{ - private final Throwable underlying; - - CMSStreamException(String msg) - { - super(msg); - this.underlying = null; - } - - CMSStreamException(String msg, Throwable underlying) - { - super(msg); - this.underlying = underlying; - } - - public Throwable getCause() - { - return underlying; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSTypedData.java b/pkix/src/main/java/org/bouncycastle/cms/CMSTypedData.java deleted file mode 100644 index f7f0a9cd..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSTypedData.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.bouncycastle.cms; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; - -public interface CMSTypedData - extends CMSProcessable -{ - ASN1ObjectIdentifier getContentType(); -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSTypedStream.java b/pkix/src/main/java/org/bouncycastle/cms/CMSTypedStream.java deleted file mode 100644 index eda3bde3..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSTypedStream.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.BufferedInputStream; -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.util.io.Streams; - -public class CMSTypedStream -{ - private static final int BUF_SIZ = 32 * 1024; - - private final ASN1ObjectIdentifier _oid; - private final InputStream _in; - - public CMSTypedStream( - InputStream in) - { - this(PKCSObjectIdentifiers.data.getId(), in, BUF_SIZ); - } - - public CMSTypedStream( - String oid, - InputStream in) - { - this(new ASN1ObjectIdentifier(oid), in, BUF_SIZ); - } - - public CMSTypedStream( - String oid, - InputStream in, - int bufSize) - { - this(new ASN1ObjectIdentifier(oid), in, bufSize); - } - - public CMSTypedStream( - ASN1ObjectIdentifier oid, - InputStream in) - { - this(oid, in, BUF_SIZ); - } - - public CMSTypedStream( - ASN1ObjectIdentifier oid, - InputStream in, - int bufSize) - { - _oid = oid; - _in = new FullReaderStream(new BufferedInputStream(in, bufSize)); - } - - public ASN1ObjectIdentifier getContentType() - { - return _oid; - } - - public InputStream getContentStream() - { - return _in; - } - - public void drain() - throws IOException - { - Streams.drain(_in); - _in.close(); - } - - private static class FullReaderStream extends FilterInputStream - { - FullReaderStream(InputStream in) - { - super(in); - } - - public int read(byte[] buf, int off, int len) throws IOException - { - int totalRead = Streams.readFully(super.in, buf, off, len); - return totalRead > 0 ? totalRead : -1; - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSUtils.java b/pkix/src/main/java/org/bouncycastle/cms/CMSUtils.java deleted file mode 100644 index 41f2c001..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSUtils.java +++ /dev/null @@ -1,335 +0,0 @@ -package 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.Iterator; -import java.util.List; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BEROctetStringGenerator; -import org.bouncycastle.asn1.BERSet; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.DERTaggedObject; -import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.cms.OtherRevocationInfoFormat; -import org.bouncycastle.asn1.ocsp.OCSPResponse; -import org.bouncycastle.asn1.ocsp.OCSPResponseStatus; -import org.bouncycastle.cert.X509AttributeCertificateHolder; -import org.bouncycastle.cert.X509CRLHolder; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.operator.DigestCalculator; -import org.bouncycastle.util.Store; -import org.bouncycastle.util.Strings; -import org.bouncycastle.util.io.Streams; -import org.bouncycastle.util.io.TeeInputStream; -import org.bouncycastle.util.io.TeeOutputStream; - -class CMSUtils -{ - 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()); - } - else if (rev instanceof OtherRevocationInfoFormat) - { - OtherRevocationInfoFormat infoFormat = OtherRevocationInfoFormat.getInstance(rev); - - validateInfoFormat(infoFormat); - - crls.add(new DERTaggedObject(false, 1, infoFormat)); - } - else if (rev instanceof ASN1TaggedObject) - { - crls.add(rev); - } - } - - return crls; - } - catch (ClassCastException e) - { - throw new CMSException("error processing certs", e); - } - } - - 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; - } - - 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 - { - return ContentInfo.getInstance(in.readObject()); - } - 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); - } - } - - static byte[] getPasswordBytes(int scheme, char[] password) - { - if (scheme == PasswordRecipient.PKCS5_SCHEME2) - { - return PKCS5PasswordToBytes(password); - } - - return PKCS5PasswordToUTF8Bytes(password); - } - - /** - * converts a password to a byte array according to the scheme in - * PKCS5 (ascii, no padding) - * - * @param password a character array representing the password. - * @return a byte array representing the password. - */ - private static byte[] PKCS5PasswordToBytes( - char[] password) - { - if (password != null) - { - byte[] bytes = new byte[password.length]; - - for (int i = 0; i != bytes.length; i++) - { - bytes[i] = (byte)password[i]; - } - - return bytes; - } - else - { - return new byte[0]; - } - } - - /** - * converts a password to a byte array according to the scheme in - * PKCS5 (UTF-8, no padding) - * - * @param password a character array representing the password. - * @return a byte array representing the password. - */ - private static byte[] PKCS5PasswordToUTF8Bytes( - char[] password) - { - if (password != null) - { - return Strings.toUTF8ByteArray(password); - } - else - { - return new byte[0]; - } - } - - 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/pkix/src/main/java/org/bouncycastle/cms/CMSVerifierCertificateNotValidException.java b/pkix/src/main/java/org/bouncycastle/cms/CMSVerifierCertificateNotValidException.java deleted file mode 100644 index 6bd8c0ac..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSVerifierCertificateNotValidException.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.bouncycastle.cms; - -public class CMSVerifierCertificateNotValidException - extends CMSException -{ - public CMSVerifierCertificateNotValidException( - String msg) - { - super(msg); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/DefaultAuthenticatedAttributeTableGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/DefaultAuthenticatedAttributeTableGenerator.java deleted file mode 100644 index fb37b4d8..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/DefaultAuthenticatedAttributeTableGenerator.java +++ /dev/null @@ -1,99 +0,0 @@ -package org.bouncycastle.cms; - -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Map; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.cms.Attribute; -import org.bouncycastle.asn1.cms.AttributeTable; -import org.bouncycastle.asn1.cms.CMSAttributes; - -/** - * Default authenticated attributes generator. - */ -public class DefaultAuthenticatedAttributeTableGenerator - implements CMSAttributeTableGenerator -{ - private final Hashtable table; - - /** - * Initialise to use all defaults - */ - public DefaultAuthenticatedAttributeTableGenerator() - { - table = new Hashtable(); - } - - /** - * Initialise with some extra attributes or overrides. - * - * @param attributeTable initial attribute table to use. - */ - public DefaultAuthenticatedAttributeTableGenerator( - 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 and messageDigest. If the constructor - * using an AttributeTable was used, entries in it for contentType 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 = new Hashtable(); - - for (Enumeration en = table.keys(); en.hasMoreElements();) - { - Object key = en.nextElement(); - - std.put(key, table.get(key)); - } - - if (!std.containsKey(CMSAttributes.contentType)) - { - ASN1ObjectIdentifier contentType = ASN1ObjectIdentifier.getInstance( - parameters.get(CMSAttributeTableGenerator.CONTENT_TYPE)); - Attribute attr = new Attribute(CMSAttributes.contentType, - new DERSet(contentType)); - 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); - } - - return std; - } - - /** - * @param parameters source parameters - * @return the populated attribute table - */ - public AttributeTable getAttributes(Map parameters) - { - return new AttributeTable(createStandardAttributeTable(parameters)); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java deleted file mode 100644 index 4a94a1f9..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java +++ /dev/null @@ -1,161 +0,0 @@ -package org.bouncycastle.cms; - -import java.util.HashMap; -import java.util.Map; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.bsi.BSIObjectIdentifiers; -import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; -import org.bouncycastle.asn1.eac.EACObjectIdentifiers; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; -import 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"); - addEntries(OIWObjectIdentifiers.md4WithRSA, "MD4", "RSA"); - addEntries(OIWObjectIdentifiers.md4WithRSAEncryption, "MD4", "RSA"); - addEntries(OIWObjectIdentifiers.md5WithRSA, "MD5", "RSA"); - addEntries(OIWObjectIdentifiers.sha1WithRSA, "SHA1", "RSA"); - addEntries(PKCSObjectIdentifiers.md2WithRSAEncryption, "MD2", "RSA"); - addEntries(PKCSObjectIdentifiers.md4WithRSAEncryption, "MD4", "RSA"); - 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"); - 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"); - - 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"); - 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"); - 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"); - 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"); - } - - /** - * 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) - { - return getDigestAlgName(digestAlg.getAlgorithm()) + "with" + getEncryptionAlgName(encryptionAlg.getAlgorithm()); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java b/pkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java deleted file mode 100644 index 7797f79f..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.bouncycastle.cms; - -import java.util.HashSet; -import java.util.Set; - -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -public class DefaultCMSSignatureEncryptionAlgorithmFinder - implements CMSSignatureEncryptionAlgorithmFinder -{ - private static final Set RSA_PKCS1d5 = new HashSet(); - - static - { - RSA_PKCS1d5.add(PKCSObjectIdentifiers.md2WithRSAEncryption); - RSA_PKCS1d5.add(PKCSObjectIdentifiers.md4WithRSAEncryption); - RSA_PKCS1d5.add(PKCSObjectIdentifiers.md5WithRSAEncryption); - RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha1WithRSAEncryption); - RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha224WithRSAEncryption); - RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha256WithRSAEncryption); - RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha384WithRSAEncryption); - RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha512WithRSAEncryption); - RSA_PKCS1d5.add(OIWObjectIdentifiers.md4WithRSAEncryption); - RSA_PKCS1d5.add(OIWObjectIdentifiers.md4WithRSA); - RSA_PKCS1d5.add(OIWObjectIdentifiers.md5WithRSA); - RSA_PKCS1d5.add(OIWObjectIdentifiers.sha1WithRSA); - RSA_PKCS1d5.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128); - RSA_PKCS1d5.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160); - RSA_PKCS1d5.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256); - } - - public AlgorithmIdentifier findEncryptionAlgorithm(AlgorithmIdentifier signatureAlgorithm) - { - // RFC3370 section 3.2 - if (RSA_PKCS1d5.contains(signatureAlgorithm.getAlgorithm())) - { - return new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE); - } - - return signatureAlgorithm; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java deleted file mode 100644 index 837edd85..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java +++ /dev/null @@ -1,121 +0,0 @@ -package org.bouncycastle.cms; - -import java.util.Date; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Map; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.cms.Attribute; -import org.bouncycastle.asn1.cms.AttributeTable; -import org.bouncycastle.asn1.cms.CMSAttributes; -import org.bouncycastle.asn1.cms.Time; - -/** - * 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, and messageDigest. 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); - } - - 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/pkix/src/main/java/org/bouncycastle/cms/KEKRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/KEKRecipient.java deleted file mode 100644 index b9679b3d..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/KEKRecipient.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.bouncycastle.cms; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -public interface KEKRecipient - extends Recipient -{ - RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncAlg, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentKey) - throws CMSException; -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/KEKRecipientId.java b/pkix/src/main/java/org/bouncycastle/cms/KEKRecipientId.java deleted file mode 100644 index daa6c7f4..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/KEKRecipientId.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.bouncycastle.cms; - -import org.bouncycastle.util.Arrays; - -public class KEKRecipientId - extends RecipientId -{ - private byte[] keyIdentifier; - - /** - * Construct a recipient ID with the key identifier of a KEK recipient. - * - * @param keyIdentifier a subjectKeyId - */ - public KEKRecipientId(byte[] keyIdentifier) - { - super(kek); - - this.keyIdentifier = keyIdentifier; - } - - public int hashCode() - { - return Arrays.hashCode(keyIdentifier); - } - - public boolean equals( - Object o) - { - if (!(o instanceof KEKRecipientId)) - { - return false; - } - - KEKRecipientId id = (KEKRecipientId)o; - - return Arrays.areEqual(keyIdentifier, id.keyIdentifier); - } - - public byte[] getKeyIdentifier() - { - return Arrays.clone(keyIdentifier); - } - - public Object clone() - { - return new KEKRecipientId(keyIdentifier); - } - - public boolean match(Object obj) - { - if (obj instanceof byte[]) - { - return Arrays.areEqual(keyIdentifier, (byte[])obj); - } - else if (obj instanceof KEKRecipientInformation) - { - return ((KEKRecipientInformation)obj).getRID().equals(this); - } - - return false; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/KEKRecipientInfoGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/KEKRecipientInfoGenerator.java deleted file mode 100644 index e3bff3ca..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/KEKRecipientInfoGenerator.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.bouncycastle.cms; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.cms.KEKIdentifier; -import org.bouncycastle.asn1.cms.KEKRecipientInfo; -import org.bouncycastle.asn1.cms.RecipientInfo; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.OperatorException; -import org.bouncycastle.operator.SymmetricKeyWrapper; - -public abstract class KEKRecipientInfoGenerator - implements RecipientInfoGenerator -{ - private final KEKIdentifier kekIdentifier; - - protected final SymmetricKeyWrapper wrapper; - - protected KEKRecipientInfoGenerator(KEKIdentifier kekIdentifier, SymmetricKeyWrapper wrapper) - { - this.kekIdentifier = kekIdentifier; - this.wrapper = wrapper; - } - - public final RecipientInfo generate(GenericKey contentEncryptionKey) - throws CMSException - { - try - { - ASN1OctetString encryptedKey = new DEROctetString(wrapper.generateWrappedKey(contentEncryptionKey)); - - return new RecipientInfo(new KEKRecipientInfo(kekIdentifier, wrapper.getAlgorithmIdentifier(), encryptedKey)); - } - catch (OperatorException e) - { - throw new CMSException("exception wrapping content key: " + e.getMessage(), e); - } - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cms/KEKRecipientInformation.java b/pkix/src/main/java/org/bouncycastle/cms/KEKRecipientInformation.java deleted file mode 100644 index 62c65294..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/KEKRecipientInformation.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.IOException; - -import org.bouncycastle.asn1.cms.KEKIdentifier; -import org.bouncycastle.asn1.cms.KEKRecipientInfo; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -/** - * the RecipientInfo class for a recipient who has been sent a message - * encrypted using a secret key known to the other side. - */ -public class KEKRecipientInformation - extends RecipientInformation -{ - private KEKRecipientInfo info; - - KEKRecipientInformation( - KEKRecipientInfo info, - AlgorithmIdentifier messageAlgorithm, - CMSSecureReadable secureReadable, - AuthAttributesProvider additionalData) - { - super(info.getKeyEncryptionAlgorithm(), messageAlgorithm, secureReadable, additionalData); - - this.info = info; - - KEKIdentifier kekId = info.getKekid(); - - this.rid = new KEKRecipientId(kekId.getKeyIdentifier().getOctets()); - } - - protected RecipientOperator getRecipientOperator(Recipient recipient) - throws CMSException, IOException - { - return ((KEKRecipient)recipient).getRecipientOperator(keyEncAlg, messageAlgorithm, info.getEncryptedKey().getOctets()); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/KeyAgreeRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/KeyAgreeRecipient.java deleted file mode 100644 index 08d83804..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/KeyAgreeRecipient.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.bouncycastle.cms; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; - -public interface KeyAgreeRecipient - extends Recipient -{ - RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncAlg, AlgorithmIdentifier contentEncryptionAlgorithm, SubjectPublicKeyInfo senderPublicKey, ASN1OctetString userKeyingMaterial, byte[] encryptedContentKey) - throws CMSException; - - AlgorithmIdentifier getPrivateKeyAlgorithmIdentifier(); -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/KeyAgreeRecipientId.java b/pkix/src/main/java/org/bouncycastle/cms/KeyAgreeRecipientId.java deleted file mode 100644 index c64c6eab..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/KeyAgreeRecipientId.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.bouncycastle.cms; - -import java.math.BigInteger; - -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.cert.selector.X509CertificateHolderSelector; - -public class KeyAgreeRecipientId - extends RecipientId -{ - private X509CertificateHolderSelector baseSelector; - - private KeyAgreeRecipientId(X509CertificateHolderSelector baseSelector) - { - super(keyAgree); - - this.baseSelector = baseSelector; - } - - /** - * Construct a key agree recipient ID with the value of a public key's subjectKeyId. - * - * @param subjectKeyId a subjectKeyId - */ - public KeyAgreeRecipientId(byte[] subjectKeyId) - { - this(null, null, subjectKeyId); - } - - /** - * Construct a key agree recipient ID based on the issuer and serial number of the recipient's associated - * certificate. - * - * @param issuer the issuer of the recipient's associated certificate. - * @param serialNumber the serial number of the recipient's associated certificate. - */ - public KeyAgreeRecipientId(X500Name issuer, BigInteger serialNumber) - { - this(issuer, serialNumber, null); - } - - public KeyAgreeRecipientId(X500Name issuer, BigInteger serialNumber, byte[] subjectKeyId) - { - this(new X509CertificateHolderSelector(issuer, serialNumber, subjectKeyId)); - } - - 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 KeyAgreeRecipientId)) - { - return false; - } - - KeyAgreeRecipientId id = (KeyAgreeRecipientId)o; - - return this.baseSelector.equals(id.baseSelector); - } - - public Object clone() - { - return new KeyAgreeRecipientId(baseSelector); - } - - public boolean match(Object obj) - { - if (obj instanceof KeyAgreeRecipientInformation) - { - return ((KeyAgreeRecipientInformation)obj).getRID().equals(this); - } - - return baseSelector.match(obj); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/KeyAgreeRecipientInfoGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/KeyAgreeRecipientInfoGenerator.java deleted file mode 100644 index 85f5881d..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/KeyAgreeRecipientInfoGenerator.java +++ /dev/null @@ -1,80 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.IOException; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.cms.KeyAgreeRecipientInfo; -import org.bouncycastle.asn1.cms.OriginatorIdentifierOrKey; -import org.bouncycastle.asn1.cms.OriginatorPublicKey; -import org.bouncycastle.asn1.cms.RecipientInfo; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.operator.GenericKey; - -public abstract class KeyAgreeRecipientInfoGenerator - implements RecipientInfoGenerator -{ - private ASN1ObjectIdentifier keyAgreementOID; - private ASN1ObjectIdentifier keyEncryptionOID; - private SubjectPublicKeyInfo originatorKeyInfo; - - protected KeyAgreeRecipientInfoGenerator(ASN1ObjectIdentifier keyAgreementOID, SubjectPublicKeyInfo originatorKeyInfo, ASN1ObjectIdentifier keyEncryptionOID) - { - this.originatorKeyInfo = originatorKeyInfo; - this.keyAgreementOID = keyAgreementOID; - this.keyEncryptionOID = keyEncryptionOID; - } - - public RecipientInfo generate(GenericKey contentEncryptionKey) - throws CMSException - { - OriginatorIdentifierOrKey originator = new OriginatorIdentifierOrKey( - createOriginatorPublicKey(originatorKeyInfo)); - - ASN1EncodableVector params = new ASN1EncodableVector(); - params.add(keyEncryptionOID); - params.add(DERNull.INSTANCE); - AlgorithmIdentifier keyEncAlg = new AlgorithmIdentifier(keyEncryptionOID, DERNull.INSTANCE); - AlgorithmIdentifier keyAgreeAlg = new AlgorithmIdentifier(keyAgreementOID, keyEncAlg); - - ASN1Sequence recipients = generateRecipientEncryptedKeys(keyAgreeAlg, keyEncAlg, contentEncryptionKey); - ASN1Encodable userKeyingMaterial = getUserKeyingMaterial(keyAgreeAlg); - - if (userKeyingMaterial != null) - { - try - { - return new RecipientInfo(new KeyAgreeRecipientInfo(originator, new DEROctetString(userKeyingMaterial), - keyAgreeAlg, recipients)); - } - catch (IOException e) - { - throw new CMSException("unable to encode userKeyingMaterial: " + e.getMessage(), e); - } - } - else - { - return new RecipientInfo(new KeyAgreeRecipientInfo(originator, null, - keyAgreeAlg, recipients)); - } - } - - protected OriginatorPublicKey createOriginatorPublicKey(SubjectPublicKeyInfo originatorKeyInfo) - { - return new OriginatorPublicKey( - new AlgorithmIdentifier(originatorKeyInfo.getAlgorithm().getAlgorithm(), DERNull.INSTANCE), - originatorKeyInfo.getPublicKeyData().getBytes()); - } - - protected abstract ASN1Sequence generateRecipientEncryptedKeys(AlgorithmIdentifier keyAgreeAlgorithm, AlgorithmIdentifier keyEncAlgorithm, GenericKey contentEncryptionKey) - throws CMSException; - - protected abstract ASN1Encodable getUserKeyingMaterial(AlgorithmIdentifier keyAgreeAlgorithm) - throws CMSException; - -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cms/KeyAgreeRecipientInformation.java b/pkix/src/main/java/org/bouncycastle/cms/KeyAgreeRecipientInformation.java deleted file mode 100644 index 16c26bde..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/KeyAgreeRecipientInformation.java +++ /dev/null @@ -1,131 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.IOException; -import java.util.List; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.cms.IssuerAndSerialNumber; -import org.bouncycastle.asn1.cms.KeyAgreeRecipientIdentifier; -import org.bouncycastle.asn1.cms.KeyAgreeRecipientInfo; -import org.bouncycastle.asn1.cms.OriginatorIdentifierOrKey; -import org.bouncycastle.asn1.cms.OriginatorPublicKey; -import org.bouncycastle.asn1.cms.RecipientEncryptedKey; -import org.bouncycastle.asn1.cms.RecipientKeyIdentifier; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; - -/** - * the RecipientInfo class for a recipient who has been sent a message - * encrypted using key agreement. - */ -public class KeyAgreeRecipientInformation - extends RecipientInformation -{ - private KeyAgreeRecipientInfo info; - private ASN1OctetString encryptedKey; - - static void readRecipientInfo(List infos, KeyAgreeRecipientInfo info, - AlgorithmIdentifier messageAlgorithm, CMSSecureReadable secureReadable, AuthAttributesProvider additionalData) - { - ASN1Sequence s = info.getRecipientEncryptedKeys(); - - for (int i = 0; i < s.size(); ++i) - { - RecipientEncryptedKey id = RecipientEncryptedKey.getInstance( - s.getObjectAt(i)); - - RecipientId rid; - - KeyAgreeRecipientIdentifier karid = id.getIdentifier(); - IssuerAndSerialNumber iAndSN = karid.getIssuerAndSerialNumber(); - - if (iAndSN != null) - { - rid = new KeyAgreeRecipientId(iAndSN.getName(), iAndSN.getSerialNumber().getValue()); - } - else - { - RecipientKeyIdentifier rKeyID = karid.getRKeyID(); - - // Note: 'date' and 'other' fields of RecipientKeyIdentifier appear to be only informational - - rid = new KeyAgreeRecipientId(rKeyID.getSubjectKeyIdentifier().getOctets()); - } - - infos.add(new KeyAgreeRecipientInformation(info, rid, id.getEncryptedKey(), messageAlgorithm, - secureReadable, additionalData)); - } - } - - KeyAgreeRecipientInformation( - KeyAgreeRecipientInfo info, - RecipientId rid, - ASN1OctetString encryptedKey, - AlgorithmIdentifier messageAlgorithm, - CMSSecureReadable secureReadable, - AuthAttributesProvider additionalData) - { - super(info.getKeyEncryptionAlgorithm(), messageAlgorithm, secureReadable, additionalData); - - this.info = info; - this.rid = rid; - this.encryptedKey = encryptedKey; - } - - private SubjectPublicKeyInfo getSenderPublicKeyInfo(AlgorithmIdentifier recKeyAlgId, - OriginatorIdentifierOrKey originator) - throws CMSException, IOException - { - OriginatorPublicKey opk = originator.getOriginatorKey(); - if (opk != null) - { - return getPublicKeyInfoFromOriginatorPublicKey(recKeyAlgId, opk); - } - - OriginatorId origID; - - IssuerAndSerialNumber iAndSN = originator.getIssuerAndSerialNumber(); - if (iAndSN != null) - { - origID = new OriginatorId(iAndSN.getName(), iAndSN.getSerialNumber().getValue()); - } - else - { - SubjectKeyIdentifier ski = originator.getSubjectKeyIdentifier(); - - origID = new OriginatorId(ski.getKeyIdentifier()); - } - - return getPublicKeyInfoFromOriginatorId(origID); - } - - private SubjectPublicKeyInfo getPublicKeyInfoFromOriginatorPublicKey(AlgorithmIdentifier recKeyAlgId, - OriginatorPublicKey originatorPublicKey) - { - SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo( - recKeyAlgId, - originatorPublicKey.getPublicKey().getBytes()); - - return pubInfo; - } - - private SubjectPublicKeyInfo getPublicKeyInfoFromOriginatorId(OriginatorId origID) - throws CMSException - { - // TODO Support all alternatives for OriginatorIdentifierOrKey - // see RFC 3852 6.2.2 - throw new CMSException("No support for 'originator' as IssuerAndSerialNumber or SubjectKeyIdentifier"); - } - - protected RecipientOperator getRecipientOperator(Recipient recipient) - throws CMSException, IOException - { - KeyAgreeRecipient agreeRecipient = (KeyAgreeRecipient)recipient; - AlgorithmIdentifier recKeyAlgId = agreeRecipient.getPrivateKeyAlgorithmIdentifier(); - - return ((KeyAgreeRecipient)recipient).getRecipientOperator(keyEncAlg, messageAlgorithm, getSenderPublicKeyInfo(recKeyAlgId, - info.getOriginator()), info.getUserKeyingMaterial(), encryptedKey.getOctets()); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/KeyTransRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/KeyTransRecipient.java deleted file mode 100644 index b61fbbed..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/KeyTransRecipient.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.bouncycastle.cms; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -public interface KeyTransRecipient - extends Recipient -{ - RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncAlg, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentKey) - throws CMSException; -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/KeyTransRecipientId.java b/pkix/src/main/java/org/bouncycastle/cms/KeyTransRecipientId.java deleted file mode 100644 index f850dcfa..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/KeyTransRecipientId.java +++ /dev/null @@ -1,102 +0,0 @@ -package org.bouncycastle.cms; - -import java.math.BigInteger; - -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.cert.selector.X509CertificateHolderSelector; - -public class KeyTransRecipientId - extends RecipientId -{ - private X509CertificateHolderSelector baseSelector; - - private KeyTransRecipientId(X509CertificateHolderSelector baseSelector) - { - super(keyTrans); - - this.baseSelector = baseSelector; - } - - /** - * Construct a key trans recipient ID with the value of a public key's subjectKeyId. - * - * @param subjectKeyId a subjectKeyId - */ - public KeyTransRecipientId(byte[] subjectKeyId) - { - this(null, null, subjectKeyId); - } - - /** - * Construct a key trans recipient ID based on the issuer and serial number of the recipient's associated - * certificate. - * - * @param issuer the issuer of the recipient's associated certificate. - * @param serialNumber the serial number of the recipient's associated certificate. - */ - public KeyTransRecipientId(X500Name issuer, BigInteger serialNumber) - { - this(issuer, serialNumber, null); - } - - /** - * Construct a key trans recipient ID based on the issuer and serial number of the recipient's associated - * certificate. - * - * @param issuer the issuer of the recipient's associated certificate. - * @param serialNumber the serial number of the recipient's associated certificate. - * @param subjectKeyId the subject key identifier to use to match the recipients associated certificate. - */ - public KeyTransRecipientId(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 KeyTransRecipientId)) - { - return false; - } - - KeyTransRecipientId id = (KeyTransRecipientId)o; - - return this.baseSelector.equals(id.baseSelector); - } - - public Object clone() - { - return new KeyTransRecipientId(this.baseSelector); - } - - public boolean match(Object obj) - { - if (obj instanceof KeyTransRecipientInformation) - { - return ((KeyTransRecipientInformation)obj).getRID().equals(this); - } - - return baseSelector.match(obj); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/KeyTransRecipientInfoGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/KeyTransRecipientInfoGenerator.java deleted file mode 100644 index e576f03f..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/KeyTransRecipientInfoGenerator.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.bouncycastle.cms; - -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.cms.IssuerAndSerialNumber; -import org.bouncycastle.asn1.cms.KeyTransRecipientInfo; -import org.bouncycastle.asn1.cms.RecipientIdentifier; -import org.bouncycastle.asn1.cms.RecipientInfo; -import org.bouncycastle.operator.AsymmetricKeyWrapper; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.OperatorException; - -public abstract class KeyTransRecipientInfoGenerator - implements RecipientInfoGenerator -{ - protected final AsymmetricKeyWrapper wrapper; - - private IssuerAndSerialNumber issuerAndSerial; - private byte[] subjectKeyIdentifier; - - protected KeyTransRecipientInfoGenerator(IssuerAndSerialNumber issuerAndSerial, AsymmetricKeyWrapper wrapper) - { - this.issuerAndSerial = issuerAndSerial; - this.wrapper = wrapper; - } - - protected KeyTransRecipientInfoGenerator(byte[] subjectKeyIdentifier, AsymmetricKeyWrapper wrapper) - { - this.subjectKeyIdentifier = subjectKeyIdentifier; - this.wrapper = wrapper; - } - - public final RecipientInfo generate(GenericKey contentEncryptionKey) - throws CMSException - { - byte[] encryptedKeyBytes; - try - { - encryptedKeyBytes = wrapper.generateWrappedKey(contentEncryptionKey); - } - catch (OperatorException e) - { - throw new CMSException("exception wrapping content key: " + e.getMessage(), e); - } - - RecipientIdentifier recipId; - if (issuerAndSerial != null) - { - recipId = new RecipientIdentifier(issuerAndSerial); - } - else - { - recipId = new RecipientIdentifier(new DEROctetString(subjectKeyIdentifier)); - } - - return new RecipientInfo(new KeyTransRecipientInfo(recipId, wrapper.getAlgorithmIdentifier(), - new DEROctetString(encryptedKeyBytes))); - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cms/KeyTransRecipientInformation.java b/pkix/src/main/java/org/bouncycastle/cms/KeyTransRecipientInformation.java deleted file mode 100644 index d59f4b3e..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/KeyTransRecipientInformation.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.bouncycastle.cms; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.cms.IssuerAndSerialNumber; -import org.bouncycastle.asn1.cms.KeyTransRecipientInfo; -import org.bouncycastle.asn1.cms.RecipientIdentifier; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -/** - * the KeyTransRecipientInformation class for a recipient who has been sent a secret - * key encrypted using their public key that needs to be used to - * extract the message. - */ -public class KeyTransRecipientInformation - extends RecipientInformation -{ - private KeyTransRecipientInfo info; - - KeyTransRecipientInformation( - KeyTransRecipientInfo info, - AlgorithmIdentifier messageAlgorithm, - CMSSecureReadable secureReadable, - AuthAttributesProvider additionalData) - { - super(info.getKeyEncryptionAlgorithm(), messageAlgorithm, secureReadable, additionalData); - - this.info = info; - - RecipientIdentifier r = info.getRecipientIdentifier(); - - if (r.isTagged()) - { - ASN1OctetString octs = ASN1OctetString.getInstance(r.getId()); - - rid = new KeyTransRecipientId(octs.getOctets()); - } - else - { - IssuerAndSerialNumber iAnds = IssuerAndSerialNumber.getInstance(r.getId()); - - rid = new KeyTransRecipientId(iAnds.getName(), iAnds.getSerialNumber().getValue()); - } - } - - protected RecipientOperator getRecipientOperator(Recipient recipient) - throws CMSException - { - return ((KeyTransRecipient)recipient).getRecipientOperator(keyEncAlg, messageAlgorithm, info.getEncryptedKey().getOctets()); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/NullOutputStream.java b/pkix/src/main/java/org/bouncycastle/cms/NullOutputStream.java deleted file mode 100644 index 03c058a5..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/NullOutputStream.java +++ /dev/null @@ -1,28 +0,0 @@ -/** - * - */ -package 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/pkix/src/main/java/org/bouncycastle/cms/OriginatorId.java b/pkix/src/main/java/org/bouncycastle/cms/OriginatorId.java deleted file mode 100644 index ab38105d..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/OriginatorId.java +++ /dev/null @@ -1,118 +0,0 @@ -package org.bouncycastle.cms; - -import java.math.BigInteger; - -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Selector; - -/** - * a basic index for an originator. - */ -class OriginatorId - implements Selector -{ - private byte[] subjectKeyId; - - private X500Name issuer; - private BigInteger serialNumber; - - /** - * Construct a signer ID with the value of a public key's subjectKeyId. - * - * @param subjectKeyId a subjectKeyId - */ - public OriginatorId(byte[] subjectKeyId) - { - setSubjectKeyID(subjectKeyId); - } - - private void setSubjectKeyID(byte[] subjectKeyId) - { - this.subjectKeyId = 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 OriginatorId(X500Name issuer, BigInteger serialNumber) - { - setIssuerAndSerial(issuer, serialNumber); - } - - private void setIssuerAndSerial(X500Name issuer, BigInteger serialNumber) - { - this.issuer = issuer; - this.serialNumber = serialNumber; - } - - /** - * 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 OriginatorId(X500Name issuer, BigInteger serialNumber, byte[] subjectKeyId) - { - setIssuerAndSerial(issuer, serialNumber); - setSubjectKeyID(subjectKeyId); - } - - public X500Name getIssuer() - { - return issuer; - } - - public Object clone() - { - return new OriginatorId(this.issuer, this.serialNumber, this.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 OriginatorId)) - { - return false; - } - - OriginatorId id = (OriginatorId)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) - { - return false; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/OriginatorInfoGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/OriginatorInfoGenerator.java deleted file mode 100644 index 8ea5a920..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/OriginatorInfoGenerator.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.bouncycastle.cms; - -import java.util.ArrayList; -import java.util.List; - -import org.bouncycastle.asn1.cms.OriginatorInfo; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.util.Store; - -public class OriginatorInfoGenerator -{ - private final List origCerts; - private final List origCRLs; - - public OriginatorInfoGenerator(X509CertificateHolder origCert) - { - this.origCerts = new ArrayList(1); - this.origCRLs = null; - origCerts.add(origCert.toASN1Structure()); - } - - public OriginatorInfoGenerator(Store origCerts) - throws CMSException - { - this(origCerts, null); - } - - public OriginatorInfoGenerator(Store origCerts, Store origCRLs) - throws CMSException - { - this.origCerts = CMSUtils.getCertificatesFromStore(origCerts); - - if (origCRLs != null) - { - this.origCRLs = CMSUtils.getCRLsFromStore(origCRLs); - } - else - { - this.origCRLs = null; - } - } - - public OriginatorInformation generate() - { - if (origCRLs != null) - { - return new OriginatorInformation(new OriginatorInfo(CMSUtils.createDerSetFromList(origCerts), CMSUtils.createDerSetFromList(origCRLs))); - } - else - { - return new OriginatorInformation(new OriginatorInfo(CMSUtils.createDerSetFromList(origCerts), null)); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/OriginatorInformation.java b/pkix/src/main/java/org/bouncycastle/cms/OriginatorInformation.java deleted file mode 100644 index 7e9379d6..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/OriginatorInformation.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.bouncycastle.cms; - -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.cms.OriginatorInfo; -import org.bouncycastle.asn1.x509.Certificate; -import org.bouncycastle.asn1.x509.CertificateList; -import org.bouncycastle.cert.X509CRLHolder; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.util.CollectionStore; -import org.bouncycastle.util.Store; - -public class OriginatorInformation -{ - private OriginatorInfo originatorInfo; - - OriginatorInformation(OriginatorInfo originatorInfo) - { - this.originatorInfo = originatorInfo; - } - - /** - * Return the certificates stored in the underlying OriginatorInfo object. - * - * @return a Store of X509CertificateHolder objects. - */ - public Store getCertificates() - { - ASN1Set certSet = originatorInfo.getCertificates(); - - 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()); - } - - /** - * Return the CRLs stored in the underlying OriginatorInfo object. - * - * @return a Store of X509CRLHolder objects. - */ - public Store getCRLs() - { - ASN1Set crlSet = originatorInfo.getCRLs(); - - 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()); - } - - /** - * Return the underlying ASN.1 object defining this SignerInformation object. - * - * @return a OriginatorInfo. - */ - public OriginatorInfo toASN1Structure() - { - return originatorInfo; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/PasswordRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/PasswordRecipient.java deleted file mode 100644 index c81c3028..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/PasswordRecipient.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.bouncycastle.cms; - -import 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; - - byte[] calculateDerivedKey(byte[] encodedPassword, 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/pkix/src/main/java/org/bouncycastle/cms/PasswordRecipientId.java b/pkix/src/main/java/org/bouncycastle/cms/PasswordRecipientId.java deleted file mode 100644 index 95688d73..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/PasswordRecipientId.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.bouncycastle.cms; - -public class PasswordRecipientId - extends RecipientId -{ - /** - * Construct a recipient ID of the password type. - */ - public PasswordRecipientId() - { - super(password); - } - - public int hashCode() - { - return password; - } - - public boolean equals( - Object o) - { - if (!(o instanceof PasswordRecipientId)) - { - return false; - } - - return true; - } - - public Object clone() - { - return new PasswordRecipientId(); - } - - public boolean match(Object obj) - { - if (obj instanceof PasswordRecipientInformation) - { - return true; - } - - return false; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/PasswordRecipientInfoGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/PasswordRecipientInfoGenerator.java deleted file mode 100644 index b570c3cf..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/PasswordRecipientInfoGenerator.java +++ /dev/null @@ -1,122 +0,0 @@ -package org.bouncycastle.cms; - -import java.security.SecureRandom; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.cms.PasswordRecipientInfo; -import org.bouncycastle.asn1.cms.RecipientInfo; -import org.bouncycastle.asn1.pkcs.PBKDF2Params; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.operator.GenericKey; - -public abstract class PasswordRecipientInfoGenerator - implements RecipientInfoGenerator -{ - private char[] password; - private AlgorithmIdentifier keyDerivationAlgorithm; - private ASN1ObjectIdentifier kekAlgorithm; - private SecureRandom random; - private int schemeID; - private int keySize; - private int blockSize; - - protected PasswordRecipientInfoGenerator(ASN1ObjectIdentifier kekAlgorithm, char[] password) - { - this(kekAlgorithm, password, getKeySize(kekAlgorithm), ((Integer)PasswordRecipientInformation.BLOCKSIZES.get(kekAlgorithm)).intValue()); - } - - protected PasswordRecipientInfoGenerator(ASN1ObjectIdentifier kekAlgorithm, char[] password, int keySize, int blockSize) - { - this.password = password; - this.schemeID = PasswordRecipient.PKCS5_SCHEME2_UTF8; - this.kekAlgorithm = kekAlgorithm; - this.keySize = keySize; - this.blockSize = blockSize; - } - - private static int getKeySize(ASN1ObjectIdentifier kekAlgorithm) - { - Integer size = (Integer)PasswordRecipientInformation.KEYSIZES.get(kekAlgorithm); - - if (size == null) - { - throw new IllegalArgumentException("cannot find key size for algorithm: " + kekAlgorithm); - } - - return size.intValue(); - } - - public PasswordRecipientInfoGenerator setPasswordConversionScheme(int schemeID) - { - this.schemeID = schemeID; - - return this; - } - - public PasswordRecipientInfoGenerator setSaltAndIterationCount(byte[] salt, int iterationCount) - { - this.keyDerivationAlgorithm = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(salt, iterationCount)); - - return this; - } - - public PasswordRecipientInfoGenerator setSecureRandom(SecureRandom random) - { - this.random = random; - - return this; - } - - public RecipientInfo generate(GenericKey contentEncryptionKey) - throws CMSException - { - byte[] iv = new byte[blockSize]; /// TODO: set IV size properly! - - if (random == null) - { - random = new SecureRandom(); - } - - random.nextBytes(iv); - - if (keyDerivationAlgorithm == null) - { - byte[] salt = new byte[20]; - - random.nextBytes(salt); - - keyDerivationAlgorithm = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(salt, 1024)); - } - - byte[] encodedPassword = CMSUtils.getPasswordBytes(schemeID, password); - - byte[] derivedKey = calculateDerivedKey(encodedPassword, keyDerivationAlgorithm, keySize); - - AlgorithmIdentifier kekAlgorithmId = new AlgorithmIdentifier(kekAlgorithm, new DEROctetString(iv)); - - byte[] encryptedKeyBytes = generateEncryptedBytes(kekAlgorithmId, derivedKey, contentEncryptionKey); - - ASN1OctetString encryptedKey = new DEROctetString(encryptedKeyBytes); - - ASN1EncodableVector v = new ASN1EncodableVector(); - v.add(kekAlgorithm); - v.add(new DEROctetString(iv)); - - AlgorithmIdentifier keyEncryptionAlgorithm = new AlgorithmIdentifier( - PKCSObjectIdentifiers.id_alg_PWRI_KEK, new DERSequence(v)); - - return new RecipientInfo(new PasswordRecipientInfo(keyDerivationAlgorithm, - keyEncryptionAlgorithm, encryptedKey)); - } - - protected abstract byte[] calculateDerivedKey(byte[] encodedPassword, AlgorithmIdentifier derivationAlgorithm, int keySize) - throws CMSException; - - protected abstract byte[] generateEncryptedBytes(AlgorithmIdentifier algorithm, byte[] derivedKey, GenericKey contentEncryptionKey) - throws CMSException; -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cms/PasswordRecipientInformation.java b/pkix/src/main/java/org/bouncycastle/cms/PasswordRecipientInformation.java deleted file mode 100644 index 2eef186a..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/PasswordRecipientInformation.java +++ /dev/null @@ -1,116 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.cms.PasswordRecipientInfo; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.util.Integers; - -/** - * the RecipientInfo class for a recipient who has been sent a message - * encrypted using a password. - */ -public class PasswordRecipientInformation - extends RecipientInformation -{ - static Map KEYSIZES = new HashMap(); - static Map BLOCKSIZES = new HashMap(); - - static - { - BLOCKSIZES.put(CMSAlgorithm.DES_EDE3_CBC, Integers.valueOf(8)); - BLOCKSIZES.put(CMSAlgorithm.AES128_CBC, Integers.valueOf(16)); - BLOCKSIZES.put(CMSAlgorithm.AES192_CBC, Integers.valueOf(16)); - BLOCKSIZES.put(CMSAlgorithm.AES256_CBC, Integers.valueOf(16)); - - KEYSIZES.put(CMSAlgorithm.DES_EDE3_CBC, Integers.valueOf(192)); - KEYSIZES.put(CMSAlgorithm.AES128_CBC, Integers.valueOf(128)); - KEYSIZES.put(CMSAlgorithm.AES192_CBC, Integers.valueOf(192)); - KEYSIZES.put(CMSAlgorithm.AES256_CBC, Integers.valueOf(256)); - } - - private PasswordRecipientInfo info; - - PasswordRecipientInformation( - PasswordRecipientInfo info, - AlgorithmIdentifier messageAlgorithm, - CMSSecureReadable secureReadable, - AuthAttributesProvider additionalData) - { - super(info.getKeyEncryptionAlgorithm(), messageAlgorithm, secureReadable, additionalData); - - this.info = info; - this.rid = new PasswordRecipientId(); - } - - /** - * return the object identifier for the key derivation algorithm, or null - * if there is none present. - * - * @return OID for key derivation algorithm, if present. - */ - public String getKeyDerivationAlgOID() - { - if (info.getKeyDerivationAlgorithm() != null) - { - return info.getKeyDerivationAlgorithm().getAlgorithm().getId(); - } - - return null; - } - - /** - * return the ASN.1 encoded key derivation algorithm parameters, or null if - * there aren't any. - * @return ASN.1 encoding of key derivation algorithm parameters. - */ - public byte[] getKeyDerivationAlgParams() - { - try - { - if (info.getKeyDerivationAlgorithm() != null) - { - ASN1Encodable params = info.getKeyDerivationAlgorithm().getParameters(); - if (params != null) - { - return params.toASN1Primitive().getEncoded(); - } - } - - return null; - } - catch (Exception e) - { - throw new RuntimeException("exception getting encryption parameters " + e); - } - } - - /** - * Return the key derivation algorithm details for the key in this recipient. - * - * @return AlgorithmIdentifier representing the key derivation algorithm. - */ - public AlgorithmIdentifier getKeyDerivationAlgorithm() - { - return info.getKeyDerivationAlgorithm(); - } - - protected RecipientOperator getRecipientOperator(Recipient recipient) - throws CMSException, IOException - { - PasswordRecipient pbeRecipient = (PasswordRecipient)recipient; - AlgorithmIdentifier kekAlg = AlgorithmIdentifier.getInstance(info.getKeyEncryptionAlgorithm()); - AlgorithmIdentifier kekAlgParams = AlgorithmIdentifier.getInstance(kekAlg.getParameters()); - - byte[] passwordBytes = CMSUtils.getPasswordBytes(pbeRecipient.getPasswordConversionScheme(), pbeRecipient.getPassword()); - - int keySize = ((Integer)KEYSIZES.get(kekAlgParams.getAlgorithm())).intValue(); - - byte[] derivedKey = pbeRecipient.calculateDerivedKey(passwordBytes, this.getKeyDerivationAlgorithm(), keySize); - - return pbeRecipient.getRecipientOperator(kekAlgParams, messageAlgorithm, derivedKey, info.getEncryptedKey().getOctets()); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/Recipient.java b/pkix/src/main/java/org/bouncycastle/cms/Recipient.java deleted file mode 100644 index 88c88a61..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/Recipient.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.bouncycastle.cms; - -public interface Recipient -{ -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/RecipientId.java b/pkix/src/main/java/org/bouncycastle/cms/RecipientId.java deleted file mode 100644 index fae5a100..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/RecipientId.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.bouncycastle.cms; - -import org.bouncycastle.util.Selector; - -public abstract class RecipientId - implements Selector -{ - public static final int keyTrans = 0; - public static final int kek = 1; - public static final int keyAgree = 2; - public static final int password = 3; - - private final int type; - - protected RecipientId(int type) - { - this.type = type; - } - - /** - * Return the type code for this recipient ID. - * - * @return one of keyTrans, kek, keyAgree, password - */ - public int getType() - { - return type; - } - - public abstract Object clone(); -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/RecipientInfoGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/RecipientInfoGenerator.java deleted file mode 100644 index 6ab41d35..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/RecipientInfoGenerator.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.bouncycastle.cms; - -import org.bouncycastle.asn1.cms.RecipientInfo; -import org.bouncycastle.operator.GenericKey; - -public interface RecipientInfoGenerator -{ - RecipientInfo generate(GenericKey contentEncryptionKey) - throws CMSException; -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/RecipientInformation.java b/pkix/src/main/java/org/bouncycastle/cms/RecipientInformation.java deleted file mode 100644 index 86f9fa30..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/RecipientInformation.java +++ /dev/null @@ -1,181 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.ByteArrayInputStream; -import java.io.IOException; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.util.io.Streams; - -public abstract class RecipientInformation -{ - protected RecipientId rid; - protected AlgorithmIdentifier keyEncAlg; - protected AlgorithmIdentifier messageAlgorithm; - protected CMSSecureReadable secureReadable; - - private AuthAttributesProvider additionalData; - - private byte[] resultMac; - private RecipientOperator operator; - - RecipientInformation( - AlgorithmIdentifier keyEncAlg, - AlgorithmIdentifier messageAlgorithm, - CMSSecureReadable secureReadable, - AuthAttributesProvider additionalData) - { - this.keyEncAlg = keyEncAlg; - this.messageAlgorithm = messageAlgorithm; - this.secureReadable = secureReadable; - this.additionalData = additionalData; - } - - public RecipientId getRID() - { - return rid; - } - - private byte[] encodeObj( - ASN1Encodable obj) - throws IOException - { - if (obj != null) - { - return obj.toASN1Primitive().getEncoded(); - } - - return null; - } - - /** - * Return the key encryption algorithm details for the key in this recipient. - * - * @return AlgorithmIdentifier representing the key encryption algorithm. - */ - public AlgorithmIdentifier getKeyEncryptionAlgorithm() - { - return keyEncAlg; - } - - /** - * return the object identifier for the key encryption algorithm. - * - * @return OID for key encryption algorithm. - */ - public String getKeyEncryptionAlgOID() - { - return keyEncAlg.getAlgorithm().getId(); - } - - /** - * return the ASN.1 encoded key encryption algorithm parameters, or null if - * there aren't any. - * - * @return ASN.1 encoding of key encryption algorithm parameters. - */ - public byte[] getKeyEncryptionAlgParams() - { - try - { - return encodeObj(keyEncAlg.getParameters()); - } - catch (Exception e) - { - throw new RuntimeException("exception getting encryption parameters " + e); - } - } - - /** - * Return the content digest calculated during the read of the content if one has been generated. This will - * only happen if we are dealing with authenticated data and authenticated attributes are present. - * - * @return byte array containing the digest. - */ - public byte[] getContentDigest() - { - if (secureReadable instanceof CMSEnvelopedHelper.CMSDigestAuthenticatedSecureReadable) - { - return ((CMSEnvelopedHelper.CMSDigestAuthenticatedSecureReadable)secureReadable).getDigest(); - } - - return null; - } - - /** - * Return the MAC calculated for the recipient. Note: this call is only meaningful once all - * the content has been read. - * - * @return byte array containing the mac. - */ - public byte[] getMac() - { - if (resultMac == null) - { - if (operator.isMacBased()) - { - if (additionalData != null) - { - try - { - Streams.drain(operator.getInputStream(new ByteArrayInputStream(additionalData.getAuthAttributes().getEncoded(ASN1Encoding.DER)))); - } - catch (IOException e) - { - throw new IllegalStateException("unable to drain input: " + e.getMessage()); - } - } - resultMac = operator.getMac(); - } - } - - return resultMac; - } - - /** - * Return the decrypted/encapsulated content in the EnvelopedData after recovering the content - * encryption/MAC key using the passed in Recipient. - * - * @param recipient recipient object to use to recover content encryption key - * @return the content inside the EnvelopedData this RecipientInformation is associated with. - * @throws CMSException if the content-encryption/MAC key cannot be recovered. - */ - public byte[] getContent( - Recipient recipient) - throws CMSException - { - try - { - return CMSUtils.streamToByteArray(getContentStream(recipient).getContentStream()); - } - catch (IOException e) - { - throw new CMSException("unable to parse internal stream: " + e.getMessage(), e); - } - } - - /** - * Return a CMSTypedStream representing the content in the EnvelopedData after recovering the content - * encryption/MAC key using the passed in Recipient. - * - * @param recipient recipient object to use to recover content encryption key - * @return the content inside the EnvelopedData this RecipientInformation is associated with. - * @throws CMSException if the content-encryption/MAC key cannot be recovered. - */ - public CMSTypedStream getContentStream(Recipient recipient) - throws CMSException, IOException - { - operator = getRecipientOperator(recipient); - - if (additionalData != null) - { - return new CMSTypedStream(secureReadable.getInputStream()); - } - - return new CMSTypedStream(operator.getInputStream(secureReadable.getInputStream())); - } - - protected abstract RecipientOperator getRecipientOperator(Recipient recipient) - throws CMSException, IOException; -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/RecipientInformationStore.java b/pkix/src/main/java/org/bouncycastle/cms/RecipientInformationStore.java deleted file mode 100644 index 5cf80e5d..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/RecipientInformationStore.java +++ /dev/null @@ -1,115 +0,0 @@ -package 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 org.bouncycastle.asn1.x500.X500Name; - -public class RecipientInformationStore -{ - private final List all; //ArrayList[RecipientInformation] - private final Map table = new HashMap(); // HashMap[RecipientID, ArrayList[RecipientInformation]] - - public RecipientInformationStore( - Collection recipientInfos) - { - Iterator it = recipientInfos.iterator(); - - while (it.hasNext()) - { - RecipientInformation recipientInformation = (RecipientInformation)it.next(); - RecipientId rid = recipientInformation.getRID(); - - List list = (ArrayList)table.get(rid); - if (list == null) - { - list = new ArrayList(1); - table.put(rid, list); - } - - list.add(recipientInformation); - } - - this.all = new ArrayList(recipientInfos); - } - - /** - * Return the first RecipientInformation object that matches the - * passed in selector. Null if there are no matches. - * - * @param selector to identify a recipient - * @return a single RecipientInformation object. Null if none matches. - */ - public RecipientInformation get( - RecipientId selector) - { - Collection list = getRecipients(selector); - - return list.size() == 0 ? null : (RecipientInformation)list.iterator().next(); - } - - /** - * Return the number of recipients in the collection. - * - * @return number of recipients identified. - */ - public int size() - { - return all.size(); - } - - /** - * Return all recipients in the collection - * - * @return a collection of recipients. - */ - public Collection getRecipients() - { - return new ArrayList(all); - } - - /** - * Return possible empty collection with recipients matching the passed in RecipientId - * - * @param selector a recipient id to select against. - * @return a collection of RecipientInformation objects. - */ - public Collection getRecipients( - RecipientId selector) - { - if (selector instanceof KeyTransRecipientId) - { - KeyTransRecipientId keyTrans = (KeyTransRecipientId)selector; - - X500Name issuer = keyTrans.getIssuer(); - byte[] subjectKeyId = keyTrans.getSubjectKeyIdentifier(); - - if (issuer != null && subjectKeyId != null) - { - List results = new ArrayList(); - - Collection match1 = getRecipients(new KeyTransRecipientId(issuer, keyTrans.getSerialNumber())); - if (match1 != null) - { - results.addAll(match1); - } - - Collection match2 = getRecipients(new KeyTransRecipientId(subjectKeyId)); - if (match2 != null) - { - results.addAll(match2); - } - - return results; - } - } - - List list = (ArrayList)table.get(selector); - - return list == null ? new ArrayList() : new ArrayList(list); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/RecipientOperator.java b/pkix/src/main/java/org/bouncycastle/cms/RecipientOperator.java deleted file mode 100644 index 7b3e3e58..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/RecipientOperator.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.InputStream; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.operator.InputDecryptor; -import org.bouncycastle.operator.MacCalculator; -import 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/pkix/src/main/java/org/bouncycastle/cms/SignerId.java b/pkix/src/main/java/org/bouncycastle/cms/SignerId.java deleted file mode 100644 index 6b53bac7..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/SignerId.java +++ /dev/null @@ -1,104 +0,0 @@ -package org.bouncycastle.cms; - -import java.math.BigInteger; - -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.cert.selector.X509CertificateHolderSelector; -import 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/pkix/src/main/java/org/bouncycastle/cms/SignerInfoGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/SignerInfoGenerator.java deleted file mode 100644 index f264729c..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/SignerInfoGenerator.java +++ /dev/null @@ -1,291 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.cms.AttributeTable; -import org.bouncycastle.asn1.cms.SignerIdentifier; -import org.bouncycastle.asn1.cms.SignerInfo; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.operator.ContentSigner; -import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder; -import org.bouncycastle.operator.DigestAlgorithmIdentifierFinder; -import org.bouncycastle.operator.DigestCalculator; -import org.bouncycastle.operator.DigestCalculatorProvider; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.util.Arrays; -import 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 digestAlg = null; - - if (sAttrGen != null) - { - digestAlg = digester.getAlgorithmIdentifier(); - calculatedDigest = digester.getDigest(); - Map parameters = getBaseParameters(contentType, digester.getAlgorithmIdentifier(), 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, calculatedDigest); - parameters.put(CMSAttributeTableGenerator.SIGNATURE, Arrays.clone(sigBytes)); - - AttributeTable unsigned = unsAttrGen.getAttributes(Collections.unmodifiableMap(parameters)); - - unsignedAttr = getAttributeSet(unsigned); - } - - AlgorithmIdentifier digestEncryptionAlgorithm = sigEncAlgFinder.findEncryptionAlgorithm(signer.getAlgorithmIdentifier()); - - 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, 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.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/pkix/src/main/java/org/bouncycastle/cms/SignerInfoGeneratorBuilder.java b/pkix/src/main/java/org/bouncycastle/cms/SignerInfoGeneratorBuilder.java deleted file mode 100644 index 7a47a2f8..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/SignerInfoGeneratorBuilder.java +++ /dev/null @@ -1,139 +0,0 @@ -package org.bouncycastle.cms; - -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.cms.IssuerAndSerialNumber; -import org.bouncycastle.asn1.cms.SignerIdentifier; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.operator.ContentSigner; -import org.bouncycastle.operator.DigestCalculatorProvider; -import 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. - * - * @param digestProvider a provider of digest calculators for the algorithms required in the signature and attribute calculations. - */ - 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/pkix/src/main/java/org/bouncycastle/cms/SignerInformation.java b/pkix/src/main/java/org/bouncycastle/cms/SignerInformation.java deleted file mode 100644 index 7e178d6c..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/SignerInformation.java +++ /dev/null @@ -1,680 +0,0 @@ -package 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 org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.cms.Attribute; -import org.bouncycastle.asn1.cms.AttributeTable; -import org.bouncycastle.asn1.cms.CMSAttributes; -import org.bouncycastle.asn1.cms.IssuerAndSerialNumber; -import org.bouncycastle.asn1.cms.SignerIdentifier; -import org.bouncycastle.asn1.cms.SignerInfo; -import org.bouncycastle.asn1.cms.Time; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.DigestInfo; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.operator.ContentVerifier; -import org.bouncycastle.operator.DigestCalculator; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.operator.RawContentVerifier; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.io.TeeOutputStream; - -/** - * an expanded SignerInfo block from a CMS Signed message - */ -public class SignerInformation -{ - private SignerId sid; - private SignerInfo info; - private AlgorithmIdentifier digestAlgorithm; - private AlgorithmIdentifier encryptionAlgorithm; - private final ASN1Set signedAttributeSet; - private final ASN1Set unsignedAttributeSet; - private CMSProcessable content; - private byte[] signature; - private ASN1ObjectIdentifier contentType; - private byte[] resultDigest; - - // Derived - private AttributeTable signedAttributeValues; - private AttributeTable unsignedAttributeValues; - private boolean isCounterSignature; - - 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; - } - - 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(); - } - - 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"); - } - } - } - - // 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) - { - AttributeTable signedAttrTable = this.getSignedAttributes(); - 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)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 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 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/pkix/src/main/java/org/bouncycastle/cms/SignerInformationStore.java b/pkix/src/main/java/org/bouncycastle/cms/SignerInformationStore.java deleted file mode 100644 index b65ab5ea..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/SignerInformationStore.java +++ /dev/null @@ -1,109 +0,0 @@ -package 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; - -public class SignerInformationStore -{ - private List all = new ArrayList(); - private Map table = new HashMap(); - - public SignerInformationStore( - Collection 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 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 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); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/SignerInformationVerifier.java b/pkix/src/main/java/org/bouncycastle/cms/SignerInformationVerifier.java deleted file mode 100644 index ada4d0ea..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/SignerInformationVerifier.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.bouncycastle.cms; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.operator.ContentVerifier; -import org.bouncycastle.operator.ContentVerifierProvider; -import org.bouncycastle.operator.DigestCalculator; -import org.bouncycastle.operator.DigestCalculatorProvider; -import org.bouncycastle.operator.OperatorCreationException; -import 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); - - return verifierProvider.get(sigAlgorithmFinder.find(signatureName)); - } - - public DigestCalculator getDigestCalculator(AlgorithmIdentifier algorithmIdentifier) - throws OperatorCreationException - { - return digestProvider.get(algorithmIdentifier); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/SignerInformationVerifierProvider.java b/pkix/src/main/java/org/bouncycastle/cms/SignerInformationVerifierProvider.java deleted file mode 100644 index 5568b0ec..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/SignerInformationVerifierProvider.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.bouncycastle.cms; - -import org.bouncycastle.operator.OperatorCreationException; - -public interface SignerInformationVerifierProvider -{ - /** - * Return a SignerInformationVerifierProvider suitable for the passed in SID. - * - * @param sid the SignerId we are trying to match for. - * @return a verifier if one is available, null otherwise. - * @throws OperatorCreationException if creation of the verifier fails when it should suceed. - */ - public SignerInformationVerifier get(SignerId sid) - throws OperatorCreationException; -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/SimpleAttributeTableGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/SimpleAttributeTableGenerator.java deleted file mode 100644 index f182431f..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/SimpleAttributeTableGenerator.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.bouncycastle.cms; - -import 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/pkix/src/main/java/org/bouncycastle/cms/bc/BcCMSContentEncryptorBuilder.java b/pkix/src/main/java/org/bouncycastle/cms/bc/BcCMSContentEncryptorBuilder.java deleted file mode 100644 index a12c66b3..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/bc/BcCMSContentEncryptorBuilder.java +++ /dev/null @@ -1,124 +0,0 @@ -package org.bouncycastle.cms.bc; - -import java.io.OutputStream; -import java.security.SecureRandom; -import java.util.HashMap; -import java.util.Map; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSAlgorithm; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.crypto.BufferedBlockCipher; -import org.bouncycastle.crypto.CipherKeyGenerator; -import org.bouncycastle.crypto.StreamCipher; -import org.bouncycastle.crypto.io.CipherOutputStream; -import org.bouncycastle.crypto.params.KeyParameter; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.OutputEncryptor; -import org.bouncycastle.util.Integers; - -public class BcCMSContentEncryptorBuilder -{ - private static Map keySizes = new HashMap(); - - static - { - keySizes.put(CMSAlgorithm.AES128_CBC, Integers.valueOf(128)); - keySizes.put(CMSAlgorithm.AES192_CBC, Integers.valueOf(192)); - keySizes.put(CMSAlgorithm.AES256_CBC, Integers.valueOf(256)); - - keySizes.put(CMSAlgorithm.CAMELLIA128_CBC, Integers.valueOf(128)); - keySizes.put(CMSAlgorithm.CAMELLIA192_CBC, Integers.valueOf(192)); - keySizes.put(CMSAlgorithm.CAMELLIA256_CBC, Integers.valueOf(256)); - } - - private static int getKeySize(ASN1ObjectIdentifier oid) - { - Integer size = (Integer)keySizes.get(oid); - - if (size != null) - { - return size.intValue(); - } - - return -1; - } - - private final ASN1ObjectIdentifier encryptionOID; - private final int keySize; - - private EnvelopedDataHelper helper = new EnvelopedDataHelper(); - private SecureRandom random; - - public BcCMSContentEncryptorBuilder(ASN1ObjectIdentifier encryptionOID) - { - this(encryptionOID, getKeySize(encryptionOID)); - } - - public BcCMSContentEncryptorBuilder(ASN1ObjectIdentifier encryptionOID, int keySize) - { - this.encryptionOID = encryptionOID; - this.keySize = keySize; - } - - public BcCMSContentEncryptorBuilder setSecureRandom(SecureRandom random) - { - this.random = random; - - return this; - } - - public OutputEncryptor build() - throws CMSException - { - return new CMSOutputEncryptor(encryptionOID, keySize, random); - } - - private class CMSOutputEncryptor - implements OutputEncryptor - { - private KeyParameter encKey; - private AlgorithmIdentifier algorithmIdentifier; - private Object cipher; - - CMSOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, SecureRandom random) - throws CMSException - { - if (random == null) - { - random = new SecureRandom(); - } - - CipherKeyGenerator keyGen = helper.createKeyGenerator(encryptionOID, random); - - encKey = new KeyParameter(keyGen.generateKey()); - - algorithmIdentifier = helper.generateAlgorithmIdentifier(encryptionOID, encKey, random); - - cipher = helper.createContentCipher(true, encKey, algorithmIdentifier); - } - - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return algorithmIdentifier; - } - - public OutputStream getOutputStream(OutputStream dOut) - { - if (cipher instanceof BufferedBlockCipher) - { - return new CipherOutputStream(dOut, (BufferedBlockCipher)cipher); - } - else - { - return new CipherOutputStream(dOut, (StreamCipher)cipher); - } - } - - public GenericKey getKey() - { - return new GenericKey(algorithmIdentifier, encKey.getKey()); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/bc/BcKEKEnvelopedRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/bc/BcKEKEnvelopedRecipient.java deleted file mode 100644 index 5641d82b..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/bc/BcKEKEnvelopedRecipient.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.bouncycastle.cms.bc; - -import java.io.InputStream; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.RecipientOperator; -import org.bouncycastle.crypto.BufferedBlockCipher; -import org.bouncycastle.crypto.StreamCipher; -import org.bouncycastle.crypto.params.KeyParameter; -import org.bouncycastle.operator.InputDecryptor; -import org.bouncycastle.operator.bc.BcSymmetricKeyUnwrapper; - -public class BcKEKEnvelopedRecipient - extends BcKEKRecipient -{ - public BcKEKEnvelopedRecipient(BcSymmetricKeyUnwrapper unwrapper) - { - super(unwrapper); - } - - public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey) - throws CMSException - { - KeyParameter secretKey = (KeyParameter)extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, encryptedContentEncryptionKey); - - final Object dataCipher = EnvelopedDataHelper.createContentCipher(false, secretKey, contentEncryptionAlgorithm); - - return new RecipientOperator(new InputDecryptor() - { - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return contentEncryptionAlgorithm; - } - - public InputStream getInputStream(InputStream dataOut) - { - if (dataCipher instanceof BufferedBlockCipher) - { - return new org.bouncycastle.crypto.io.CipherInputStream(dataOut, (BufferedBlockCipher)dataCipher); - } - else - { - return new org.bouncycastle.crypto.io.CipherInputStream(dataOut, (StreamCipher)dataCipher); - } - } - }); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/bc/BcKEKRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/bc/BcKEKRecipient.java deleted file mode 100644 index a7d5eb76..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/bc/BcKEKRecipient.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.bouncycastle.cms.bc; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.KEKRecipient; -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.operator.OperatorException; -import org.bouncycastle.operator.SymmetricKeyUnwrapper; -import org.bouncycastle.operator.bc.BcSymmetricKeyUnwrapper; - -public abstract class BcKEKRecipient - implements KEKRecipient -{ - private SymmetricKeyUnwrapper unwrapper; - - public BcKEKRecipient(BcSymmetricKeyUnwrapper unwrapper) - { - this.unwrapper = unwrapper; - } - - protected CipherParameters extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey) - throws CMSException - { - try - { - return CMSUtils.getBcKey(unwrapper.generateUnwrappedKey(contentEncryptionAlgorithm, encryptedContentEncryptionKey)); - } - catch (OperatorException e) - { - throw new CMSException("exception unwrapping key: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/bc/BcKEKRecipientInfoGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/bc/BcKEKRecipientInfoGenerator.java deleted file mode 100644 index 309ad64b..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/bc/BcKEKRecipientInfoGenerator.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.bouncycastle.cms.bc; - -import org.bouncycastle.asn1.cms.KEKIdentifier; -import org.bouncycastle.cms.KEKRecipientInfoGenerator; -import org.bouncycastle.operator.bc.BcSymmetricKeyWrapper; - -public class BcKEKRecipientInfoGenerator - extends KEKRecipientInfoGenerator -{ - public BcKEKRecipientInfoGenerator(KEKIdentifier kekIdentifier, BcSymmetricKeyWrapper kekWrapper) - { - super(kekIdentifier, kekWrapper); - } - - public BcKEKRecipientInfoGenerator(byte[] keyIdentifier, BcSymmetricKeyWrapper kekWrapper) - { - this(new KEKIdentifier(keyIdentifier, null, null), kekWrapper); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/bc/BcKeyTransRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/bc/BcKeyTransRecipient.java deleted file mode 100644 index 8c698853..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/bc/BcKeyTransRecipient.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.bouncycastle.cms.bc; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.KeyTransRecipient; -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.operator.AsymmetricKeyUnwrapper; -import org.bouncycastle.operator.OperatorException; -import org.bouncycastle.operator.bc.BcRSAAsymmetricKeyUnwrapper; - -public abstract class BcKeyTransRecipient - implements KeyTransRecipient -{ - private AsymmetricKeyParameter recipientKey; - - public BcKeyTransRecipient(AsymmetricKeyParameter recipientKey) - { - this.recipientKey = recipientKey; - } - - protected CipherParameters extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedEncryptionKey) - throws CMSException - { - AsymmetricKeyUnwrapper unwrapper = new BcRSAAsymmetricKeyUnwrapper(keyEncryptionAlgorithm, recipientKey); - - try - { - return CMSUtils.getBcKey(unwrapper.generateUnwrappedKey(encryptedKeyAlgorithm, encryptedEncryptionKey)); - } - catch (OperatorException e) - { - throw new CMSException("exception unwrapping key: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/bc/BcKeyTransRecipientInfoGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/bc/BcKeyTransRecipientInfoGenerator.java deleted file mode 100644 index eebbbda4..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/bc/BcKeyTransRecipientInfoGenerator.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.bouncycastle.cms.bc; - -import org.bouncycastle.asn1.cms.IssuerAndSerialNumber; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cms.KeyTransRecipientInfoGenerator; -import org.bouncycastle.operator.bc.BcAsymmetricKeyWrapper; - -public abstract class BcKeyTransRecipientInfoGenerator - extends KeyTransRecipientInfoGenerator -{ - public BcKeyTransRecipientInfoGenerator(X509CertificateHolder recipientCert, BcAsymmetricKeyWrapper wrapper) - { - super(new IssuerAndSerialNumber(recipientCert.toASN1Structure()), wrapper); - } - - public BcKeyTransRecipientInfoGenerator(byte[] subjectKeyIdentifier, BcAsymmetricKeyWrapper wrapper) - { - super(subjectKeyIdentifier, wrapper); - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cms/bc/BcPasswordEnvelopedRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/bc/BcPasswordEnvelopedRecipient.java deleted file mode 100644 index d3d38cf6..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/bc/BcPasswordEnvelopedRecipient.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.bouncycastle.cms.bc; - -import java.io.InputStream; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.RecipientOperator; -import org.bouncycastle.crypto.BufferedBlockCipher; -import org.bouncycastle.crypto.StreamCipher; -import org.bouncycastle.crypto.io.CipherInputStream; -import org.bouncycastle.crypto.params.KeyParameter; -import org.bouncycastle.operator.InputDecryptor; - -public class BcPasswordEnvelopedRecipient - extends BcPasswordRecipient -{ - public BcPasswordEnvelopedRecipient(char[] password) - { - super(password); - } - - public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, byte[] derivedKey, byte[] encryptedContentEncryptionKey) - throws CMSException - { - KeyParameter secretKey = extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, derivedKey, encryptedContentEncryptionKey); - - final Object dataCipher = EnvelopedDataHelper.createContentCipher(false, secretKey, contentEncryptionAlgorithm); - - return new RecipientOperator(new InputDecryptor() - { - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return contentEncryptionAlgorithm; - } - - public InputStream getInputStream(InputStream dataOut) - { - if (dataCipher instanceof BufferedBlockCipher) - { - return new CipherInputStream(dataOut, (BufferedBlockCipher)dataCipher); - } - else - { - return new CipherInputStream(dataOut, (StreamCipher)dataCipher); - } - } - }); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/bc/BcPasswordRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/bc/BcPasswordRecipient.java deleted file mode 100644 index 50f9c6c0..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/bc/BcPasswordRecipient.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.bouncycastle.cms.bc; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.pkcs.PBKDF2Params; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.PasswordRecipient; -import org.bouncycastle.crypto.InvalidCipherTextException; -import org.bouncycastle.crypto.Wrapper; -import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; -import org.bouncycastle.crypto.params.KeyParameter; -import org.bouncycastle.crypto.params.ParametersWithIV; - -/** - * the RecipientInfo class for a recipient who has been sent a message - * encrypted using a password. - */ -public abstract class BcPasswordRecipient - implements PasswordRecipient -{ - private int schemeID = PasswordRecipient.PKCS5_SCHEME2_UTF8; - private char[] password; - - BcPasswordRecipient( - char[] password) - { - this.password = password; - } - - public BcPasswordRecipient setPasswordConversionScheme(int schemeID) - { - this.schemeID = schemeID; - - return this; - } - - protected KeyParameter extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] derivedKey, byte[] encryptedContentEncryptionKey) - throws CMSException - { - Wrapper keyEncryptionCipher = EnvelopedDataHelper.createRFC3211Wrapper(keyEncryptionAlgorithm.getAlgorithm()); - - keyEncryptionCipher.init(false, new ParametersWithIV(new KeyParameter(derivedKey), ASN1OctetString.getInstance(keyEncryptionAlgorithm.getParameters()).getOctets())); - - try - { - return new KeyParameter(keyEncryptionCipher.unwrap(encryptedContentEncryptionKey, 0, encryptedContentEncryptionKey.length)); - } - catch (InvalidCipherTextException e) - { - throw new CMSException("unable to unwrap key: " + e.getMessage(), e); - } - } - - public byte[] calculateDerivedKey(byte[] encodedPassword, AlgorithmIdentifier derivationAlgorithm, int keySize) - throws CMSException - { - PBKDF2Params params = PBKDF2Params.getInstance(derivationAlgorithm.getParameters()); - - PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(); - - gen.init(encodedPassword, params.getSalt(), params.getIterationCount().intValue()); - - return ((KeyParameter)gen.generateDerivedParameters(keySize)).getKey(); - } - - public int getPasswordConversionScheme() - { - return schemeID; - } - - public char[] getPassword() - { - return password; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/bc/BcPasswordRecipientInfoGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/bc/BcPasswordRecipientInfoGenerator.java deleted file mode 100644 index 6e1bfdb7..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/bc/BcPasswordRecipientInfoGenerator.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.bouncycastle.cms.bc; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.pkcs.PBKDF2Params; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.PasswordRecipientInfoGenerator; -import org.bouncycastle.crypto.Wrapper; -import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; -import org.bouncycastle.crypto.params.KeyParameter; -import org.bouncycastle.crypto.params.ParametersWithIV; -import org.bouncycastle.operator.GenericKey; - -public class BcPasswordRecipientInfoGenerator - extends PasswordRecipientInfoGenerator -{ - public BcPasswordRecipientInfoGenerator(ASN1ObjectIdentifier kekAlgorithm, char[] password) - { - super(kekAlgorithm, password); - } - - protected byte[] calculateDerivedKey(byte[] encodedPassword, AlgorithmIdentifier derivationAlgorithm, int keySize) - throws CMSException - { - PBKDF2Params params = PBKDF2Params.getInstance(derivationAlgorithm.getParameters()); - - PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(); - - gen.init(encodedPassword, params.getSalt(), params.getIterationCount().intValue()); - - return ((KeyParameter)gen.generateDerivedParameters(keySize)).getKey(); - } - - public byte[] generateEncryptedBytes(AlgorithmIdentifier keyEncryptionAlgorithm, byte[] derivedKey, GenericKey contentEncryptionKey) - throws CMSException - { - byte[] contentEncryptionKeySpec = ((KeyParameter)CMSUtils.getBcKey(contentEncryptionKey)).getKey(); - Wrapper keyEncryptionCipher = EnvelopedDataHelper.createRFC3211Wrapper(keyEncryptionAlgorithm.getAlgorithm()); - - keyEncryptionCipher.init(true, new ParametersWithIV(new KeyParameter(derivedKey), ASN1OctetString.getInstance(keyEncryptionAlgorithm.getParameters()).getOctets())); - - return keyEncryptionCipher.wrap(contentEncryptionKeySpec, 0, contentEncryptionKeySpec.length); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/bc/BcRSAKeyTransEnvelopedRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/bc/BcRSAKeyTransEnvelopedRecipient.java deleted file mode 100644 index ed933fe6..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/bc/BcRSAKeyTransEnvelopedRecipient.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.bouncycastle.cms.bc; - -import java.io.InputStream; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.RecipientOperator; -import org.bouncycastle.crypto.BufferedBlockCipher; -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.StreamCipher; -import org.bouncycastle.crypto.io.CipherInputStream; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.operator.InputDecryptor; - -public class BcRSAKeyTransEnvelopedRecipient - extends BcKeyTransRecipient -{ - public BcRSAKeyTransEnvelopedRecipient(AsymmetricKeyParameter key) - { - super(key); - } - - public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey) - throws CMSException - { - CipherParameters secretKey = extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, encryptedContentEncryptionKey); - - final Object dataCipher = EnvelopedDataHelper.createContentCipher(false, secretKey, contentEncryptionAlgorithm); - - return new RecipientOperator(new InputDecryptor() - { - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return contentEncryptionAlgorithm; - } - - public InputStream getInputStream(InputStream dataIn) - { - if (dataCipher instanceof BufferedBlockCipher) - { - return new CipherInputStream(dataIn, (BufferedBlockCipher)dataCipher); - } - else - { - return new CipherInputStream(dataIn, (StreamCipher)dataCipher); - } - } - }); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/bc/BcRSAKeyTransRecipientInfoGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/bc/BcRSAKeyTransRecipientInfoGenerator.java deleted file mode 100644 index b571b9ae..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/bc/BcRSAKeyTransRecipientInfoGenerator.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.bouncycastle.cms.bc; - -import java.io.IOException; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.operator.bc.BcRSAAsymmetricKeyWrapper; - -public class BcRSAKeyTransRecipientInfoGenerator - extends BcKeyTransRecipientInfoGenerator -{ - public BcRSAKeyTransRecipientInfoGenerator(byte[] subjectKeyIdentifier, AlgorithmIdentifier encAlgId, AsymmetricKeyParameter publicKey) - { - super(subjectKeyIdentifier, new BcRSAAsymmetricKeyWrapper(encAlgId, publicKey)); - } - - public BcRSAKeyTransRecipientInfoGenerator(X509CertificateHolder recipientCert) - throws IOException - { - super(recipientCert, new BcRSAAsymmetricKeyWrapper(recipientCert.getSubjectPublicKeyInfo().getAlgorithmId(), recipientCert.getSubjectPublicKeyInfo())); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/bc/BcRSASignerInfoVerifierBuilder.java b/pkix/src/main/java/org/bouncycastle/cms/bc/BcRSASignerInfoVerifierBuilder.java deleted file mode 100644 index 93abd65e..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/bc/BcRSASignerInfoVerifierBuilder.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.bouncycastle.cms.bc; - -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cms.CMSSignatureAlgorithmNameGenerator; -import org.bouncycastle.cms.SignerInformationVerifier; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.operator.DigestAlgorithmIdentifierFinder; -import org.bouncycastle.operator.DigestCalculatorProvider; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.operator.SignatureAlgorithmIdentifierFinder; -import org.bouncycastle.operator.bc.BcRSAContentVerifierProviderBuilder; - -public class BcRSASignerInfoVerifierBuilder -{ - private BcRSAContentVerifierProviderBuilder contentVerifierProviderBuilder; - private DigestCalculatorProvider digestCalculatorProvider; - private CMSSignatureAlgorithmNameGenerator sigAlgNameGen; - private SignatureAlgorithmIdentifierFinder sigAlgIdFinder; - - public BcRSASignerInfoVerifierBuilder(CMSSignatureAlgorithmNameGenerator sigAlgNameGen, SignatureAlgorithmIdentifierFinder sigAlgIdFinder, DigestAlgorithmIdentifierFinder digestAlgorithmFinder, DigestCalculatorProvider digestCalculatorProvider) - { - this.sigAlgNameGen = sigAlgNameGen; - this.sigAlgIdFinder = sigAlgIdFinder; - this.contentVerifierProviderBuilder = new BcRSAContentVerifierProviderBuilder(digestAlgorithmFinder); - this.digestCalculatorProvider = digestCalculatorProvider; - } - - public SignerInformationVerifier build(X509CertificateHolder certHolder) - throws OperatorCreationException - { - return new SignerInformationVerifier(sigAlgNameGen, sigAlgIdFinder, contentVerifierProviderBuilder.build(certHolder), digestCalculatorProvider); - } - - public SignerInformationVerifier build(AsymmetricKeyParameter pubKey) - throws OperatorCreationException - { - return new SignerInformationVerifier(sigAlgNameGen, sigAlgIdFinder, contentVerifierProviderBuilder.build(pubKey), digestCalculatorProvider); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/bc/CMSUtils.java b/pkix/src/main/java/org/bouncycastle/cms/bc/CMSUtils.java deleted file mode 100644 index 8beb36a1..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/bc/CMSUtils.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.bouncycastle.cms.bc; - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.params.KeyParameter; -import org.bouncycastle.operator.GenericKey; - -class CMSUtils -{ - static CipherParameters getBcKey(GenericKey key) - { - if (key.getRepresentation() instanceof CipherParameters) - { - return (CipherParameters)key.getRepresentation(); - } - - if (key.getRepresentation() instanceof byte[]) - { - return new KeyParameter((byte[])key.getRepresentation()); - } - - throw new IllegalArgumentException("unknown generic key type"); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/bc/EnvelopedDataHelper.java b/pkix/src/main/java/org/bouncycastle/cms/bc/EnvelopedDataHelper.java deleted file mode 100644 index bb7c3cd6..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/bc/EnvelopedDataHelper.java +++ /dev/null @@ -1,378 +0,0 @@ -package org.bouncycastle.cms.bc; - -import java.security.SecureRandom; -import java.util.HashMap; -import java.util.Map; - -import org.bouncycastle.asn1.ASN1Null; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers; -import org.bouncycastle.asn1.misc.CAST5CBCParameters; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.RC2CBCParameter; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSAlgorithm; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.crypto.BlockCipher; -import org.bouncycastle.crypto.BufferedBlockCipher; -import org.bouncycastle.crypto.CipherKeyGenerator; -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.KeyGenerationParameters; -import org.bouncycastle.crypto.StreamCipher; -import org.bouncycastle.crypto.Wrapper; -import org.bouncycastle.crypto.engines.AESEngine; -import org.bouncycastle.crypto.engines.DESEngine; -import org.bouncycastle.crypto.engines.DESedeEngine; -import org.bouncycastle.crypto.engines.RC2Engine; -import org.bouncycastle.crypto.engines.RC4Engine; -import org.bouncycastle.crypto.engines.RFC3211WrapEngine; -import org.bouncycastle.crypto.generators.DESKeyGenerator; -import org.bouncycastle.crypto.generators.DESedeKeyGenerator; -import org.bouncycastle.crypto.modes.CBCBlockCipher; -import org.bouncycastle.crypto.paddings.PKCS7Padding; -import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; -import org.bouncycastle.crypto.params.KeyParameter; -import org.bouncycastle.crypto.params.ParametersWithIV; -import org.bouncycastle.crypto.params.RC2Parameters; - -class EnvelopedDataHelper -{ - protected static final Map BASE_CIPHER_NAMES = new HashMap(); - protected static final Map CIPHER_ALG_NAMES = new HashMap(); - protected static final Map MAC_ALG_NAMES = new HashMap(); - - static - { - BASE_CIPHER_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDE"); - BASE_CIPHER_NAMES.put(CMSAlgorithm.AES128_CBC, "AES"); - BASE_CIPHER_NAMES.put(CMSAlgorithm.AES192_CBC, "AES"); - BASE_CIPHER_NAMES.put(CMSAlgorithm.AES256_CBC, "AES"); - - CIPHER_ALG_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDE/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(CMSAlgorithm.AES128_CBC, "AES/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(CMSAlgorithm.AES192_CBC, "AES/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(CMSAlgorithm.AES256_CBC, "AES/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(new ASN1ObjectIdentifier(PKCSObjectIdentifiers.rsaEncryption.getId()), "RSA/ECB/PKCS1Padding"); - CIPHER_ALG_NAMES.put(CMSAlgorithm.CAST5_CBC, "CAST5/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(CMSAlgorithm.CAMELLIA128_CBC, "Camellia/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(CMSAlgorithm.CAMELLIA192_CBC, "Camellia/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(CMSAlgorithm.CAMELLIA256_CBC, "Camellia/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(CMSAlgorithm.SEED_CBC, "SEED/CBC/PKCS5Padding"); - - MAC_ALG_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDEMac"); - MAC_ALG_NAMES.put(CMSAlgorithm.AES128_CBC, "AESMac"); - MAC_ALG_NAMES.put(CMSAlgorithm.AES192_CBC, "AESMac"); - MAC_ALG_NAMES.put(CMSAlgorithm.AES256_CBC, "AESMac"); - MAC_ALG_NAMES.put(CMSAlgorithm.RC2_CBC, "RC2Mac"); - } - - private static final short[] rc2Table = { - 0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0, - 0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a, - 0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36, - 0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c, - 0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60, - 0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa, - 0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e, - 0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf, - 0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6, - 0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3, - 0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c, - 0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2, - 0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5, - 0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5, - 0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f, - 0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab - }; - - private static final short[] rc2Ekb = { - 0x5d, 0xbe, 0x9b, 0x8b, 0x11, 0x99, 0x6e, 0x4d, 0x59, 0xf3, 0x85, 0xa6, 0x3f, 0xb7, 0x83, 0xc5, - 0xe4, 0x73, 0x6b, 0x3a, 0x68, 0x5a, 0xc0, 0x47, 0xa0, 0x64, 0x34, 0x0c, 0xf1, 0xd0, 0x52, 0xa5, - 0xb9, 0x1e, 0x96, 0x43, 0x41, 0xd8, 0xd4, 0x2c, 0xdb, 0xf8, 0x07, 0x77, 0x2a, 0xca, 0xeb, 0xef, - 0x10, 0x1c, 0x16, 0x0d, 0x38, 0x72, 0x2f, 0x89, 0xc1, 0xf9, 0x80, 0xc4, 0x6d, 0xae, 0x30, 0x3d, - 0xce, 0x20, 0x63, 0xfe, 0xe6, 0x1a, 0xc7, 0xb8, 0x50, 0xe8, 0x24, 0x17, 0xfc, 0x25, 0x6f, 0xbb, - 0x6a, 0xa3, 0x44, 0x53, 0xd9, 0xa2, 0x01, 0xab, 0xbc, 0xb6, 0x1f, 0x98, 0xee, 0x9a, 0xa7, 0x2d, - 0x4f, 0x9e, 0x8e, 0xac, 0xe0, 0xc6, 0x49, 0x46, 0x29, 0xf4, 0x94, 0x8a, 0xaf, 0xe1, 0x5b, 0xc3, - 0xb3, 0x7b, 0x57, 0xd1, 0x7c, 0x9c, 0xed, 0x87, 0x40, 0x8c, 0xe2, 0xcb, 0x93, 0x14, 0xc9, 0x61, - 0x2e, 0xe5, 0xcc, 0xf6, 0x5e, 0xa8, 0x5c, 0xd6, 0x75, 0x8d, 0x62, 0x95, 0x58, 0x69, 0x76, 0xa1, - 0x4a, 0xb5, 0x55, 0x09, 0x78, 0x33, 0x82, 0xd7, 0xdd, 0x79, 0xf5, 0x1b, 0x0b, 0xde, 0x26, 0x21, - 0x28, 0x74, 0x04, 0x97, 0x56, 0xdf, 0x3c, 0xf0, 0x37, 0x39, 0xdc, 0xff, 0x06, 0xa4, 0xea, 0x42, - 0x08, 0xda, 0xb4, 0x71, 0xb0, 0xcf, 0x12, 0x7a, 0x4e, 0xfa, 0x6c, 0x1d, 0x84, 0x00, 0xc8, 0x7f, - 0x91, 0x45, 0xaa, 0x2b, 0xc2, 0xb1, 0x8f, 0xd5, 0xba, 0xf2, 0xad, 0x19, 0xb2, 0x67, 0x36, 0xf7, - 0x0f, 0x0a, 0x92, 0x7d, 0xe3, 0x9d, 0xe9, 0x90, 0x3e, 0x23, 0x27, 0x66, 0x13, 0xec, 0x81, 0x15, - 0xbd, 0x22, 0xbf, 0x9f, 0x7e, 0xa9, 0x51, 0x4b, 0x4c, 0xfb, 0x02, 0xd3, 0x70, 0x86, 0x31, 0xe7, - 0x3b, 0x05, 0x03, 0x54, 0x60, 0x48, 0x65, 0x18, 0xd2, 0xcd, 0x5f, 0x32, 0x88, 0x0e, 0x35, 0xfd - }; - - EnvelopedDataHelper() - { - } - - String getBaseCipherName(ASN1ObjectIdentifier algorithm) - { - String name = (String)BASE_CIPHER_NAMES.get(algorithm); - - if (name == null) - { - return algorithm.getId(); - } - - return name; - } - - static BufferedBlockCipher createCipher(ASN1ObjectIdentifier algorithm) - throws CMSException - { - BlockCipher cipher; - - if (NISTObjectIdentifiers.id_aes128_CBC.equals(algorithm) - || NISTObjectIdentifiers.id_aes192_CBC.equals(algorithm) - || NISTObjectIdentifiers.id_aes256_CBC.equals(algorithm)) - { - cipher = new CBCBlockCipher(new AESEngine()); - } - else if (PKCSObjectIdentifiers.des_EDE3_CBC.equals(algorithm)) - { - cipher = new CBCBlockCipher(new DESedeEngine()); - } - else if (OIWObjectIdentifiers.desCBC.equals(algorithm)) - { - cipher = new CBCBlockCipher(new DESEngine()); - } - else if (PKCSObjectIdentifiers.RC2_CBC.equals(algorithm)) - { - cipher = new CBCBlockCipher(new RC2Engine()); - } - else - { - throw new CMSException("cannot recognise cipher: " + algorithm); - } - - return new PaddedBufferedBlockCipher(cipher, new PKCS7Padding()); - } - - static Wrapper createRFC3211Wrapper(ASN1ObjectIdentifier algorithm) - throws CMSException - { - if (NISTObjectIdentifiers.id_aes128_CBC.equals(algorithm) - || NISTObjectIdentifiers.id_aes192_CBC.equals(algorithm) - || NISTObjectIdentifiers.id_aes256_CBC.equals(algorithm)) - { - return new RFC3211WrapEngine(new AESEngine()); - } - else if (PKCSObjectIdentifiers.des_EDE3_CBC.equals(algorithm)) - { - return new RFC3211WrapEngine(new DESedeEngine()); - } - else if (OIWObjectIdentifiers.desCBC.equals(algorithm)) - { - return new RFC3211WrapEngine(new DESEngine()); - } - else if (PKCSObjectIdentifiers.RC2_CBC.equals(algorithm)) - { - return new RFC3211WrapEngine(new RC2Engine()); - } - else - { - throw new CMSException("cannot recognise wrapper: " + algorithm); - } - } - - static Object createContentCipher(boolean forEncryption, CipherParameters encKey, AlgorithmIdentifier encryptionAlgID) - throws CMSException - { - ASN1ObjectIdentifier encAlg = encryptionAlgID.getAlgorithm(); - - if (encAlg.equals(PKCSObjectIdentifiers.rc4)) - { - StreamCipher cipher = new RC4Engine(); - - cipher.init(forEncryption, encKey); - - return cipher; - } - else - { - BufferedBlockCipher cipher = createCipher(encryptionAlgID.getAlgorithm()); - ASN1Primitive sParams = encryptionAlgID.getParameters().toASN1Primitive(); - - if (sParams != null && !(sParams instanceof ASN1Null)) - { - if (encAlg.equals(CMSAlgorithm.DES_EDE3_CBC) - || encAlg.equals(CMSAlgorithm.IDEA_CBC) - || encAlg.equals(CMSAlgorithm.AES128_CBC) - || encAlg.equals(CMSAlgorithm.AES192_CBC) - || encAlg.equals(CMSAlgorithm.AES256_CBC) - || encAlg.equals(CMSAlgorithm.CAMELLIA128_CBC) - || encAlg.equals(CMSAlgorithm.CAMELLIA192_CBC) - || encAlg.equals(CMSAlgorithm.CAMELLIA256_CBC) - || encAlg.equals(CMSAlgorithm.SEED_CBC) - || encAlg.equals(OIWObjectIdentifiers.desCBC)) - { - cipher.init(forEncryption, new ParametersWithIV(encKey, - ASN1OctetString.getInstance(sParams).getOctets())); - } - else if (encAlg.equals(CMSAlgorithm.CAST5_CBC)) - { - CAST5CBCParameters cbcParams = CAST5CBCParameters.getInstance(sParams); - - cipher.init(forEncryption, new ParametersWithIV(encKey, cbcParams.getIV())); - } - else if (encAlg.equals(CMSAlgorithm.RC2_CBC)) - { - RC2CBCParameter cbcParams = RC2CBCParameter.getInstance(sParams); - - cipher.init(forEncryption, new ParametersWithIV(new RC2Parameters(((KeyParameter)encKey).getKey(), rc2Ekb[cbcParams.getRC2ParameterVersion().intValue()]), cbcParams.getIV())); - } - else - { - throw new CMSException("cannot match parameters"); - } - } - else - { - if (encAlg.equals(CMSAlgorithm.DES_EDE3_CBC) - || encAlg.equals(CMSAlgorithm.IDEA_CBC) - || encAlg.equals(CMSAlgorithm.CAST5_CBC)) - { - cipher.init(forEncryption, new ParametersWithIV(encKey, new byte[8])); - } - else - { - cipher.init(forEncryption, encKey); - } - } - - return cipher; - } - } - - AlgorithmIdentifier generateAlgorithmIdentifier(ASN1ObjectIdentifier encryptionOID, CipherParameters encKey, SecureRandom random) - throws CMSException - { - if (encryptionOID.equals(CMSAlgorithm.AES128_CBC) - || encryptionOID.equals(CMSAlgorithm.AES192_CBC) - || encryptionOID.equals(CMSAlgorithm.AES256_CBC) - || encryptionOID.equals(CMSAlgorithm.CAMELLIA128_CBC) - || encryptionOID.equals(CMSAlgorithm.CAMELLIA192_CBC) - || encryptionOID.equals(CMSAlgorithm.CAMELLIA256_CBC) - || encryptionOID.equals(CMSAlgorithm.SEED_CBC)) - { - byte[] iv = new byte[16]; - - random.nextBytes(iv); - - return new AlgorithmIdentifier(encryptionOID, new DEROctetString(iv)); - } - else if (encryptionOID.equals(CMSAlgorithm.DES_EDE3_CBC) - || encryptionOID.equals(CMSAlgorithm.IDEA_CBC) - || encryptionOID.equals(OIWObjectIdentifiers.desCBC)) - { - byte[] iv = new byte[8]; - - random.nextBytes(iv); - - return new AlgorithmIdentifier(encryptionOID, new DEROctetString(iv)); - } - else if (encryptionOID.equals(CMSAlgorithm.CAST5_CBC)) - { - byte[] iv = new byte[8]; - - random.nextBytes(iv); - - CAST5CBCParameters cbcParams = new CAST5CBCParameters(iv, ((KeyParameter)encKey).getKey().length * 8); - - return new AlgorithmIdentifier(encryptionOID, cbcParams); - } - else if (encryptionOID.equals(PKCSObjectIdentifiers.rc4)) - { - return new AlgorithmIdentifier(encryptionOID, DERNull.INSTANCE); - } - else - { - throw new CMSException("unable to match algorithm"); - } - } - - CipherKeyGenerator createKeyGenerator(ASN1ObjectIdentifier algorithm, SecureRandom random) - throws CMSException - { - if (NISTObjectIdentifiers.id_aes128_CBC.equals(algorithm)) - { - return createCipherKeyGenerator(random, 128); - } - else if (NISTObjectIdentifiers.id_aes192_CBC.equals(algorithm)) - { - return createCipherKeyGenerator(random, 192); - } - else if (NISTObjectIdentifiers.id_aes256_CBC.equals(algorithm)) - { - return createCipherKeyGenerator(random, 256); - } - else if (PKCSObjectIdentifiers.des_EDE3_CBC.equals(algorithm)) - { - DESedeKeyGenerator keyGen = new DESedeKeyGenerator(); - - keyGen.init(new KeyGenerationParameters(random, 192)); - - return keyGen; - } - else if (NTTObjectIdentifiers.id_camellia128_cbc.equals(algorithm)) - { - return createCipherKeyGenerator(random, 128); - } - else if (NTTObjectIdentifiers.id_camellia192_cbc.equals(algorithm)) - { - return createCipherKeyGenerator(random, 192); - } - else if (NTTObjectIdentifiers.id_camellia256_cbc.equals(algorithm)) - { - return createCipherKeyGenerator(random, 256); - } - else if (KISAObjectIdentifiers.id_seedCBC.equals(algorithm)) - { - return createCipherKeyGenerator(random, 128); - } - else if (CMSAlgorithm.CAST5_CBC.equals(algorithm)) - { - return createCipherKeyGenerator(random, 128); - } - else if (OIWObjectIdentifiers.desCBC.equals(algorithm)) - { - DESKeyGenerator keyGen = new DESKeyGenerator(); - - keyGen.init(new KeyGenerationParameters(random, 64)); - - return keyGen; - } - else if (PKCSObjectIdentifiers.rc4.equals(algorithm)) - { - return createCipherKeyGenerator(random, 128); - } -// else if (PKCSObjectIdentifiers.RC2_CBC.equals(algorithm)) -// { -// cipher = new CBCBlockCipher(new RC2Engine()); -// } - else - { - throw new CMSException("cannot recognise cipher: " + algorithm); - } - - } - - private CipherKeyGenerator createCipherKeyGenerator(SecureRandom random, int keySize) - { - CipherKeyGenerator keyGen = new CipherKeyGenerator(); - - keyGen.init(new KeyGenerationParameters(random, keySize)); - - return keyGen; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/CMSUtils.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/CMSUtils.java deleted file mode 100644 index 1596caee..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/CMSUtils.java +++ /dev/null @@ -1,99 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.io.IOException; -import java.security.AlgorithmParameters; -import java.security.Provider; -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.cms.IssuerAndSerialNumber; -import org.bouncycastle.asn1.x509.Certificate; -import org.bouncycastle.asn1.x509.Extension; -import org.bouncycastle.asn1.x509.TBSCertificateStructure; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.jcajce.util.JcaJceUtils; - -class CMSUtils -{ - static TBSCertificateStructure getTBSCertificateStructure( - X509Certificate cert) - throws CertificateEncodingException - { - return TBSCertificateStructure.getInstance(cert.getTBSCertificate()); - } - - static IssuerAndSerialNumber getIssuerAndSerialNumber(X509Certificate cert) - throws CertificateEncodingException - { - Certificate certStruct = Certificate.getInstance(cert.getEncoded()); - - return new IssuerAndSerialNumber(certStruct.getIssuer(), cert.getSerialNumber()); - } - - - static byte[] getSubjectKeyId(X509Certificate cert) - { - byte[] ext = cert.getExtensionValue(Extension.subjectKeyIdentifier.getId()); - - if (ext != null) - { - return ASN1OctetString.getInstance(ASN1OctetString.getInstance(ext).getOctets()).getOctets(); - } - else - { - return null; - } - } - - static EnvelopedDataHelper createContentHelper(Provider provider) - { - if (provider != null) - { - return new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); - } - else - { - return new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); - } - } - - static EnvelopedDataHelper createContentHelper(String providerName) - { - if (providerName != null) - { - return new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); - } - else - { - return new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); - } - } - - static ASN1Encodable extractParameters(AlgorithmParameters params) - throws CMSException - { - try - { - return JcaJceUtils.extractParameters(params); - } - catch (IOException e) - { - throw new CMSException("cannot extract parameters: " + e.getMessage(), e); - } - } - - static void loadParameters(AlgorithmParameters params, ASN1Encodable sParams) - throws CMSException - { - try - { - JcaJceUtils.loadParameters(params, sParams); - } - catch (IOException e) - { - throw new CMSException("error encoding algorithm parameters.", e); - } - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/DefaultJcaJceExtHelper.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/DefaultJcaJceExtHelper.java deleted file mode 100644 index c6cd8257..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/DefaultJcaJceExtHelper.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.security.PrivateKey; - -import javax.crypto.SecretKey; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; -import org.bouncycastle.operator.SymmetricKeyUnwrapper; -import org.bouncycastle.operator.jcajce.JceAsymmetricKeyUnwrapper; -import org.bouncycastle.operator.jcajce.JceSymmetricKeyUnwrapper; - -class DefaultJcaJceExtHelper - extends DefaultJcaJceHelper - implements JcaJceExtHelper -{ - public JceAsymmetricKeyUnwrapper createAsymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, PrivateKey keyEncryptionKey) - { - return new JceAsymmetricKeyUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey); - } - - public SymmetricKeyUnwrapper createSymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, SecretKey keyEncryptionKey) - { - return new JceSymmetricKeyUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/EnvelopedDataHelper.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/EnvelopedDataHelper.java deleted file mode 100644 index b0810515..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/EnvelopedDataHelper.java +++ /dev/null @@ -1,668 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.security.AlgorithmParameterGenerator; -import java.security.AlgorithmParameters; -import java.security.GeneralSecurityException; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.KeyFactory; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PrivateKey; -import java.security.SecureRandom; -import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.InvalidParameterSpecException; -import java.util.HashMap; -import java.util.Map; - -import javax.crypto.Cipher; -import javax.crypto.KeyAgreement; -import javax.crypto.KeyGenerator; -import javax.crypto.Mac; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.SecretKey; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.RC2ParameterSpec; -import javax.crypto.spec.SecretKeySpec; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1Null; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.RC2CBCParameter; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSAlgorithm; -import org.bouncycastle.cms.CMSEnvelopedDataGenerator; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.operator.DefaultSecretKeySizeProvider; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.SecretKeySizeProvider; -import org.bouncycastle.operator.SymmetricKeyUnwrapper; -import org.bouncycastle.operator.jcajce.JceAsymmetricKeyUnwrapper; - -public class EnvelopedDataHelper -{ - protected static final SecretKeySizeProvider KEY_SIZE_PROVIDER = DefaultSecretKeySizeProvider.INSTANCE; - - protected static final Map BASE_CIPHER_NAMES = new HashMap(); - protected static final Map CIPHER_ALG_NAMES = new HashMap(); - protected static final Map MAC_ALG_NAMES = new HashMap(); - - static - { - BASE_CIPHER_NAMES.put(CMSAlgorithm.DES_CBC, "DES"); - BASE_CIPHER_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDE"); - BASE_CIPHER_NAMES.put(CMSAlgorithm.AES128_CBC, "AES"); - BASE_CIPHER_NAMES.put(CMSAlgorithm.AES192_CBC, "AES"); - BASE_CIPHER_NAMES.put(CMSAlgorithm.AES256_CBC, "AES"); - BASE_CIPHER_NAMES.put(CMSAlgorithm.RC2_CBC, "RC2"); - BASE_CIPHER_NAMES.put(CMSAlgorithm.CAST5_CBC, "CAST5"); - BASE_CIPHER_NAMES.put(CMSAlgorithm.CAMELLIA128_CBC, "Camellia"); - BASE_CIPHER_NAMES.put(CMSAlgorithm.CAMELLIA192_CBC, "Camellia"); - BASE_CIPHER_NAMES.put(CMSAlgorithm.CAMELLIA256_CBC, "Camellia"); - BASE_CIPHER_NAMES.put(CMSAlgorithm.SEED_CBC, "SEED"); - BASE_CIPHER_NAMES.put(PKCSObjectIdentifiers.rc4, "RC4"); - - CIPHER_ALG_NAMES.put(CMSAlgorithm.DES_CBC, "DES/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(CMSAlgorithm.RC2_CBC, "RC2/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDE/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(CMSAlgorithm.AES128_CBC, "AES/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(CMSAlgorithm.AES192_CBC, "AES/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(CMSAlgorithm.AES256_CBC, "AES/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(PKCSObjectIdentifiers.rsaEncryption, "RSA/ECB/PKCS1Padding"); - CIPHER_ALG_NAMES.put(CMSAlgorithm.CAST5_CBC, "CAST5/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(CMSAlgorithm.CAMELLIA128_CBC, "Camellia/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(CMSAlgorithm.CAMELLIA192_CBC, "Camellia/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(CMSAlgorithm.CAMELLIA256_CBC, "Camellia/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(CMSAlgorithm.SEED_CBC, "SEED/CBC/PKCS5Padding"); - CIPHER_ALG_NAMES.put(PKCSObjectIdentifiers.rc4, "RC4"); - - MAC_ALG_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDEMac"); - MAC_ALG_NAMES.put(CMSAlgorithm.AES128_CBC, "AESMac"); - MAC_ALG_NAMES.put(CMSAlgorithm.AES192_CBC, "AESMac"); - MAC_ALG_NAMES.put(CMSAlgorithm.AES256_CBC, "AESMac"); - MAC_ALG_NAMES.put(CMSAlgorithm.RC2_CBC, "RC2Mac"); - } - - private static final short[] rc2Table = { - 0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0, - 0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a, - 0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36, - 0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c, - 0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60, - 0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa, - 0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e, - 0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf, - 0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6, - 0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3, - 0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c, - 0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2, - 0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5, - 0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5, - 0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f, - 0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab - }; - - private static final short[] rc2Ekb = { - 0x5d, 0xbe, 0x9b, 0x8b, 0x11, 0x99, 0x6e, 0x4d, 0x59, 0xf3, 0x85, 0xa6, 0x3f, 0xb7, 0x83, 0xc5, - 0xe4, 0x73, 0x6b, 0x3a, 0x68, 0x5a, 0xc0, 0x47, 0xa0, 0x64, 0x34, 0x0c, 0xf1, 0xd0, 0x52, 0xa5, - 0xb9, 0x1e, 0x96, 0x43, 0x41, 0xd8, 0xd4, 0x2c, 0xdb, 0xf8, 0x07, 0x77, 0x2a, 0xca, 0xeb, 0xef, - 0x10, 0x1c, 0x16, 0x0d, 0x38, 0x72, 0x2f, 0x89, 0xc1, 0xf9, 0x80, 0xc4, 0x6d, 0xae, 0x30, 0x3d, - 0xce, 0x20, 0x63, 0xfe, 0xe6, 0x1a, 0xc7, 0xb8, 0x50, 0xe8, 0x24, 0x17, 0xfc, 0x25, 0x6f, 0xbb, - 0x6a, 0xa3, 0x44, 0x53, 0xd9, 0xa2, 0x01, 0xab, 0xbc, 0xb6, 0x1f, 0x98, 0xee, 0x9a, 0xa7, 0x2d, - 0x4f, 0x9e, 0x8e, 0xac, 0xe0, 0xc6, 0x49, 0x46, 0x29, 0xf4, 0x94, 0x8a, 0xaf, 0xe1, 0x5b, 0xc3, - 0xb3, 0x7b, 0x57, 0xd1, 0x7c, 0x9c, 0xed, 0x87, 0x40, 0x8c, 0xe2, 0xcb, 0x93, 0x14, 0xc9, 0x61, - 0x2e, 0xe5, 0xcc, 0xf6, 0x5e, 0xa8, 0x5c, 0xd6, 0x75, 0x8d, 0x62, 0x95, 0x58, 0x69, 0x76, 0xa1, - 0x4a, 0xb5, 0x55, 0x09, 0x78, 0x33, 0x82, 0xd7, 0xdd, 0x79, 0xf5, 0x1b, 0x0b, 0xde, 0x26, 0x21, - 0x28, 0x74, 0x04, 0x97, 0x56, 0xdf, 0x3c, 0xf0, 0x37, 0x39, 0xdc, 0xff, 0x06, 0xa4, 0xea, 0x42, - 0x08, 0xda, 0xb4, 0x71, 0xb0, 0xcf, 0x12, 0x7a, 0x4e, 0xfa, 0x6c, 0x1d, 0x84, 0x00, 0xc8, 0x7f, - 0x91, 0x45, 0xaa, 0x2b, 0xc2, 0xb1, 0x8f, 0xd5, 0xba, 0xf2, 0xad, 0x19, 0xb2, 0x67, 0x36, 0xf7, - 0x0f, 0x0a, 0x92, 0x7d, 0xe3, 0x9d, 0xe9, 0x90, 0x3e, 0x23, 0x27, 0x66, 0x13, 0xec, 0x81, 0x15, - 0xbd, 0x22, 0xbf, 0x9f, 0x7e, 0xa9, 0x51, 0x4b, 0x4c, 0xfb, 0x02, 0xd3, 0x70, 0x86, 0x31, 0xe7, - 0x3b, 0x05, 0x03, 0x54, 0x60, 0x48, 0x65, 0x18, 0xd2, 0xcd, 0x5f, 0x32, 0x88, 0x0e, 0x35, 0xfd - }; - - private JcaJceExtHelper helper; - - EnvelopedDataHelper(JcaJceExtHelper helper) - { - this.helper = helper; - } - - String getBaseCipherName(ASN1ObjectIdentifier algorithm) - { - String name = (String)BASE_CIPHER_NAMES.get(algorithm); - - if (name == null) - { - return algorithm.getId(); - } - - return name; - } - - Key getJceKey(GenericKey key) - { - if (key.getRepresentation() instanceof Key) - { - return (Key)key.getRepresentation(); - } - - if (key.getRepresentation() instanceof byte[]) - { - return new SecretKeySpec((byte[])key.getRepresentation(), "ENC"); - } - - throw new IllegalArgumentException("unknown generic key type"); - } - - public Key getJceKey(ASN1ObjectIdentifier algorithm, GenericKey key) - { - if (key.getRepresentation() instanceof Key) - { - return (Key)key.getRepresentation(); - } - - if (key.getRepresentation() instanceof byte[]) - { - return new SecretKeySpec((byte[])key.getRepresentation(), getBaseCipherName(algorithm)); - } - - throw new IllegalArgumentException("unknown generic key type"); - } - - public void keySizeCheck(AlgorithmIdentifier keyAlgorithm, Key key) - throws CMSException - { - int expectedKeySize = EnvelopedDataHelper.KEY_SIZE_PROVIDER.getKeySize(keyAlgorithm); - if (expectedKeySize > 0) - { - byte[] keyEnc = null; - - try - { - keyEnc = key.getEncoded(); - } - catch (Exception e) - { - // ignore - we're using a HSM... - } - - if (keyEnc != null) - { - if (keyEnc.length * 8 != expectedKeySize) - { - throw new CMSException("Expected key size for algorithm OID not found in recipient."); - } - } - } - } - - Cipher createCipher(ASN1ObjectIdentifier algorithm) - throws CMSException - { - try - { - String cipherName = (String)CIPHER_ALG_NAMES.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 CMSException("cannot create cipher: " + e.getMessage(), e); - } - } - - Mac createMac(ASN1ObjectIdentifier algorithm) - throws CMSException - { - try - { - String macName = (String)MAC_ALG_NAMES.get(algorithm); - - if (macName != null) - { - try - { - // this is reversed as the Sun policy files now allow unlimited strength RSA - return helper.createMac(macName); - } - catch (NoSuchAlgorithmException e) - { - // Ignore - } - } - return helper.createMac(algorithm.getId()); - } - catch (GeneralSecurityException e) - { - throw new CMSException("cannot create mac: " + e.getMessage(), e); - } - } - - Cipher createRFC3211Wrapper(ASN1ObjectIdentifier algorithm) - throws CMSException - { - String cipherName = (String)BASE_CIPHER_NAMES.get(algorithm); - - if (cipherName == null) - { - throw new CMSException("no name for " + algorithm); - } - - cipherName += "RFC3211Wrap"; - - try - { - return helper.createCipher(cipherName); - } - catch (GeneralSecurityException e) - { - throw new CMSException("cannot create cipher: " + e.getMessage(), e); - } - } - - KeyAgreement createKeyAgreement(ASN1ObjectIdentifier algorithm) - throws CMSException - { - try - { - String agreementName = (String)BASE_CIPHER_NAMES.get(algorithm); - - if (agreementName != null) - { - try - { - // this is reversed as the Sun policy files now allow unlimited strength RSA - return helper.createKeyAgreement(agreementName); - } - catch (NoSuchAlgorithmException e) - { - // Ignore - } - } - return helper.createKeyAgreement(algorithm.getId()); - } - catch (GeneralSecurityException e) - { - throw new CMSException("cannot create key pair generator: " + e.getMessage(), e); - } - } - - AlgorithmParameterGenerator createAlgorithmParameterGenerator(ASN1ObjectIdentifier algorithm) - throws GeneralSecurityException - { - String algorithmName = (String)BASE_CIPHER_NAMES.get(algorithm); - - if (algorithmName != null) - { - try - { - // this is reversed as the Sun policy files now allow unlimited strength RSA - return helper.createAlgorithmParameterGenerator(algorithmName); - } - catch (NoSuchAlgorithmException e) - { - // Ignore - } - } - return helper.createAlgorithmParameterGenerator(algorithm.getId()); - } - - public Cipher createContentCipher(final Key sKey, final AlgorithmIdentifier encryptionAlgID) - throws CMSException - { - return (Cipher)execute(new JCECallback() - { - public Object doInJCE() - throws CMSException, InvalidAlgorithmParameterException, - InvalidKeyException, InvalidParameterSpecException, NoSuchAlgorithmException, - NoSuchPaddingException, NoSuchProviderException - { - Cipher cipher = createCipher(encryptionAlgID.getAlgorithm()); - ASN1Encodable sParams = encryptionAlgID.getParameters(); - String encAlg = encryptionAlgID.getAlgorithm().getId(); - - if (sParams != null && !(sParams instanceof ASN1Null)) - { - try - { - AlgorithmParameters params = createAlgorithmParameters(encryptionAlgID.getAlgorithm()); - - CMSUtils.loadParameters(params, sParams); - - cipher.init(Cipher.DECRYPT_MODE, sKey, params); - } - catch (NoSuchAlgorithmException e) - { - if (encAlg.equals(CMSAlgorithm.DES_CBC.getId()) - || encAlg.equals(CMSEnvelopedDataGenerator.DES_EDE3_CBC) - || encAlg.equals(CMSEnvelopedDataGenerator.IDEA_CBC) - || encAlg.equals(CMSEnvelopedDataGenerator.AES128_CBC) - || encAlg.equals(CMSEnvelopedDataGenerator.AES192_CBC) - || encAlg.equals(CMSEnvelopedDataGenerator.AES256_CBC)) - { - cipher.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec( - ASN1OctetString.getInstance(sParams).getOctets())); - } - else - { - throw e; - } - } - } - else - { - if (encAlg.equals(CMSAlgorithm.DES_CBC.getId()) - || encAlg.equals(CMSEnvelopedDataGenerator.DES_EDE3_CBC) - || encAlg.equals(CMSEnvelopedDataGenerator.IDEA_CBC) - || encAlg.equals(CMSEnvelopedDataGenerator.CAST5_CBC)) - { - cipher.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec(new byte[8])); - } - else - { - cipher.init(Cipher.DECRYPT_MODE, sKey); - } - } - - return cipher; - } - }); - } - - Mac createContentMac(final Key sKey, final AlgorithmIdentifier macAlgId) - throws CMSException - { - return (Mac)execute(new JCECallback() - { - public Object doInJCE() - throws CMSException, InvalidAlgorithmParameterException, - InvalidKeyException, InvalidParameterSpecException, NoSuchAlgorithmException, - NoSuchPaddingException, NoSuchProviderException - { - Mac mac = createMac(macAlgId.getAlgorithm()); - ASN1Encodable sParams = macAlgId.getParameters(); - String macAlg = macAlgId.getAlgorithm().getId(); - - if (sParams != null && !(sParams instanceof ASN1Null)) - { - try - { - AlgorithmParameters params = createAlgorithmParameters(macAlgId.getAlgorithm()); - - CMSUtils.loadParameters(params, sParams); - - mac.init(sKey, params.getParameterSpec(IvParameterSpec.class)); - } - catch (NoSuchAlgorithmException e) - { - throw e; - } - } - else - { - mac.init(sKey); - } - - return mac; - } - }); - } - - AlgorithmParameters createAlgorithmParameters(ASN1ObjectIdentifier algorithm) - throws NoSuchAlgorithmException, NoSuchProviderException - { - String algorithmName = (String)BASE_CIPHER_NAMES.get(algorithm); - - if (algorithmName != null) - { - try - { - // this is reversed as the Sun policy files now allow unlimited strength RSA - return helper.createAlgorithmParameters(algorithmName); - } - catch (NoSuchAlgorithmException e) - { - // Ignore - } - } - return helper.createAlgorithmParameters(algorithm.getId()); - } - - - KeyPairGenerator createKeyPairGenerator(ASN1ObjectIdentifier algorithm) - throws CMSException - { - try - { - String cipherName = (String)BASE_CIPHER_NAMES.get(algorithm); - - if (cipherName != null) - { - try - { - // this is reversed as the Sun policy files now allow unlimited strength RSA - return helper.createKeyPairGenerator(cipherName); - } - catch (NoSuchAlgorithmException e) - { - // Ignore - } - } - return helper.createKeyPairGenerator(algorithm.getId()); - } - catch (GeneralSecurityException e) - { - throw new CMSException("cannot create key pair generator: " + e.getMessage(), e); - } - } - - public KeyGenerator createKeyGenerator(ASN1ObjectIdentifier algorithm) - throws CMSException - { - try - { - String cipherName = (String)BASE_CIPHER_NAMES.get(algorithm); - - if (cipherName != null) - { - try - { - // this is reversed as the Sun policy files now allow unlimited strength RSA - return helper.createKeyGenerator(cipherName); - } - catch (NoSuchAlgorithmException e) - { - // Ignore - } - } - return helper.createKeyGenerator(algorithm.getId()); - } - catch (GeneralSecurityException e) - { - throw new CMSException("cannot create key generator: " + e.getMessage(), e); - } - } - - AlgorithmParameters generateParameters(ASN1ObjectIdentifier encryptionOID, SecretKey encKey, SecureRandom rand) - throws CMSException - { - try - { - AlgorithmParameterGenerator pGen = createAlgorithmParameterGenerator(encryptionOID); - - if (encryptionOID.equals(CMSAlgorithm.RC2_CBC)) - { - byte[] iv = new byte[8]; - - rand.nextBytes(iv); - - try - { - pGen.init(new RC2ParameterSpec(encKey.getEncoded().length * 8, iv), rand); - } - catch (InvalidAlgorithmParameterException e) - { - throw new CMSException("parameters generation error: " + e, e); - } - } - - return pGen.generateParameters(); - } - catch (NoSuchAlgorithmException e) - { - return null; - } - catch (GeneralSecurityException e) - { - throw new CMSException("exception creating algorithm parameter generator: " + e, e); - } - } - - AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier encryptionOID, AlgorithmParameters params) - throws CMSException - { - ASN1Encodable asn1Params; - if (params != null) - { - asn1Params = CMSUtils.extractParameters(params); - } - else - { - asn1Params = DERNull.INSTANCE; - } - - return new AlgorithmIdentifier( - encryptionOID, - asn1Params); - } - - static Object execute(JCECallback callback) throws CMSException - { - try - { - return callback.doInJCE(); - } - catch (NoSuchAlgorithmException e) - { - throw new CMSException("can't find algorithm.", e); - } - catch (InvalidKeyException e) - { - throw new CMSException("key invalid in message.", e); - } - catch (NoSuchProviderException e) - { - throw new CMSException("can't find provider.", e); - } - catch (NoSuchPaddingException e) - { - throw new CMSException("required padding not supported.", e); - } - catch (InvalidAlgorithmParameterException e) - { - throw new CMSException("algorithm parameters invalid.", e); - } - catch (InvalidParameterSpecException e) - { - throw new CMSException("MAC algorithm parameter spec invalid.", e); - } - } - - public KeyFactory createKeyFactory(ASN1ObjectIdentifier algorithm) - throws CMSException - { - try - { - String cipherName = (String)BASE_CIPHER_NAMES.get(algorithm); - - if (cipherName != null) - { - try - { - // this is reversed as the Sun policy files now allow unlimited strength RSA - return helper.createKeyFactory(cipherName); - } - catch (NoSuchAlgorithmException e) - { - // Ignore - } - } - return helper.createKeyFactory(algorithm.getId()); - } - catch (GeneralSecurityException e) - { - throw new CMSException("cannot create key factory: " + e.getMessage(), e); - } - } - - public JceAsymmetricKeyUnwrapper createAsymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, PrivateKey keyEncryptionKey) - { - return helper.createAsymmetricUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey); - } - - public SymmetricKeyUnwrapper createSymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, SecretKey keyEncryptionKey) - { - return helper.createSymmetricUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey); - } - - public AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier macOID, AlgorithmParameterSpec paramSpec) - { - if (paramSpec instanceof IvParameterSpec) - { - return new AlgorithmIdentifier(macOID, new DEROctetString(((IvParameterSpec)paramSpec).getIV())); - } - - if (paramSpec instanceof RC2ParameterSpec) - { - RC2ParameterSpec rc2Spec = (RC2ParameterSpec)paramSpec; - - int effKeyBits = ((RC2ParameterSpec)paramSpec).getEffectiveKeyBits(); - - if (effKeyBits != -1) - { - int parameterVersion; - - if (effKeyBits < 256) - { - parameterVersion = rc2Table[effKeyBits]; - } - else - { - parameterVersion = effKeyBits; - } - - return new AlgorithmIdentifier(macOID, new RC2CBCParameter(parameterVersion, rc2Spec.getIV())); - } - - return new AlgorithmIdentifier(macOID, new RC2CBCParameter(rc2Spec.getIV())); - } - - throw new IllegalStateException("unknown parameter spec: " + paramSpec); - } - - static interface JCECallback - { - Object doInJCE() - throws CMSException, InvalidAlgorithmParameterException, InvalidKeyException, InvalidParameterSpecException, - NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaJceExtHelper.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaJceExtHelper.java deleted file mode 100644 index 3eb54a10..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaJceExtHelper.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.security.PrivateKey; - -import javax.crypto.SecretKey; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.jcajce.util.JcaJceHelper; -import org.bouncycastle.operator.SymmetricKeyUnwrapper; -import org.bouncycastle.operator.jcajce.JceAsymmetricKeyUnwrapper; - -public interface JcaJceExtHelper - extends JcaJceHelper -{ - JceAsymmetricKeyUnwrapper createAsymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, PrivateKey keyEncryptionKey); - - SymmetricKeyUnwrapper createSymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, SecretKey keyEncryptionKey); -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSelectorConverter.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSelectorConverter.java deleted file mode 100644 index a26cbe70..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSelectorConverter.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.io.IOException; -import java.security.cert.X509CertSelector; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.cms.KeyTransRecipientId; -import org.bouncycastle.cms.SignerId; - -public class JcaSelectorConverter -{ - public JcaSelectorConverter() - { - - } - - public SignerId getSignerId(X509CertSelector certSelector) - { - try - { - if (certSelector.getSubjectKeyIdentifier() != null) - { - return new SignerId(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber(), ASN1OctetString.getInstance(certSelector.getSubjectKeyIdentifier()).getOctets()); - } - else - { - return new SignerId(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber()); - } - } - catch (IOException e) - { - throw new IllegalArgumentException("unable to convert issuer: " + e.getMessage()); - } - } - - public KeyTransRecipientId getKeyTransRecipientId(X509CertSelector certSelector) - { - try - { - if (certSelector.getSubjectKeyIdentifier() != null) - { - return new KeyTransRecipientId(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber(), ASN1OctetString.getInstance(certSelector.getSubjectKeyIdentifier()).getOctets()); - } - else - { - return new KeyTransRecipientId(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber()); - } - } - catch (IOException e) - { - throw new IllegalArgumentException("unable to convert issuer: " + e.getMessage()); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSignerId.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSignerId.java deleted file mode 100644 index 056f7c06..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSignerId.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.math.BigInteger; -import java.security.cert.X509Certificate; - -import javax.security.auth.x500.X500Principal; - -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.cms.SignerId; - -public class JcaSignerId - extends SignerId -{ - /** - * Construct a signer identifier based on the issuer, serial number and subject key identifier (if present) of the passed in - * certificate. - * - * @param certificate certificate providing the issue and serial number and subject key identifier. - */ - public JcaSignerId(X509Certificate certificate) - { - super(convertPrincipal(certificate.getIssuerX500Principal()), certificate.getSerialNumber(), CMSUtils.getSubjectKeyId(certificate)); - } - - /** - * Construct a signer identifier based on the provided issuer and serial number.. - * - * @param issuer the issuer to use. - * @param serialNumber the serial number to use. - */ - public JcaSignerId(X500Principal issuer, BigInteger serialNumber) - { - super(convertPrincipal(issuer), serialNumber); - } - - /** - * Construct a signer identifier based on the provided issuer, serial number, and subjectKeyId.. - * - * @param issuer the issuer to use. - * @param serialNumber the serial number to use. - * @param subjectKeyId the subject key ID to use. - */ - public JcaSignerId(X500Principal issuer, BigInteger serialNumber, byte[] subjectKeyId) - { - super(convertPrincipal(issuer), serialNumber, subjectKeyId); - } - - private static X500Name convertPrincipal(X500Principal issuer) - { - if (issuer == null) - { - return null; - } - return X500Name.getInstance(issuer.getEncoded()); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSignerInfoGeneratorBuilder.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSignerInfoGeneratorBuilder.java deleted file mode 100644 index 4a0e7ca4..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSignerInfoGeneratorBuilder.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; - -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; -import org.bouncycastle.cms.CMSAttributeTableGenerator; -import org.bouncycastle.cms.SignerInfoGenerator; -import org.bouncycastle.cms.SignerInfoGeneratorBuilder; -import org.bouncycastle.operator.ContentSigner; -import org.bouncycastle.operator.DigestCalculatorProvider; -import org.bouncycastle.operator.OperatorCreationException; - -public class JcaSignerInfoGeneratorBuilder -{ - private SignerInfoGeneratorBuilder builder; - - public JcaSignerInfoGeneratorBuilder(DigestCalculatorProvider digestProvider) - { - builder = new SignerInfoGeneratorBuilder(digestProvider); - } - - /** - * 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/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSignerInfoVerifierBuilder.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSignerInfoVerifierBuilder.java deleted file mode 100644 index a8058398..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSignerInfoVerifierBuilder.java +++ /dev/null @@ -1,180 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.security.Provider; -import java.security.PublicKey; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; - -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cms.CMSSignatureAlgorithmNameGenerator; -import org.bouncycastle.cms.DefaultCMSSignatureAlgorithmNameGenerator; -import org.bouncycastle.cms.SignerInformationVerifier; -import org.bouncycastle.operator.ContentVerifierProvider; -import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; -import org.bouncycastle.operator.DigestCalculatorProvider; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.operator.SignatureAlgorithmIdentifierFinder; -import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder; -import 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/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSimpleSignerInfoGeneratorBuilder.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSimpleSignerInfoGeneratorBuilder.java deleted file mode 100644 index 0de417aa..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSimpleSignerInfoGeneratorBuilder.java +++ /dev/null @@ -1,202 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.security.PrivateKey; -import java.security.Provider; -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; - -import org.bouncycastle.asn1.cms.AttributeTable; -import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; -import org.bouncycastle.cms.CMSAttributeTableGenerator; -import org.bouncycastle.cms.DefaultSignedAttributeTableGenerator; -import org.bouncycastle.cms.SignerInfoGenerator; -import org.bouncycastle.cms.SignerInfoGeneratorBuilder; -import org.bouncycastle.operator.ContentSigner; -import org.bouncycastle.operator.DigestCalculatorProvider; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; -import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; - -/** - * Use this class if you are using a provider that has all the facilities you - * need. - * <p> - * For example: - * <pre> - * 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)); - * </pre> - * becomes: - * <pre> - * CMSSignedDataGenerator gen = new CMSSignedDataGenerator(); - * - * gen.addSignerInfoGenerator( - * new JcaSimpleSignerInfoGeneratorBuilder() - * .setProvider("BC") - * .build("SHA1withRSA", signKP.getPrivate(), signCert)); - * </pre> - */ -public class JcaSimpleSignerInfoGeneratorBuilder -{ - private Helper helper; - - private boolean hasNoSignedAttributes; - private CMSAttributeTableGenerator signedGen; - private CMSAttributeTableGenerator unsignedGen; - - public JcaSimpleSignerInfoGeneratorBuilder() - throws OperatorCreationException - { - this.helper = new Helper(); - } - - public JcaSimpleSignerInfoGeneratorBuilder setProvider(String providerName) - throws OperatorCreationException - { - this.helper = new NamedHelper(providerName); - - return this; - } - - public JcaSimpleSignerInfoGeneratorBuilder setProvider(Provider provider) - throws OperatorCreationException - { - this.helper = new ProviderHelper(provider); - - return this; - } - - /** - * 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 JcaSimpleSignerInfoGeneratorBuilder setDirectSignature(boolean hasNoSignedAttributes) - { - this.hasNoSignedAttributes = hasNoSignedAttributes; - - return this; - } - - public JcaSimpleSignerInfoGeneratorBuilder setSignedAttributeGenerator(CMSAttributeTableGenerator signedGen) - { - this.signedGen = signedGen; - - return this; - } - - /** - * set up a DefaultSignedAttributeTableGenerator primed with the passed in AttributeTable. - * - * @param attrTable table of attributes for priming generator - * @return this. - */ - public JcaSimpleSignerInfoGeneratorBuilder setSignedAttributeGenerator(AttributeTable attrTable) - { - this.signedGen = new DefaultSignedAttributeTableGenerator(attrTable); - - return this; - } - - public JcaSimpleSignerInfoGeneratorBuilder setUnsignedAttributeGenerator(CMSAttributeTableGenerator unsignedGen) - { - this.unsignedGen = unsignedGen; - - return this; - } - - public SignerInfoGenerator build(String algorithmName, PrivateKey privateKey, X509Certificate certificate) - throws OperatorCreationException, CertificateEncodingException - { - ContentSigner contentSigner = helper.createContentSigner(algorithmName, privateKey); - - return configureAndBuild().build(contentSigner, new JcaX509CertificateHolder(certificate)); - } - - public SignerInfoGenerator build(String algorithmName, PrivateKey privateKey, byte[] keyIdentifier) - throws OperatorCreationException, CertificateEncodingException - { - ContentSigner contentSigner = helper.createContentSigner(algorithmName, privateKey); - - return configureAndBuild().build(contentSigner, keyIdentifier); - } - - private SignerInfoGeneratorBuilder configureAndBuild() - throws OperatorCreationException - { - SignerInfoGeneratorBuilder infoGeneratorBuilder = new SignerInfoGeneratorBuilder(helper.createDigestCalculatorProvider()); - - infoGeneratorBuilder.setDirectSignature(hasNoSignedAttributes); - infoGeneratorBuilder.setSignedAttributeGenerator(signedGen); - infoGeneratorBuilder.setUnsignedAttributeGenerator(unsignedGen); - - return infoGeneratorBuilder; - } - - private class Helper - { - ContentSigner createContentSigner(String algorithm, PrivateKey privateKey) - throws OperatorCreationException - { - return new JcaContentSignerBuilder(algorithm).build(privateKey); - } - - DigestCalculatorProvider createDigestCalculatorProvider() - throws OperatorCreationException - { - return new JcaDigestCalculatorProviderBuilder().build(); - } - } - - private class NamedHelper - extends Helper - { - private final String providerName; - - public NamedHelper(String providerName) - { - this.providerName = providerName; - } - - ContentSigner createContentSigner(String algorithm, PrivateKey privateKey) - throws OperatorCreationException - { - return new JcaContentSignerBuilder(algorithm).setProvider(providerName).build(privateKey); - } - - DigestCalculatorProvider createDigestCalculatorProvider() - throws OperatorCreationException - { - return new JcaDigestCalculatorProviderBuilder().setProvider(providerName).build(); - } - } - - private class ProviderHelper - extends Helper - { - private final Provider provider; - - public ProviderHelper(Provider provider) - { - this.provider = provider; - } - - ContentSigner createContentSigner(String algorithm, PrivateKey privateKey) - throws OperatorCreationException - { - return new JcaContentSignerBuilder(algorithm).setProvider(provider).build(privateKey); - } - - DigestCalculatorProvider createDigestCalculatorProvider() - throws OperatorCreationException - { - return new JcaDigestCalculatorProviderBuilder().setProvider(provider).build(); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSimpleSignerInfoVerifierBuilder.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSimpleSignerInfoVerifierBuilder.java deleted file mode 100644 index 441f27d2..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSimpleSignerInfoVerifierBuilder.java +++ /dev/null @@ -1,150 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.security.Provider; -import java.security.PublicKey; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; - -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cms.DefaultCMSSignatureAlgorithmNameGenerator; -import org.bouncycastle.cms.SignerInformationVerifier; -import org.bouncycastle.operator.ContentVerifierProvider; -import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; -import org.bouncycastle.operator.DigestCalculatorProvider; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder; -import 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/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaX509CertSelectorConverter.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaX509CertSelectorConverter.java deleted file mode 100644 index 86f59f69..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaX509CertSelectorConverter.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.security.cert.X509CertSelector; - -import org.bouncycastle.cms.KeyTransRecipientId; -import org.bouncycastle.cms.SignerId; - -public class JcaX509CertSelectorConverter - extends org.bouncycastle.cert.selector.jcajce.JcaX509CertSelectorConverter -{ - public JcaX509CertSelectorConverter() - { - } - - public X509CertSelector getCertSelector(KeyTransRecipientId recipientId) - { - return doConversion(recipientId.getIssuer(), recipientId.getSerialNumber(), recipientId.getSubjectKeyIdentifier()); - } - - public X509CertSelector getCertSelector(SignerId signerId) - { - return doConversion(signerId.getIssuer(), signerId.getSerialNumber(), signerId.getSubjectKeyIdentifier()); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceAlgorithmIdentifierConverter.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceAlgorithmIdentifierConverter.java deleted file mode 100644 index 59928f45..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceAlgorithmIdentifierConverter.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.bouncycastle.cms.jcajce; - - -import java.security.AlgorithmParameters; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.Provider; -import java.security.SecureRandom; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSException; - -public class JceAlgorithmIdentifierConverter -{ - private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); - private SecureRandom random; - - public JceAlgorithmIdentifierConverter() - { - } - - public JceAlgorithmIdentifierConverter setProvider(Provider provider) - { - this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); - - return this; - } - - public JceAlgorithmIdentifierConverter setProvider(String providerName) - { - this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); - - return this; - } - - public AlgorithmParameters getAlgorithmParameters(AlgorithmIdentifier algorithmIdentifier) - throws CMSException - { - ASN1Encodable parameters = algorithmIdentifier.getParameters(); - - if (parameters == null) - { - return null; - } - - try - { - AlgorithmParameters params = helper.createAlgorithmParameters(algorithmIdentifier.getAlgorithm()); - - CMSUtils.loadParameters(params, algorithmIdentifier.getParameters()); - - return params; - } - catch (NoSuchAlgorithmException e) - { - throw new CMSException("can't find parameters for algorithm", e); - } - catch (NoSuchProviderException e) - { - throw new CMSException("can't find provider for algorithm", e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java deleted file mode 100644 index 93d8b72c..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java +++ /dev/null @@ -1,160 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.io.OutputStream; -import java.security.AlgorithmParameters; -import java.security.GeneralSecurityException; -import java.security.Provider; -import java.security.SecureRandom; - -import javax.crypto.Cipher; -import javax.crypto.CipherOutputStream; -import javax.crypto.KeyGenerator; -import javax.crypto.SecretKey; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.operator.DefaultSecretKeySizeProvider; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.OutputEncryptor; -import org.bouncycastle.operator.SecretKeySizeProvider; -import org.bouncycastle.operator.jcajce.JceGenericKey; - -public class JceCMSContentEncryptorBuilder -{ - private static final SecretKeySizeProvider KEY_SIZE_PROVIDER = DefaultSecretKeySizeProvider.INSTANCE; - - - private final ASN1ObjectIdentifier encryptionOID; - private final int keySize; - - private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); - private SecureRandom random; - - public JceCMSContentEncryptorBuilder(ASN1ObjectIdentifier encryptionOID) - { - this(encryptionOID, KEY_SIZE_PROVIDER.getKeySize(encryptionOID)); - } - - public JceCMSContentEncryptorBuilder(ASN1ObjectIdentifier encryptionOID, int keySize) - { - this.encryptionOID = encryptionOID; - this.keySize = keySize; - - int fixedSize = KEY_SIZE_PROVIDER.getKeySize(encryptionOID); - - if (encryptionOID.equals(PKCSObjectIdentifiers.des_EDE3_CBC)) - { - if (keySize != 168 && keySize != fixedSize) - { - throw new IllegalArgumentException("incorrect keySize for encryptionOID passed to builder."); - } - } - else - { - if (fixedSize > 0 && fixedSize != keySize) - { - throw new IllegalArgumentException("incorrect keySize for encryptionOID passed to builder."); - } - } - } - - public JceCMSContentEncryptorBuilder setProvider(Provider provider) - { - this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); - - return this; - } - - public JceCMSContentEncryptorBuilder setProvider(String providerName) - { - this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); - - return this; - } - - public JceCMSContentEncryptorBuilder setSecureRandom(SecureRandom random) - { - this.random = random; - - return this; - } - - public OutputEncryptor build() - throws CMSException - { - return new CMSOutputEncryptor(encryptionOID, keySize, random); - } - - private class CMSOutputEncryptor - implements OutputEncryptor - { - private SecretKey encKey; - private AlgorithmIdentifier algorithmIdentifier; - private Cipher cipher; - - CMSOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, SecureRandom random) - throws CMSException - { - KeyGenerator keyGen = helper.createKeyGenerator(encryptionOID); - - if (random == null) - { - random = new SecureRandom(); - } - - if (keySize < 0) - { - keyGen.init(random); - } - else - { - if (encryptionOID.equals(PKCSObjectIdentifiers.des_EDE3_CBC) && keySize == 192) - { - keySize = 168; - } - keyGen.init(keySize, random); - } - - cipher = helper.createCipher(encryptionOID); - encKey = keyGen.generateKey(); - AlgorithmParameters params = helper.generateParameters(encryptionOID, encKey, random); - - try - { - cipher.init(Cipher.ENCRYPT_MODE, encKey, params, random); - } - catch (GeneralSecurityException e) - { - throw new CMSException("unable to initialize cipher: " + e.getMessage(), e); - } - - // - // If params are null we try and second guess on them as some providers don't provide - // algorithm parameter generation explicity but instead generate them under the hood. - // - if (params == null) - { - params = cipher.getParameters(); - } - - algorithmIdentifier = helper.getAlgorithmIdentifier(encryptionOID, params); - } - - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return algorithmIdentifier; - } - - public OutputStream getOutputStream(OutputStream dOut) - { - return new CipherOutputStream(dOut, cipher); - } - - public GenericKey getKey() - { - return new JceGenericKey(algorithmIdentifier, encKey); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java deleted file mode 100644 index d6ba1609..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java +++ /dev/null @@ -1,155 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.io.OutputStream; -import java.security.AlgorithmParameterGenerator; -import java.security.AlgorithmParameters; -import java.security.GeneralSecurityException; -import java.security.Provider; -import java.security.SecureRandom; -import java.security.spec.AlgorithmParameterSpec; - -import javax.crypto.KeyGenerator; -import javax.crypto.Mac; -import javax.crypto.SecretKey; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.RC2ParameterSpec; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.jcajce.io.MacOutputStream; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.MacCalculator; -import org.bouncycastle.operator.jcajce.JceGenericKey; - -public class JceCMSMacCalculatorBuilder -{ - private final ASN1ObjectIdentifier macOID; - private final int keySize; - - private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); - private SecureRandom random; - - public JceCMSMacCalculatorBuilder(ASN1ObjectIdentifier macOID) - { - this(macOID, -1); - } - - public JceCMSMacCalculatorBuilder(ASN1ObjectIdentifier macOID, int keySize) - { - this.macOID = macOID; - this.keySize = keySize; - } - - public JceCMSMacCalculatorBuilder setProvider(Provider provider) - { - this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); - - return this; - } - - public JceCMSMacCalculatorBuilder setProvider(String providerName) - { - this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); - - return this; - } - - public JceCMSMacCalculatorBuilder setSecureRandom(SecureRandom random) - { - this.random = random; - - return this; - } - - public MacCalculator build() - throws CMSException - { - return new CMSMacCalculator(macOID, keySize, random); - } - - private class CMSMacCalculator - implements MacCalculator - { - private SecretKey encKey; - private AlgorithmIdentifier algorithmIdentifier; - private Mac mac; - private SecureRandom random; - - CMSMacCalculator(ASN1ObjectIdentifier macOID, int keySize, SecureRandom random) - throws CMSException - { - KeyGenerator keyGen = helper.createKeyGenerator(macOID); - - if (random == null) - { - random = new SecureRandom(); - } - - this.random = random; - - if (keySize < 0) - { - keyGen.init(random); - } - else - { - keyGen.init(keySize, random); - } - - encKey = keyGen.generateKey(); - - AlgorithmParameterSpec paramSpec = generateParameterSpec(macOID, encKey); - - algorithmIdentifier = helper.getAlgorithmIdentifier(macOID, paramSpec); - mac = helper.createContentMac(encKey, algorithmIdentifier); - } - - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return algorithmIdentifier; - } - - public OutputStream getOutputStream() - { - return new MacOutputStream(mac); - } - - public byte[] getMac() - { - return mac.doFinal(); - } - - public GenericKey getKey() - { - return new JceGenericKey(algorithmIdentifier, encKey); - } - - protected AlgorithmParameterSpec generateParameterSpec(ASN1ObjectIdentifier macOID, SecretKey encKey) - throws CMSException - { - try - { - if (macOID.equals(PKCSObjectIdentifiers.RC2_CBC)) - { - byte[] iv = new byte[8]; - - random.nextBytes(iv); - - return new RC2ParameterSpec(encKey.getEncoded().length * 8, iv); - } - - AlgorithmParameterGenerator pGen = helper.createAlgorithmParameterGenerator(macOID); - - AlgorithmParameters p = pGen.generateParameters(); - - return p.getParameterSpec(IvParameterSpec.class); - } - catch (GeneralSecurityException e) - { - return null; - } - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKEKAuthenticatedRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKEKAuthenticatedRecipient.java deleted file mode 100644 index eb73555d..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKEKAuthenticatedRecipient.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.io.OutputStream; -import java.security.Key; - -import javax.crypto.Mac; -import javax.crypto.SecretKey; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.RecipientOperator; -import org.bouncycastle.jcajce.io.MacOutputStream; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.MacCalculator; -import org.bouncycastle.operator.jcajce.JceGenericKey; - - -/** - * the KeyTransRecipientInformation class for a recipient who has been sent a secret - * key encrypted using their public key that needs to be used to - * extract the message. - */ -public class JceKEKAuthenticatedRecipient - extends JceKEKRecipient -{ - public JceKEKAuthenticatedRecipient(SecretKey recipientKey) - { - super(recipientKey); - } - - public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentMacAlgorithm, byte[] encryptedContentEncryptionKey) - throws CMSException - { - final Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentMacAlgorithm, encryptedContentEncryptionKey); - - final Mac dataMac = contentHelper.createContentMac(secretKey, contentMacAlgorithm); - - return new RecipientOperator(new MacCalculator() - { - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return contentMacAlgorithm; - } - - public GenericKey getKey() - { - return new JceGenericKey(contentMacAlgorithm, secretKey); - } - - public OutputStream getOutputStream() - { - return new MacOutputStream(dataMac); - } - - public byte[] getMac() - { - return dataMac.doFinal(); - } - }); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKEKEnvelopedRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKEKEnvelopedRecipient.java deleted file mode 100644 index a7293794..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKEKEnvelopedRecipient.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.io.InputStream; -import java.security.Key; - -import javax.crypto.Cipher; -import javax.crypto.CipherInputStream; -import javax.crypto.SecretKey; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.RecipientOperator; -import org.bouncycastle.operator.InputDecryptor; - -public class JceKEKEnvelopedRecipient - extends JceKEKRecipient -{ - public JceKEKEnvelopedRecipient(SecretKey recipientKey) - { - super(recipientKey); - } - - public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey) - throws CMSException - { - Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, encryptedContentEncryptionKey); - - final Cipher dataCipher = contentHelper.createContentCipher(secretKey, contentEncryptionAlgorithm); - - return new RecipientOperator(new InputDecryptor() - { - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return contentEncryptionAlgorithm; - } - - public InputStream getInputStream(InputStream dataOut) - { - return new CipherInputStream(dataOut, dataCipher); - } - }); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKEKRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKEKRecipient.java deleted file mode 100644 index d0e41644..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKEKRecipient.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.security.Key; -import java.security.Provider; - -import javax.crypto.SecretKey; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.KEKRecipient; -import org.bouncycastle.operator.OperatorException; -import org.bouncycastle.operator.SymmetricKeyUnwrapper; - -public abstract class JceKEKRecipient - implements KEKRecipient -{ - private SecretKey recipientKey; - - protected EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); - protected EnvelopedDataHelper contentHelper = helper; - protected boolean validateKeySize = false; - - public JceKEKRecipient(SecretKey recipientKey) - { - this.recipientKey = recipientKey; - } - - /** - * Set the provider to use for key recovery and content processing. - * - * @param provider provider to use. - * @return this recipient. - */ - public JceKEKRecipient setProvider(Provider provider) - { - this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); - this.contentHelper = helper; - - return this; - } - - /** - * Set the provider to use for key recovery and content processing. - * - * @param providerName the name of the provider to use. - * @return this recipient. - */ - public JceKEKRecipient setProvider(String providerName) - { - this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); - this.contentHelper = helper; - - return this; - } - - /** - * Set the provider to use for content processing. - * - * @param provider the provider to use. - * @return this recipient. - */ - public JceKEKRecipient setContentProvider(Provider provider) - { - this.contentHelper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); - - return this; - } - - /** - * Set the provider to use for content processing. - * - * @param providerName the name of the provider to use. - * @return this recipient. - */ - public JceKEKRecipient setContentProvider(String providerName) - { - this.contentHelper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); - - return this; - } - - /** - * Set validation of retrieved key sizes against the algorithm parameters for the encrypted key where possible - default is off. - * <p> - * This setting will not have any affect if the encryption algorithm in the recipient does not specify a particular key size, or - * if the unwrapper is a HSM and the byte encoding of the unwrapped secret key is not available. - * </p> - * @param doValidate true if unwrapped key's should be validated against the content encryption algorithm, false otherwise. - * @return this recipient. - */ - public JceKEKRecipient setKeySizeValidation(boolean doValidate) - { - this.validateKeySize = doValidate; - - return this; - } - - protected Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedContentEncryptionKey) - throws CMSException - { - SymmetricKeyUnwrapper unwrapper = helper.createSymmetricUnwrapper(keyEncryptionAlgorithm, recipientKey); - - try - { - Key key = helper.getJceKey(encryptedKeyAlgorithm.getAlgorithm(), unwrapper.generateUnwrappedKey(encryptedKeyAlgorithm, encryptedContentEncryptionKey)); - - if (validateKeySize) - { - helper.keySizeCheck(encryptedKeyAlgorithm, key); - } - - return key; - } - catch (OperatorException e) - { - throw new CMSException("exception unwrapping key: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKEKRecipientInfoGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKEKRecipientInfoGenerator.java deleted file mode 100644 index 15ec8ffd..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKEKRecipientInfoGenerator.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.security.Provider; -import java.security.SecureRandom; - -import javax.crypto.SecretKey; - -import org.bouncycastle.asn1.cms.KEKIdentifier; -import org.bouncycastle.cms.KEKRecipientInfoGenerator; -import org.bouncycastle.operator.jcajce.JceSymmetricKeyWrapper; - -public class JceKEKRecipientInfoGenerator - extends KEKRecipientInfoGenerator -{ - public JceKEKRecipientInfoGenerator(KEKIdentifier kekIdentifier, SecretKey keyEncryptionKey) - { - super(kekIdentifier, new JceSymmetricKeyWrapper(keyEncryptionKey)); - } - - public JceKEKRecipientInfoGenerator(byte[] keyIdentifier, SecretKey keyEncryptionKey) - { - this(new KEKIdentifier(keyIdentifier, null, null), keyEncryptionKey); - } - - public JceKEKRecipientInfoGenerator setProvider(Provider provider) - { - ((JceSymmetricKeyWrapper)this.wrapper).setProvider(provider); - - return this; - } - - public JceKEKRecipientInfoGenerator setProvider(String providerName) - { - ((JceSymmetricKeyWrapper)this.wrapper).setProvider(providerName); - - return this; - } - - public JceKEKRecipientInfoGenerator setSecureRandom(SecureRandom random) - { - ((JceSymmetricKeyWrapper)this.wrapper).setSecureRandom(random); - - return this; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeAuthenticatedRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeAuthenticatedRecipient.java deleted file mode 100644 index d231f56f..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeAuthenticatedRecipient.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.io.OutputStream; -import java.security.Key; -import java.security.PrivateKey; - -import javax.crypto.Mac; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.RecipientOperator; -import org.bouncycastle.jcajce.io.MacOutputStream; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.MacCalculator; -import org.bouncycastle.operator.jcajce.JceGenericKey; - -public class JceKeyAgreeAuthenticatedRecipient - extends JceKeyAgreeRecipient -{ - public JceKeyAgreeAuthenticatedRecipient(PrivateKey recipientKey) - { - super(recipientKey); - } - - public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentMacAlgorithm, SubjectPublicKeyInfo senderPublicKey, ASN1OctetString userKeyingMaterial, byte[] encryptedContentKey) - throws CMSException - { - final Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentMacAlgorithm, senderPublicKey, userKeyingMaterial, encryptedContentKey); - - final Mac dataMac = contentHelper.createContentMac(secretKey, contentMacAlgorithm); - - return new RecipientOperator(new MacCalculator() - { - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return contentMacAlgorithm; - } - - public GenericKey getKey() - { - return new JceGenericKey(contentMacAlgorithm, secretKey); - } - - public OutputStream getOutputStream() - { - return new MacOutputStream(dataMac); - } - - public byte[] getMac() - { - return dataMac.doFinal(); - } - }); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeEnvelopedRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeEnvelopedRecipient.java deleted file mode 100644 index fe647d7d..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeEnvelopedRecipient.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.io.InputStream; -import java.security.Key; -import java.security.PrivateKey; - -import javax.crypto.Cipher; -import javax.crypto.CipherInputStream; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.RecipientOperator; -import org.bouncycastle.operator.InputDecryptor; - -public class JceKeyAgreeEnvelopedRecipient - extends JceKeyAgreeRecipient -{ - public JceKeyAgreeEnvelopedRecipient(PrivateKey recipientKey) - { - super(recipientKey); - } - - public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, SubjectPublicKeyInfo senderPublicKey, ASN1OctetString userKeyingMaterial, byte[] encryptedContentKey) - throws CMSException - { - Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, senderPublicKey, userKeyingMaterial, encryptedContentKey); - - final Cipher dataCipher = contentHelper.createContentCipher(secretKey, contentEncryptionAlgorithm); - - return new RecipientOperator(new InputDecryptor() - { - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return contentEncryptionAlgorithm; - } - - public InputStream getInputStream(InputStream dataOut) - { - return new CipherInputStream(dataOut, dataCipher); - } - }); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeRecipient.java deleted file mode 100644 index 8c41f914..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeRecipient.java +++ /dev/null @@ -1,184 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.Provider; -import java.security.PublicKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.X509EncodedKeySpec; - -import javax.crypto.Cipher; -import javax.crypto.KeyAgreement; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.SecretKey; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.cms.ecc.MQVuserKeyingMaterial; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.cms.CMSEnvelopedGenerator; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.KeyAgreeRecipient; -import org.bouncycastle.jce.spec.MQVPrivateKeySpec; -import org.bouncycastle.jce.spec.MQVPublicKeySpec; - -public abstract class JceKeyAgreeRecipient - implements KeyAgreeRecipient -{ - private PrivateKey recipientKey; - protected EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); - protected EnvelopedDataHelper contentHelper = helper; - - public JceKeyAgreeRecipient(PrivateKey recipientKey) - { - this.recipientKey = recipientKey; - } - - /** - * Set the provider to use for key recovery and content processing. - * - * @param provider provider to use. - * @return this recipient. - */ - public JceKeyAgreeRecipient setProvider(Provider provider) - { - this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); - this.contentHelper = helper; - - return this; - } - - /** - * Set the provider to use for key recovery and content processing. - * - * @param providerName the name of the provider to use. - * @return this recipient. - */ - public JceKeyAgreeRecipient setProvider(String providerName) - { - this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); - this.contentHelper = helper; - - return this; - } - - /** - * Set the provider to use for content processing. If providerName is null a "no provider" search will be - * used to satisfy getInstance calls. - * - * @param provider the provider to use. - * @return this recipient. - */ - public JceKeyAgreeRecipient setContentProvider(Provider provider) - { - this.contentHelper = CMSUtils.createContentHelper(provider); - - return this; - } - - /** - * Set the provider to use for content processing. If providerName is null a "no provider" search will be - * used to satisfy getInstance calls. - * - * @param providerName the name of the provider to use. - * @return this recipient. - */ - public JceKeyAgreeRecipient setContentProvider(String providerName) - { - this.contentHelper = CMSUtils.createContentHelper(providerName); - - return this; - } - - private SecretKey calculateAgreedWrapKey(AlgorithmIdentifier keyEncAlg, ASN1ObjectIdentifier wrapAlg, - PublicKey senderPublicKey, ASN1OctetString userKeyingMaterial, PrivateKey receiverPrivateKey) - throws CMSException, GeneralSecurityException, IOException - { - String agreeAlg = keyEncAlg.getAlgorithm().getId(); - - if (agreeAlg.equals(CMSEnvelopedGenerator.ECMQV_SHA1KDF)) - { - byte[] ukmEncoding = userKeyingMaterial.getOctets(); - MQVuserKeyingMaterial ukm = MQVuserKeyingMaterial.getInstance( - ASN1Primitive.fromByteArray(ukmEncoding)); - - SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo( - getPrivateKeyAlgorithmIdentifier(), - ukm.getEphemeralPublicKey().getPublicKey().getBytes()); - - X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubInfo.getEncoded()); - KeyFactory fact = helper.createKeyFactory(keyEncAlg.getAlgorithm()); - PublicKey ephemeralKey = fact.generatePublic(pubSpec); - - senderPublicKey = new MQVPublicKeySpec(senderPublicKey, ephemeralKey); - receiverPrivateKey = new MQVPrivateKeySpec(receiverPrivateKey, receiverPrivateKey); - } - - KeyAgreement agreement = helper.createKeyAgreement(keyEncAlg.getAlgorithm()); - - agreement.init(receiverPrivateKey); - agreement.doPhase(senderPublicKey, true); - - return agreement.generateSecret(wrapAlg.getId()); - } - - private Key unwrapSessionKey(ASN1ObjectIdentifier wrapAlg, SecretKey agreedKey, ASN1ObjectIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey) - throws CMSException, InvalidKeyException, NoSuchAlgorithmException - { - Cipher keyCipher = helper.createCipher(wrapAlg); - keyCipher.init(Cipher.UNWRAP_MODE, agreedKey); - return keyCipher.unwrap(encryptedContentEncryptionKey, helper.getBaseCipherName(contentEncryptionAlgorithm), Cipher.SECRET_KEY); - } - - protected Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier contentEncryptionAlgorithm, SubjectPublicKeyInfo senderKey, ASN1OctetString userKeyingMaterial, byte[] encryptedContentEncryptionKey) - throws CMSException - { - try - { - ASN1ObjectIdentifier wrapAlg = - AlgorithmIdentifier.getInstance(keyEncryptionAlgorithm.getParameters()).getAlgorithm(); - - X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(senderKey.getEncoded()); - KeyFactory fact = helper.createKeyFactory(keyEncryptionAlgorithm.getAlgorithm()); - PublicKey senderPublicKey = fact.generatePublic(pubSpec); - - SecretKey agreedWrapKey = calculateAgreedWrapKey(keyEncryptionAlgorithm, wrapAlg, - senderPublicKey, userKeyingMaterial, recipientKey); - - return unwrapSessionKey(wrapAlg, agreedWrapKey, contentEncryptionAlgorithm.getAlgorithm(), encryptedContentEncryptionKey); - } - catch (NoSuchAlgorithmException e) - { - throw new CMSException("can't find algorithm.", e); - } - catch (InvalidKeyException e) - { - throw new CMSException("key invalid in message.", e); - } - catch (InvalidKeySpecException e) - { - throw new CMSException("originator key spec invalid.", e); - } - catch (NoSuchPaddingException e) - { - throw new CMSException("required padding not supported.", e); - } - catch (Exception e) - { - throw new CMSException("originator key invalid.", e); - } - } - - public AlgorithmIdentifier getPrivateKeyAlgorithmIdentifier() - { - return PrivateKeyInfo.getInstance(recipientKey.getEncoded()).getPrivateKeyAlgorithm(); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeRecipientId.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeRecipientId.java deleted file mode 100644 index 56911bec..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeRecipientId.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.math.BigInteger; -import java.security.cert.X509Certificate; - -import javax.security.auth.x500.X500Principal; - -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.cms.KeyAgreeRecipientId; - -public class JceKeyAgreeRecipientId - extends KeyAgreeRecipientId -{ - public JceKeyAgreeRecipientId(X509Certificate certificate) - { - this(certificate.getIssuerX500Principal(), certificate.getSerialNumber()); - } - - public JceKeyAgreeRecipientId(X500Principal issuer, BigInteger serialNumber) - { - super(X500Name.getInstance(issuer.getEncoded()), serialNumber); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java deleted file mode 100644 index 583ede2d..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java +++ /dev/null @@ -1,215 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.security.GeneralSecurityException; -import java.security.InvalidAlgorithmParameterException; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.PrivateKey; -import java.security.Provider; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; -import java.security.interfaces.ECPublicKey; -import java.security.spec.ECParameterSpec; -import java.util.ArrayList; -import java.util.List; - -import javax.crypto.Cipher; -import javax.crypto.KeyAgreement; -import javax.crypto.SecretKey; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.cms.KeyAgreeRecipientIdentifier; -import org.bouncycastle.asn1.cms.RecipientEncryptedKey; -import org.bouncycastle.asn1.cms.RecipientKeyIdentifier; -import org.bouncycastle.asn1.cms.ecc.MQVuserKeyingMaterial; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.cms.CMSAlgorithm; -import org.bouncycastle.cms.CMSEnvelopedGenerator; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.KeyAgreeRecipientInfoGenerator; -import org.bouncycastle.jce.spec.MQVPrivateKeySpec; -import org.bouncycastle.jce.spec.MQVPublicKeySpec; -import org.bouncycastle.operator.GenericKey; - -public class JceKeyAgreeRecipientInfoGenerator - extends KeyAgreeRecipientInfoGenerator -{ - private List recipientIDs = new ArrayList(); - private List recipientKeys = new ArrayList(); - private PublicKey senderPublicKey; - private PrivateKey senderPrivateKey; - - private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); - private SecureRandom random; - private KeyPair ephemeralKP; - - public JceKeyAgreeRecipientInfoGenerator(ASN1ObjectIdentifier keyAgreementOID, PrivateKey senderPrivateKey, PublicKey senderPublicKey, ASN1ObjectIdentifier keyEncryptionOID) - { - super(keyAgreementOID, SubjectPublicKeyInfo.getInstance(senderPublicKey.getEncoded()), keyEncryptionOID); - - this.senderPublicKey = senderPublicKey; - this.senderPrivateKey = senderPrivateKey; - } - - public JceKeyAgreeRecipientInfoGenerator setProvider(Provider provider) - { - this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); - - return this; - } - - public JceKeyAgreeRecipientInfoGenerator setProvider(String providerName) - { - this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); - - return this; - } - - public JceKeyAgreeRecipientInfoGenerator setSecureRandom(SecureRandom random) - { - this.random = random; - - return this; - } - - /** - * Add a recipient based on the passed in certificate's public key and its issuer and serial number. - * - * @param recipientCert recipient's certificate - * @return the current instance. - * @throws CertificateEncodingException if the necessary data cannot be extracted from the certificate. - */ - public JceKeyAgreeRecipientInfoGenerator addRecipient(X509Certificate recipientCert) - throws CertificateEncodingException - { - recipientIDs.add(new KeyAgreeRecipientIdentifier(CMSUtils.getIssuerAndSerialNumber(recipientCert))); - recipientKeys.add(recipientCert.getPublicKey()); - - return this; - } - - /** - * Add a recipient identified by the passed in subjectKeyID and the for the passed in public key. - * - * @param subjectKeyID identifier actual recipient will use to match the private key. - * @param publicKey the public key for encrypting the secret key. - * @return the current instance. - * @throws CertificateEncodingException - */ - public JceKeyAgreeRecipientInfoGenerator addRecipient(byte[] subjectKeyID, PublicKey publicKey) - throws CertificateEncodingException - { - recipientIDs.add(new KeyAgreeRecipientIdentifier(new RecipientKeyIdentifier(subjectKeyID))); - recipientKeys.add(publicKey); - - return this; - } - - public ASN1Sequence generateRecipientEncryptedKeys(AlgorithmIdentifier keyAgreeAlgorithm, AlgorithmIdentifier keyEncryptionAlgorithm, GenericKey contentEncryptionKey) - throws CMSException - { - init(keyAgreeAlgorithm.getAlgorithm()); - - PrivateKey senderPrivateKey = this.senderPrivateKey; - - ASN1ObjectIdentifier keyAgreementOID = keyAgreeAlgorithm.getAlgorithm(); - - if (keyAgreementOID.getId().equals(CMSEnvelopedGenerator.ECMQV_SHA1KDF)) - { - senderPrivateKey = new MQVPrivateKeySpec( - senderPrivateKey, ephemeralKP.getPrivate(), ephemeralKP.getPublic()); - } - - ASN1EncodableVector recipientEncryptedKeys = new ASN1EncodableVector(); - for (int i = 0; i != recipientIDs.size(); i++) - { - PublicKey recipientPublicKey = (PublicKey)recipientKeys.get(i); - KeyAgreeRecipientIdentifier karId = (KeyAgreeRecipientIdentifier)recipientIDs.get(i); - - if (keyAgreementOID.getId().equals(CMSEnvelopedGenerator.ECMQV_SHA1KDF)) - { - recipientPublicKey = new MQVPublicKeySpec(recipientPublicKey, recipientPublicKey); - } - - try - { - // Use key agreement to choose a wrap key for this recipient - KeyAgreement keyAgreement = helper.createKeyAgreement(keyAgreementOID); - keyAgreement.init(senderPrivateKey, random); - keyAgreement.doPhase(recipientPublicKey, true); - SecretKey keyEncryptionKey = keyAgreement.generateSecret(keyEncryptionAlgorithm.getAlgorithm().getId()); - - // Wrap the content encryption key with the agreement key - Cipher keyEncryptionCipher = helper.createCipher(keyEncryptionAlgorithm.getAlgorithm()); - - keyEncryptionCipher.init(Cipher.WRAP_MODE, keyEncryptionKey, random); - - byte[] encryptedKeyBytes = keyEncryptionCipher.wrap(helper.getJceKey(contentEncryptionKey)); - - ASN1OctetString encryptedKey = new DEROctetString(encryptedKeyBytes); - - recipientEncryptedKeys.add(new RecipientEncryptedKey(karId, encryptedKey)); - } - catch (GeneralSecurityException e) - { - throw new CMSException("cannot perform agreement step: " + e.getMessage(), e); - } - } - - return new DERSequence(recipientEncryptedKeys); - } - - protected ASN1Encodable getUserKeyingMaterial(AlgorithmIdentifier keyAgreeAlg) - throws CMSException - { - init(keyAgreeAlg.getAlgorithm()); - - if (ephemeralKP != null) - { - return new MQVuserKeyingMaterial( - createOriginatorPublicKey(SubjectPublicKeyInfo.getInstance(ephemeralKP.getPublic().getEncoded())), null); - } - - return null; - } - - private void init(ASN1ObjectIdentifier keyAgreementOID) - throws CMSException - { - if (random == null) - { - random = new SecureRandom(); - } - - if (keyAgreementOID.equals(CMSAlgorithm.ECMQV_SHA1KDF)) - { - if (ephemeralKP == null) - { - try - { - ECParameterSpec ecParamSpec = ((ECPublicKey)senderPublicKey).getParams(); - - KeyPairGenerator ephemKPG = helper.createKeyPairGenerator(keyAgreementOID); - - ephemKPG.initialize(ecParamSpec, random); - - ephemeralKP = ephemKPG.generateKeyPair(); - } - catch (InvalidAlgorithmParameterException e) - { - throw new CMSException( - "cannot determine MQV ephemeral key pair parameters from public key: " + e); - } - } - } - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyTransAuthenticatedRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyTransAuthenticatedRecipient.java deleted file mode 100644 index f15aadb0..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyTransAuthenticatedRecipient.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.io.OutputStream; -import java.security.Key; -import java.security.PrivateKey; - -import javax.crypto.Mac; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.RecipientOperator; -import org.bouncycastle.jcajce.io.MacOutputStream; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.MacCalculator; - - -/** - * the KeyTransRecipientInformation class for a recipient who has been sent a secret - * key encrypted using their public key that needs to be used to - * extract the message. - */ -public class JceKeyTransAuthenticatedRecipient - extends JceKeyTransRecipient -{ - public JceKeyTransAuthenticatedRecipient(PrivateKey recipientKey) - { - super(recipientKey); - } - - public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentMacAlgorithm, byte[] encryptedContentEncryptionKey) - throws CMSException - { - final Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentMacAlgorithm, encryptedContentEncryptionKey); - - final Mac dataMac = contentHelper.createContentMac(secretKey, contentMacAlgorithm); - - return new RecipientOperator(new MacCalculator() - { - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return contentMacAlgorithm; - } - - public GenericKey getKey() - { - return new GenericKey(secretKey); - } - - public OutputStream getOutputStream() - { - return new MacOutputStream(dataMac); - } - - public byte[] getMac() - { - return dataMac.doFinal(); - } - }); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyTransEnvelopedRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyTransEnvelopedRecipient.java deleted file mode 100644 index 1bc0188f..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyTransEnvelopedRecipient.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.io.InputStream; -import java.security.Key; -import java.security.PrivateKey; - -import javax.crypto.Cipher; -import javax.crypto.CipherInputStream; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.RecipientOperator; -import org.bouncycastle.operator.InputDecryptor; - -public class JceKeyTransEnvelopedRecipient - extends JceKeyTransRecipient -{ - public JceKeyTransEnvelopedRecipient(PrivateKey recipientKey) - { - super(recipientKey); - } - - public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey) - throws CMSException - { - Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, encryptedContentEncryptionKey); - - final Cipher dataCipher = contentHelper.createContentCipher(secretKey, contentEncryptionAlgorithm); - - return new RecipientOperator(new InputDecryptor() - { - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return contentEncryptionAlgorithm; - } - - public InputStream getInputStream(InputStream dataIn) - { - return new CipherInputStream(dataIn, dataCipher); - } - }); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyTransRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyTransRecipient.java deleted file mode 100644 index a457ede4..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyTransRecipient.java +++ /dev/null @@ -1,156 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.security.Key; -import java.security.PrivateKey; -import java.security.Provider; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.KeyTransRecipient; -import org.bouncycastle.operator.OperatorException; -import org.bouncycastle.operator.jcajce.JceAsymmetricKeyUnwrapper; - -public abstract class JceKeyTransRecipient - implements KeyTransRecipient -{ - private PrivateKey recipientKey; - - protected EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); - protected EnvelopedDataHelper contentHelper = helper; - protected Map extraMappings = new HashMap(); - protected boolean validateKeySize = false; - - public JceKeyTransRecipient(PrivateKey recipientKey) - { - this.recipientKey = recipientKey; - } - - /** - * Set the provider to use for key recovery and content processing. - * - * @param provider provider to use. - * @return this recipient. - */ - public JceKeyTransRecipient setProvider(Provider provider) - { - this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); - this.contentHelper = helper; - - return this; - } - - /** - * Set the provider to use for key recovery and content processing. - * - * @param providerName the name of the provider to use. - * @return this recipient. - */ - public JceKeyTransRecipient setProvider(String providerName) - { - this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); - this.contentHelper = helper; - - return this; - } - - /** - * Internally algorithm ids are converted into cipher names using a lookup table. For some providers - * the standard lookup table won't work. Use this method to establish a specific mapping from an - * algorithm identifier to a specific algorithm. - * <p> - * For example: - * <pre> - * unwrapper.setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA"); - * </pre> - * </p> - * @param algorithm OID of algorithm in recipient. - * @param algorithmName JCE algorithm name to use. - * @return the current Recipient. - */ - public JceKeyTransRecipient setAlgorithmMapping(ASN1ObjectIdentifier algorithm, String algorithmName) - { - extraMappings.put(algorithm, algorithmName); - - return this; - } - - /** - * Set the provider to use for content processing. If providerName is null a "no provider" search will be - * used to satisfy getInstance calls. - * - * @param provider the provider to use. - * @return this recipient. - */ - public JceKeyTransRecipient setContentProvider(Provider provider) - { - this.contentHelper = CMSUtils.createContentHelper(provider); - - return this; - } - - /** - * Set the provider to use for content processing. If providerName is null a "no provider" search will be - * used to satisfy getInstance calls. - * - * @param providerName the name of the provider to use. - * @return this recipient. - */ - public JceKeyTransRecipient setContentProvider(String providerName) - { - this.contentHelper = CMSUtils.createContentHelper(providerName); - - return this; - } - - /** - * Set validation of retrieved key sizes against the algorithm parameters for the encrypted key where possible - default is off. - * <p> - * This setting will not have any affect if the encryption algorithm in the recipient does not specify a particular key size, or - * if the unwrapper is a HSM and the byte encoding of the unwrapped secret key is not available. - * </p> - * @param doValidate true if unwrapped key's should be validated against the content encryption algorithm, false otherwise. - * @return this recipient. - */ - public JceKeyTransRecipient setKeySizeValidation(boolean doValidate) - { - this.validateKeySize = doValidate; - - return this; - } - - protected Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedEncryptionKey) - throws CMSException - { - JceAsymmetricKeyUnwrapper unwrapper = helper.createAsymmetricUnwrapper(keyEncryptionAlgorithm, recipientKey); - - if (!extraMappings.isEmpty()) - { - for (Iterator it = extraMappings.keySet().iterator(); it.hasNext();) - { - ASN1ObjectIdentifier algorithm = (ASN1ObjectIdentifier)it.next(); - - unwrapper.setAlgorithmMapping(algorithm, (String)extraMappings.get(algorithm)); - } - } - - try - { - Key key = helper.getJceKey(encryptedKeyAlgorithm.getAlgorithm(), unwrapper.generateUnwrappedKey(encryptedKeyAlgorithm, encryptedEncryptionKey)); - - if (validateKeySize) - { - helper.keySizeCheck(encryptedKeyAlgorithm, key); - } - - return key; - } - catch (OperatorException e) - { - throw new CMSException("exception unwrapping key: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyTransRecipientId.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyTransRecipientId.java deleted file mode 100644 index 8b44817b..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyTransRecipientId.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.math.BigInteger; -import java.security.cert.X509Certificate; - -import javax.security.auth.x500.X500Principal; - -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.cms.KeyTransRecipientId; - -public class JceKeyTransRecipientId - extends KeyTransRecipientId -{ - /** - * Construct a recipient id based on the issuer, serial number and subject key identifier (if present) of the passed in - * certificate. - * - * @param certificate certificate providing the issue and serial number and subject key identifier. - */ - public JceKeyTransRecipientId(X509Certificate certificate) - { - super(convertPrincipal(certificate.getIssuerX500Principal()), certificate.getSerialNumber(), CMSUtils.getSubjectKeyId(certificate)); - } - - /** - * Construct a recipient id based on the provided issuer and serial number.. - * - * @param issuer the issuer to use. - * @param serialNumber the serial number to use. - */ - public JceKeyTransRecipientId(X500Principal issuer, BigInteger serialNumber) - { - super(convertPrincipal(issuer), serialNumber); - } - - /** - * Construct a recipient id based on the provided issuer, serial number, and subjectKeyId.. - * - * @param issuer the issuer to use. - * @param serialNumber the serial number to use. - * @param subjectKeyId the subject key ID to use. - */ - public JceKeyTransRecipientId(X500Principal issuer, BigInteger serialNumber, byte[] subjectKeyId) - { - super(convertPrincipal(issuer), serialNumber, subjectKeyId); - } - - private static X500Name convertPrincipal(X500Principal issuer) - { - if (issuer == null) - { - return null; - } - - return X500Name.getInstance(issuer.getEncoded()); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyTransRecipientInfoGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyTransRecipientInfoGenerator.java deleted file mode 100644 index 60a2ff20..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyTransRecipientInfoGenerator.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.security.Provider; -import java.security.PublicKey; -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.cms.IssuerAndSerialNumber; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; -import org.bouncycastle.cms.KeyTransRecipientInfoGenerator; -import org.bouncycastle.operator.jcajce.JceAsymmetricKeyWrapper; - -public class JceKeyTransRecipientInfoGenerator - extends KeyTransRecipientInfoGenerator -{ - public JceKeyTransRecipientInfoGenerator(X509Certificate recipientCert) - throws CertificateEncodingException - { - super(new IssuerAndSerialNumber(new JcaX509CertificateHolder(recipientCert).toASN1Structure()), new JceAsymmetricKeyWrapper(recipientCert)); - } - - public JceKeyTransRecipientInfoGenerator(byte[] subjectKeyIdentifier, PublicKey publicKey) - { - super(subjectKeyIdentifier, new JceAsymmetricKeyWrapper(publicKey)); - } - - /** - * Create a generator overriding the algorithm type implied by the public key in the certificate passed in. - * - * @param recipientCert certificate carrying the public key. - * @param algorithmIdentifier the identifier and parameters for the encryption algorithm to be used. - */ - public JceKeyTransRecipientInfoGenerator(X509Certificate recipientCert, AlgorithmIdentifier algorithmIdentifier) - throws CertificateEncodingException - { - super(new IssuerAndSerialNumber(new JcaX509CertificateHolder(recipientCert).toASN1Structure()), new JceAsymmetricKeyWrapper(algorithmIdentifier, recipientCert.getPublicKey())); - } - - /** - * Create a generator overriding the algorithm type implied by the public key passed in. - * - * @param subjectKeyIdentifier the subject key identifier value to associate with the public key. - * @param algorithmIdentifier the identifier and parameters for the encryption algorithm to be used. - * @param publicKey the public key to use. - */ - public JceKeyTransRecipientInfoGenerator(byte[] subjectKeyIdentifier, AlgorithmIdentifier algorithmIdentifier, PublicKey publicKey) - { - super(subjectKeyIdentifier, new JceAsymmetricKeyWrapper(algorithmIdentifier, publicKey)); - } - - public JceKeyTransRecipientInfoGenerator setProvider(String providerName) - { - ((JceAsymmetricKeyWrapper)this.wrapper).setProvider(providerName); - - return this; - } - - public JceKeyTransRecipientInfoGenerator setProvider(Provider provider) - { - ((JceAsymmetricKeyWrapper)this.wrapper).setProvider(provider); - - return this; - } - - /** - * Internally algorithm ids are converted into cipher names using a lookup table. For some providers - * the standard lookup table won't work. Use this method to establish a specific mapping from an - * algorithm identifier to a specific algorithm. - * <p> - * For example: - * <pre> - * unwrapper.setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA"); - * </pre> - * </p> - * @param algorithm OID of algorithm in recipient. - * @param algorithmName JCE algorithm name to use. - * @return the current RecipientInfoGenerator. - */ - public JceKeyTransRecipientInfoGenerator setAlgorithmMapping(ASN1ObjectIdentifier algorithm, String algorithmName) - { - ((JceAsymmetricKeyWrapper)this.wrapper).setAlgorithmMapping(algorithm, algorithmName); - - return this; - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcePasswordAuthenticatedRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcePasswordAuthenticatedRecipient.java deleted file mode 100644 index ba873d25..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcePasswordAuthenticatedRecipient.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.io.OutputStream; -import java.security.Key; - -import javax.crypto.Mac; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.RecipientOperator; -import org.bouncycastle.jcajce.io.MacOutputStream; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.MacCalculator; -import org.bouncycastle.operator.jcajce.JceGenericKey; - -public class JcePasswordAuthenticatedRecipient - extends JcePasswordRecipient -{ - public JcePasswordAuthenticatedRecipient(char[] password) - { - super(password); - } - - public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentMacAlgorithm, byte[] derivedKey, byte[] encryptedContentEncryptionKey) - throws CMSException - { - final Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentMacAlgorithm, derivedKey, encryptedContentEncryptionKey); - - final Mac dataMac = helper.createContentMac(secretKey, contentMacAlgorithm); - - return new RecipientOperator(new MacCalculator() - { - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return contentMacAlgorithm; - } - - public GenericKey getKey() - { - return new JceGenericKey(contentMacAlgorithm, secretKey); - } - - public OutputStream getOutputStream() - { - return new MacOutputStream(dataMac); - } - - public byte[] getMac() - { - return dataMac.doFinal(); - } - }); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcePasswordEnvelopedRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcePasswordEnvelopedRecipient.java deleted file mode 100644 index be741db4..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcePasswordEnvelopedRecipient.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.io.InputStream; -import java.security.Key; - -import javax.crypto.Cipher; -import javax.crypto.CipherInputStream; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.RecipientOperator; -import org.bouncycastle.operator.InputDecryptor; - -public class JcePasswordEnvelopedRecipient - extends JcePasswordRecipient -{ - public JcePasswordEnvelopedRecipient(char[] password) - { - super(password); - } - - public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, byte[] derivedKey, byte[] encryptedContentEncryptionKey) - throws CMSException - { - Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, derivedKey, encryptedContentEncryptionKey); - - final Cipher dataCipher = helper.createContentCipher(secretKey, contentEncryptionAlgorithm); - - return new RecipientOperator(new InputDecryptor() - { - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return contentEncryptionAlgorithm; - } - - public InputStream getInputStream(InputStream dataOut) - { - return new CipherInputStream(dataOut, dataCipher); - } - }); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcePasswordRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcePasswordRecipient.java deleted file mode 100644 index 3c00b5ef..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcePasswordRecipient.java +++ /dev/null @@ -1,97 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.security.GeneralSecurityException; -import java.security.Key; -import java.security.Provider; - -import javax.crypto.Cipher; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.pkcs.PBKDF2Params; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.PasswordRecipient; -import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; -import org.bouncycastle.crypto.params.KeyParameter; - -/** - * the RecipientInfo class for a recipient who has been sent a message - * encrypted using a password. - */ -public abstract class JcePasswordRecipient - implements PasswordRecipient -{ - private int schemeID = PasswordRecipient.PKCS5_SCHEME2_UTF8; - protected EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); - private char[] password; - - JcePasswordRecipient( - char[] password) - { - this.password = password; - } - - public JcePasswordRecipient setPasswordConversionScheme(int schemeID) - { - this.schemeID = schemeID; - - return this; - } - - public JcePasswordRecipient setProvider(Provider provider) - { - this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); - - return this; - } - - public JcePasswordRecipient setProvider(String providerName) - { - this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); - - return this; - } - - protected Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] derivedKey, byte[] encryptedContentEncryptionKey) - throws CMSException - { - Cipher keyEncryptionCipher = helper.createRFC3211Wrapper(keyEncryptionAlgorithm.getAlgorithm()); - - try - { - IvParameterSpec ivSpec = new IvParameterSpec(ASN1OctetString.getInstance(keyEncryptionAlgorithm.getParameters()).getOctets()); - - keyEncryptionCipher.init(Cipher.UNWRAP_MODE, new SecretKeySpec(derivedKey, keyEncryptionCipher.getAlgorithm()), ivSpec); - - return keyEncryptionCipher.unwrap(encryptedContentEncryptionKey, contentEncryptionAlgorithm.getAlgorithm().getId(), Cipher.SECRET_KEY); - } - catch (GeneralSecurityException e) - { - throw new CMSException("cannot process content encryption key: " + e.getMessage(), e); - } - } - - public byte[] calculateDerivedKey(byte[] encodedPassword, AlgorithmIdentifier derivationAlgorithm, int keySize) - throws CMSException - { - PBKDF2Params params = PBKDF2Params.getInstance(derivationAlgorithm.getParameters()); - - PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(); - - gen.init(encodedPassword, params.getSalt(), params.getIterationCount().intValue()); - - return ((KeyParameter)gen.generateDerivedParameters(keySize)).getKey(); - } - - public int getPasswordConversionScheme() - { - return schemeID; - } - - public char[] getPassword() - { - return password; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcePasswordRecipientInfoGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcePasswordRecipientInfoGenerator.java deleted file mode 100644 index fefe016e..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcePasswordRecipientInfoGenerator.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.security.GeneralSecurityException; -import java.security.Key; -import java.security.Provider; - -import javax.crypto.Cipher; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.pkcs.PBKDF2Params; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.PasswordRecipientInfoGenerator; -import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; -import org.bouncycastle.crypto.params.KeyParameter; -import org.bouncycastle.operator.GenericKey; - -public class JcePasswordRecipientInfoGenerator - extends PasswordRecipientInfoGenerator -{ - private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); - - public JcePasswordRecipientInfoGenerator(ASN1ObjectIdentifier kekAlgorithm, char[] password) - { - super(kekAlgorithm, password); - } - - public JcePasswordRecipientInfoGenerator setProvider(Provider provider) - { - this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); - - return this; - } - - public JcePasswordRecipientInfoGenerator setProvider(String providerName) - { - this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); - - return this; - } - - protected byte[] calculateDerivedKey(byte[] encodedPassword, AlgorithmIdentifier derivationAlgorithm, int keySize) - throws CMSException - { - PBKDF2Params params = PBKDF2Params.getInstance(derivationAlgorithm.getParameters()); - - PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(); - - gen.init(encodedPassword, params.getSalt(), params.getIterationCount().intValue()); - - return ((KeyParameter)gen.generateDerivedParameters(keySize)).getKey(); - } - - public byte[] generateEncryptedBytes(AlgorithmIdentifier keyEncryptionAlgorithm, byte[] derivedKey, GenericKey contentEncryptionKey) - throws CMSException - { - Key contentEncryptionKeySpec = helper.getJceKey(contentEncryptionKey); - Cipher keyEncryptionCipher = helper.createRFC3211Wrapper(keyEncryptionAlgorithm.getAlgorithm()); - - try - { - IvParameterSpec ivSpec = new IvParameterSpec(ASN1OctetString.getInstance(keyEncryptionAlgorithm.getParameters()).getOctets()); - - keyEncryptionCipher.init(Cipher.WRAP_MODE, new SecretKeySpec(derivedKey, keyEncryptionCipher.getAlgorithm()), ivSpec); - - return keyEncryptionCipher.wrap(contentEncryptionKeySpec); - } - catch (GeneralSecurityException e) - { - throw new CMSException("cannot process content encryption key: " + e.getMessage(), e); - } - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/NamedJcaJceExtHelper.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/NamedJcaJceExtHelper.java deleted file mode 100644 index fba72dc7..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/NamedJcaJceExtHelper.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.security.PrivateKey; - -import javax.crypto.SecretKey; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.jcajce.util.NamedJcaJceHelper; -import org.bouncycastle.operator.SymmetricKeyUnwrapper; -import org.bouncycastle.operator.jcajce.JceAsymmetricKeyUnwrapper; -import org.bouncycastle.operator.jcajce.JceSymmetricKeyUnwrapper; - -class NamedJcaJceExtHelper - extends NamedJcaJceHelper - implements JcaJceExtHelper -{ - public NamedJcaJceExtHelper(String providerName) - { - super(providerName); - } - - public JceAsymmetricKeyUnwrapper createAsymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, PrivateKey keyEncryptionKey) - { - return new JceAsymmetricKeyUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey).setProvider(providerName); - } - - public SymmetricKeyUnwrapper createSymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, SecretKey keyEncryptionKey) - { - return new JceSymmetricKeyUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey).setProvider(providerName); - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/ProviderJcaJceExtHelper.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/ProviderJcaJceExtHelper.java deleted file mode 100644 index f6991a89..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/ProviderJcaJceExtHelper.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.security.PrivateKey; -import java.security.Provider; - -import javax.crypto.SecretKey; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; -import org.bouncycastle.operator.SymmetricKeyUnwrapper; -import org.bouncycastle.operator.jcajce.JceAsymmetricKeyUnwrapper; -import org.bouncycastle.operator.jcajce.JceSymmetricKeyUnwrapper; - -class ProviderJcaJceExtHelper - extends ProviderJcaJceHelper - implements JcaJceExtHelper -{ - public ProviderJcaJceExtHelper(Provider provider) - { - super(provider); - } - - public JceAsymmetricKeyUnwrapper createAsymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, PrivateKey keyEncryptionKey) - { - return new JceAsymmetricKeyUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey).setProvider(provider); - } - - public SymmetricKeyUnwrapper createSymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, SecretKey keyEncryptionKey) - { - return new JceSymmetricKeyUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey).setProvider(provider); - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/ZlibCompressor.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/ZlibCompressor.java deleted file mode 100644 index 53da722b..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/ZlibCompressor.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.io.OutputStream; -import java.util.zip.DeflaterOutputStream; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.operator.OutputCompressor; - -public class ZlibCompressor - implements OutputCompressor -{ - private static final String ZLIB = "1.2.840.113549.1.9.16.3.8"; - - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return new AlgorithmIdentifier(new ASN1ObjectIdentifier(ZLIB)); - } - - public OutputStream getOutputStream(OutputStream comOut) - { - return new DeflaterOutputStream(comOut); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/ZlibExpanderProvider.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/ZlibExpanderProvider.java deleted file mode 100644 index 15729a73..00000000 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/ZlibExpanderProvider.java +++ /dev/null @@ -1,116 +0,0 @@ -package org.bouncycastle.cms.jcajce; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.zip.InflaterInputStream; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.operator.InputExpander; -import org.bouncycastle.operator.InputExpanderProvider; -import org.bouncycastle.util.io.StreamOverflowException; - -public class ZlibExpanderProvider - implements InputExpanderProvider -{ - private final long limit; - - /** - * Base constructor. Create an expander which will not limit the size of any objects expanded in the stream. - */ - public ZlibExpanderProvider() - { - this.limit = -1; - } - - /** - * Create a provider which caps the number of expanded bytes that can be produced when the - * compressed stream is parsed. - * - * @param limit max number of bytes allowed in an expanded stream. - */ - public ZlibExpanderProvider(long limit) - { - this.limit = limit; - } - - public InputExpander get(final AlgorithmIdentifier algorithm) - { - return new InputExpander() - { - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return algorithm; - } - - public InputStream getInputStream(InputStream comIn) - { - InputStream s = new InflaterInputStream(comIn); - if (limit >= 0) - { - s = new LimitedInputStream(s, limit); - } - return s; - } - }; - } - - private static class LimitedInputStream - extends FilterInputStream - { - private long remaining; - - public LimitedInputStream(InputStream input, long limit) - { - super(input); - - this.remaining = limit; - } - - public int read() - throws IOException - { - // Only a single 'extra' byte will ever be read - if (remaining >= 0) - { - int b = super.in.read(); - if (b < 0 || --remaining >= 0) - { - return b; - } - } - - throw new StreamOverflowException("expanded byte limit exceeded"); - } - - public int read(byte[] buf, int off, int len) - throws IOException - { - if (len < 1) - { - // This will give correct exceptions/returns for strange lengths - return super.read(buf, off, len); - } - - if (remaining < 1) - { - // Will either return EOF or throw exception - read(); - return -1; - } - - /* - * Limit the underlying request to 'remaining' bytes. This ensures the - * caller will see the full 'limit' bytes before getting an exception. - * Also, only one extra byte will ever be read. - */ - int actualLen = (remaining > len ? len : (int)remaining); - int numRead = super.in.read(buf, off, actualLen); - if (numRead > 0) - { - remaining -= numRead; - } - return numRead; - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/dvcs/CCPDRequestBuilder.java b/pkix/src/main/java/org/bouncycastle/dvcs/CCPDRequestBuilder.java deleted file mode 100644 index d8ed653a..00000000 --- a/pkix/src/main/java/org/bouncycastle/dvcs/CCPDRequestBuilder.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.bouncycastle.dvcs; - -import org.bouncycastle.asn1.dvcs.DVCSRequestInformationBuilder; -import org.bouncycastle.asn1.dvcs.Data; -import org.bouncycastle.asn1.dvcs.ServiceType; - -/** - * Builder of CCPD requests (Certify Claim of Possession of Data). - */ -public class CCPDRequestBuilder - extends DVCSRequestBuilder -{ - public CCPDRequestBuilder() - { - super(new DVCSRequestInformationBuilder(ServiceType.CCPD)); - } - - /** - * Builds CCPD request. - * - * @param messageImprint - the message imprint to include. - * @return - * @throws DVCSException - */ - public DVCSRequest build(MessageImprint messageImprint) - throws DVCSException - { - Data data = new Data(messageImprint.toASN1Structure()); - - return createDVCRequest(data); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/dvcs/CCPDRequestData.java b/pkix/src/main/java/org/bouncycastle/dvcs/CCPDRequestData.java deleted file mode 100644 index d2edada3..00000000 --- a/pkix/src/main/java/org/bouncycastle/dvcs/CCPDRequestData.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.bouncycastle.dvcs; - -import org.bouncycastle.asn1.dvcs.Data; - -/** - * Data piece of DVCRequest for CCPD service (Certify Claim of Possession of Data). - * It contains CCPD-specific selector interface. - * <p/> - * This objects are constructed internally, - * to build DVCS request to CCPD service use CCPDRequestBuilder. - */ -public class CCPDRequestData - extends DVCSRequestData -{ - /** - * Construct from corresponding ASN.1 Data structure. - * Note, that data should have messageImprint choice, - * otherwise DVCSConstructionException is thrown. - * - * @param data - * @throws DVCSConstructionException - */ - CCPDRequestData(Data data) - throws DVCSConstructionException - { - super(data); - initDigest(); - } - - private void initDigest() - throws DVCSConstructionException - { - if (data.getMessageImprint() == null) - { - throw new DVCSConstructionException("DVCSRequest.data.messageImprint should be specified for CCPD service"); - } - } - - /** - * Get MessageImprint value - * - * @return - */ - public MessageImprint getMessageImprint() - { - return new MessageImprint(data.getMessageImprint()); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/dvcs/CPDRequestBuilder.java b/pkix/src/main/java/org/bouncycastle/dvcs/CPDRequestBuilder.java deleted file mode 100644 index 3d671f2e..00000000 --- a/pkix/src/main/java/org/bouncycastle/dvcs/CPDRequestBuilder.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.bouncycastle.dvcs; - -import java.io.IOException; - -import org.bouncycastle.asn1.dvcs.DVCSRequestInformationBuilder; -import org.bouncycastle.asn1.dvcs.Data; -import org.bouncycastle.asn1.dvcs.ServiceType; - -/** - * Builder of DVCSRequests to CPD service (Certify Possession of Data). - */ -public class CPDRequestBuilder - extends DVCSRequestBuilder -{ - public CPDRequestBuilder() - { - super(new DVCSRequestInformationBuilder(ServiceType.CPD)); - } - - /** - * Build CPD request. - * - * @param messageBytes - data to be certified - * @return - * @throws DVCSException - */ - public DVCSRequest build(byte[] messageBytes) - throws DVCSException, IOException - { - Data data = new Data(messageBytes); - - return createDVCRequest(data); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/dvcs/CPDRequestData.java b/pkix/src/main/java/org/bouncycastle/dvcs/CPDRequestData.java deleted file mode 100644 index 026b6011..00000000 --- a/pkix/src/main/java/org/bouncycastle/dvcs/CPDRequestData.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.bouncycastle.dvcs; - -import org.bouncycastle.asn1.dvcs.Data; - -/** - * Data piece of DVCRequest for CPD service (Certify Possession of Data). - * It contains CPD-specific selector interface. - * <p/> - * This objects are constructed internally, - * to build DVCS request to CPD service use CPDRequestBuilder. - */ -public class CPDRequestData - extends DVCSRequestData -{ - CPDRequestData(Data data) - throws DVCSConstructionException - { - super(data); - initMessage(); - } - - private void initMessage() - throws DVCSConstructionException - { - if (data.getMessage() == null) - { - throw new DVCSConstructionException("DVCSRequest.data.message should be specified for CPD service"); - } - } - - /** - * Get contained message (data to be certified). - * - * @return - */ - public byte[] getMessage() - { - return data.getMessage().getOctets(); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/dvcs/DVCSConstructionException.java b/pkix/src/main/java/org/bouncycastle/dvcs/DVCSConstructionException.java deleted file mode 100644 index ec865c86..00000000 --- a/pkix/src/main/java/org/bouncycastle/dvcs/DVCSConstructionException.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.bouncycastle.dvcs; - -/** - * Exception thrown when failed to initialize some DVCS-related staff. - */ -public class DVCSConstructionException - extends DVCSException -{ - private static final long serialVersionUID = 660035299653583980L; - - public DVCSConstructionException(String message) - { - super(message); - } - - public DVCSConstructionException(String message, Throwable cause) - { - super(message, cause); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/dvcs/DVCSException.java b/pkix/src/main/java/org/bouncycastle/dvcs/DVCSException.java deleted file mode 100644 index c5e3897d..00000000 --- a/pkix/src/main/java/org/bouncycastle/dvcs/DVCSException.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.bouncycastle.dvcs; - -/** - * General DVCSException. - */ -public class DVCSException - extends Exception -{ - private static final long serialVersionUID = 389345256020131488L; - - private Throwable cause; - - public DVCSException(String message) - { - super(message); - } - - public DVCSException(String message, Throwable cause) - { - super(message); - this.cause = cause; - } - - public Throwable getCause() - { - return cause; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/dvcs/DVCSMessage.java b/pkix/src/main/java/org/bouncycastle/dvcs/DVCSMessage.java deleted file mode 100644 index f6db5fac..00000000 --- a/pkix/src/main/java/org/bouncycastle/dvcs/DVCSMessage.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.bouncycastle.dvcs; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.cms.ContentInfo; - -public abstract class DVCSMessage -{ - private final ContentInfo contentInfo; - - protected DVCSMessage(ContentInfo contentInfo) - { - this.contentInfo = contentInfo; - } - - public ASN1ObjectIdentifier getContentType() - { - return contentInfo.getContentType(); - } - - public abstract ASN1Encodable getContent(); -} diff --git a/pkix/src/main/java/org/bouncycastle/dvcs/DVCSParsingException.java b/pkix/src/main/java/org/bouncycastle/dvcs/DVCSParsingException.java deleted file mode 100644 index a034e38d..00000000 --- a/pkix/src/main/java/org/bouncycastle/dvcs/DVCSParsingException.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.bouncycastle.dvcs; - -/** - * DVCS parsing exception - thrown when failed to parse DVCS message. - */ -public class DVCSParsingException - extends DVCSException -{ - private static final long serialVersionUID = -7895880961377691266L; - - public DVCSParsingException(String message) - { - super(message); - } - - public DVCSParsingException(String message, Throwable cause) - { - super(message, cause); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/dvcs/DVCSRequest.java b/pkix/src/main/java/org/bouncycastle/dvcs/DVCSRequest.java deleted file mode 100644 index b82f1f17..00000000 --- a/pkix/src/main/java/org/bouncycastle/dvcs/DVCSRequest.java +++ /dev/null @@ -1,134 +0,0 @@ -package org.bouncycastle.dvcs; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.cms.SignedData; -import org.bouncycastle.asn1.dvcs.DVCSObjectIdentifiers; -import org.bouncycastle.asn1.dvcs.ServiceType; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.cms.CMSSignedData; - -/** - * DVCRequest is general request to DVCS (RFC 3029). - * It represents requests for all types of services. - * Requests for different services differ in DVCData structure. - */ -public class DVCSRequest - extends DVCSMessage -{ - private org.bouncycastle.asn1.dvcs.DVCSRequest asn1; - private DVCSRequestInfo reqInfo; - private DVCSRequestData data; - - /** - * Constructs DVCRequest from CMS SignedData object. - * - * @param signedData the CMS SignedData object containing the request - * @throws DVCSConstructionException - */ - public DVCSRequest(CMSSignedData signedData) - throws DVCSConstructionException - { - this(SignedData.getInstance(signedData.toASN1Structure().getContent()).getEncapContentInfo()); - } - - /** - * Construct a DVCS Request from a ContentInfo - * - * @param contentInfo the contentInfo representing the DVCSRequest - * @throws DVCSConstructionException - */ - public DVCSRequest(ContentInfo contentInfo) - throws DVCSConstructionException - { - super(contentInfo); - - if (!DVCSObjectIdentifiers.id_ct_DVCSRequestData.equals(contentInfo.getContentType())) - { - throw new DVCSConstructionException("ContentInfo not a DVCS Request"); - } - - try - { - if (contentInfo.getContent().toASN1Primitive() instanceof ASN1Sequence) - { - this.asn1 = org.bouncycastle.asn1.dvcs.DVCSRequest.getInstance(contentInfo.getContent()); - } - else - { - this.asn1 = org.bouncycastle.asn1.dvcs.DVCSRequest.getInstance(ASN1OctetString.getInstance(contentInfo.getContent()).getOctets()); - } - } - catch (Exception e) - { - throw new DVCSConstructionException("Unable to parse content: " + e.getMessage(), e); - } - - this.reqInfo = new DVCSRequestInfo(asn1.getRequestInformation()); - - int service = reqInfo.getServiceType(); - if (service == ServiceType.CPD.getValue().intValue()) - { - this.data = new CPDRequestData(asn1.getData()); - } - else if (service == ServiceType.VSD.getValue().intValue()) - { - this.data = new VSDRequestData(asn1.getData()); - } - else if (service == ServiceType.VPKC.getValue().intValue()) - { - this.data = new VPKCRequestData(asn1.getData()); - } - else if (service == ServiceType.CCPD.getValue().intValue()) - { - this.data = new CCPDRequestData(asn1.getData()); - } - else - { - throw new DVCSConstructionException("Unknown service type: " + service); - } - } - - /** - * Return the ASN.1 DVCSRequest structure making up the body of this request. - * - * @return an org.bouncycastle.asn1.dvcs.DVCSRequest object. - */ - public ASN1Encodable getContent() - { - return asn1; - } - - /** - * Get RequestInformation envelope. - * - * @return the request info object. - */ - public DVCSRequestInfo getRequestInfo() - { - return reqInfo; - } - - /** - * Get data of DVCRequest. - * Depending on type of the request it could be different subclasses of DVCRequestData. - * - * @return the request Data object. - */ - public DVCSRequestData getData() - { - return data; - } - - /** - * Get the transaction identifier of request. - * - * @return the GeneralName representing the Transaction Identifier. - */ - public GeneralName getTransactionIdentifier() - { - return asn1.getTransactionIdentifier(); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/dvcs/DVCSRequestBuilder.java b/pkix/src/main/java/org/bouncycastle/dvcs/DVCSRequestBuilder.java deleted file mode 100644 index aab45707..00000000 --- a/pkix/src/main/java/org/bouncycastle/dvcs/DVCSRequestBuilder.java +++ /dev/null @@ -1,131 +0,0 @@ -package org.bouncycastle.dvcs; - -import java.io.IOException; -import java.math.BigInteger; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.dvcs.DVCSObjectIdentifiers; -import org.bouncycastle.asn1.dvcs.DVCSRequestInformationBuilder; -import org.bouncycastle.asn1.dvcs.Data; -import org.bouncycastle.asn1.x509.ExtensionsGenerator; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.asn1.x509.GeneralNames; -import org.bouncycastle.cms.CMSSignedDataGenerator; - -/** - * Common base class for client DVCRequest builders. - * This class aims at DVCSRequestInformation and TransactionIdentifier construction, - * and its subclasses - for Data field construction (as it is specific for the requested service). - */ -public abstract class DVCSRequestBuilder -{ - private final ExtensionsGenerator extGenerator = new ExtensionsGenerator(); - private final CMSSignedDataGenerator signedDataGen = new CMSSignedDataGenerator(); - - protected final DVCSRequestInformationBuilder requestInformationBuilder; - - protected DVCSRequestBuilder(DVCSRequestInformationBuilder requestInformationBuilder) - { - this.requestInformationBuilder = requestInformationBuilder; - } - - /** - * Set a nonce for this request, - * - * @param nonce - */ - public void setNonce(BigInteger nonce) - { - requestInformationBuilder.setNonce(nonce); - } - - /** - * Set requester name. - * - * @param requester - */ - public void setRequester(GeneralName requester) - { - requestInformationBuilder.setRequester(requester); - } - - /** - * Set DVCS name to generated requests. - * - * @param dvcs - */ - public void setDVCS(GeneralName dvcs) - { - requestInformationBuilder.setDVCS(dvcs); - } - - /** - * Set DVCS name to generated requests. - * - * @param dvcs - */ - public void setDVCS(GeneralNames dvcs) - { - requestInformationBuilder.setDVCS(dvcs); - } - - /** - * Set data location to generated requests. - * - * @param dataLocation - */ - public void setDataLocations(GeneralName dataLocation) - { - requestInformationBuilder.setDataLocations(dataLocation); - } - - /** - * Set data location to generated requests. - * - * @param dataLocations - */ - public void setDataLocations(GeneralNames dataLocations) - { - requestInformationBuilder.setDataLocations(dataLocations); - } - - /** - * Add a given extension field. - * - * @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. - * @throws DVCSException if there is an issue encoding the extension for adding. - */ - public void addExtension( - ASN1ObjectIdentifier oid, - boolean isCritical, - ASN1Encodable value) - throws DVCSException - { - try - { - extGenerator.addExtension(oid, isCritical, value); - } - catch (IOException e) - { - throw new DVCSException("cannot encode extension: " + e.getMessage(), e); - } - } - - protected DVCSRequest createDVCRequest(Data data) - throws DVCSException - { - if (!extGenerator.isEmpty()) - { - requestInformationBuilder.setExtensions(extGenerator.generate()); - } - - org.bouncycastle.asn1.dvcs.DVCSRequest request = new org.bouncycastle.asn1.dvcs.DVCSRequest(requestInformationBuilder.build(), data); - - return new DVCSRequest(new ContentInfo(DVCSObjectIdentifiers.id_ct_DVCSRequestData, request)); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/dvcs/DVCSRequestData.java b/pkix/src/main/java/org/bouncycastle/dvcs/DVCSRequestData.java deleted file mode 100644 index 3dbc6ba9..00000000 --- a/pkix/src/main/java/org/bouncycastle/dvcs/DVCSRequestData.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.bouncycastle.dvcs; - -import org.bouncycastle.asn1.dvcs.Data; - -/** - * Data piece of DVCRequest object (DVCS Data structure). - * Its contents depend on the service type. - * Its subclasses define the service-specific interface. - * <p/> - * The concrete objects of DVCRequestData are created by buildDVCRequestData static method. - */ -public abstract class DVCSRequestData -{ - /** - * The underlying data object is accessible by subclasses. - */ - protected Data data; - - /** - * The constructor is accessible by subclasses. - * - * @param data - */ - protected DVCSRequestData(Data data) - { - this.data = data; - } - - /** - * Convert to ASN.1 structure (Data). - * - * @return - */ - public Data toASN1Structure() - { - return data; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/dvcs/DVCSRequestInfo.java b/pkix/src/main/java/org/bouncycastle/dvcs/DVCSRequestInfo.java deleted file mode 100644 index 4d0767d8..00000000 --- a/pkix/src/main/java/org/bouncycastle/dvcs/DVCSRequestInfo.java +++ /dev/null @@ -1,237 +0,0 @@ -package org.bouncycastle.dvcs; - -import java.math.BigInteger; -import java.util.Date; - -import org.bouncycastle.asn1.dvcs.DVCSRequestInformation; -import org.bouncycastle.asn1.dvcs.DVCSTime; -import org.bouncycastle.asn1.x509.GeneralNames; -import org.bouncycastle.asn1.x509.PolicyInformation; -import org.bouncycastle.tsp.TimeStampToken; -import org.bouncycastle.util.Arrays; - -/** - * Information piece of DVCS requests. - * It is common for all types of DVCS requests. - */ -public class DVCSRequestInfo -{ - private DVCSRequestInformation data; - - /** - * Constructs DVCRequestInfo from byte array (DER encoded DVCSRequestInformation). - * - * @param in - */ - public DVCSRequestInfo(byte[] in) - { - this(DVCSRequestInformation.getInstance(in)); - } - - /** - * Constructs DVCRequestInfo from DVCSRequestInformation ASN.1 structure. - * - * @param data - */ - public DVCSRequestInfo(DVCSRequestInformation data) - { - this.data = data; - } - - /** - * Converts to corresponding ASN.1 structure (DVCSRequestInformation). - * - * @return - */ - public DVCSRequestInformation toASN1Structure() - { - return data; - } - - // - // DVCRequestInfo selector interface - // - - /** - * Get DVCS version of request. - * - * @return - */ - public int getVersion() - { - return data.getVersion(); - } - - /** - * Get requested service type. - * - * @return one of CPD, VSD, VPKC, CCPD (see constants). - */ - public int getServiceType() - { - return data.getService().getValue().intValue(); - } - - /** - * Get nonce if it is set. - * Note: this field can be set (if not present) or extended (if present) by DVCS. - * - * @return nonce value, or null if it is not set. - */ - public BigInteger getNonce() - { - return data.getNonce(); - } - - /** - * Get request generation time if it is set. - * - * @return time of request, or null if it is not set. - * @throws DVCSParsingException if a request time is present but cannot be extracted. - */ - public Date getRequestTime() - throws DVCSParsingException - { - DVCSTime time = data.getRequestTime(); - - if (time == null) - { - return null; - } - - try - { - if (time.getGenTime() != null) - { - return time.getGenTime().getDate(); - } - else - { - TimeStampToken token = new TimeStampToken(time.getTimeStampToken()); - - return token.getTimeStampInfo().getGenTime(); - } - } - catch (Exception e) - { - throw new DVCSParsingException("unable to extract time: " + e.getMessage(), e); - } - } - - /** - * Get names of requesting entity, if set. - * - * @return - */ - public GeneralNames getRequester() - { - return data.getRequester(); - } - - /** - * Get policy, under which the validation is requested. - * - * @return policy identifier or null, if any policy is acceptable. - */ - public PolicyInformation getRequestPolicy() - { - if (data.getRequestPolicy() != null) - { - return data.getRequestPolicy(); - } - return null; - } - - /** - * Get names of DVCS servers. - * Note: this field can be set by DVCS. - * - * @return - */ - public GeneralNames getDVCSNames() - { - return data.getDVCS(); - } - - /** - * Get data locations, where the copy of request Data can be obtained. - * Note: the exact meaning of field is up to applications. - * Note: this field can be set by DVCS. - * - * @return - */ - public GeneralNames getDataLocations() - { - return data.getDataLocations(); - } - - /** - * Compares two DVCRequestInfo structures: one from DVCRequest, and one from DVCResponse. - * This function implements RFC 3029, 9.1 checks of reqInfo. - * - * @param requestInfo - DVCRequestInfo of DVCRequest - * @param responseInfo - DVCRequestInfo of DVCResponse - * @return true if server's requestInfo matches client's requestInfo - */ - public static boolean validate(DVCSRequestInfo requestInfo, DVCSRequestInfo responseInfo) - { - // RFC 3029, 9.1 - // The DVCS MAY modify the fields: - // 'dvcs', 'requester', 'dataLocations', and 'nonce' of the ReqInfo structure. - - DVCSRequestInformation clientInfo = requestInfo.data; - DVCSRequestInformation serverInfo = responseInfo.data; - - if (clientInfo.getVersion() != serverInfo.getVersion()) - { - return false; - } - if (!clientEqualsServer(clientInfo.getService(), serverInfo.getService())) - { - return false; - } - if (!clientEqualsServer(clientInfo.getRequestTime(), serverInfo.getRequestTime())) - { - return false; - } - if (!clientEqualsServer(clientInfo.getRequestPolicy(), serverInfo.getRequestPolicy())) - { - return false; - } - if (!clientEqualsServer(clientInfo.getExtensions(), serverInfo.getExtensions())) - { - return false; - } - - // RFC 3029, 9.1. The only modification allowed to a 'nonce' - // is the inclusion of a new field if it was not present, - // or to concatenate other data to the end (right) of an existing value. - - if (clientInfo.getNonce() != null) - { - if (serverInfo.getNonce() == null) - { - return false; - } - byte[] clientNonce = clientInfo.getNonce().toByteArray(); - byte[] serverNonce = serverInfo.getNonce().toByteArray(); - if (serverNonce.length < clientNonce.length) - { - return false; - } - if (!Arrays.areEqual(clientNonce, Arrays.copyOfRange(serverNonce, 0, clientNonce.length))) - { - return false; - } - } - - return true; - } - - // null-protected compare of any two objects - private static boolean clientEqualsServer(Object client, Object server) - { - return (client == null && server == null) || (client != null && client.equals(server)); - } -} - diff --git a/pkix/src/main/java/org/bouncycastle/dvcs/DVCSResponse.java b/pkix/src/main/java/org/bouncycastle/dvcs/DVCSResponse.java deleted file mode 100644 index ac1a6b7d..00000000 --- a/pkix/src/main/java/org/bouncycastle/dvcs/DVCSResponse.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.bouncycastle.dvcs; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.cms.SignedData; -import org.bouncycastle.asn1.dvcs.DVCSObjectIdentifiers; -import org.bouncycastle.cms.CMSSignedData; - -/** - * DVCResponse is general response to DVCS (RFC 3029). - * It represents responses for all types of services. - */ -public class DVCSResponse - extends DVCSMessage -{ - private org.bouncycastle.asn1.dvcs.DVCSResponse asn1; - - /** - * Constructs DVCRequest from CMS SignedData object. - * - * @param signedData the CMS SignedData object containing the request - * @throws org.bouncycastle.dvcs.DVCSConstructionException - */ - public DVCSResponse(CMSSignedData signedData) - throws DVCSConstructionException - { - this(SignedData.getInstance(signedData.toASN1Structure().getContent()).getEncapContentInfo()); - } - - /** - * Construct a DVCS Request from a ContentInfo - * - * @param contentInfo the contentInfo representing the DVCSRequest - * @throws org.bouncycastle.dvcs.DVCSConstructionException - */ - public DVCSResponse(ContentInfo contentInfo) - throws DVCSConstructionException - { - super(contentInfo); - - if (!DVCSObjectIdentifiers.id_ct_DVCSResponseData.equals(contentInfo.getContentType())) - { - throw new DVCSConstructionException("ContentInfo not a DVCS Request"); - } - - try - { - if (contentInfo.getContent().toASN1Primitive() instanceof ASN1Sequence) - { - this.asn1 = org.bouncycastle.asn1.dvcs.DVCSResponse.getInstance(contentInfo.getContent()); - } - else - { - this.asn1 = org.bouncycastle.asn1.dvcs.DVCSResponse.getInstance(ASN1OctetString.getInstance(contentInfo.getContent()).getOctets()); - } - } - catch (Exception e) - { - throw new DVCSConstructionException("Unable to parse content: " + e.getMessage(), e); - } - } - - /** - * Return the ASN.1 DVCSResponse structure making up the body of this response. - * - * @return an org.bouncycastle.asn1.dvcs.DVCSResponse object. - */ - public ASN1Encodable getContent() - { - return asn1; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/dvcs/MessageImprint.java b/pkix/src/main/java/org/bouncycastle/dvcs/MessageImprint.java deleted file mode 100644 index 5f4fbc12..00000000 --- a/pkix/src/main/java/org/bouncycastle/dvcs/MessageImprint.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.bouncycastle.dvcs; - -import org.bouncycastle.asn1.x509.DigestInfo; - -public class MessageImprint -{ - private final DigestInfo messageImprint; - - public MessageImprint(DigestInfo messageImprint) - { - this.messageImprint = messageImprint; - } - - public DigestInfo toASN1Structure() - { - return messageImprint; - } - - public boolean equals(Object o) - { - if (o == this) - { - return true; - } - - if (o instanceof MessageImprint) - { - return messageImprint.equals(((MessageImprint)o).messageImprint); - } - - return false; - } - - public int hashCode() - { - return messageImprint.hashCode(); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/dvcs/MessageImprintBuilder.java b/pkix/src/main/java/org/bouncycastle/dvcs/MessageImprintBuilder.java deleted file mode 100644 index 052d4fe9..00000000 --- a/pkix/src/main/java/org/bouncycastle/dvcs/MessageImprintBuilder.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.bouncycastle.dvcs; - -import java.io.OutputStream; - -import org.bouncycastle.asn1.x509.DigestInfo; -import org.bouncycastle.operator.DigestCalculator; - -public class MessageImprintBuilder -{ - private final DigestCalculator digestCalculator; - - public MessageImprintBuilder(DigestCalculator digestCalculator) - { - this.digestCalculator = digestCalculator; - } - - public MessageImprint build(byte[] message) - throws DVCSException - { - try - { - OutputStream dOut = digestCalculator.getOutputStream(); - - dOut.write(message); - - dOut.close(); - - return new MessageImprint(new DigestInfo(digestCalculator.getAlgorithmIdentifier(), digestCalculator.getDigest())); - } - catch (Exception e) - { - throw new DVCSException("unable to build MessageImprint: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/dvcs/SignedDVCSMessageGenerator.java b/pkix/src/main/java/org/bouncycastle/dvcs/SignedDVCSMessageGenerator.java deleted file mode 100644 index 68be7775..00000000 --- a/pkix/src/main/java/org/bouncycastle/dvcs/SignedDVCSMessageGenerator.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.bouncycastle.dvcs; - -import java.io.IOException; - -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.CMSProcessableByteArray; -import org.bouncycastle.cms.CMSSignedData; -import org.bouncycastle.cms.CMSSignedDataGenerator; - -public class SignedDVCSMessageGenerator -{ - private final CMSSignedDataGenerator signedDataGen; - - public SignedDVCSMessageGenerator(CMSSignedDataGenerator signedDataGen) - { - this.signedDataGen = signedDataGen; - } - - /** - * Creates a CMSSignedData object containing the passed in DVCSMessage - * - * @param message the request to be signed. - * @return an encapsulating SignedData object. - * @throws DVCSException in the event of failure to encode the request or sign it. - */ - public CMSSignedData build(DVCSMessage message) - throws DVCSException - { - try - { - byte[] encapsulatedData = message.getContent().toASN1Primitive().getEncoded(ASN1Encoding.DER); - - return signedDataGen.generate(new CMSProcessableByteArray(message.getContentType(), encapsulatedData), true); - } - catch (CMSException e) - { - throw new DVCSException("Could not sign DVCS request", e); - } - catch (IOException e) - { - throw new DVCSException("Could not encode DVCS request", e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/dvcs/TargetChain.java b/pkix/src/main/java/org/bouncycastle/dvcs/TargetChain.java deleted file mode 100644 index 7dca8f8e..00000000 --- a/pkix/src/main/java/org/bouncycastle/dvcs/TargetChain.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.bouncycastle.dvcs; - -import org.bouncycastle.asn1.dvcs.TargetEtcChain; - -public class TargetChain -{ - private final TargetEtcChain certs; - - public TargetChain(TargetEtcChain certs) - { - this.certs = certs; - } - - public TargetEtcChain toASN1Structure() - { - return certs; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/dvcs/VPKCRequestBuilder.java b/pkix/src/main/java/org/bouncycastle/dvcs/VPKCRequestBuilder.java deleted file mode 100644 index 51e0307f..00000000 --- a/pkix/src/main/java/org/bouncycastle/dvcs/VPKCRequestBuilder.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.bouncycastle.dvcs; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import org.bouncycastle.asn1.dvcs.CertEtcToken; -import org.bouncycastle.asn1.dvcs.DVCSRequestInformationBuilder; -import org.bouncycastle.asn1.dvcs.DVCSTime; -import org.bouncycastle.asn1.dvcs.Data; -import org.bouncycastle.asn1.dvcs.ServiceType; -import org.bouncycastle.asn1.dvcs.TargetEtcChain; -import org.bouncycastle.asn1.x509.Extension; -import org.bouncycastle.cert.X509CertificateHolder; - -/** - * Builder of DVC requests to VPKC service (Verify Public Key Certificates). - */ -public class VPKCRequestBuilder - extends DVCSRequestBuilder -{ - private List chains = new ArrayList(); - - public VPKCRequestBuilder() - { - super(new DVCSRequestInformationBuilder(ServiceType.VPKC)); - } - - /** - * Adds a TargetChain representing a X.509 certificate to the request. - * - * @param cert the certificate to be added - */ - public void addTargetChain(X509CertificateHolder cert) - { - chains.add(new TargetEtcChain(new CertEtcToken(CertEtcToken.TAG_CERTIFICATE, cert.toASN1Structure()))); - } - - /** - * Adds a TargetChain representing a single X.509 Extension to the request - * - * @param extension the extension to be added. - */ - public void addTargetChain(Extension extension) - { - chains.add(new TargetEtcChain(new CertEtcToken(extension))); - } - - /** - * Adds a X.509 certificate to the request. - * - * @param targetChain the CertChain object to be added. - */ - public void addTargetChain(TargetChain targetChain) - { - chains.add(targetChain.toASN1Structure()); - } - - public void setRequestTime(Date requestTime) - { - requestInformationBuilder.setRequestTime(new DVCSTime(requestTime)); - } - - /** - * Build DVCS request to VPKC service. - * - * @throws DVCSException - */ - public DVCSRequest build() - throws DVCSException - { - Data data = new Data((TargetEtcChain[])chains.toArray(new TargetEtcChain[chains.size()])); - - return createDVCRequest(data); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/dvcs/VPKCRequestData.java b/pkix/src/main/java/org/bouncycastle/dvcs/VPKCRequestData.java deleted file mode 100644 index 9624ef7f..00000000 --- a/pkix/src/main/java/org/bouncycastle/dvcs/VPKCRequestData.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.bouncycastle.dvcs; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.bouncycastle.asn1.dvcs.Data; -import org.bouncycastle.asn1.dvcs.TargetEtcChain; - -/** - * Data piece of DVCS request to VPKC service (Verify Public Key Certificates). - * It contains VPKC-specific interface. - * <p/> - * This objects are constructed internally, - * to build DVCS request to VPKC service use VPKCRequestBuilder. - */ -public class VPKCRequestData - extends DVCSRequestData -{ - private List chains; - - VPKCRequestData(Data data) - throws DVCSConstructionException - { - super(data); - - TargetEtcChain[] certs = data.getCerts(); - - if (certs == null) - { - throw new DVCSConstructionException("DVCSRequest.data.certs should be specified for VPKC service"); - } - - chains = new ArrayList(certs.length); - - for (int i = 0; i != certs.length; i++) - { - chains.add(new TargetChain(certs[i])); - } - } - - /** - * Get contained certs choice data.. - * - * @return a list of CertChain objects. - */ - public List getCerts() - { - return Collections.unmodifiableList(chains); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/dvcs/VSDRequestBuilder.java b/pkix/src/main/java/org/bouncycastle/dvcs/VSDRequestBuilder.java deleted file mode 100644 index 52ca3203..00000000 --- a/pkix/src/main/java/org/bouncycastle/dvcs/VSDRequestBuilder.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.bouncycastle.dvcs; - -import java.io.IOException; -import java.util.Date; - -import org.bouncycastle.asn1.dvcs.DVCSRequestInformationBuilder; -import org.bouncycastle.asn1.dvcs.DVCSTime; -import org.bouncycastle.asn1.dvcs.Data; -import org.bouncycastle.asn1.dvcs.ServiceType; -import org.bouncycastle.cms.CMSSignedData; - -/** - * Builder of DVCS requests to VSD service (Verify Signed Document). - */ -public class VSDRequestBuilder - extends DVCSRequestBuilder -{ - public VSDRequestBuilder() - { - super(new DVCSRequestInformationBuilder(ServiceType.VSD)); - } - - public void setRequestTime(Date requestTime) - { - requestInformationBuilder.setRequestTime(new DVCSTime(requestTime)); - } - - /** - * Build VSD request from CMS SignedData object. - * - * @param document - * @return - * @throws DVCSException - */ - public DVCSRequest build(CMSSignedData document) - throws DVCSException - { - try - { - Data data = new Data(document.getEncoded()); - - return createDVCRequest(data); - } - catch (IOException e) - { - throw new DVCSException("Failed to encode CMS signed data", e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/dvcs/VSDRequestData.java b/pkix/src/main/java/org/bouncycastle/dvcs/VSDRequestData.java deleted file mode 100644 index 6823c0f0..00000000 --- a/pkix/src/main/java/org/bouncycastle/dvcs/VSDRequestData.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.bouncycastle.dvcs; - -import org.bouncycastle.asn1.dvcs.Data; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.CMSSignedData; - -/** - * Data piece of DVCS request to VSD service (Verify Signed Document). - * It contains VSD-specific selector interface. - * Note: the request should contain CMS SignedData object as message. - * <p/> - * This objects are constructed internally, - * to build DVCS request to VSD service use VSDRequestBuilder. - */ -public class VSDRequestData - extends DVCSRequestData -{ - private CMSSignedData doc; - - VSDRequestData(Data data) - throws DVCSConstructionException - { - super(data); - initDocument(); - } - - private void initDocument() - throws DVCSConstructionException - { - if (doc == null) - { - if (data.getMessage() == null) - { - throw new DVCSConstructionException("DVCSRequest.data.message should be specified for VSD service"); - } - try - { - doc = new CMSSignedData(data.getMessage().getOctets()); - } - catch (CMSException e) - { - throw new DVCSConstructionException("Can't read CMS SignedData from input", e); - } - } - } - - /** - * Get contained message (data to be certified). - * - * @return - */ - public byte[] getMessage() - { - return data.getMessage().getOctets(); - } - - /** - * Get the CMS SignedData object represented by the encoded message. - * - * @return - */ - public CMSSignedData getParsedMessage() - { - return doc; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/eac/EACCertificateBuilder.java b/pkix/src/main/java/org/bouncycastle/eac/EACCertificateBuilder.java deleted file mode 100644 index a5b33739..00000000 --- a/pkix/src/main/java/org/bouncycastle/eac/EACCertificateBuilder.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.bouncycastle.eac; - -import java.io.OutputStream; - -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.DERApplicationSpecific; -import org.bouncycastle.asn1.eac.CVCertificate; -import org.bouncycastle.asn1.eac.CertificateBody; -import org.bouncycastle.asn1.eac.CertificateHolderAuthorization; -import org.bouncycastle.asn1.eac.CertificateHolderReference; -import org.bouncycastle.asn1.eac.CertificationAuthorityReference; -import org.bouncycastle.asn1.eac.EACTags; -import org.bouncycastle.asn1.eac.PackedDate; -import org.bouncycastle.asn1.eac.PublicKeyDataObject; -import org.bouncycastle.eac.operator.EACSigner; - -public class EACCertificateBuilder -{ - private static final byte [] ZeroArray = new byte [] {0}; - - private PublicKeyDataObject publicKey; - private CertificateHolderAuthorization certificateHolderAuthorization; - private PackedDate certificateEffectiveDate; - private PackedDate certificateExpirationDate; - private CertificateHolderReference certificateHolderReference; - private CertificationAuthorityReference certificationAuthorityReference; - - public EACCertificateBuilder( - CertificationAuthorityReference certificationAuthorityReference, - PublicKeyDataObject publicKey, - CertificateHolderReference certificateHolderReference, - CertificateHolderAuthorization certificateHolderAuthorization, - PackedDate certificateEffectiveDate, - PackedDate certificateExpirationDate) - { - this.certificationAuthorityReference = certificationAuthorityReference; - this.publicKey = publicKey; - this.certificateHolderReference = certificateHolderReference; - this.certificateHolderAuthorization = certificateHolderAuthorization; - this.certificateEffectiveDate = certificateEffectiveDate; - this.certificateExpirationDate = certificateExpirationDate; - } - - private CertificateBody buildBody() - { - DERApplicationSpecific certificateProfileIdentifier; - - certificateProfileIdentifier = new DERApplicationSpecific( - EACTags.INTERCHANGE_PROFILE, ZeroArray); - - CertificateBody body = new CertificateBody( - certificateProfileIdentifier, - certificationAuthorityReference, - publicKey, - certificateHolderReference, - certificateHolderAuthorization, - certificateEffectiveDate, - certificateExpirationDate); - - return body; - } - - public EACCertificateHolder build(EACSigner signer) - throws EACException - { - try - { - CertificateBody body = buildBody(); - - OutputStream vOut = signer.getOutputStream(); - - vOut.write(body.getEncoded(ASN1Encoding.DER)); - - vOut.close(); - - return new EACCertificateHolder(new CVCertificate(body, signer.getSignature())); - } - catch (Exception e) - { - throw new EACException("unable to process signature: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/eac/EACCertificateHolder.java b/pkix/src/main/java/org/bouncycastle/eac/EACCertificateHolder.java deleted file mode 100644 index c5e2033c..00000000 --- a/pkix/src/main/java/org/bouncycastle/eac/EACCertificateHolder.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.bouncycastle.eac; - -import java.io.IOException; -import java.io.OutputStream; - -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.ASN1ParsingException; -import org.bouncycastle.asn1.eac.CVCertificate; -import org.bouncycastle.asn1.eac.PublicKeyDataObject; -import org.bouncycastle.eac.operator.EACSignatureVerifier; - -public class EACCertificateHolder -{ - private CVCertificate cvCertificate; - - private static CVCertificate parseBytes(byte[] certEncoding) - throws IOException - { - try - { - return CVCertificate.getInstance(certEncoding); - } - catch (ClassCastException e) - { - throw new EACIOException("malformed data: " + e.getMessage(), e); - } - catch (IllegalArgumentException e) - { - throw new EACIOException("malformed data: " + e.getMessage(), e); - } - catch (ASN1ParsingException e) - { - if (e.getCause() instanceof IOException) - { - throw (IOException)e.getCause(); - } - else - { - throw new EACIOException("malformed data: " + e.getMessage(), e); - } - } - } - - public EACCertificateHolder(byte[] certEncoding) - throws IOException - { - this(parseBytes(certEncoding)); - } - - public EACCertificateHolder(CVCertificate cvCertificate) - { - this.cvCertificate = cvCertificate; - } - - /** - * Return the underlying ASN.1 structure for the certificate in this holder. - * - * @return a X509CertificateStructure object. - */ - public CVCertificate toASN1Structure() - { - return cvCertificate; - } - - public PublicKeyDataObject getPublicKeyDataObject() - { - return cvCertificate.getBody().getPublicKey(); - } - - public boolean isSignatureValid(EACSignatureVerifier verifier) - throws EACException - { - try - { - OutputStream vOut = verifier.getOutputStream(); - - vOut.write(cvCertificate.getBody().getEncoded(ASN1Encoding.DER)); - - vOut.close(); - - return verifier.verify(cvCertificate.getSignature()); - } - catch (Exception e) - { - throw new EACException("unable to process signature: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/eac/EACCertificateRequestHolder.java b/pkix/src/main/java/org/bouncycastle/eac/EACCertificateRequestHolder.java deleted file mode 100644 index 560b7301..00000000 --- a/pkix/src/main/java/org/bouncycastle/eac/EACCertificateRequestHolder.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.bouncycastle.eac; - -import java.io.IOException; -import java.io.OutputStream; - -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.ASN1ParsingException; -import org.bouncycastle.asn1.eac.CVCertificateRequest; -import org.bouncycastle.asn1.eac.PublicKeyDataObject; -import org.bouncycastle.eac.operator.EACSignatureVerifier; - -public class EACCertificateRequestHolder -{ - private CVCertificateRequest request; - - private static CVCertificateRequest parseBytes(byte[] requestEncoding) - throws IOException - { - try - { - return CVCertificateRequest.getInstance(requestEncoding); - } - catch (ClassCastException e) - { - throw new EACIOException("malformed data: " + e.getMessage(), e); - } - catch (IllegalArgumentException e) - { - throw new EACIOException("malformed data: " + e.getMessage(), e); - } - catch (ASN1ParsingException e) - { - if (e.getCause() instanceof IOException) - { - throw (IOException)e.getCause(); - } - else - { - throw new EACIOException("malformed data: " + e.getMessage(), e); - } - } - } - - public EACCertificateRequestHolder(byte[] certEncoding) - throws IOException - { - this(parseBytes(certEncoding)); - } - - public EACCertificateRequestHolder(CVCertificateRequest request) - { - this.request = request; - } - - /** - * Return the underlying ASN.1 structure for the certificate in this holder. - * - * @return a X509CertificateStructure object. - */ - public CVCertificateRequest toASN1Structure() - { - return request; - } - - public PublicKeyDataObject getPublicKeyDataObject() - { - return request.getPublicKey(); - } - - public boolean isInnerSignatureValid(EACSignatureVerifier verifier) - throws EACException - { - try - { - OutputStream vOut = verifier.getOutputStream(); - - vOut.write(request.getCertificateBody().getEncoded(ASN1Encoding.DER)); - - vOut.close(); - - return verifier.verify(request.getInnerSignature()); - } - catch (Exception e) - { - throw new EACException("unable to process signature: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/eac/EACException.java b/pkix/src/main/java/org/bouncycastle/eac/EACException.java deleted file mode 100644 index b6e02cfa..00000000 --- a/pkix/src/main/java/org/bouncycastle/eac/EACException.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.bouncycastle.eac; - -/** - * General checked Exception thrown in the cert package and its sub-packages. - */ -public class EACException - extends Exception -{ - private Throwable cause; - - public EACException(String msg, Throwable cause) - { - super(msg); - - this.cause = cause; - } - - public EACException(String msg) - { - super(msg); - } - - public Throwable getCause() - { - return cause; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/eac/EACIOException.java b/pkix/src/main/java/org/bouncycastle/eac/EACIOException.java deleted file mode 100644 index 8aa480bc..00000000 --- a/pkix/src/main/java/org/bouncycastle/eac/EACIOException.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.bouncycastle.eac; - -import java.io.IOException; - -/** - * General IOException thrown in the cert package and its sub-packages. - */ -public class EACIOException - extends IOException -{ - private Throwable cause; - - public EACIOException(String msg, Throwable cause) - { - super(msg); - - this.cause = cause; - } - - public EACIOException(String msg) - { - super(msg); - } - - public Throwable getCause() - { - return cause; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/eac/jcajce/DefaultEACHelper.java b/pkix/src/main/java/org/bouncycastle/eac/jcajce/DefaultEACHelper.java deleted file mode 100644 index d281fb35..00000000 --- a/pkix/src/main/java/org/bouncycastle/eac/jcajce/DefaultEACHelper.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.bouncycastle.eac.jcajce; - -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; - -class DefaultEACHelper - implements EACHelper -{ - public KeyFactory createKeyFactory(String type) - throws NoSuchAlgorithmException - { - return KeyFactory.getInstance(type); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/eac/jcajce/EACHelper.java b/pkix/src/main/java/org/bouncycastle/eac/jcajce/EACHelper.java deleted file mode 100644 index 8c42a63d..00000000 --- a/pkix/src/main/java/org/bouncycastle/eac/jcajce/EACHelper.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.bouncycastle.eac.jcajce; - -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; - -interface EACHelper -{ - KeyFactory createKeyFactory(String type) - throws NoSuchProviderException, NoSuchAlgorithmException; -} diff --git a/pkix/src/main/java/org/bouncycastle/eac/jcajce/JcaPublicKeyConverter.java b/pkix/src/main/java/org/bouncycastle/eac/jcajce/JcaPublicKeyConverter.java deleted file mode 100644 index f47709b7..00000000 --- a/pkix/src/main/java/org/bouncycastle/eac/jcajce/JcaPublicKeyConverter.java +++ /dev/null @@ -1,168 +0,0 @@ -package org.bouncycastle.eac.jcajce; - -import java.math.BigInteger; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.Provider; -import java.security.PublicKey; -import java.security.interfaces.ECPublicKey; -import java.security.spec.ECField; -import java.security.spec.ECFieldFp; -import java.security.spec.EllipticCurve; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.RSAPublicKeySpec; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.eac.EACObjectIdentifiers; -import org.bouncycastle.asn1.eac.ECDSAPublicKey; -import org.bouncycastle.asn1.eac.PublicKeyDataObject; -import org.bouncycastle.asn1.eac.RSAPublicKey; -import org.bouncycastle.eac.EACException; -import org.bouncycastle.jce.spec.ECParameterSpec; -import org.bouncycastle.jce.spec.ECPublicKeySpec; -import org.bouncycastle.math.ec.ECCurve; -import org.bouncycastle.math.ec.ECPoint; - -public class JcaPublicKeyConverter -{ - private EACHelper helper = new DefaultEACHelper(); - - public JcaPublicKeyConverter setProvider(String providerName) - { - this.helper = new NamedEACHelper(providerName); - - return this; - } - - public JcaPublicKeyConverter setProvider(Provider provider) - { - this.helper = new ProviderEACHelper(provider); - - return this; - } - - public PublicKey getKey(PublicKeyDataObject publicKeyDataObject) - throws EACException, InvalidKeySpecException - { - if (publicKeyDataObject.getUsage().on(EACObjectIdentifiers.id_TA_ECDSA)) - { - return getECPublicKeyPublicKey((ECDSAPublicKey)publicKeyDataObject); - } - else - { - RSAPublicKey pubKey = (RSAPublicKey)publicKeyDataObject; - RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(pubKey.getModulus(), pubKey.getPublicExponent()); - - try - { - KeyFactory factk = helper.createKeyFactory("RSA"); - - return factk.generatePublic(pubKeySpec); - } - catch (NoSuchProviderException e) - { - throw new EACException("cannot find provider: " + e.getMessage(), e); - } - catch (NoSuchAlgorithmException e) - { - throw new EACException("cannot find algorithm ECDSA: " + e.getMessage(), e); - } - } - } - - private PublicKey getECPublicKeyPublicKey(ECDSAPublicKey key) - throws EACException, InvalidKeySpecException - { - ECParameterSpec spec = getParams(key); - ECCurve curve = spec.getCurve(); - - ECPoint point = curve.decodePoint(key.getPublicPointY()); - ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, spec); - - KeyFactory factk; - try - { - factk = helper.createKeyFactory("ECDSA"); - } - catch (NoSuchProviderException e) - { - throw new EACException("cannot find provider: " + e.getMessage(), e); - } - catch (NoSuchAlgorithmException e) - { - throw new EACException("cannot find algorithm ECDSA: " + e.getMessage(), e); - } - - return factk.generatePublic(pubKeySpec); - } - - private ECParameterSpec getParams(ECDSAPublicKey key) - { - if (!key.hasParameters()) - { - throw new IllegalArgumentException("Public key does not contains EC Params"); - } - - BigInteger p = key.getPrimeModulusP(); - ECCurve.Fp curve = new ECCurve.Fp(p, key.getFirstCoefA(), key.getSecondCoefB()); - - ECPoint G = curve.decodePoint(key.getBasePointG()); - - BigInteger order = key.getOrderOfBasePointR(); - BigInteger coFactor = key.getCofactorF(); - // TODO: update to use JDK 1.5 EC API - ECParameterSpec ecspec = new ECParameterSpec(curve, G, order, coFactor); - - return ecspec; - } - - public PublicKeyDataObject getPublicKeyDataObject(ASN1ObjectIdentifier usage, PublicKey publicKey) - { - if (publicKey instanceof java.security.interfaces.RSAPublicKey) - { - java.security.interfaces.RSAPublicKey pubKey = (java.security.interfaces.RSAPublicKey)publicKey; - - return new RSAPublicKey(usage, pubKey.getModulus(), pubKey.getPublicExponent()); - } - else - { - ECPublicKey pubKey = (ECPublicKey)publicKey; - java.security.spec.ECParameterSpec params = pubKey.getParams(); - - return new ECDSAPublicKey( - usage, - ((ECFieldFp)params.getCurve().getField()).getP(), - params.getCurve().getA(), params.getCurve().getB(), - convertPoint(convertCurve(params.getCurve()), params.getGenerator(), false).getEncoded(), - params.getOrder(), - convertPoint(convertCurve(params.getCurve()), pubKey.getW(), false).getEncoded(), - params.getCofactor()); - } - } - - private static org.bouncycastle.math.ec.ECPoint convertPoint( - ECCurve curve, - java.security.spec.ECPoint point, - boolean withCompression) - { - return curve.createPoint(point.getAffineX(), point.getAffineY(), withCompression); - } - - private static ECCurve convertCurve( - EllipticCurve ec) - { - ECField field = ec.getField(); - BigInteger a = ec.getA(); - BigInteger b = ec.getB(); - - if (field instanceof ECFieldFp) - { - return new ECCurve.Fp(((ECFieldFp)field).getP(), a, b); - } - else - { - throw new IllegalStateException("not implemented yet!!!"); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/eac/jcajce/NamedEACHelper.java b/pkix/src/main/java/org/bouncycastle/eac/jcajce/NamedEACHelper.java deleted file mode 100644 index e1af5be9..00000000 --- a/pkix/src/main/java/org/bouncycastle/eac/jcajce/NamedEACHelper.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.bouncycastle.eac.jcajce; - -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; - -class NamedEACHelper - implements EACHelper -{ - private final String providerName; - - NamedEACHelper(String providerName) - { - this.providerName = providerName; - } - - public KeyFactory createKeyFactory(String type) - throws NoSuchProviderException, NoSuchAlgorithmException - { - return KeyFactory.getInstance(type, providerName); - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/eac/jcajce/ProviderEACHelper.java b/pkix/src/main/java/org/bouncycastle/eac/jcajce/ProviderEACHelper.java deleted file mode 100644 index 5ecfee97..00000000 --- a/pkix/src/main/java/org/bouncycastle/eac/jcajce/ProviderEACHelper.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.bouncycastle.eac.jcajce; - -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.Provider; - -class ProviderEACHelper - implements EACHelper -{ - private final Provider provider; - - ProviderEACHelper(Provider provider) - { - this.provider = provider; - } - - public KeyFactory createKeyFactory(String type) - throws NoSuchAlgorithmException - { - return KeyFactory.getInstance(type, provider); - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/eac/operator/EACSignatureVerifier.java b/pkix/src/main/java/org/bouncycastle/eac/operator/EACSignatureVerifier.java deleted file mode 100644 index 2cd4b50a..00000000 --- a/pkix/src/main/java/org/bouncycastle/eac/operator/EACSignatureVerifier.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.bouncycastle.eac.operator; - -import java.io.OutputStream; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; - -public interface EACSignatureVerifier -{ - /** - * Return the usage OID specifying the signature type. - * - * @return algorithm oid. - */ - ASN1ObjectIdentifier getUsageIdentifier(); - - /** - * 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/pkix/src/main/java/org/bouncycastle/eac/operator/EACSigner.java b/pkix/src/main/java/org/bouncycastle/eac/operator/EACSigner.java deleted file mode 100644 index 999d8124..00000000 --- a/pkix/src/main/java/org/bouncycastle/eac/operator/EACSigner.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.bouncycastle.eac.operator; - -import java.io.OutputStream; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; - -public interface EACSigner -{ - ASN1ObjectIdentifier getUsageIdentifier(); - - /** - * 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/pkix/src/main/java/org/bouncycastle/eac/operator/jcajce/DefaultEACHelper.java b/pkix/src/main/java/org/bouncycastle/eac/operator/jcajce/DefaultEACHelper.java deleted file mode 100644 index a84fda77..00000000 --- a/pkix/src/main/java/org/bouncycastle/eac/operator/jcajce/DefaultEACHelper.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.bouncycastle.eac.operator.jcajce; - -import java.security.NoSuchAlgorithmException; -import java.security.Signature; - -class DefaultEACHelper - extends EACHelper -{ - protected Signature createSignature(String type) - throws NoSuchAlgorithmException - { - return Signature.getInstance(type); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/eac/operator/jcajce/EACHelper.java b/pkix/src/main/java/org/bouncycastle/eac/operator/jcajce/EACHelper.java deleted file mode 100644 index da756ff5..00000000 --- a/pkix/src/main/java/org/bouncycastle/eac/operator/jcajce/EACHelper.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.bouncycastle.eac.operator.jcajce; - -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.Signature; -import java.util.Hashtable; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.eac.EACObjectIdentifiers; - -abstract class EACHelper -{ - private static final Hashtable sigNames = new Hashtable(); - - static - { - sigNames.put(EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_1, "SHA1withRSA"); - sigNames.put(EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_256, "SHA256withRSA"); - sigNames.put(EACObjectIdentifiers.id_TA_RSA_PSS_SHA_1, "SHA1withRSAandMGF1"); - sigNames.put(EACObjectIdentifiers.id_TA_RSA_PSS_SHA_256, "SHA256withRSAandMGF1"); - sigNames.put(EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_512, "SHA512withRSA"); - sigNames.put(EACObjectIdentifiers.id_TA_RSA_PSS_SHA_512, "SHA512withRSAandMGF1"); - - sigNames.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_1, "SHA1withECDSA"); - sigNames.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224withECDSA"); - sigNames.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_256, "SHA256withECDSA"); - sigNames.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_384, "SHA384withECDSA"); - sigNames.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_512, "SHA512withECDSA"); - } - - public Signature getSignature(ASN1ObjectIdentifier oid) - throws NoSuchProviderException, NoSuchAlgorithmException - { - return createSignature((String)sigNames.get(oid)); - } - - protected abstract Signature createSignature(String type) - throws NoSuchProviderException, NoSuchAlgorithmException; -} diff --git a/pkix/src/main/java/org/bouncycastle/eac/operator/jcajce/EACUtil.java b/pkix/src/main/java/org/bouncycastle/eac/operator/jcajce/EACUtil.java deleted file mode 100644 index 5e5942a8..00000000 --- a/pkix/src/main/java/org/bouncycastle/eac/operator/jcajce/EACUtil.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.bouncycastle.eac.operator.jcajce; - -class EACUtil -{ -} diff --git a/pkix/src/main/java/org/bouncycastle/eac/operator/jcajce/JcaEACSignatureVerifierBuilder.java b/pkix/src/main/java/org/bouncycastle/eac/operator/jcajce/JcaEACSignatureVerifierBuilder.java deleted file mode 100644 index 51156423..00000000 --- a/pkix/src/main/java/org/bouncycastle/eac/operator/jcajce/JcaEACSignatureVerifierBuilder.java +++ /dev/null @@ -1,181 +0,0 @@ -package org.bouncycastle.eac.operator.jcajce; - -import java.io.IOException; -import java.io.OutputStream; -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.Provider; -import java.security.PublicKey; -import java.security.Signature; -import java.security.SignatureException; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.eac.EACObjectIdentifiers; -import org.bouncycastle.eac.operator.EACSignatureVerifier; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.operator.OperatorStreamException; -import org.bouncycastle.operator.RuntimeOperatorException; - -public class JcaEACSignatureVerifierBuilder -{ - private EACHelper helper = new DefaultEACHelper(); - - public JcaEACSignatureVerifierBuilder setProvider(String providerName) - { - this.helper = new NamedEACHelper(providerName); - - return this; - } - - public JcaEACSignatureVerifierBuilder setProvider(Provider provider) - { - this.helper = new ProviderEACHelper(provider); - - return this; - } - - public EACSignatureVerifier build(final ASN1ObjectIdentifier usageOid, PublicKey pubKey) - throws OperatorCreationException - { - Signature sig; - try - { - sig = helper.getSignature(usageOid); - - sig.initVerify(pubKey); - } - catch (NoSuchAlgorithmException e) - { - throw new OperatorCreationException("unable to find algorithm: " + e.getMessage(), e); - } - catch (NoSuchProviderException e) - { - throw new OperatorCreationException("unable to find provider: " + e.getMessage(), e); - } - catch (InvalidKeyException e) - { - throw new OperatorCreationException("invalid key: " + e.getMessage(), e); - } - - final SignatureOutputStream sigStream = new SignatureOutputStream(sig); - - return new EACSignatureVerifier() - { - public ASN1ObjectIdentifier getUsageIdentifier() - { - return usageOid; - } - - public OutputStream getOutputStream() - { - return sigStream; - } - - public boolean verify(byte[] expected) - { - try - { - if (usageOid.on(EACObjectIdentifiers.id_TA_ECDSA)) - { - try - { - byte[] reencoded = derEncode(expected); - - return sigStream.verify(reencoded); - } - catch (Exception e) - { - return false; - } - } - else - { - return sigStream.verify(expected); - } - } - catch (SignatureException e) - { - throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e); - } - } - }; - } - - private static byte[] derEncode(byte[] rawSign) throws IOException - { - int len = rawSign.length / 2; - - byte[] r = new byte[len]; - byte[] s = new byte[len]; - System.arraycopy(rawSign, 0, r, 0, len); - System.arraycopy(rawSign, len, s, 0, len); - - ASN1EncodableVector v = new ASN1EncodableVector(); - v.add(new ASN1Integer(new BigInteger(1, r))); - v.add(new ASN1Integer(new BigInteger(1, s))); - - DERSequence seq = new DERSequence(v); - return seq.getEncoded(); - } - - 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); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/eac/operator/jcajce/JcaEACSignerBuilder.java b/pkix/src/main/java/org/bouncycastle/eac/operator/jcajce/JcaEACSignerBuilder.java deleted file mode 100644 index 380ec143..00000000 --- a/pkix/src/main/java/org/bouncycastle/eac/operator/jcajce/JcaEACSignerBuilder.java +++ /dev/null @@ -1,234 +0,0 @@ -package org.bouncycastle.eac.operator.jcajce; - -import java.io.IOException; -import java.io.OutputStream; -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PrivateKey; -import java.security.Provider; -import java.security.Signature; -import java.security.SignatureException; -import java.util.Arrays; -import java.util.Hashtable; - -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.eac.EACObjectIdentifiers; -import org.bouncycastle.eac.operator.EACSigner; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.operator.OperatorStreamException; -import org.bouncycastle.operator.RuntimeOperatorException; - -public class JcaEACSignerBuilder -{ - private static final Hashtable sigNames = new Hashtable(); - - static - { - sigNames.put("SHA1withRSA", EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_1); - sigNames.put("SHA256withRSA", EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_256); - sigNames.put("SHA1withRSAandMGF1", EACObjectIdentifiers.id_TA_RSA_PSS_SHA_1); - sigNames.put("SHA256withRSAandMGF1", EACObjectIdentifiers.id_TA_RSA_PSS_SHA_256); - sigNames.put("SHA512withRSA", EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_512); - sigNames.put("SHA512withRSAandMGF1", EACObjectIdentifiers.id_TA_RSA_PSS_SHA_512); - - sigNames.put("SHA1withECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1); - sigNames.put("SHA224withECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_224); - sigNames.put("SHA256withECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_256); - sigNames.put("SHA384withECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_384); - sigNames.put("SHA512withECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_512); - } - - private EACHelper helper = new DefaultEACHelper(); - - public JcaEACSignerBuilder setProvider(String providerName) - { - this.helper = new NamedEACHelper(providerName); - - return this; - } - - public JcaEACSignerBuilder setProvider(Provider provider) - { - this.helper = new ProviderEACHelper(provider); - - return this; - } - - public EACSigner build(String algorithm, PrivateKey privKey) - throws OperatorCreationException - { - return build((ASN1ObjectIdentifier)sigNames.get(algorithm), privKey); - } - - public EACSigner build(final ASN1ObjectIdentifier usageOid, PrivateKey privKey) - throws OperatorCreationException - { - Signature sig; - try - { - sig = helper.getSignature(usageOid); - - sig.initSign(privKey); - } - catch (NoSuchAlgorithmException e) - { - throw new OperatorCreationException("unable to find algorithm: " + e.getMessage(), e); - } - catch (NoSuchProviderException e) - { - throw new OperatorCreationException("unable to find provider: " + e.getMessage(), e); - } - catch (InvalidKeyException e) - { - throw new OperatorCreationException("invalid key: " + e.getMessage(), e); - } - - final SignatureOutputStream sigStream = new SignatureOutputStream(sig); - - return new EACSigner() - { - public ASN1ObjectIdentifier getUsageIdentifier() - { - return usageOid; - } - - public OutputStream getOutputStream() - { - return sigStream; - } - - public byte[] getSignature() - { - try - { - byte[] signature = sigStream.getSignature(); - - if (usageOid.on(EACObjectIdentifiers.id_TA_ECDSA)) - { - return reencode(signature); - } - - return signature; - } - catch (SignatureException e) - { - throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e); - } - } - }; - } - - public static int max(int el1, int el2) - { - return el1 > el2 ? el1 : el2; - } - - private static byte[] reencode(byte[] rawSign) - { - ASN1Sequence sData = ASN1Sequence.getInstance(rawSign); - - BigInteger r = ASN1Integer.getInstance(sData.getObjectAt(0)).getValue(); - BigInteger s = ASN1Integer.getInstance(sData.getObjectAt(1)).getValue(); - - byte[] rB = r.toByteArray(); - byte[] sB = s.toByteArray(); - - int rLen = unsignedIntLength(rB); - int sLen = unsignedIntLength(sB); - - byte[] ret; - int len = max(rLen, sLen); - - ret = new byte[len * 2]; - Arrays.fill(ret, (byte)0); - - copyUnsignedInt(rB, ret, len - rLen); - copyUnsignedInt(sB, ret, 2 * len - sLen); - - return ret; - } - - private static int unsignedIntLength(byte[] i) - { - int len = i.length; - if (i[0] == 0) - { - len--; - } - - return len; - } - - private static void copyUnsignedInt(byte[] src, byte[] dst, int offset) - { - int len = src.length; - int readoffset = 0; - if (src[0] == 0) - { - len--; - readoffset = 1; - } - - System.arraycopy(src, readoffset, dst, offset, len); - } - - 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/pkix/src/main/java/org/bouncycastle/eac/operator/jcajce/NamedEACHelper.java b/pkix/src/main/java/org/bouncycastle/eac/operator/jcajce/NamedEACHelper.java deleted file mode 100644 index 511cfcf2..00000000 --- a/pkix/src/main/java/org/bouncycastle/eac/operator/jcajce/NamedEACHelper.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.bouncycastle.eac.operator.jcajce; - -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.Signature; - -class NamedEACHelper - extends EACHelper -{ - private final String providerName; - - NamedEACHelper(String providerName) - { - this.providerName = providerName; - } - - protected Signature createSignature(String type) - throws NoSuchProviderException, NoSuchAlgorithmException - { - return Signature.getInstance(type, providerName); - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/eac/operator/jcajce/ProviderEACHelper.java b/pkix/src/main/java/org/bouncycastle/eac/operator/jcajce/ProviderEACHelper.java deleted file mode 100644 index 148a41eb..00000000 --- a/pkix/src/main/java/org/bouncycastle/eac/operator/jcajce/ProviderEACHelper.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.bouncycastle.eac.operator.jcajce; - -import java.security.NoSuchAlgorithmException; -import java.security.Provider; -import java.security.Signature; - -class ProviderEACHelper - extends EACHelper -{ - private final Provider provider; - - ProviderEACHelper(Provider provider) - { - this.provider = provider; - } - - protected Signature createSignature(String type) - throws NoSuchAlgorithmException - { - return Signature.getInstance(type, provider); - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/mozilla/SignedPublicKeyAndChallenge.java b/pkix/src/main/java/org/bouncycastle/mozilla/SignedPublicKeyAndChallenge.java deleted file mode 100644 index f9c4bcad..00000000 --- a/pkix/src/main/java/org/bouncycastle/mozilla/SignedPublicKeyAndChallenge.java +++ /dev/null @@ -1,139 +0,0 @@ -package org.bouncycastle.mozilla; - -import java.io.ByteArrayInputStream; -import java.security.InvalidKeyException; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PublicKey; -import java.security.Signature; -import java.security.SignatureException; -import java.security.spec.X509EncodedKeySpec; - -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.ASN1Object; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.mozilla.PublicKeyAndChallenge; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; - -/** - * This is designed to parse the SignedPublicKeyAndChallenge created by the - * KEYGEN tag included by Mozilla based browsers. - * <pre> - * PublicKeyAndChallenge ::= SEQUENCE { - * spki SubjectPublicKeyInfo, - * challenge IA5STRING - * } - * - * SignedPublicKeyAndChallenge ::= SEQUENCE { - * publicKeyAndChallenge PublicKeyAndChallenge, - * signatureAlgorithm AlgorithmIdentifier, - * signature BIT STRING - * } - * </pre> - */ -public class SignedPublicKeyAndChallenge - extends ASN1Object -{ - private static ASN1Sequence toDERSequence(byte[] bytes) - { - try - { - ByteArrayInputStream bIn = new ByteArrayInputStream(bytes); - ASN1InputStream aIn = new ASN1InputStream(bIn); - - return (ASN1Sequence)aIn.readObject(); - } - catch (Exception e) - { - throw new IllegalArgumentException("badly encoded request"); - } - } - - private ASN1Sequence spkacSeq; - private PublicKeyAndChallenge pkac; - private AlgorithmIdentifier signatureAlgorithm; - private DERBitString signature; - - public SignedPublicKeyAndChallenge(byte[] bytes) - { - spkacSeq = toDERSequence(bytes); - pkac = PublicKeyAndChallenge.getInstance(spkacSeq.getObjectAt(0)); - signatureAlgorithm = - AlgorithmIdentifier.getInstance(spkacSeq.getObjectAt(1)); - signature = (DERBitString)spkacSeq.getObjectAt(2); - } - - public ASN1Primitive toASN1Primitive() - { - return spkacSeq; - } - - public PublicKeyAndChallenge getPublicKeyAndChallenge() - { - return pkac; - } - - public boolean verify() - throws NoSuchAlgorithmException, SignatureException, - NoSuchProviderException, InvalidKeyException - { - return verify(null); - } - - public boolean verify(String provider) - throws NoSuchAlgorithmException, SignatureException, - NoSuchProviderException, InvalidKeyException - { - Signature sig = null; - if (provider == null) - { - sig = Signature.getInstance(signatureAlgorithm.getAlgorithm().getId()); - } - else - { - sig = Signature.getInstance(signatureAlgorithm.getAlgorithm().getId(), provider); - } - PublicKey pubKey = this.getPublicKey(provider); - sig.initVerify(pubKey); - try - { - DERBitString pkBytes = new DERBitString(pkac); - sig.update(pkBytes.getBytes()); - - return sig.verify(signature.getBytes()); - } - catch (Exception e) - { - throw new InvalidKeyException("error encoding public key"); - } - } - - public PublicKey getPublicKey(String provider) - throws NoSuchAlgorithmException, NoSuchProviderException, - InvalidKeyException - { - SubjectPublicKeyInfo subjectPKInfo = pkac.getSubjectPublicKeyInfo(); - try - { - DERBitString bStr = new DERBitString(subjectPKInfo); - X509EncodedKeySpec xspec = new X509EncodedKeySpec(bStr.getBytes()); - - - AlgorithmIdentifier keyAlg = subjectPKInfo.getAlgorithm(); - - KeyFactory factory = - KeyFactory.getInstance(keyAlg.getAlgorithm().getId(),provider); - - return factory.generatePublic(xspec); - - } - catch (Exception e) - { - throw new InvalidKeyException("error encoding public key"); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/EncryptionException.java b/pkix/src/main/java/org/bouncycastle/openssl/EncryptionException.java deleted file mode 100644 index 67db2073..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/EncryptionException.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.bouncycastle.openssl; - -public class EncryptionException - extends PEMException -{ - private Throwable cause; - - public EncryptionException(String msg) - { - super(msg); - } - - public EncryptionException(String msg, Throwable ex) - { - super(msg); - this.cause = ex; - } - - public Throwable getCause() - { - return cause; - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/openssl/MiscPEMGenerator.java b/pkix/src/main/java/org/bouncycastle/openssl/MiscPEMGenerator.java deleted file mode 100644 index 02866883..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/MiscPEMGenerator.java +++ /dev/null @@ -1,209 +0,0 @@ -package org.bouncycastle.openssl; - -import java.io.IOException; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.asn1.x509.DSAParameter; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; -import org.bouncycastle.cert.X509AttributeCertificateHolder; -import org.bouncycastle.cert.X509CRLHolder; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.pkcs.PKCS10CertificationRequest; -import org.bouncycastle.util.Strings; -import org.bouncycastle.util.io.pem.PemGenerationException; -import org.bouncycastle.util.io.pem.PemHeader; -import org.bouncycastle.util.io.pem.PemObject; -import org.bouncycastle.util.io.pem.PemObjectGenerator; - -/** - * PEM generator for the original set of PEM objects used in Open SSL. - */ -public class MiscPEMGenerator - implements PemObjectGenerator -{ - private static final ASN1ObjectIdentifier[] dsaOids = - { - X9ObjectIdentifiers.id_dsa, - OIWObjectIdentifiers.dsaWithSHA1 - }; - - private static final byte[] hexEncodingTable = - { - (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', - (byte)'8', (byte)'9', (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F' - }; - - private final Object obj; - private final PEMEncryptor encryptor; - - public MiscPEMGenerator(Object o) - { - this.obj = o; // use of this confuses some earlier JDKs. - this.encryptor = null; - } - - public MiscPEMGenerator(Object o, PEMEncryptor encryptor) - { - this.obj = o; - this.encryptor = encryptor; - } - - private PemObject createPemObject(Object o) - throws IOException - { - String type; - byte[] encoding; - - if (o instanceof PemObject) - { - return (PemObject)o; - } - if (o instanceof PemObjectGenerator) - { - return ((PemObjectGenerator)o).generate(); - } - if (o instanceof X509CertificateHolder) - { - type = "CERTIFICATE"; - - encoding = ((X509CertificateHolder)o).getEncoded(); - } - else if (o instanceof X509CRLHolder) - { - type = "X509 CRL"; - - encoding = ((X509CRLHolder)o).getEncoded(); - } - else if (o instanceof PrivateKeyInfo) - { - PrivateKeyInfo info = (PrivateKeyInfo)o; - ASN1ObjectIdentifier algOID = info.getPrivateKeyAlgorithm().getAlgorithm(); - - if (algOID.equals(PKCSObjectIdentifiers.rsaEncryption)) - { - type = "RSA PRIVATE KEY"; - - encoding = info.parsePrivateKey().toASN1Primitive().getEncoded(); - } - else if (algOID.equals(dsaOids[0]) || algOID.equals(dsaOids[1])) - { - type = "DSA PRIVATE KEY"; - - DSAParameter p = DSAParameter.getInstance(info.getPrivateKeyAlgorithm().getParameters()); - ASN1EncodableVector v = new ASN1EncodableVector(); - - v.add(new ASN1Integer(0)); - v.add(new ASN1Integer(p.getP())); - v.add(new ASN1Integer(p.getQ())); - v.add(new ASN1Integer(p.getG())); - - BigInteger x = ASN1Integer.getInstance(info.parsePrivateKey()).getValue(); - BigInteger y = p.getG().modPow(x, p.getP()); - - v.add(new ASN1Integer(y)); - v.add(new ASN1Integer(x)); - - encoding = new DERSequence(v).getEncoded(); - } - else if (algOID.equals(X9ObjectIdentifiers.id_ecPublicKey)) - { - type = "EC PRIVATE KEY"; - - encoding = info.parsePrivateKey().toASN1Primitive().getEncoded(); - } - else - { - throw new IOException("Cannot identify private key"); - } - } - else if (o instanceof SubjectPublicKeyInfo) - { - type = "PUBLIC KEY"; - - encoding = ((SubjectPublicKeyInfo)o).getEncoded(); - } - else if (o instanceof X509AttributeCertificateHolder) - { - type = "ATTRIBUTE CERTIFICATE"; - encoding = ((X509AttributeCertificateHolder)o).getEncoded(); - } - else if (o instanceof org.bouncycastle.pkcs.PKCS10CertificationRequest) - { - type = "CERTIFICATE REQUEST"; - encoding = ((PKCS10CertificationRequest)o).getEncoded(); - } - else if (o instanceof ContentInfo) - { - type = "PKCS7"; - encoding = ((ContentInfo)o).getEncoded(); - } - else - { - throw new PemGenerationException("unknown object passed - can't encode."); - } - - if (encryptor != null) - { - String dekAlgName = Strings.toUpperCase(encryptor.getAlgorithm()); - - // Note: For backward compatibility - if (dekAlgName.equals("DESEDE")) - { - dekAlgName = "DES-EDE3-CBC"; - } - - - byte[] iv = encryptor.getIV(); - - byte[] encData = encryptor.encrypt(encoding); - - List headers = new ArrayList(2); - - headers.add(new PemHeader("Proc-Type", "4,ENCRYPTED")); - headers.add(new PemHeader("DEK-Info", dekAlgName + "," + getHexEncoded(iv))); - - return new PemObject(type, headers, encData); - } - return new PemObject(type, encoding); - } - - private String getHexEncoded(byte[] bytes) - throws IOException - { - char[] chars = new char[bytes.length * 2]; - - for (int i = 0; i != bytes.length; i++) - { - int v = bytes[i] & 0xff; - - chars[2 * i] = (char)(hexEncodingTable[(v >>> 4)]); - chars[2 * i + 1] = (char)(hexEncodingTable[v & 0xf]); - } - - return new String(chars); - } - - public PemObject generate() - throws PemGenerationException - { - try - { - return createPemObject(obj); - } - catch (IOException e) - { - throw new PemGenerationException("encoding exception: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/PEMDecryptor.java b/pkix/src/main/java/org/bouncycastle/openssl/PEMDecryptor.java deleted file mode 100644 index 09cef5b7..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/PEMDecryptor.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.bouncycastle.openssl; - -public interface PEMDecryptor -{ - byte[] decrypt(byte[] keyBytes, byte[] iv) - throws PEMException; -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/PEMDecryptorProvider.java b/pkix/src/main/java/org/bouncycastle/openssl/PEMDecryptorProvider.java deleted file mode 100644 index b1827cde..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/PEMDecryptorProvider.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.bouncycastle.openssl; - -import org.bouncycastle.operator.OperatorCreationException; - -public interface PEMDecryptorProvider -{ - PEMDecryptor get(String dekAlgName) - throws OperatorCreationException; -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/PEMEncryptedKeyPair.java b/pkix/src/main/java/org/bouncycastle/openssl/PEMEncryptedKeyPair.java deleted file mode 100644 index 4c28f8d1..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/PEMEncryptedKeyPair.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.bouncycastle.openssl; - -import java.io.IOException; - -import org.bouncycastle.operator.OperatorCreationException; - -public class PEMEncryptedKeyPair -{ - private final String dekAlgName; - private final byte[] iv; - private final byte[] keyBytes; - private final PEMKeyPairParser parser; - - PEMEncryptedKeyPair(String dekAlgName, byte[] iv, byte[] keyBytes, PEMKeyPairParser parser) - { - this.dekAlgName = dekAlgName; - this.iv = iv; - this.keyBytes = keyBytes; - this.parser = parser; - } - - public PEMKeyPair decryptKeyPair(PEMDecryptorProvider keyDecryptorProvider) - throws IOException - { - try - { - PEMDecryptor keyDecryptor = keyDecryptorProvider.get(dekAlgName); - - return parser.parse(keyDecryptor.decrypt(keyBytes, iv)); - } - catch (IOException e) - { - throw e; - } - catch (OperatorCreationException e) - { - throw new PEMException("cannot create extraction operator: " + e.getMessage(), e); - } - catch (Exception e) - { - throw new PEMException("exception processing key pair: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/PEMEncryptor.java b/pkix/src/main/java/org/bouncycastle/openssl/PEMEncryptor.java deleted file mode 100644 index 5fb6647a..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/PEMEncryptor.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.bouncycastle.openssl; - -public interface PEMEncryptor -{ - String getAlgorithm(); - - byte[] getIV(); - - byte[] encrypt(byte[] encoding) - throws PEMException; -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/PEMException.java b/pkix/src/main/java/org/bouncycastle/openssl/PEMException.java deleted file mode 100644 index 3753aece..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/PEMException.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.bouncycastle.openssl; - -import java.io.IOException; - -public class PEMException - extends IOException -{ - Exception underlying; - - public PEMException( - String message) - { - super(message); - } - - public PEMException( - String message, - Exception underlying) - { - super(message); - this.underlying = underlying; - } - - public Exception getUnderlyingException() - { - return underlying; - } - - - public Throwable getCause() - { - return underlying; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/PEMKeyPair.java b/pkix/src/main/java/org/bouncycastle/openssl/PEMKeyPair.java deleted file mode 100644 index 077934e1..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/PEMKeyPair.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.bouncycastle.openssl; - -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; - -public class PEMKeyPair -{ - private final SubjectPublicKeyInfo publicKeyInfo; - private final PrivateKeyInfo privateKeyInfo; - - public PEMKeyPair(SubjectPublicKeyInfo publicKeyInfo, PrivateKeyInfo privateKeyInfo) - { - this.publicKeyInfo = publicKeyInfo; - this.privateKeyInfo = privateKeyInfo; - } - - public PrivateKeyInfo getPrivateKeyInfo() - { - return privateKeyInfo; - } - - public SubjectPublicKeyInfo getPublicKeyInfo() - { - return publicKeyInfo; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/PEMKeyPairParser.java b/pkix/src/main/java/org/bouncycastle/openssl/PEMKeyPairParser.java deleted file mode 100644 index fc0cb041..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/PEMKeyPairParser.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.bouncycastle.openssl; - -import java.io.IOException; - -interface PEMKeyPairParser -{ - PEMKeyPair parse(byte[] encoding) - throws IOException; -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/PEMParser.java b/pkix/src/main/java/org/bouncycastle/openssl/PEMParser.java deleted file mode 100644 index dacdba44..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/PEMParser.java +++ /dev/null @@ -1,510 +0,0 @@ -package org.bouncycastle.openssl; - -import java.io.IOException; -import java.io.Reader; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; - -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.asn1.pkcs.RSAPublicKey; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.DSAParameter; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.asn1.x9.X9ECParameters; -import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; -import org.bouncycastle.cert.X509AttributeCertificateHolder; -import org.bouncycastle.cert.X509CRLHolder; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.pkcs.PKCS10CertificationRequest; -import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo; -import org.bouncycastle.util.encoders.Hex; -import org.bouncycastle.util.io.pem.PemHeader; -import org.bouncycastle.util.io.pem.PemObject; -import org.bouncycastle.util.io.pem.PemObjectParser; -import org.bouncycastle.util.io.pem.PemReader; - -/** - * Class for parsing OpenSSL PEM encoded streams containing - * X509 certificates, PKCS8 encoded keys and PKCS7 objects. - * <p> - * In the case of PKCS7 objects the reader will return a CMS ContentInfo object. Public keys will be returned as - * well formed SubjectPublicKeyInfo objects, private keys will be returned as well formed PrivateKeyInfo objects. In the - * case of a private key a PEMKeyPair will normally be returned if the encoding contains both the private and public - * key definition. CRLs, Certificates, PKCS#10 requests, and Attribute Certificates will generate the appropriate BC holder class. - * </p> - */ -public class PEMParser - extends PemReader -{ - private final Map parsers = new HashMap(); - - /** - * Create a new PEMReader - * - * @param reader the Reader - */ - public PEMParser( - Reader reader) - { - super(reader); - - parsers.put("CERTIFICATE REQUEST", new PKCS10CertificationRequestParser()); - parsers.put("NEW CERTIFICATE REQUEST", new PKCS10CertificationRequestParser()); - parsers.put("CERTIFICATE", new X509CertificateParser()); - parsers.put("TRUSTED CERTIFICATE", new X509CertificateParser()); - parsers.put("X509 CERTIFICATE", new X509CertificateParser()); - parsers.put("X509 CRL", new X509CRLParser()); - parsers.put("PKCS7", new PKCS7Parser()); - parsers.put("ATTRIBUTE CERTIFICATE", new X509AttributeCertificateParser()); - parsers.put("EC PARAMETERS", new ECCurveParamsParser()); - parsers.put("PUBLIC KEY", new PublicKeyParser()); - parsers.put("RSA PUBLIC KEY", new RSAPublicKeyParser()); - parsers.put("RSA PRIVATE KEY", new KeyPairParser(new RSAKeyPairParser())); - parsers.put("DSA PRIVATE KEY", new KeyPairParser(new DSAKeyPairParser())); - parsers.put("EC PRIVATE KEY", new KeyPairParser(new ECDSAKeyPairParser())); - parsers.put("ENCRYPTED PRIVATE KEY", new EncryptedPrivateKeyParser()); - parsers.put("PRIVATE KEY", new PrivateKeyParser()); - } - - public Object readObject() - throws IOException - { - PemObject obj = readPemObject(); - - if (obj != null) - { - String type = obj.getType(); - if (parsers.containsKey(type)) - { - return ((PemObjectParser)parsers.get(type)).parseObject(obj); - } - else - { - throw new IOException("unrecognised object: " + type); - } - } - - return null; - } - - private class KeyPairParser - implements PemObjectParser - { - private final PEMKeyPairParser pemKeyPairParser; - - public KeyPairParser(PEMKeyPairParser pemKeyPairParser) - { - this.pemKeyPairParser = pemKeyPairParser; - } - - /** - * Read a Key Pair - */ - public Object parseObject( - PemObject obj) - throws IOException - { - boolean isEncrypted = false; - String dekInfo = null; - List headers = obj.getHeaders(); - - for (Iterator it = headers.iterator(); it.hasNext();) - { - PemHeader hdr = (PemHeader)it.next(); - - if (hdr.getName().equals("Proc-Type") && hdr.getValue().equals("4,ENCRYPTED")) - { - isEncrypted = true; - } - else if (hdr.getName().equals("DEK-Info")) - { - dekInfo = hdr.getValue(); - } - } - - // - // extract the key - // - byte[] keyBytes = obj.getContent(); - - try - { - if (isEncrypted) - { - StringTokenizer tknz = new StringTokenizer(dekInfo, ","); - String dekAlgName = tknz.nextToken(); - byte[] iv = Hex.decode(tknz.nextToken()); - - return new PEMEncryptedKeyPair(dekAlgName, iv, keyBytes, pemKeyPairParser); - } - - return pemKeyPairParser.parse(keyBytes); - } - catch (IOException e) - { - if (isEncrypted) - { - throw new PEMException("exception decoding - please check password and data.", e); - } - else - { - throw new PEMException(e.getMessage(), e); - } - } - catch (IllegalArgumentException e) - { - if (isEncrypted) - { - throw new PEMException("exception decoding - please check password and data.", e); - } - else - { - throw new PEMException(e.getMessage(), e); - } - } - } - } - - private class DSAKeyPairParser - implements PEMKeyPairParser - { - public PEMKeyPair parse(byte[] encoding) - throws IOException - { - try - { - ASN1Sequence seq = ASN1Sequence.getInstance(encoding); - - if (seq.size() != 6) - { - throw new PEMException("malformed sequence in DSA private key"); - } - - // ASN1Integer v = (ASN1Integer)seq.getObjectAt(0); - ASN1Integer p = ASN1Integer.getInstance(seq.getObjectAt(1)); - ASN1Integer q = ASN1Integer.getInstance(seq.getObjectAt(2)); - ASN1Integer g = ASN1Integer.getInstance(seq.getObjectAt(3)); - ASN1Integer y = ASN1Integer.getInstance(seq.getObjectAt(4)); - ASN1Integer x = ASN1Integer.getInstance(seq.getObjectAt(5)); - - return new PEMKeyPair( - new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(p.getValue(), q.getValue(), g.getValue())), y), - new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(p.getValue(), q.getValue(), g.getValue())), x)); - } - catch (IOException e) - { - throw e; - } - catch (Exception e) - { - throw new PEMException( - "problem creating DSA private key: " + e.toString(), e); - } - } - } - - private class ECDSAKeyPairParser - implements PEMKeyPairParser - { - public PEMKeyPair parse(byte[] encoding) - throws IOException - { - try - { - ASN1Sequence seq = ASN1Sequence.getInstance(encoding); - - org.bouncycastle.asn1.sec.ECPrivateKey pKey = org.bouncycastle.asn1.sec.ECPrivateKey.getInstance(seq); - AlgorithmIdentifier algId = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, pKey.getParameters()); - PrivateKeyInfo privInfo = new PrivateKeyInfo(algId, pKey); - SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(algId, pKey.getPublicKey().getBytes()); - - return new PEMKeyPair(pubInfo, privInfo); - } - catch (IOException e) - { - throw e; - } - catch (Exception e) - { - throw new PEMException( - "problem creating EC private key: " + e.toString(), e); - } - } - } - - private class RSAKeyPairParser - implements PEMKeyPairParser - { - public PEMKeyPair parse(byte[] encoding) - throws IOException - { - try - { - ASN1Sequence seq = ASN1Sequence.getInstance(encoding); - - if (seq.size() != 9) - { - throw new PEMException("malformed sequence in RSA private key"); - } - - org.bouncycastle.asn1.pkcs.RSAPrivateKey keyStruct = org.bouncycastle.asn1.pkcs.RSAPrivateKey.getInstance(seq); - - RSAPublicKey pubSpec = new RSAPublicKey( - keyStruct.getModulus(), keyStruct.getPublicExponent()); - - AlgorithmIdentifier algId = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE); - - return new PEMKeyPair(new SubjectPublicKeyInfo(algId, pubSpec), new PrivateKeyInfo(algId, keyStruct)); - } - catch (IOException e) - { - throw e; - } - catch (Exception e) - { - throw new PEMException( - "problem creating RSA private key: " + e.toString(), e); - } - } - } - - private class PublicKeyParser - implements PemObjectParser - { - public PublicKeyParser() - { - } - - public Object parseObject(PemObject obj) - throws IOException - { - return SubjectPublicKeyInfo.getInstance(obj.getContent()); - } - } - - private class RSAPublicKeyParser - implements PemObjectParser - { - public RSAPublicKeyParser() - { - } - - public Object parseObject(PemObject obj) - throws IOException - { - try - { - RSAPublicKey rsaPubStructure = RSAPublicKey.getInstance(obj.getContent()); - - return new SubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), rsaPubStructure); - } - catch (IOException e) - { - throw e; - } - catch (Exception e) - { - throw new PEMException("problem extracting key: " + e.toString(), e); - } - } - } - - private class X509CertificateParser - implements PemObjectParser - { - /** - * Reads in a X509Certificate. - * - * @return the X509Certificate - * @throws java.io.IOException if an I/O error occured - */ - public Object parseObject(PemObject obj) - throws IOException - { - try - { - return new X509CertificateHolder(obj.getContent()); - } - catch (Exception e) - { - throw new PEMException("problem parsing cert: " + e.toString(), e); - } - } - } - - private class X509CRLParser - implements PemObjectParser - { - /** - * Reads in a X509CRL. - * - * @return the X509Certificate - * @throws java.io.IOException if an I/O error occured - */ - public Object parseObject(PemObject obj) - throws IOException - { - try - { - return new X509CRLHolder(obj.getContent()); - } - catch (Exception e) - { - throw new PEMException("problem parsing cert: " + e.toString(), e); - } - } - } - - private class PKCS10CertificationRequestParser - implements PemObjectParser - { - /** - * Reads in a PKCS10 certification request. - * - * @return the certificate request. - * @throws java.io.IOException if an I/O error occured - */ - public Object parseObject(PemObject obj) - throws IOException - { - try - { - return new PKCS10CertificationRequest(obj.getContent()); - } - catch (Exception e) - { - throw new PEMException("problem parsing certrequest: " + e.toString(), e); - } - } - } - - private class PKCS7Parser - implements PemObjectParser - { - /** - * Reads in a PKCS7 object. This returns a ContentInfo object suitable for use with the CMS - * API. - * - * @return the X509Certificate - * @throws java.io.IOException if an I/O error occured - */ - public Object parseObject(PemObject obj) - throws IOException - { - try - { - ASN1InputStream aIn = new ASN1InputStream(obj.getContent()); - - return ContentInfo.getInstance(aIn.readObject()); - } - catch (Exception e) - { - throw new PEMException("problem parsing PKCS7 object: " + e.toString(), e); - } - } - } - - private class X509AttributeCertificateParser - implements PemObjectParser - { - public Object parseObject(PemObject obj) - throws IOException - { - return new X509AttributeCertificateHolder(obj.getContent()); - } - } - - private class ECCurveParamsParser - implements PemObjectParser - { - public Object parseObject(PemObject obj) - throws IOException - { - try - { - Object param = ASN1Primitive.fromByteArray(obj.getContent()); - - if (param instanceof ASN1ObjectIdentifier) - { - return ASN1Primitive.fromByteArray(obj.getContent()); - } - else if (param instanceof ASN1Sequence) - { - return X9ECParameters.getInstance(param); - } - else - { - return null; // implicitly CA - } - } - catch (IOException e) - { - throw e; - } - catch (Exception e) - { - throw new PEMException("exception extracting EC named curve: " + e.toString()); - } - } - } - - private class EncryptedPrivateKeyParser - implements PemObjectParser - { - public EncryptedPrivateKeyParser() - { - } - - /** - * Reads in an EncryptedPrivateKeyInfo - * - * @return the X509Certificate - * @throws java.io.IOException if an I/O error occured - */ - public Object parseObject(PemObject obj) - throws IOException - { - try - { - return new PKCS8EncryptedPrivateKeyInfo(EncryptedPrivateKeyInfo.getInstance(obj.getContent())); - } - catch (Exception e) - { - throw new PEMException("problem parsing ENCRYPTED PRIVATE KEY: " + e.toString(), e); - } - } - } - - private class PrivateKeyParser - implements PemObjectParser - { - public PrivateKeyParser() - { - } - - public Object parseObject(PemObject obj) - throws IOException - { - try - { - return PrivateKeyInfo.getInstance(obj.getContent()); - } - catch (Exception e) - { - throw new PEMException("problem parsing PRIVATE KEY: " + e.toString(), e); - } - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/PEMUtilities.java b/pkix/src/main/java/org/bouncycastle/openssl/PEMUtilities.java deleted file mode 100644 index 71b365a9..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/PEMUtilities.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.bouncycastle.openssl; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.util.Integers; - -public final class PEMUtilities -{ - private static final Map KEYSIZES = new HashMap(); - private static final Set PKCS5_SCHEME_1 = new HashSet(); - private static final Set PKCS5_SCHEME_2 = new HashSet(); - - static - { - PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC); - PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC); - PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC); - PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC); - PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC); - PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC); - - PKCS5_SCHEME_2.add(PKCSObjectIdentifiers.id_PBES2); - PKCS5_SCHEME_2.add(PKCSObjectIdentifiers.des_EDE3_CBC); - PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes128_CBC); - PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes192_CBC); - PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes256_CBC); - - KEYSIZES.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), Integers.valueOf(192)); - KEYSIZES.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), Integers.valueOf(128)); - KEYSIZES.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), Integers.valueOf(192)); - KEYSIZES.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), Integers.valueOf(256)); - } - - static int getKeySize(String algorithm) - { - if (!KEYSIZES.containsKey(algorithm)) - { - throw new IllegalStateException("no key size for algorithm: " + algorithm); - } - - return ((Integer)KEYSIZES.get(algorithm)).intValue(); - } - - static boolean isPKCS5Scheme1(ASN1ObjectIdentifier algOid) - { - return PKCS5_SCHEME_1.contains(algOid); - } - - public static boolean isPKCS5Scheme2(ASN1ObjectIdentifier algOid) - { - return PKCS5_SCHEME_2.contains(algOid); - } - - public static boolean isPKCS12(ASN1ObjectIdentifier algOid) - { - return algOid.getId().startsWith(PKCSObjectIdentifiers.pkcs_12PbeIds.getId()); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/PEMWriter.java b/pkix/src/main/java/org/bouncycastle/openssl/PEMWriter.java deleted file mode 100644 index 131d02c4..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/PEMWriter.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.bouncycastle.openssl; - -import java.io.IOException; -import java.io.Writer; - -import org.bouncycastle.openssl.jcajce.JcaMiscPEMGenerator; -import org.bouncycastle.util.io.pem.PemGenerationException; -import org.bouncycastle.util.io.pem.PemObjectGenerator; -import org.bouncycastle.util.io.pem.PemWriter; - -/** - * General purpose writer for OpenSSL PEM objects. - * @deprecated use JcaPEMWriter - */ -public class PEMWriter - extends PemWriter -{ - /** - * Base constructor. - * - * @param out output stream to use. - */ - public PEMWriter(Writer out) - { - super(out); - } - - /** - * @throws IOException - */ - public void writeObject( - Object obj) - throws IOException - { - writeObject(obj, null); - } - - /** - * @param obj - * @param encryptor - * @throws IOException - */ - public void writeObject( - Object obj, - PEMEncryptor encryptor) - throws IOException - { - try - { - super.writeObject(new JcaMiscPEMGenerator(obj, encryptor)); - } - catch (PemGenerationException e) - { - if (e.getCause() instanceof IOException) - { - throw (IOException)e.getCause(); - } - - throw e; - } - } - - public void writeObject( - PemObjectGenerator obj) - throws IOException - { - super.writeObject(obj); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/PKCS8Generator.java b/pkix/src/main/java/org/bouncycastle/openssl/PKCS8Generator.java deleted file mode 100644 index f822cba1..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/PKCS8Generator.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.bouncycastle.openssl; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.operator.OutputEncryptor; -import org.bouncycastle.util.io.pem.PemGenerationException; -import org.bouncycastle.util.io.pem.PemObject; -import org.bouncycastle.util.io.pem.PemObjectGenerator; - -public class PKCS8Generator - implements PemObjectGenerator -{ - public static final ASN1ObjectIdentifier AES_128_CBC = NISTObjectIdentifiers.id_aes128_CBC; - public static final ASN1ObjectIdentifier AES_192_CBC = NISTObjectIdentifiers.id_aes192_CBC; - public static final ASN1ObjectIdentifier AES_256_CBC = NISTObjectIdentifiers.id_aes256_CBC; - - public static final ASN1ObjectIdentifier DES3_CBC = PKCSObjectIdentifiers.des_EDE3_CBC; - - public static final ASN1ObjectIdentifier PBE_SHA1_RC4_128 = PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4; - public static final ASN1ObjectIdentifier PBE_SHA1_RC4_40 = PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4; - public static final ASN1ObjectIdentifier PBE_SHA1_3DES = PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC; - public static final ASN1ObjectIdentifier PBE_SHA1_2DES = PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC; - public static final ASN1ObjectIdentifier PBE_SHA1_RC2_128 = PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC; - public static final ASN1ObjectIdentifier PBE_SHA1_RC2_40 = PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC; - - private PrivateKeyInfo key; - private OutputEncryptor outputEncryptor; - - /** - * Base constructor. - */ - public PKCS8Generator(PrivateKeyInfo key, OutputEncryptor outputEncryptor) - { - this.key = key; - this.outputEncryptor = outputEncryptor; - } - - public PemObject generate() - throws PemGenerationException - { - if (outputEncryptor != null) - { - return generate(key, outputEncryptor); - } - else - { - return generate(key, null); - } - } - - private PemObject generate(PrivateKeyInfo key, OutputEncryptor encryptor) - throws PemGenerationException - { - try - { - byte[] keyData = key.getEncoded(); - - if (encryptor == null) - { - return new PemObject("PRIVATE KEY", keyData); - } - - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - - OutputStream cOut = encryptor.getOutputStream(bOut); - - cOut.write(key.getEncoded()); - - cOut.close(); - - EncryptedPrivateKeyInfo info = new EncryptedPrivateKeyInfo(encryptor.getAlgorithmIdentifier(), bOut.toByteArray()); - - return new PemObject("ENCRYPTED PRIVATE KEY", info.getEncoded()); - } - catch (IOException e) - { - throw new PemGenerationException("unable to process encoded key data: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/PasswordException.java b/pkix/src/main/java/org/bouncycastle/openssl/PasswordException.java deleted file mode 100644 index 89625e78..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/PasswordException.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.bouncycastle.openssl; - -public class PasswordException - extends PEMException -{ - public PasswordException(String msg) - { - super(msg); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/PasswordFinder.java b/pkix/src/main/java/org/bouncycastle/openssl/PasswordFinder.java deleted file mode 100644 index fb89cf08..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/PasswordFinder.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.bouncycastle.openssl; - -/** - * call back to allow a password to be fetched when one is requested. - */ -public interface PasswordFinder -{ - public char[] getPassword(); -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JcaMiscPEMGenerator.java b/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JcaMiscPEMGenerator.java deleted file mode 100644 index 6547078d..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JcaMiscPEMGenerator.java +++ /dev/null @@ -1,98 +0,0 @@ -package org.bouncycastle.openssl.jcajce; - -import java.io.IOException; -import java.security.Key; -import java.security.KeyPair; -import java.security.PrivateKey; -import java.security.Provider; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.cert.CRLException; -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509CRL; -import java.security.cert.X509Certificate; - -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.cert.jcajce.JcaX509AttributeCertificateHolder; -import org.bouncycastle.cert.jcajce.JcaX509CRLHolder; -import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; -import org.bouncycastle.jce.PKCS10CertificationRequest; -import org.bouncycastle.openssl.MiscPEMGenerator; -import org.bouncycastle.openssl.PEMEncryptor; -import org.bouncycastle.x509.X509AttributeCertificate; -import org.bouncycastle.x509.X509V2AttributeCertificate; - -/** - * PEM generator for the original set of PEM objects used in Open SSL. - */ -public class JcaMiscPEMGenerator - extends MiscPEMGenerator -{ - private Object obj; - private String algorithm; - private char[] password; - private SecureRandom random; - private Provider provider; - - public JcaMiscPEMGenerator(Object o) - throws IOException - { - super(convertObject(o)); - } - - public JcaMiscPEMGenerator(Object o, PEMEncryptor encryptor) - throws IOException - { - super(convertObject(o), encryptor); - } - - private static Object convertObject(Object o) - throws IOException - { - if (o instanceof X509Certificate) - { - try - { - return new JcaX509CertificateHolder((X509Certificate)o); - } - catch (CertificateEncodingException e) - { - throw new IllegalArgumentException("Cannot encode object: " + e.toString()); - } - } - else if (o instanceof X509CRL) - { - try - { - return new JcaX509CRLHolder((X509CRL)o); - } - catch (CRLException e) - { - throw new IllegalArgumentException("Cannot encode object: " + e.toString()); - } - } - else if (o instanceof KeyPair) - { - return convertObject(((KeyPair)o).getPrivate()); - } - else if (o instanceof PrivateKey) - { - return PrivateKeyInfo.getInstance(((Key)o).getEncoded()); - } - else if (o instanceof PublicKey) - { - return SubjectPublicKeyInfo.getInstance(((PublicKey)o).getEncoded()); - } - else if (o instanceof X509AttributeCertificate) - { - return new JcaX509AttributeCertificateHolder((X509V2AttributeCertificate)o); - } - else if (o instanceof PKCS10CertificationRequest) - { - return new org.bouncycastle.pkcs.PKCS10CertificationRequest(((PKCS10CertificationRequest)o).getEncoded()); - } - - return o; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JcaPEMKeyConverter.java b/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JcaPEMKeyConverter.java deleted file mode 100644 index 0107f4a2..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JcaPEMKeyConverter.java +++ /dev/null @@ -1,115 +0,0 @@ -package org.bouncycastle.openssl.jcajce; - -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PrivateKey; -import java.security.Provider; -import java.security.PublicKey; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.X509EncodedKeySpec; -import java.util.HashMap; -import java.util.Map; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; -import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.util.JcaJceHelper; -import org.bouncycastle.jcajce.util.NamedJcaJceHelper; -import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; -import org.bouncycastle.openssl.PEMException; -import org.bouncycastle.openssl.PEMKeyPair; - -public class JcaPEMKeyConverter -{ - private JcaJceHelper helper = new DefaultJcaJceHelper(); - - private static final Map algorithms = new HashMap(); - - static - { - algorithms.put(X9ObjectIdentifiers.id_ecPublicKey, "ECDSA"); - algorithms.put(PKCSObjectIdentifiers.rsaEncryption, "RSA"); - algorithms.put(X9ObjectIdentifiers.id_dsa, "DSA"); - } - - public JcaPEMKeyConverter setProvider(Provider provider) - { - this.helper = new ProviderJcaJceHelper(provider); - - return this; - } - - public JcaPEMKeyConverter setProvider(String providerName) - { - this.helper = new NamedJcaJceHelper(providerName); - - return this; - } - - public KeyPair getKeyPair(PEMKeyPair keyPair) - throws PEMException - { - try - { - KeyFactory keyFactory = getKeyFactory(keyPair.getPrivateKeyInfo().getPrivateKeyAlgorithm()); - - return new KeyPair(keyFactory.generatePublic(new X509EncodedKeySpec(keyPair.getPublicKeyInfo().getEncoded())), - keyFactory.generatePrivate(new PKCS8EncodedKeySpec(keyPair.getPrivateKeyInfo().getEncoded()))); - } - catch (Exception e) - { - throw new PEMException("unable to convert key pair: " + e.getMessage(), e); - } - } - - public PublicKey getPublicKey(SubjectPublicKeyInfo publicKeyInfo) - throws PEMException - { - try - { - KeyFactory keyFactory = getKeyFactory(publicKeyInfo.getAlgorithm()); - - return keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyInfo.getEncoded())); - } - catch (Exception e) - { - throw new PEMException("unable to convert key pair: " + e.getMessage(), e); - } - } - - public PrivateKey getPrivateKey(PrivateKeyInfo privateKeyInfo) - throws PEMException - { - try - { - KeyFactory keyFactory = getKeyFactory(privateKeyInfo.getPrivateKeyAlgorithm()); - - return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyInfo.getEncoded())); - } - catch (Exception e) - { - throw new PEMException("unable to convert key pair: " + e.getMessage(), e); - } - } - - private KeyFactory getKeyFactory(AlgorithmIdentifier algId) - throws NoSuchAlgorithmException, NoSuchProviderException - { - ASN1ObjectIdentifier algorithm = algId.getAlgorithm(); - - String algName = (String)algorithms.get(algorithm); - - if (algName == null) - { - algName = algorithm.getId(); - } - - return helper.createKeyFactory(algName); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JcaPEMWriter.java b/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JcaPEMWriter.java deleted file mode 100644 index 423f9500..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JcaPEMWriter.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.bouncycastle.openssl.jcajce; - -import java.io.IOException; -import java.io.Writer; - -import org.bouncycastle.openssl.PEMEncryptor; -import org.bouncycastle.util.io.pem.PemGenerationException; -import org.bouncycastle.util.io.pem.PemObjectGenerator; -import org.bouncycastle.util.io.pem.PemWriter; - -/** - * General purpose writer for OpenSSL PEM objects based on JCA/JCE classes. - */ -public class JcaPEMWriter - extends PemWriter -{ - /** - * Base constructor. - * - * @param out output stream to use. - */ - public JcaPEMWriter(Writer out) - { - super(out); - } - - /** - * @throws java.io.IOException - */ - public void writeObject( - Object obj) - throws IOException - { - writeObject(obj, null); - } - - /** - * @param obj - * @param encryptor - * @throws java.io.IOException - */ - public void writeObject( - Object obj, - PEMEncryptor encryptor) - throws IOException - { - try - { - super.writeObject(new JcaMiscPEMGenerator(obj, encryptor)); - } - catch (PemGenerationException e) - { - if (e.getCause() instanceof IOException) - { - throw (IOException)e.getCause(); - } - - throw e; - } - } - - public void writeObject( - PemObjectGenerator obj) - throws IOException - { - super.writeObject(obj); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JcaPKCS8Generator.java b/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JcaPKCS8Generator.java deleted file mode 100644 index 261dcecb..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JcaPKCS8Generator.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.bouncycastle.openssl.jcajce; - -import java.security.PrivateKey; - -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.openssl.PKCS8Generator; -import org.bouncycastle.operator.OutputEncryptor; -import org.bouncycastle.util.io.pem.PemGenerationException; - -public class JcaPKCS8Generator - extends PKCS8Generator -{ - public JcaPKCS8Generator(PrivateKey key, OutputEncryptor encryptor) - throws PemGenerationException - { - super(PrivateKeyInfo.getInstance(key.getEncoded()), encryptor); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JceOpenSSLPKCS8DecryptorProviderBuilder.java b/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JceOpenSSLPKCS8DecryptorProviderBuilder.java deleted file mode 100644 index 46cca30d..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JceOpenSSLPKCS8DecryptorProviderBuilder.java +++ /dev/null @@ -1,141 +0,0 @@ -package org.bouncycastle.openssl.jcajce; - -import java.io.IOException; -import java.io.InputStream; -import java.security.AlgorithmParameters; -import java.security.GeneralSecurityException; -import java.security.Provider; - -import javax.crypto.Cipher; -import javax.crypto.CipherInputStream; -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.PBEParameterSpec; - -import org.bouncycastle.asn1.pkcs.EncryptionScheme; -import org.bouncycastle.asn1.pkcs.KeyDerivationFunc; -import org.bouncycastle.asn1.pkcs.PBEParameter; -import org.bouncycastle.asn1.pkcs.PBES2Parameters; -import org.bouncycastle.asn1.pkcs.PBKDF2Params; -import org.bouncycastle.asn1.pkcs.PKCS12PBEParams; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.util.JcaJceHelper; -import org.bouncycastle.jcajce.util.NamedJcaJceHelper; -import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; -import org.bouncycastle.openssl.PEMException; -import org.bouncycastle.operator.InputDecryptor; -import org.bouncycastle.operator.InputDecryptorProvider; -import org.bouncycastle.operator.OperatorCreationException; - -public class JceOpenSSLPKCS8DecryptorProviderBuilder -{ - private JcaJceHelper helper = new DefaultJcaJceHelper(); - - public JceOpenSSLPKCS8DecryptorProviderBuilder() - { - helper = new DefaultJcaJceHelper(); - } - - public JceOpenSSLPKCS8DecryptorProviderBuilder setProvider(String providerName) - { - helper = new NamedJcaJceHelper(providerName); - - return this; - } - - public JceOpenSSLPKCS8DecryptorProviderBuilder setProvider(Provider provider) - { - helper = new ProviderJcaJceHelper(provider); - - return this; - } - - public InputDecryptorProvider build(final char[] password) - throws OperatorCreationException - { - return new InputDecryptorProvider() - { - public InputDecryptor get(final AlgorithmIdentifier algorithm) - throws OperatorCreationException - { - final Cipher cipher; - - try - { - if (PEMUtilities.isPKCS5Scheme2(algorithm.getAlgorithm())) - { - PBES2Parameters params = PBES2Parameters.getInstance(algorithm.getParameters()); - KeyDerivationFunc func = params.getKeyDerivationFunc(); - EncryptionScheme scheme = params.getEncryptionScheme(); - PBKDF2Params defParams = (PBKDF2Params)func.getParameters(); - - int iterationCount = defParams.getIterationCount().intValue(); - byte[] salt = defParams.getSalt(); - - String oid = scheme.getAlgorithm().getId(); - - SecretKey key = PEMUtilities.generateSecretKeyForPKCS5Scheme2(oid, password, salt, iterationCount); - - cipher = helper.createCipher(oid); - AlgorithmParameters algParams = helper.createAlgorithmParameters(oid); - - algParams.init(scheme.getParameters().toASN1Primitive().getEncoded()); - - cipher.init(Cipher.DECRYPT_MODE, key, algParams); - } - else if (PEMUtilities.isPKCS12(algorithm.getAlgorithm())) - { - PKCS12PBEParams params = PKCS12PBEParams.getInstance(algorithm.getParameters()); - PBEKeySpec pbeSpec = new PBEKeySpec(password); - - SecretKeyFactory secKeyFact = helper.createSecretKeyFactory(algorithm.getAlgorithm().getId()); - PBEParameterSpec defParams = new PBEParameterSpec(params.getIV(), params.getIterations().intValue()); - - cipher = helper.createCipher(algorithm.getAlgorithm().getId()); - - cipher.init(Cipher.DECRYPT_MODE, secKeyFact.generateSecret(pbeSpec), defParams); - } - else if (PEMUtilities.isPKCS5Scheme1(algorithm.getAlgorithm())) - { - PBEParameter params = PBEParameter.getInstance(algorithm.getParameters()); - PBEKeySpec pbeSpec = new PBEKeySpec(password); - - SecretKeyFactory secKeyFact = helper.createSecretKeyFactory(algorithm.getAlgorithm().getId()); - PBEParameterSpec defParams = new PBEParameterSpec(params.getSalt(), params.getIterationCount().intValue()); - - cipher = helper.createCipher(algorithm.getAlgorithm().getId()); - - cipher.init(Cipher.DECRYPT_MODE, secKeyFact.generateSecret(pbeSpec), defParams); - } - else - { - throw new PEMException("Unknown algorithm: " + algorithm.getAlgorithm()); - } - - return new InputDecryptor() - { - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return algorithm; - } - - public InputStream getInputStream(InputStream encIn) - { - return new CipherInputStream(encIn, cipher); - } - }; - } - catch (IOException e) - { - throw new OperatorCreationException(algorithm.getAlgorithm() + " not available: " + e.getMessage(), e); - } - catch (GeneralSecurityException e) - { - throw new OperatorCreationException(algorithm.getAlgorithm() + " not available: " + e.getMessage(), e); - } - }; - }; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JceOpenSSLPKCS8EncryptorBuilder.java b/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JceOpenSSLPKCS8EncryptorBuilder.java deleted file mode 100644 index 09f8807b..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JceOpenSSLPKCS8EncryptorBuilder.java +++ /dev/null @@ -1,221 +0,0 @@ -package org.bouncycastle.openssl.jcajce; - -import java.io.IOException; -import java.io.OutputStream; -import java.security.AlgorithmParameterGenerator; -import java.security.AlgorithmParameters; -import java.security.GeneralSecurityException; -import java.security.Provider; -import java.security.SecureRandom; - -import javax.crypto.Cipher; -import javax.crypto.CipherOutputStream; -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.PBEParameterSpec; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.KeyDerivationFunc; -import org.bouncycastle.asn1.pkcs.PBES2Parameters; -import org.bouncycastle.asn1.pkcs.PBKDF2Params; -import org.bouncycastle.asn1.pkcs.PKCS12PBEParams; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.util.JcaJceHelper; -import org.bouncycastle.jcajce.util.NamedJcaJceHelper; -import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.operator.OutputEncryptor; -import org.bouncycastle.operator.jcajce.JceGenericKey; - -public class JceOpenSSLPKCS8EncryptorBuilder -{ - public static final String AES_128_CBC = NISTObjectIdentifiers.id_aes128_CBC.getId(); - public static final String AES_192_CBC = NISTObjectIdentifiers.id_aes192_CBC.getId(); - public static final String AES_256_CBC = NISTObjectIdentifiers.id_aes256_CBC.getId(); - - public static final String DES3_CBC = PKCSObjectIdentifiers.des_EDE3_CBC.getId(); - - public static final String PBE_SHA1_RC4_128 = PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4.getId(); - public static final String PBE_SHA1_RC4_40 = PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4.getId(); - public static final String PBE_SHA1_3DES = PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC.getId(); - public static final String PBE_SHA1_2DES = PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC.getId(); - public static final String PBE_SHA1_RC2_128 = PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC.getId(); - public static final String PBE_SHA1_RC2_40 = PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC.getId(); - - private JcaJceHelper helper = new DefaultJcaJceHelper(); - - private AlgorithmParameters params; - private ASN1ObjectIdentifier algOID; - byte[] salt; - int iterationCount; - private Cipher cipher; - private SecureRandom random; - private AlgorithmParameterGenerator paramGen; - private SecretKeyFactory secKeyFact; - private char[] password; - - private SecretKey key; - - public JceOpenSSLPKCS8EncryptorBuilder(ASN1ObjectIdentifier algorithm) - { - algOID = algorithm; - - this.iterationCount = 2048; - } - - public JceOpenSSLPKCS8EncryptorBuilder setRandom(SecureRandom random) - { - this.random = random; - - return this; - } - - public JceOpenSSLPKCS8EncryptorBuilder setPasssword(char[] password) - { - this.password = password; - - return this; - } - - public JceOpenSSLPKCS8EncryptorBuilder setIterationCount(int iterationCount) - { - this.iterationCount = iterationCount; - - return this; - } - - public JceOpenSSLPKCS8EncryptorBuilder setProvider(String providerName) - { - helper = new NamedJcaJceHelper(providerName); - - return this; - } - - public JceOpenSSLPKCS8EncryptorBuilder setProvider(Provider provider) - { - helper = new ProviderJcaJceHelper(provider); - - return this; - } - - public OutputEncryptor build() - throws OperatorCreationException - { - final AlgorithmIdentifier algID; - - salt = new byte[20]; - - if (random == null) - { - random = new SecureRandom(); - } - - random.nextBytes(salt); - - try - { - this.cipher = helper.createCipher(algOID.getId()); - - if (PEMUtilities.isPKCS5Scheme2(algOID)) - { - this.paramGen = helper.createAlgorithmParameterGenerator(algOID.getId()); - } - else - { - this.secKeyFact = helper.createSecretKeyFactory(algOID.getId()); - } - } - catch (GeneralSecurityException e) - { - throw new OperatorCreationException(algOID + " not available: " + e.getMessage(), e); - } - - if (PEMUtilities.isPKCS5Scheme2(algOID)) - { - params = paramGen.generateParameters(); - - try - { - KeyDerivationFunc scheme = new KeyDerivationFunc(algOID, ASN1Primitive.fromByteArray(params.getEncoded())); - KeyDerivationFunc func = new KeyDerivationFunc(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(salt, iterationCount)); - - ASN1EncodableVector v = new ASN1EncodableVector(); - - v.add(func); - v.add(scheme); - - algID = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, PBES2Parameters.getInstance(new DERSequence(v))); - } - catch (IOException e) - { - throw new OperatorCreationException(e.getMessage(), e); - } - - key = PEMUtilities.generateSecretKeyForPKCS5Scheme2(algOID.getId(), password, salt, iterationCount); - - try - { - cipher.init(Cipher.ENCRYPT_MODE, key, params); - } - catch (GeneralSecurityException e) - { - throw new OperatorCreationException(e.getMessage(), e); - } - } - else if (PEMUtilities.isPKCS12(algOID)) - { - ASN1EncodableVector v = new ASN1EncodableVector(); - - v.add(new DEROctetString(salt)); - v.add(new ASN1Integer(iterationCount)); - - algID = new AlgorithmIdentifier(algOID, PKCS12PBEParams.getInstance(new DERSequence(v))); - - try - { - PBEKeySpec pbeSpec = new PBEKeySpec(password); - PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount); - - key = secKeyFact.generateSecret(pbeSpec); - - cipher.init(Cipher.ENCRYPT_MODE, key, defParams); - } - catch (GeneralSecurityException e) - { - throw new OperatorCreationException(e.getMessage(), e); - } - } - else - { - throw new OperatorCreationException("unknown algorithm: " + algOID, null); - } - - return new OutputEncryptor() - { - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return algID; - } - - public OutputStream getOutputStream(OutputStream encOut) - { - return new CipherOutputStream(encOut, cipher); - } - - public GenericKey getKey() - { - return new JceGenericKey(algID, key); - } - }; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JcePEMDecryptorProviderBuilder.java b/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JcePEMDecryptorProviderBuilder.java deleted file mode 100644 index a9d5c5c5..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JcePEMDecryptorProviderBuilder.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.bouncycastle.openssl.jcajce; - -import java.security.Provider; - -import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.util.JcaJceHelper; -import org.bouncycastle.jcajce.util.NamedJcaJceHelper; -import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; -import org.bouncycastle.openssl.PEMDecryptor; -import org.bouncycastle.openssl.PEMDecryptorProvider; -import org.bouncycastle.openssl.PEMException; -import org.bouncycastle.openssl.PasswordException; - -public class JcePEMDecryptorProviderBuilder -{ - private JcaJceHelper helper = new DefaultJcaJceHelper(); - - public JcePEMDecryptorProviderBuilder setProvider(Provider provider) - { - this.helper = new ProviderJcaJceHelper(provider); - - return this; - } - - public JcePEMDecryptorProviderBuilder setProvider(String providerName) - { - this.helper = new NamedJcaJceHelper(providerName); - - return this; - } - - public PEMDecryptorProvider build(final char[] password) - { - return new PEMDecryptorProvider() - { - public PEMDecryptor get(final String dekAlgName) - { - return new PEMDecryptor() - { - public byte[] decrypt(byte[] keyBytes, byte[] iv) - throws PEMException - { - if (password == null) - { - throw new PasswordException("Password is null, but a password is required"); - } - - return PEMUtilities.crypt(false, helper, keyBytes, password, dekAlgName, iv); - } - }; - } - }; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JcePEMEncryptorBuilder.java b/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JcePEMEncryptorBuilder.java deleted file mode 100644 index de1de13a..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JcePEMEncryptorBuilder.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.bouncycastle.openssl.jcajce; - -import java.security.Provider; -import java.security.SecureRandom; - -import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.util.JcaJceHelper; -import org.bouncycastle.jcajce.util.NamedJcaJceHelper; -import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; -import org.bouncycastle.openssl.PEMEncryptor; -import org.bouncycastle.openssl.PEMException; - -public class JcePEMEncryptorBuilder -{ - private final String algorithm; - - private JcaJceHelper helper = new DefaultJcaJceHelper(); - private SecureRandom random; - - public JcePEMEncryptorBuilder(String algorithm) - { - this.algorithm = algorithm; - } - - public JcePEMEncryptorBuilder setProvider(Provider provider) - { - this.helper = new ProviderJcaJceHelper(provider); - - return this; - } - - public JcePEMEncryptorBuilder setProvider(String providerName) - { - this.helper = new NamedJcaJceHelper(providerName); - - return this; - } - - public JcePEMEncryptorBuilder setSecureRandom(SecureRandom random) - { - this.random = random; - - return this; - } - - public PEMEncryptor build(final char[] password) - { - if (random == null) - { - random = new SecureRandom(); - } - - int ivLength = algorithm.startsWith("AES-") ? 16 : 8; - - final byte[] iv = new byte[ivLength]; - - random.nextBytes(iv); - - return new PEMEncryptor() - { - public String getAlgorithm() - { - return algorithm; - } - - public byte[] getIV() - { - return iv; - } - - public byte[] encrypt(byte[] encoding) - throws PEMException - { - return PEMUtilities.crypt(true, helper, encoding, password, algorithm, iv); - } - }; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/openssl/jcajce/PEMUtilities.java b/pkix/src/main/java/org/bouncycastle/openssl/jcajce/PEMUtilities.java deleted file mode 100644 index a5a88a90..00000000 --- a/pkix/src/main/java/org/bouncycastle/openssl/jcajce/PEMUtilities.java +++ /dev/null @@ -1,257 +0,0 @@ -package org.bouncycastle.openssl.jcajce; - -import java.security.Key; -import java.security.spec.AlgorithmParameterSpec; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import javax.crypto.Cipher; -import javax.crypto.SecretKey; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.RC2ParameterSpec; -import javax.crypto.spec.SecretKeySpec; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.crypto.PBEParametersGenerator; -import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator; -import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; -import org.bouncycastle.crypto.params.KeyParameter; -import org.bouncycastle.jcajce.util.JcaJceHelper; -import org.bouncycastle.openssl.EncryptionException; -import org.bouncycastle.openssl.PEMException; -import org.bouncycastle.util.Integers; - -class PEMUtilities -{ - private static final Map KEYSIZES = new HashMap(); - private static final Set PKCS5_SCHEME_1 = new HashSet(); - private static final Set PKCS5_SCHEME_2 = new HashSet(); - - static - { - PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC); - PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC); - PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC); - PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC); - PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC); - PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC); - - PKCS5_SCHEME_2.add(PKCSObjectIdentifiers.id_PBES2); - PKCS5_SCHEME_2.add(PKCSObjectIdentifiers.des_EDE3_CBC); - PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes128_CBC); - PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes192_CBC); - PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes256_CBC); - - KEYSIZES.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), Integers.valueOf(192)); - KEYSIZES.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), Integers.valueOf(128)); - KEYSIZES.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), Integers.valueOf(192)); - KEYSIZES.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), Integers.valueOf(256)); - } - - static int getKeySize(String algorithm) - { - if (!KEYSIZES.containsKey(algorithm)) - { - throw new IllegalStateException("no key size for algorithm: " + algorithm); - } - - return ((Integer)KEYSIZES.get(algorithm)).intValue(); - } - - static boolean isPKCS5Scheme1(ASN1ObjectIdentifier algOid) - { - return PKCS5_SCHEME_1.contains(algOid); - } - - static boolean isPKCS5Scheme2(ASN1ObjectIdentifier algOid) - { - return PKCS5_SCHEME_2.contains(algOid); - } - - public static boolean isPKCS12(ASN1ObjectIdentifier algOid) - { - return algOid.getId().startsWith(PKCSObjectIdentifiers.pkcs_12PbeIds.getId()); - } - - public static SecretKey generateSecretKeyForPKCS5Scheme2(String algorithm, char[] password, byte[] salt, int iterationCount) - { - PBEParametersGenerator generator = new PKCS5S2ParametersGenerator(); - - generator.init( - PBEParametersGenerator.PKCS5PasswordToBytes(password), - salt, - iterationCount); - - return new SecretKeySpec(((KeyParameter)generator.generateDerivedParameters(PEMUtilities.getKeySize(algorithm))).getKey(), algorithm); - } - - static byte[] crypt( - boolean encrypt, - JcaJceHelper helper, - byte[] bytes, - char[] password, - String dekAlgName, - byte[] iv) - throws PEMException - { - AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv); - String alg; - String blockMode = "CBC"; - String padding = "PKCS5Padding"; - Key sKey; - - // Figure out block mode and padding. - if (dekAlgName.endsWith("-CFB")) - { - blockMode = "CFB"; - padding = "NoPadding"; - } - if (dekAlgName.endsWith("-ECB") || - "DES-EDE".equals(dekAlgName) || - "DES-EDE3".equals(dekAlgName)) - { - // ECB is actually the default (though seldom used) when OpenSSL - // uses DES-EDE (des2) or DES-EDE3 (des3). - blockMode = "ECB"; - paramSpec = null; - } - if (dekAlgName.endsWith("-OFB")) - { - blockMode = "OFB"; - padding = "NoPadding"; - } - - - // Figure out algorithm and key size. - if (dekAlgName.startsWith("DES-EDE")) - { - alg = "DESede"; - // "DES-EDE" is actually des2 in OpenSSL-speak! - // "DES-EDE3" is des3. - boolean des2 = !dekAlgName.startsWith("DES-EDE3"); - sKey = getKey(password, alg, 24, iv, des2); - } - else if (dekAlgName.startsWith("DES-")) - { - alg = "DES"; - sKey = getKey(password, alg, 8, iv); - } - else if (dekAlgName.startsWith("BF-")) - { - alg = "Blowfish"; - sKey = getKey(password, alg, 16, iv); - } - else if (dekAlgName.startsWith("RC2-")) - { - alg = "RC2"; - int keyBits = 128; - if (dekAlgName.startsWith("RC2-40-")) - { - keyBits = 40; - } - else if (dekAlgName.startsWith("RC2-64-")) - { - keyBits = 64; - } - sKey = getKey(password, alg, keyBits / 8, iv); - if (paramSpec == null) // ECB block mode - { - paramSpec = new RC2ParameterSpec(keyBits); - } - else - { - paramSpec = new RC2ParameterSpec(keyBits, iv); - } - } - else if (dekAlgName.startsWith("AES-")) - { - alg = "AES"; - byte[] salt = iv; - if (salt.length > 8) - { - salt = new byte[8]; - System.arraycopy(iv, 0, salt, 0, 8); - } - - int keyBits; - if (dekAlgName.startsWith("AES-128-")) - { - keyBits = 128; - } - else if (dekAlgName.startsWith("AES-192-")) - { - keyBits = 192; - } - else if (dekAlgName.startsWith("AES-256-")) - { - keyBits = 256; - } - else - { - throw new EncryptionException("unknown AES encryption with private key"); - } - sKey = getKey(password, "AES", keyBits / 8, salt); - } - else - { - throw new EncryptionException("unknown encryption with private key"); - } - - String transformation = alg + "/" + blockMode + "/" + padding; - - try - { - Cipher c = helper.createCipher(transformation); - int mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE; - - if (paramSpec == null) // ECB block mode - { - c.init(mode, sKey); - } - else - { - c.init(mode, sKey, paramSpec); - } - return c.doFinal(bytes); - } - catch (Exception e) - { - throw new EncryptionException("exception using cipher - please check password and data.", e); - } - } - - private static SecretKey getKey( - char[] password, - String algorithm, - int keyLength, - byte[] salt) - { - return getKey(password, algorithm, keyLength, salt, false); - } - - private static SecretKey getKey( - char[] password, - String algorithm, - int keyLength, - byte[] salt, - boolean des2) - { - OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator(); - - pGen.init(PBEParametersGenerator.PKCS5PasswordToBytes(password), salt); - - KeyParameter keyParam; - keyParam = (KeyParameter) pGen.generateDerivedParameters(keyLength * 8); - byte[] key = keyParam.getKey(); - if (des2 && key.length >= 24) - { - // For DES2, we must copy first 8 bytes into the last 8 bytes. - System.arraycopy(key, 0, key, 16, 8); - } - return new SecretKeySpec(key, algorithm); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/AsymmetricKeyUnwrapper.java b/pkix/src/main/java/org/bouncycastle/operator/AsymmetricKeyUnwrapper.java deleted file mode 100644 index 3c3aa2fb..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/AsymmetricKeyUnwrapper.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.bouncycastle.operator; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -public abstract class AsymmetricKeyUnwrapper - implements KeyUnwrapper -{ - private AlgorithmIdentifier algorithmId; - - protected AsymmetricKeyUnwrapper(AlgorithmIdentifier algorithmId) - { - this.algorithmId = algorithmId; - } - - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return algorithmId; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/AsymmetricKeyWrapper.java b/pkix/src/main/java/org/bouncycastle/operator/AsymmetricKeyWrapper.java deleted file mode 100644 index 27af7195..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/AsymmetricKeyWrapper.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.bouncycastle.operator; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -public abstract class AsymmetricKeyWrapper - implements KeyWrapper -{ - private AlgorithmIdentifier algorithmId; - - protected AsymmetricKeyWrapper(AlgorithmIdentifier algorithmId) - { - this.algorithmId = algorithmId; - } - - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return algorithmId; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/BufferingContentSigner.java b/pkix/src/main/java/org/bouncycastle/operator/BufferingContentSigner.java deleted file mode 100644 index d1743672..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/BufferingContentSigner.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.bouncycastle.operator; - -import java.io.OutputStream; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.util.io.BufferingOutputStream; - -/** - * A class that explicitly buffers the data to be signed, sending it in one - * block when ready for signing. - */ -public class BufferingContentSigner - implements ContentSigner -{ - private final ContentSigner contentSigner; - private final OutputStream output; - - /** - * Base constructor. - * - * @param contentSigner the content signer to be wrapped. - */ - public BufferingContentSigner(ContentSigner contentSigner) - { - this.contentSigner = contentSigner; - this.output = new BufferingOutputStream(contentSigner.getOutputStream()); - } - - /** - * Base constructor. - * - * @param contentSigner the content signer to be wrapped. - * @param bufferSize the size of the internal buffer to use. - */ - public BufferingContentSigner(ContentSigner contentSigner, int bufferSize) - { - this.contentSigner = contentSigner; - this.output = new BufferingOutputStream(contentSigner.getOutputStream(), bufferSize); - } - - /** - * Return the algorithm identifier supported by this signer. - * - * @return algorithm identifier for the signature generated. - */ - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return contentSigner.getAlgorithmIdentifier(); - } - - /** - * Return the buffering stream. - * - * @return the output stream used to accumulate the data. - */ - public OutputStream getOutputStream() - { - return output; - } - - /** - * Generate signature from internally buffered data. - * - * @return the signature calculated from the bytes written to the buffering stream. - */ - public byte[] getSignature() - { - return contentSigner.getSignature(); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/ContentSigner.java b/pkix/src/main/java/org/bouncycastle/operator/ContentSigner.java deleted file mode 100644 index fadef603..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/ContentSigner.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.bouncycastle.operator; - -import java.io.OutputStream; - -import 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/pkix/src/main/java/org/bouncycastle/operator/ContentVerifier.java b/pkix/src/main/java/org/bouncycastle/operator/ContentVerifier.java deleted file mode 100644 index 54d9ef1d..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/ContentVerifier.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.bouncycastle.operator; - -import java.io.OutputStream; - -import 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/pkix/src/main/java/org/bouncycastle/operator/ContentVerifierProvider.java b/pkix/src/main/java/org/bouncycastle/operator/ContentVerifierProvider.java deleted file mode 100644 index 9594382f..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/ContentVerifierProvider.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.bouncycastle.operator; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import 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/pkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java b/pkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java deleted file mode 100644 index c03b5d3f..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java +++ /dev/null @@ -1,97 +0,0 @@ -package org.bouncycastle.operator; - -import java.util.HashMap; -import java.util.Map; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.RSASSAPSSparams; -import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; - -public class DefaultDigestAlgorithmIdentifierFinder - implements DigestAlgorithmIdentifierFinder -{ - private static Map digestOids = new HashMap(); - private static Map digestNameToOids = new HashMap(); - - static - { - // - // digests - // - digestOids.put(OIWObjectIdentifiers.md4WithRSAEncryption, PKCSObjectIdentifiers.md4); - digestOids.put(OIWObjectIdentifiers.md4WithRSA, PKCSObjectIdentifiers.md4); - 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); - digestOids.put(PKCSObjectIdentifiers.md2WithRSAEncryption, PKCSObjectIdentifiers.md2); - digestOids.put(PKCSObjectIdentifiers.md4WithRSAEncryption, PKCSObjectIdentifiers.md4); - 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); - - 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); - - 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); - - 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); - - digestNameToOids.put("GOST3411", CryptoProObjectIdentifiers.gostR3411); - - digestNameToOids.put("MD2", PKCSObjectIdentifiers.md2); - digestNameToOids.put("MD4", PKCSObjectIdentifiers.md4); - digestNameToOids.put("MD5", PKCSObjectIdentifiers.md5); - - digestNameToOids.put("RIPEMD128", TeleTrusTObjectIdentifiers.ripemd128); - digestNameToOids.put("RIPEMD160", TeleTrusTObjectIdentifiers.ripemd160); - digestNameToOids.put("RIPEMD256", TeleTrusTObjectIdentifiers.ripemd256); - } - - 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/pkix/src/main/java/org/bouncycastle/operator/DefaultSecretKeySizeProvider.java b/pkix/src/main/java/org/bouncycastle/operator/DefaultSecretKeySizeProvider.java deleted file mode 100644 index a1c6ba11..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/DefaultSecretKeySizeProvider.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.bouncycastle.operator; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.util.Integers; - -public class DefaultSecretKeySizeProvider - implements SecretKeySizeProvider -{ - public static final SecretKeySizeProvider INSTANCE = new DefaultSecretKeySizeProvider(); - - private static final Map KEY_SIZES; - - static - { - Map keySizes = new HashMap(); - - keySizes.put(new ASN1ObjectIdentifier("1.2.840.113533.7.66.10"), Integers.valueOf(128)); - - keySizes.put(PKCSObjectIdentifiers.des_EDE3_CBC, Integers.valueOf(192)); - - keySizes.put(NISTObjectIdentifiers.id_aes128_CBC, Integers.valueOf(128)); - keySizes.put(NISTObjectIdentifiers.id_aes192_CBC, Integers.valueOf(192)); - keySizes.put(NISTObjectIdentifiers.id_aes256_CBC, Integers.valueOf(256)); - - keySizes.put(NTTObjectIdentifiers.id_camellia128_cbc, Integers.valueOf(128)); - keySizes.put(NTTObjectIdentifiers.id_camellia192_cbc, Integers.valueOf(192)); - keySizes.put(NTTObjectIdentifiers.id_camellia256_cbc, Integers.valueOf(256)); - - keySizes.put(CryptoProObjectIdentifiers.gostR28147_gcfb, Integers.valueOf(256)); - - KEY_SIZES = Collections.unmodifiableMap(keySizes); - } - - public int getKeySize(AlgorithmIdentifier algorithmIdentifier) - { - int keySize = getKeySize(algorithmIdentifier.getAlgorithm()); - - // just need the OID - if (keySize > 0) - { - return keySize; - } - - // TODO: support OID/Parameter key sizes (e.g. RC2). - - return -1; - } - - public int getKeySize(ASN1ObjectIdentifier algorithm) - { - Integer keySize = (Integer)KEY_SIZES.get(algorithm); - - if (keySize != null) - { - return keySize.intValue(); - } - - return -1; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java b/pkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java deleted file mode 100644 index 5eb18d45..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java +++ /dev/null @@ -1,224 +0,0 @@ -package org.bouncycastle.operator; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.bsi.BSIObjectIdentifiers; -import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; -import org.bouncycastle.asn1.eac.EACObjectIdentifiers; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.RSASSAPSSparams; -import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; -import 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; - private static final ASN1ObjectIdentifier ENCRYPTION_GOST3410 = CryptoProObjectIdentifiers.gostR3410_94; - private static final ASN1ObjectIdentifier ENCRYPTION_ECGOST3410 = CryptoProObjectIdentifiers.gostR3410_2001; - - static - { - algorithms.put("MD2WITHRSAENCRYPTION", PKCSObjectIdentifiers.md2WithRSAEncryption); - algorithms.put("MD2WITHRSA", PKCSObjectIdentifiers.md2WithRSAEncryption); - 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); - 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); - 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); - 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("SHA224WITHPCVC-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); - // - // 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); - - // - // RFC 4491 - // - noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94); - noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001); - - // - // 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); - pkcs15RsaEncryption.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128); - pkcs15RsaEncryption.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160); - pkcs15RsaEncryption.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256); - - // - // 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); - digestOids.put(PKCSObjectIdentifiers.md2WithRSAEncryption, PKCSObjectIdentifiers.md2); - digestOids.put(PKCSObjectIdentifiers.md4WithRSAEncryption, PKCSObjectIdentifiers.md4); - digestOids.put(PKCSObjectIdentifiers.md5WithRSAEncryption, PKCSObjectIdentifiers.md5); - digestOids.put(PKCSObjectIdentifiers.sha1WithRSAEncryption, OIWObjectIdentifiers.idSHA1); - 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); - } - - 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/pkix/src/main/java/org/bouncycastle/operator/DigestAlgorithmIdentifierFinder.java b/pkix/src/main/java/org/bouncycastle/operator/DigestAlgorithmIdentifierFinder.java deleted file mode 100644 index b2d57c60..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/DigestAlgorithmIdentifierFinder.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.bouncycastle.operator; - -import 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/pkix/src/main/java/org/bouncycastle/operator/DigestCalculator.java b/pkix/src/main/java/org/bouncycastle/operator/DigestCalculator.java deleted file mode 100644 index 203e876f..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/DigestCalculator.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.bouncycastle.operator; - -import java.io.OutputStream; - -import 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/pkix/src/main/java/org/bouncycastle/operator/DigestCalculatorProvider.java b/pkix/src/main/java/org/bouncycastle/operator/DigestCalculatorProvider.java deleted file mode 100644 index 23652703..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/DigestCalculatorProvider.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.bouncycastle.operator; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -public interface DigestCalculatorProvider -{ - DigestCalculator get(AlgorithmIdentifier digestAlgorithmIdentifier) - throws OperatorCreationException; -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/GenericKey.java b/pkix/src/main/java/org/bouncycastle/operator/GenericKey.java deleted file mode 100644 index c637b667..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/GenericKey.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.bouncycastle.operator; - -import 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/pkix/src/main/java/org/bouncycastle/operator/InputDecryptor.java b/pkix/src/main/java/org/bouncycastle/operator/InputDecryptor.java deleted file mode 100644 index 80d7d82a..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/InputDecryptor.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.bouncycastle.operator; - -import java.io.InputStream; - -import 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/pkix/src/main/java/org/bouncycastle/operator/InputDecryptorProvider.java b/pkix/src/main/java/org/bouncycastle/operator/InputDecryptorProvider.java deleted file mode 100644 index d50e6a7b..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/InputDecryptorProvider.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.bouncycastle.operator; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -public interface InputDecryptorProvider -{ - public InputDecryptor get(AlgorithmIdentifier algorithm) - throws OperatorCreationException; -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/InputExpander.java b/pkix/src/main/java/org/bouncycastle/operator/InputExpander.java deleted file mode 100644 index 4767aed6..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/InputExpander.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.bouncycastle.operator; - -import java.io.InputStream; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -/** - * General interface for an operator that is able to produce - * an InputStream that will produce uncompressed data. - */ -public interface InputExpander -{ - /** - * Return the algorithm identifier describing the compression - * algorithm and parameters this expander supports. - * - * @return algorithm oid and parameters. - */ - AlgorithmIdentifier getAlgorithmIdentifier(); - - /** - * Wrap the passed in input stream comIn, returning an input stream - * that expands anything read in from comIn. - * - * @param comIn the compressed input data stream.. - * @return an expanding InputStream. - */ - InputStream getInputStream(InputStream comIn); -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/InputExpanderProvider.java b/pkix/src/main/java/org/bouncycastle/operator/InputExpanderProvider.java deleted file mode 100644 index f560e04b..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/InputExpanderProvider.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.bouncycastle.operator; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -public interface InputExpanderProvider -{ - InputExpander get(AlgorithmIdentifier algorithm); -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/KeyUnwrapper.java b/pkix/src/main/java/org/bouncycastle/operator/KeyUnwrapper.java deleted file mode 100644 index e34f6708..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/KeyUnwrapper.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.bouncycastle.operator; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -public interface KeyUnwrapper -{ - AlgorithmIdentifier getAlgorithmIdentifier(); - - GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptionKeyAlgorithm, byte[] encryptedKey) - throws OperatorException; -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/KeyWrapper.java b/pkix/src/main/java/org/bouncycastle/operator/KeyWrapper.java deleted file mode 100644 index 29b76a84..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/KeyWrapper.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.bouncycastle.operator; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -public interface KeyWrapper -{ - AlgorithmIdentifier getAlgorithmIdentifier(); - - byte[] generateWrappedKey(GenericKey encryptionKey) - throws OperatorException; -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/MacCalculator.java b/pkix/src/main/java/org/bouncycastle/operator/MacCalculator.java deleted file mode 100644 index 0572afcb..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/MacCalculator.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.bouncycastle.operator; - -import java.io.OutputStream; - -import 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/pkix/src/main/java/org/bouncycastle/operator/MacCalculatorProvider.java b/pkix/src/main/java/org/bouncycastle/operator/MacCalculatorProvider.java deleted file mode 100644 index 5f507449..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/MacCalculatorProvider.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.bouncycastle.operator; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -public interface MacCalculatorProvider -{ - public MacCalculator get(AlgorithmIdentifier algorithm); -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/OperatorCreationException.java b/pkix/src/main/java/org/bouncycastle/operator/OperatorCreationException.java deleted file mode 100644 index 06d3fa02..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/OperatorCreationException.java +++ /dev/null @@ -1,15 +0,0 @@ -package 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/pkix/src/main/java/org/bouncycastle/operator/OperatorException.java b/pkix/src/main/java/org/bouncycastle/operator/OperatorException.java deleted file mode 100644 index a2146522..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/OperatorException.java +++ /dev/null @@ -1,24 +0,0 @@ -package 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/pkix/src/main/java/org/bouncycastle/operator/OperatorStreamException.java b/pkix/src/main/java/org/bouncycastle/operator/OperatorStreamException.java deleted file mode 100644 index a4534eba..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/OperatorStreamException.java +++ /dev/null @@ -1,21 +0,0 @@ -package 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/pkix/src/main/java/org/bouncycastle/operator/OutputCompressor.java b/pkix/src/main/java/org/bouncycastle/operator/OutputCompressor.java deleted file mode 100644 index 054966ec..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/OutputCompressor.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.bouncycastle.operator; - -import java.io.OutputStream; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -/** - * General interface for an operator that is able to produce - * an OutputStream that will output compressed data. - */ -public interface OutputCompressor -{ - /** - * Return the algorithm identifier describing the compression - * algorithm and parameters this compressor uses. - * - * @return algorithm oid and parameters. - */ - AlgorithmIdentifier getAlgorithmIdentifier(); - - /** - * Wrap the passed in output stream comOut, returning an output stream - * that compresses anything passed in before sending on to comOut. - * - * @param comOut output stream for compressed output. - * @return a compressing OutputStream - */ - OutputStream getOutputStream(OutputStream comOut); -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/OutputEncryptor.java b/pkix/src/main/java/org/bouncycastle/operator/OutputEncryptor.java deleted file mode 100644 index 383e1fd8..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/OutputEncryptor.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.bouncycastle.operator; - -import java.io.OutputStream; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -/** - * General interface for an operator that is able to produce - * an OutputStream that will output encrypted data. - */ -public interface OutputEncryptor -{ - /** - * Return the algorithm identifier describing the encryption - * algorithm and parameters this encryptor uses. - * - * @return algorithm oid and parameters. - */ - AlgorithmIdentifier getAlgorithmIdentifier(); - - /** - * Wrap the passed in output stream encOut, returning an output stream - * that encrypts anything passed in before sending on to encOut. - * - * @param encOut output stream for encrypted output. - * @return an encrypting OutputStream - */ - OutputStream getOutputStream(OutputStream encOut); - - /** - * Return the key used for encrypting the output. - * - * @return the encryption key. - */ - GenericKey getKey(); -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/RawContentVerifier.java b/pkix/src/main/java/org/bouncycastle/operator/RawContentVerifier.java deleted file mode 100644 index 447a27b0..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/RawContentVerifier.java +++ /dev/null @@ -1,17 +0,0 @@ -package 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/pkix/src/main/java/org/bouncycastle/operator/RuntimeOperatorException.java b/pkix/src/main/java/org/bouncycastle/operator/RuntimeOperatorException.java deleted file mode 100644 index 58242b2a..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/RuntimeOperatorException.java +++ /dev/null @@ -1,24 +0,0 @@ -package 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/pkix/src/main/java/org/bouncycastle/operator/SecretKeySizeProvider.java b/pkix/src/main/java/org/bouncycastle/operator/SecretKeySizeProvider.java deleted file mode 100644 index 5f92ef03..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/SecretKeySizeProvider.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.bouncycastle.operator; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -public interface SecretKeySizeProvider -{ - int getKeySize(AlgorithmIdentifier algorithmIdentifier); - - /** - * Return the key size implied by the OID, if one exists. - * - * @param algorithm the OID of the algorithm of interest. - * @return -1 if there is no fixed key size associated with the OID, or more information is required. - */ - int getKeySize(ASN1ObjectIdentifier algorithm); -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/SignatureAlgorithmIdentifierFinder.java b/pkix/src/main/java/org/bouncycastle/operator/SignatureAlgorithmIdentifierFinder.java deleted file mode 100644 index 87521dd6..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/SignatureAlgorithmIdentifierFinder.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.bouncycastle.operator; - -import 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/pkix/src/main/java/org/bouncycastle/operator/SymmetricKeyUnwrapper.java b/pkix/src/main/java/org/bouncycastle/operator/SymmetricKeyUnwrapper.java deleted file mode 100644 index 7c724554..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/SymmetricKeyUnwrapper.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.bouncycastle.operator; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -public abstract class SymmetricKeyUnwrapper - implements KeyUnwrapper -{ - private AlgorithmIdentifier algorithmId; - - protected SymmetricKeyUnwrapper(AlgorithmIdentifier algorithmId) - { - this.algorithmId = algorithmId; - } - - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return algorithmId; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/SymmetricKeyWrapper.java b/pkix/src/main/java/org/bouncycastle/operator/SymmetricKeyWrapper.java deleted file mode 100644 index b1864d23..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/SymmetricKeyWrapper.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.bouncycastle.operator; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -public abstract class SymmetricKeyWrapper - implements KeyWrapper -{ - private AlgorithmIdentifier algorithmId; - - protected SymmetricKeyWrapper(AlgorithmIdentifier algorithmId) - { - this.algorithmId = algorithmId; - } - - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return algorithmId; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/bc/AESUtil.java b/pkix/src/main/java/org/bouncycastle/operator/bc/AESUtil.java deleted file mode 100644 index 83fab445..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/bc/AESUtil.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.bouncycastle.operator.bc; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.params.KeyParameter; - -class AESUtil -{ - static AlgorithmIdentifier determineKeyEncAlg(KeyParameter key) - { - int length = key.getKey().length * 8; - ASN1ObjectIdentifier wrapOid; - - if (length == 128) - { - wrapOid = NISTObjectIdentifiers.id_aes128_wrap; - } - else if (length == 192) - { - wrapOid = NISTObjectIdentifiers.id_aes192_wrap; - } - else if (length == 256) - { - wrapOid = NISTObjectIdentifiers.id_aes256_wrap; - } - else - { - throw new IllegalArgumentException("illegal keysize in AES"); - } - - return new AlgorithmIdentifier(wrapOid); // parameters absent - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/bc/BcAESSymmetricKeyUnwrapper.java b/pkix/src/main/java/org/bouncycastle/operator/bc/BcAESSymmetricKeyUnwrapper.java deleted file mode 100644 index 024bbd66..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/bc/BcAESSymmetricKeyUnwrapper.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.bouncycastle.operator.bc; - -import org.bouncycastle.crypto.engines.AESWrapEngine; -import org.bouncycastle.crypto.params.KeyParameter; - -public class BcAESSymmetricKeyUnwrapper - extends BcSymmetricKeyUnwrapper -{ - public BcAESSymmetricKeyUnwrapper(KeyParameter wrappingKey) - { - super(AESUtil.determineKeyEncAlg(wrappingKey), new AESWrapEngine(), wrappingKey); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/bc/BcAESSymmetricKeyWrapper.java b/pkix/src/main/java/org/bouncycastle/operator/bc/BcAESSymmetricKeyWrapper.java deleted file mode 100644 index 0da561b0..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/bc/BcAESSymmetricKeyWrapper.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.bouncycastle.operator.bc; - -import org.bouncycastle.crypto.engines.AESWrapEngine; -import org.bouncycastle.crypto.params.KeyParameter; - -public class BcAESSymmetricKeyWrapper - extends BcSymmetricKeyWrapper -{ - public BcAESSymmetricKeyWrapper(KeyParameter wrappingKey) - { - super(AESUtil.determineKeyEncAlg(wrappingKey), new AESWrapEngine(), wrappingKey); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/bc/BcAsymmetricKeyUnwrapper.java b/pkix/src/main/java/org/bouncycastle/operator/bc/BcAsymmetricKeyUnwrapper.java deleted file mode 100644 index 2bf5c2d7..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/bc/BcAsymmetricKeyUnwrapper.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.bouncycastle.operator.bc; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.AsymmetricBlockCipher; -import org.bouncycastle.crypto.InvalidCipherTextException; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.operator.AsymmetricKeyUnwrapper; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.OperatorException; - -public abstract class BcAsymmetricKeyUnwrapper - extends AsymmetricKeyUnwrapper -{ - private AsymmetricKeyParameter privateKey; - - public BcAsymmetricKeyUnwrapper(AlgorithmIdentifier encAlgId, AsymmetricKeyParameter privateKey) - { - super(encAlgId); - - this.privateKey = privateKey; - } - - public GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedKey) - throws OperatorException - { - AsymmetricBlockCipher keyCipher = createAsymmetricUnwrapper(this.getAlgorithmIdentifier().getAlgorithm()); - - keyCipher.init(false, privateKey); - try - { - byte[] key = keyCipher.processBlock(encryptedKey, 0, encryptedKey.length); - - if (encryptedKeyAlgorithm.getAlgorithm().equals(PKCSObjectIdentifiers.des_EDE3_CBC)) - { - return new GenericKey(encryptedKeyAlgorithm, key); - } - else - { - return new GenericKey(encryptedKeyAlgorithm, key); - } - } - catch (InvalidCipherTextException e) - { - throw new OperatorException("unable to recover secret key: " + e.getMessage(), e); - } - } - - protected abstract AsymmetricBlockCipher createAsymmetricUnwrapper(ASN1ObjectIdentifier algorithm); -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/bc/BcAsymmetricKeyWrapper.java b/pkix/src/main/java/org/bouncycastle/operator/bc/BcAsymmetricKeyWrapper.java deleted file mode 100644 index f9c78087..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/bc/BcAsymmetricKeyWrapper.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.bouncycastle.operator.bc; - -import java.security.SecureRandom; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.AsymmetricBlockCipher; -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.InvalidCipherTextException; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.operator.AsymmetricKeyWrapper; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.OperatorException; - -public abstract class BcAsymmetricKeyWrapper - extends AsymmetricKeyWrapper -{ - private AsymmetricKeyParameter publicKey; - private SecureRandom random; - - public BcAsymmetricKeyWrapper(AlgorithmIdentifier encAlgId, AsymmetricKeyParameter publicKey) - { - super(encAlgId); - - this.publicKey = publicKey; - } - - public BcAsymmetricKeyWrapper setSecureRandom(SecureRandom random) - { - this.random = random; - - return this; - } - - public byte[] generateWrappedKey(GenericKey encryptionKey) - throws OperatorException - { - AsymmetricBlockCipher keyEncryptionCipher = createAsymmetricWrapper(getAlgorithmIdentifier().getAlgorithm()); - - CipherParameters params = publicKey; - if (random != null) - { - params = new ParametersWithRandom(params, random); - } - - try - { - byte[] keyEnc = OperatorUtils.getKeyBytes(encryptionKey); - keyEncryptionCipher.init(true, publicKey); - return keyEncryptionCipher.processBlock(keyEnc, 0, keyEnc.length); - } - catch (InvalidCipherTextException e) - { - throw new OperatorException("unable to encrypt contents key", e); - } - } - - protected abstract AsymmetricBlockCipher createAsymmetricWrapper(ASN1ObjectIdentifier algorithm); -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/bc/BcContentSignerBuilder.java b/pkix/src/main/java/org/bouncycastle/operator/bc/BcContentSignerBuilder.java deleted file mode 100644 index a7b45fcb..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/bc/BcContentSignerBuilder.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.bouncycastle.operator.bc; - -import java.io.OutputStream; -import java.security.SecureRandom; -import java.util.Map; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.CryptoException; -import org.bouncycastle.crypto.Signer; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.operator.ContentSigner; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.operator.RuntimeOperatorException; - -public abstract class BcContentSignerBuilder -{ - private SecureRandom random; - private AlgorithmIdentifier sigAlgId; - private AlgorithmIdentifier digAlgId; - - protected BcDigestProvider digestProvider; - - public BcContentSignerBuilder(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier digAlgId) - { - this.sigAlgId = sigAlgId; - this.digAlgId = digAlgId; - this.digestProvider = BcDefaultDigestProvider.INSTANCE; - } - - public BcContentSignerBuilder setSecureRandom(SecureRandom random) - { - this.random = random; - - return this; - } - - public ContentSigner build(AsymmetricKeyParameter privateKey) - throws OperatorCreationException - { - final Signer sig = createSigner(sigAlgId, digAlgId); - - if (random != null) - { - sig.init(true, new ParametersWithRandom(privateKey, random)); - } - else - { - sig.init(true, privateKey); - } - - return new ContentSigner() - { - private BcSignerOutputStream stream = new BcSignerOutputStream(sig); - - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return sigAlgId; - } - - public OutputStream getOutputStream() - { - return stream; - } - - public byte[] getSignature() - { - try - { - return stream.getSignature(); - } - catch (CryptoException e) - { - throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e); - } - } - }; - } - - protected abstract Signer createSigner(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier algorithmIdentifier) - throws OperatorCreationException; -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/bc/BcContentVerifierProviderBuilder.java b/pkix/src/main/java/org/bouncycastle/operator/bc/BcContentVerifierProviderBuilder.java deleted file mode 100644 index ff57e60b..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/bc/BcContentVerifierProviderBuilder.java +++ /dev/null @@ -1,144 +0,0 @@ -package org.bouncycastle.operator.bc; - -import java.io.IOException; -import java.io.OutputStream; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.crypto.Signer; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.operator.ContentVerifier; -import org.bouncycastle.operator.ContentVerifierProvider; -import org.bouncycastle.operator.OperatorCreationException; - -public abstract class BcContentVerifierProviderBuilder -{ - protected BcDigestProvider digestProvider; - - public BcContentVerifierProviderBuilder() - { - this.digestProvider = BcDefaultDigestProvider.INSTANCE; - } - - public ContentVerifierProvider build(final X509CertificateHolder certHolder) - throws OperatorCreationException - { - return new ContentVerifierProvider() - { - public boolean hasAssociatedCertificate() - { - return true; - } - - public X509CertificateHolder getAssociatedCertificate() - { - return certHolder; - } - - public ContentVerifier get(AlgorithmIdentifier algorithm) - throws OperatorCreationException - { - try - { - AsymmetricKeyParameter publicKey = extractKeyParameters(certHolder.getSubjectPublicKeyInfo()); - BcSignerOutputStream stream = createSignatureStream(algorithm, publicKey); - - return new SigVerifier(algorithm, stream); - } - catch (IOException e) - { - throw new OperatorCreationException("exception on setup: " + e, e); - } - } - }; - } - - public ContentVerifierProvider build(final AsymmetricKeyParameter publicKey) - throws OperatorCreationException - { - return new ContentVerifierProvider() - { - public boolean hasAssociatedCertificate() - { - return false; - } - - public X509CertificateHolder getAssociatedCertificate() - { - return null; - } - - public ContentVerifier get(AlgorithmIdentifier algorithm) - throws OperatorCreationException - { - BcSignerOutputStream stream = createSignatureStream(algorithm, publicKey); - - return new SigVerifier(algorithm, stream); - } - }; - } - - private BcSignerOutputStream createSignatureStream(AlgorithmIdentifier algorithm, AsymmetricKeyParameter publicKey) - throws OperatorCreationException - { - Signer sig = createSigner(algorithm); - - sig.init(false, publicKey); - - return new BcSignerOutputStream(sig); - } - - /** - * Extract an AsymmetricKeyParameter from the passed in SubjectPublicKeyInfo structure. - * - * @param publicKeyInfo a publicKeyInfo structure describing the public key required. - * @return an AsymmetricKeyParameter object containing the appropriate public key. - * @throws IOException if the publicKeyInfo data cannot be parsed, - */ - protected abstract AsymmetricKeyParameter extractKeyParameters(SubjectPublicKeyInfo publicKeyInfo) - throws IOException; - - /** - * Create the correct signer for the algorithm identifier sigAlgId. - * - * @param sigAlgId the algorithm details for the signature we want to verify. - * @return a Signer object. - * @throws OperatorCreationException if the Signer cannot be constructed. - */ - protected abstract Signer createSigner(AlgorithmIdentifier sigAlgId) - throws OperatorCreationException; - - private class SigVerifier - implements ContentVerifier - { - private BcSignerOutputStream stream; - private AlgorithmIdentifier algorithm; - - SigVerifier(AlgorithmIdentifier algorithm, BcSignerOutputStream 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) - { - return stream.verify(expected); - } - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/operator/bc/BcDSAContentSignerBuilder.java b/pkix/src/main/java/org/bouncycastle/operator/bc/BcDSAContentSignerBuilder.java deleted file mode 100644 index 893f9fdd..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/bc/BcDSAContentSignerBuilder.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.bouncycastle.operator.bc; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.Signer; -import org.bouncycastle.crypto.signers.DSADigestSigner; -import org.bouncycastle.crypto.signers.DSASigner; -import org.bouncycastle.operator.OperatorCreationException; - -public class BcDSAContentSignerBuilder - extends BcContentSignerBuilder -{ - public BcDSAContentSignerBuilder(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier digAlgId) - { - super(sigAlgId, digAlgId); - } - - protected Signer createSigner(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier digAlgId) - throws OperatorCreationException - { - Digest dig = digestProvider.get(digAlgId); - - return new DSADigestSigner(new DSASigner(), dig); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/bc/BcDSAContentVerifierProviderBuilder.java b/pkix/src/main/java/org/bouncycastle/operator/bc/BcDSAContentVerifierProviderBuilder.java deleted file mode 100644 index 15bb3018..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/bc/BcDSAContentVerifierProviderBuilder.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.bouncycastle.operator.bc; - -import java.io.IOException; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.Signer; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.signers.DSADigestSigner; -import org.bouncycastle.crypto.signers.DSASigner; -import org.bouncycastle.crypto.util.PublicKeyFactory; -import org.bouncycastle.operator.DigestAlgorithmIdentifierFinder; -import org.bouncycastle.operator.OperatorCreationException; - -public class BcDSAContentVerifierProviderBuilder - extends BcContentVerifierProviderBuilder -{ - private DigestAlgorithmIdentifierFinder digestAlgorithmFinder; - - public BcDSAContentVerifierProviderBuilder(DigestAlgorithmIdentifierFinder digestAlgorithmFinder) - { - this.digestAlgorithmFinder = digestAlgorithmFinder; - } - - protected Signer createSigner(AlgorithmIdentifier sigAlgId) - throws OperatorCreationException - { - AlgorithmIdentifier digAlg = digestAlgorithmFinder.find(sigAlgId); - Digest dig = digestProvider.get(digAlg); - - return new DSADigestSigner(new DSASigner(), dig); - } - - protected AsymmetricKeyParameter extractKeyParameters(SubjectPublicKeyInfo publicKeyInfo) - throws IOException - { - return PublicKeyFactory.createKey(publicKeyInfo); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java b/pkix/src/main/java/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java deleted file mode 100644 index 655b695b..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/bc/BcDefaultDigestProvider.java +++ /dev/null @@ -1,144 +0,0 @@ -package org.bouncycastle.operator.bc; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.ExtendedDigest; -import org.bouncycastle.crypto.digests.GOST3411Digest; -import org.bouncycastle.crypto.digests.MD2Digest; -import org.bouncycastle.crypto.digests.MD4Digest; -import org.bouncycastle.crypto.digests.MD5Digest; -import org.bouncycastle.crypto.digests.RIPEMD128Digest; -import org.bouncycastle.crypto.digests.RIPEMD160Digest; -import org.bouncycastle.crypto.digests.RIPEMD256Digest; -import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.digests.SHA224Digest; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.digests.SHA384Digest; -import org.bouncycastle.crypto.digests.SHA512Digest; -import 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(); - } - }); - 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(); - } - }); - - 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/pkix/src/main/java/org/bouncycastle/operator/bc/BcDigestCalculatorProvider.java b/pkix/src/main/java/org/bouncycastle/operator/bc/BcDigestCalculatorProvider.java deleted file mode 100644 index 4d029dd8..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/bc/BcDigestCalculatorProvider.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.bouncycastle.operator.bc; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.Map; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.ExtendedDigest; -import org.bouncycastle.operator.DigestCalculator; -import org.bouncycastle.operator.DigestCalculatorProvider; -import 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/pkix/src/main/java/org/bouncycastle/operator/bc/BcDigestProvider.java b/pkix/src/main/java/org/bouncycastle/operator/bc/BcDigestProvider.java deleted file mode 100644 index 691a56ac..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/bc/BcDigestProvider.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.bouncycastle.operator.bc; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.ExtendedDigest; -import org.bouncycastle.operator.OperatorCreationException; - -public interface BcDigestProvider -{ - ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) - throws OperatorCreationException; -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/bc/BcRSAAsymmetricKeyUnwrapper.java b/pkix/src/main/java/org/bouncycastle/operator/bc/BcRSAAsymmetricKeyUnwrapper.java deleted file mode 100644 index 84eb29db..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/bc/BcRSAAsymmetricKeyUnwrapper.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.bouncycastle.operator.bc; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.AsymmetricBlockCipher; -import org.bouncycastle.crypto.encodings.PKCS1Encoding; -import org.bouncycastle.crypto.engines.RSAEngine; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; - -public class BcRSAAsymmetricKeyUnwrapper - extends BcAsymmetricKeyUnwrapper -{ - public BcRSAAsymmetricKeyUnwrapper(AlgorithmIdentifier encAlgId, AsymmetricKeyParameter privateKey) - { - super(encAlgId, privateKey); - } - - protected AsymmetricBlockCipher createAsymmetricUnwrapper(ASN1ObjectIdentifier algorithm) - { - return new PKCS1Encoding(new RSAEngine()); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/bc/BcRSAAsymmetricKeyWrapper.java b/pkix/src/main/java/org/bouncycastle/operator/bc/BcRSAAsymmetricKeyWrapper.java deleted file mode 100644 index 9375bd15..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/bc/BcRSAAsymmetricKeyWrapper.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.bouncycastle.operator.bc; - -import java.io.IOException; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.crypto.AsymmetricBlockCipher; -import org.bouncycastle.crypto.encodings.PKCS1Encoding; -import org.bouncycastle.crypto.engines.RSAEngine; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.util.PublicKeyFactory; - -public class BcRSAAsymmetricKeyWrapper - extends BcAsymmetricKeyWrapper -{ - public BcRSAAsymmetricKeyWrapper(AlgorithmIdentifier encAlgId, AsymmetricKeyParameter publicKey) - { - super(encAlgId, publicKey); - } - - public BcRSAAsymmetricKeyWrapper(AlgorithmIdentifier encAlgId, SubjectPublicKeyInfo publicKeyInfo) - throws IOException - { - super(encAlgId, PublicKeyFactory.createKey(publicKeyInfo)); - } - - protected AsymmetricBlockCipher createAsymmetricWrapper(ASN1ObjectIdentifier algorithm) - { - return new PKCS1Encoding(new RSAEngine()); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/bc/BcRSAContentSignerBuilder.java b/pkix/src/main/java/org/bouncycastle/operator/bc/BcRSAContentSignerBuilder.java deleted file mode 100644 index db317deb..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/bc/BcRSAContentSignerBuilder.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.bouncycastle.operator.bc; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.Signer; -import org.bouncycastle.crypto.signers.RSADigestSigner; -import org.bouncycastle.operator.OperatorCreationException; - -public class BcRSAContentSignerBuilder - extends BcContentSignerBuilder -{ - public BcRSAContentSignerBuilder(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier digAlgId) - { - super(sigAlgId, digAlgId); - } - - protected Signer createSigner(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier digAlgId) - throws OperatorCreationException - { - Digest dig = digestProvider.get(digAlgId); - - return new RSADigestSigner(dig); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/bc/BcRSAContentVerifierProviderBuilder.java b/pkix/src/main/java/org/bouncycastle/operator/bc/BcRSAContentVerifierProviderBuilder.java deleted file mode 100644 index 7b2249c8..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/bc/BcRSAContentVerifierProviderBuilder.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.bouncycastle.operator.bc; - -import java.io.IOException; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.Signer; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.signers.RSADigestSigner; -import org.bouncycastle.crypto.util.PublicKeyFactory; -import org.bouncycastle.operator.DigestAlgorithmIdentifierFinder; -import org.bouncycastle.operator.OperatorCreationException; - -public class BcRSAContentVerifierProviderBuilder - extends BcContentVerifierProviderBuilder -{ - private DigestAlgorithmIdentifierFinder digestAlgorithmFinder; - - public BcRSAContentVerifierProviderBuilder(DigestAlgorithmIdentifierFinder digestAlgorithmFinder) - { - this.digestAlgorithmFinder = digestAlgorithmFinder; - } - - protected Signer createSigner(AlgorithmIdentifier sigAlgId) - throws OperatorCreationException - { - AlgorithmIdentifier digAlg = digestAlgorithmFinder.find(sigAlgId); - Digest dig = digestProvider.get(digAlg); - - return new RSADigestSigner(dig); - } - - protected AsymmetricKeyParameter extractKeyParameters(SubjectPublicKeyInfo publicKeyInfo) - throws IOException - { - return PublicKeyFactory.createKey(publicKeyInfo); - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/operator/bc/BcSignerOutputStream.java b/pkix/src/main/java/org/bouncycastle/operator/bc/BcSignerOutputStream.java deleted file mode 100644 index 0ef1656b..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/bc/BcSignerOutputStream.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.bouncycastle.operator.bc; - -import java.io.IOException; -import java.io.OutputStream; - -import org.bouncycastle.crypto.CryptoException; -import org.bouncycastle.crypto.Signer; - -public class BcSignerOutputStream - extends OutputStream -{ - private Signer sig; - - BcSignerOutputStream(Signer sig) - { - this.sig = sig; - } - - public void write(byte[] bytes, int off, int len) - throws IOException - { - sig.update(bytes, off, len); - } - - public void write(byte[] bytes) - throws IOException - { - sig.update(bytes, 0, bytes.length); - } - - public void write(int b) - throws IOException - { - sig.update((byte)b); - } - - byte[] getSignature() - throws CryptoException - { - return sig.generateSignature(); - } - - boolean verify(byte[] expected) - { - return sig.verifySignature(expected); - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/operator/bc/BcSymmetricKeyUnwrapper.java b/pkix/src/main/java/org/bouncycastle/operator/bc/BcSymmetricKeyUnwrapper.java deleted file mode 100644 index f8df3b61..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/bc/BcSymmetricKeyUnwrapper.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.bouncycastle.operator.bc; - -import java.security.SecureRandom; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.InvalidCipherTextException; -import org.bouncycastle.crypto.Wrapper; -import org.bouncycastle.crypto.params.KeyParameter; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.OperatorException; -import org.bouncycastle.operator.SymmetricKeyUnwrapper; - -public class BcSymmetricKeyUnwrapper - extends SymmetricKeyUnwrapper -{ - private SecureRandom random; - private Wrapper wrapper; - private KeyParameter wrappingKey; - - public BcSymmetricKeyUnwrapper(AlgorithmIdentifier wrappingAlgorithm, Wrapper wrapper, KeyParameter wrappingKey) - { - super(wrappingAlgorithm); - - this.wrapper = wrapper; - this.wrappingKey = wrappingKey; - } - - public BcSymmetricKeyUnwrapper setSecureRandom(SecureRandom random) - { - this.random = random; - - return this; - } - - public GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedKey) - throws OperatorException - { - wrapper.init(false, wrappingKey); - - try - { - return new GenericKey(encryptedKeyAlgorithm, wrapper.unwrap(encryptedKey, 0, encryptedKey.length)); - } - catch (InvalidCipherTextException e) - { - throw new OperatorException("unable to unwrap key: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/bc/BcSymmetricKeyWrapper.java b/pkix/src/main/java/org/bouncycastle/operator/bc/BcSymmetricKeyWrapper.java deleted file mode 100644 index b7f89505..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/bc/BcSymmetricKeyWrapper.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.bouncycastle.operator.bc; - -import java.security.SecureRandom; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.Wrapper; -import org.bouncycastle.crypto.params.KeyParameter; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.OperatorException; -import org.bouncycastle.operator.SymmetricKeyWrapper; - -public class BcSymmetricKeyWrapper - extends SymmetricKeyWrapper -{ - private SecureRandom random; - private Wrapper wrapper; - private KeyParameter wrappingKey; - - public BcSymmetricKeyWrapper(AlgorithmIdentifier wrappingAlgorithm, Wrapper wrapper, KeyParameter wrappingKey) - { - super(wrappingAlgorithm); - - this.wrapper = wrapper; - this.wrappingKey = wrappingKey; - } - - public BcSymmetricKeyWrapper setSecureRandom(SecureRandom random) - { - this.random = random; - - return this; - } - - public byte[] generateWrappedKey(GenericKey encryptionKey) - throws OperatorException - { - byte[] contentEncryptionKeySpec = OperatorUtils.getKeyBytes(encryptionKey); - - if (random == null) - { - wrapper.init(true, wrappingKey); - } - else - { - wrapper.init(true, new ParametersWithRandom(wrappingKey, random)); - } - - return wrapper.wrap(contentEncryptionKeySpec, 0, contentEncryptionKeySpec.length); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/bc/CamelliaUtil.java b/pkix/src/main/java/org/bouncycastle/operator/bc/CamelliaUtil.java deleted file mode 100644 index 819637da..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/bc/CamelliaUtil.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.bouncycastle.operator.bc; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.params.KeyParameter; - -class CamelliaUtil -{ - static AlgorithmIdentifier determineKeyEncAlg(KeyParameter key) - { - int length = key.getKey().length * 8; - ASN1ObjectIdentifier wrapOid; - - if (length == 128) - { - wrapOid = NTTObjectIdentifiers.id_camellia128_wrap; - } - else if (length == 192) - { - wrapOid = NTTObjectIdentifiers.id_camellia192_wrap; - } - else if (length == 256) - { - wrapOid = NTTObjectIdentifiers.id_camellia256_wrap; - } - else - { - throw new IllegalArgumentException( - "illegal keysize in Camellia"); - } - - return new AlgorithmIdentifier(wrapOid); // parameters must be - // absent - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/bc/OperatorUtils.java b/pkix/src/main/java/org/bouncycastle/operator/bc/OperatorUtils.java deleted file mode 100644 index bc8e7f6e..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/bc/OperatorUtils.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.bouncycastle.operator.bc; - -import java.security.Key; - -import org.bouncycastle.operator.GenericKey; - -class OperatorUtils -{ - static byte[] getKeyBytes(GenericKey key) - { - if (key.getRepresentation() instanceof Key) - { - return ((Key)key.getRepresentation()).getEncoded(); - } - - if (key.getRepresentation() instanceof byte[]) - { - return (byte[])key.getRepresentation(); - } - - throw new IllegalArgumentException("unknown generic key type"); - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/operator/bc/SEEDUtil.java b/pkix/src/main/java/org/bouncycastle/operator/bc/SEEDUtil.java deleted file mode 100644 index 3b1971c4..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/bc/SEEDUtil.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.bouncycastle.operator.bc; - -import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -class SEEDUtil -{ - static AlgorithmIdentifier determineKeyEncAlg() - { - // parameters absent - return new AlgorithmIdentifier( - KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaAlgorithmParametersConverter.java b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaAlgorithmParametersConverter.java deleted file mode 100644 index d4e21621..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaAlgorithmParametersConverter.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.bouncycastle.operator.jcajce; - - -import java.io.IOException; -import java.security.AlgorithmParameters; -import java.security.InvalidAlgorithmParameterException; -import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.MGF1ParameterSpec; - -import javax.crypto.spec.OAEPParameterSpec; -import javax.crypto.spec.PSource; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.RSAESOAEPparams; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder; - -public class JcaAlgorithmParametersConverter -{ - public JcaAlgorithmParametersConverter() - { - } - - public AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier algId, AlgorithmParameters parameters) - throws InvalidAlgorithmParameterException - { - try - { - ASN1Encodable params = ASN1Primitive.fromByteArray(parameters.getEncoded()); - - return new AlgorithmIdentifier(algId, params); - } - catch (IOException e) - { - throw new InvalidAlgorithmParameterException("unable to encode parameters object: " + e.getMessage()); - } - } - - public AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier algorithm, AlgorithmParameterSpec algorithmSpec) - throws InvalidAlgorithmParameterException - { - if (algorithmSpec instanceof OAEPParameterSpec) - { - if (algorithmSpec.equals(OAEPParameterSpec.DEFAULT)) - { - return new AlgorithmIdentifier(algorithm, - new RSAESOAEPparams(RSAESOAEPparams.DEFAULT_HASH_ALGORITHM, RSAESOAEPparams.DEFAULT_MASK_GEN_FUNCTION, RSAESOAEPparams.DEFAULT_P_SOURCE_ALGORITHM)); - } - else - { - OAEPParameterSpec oaepSpec = (OAEPParameterSpec)algorithmSpec; - PSource pSource = oaepSpec.getPSource(); - - if (!oaepSpec.getMGFAlgorithm().equals(OAEPParameterSpec.DEFAULT.getMGFAlgorithm())) - { - throw new InvalidAlgorithmParameterException("only " + OAEPParameterSpec.DEFAULT.getMGFAlgorithm() + " mask generator supported."); - } - - AlgorithmIdentifier hashAlgorithm = new DefaultDigestAlgorithmIdentifierFinder().find(oaepSpec.getDigestAlgorithm()); - AlgorithmIdentifier mgf1HashAlgorithm = new DefaultDigestAlgorithmIdentifierFinder().find((((MGF1ParameterSpec)oaepSpec.getMGFParameters()).getDigestAlgorithm())); - return new AlgorithmIdentifier(algorithm, - new RSAESOAEPparams(hashAlgorithm, new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, mgf1HashAlgorithm), - new AlgorithmIdentifier(PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(((PSource.PSpecified)pSource).getValue())))); - } - } - - throw new InvalidAlgorithmParameterException("unknown parameter spec passed."); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java deleted file mode 100644 index 31af916f..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java +++ /dev/null @@ -1,160 +0,0 @@ -package 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 org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.util.NamedJcaJceHelper; -import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; -import org.bouncycastle.operator.ContentSigner; -import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.operator.OperatorStreamException; -import 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); - - if (random != null) - { - sig.initSign(privateKey, random); - } - else - { - sig.initSign(privateKey); - } - - return new ContentSigner() - { - private SignatureOutputStream stream = new SignatureOutputStream(sig); - - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return sigAlgId; - } - - 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/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java deleted file mode 100644 index 14ab78df..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java +++ /dev/null @@ -1,312 +0,0 @@ -package 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 org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; -import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.util.NamedJcaJceHelper; -import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; -import org.bouncycastle.operator.ContentVerifier; -import org.bouncycastle.operator.ContentVerifierProvider; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.operator.OperatorStreamException; -import org.bouncycastle.operator.RawContentVerifier; -import 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 SignatureOutputStream stream; - private AlgorithmIdentifier algorithm; - - 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[] digest, byte[] expected) - { - try - { - rawSignature.update(digest); - - return rawSignature.verify(expected); - } - catch (SignatureException e) - { - throw new RuntimeOperatorException("exception obtaining raw signature: " + 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); - } - } - - boolean verify(byte[] expected) - throws SignatureException - { - return sig.verify(expected); - } - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaDigestCalculatorProviderBuilder.java b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaDigestCalculatorProviderBuilder.java deleted file mode 100644 index e3567962..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaDigestCalculatorProviderBuilder.java +++ /dev/null @@ -1,114 +0,0 @@ -package 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 org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.util.NamedJcaJceHelper; -import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; -import org.bouncycastle.operator.DigestCalculator; -import org.bouncycastle.operator.DigestCalculatorProvider; -import 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/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java deleted file mode 100644 index 8e0ea75e..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java +++ /dev/null @@ -1,133 +0,0 @@ -package org.bouncycastle.operator.jcajce; - -import java.security.AlgorithmParameters; -import java.security.GeneralSecurityException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.PrivateKey; -import java.security.Provider; -import java.security.ProviderException; -import java.util.HashMap; -import java.util.Map; - -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.spec.SecretKeySpec; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.util.NamedJcaJceHelper; -import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; -import org.bouncycastle.operator.AsymmetricKeyUnwrapper; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.OperatorException; - -public class JceAsymmetricKeyUnwrapper - extends AsymmetricKeyUnwrapper -{ - private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper()); - private Map extraMappings = new HashMap(); - private PrivateKey privKey; - - public JceAsymmetricKeyUnwrapper(AlgorithmIdentifier algorithmIdentifier, PrivateKey privKey) - { - super(algorithmIdentifier); - - this.privKey = privKey; - } - - public JceAsymmetricKeyUnwrapper setProvider(Provider provider) - { - this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider)); - - return this; - } - - public JceAsymmetricKeyUnwrapper setProvider(String providerName) - { - this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName)); - - return this; - } - - /** - * Internally algorithm ids are converted into cipher names using a lookup table. For some providers - * the standard lookup table won't work. Use this method to establish a specific mapping from an - * algorithm identifier to a specific algorithm. - * <p> - * For example: - * <pre> - * unwrapper.setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA"); - * </pre> - * </p> - * @param algorithm OID of algorithm in recipient. - * @param algorithmName JCE algorithm name to use. - * @return the current Unwrapper. - */ - public JceAsymmetricKeyUnwrapper setAlgorithmMapping(ASN1ObjectIdentifier algorithm, String algorithmName) - { - extraMappings.put(algorithm, algorithmName); - - return this; - } - - public GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedKey) - throws OperatorException - { - try - { - Key sKey = null; - - Cipher keyCipher = helper.createAsymmetricWrapper(this.getAlgorithmIdentifier().getAlgorithm(), extraMappings); - AlgorithmParameters algParams = helper.createAlgorithmParameters(this.getAlgorithmIdentifier()); - - try - { - if (algParams != null) - { - keyCipher.init(Cipher.UNWRAP_MODE, privKey, algParams); - } - else - { - keyCipher.init(Cipher.UNWRAP_MODE, privKey); - } - sKey = keyCipher.unwrap(encryptedKey, helper.getKeyAlgorithmName(encryptedKeyAlgorithm.getAlgorithm()), Cipher.SECRET_KEY); - } - catch (GeneralSecurityException e) - { - } - catch (IllegalStateException e) - { - } - catch (UnsupportedOperationException e) - { - } - catch (ProviderException e) - { - } - - // some providers do not support UNWRAP (this appears to be only for asymmetric algorithms) - if (sKey == null) - { - keyCipher.init(Cipher.DECRYPT_MODE, privKey); - sKey = new SecretKeySpec(keyCipher.doFinal(encryptedKey), encryptedKeyAlgorithm.getAlgorithm().getId()); - } - - return new JceGenericKey(encryptedKeyAlgorithm, sKey); - } - catch (InvalidKeyException e) - { - throw new OperatorException("key invalid: " + e.getMessage(), e); - } - catch (IllegalBlockSizeException e) - { - throw new OperatorException("illegal blocksize: " + e.getMessage(), e); - } - catch (BadPaddingException e) - { - throw new OperatorException("bad padding: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceAsymmetricKeyWrapper.java b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceAsymmetricKeyWrapper.java deleted file mode 100644 index 6ae402d7..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceAsymmetricKeyWrapper.java +++ /dev/null @@ -1,157 +0,0 @@ -package org.bouncycastle.operator.jcajce; - -import java.security.AlgorithmParameters; -import java.security.GeneralSecurityException; -import java.security.InvalidKeyException; -import java.security.Provider; -import java.security.ProviderException; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.cert.X509Certificate; -import java.util.HashMap; -import java.util.Map; - -import javax.crypto.Cipher; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.util.NamedJcaJceHelper; -import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; -import org.bouncycastle.operator.AsymmetricKeyWrapper; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.OperatorException; - -public class JceAsymmetricKeyWrapper - extends AsymmetricKeyWrapper -{ - private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper()); - private Map extraMappings = new HashMap(); - private PublicKey publicKey; - private SecureRandom random; - - public JceAsymmetricKeyWrapper(PublicKey publicKey) - { - super(SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()).getAlgorithm()); - - this.publicKey = publicKey; - } - - public JceAsymmetricKeyWrapper(X509Certificate certificate) - { - this(certificate.getPublicKey()); - } - - /** - * Create a wrapper, overriding the algorithm type that is stored in the public key. - * - * @param algorithmIdentifier identifier for encryption algorithm to be used. - * @param publicKey the public key to be used. - */ - public JceAsymmetricKeyWrapper(AlgorithmIdentifier algorithmIdentifier, PublicKey publicKey) - { - super(algorithmIdentifier); - - this.publicKey = publicKey; - } - - public JceAsymmetricKeyWrapper setProvider(Provider provider) - { - this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider)); - - return this; - } - - public JceAsymmetricKeyWrapper setProvider(String providerName) - { - this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName)); - - return this; - } - - public JceAsymmetricKeyWrapper setSecureRandom(SecureRandom random) - { - this.random = random; - - return this; - } - - /** - * Internally algorithm ids are converted into cipher names using a lookup table. For some providers - * the standard lookup table won't work. Use this method to establish a specific mapping from an - * algorithm identifier to a specific algorithm. - * <p> - * For example: - * <pre> - * unwrapper.setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA"); - * </pre> - * </p> - * @param algorithm OID of algorithm in recipient. - * @param algorithmName JCE algorithm name to use. - * @return the current Wrapper. - */ - public JceAsymmetricKeyWrapper setAlgorithmMapping(ASN1ObjectIdentifier algorithm, String algorithmName) - { - extraMappings.put(algorithm, algorithmName); - - return this; - } - - public byte[] generateWrappedKey(GenericKey encryptionKey) - throws OperatorException - { - Cipher keyEncryptionCipher = helper.createAsymmetricWrapper(getAlgorithmIdentifier().getAlgorithm(), extraMappings); - AlgorithmParameters algParams = helper.createAlgorithmParameters(this.getAlgorithmIdentifier()); - - byte[] encryptedKeyBytes = null; - - try - { - if (algParams != null) - { - keyEncryptionCipher.init(Cipher.WRAP_MODE, publicKey, algParams, random); - } - else - { - keyEncryptionCipher.init(Cipher.WRAP_MODE, publicKey, random); - } - encryptedKeyBytes = keyEncryptionCipher.wrap(OperatorUtils.getJceKey(encryptionKey)); - } - catch (InvalidKeyException e) - { - } - catch (GeneralSecurityException e) - { - } - catch (IllegalStateException e) - { - } - catch (UnsupportedOperationException e) - { - } - catch (ProviderException e) - { - } - - // some providers do not support WRAP (this appears to be only for asymmetric algorithms) - if (encryptedKeyBytes == null) - { - try - { - keyEncryptionCipher.init(Cipher.ENCRYPT_MODE, publicKey, random); - encryptedKeyBytes = keyEncryptionCipher.doFinal(OperatorUtils.getJceKey(encryptionKey).getEncoded()); - } - catch (InvalidKeyException e) - { - throw new OperatorException("unable to encrypt contents key", e); - } - catch (GeneralSecurityException e) - { - throw new OperatorException("unable to encrypt contents key", e); - } - } - - return encryptedKeyBytes; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceGenericKey.java b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceGenericKey.java deleted file mode 100644 index efcbc3dc..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceGenericKey.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.bouncycastle.operator.jcajce; - -import java.security.Key; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.operator.GenericKey; - -public class JceGenericKey - extends GenericKey -{ - /** - * Attempt to simplify the key representation if possible. - * - * @param key a provider based key - * @return the byte encoding if one exists, key object otherwise. - */ - private static Object getRepresentation(Key key) - { - byte[] keyBytes = key.getEncoded(); - - if (keyBytes != null) - { - return keyBytes; - } - - return key; - } - - public JceGenericKey(AlgorithmIdentifier algorithmIdentifier, Key representation) - { - super(algorithmIdentifier, getRepresentation(representation)); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceSymmetricKeyUnwrapper.java b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceSymmetricKeyUnwrapper.java deleted file mode 100644 index b2c9cd3f..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceSymmetricKeyUnwrapper.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.bouncycastle.operator.jcajce; - -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.Provider; - -import javax.crypto.Cipher; -import javax.crypto.SecretKey; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.util.NamedJcaJceHelper; -import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.OperatorException; -import org.bouncycastle.operator.SymmetricKeyUnwrapper; - -public class JceSymmetricKeyUnwrapper - extends SymmetricKeyUnwrapper -{ - private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper()); - private SecretKey secretKey; - - public JceSymmetricKeyUnwrapper(AlgorithmIdentifier algorithmIdentifier, SecretKey secretKey) - { - super(algorithmIdentifier); - - this.secretKey = secretKey; - } - - public JceSymmetricKeyUnwrapper setProvider(Provider provider) - { - this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider)); - - return this; - } - - public JceSymmetricKeyUnwrapper setProvider(String providerName) - { - this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName)); - - return this; - } - - public GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedKey) - throws OperatorException - { - try - { - Cipher keyCipher = helper.createSymmetricWrapper(this.getAlgorithmIdentifier().getAlgorithm()); - - keyCipher.init(Cipher.UNWRAP_MODE, secretKey); - - return new JceGenericKey(encryptedKeyAlgorithm, keyCipher.unwrap(encryptedKey, helper.getKeyAlgorithmName(encryptedKeyAlgorithm.getAlgorithm()), Cipher.SECRET_KEY)); - } - catch (InvalidKeyException e) - { - throw new OperatorException("key invalid in message.", e); - } - catch (NoSuchAlgorithmException e) - { - throw new OperatorException("can't find algorithm.", e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceSymmetricKeyWrapper.java b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceSymmetricKeyWrapper.java deleted file mode 100644 index a8f712a5..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceSymmetricKeyWrapper.java +++ /dev/null @@ -1,154 +0,0 @@ -package org.bouncycastle.operator.jcajce; - -import java.security.GeneralSecurityException; -import java.security.Key; -import java.security.Provider; -import java.security.SecureRandom; - -import javax.crypto.Cipher; -import javax.crypto.SecretKey; - -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.util.NamedJcaJceHelper; -import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.OperatorException; -import org.bouncycastle.operator.SymmetricKeyWrapper; - -public class JceSymmetricKeyWrapper - extends SymmetricKeyWrapper -{ - private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper()); - private SecureRandom random; - private SecretKey wrappingKey; - - public JceSymmetricKeyWrapper(SecretKey wrappingKey) - { - super(determineKeyEncAlg(wrappingKey)); - - this.wrappingKey = wrappingKey; - } - - public JceSymmetricKeyWrapper setProvider(Provider provider) - { - this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider)); - - return this; - } - - public JceSymmetricKeyWrapper setProvider(String providerName) - { - this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName)); - - return this; - } - - public JceSymmetricKeyWrapper setSecureRandom(SecureRandom random) - { - this.random = random; - - return this; - } - - public byte[] generateWrappedKey(GenericKey encryptionKey) - throws OperatorException - { - Key contentEncryptionKeySpec = OperatorUtils.getJceKey(encryptionKey); - - Cipher keyEncryptionCipher = helper.createSymmetricWrapper(this.getAlgorithmIdentifier().getAlgorithm()); - - try - { - keyEncryptionCipher.init(Cipher.WRAP_MODE, wrappingKey, random); - - return keyEncryptionCipher.wrap(contentEncryptionKeySpec); - } - catch (GeneralSecurityException e) - { - throw new OperatorException("cannot wrap key: " + e.getMessage(), e); - } - } - - private static AlgorithmIdentifier determineKeyEncAlg(SecretKey key) - { - String algorithm = key.getAlgorithm(); - - if (algorithm.startsWith("DES")) - { - return new AlgorithmIdentifier(new ASN1ObjectIdentifier( - "1.2.840.113549.1.9.16.3.6"), DERNull.INSTANCE); - } - else if (algorithm.startsWith("RC2")) - { - return new AlgorithmIdentifier(new ASN1ObjectIdentifier( - "1.2.840.113549.1.9.16.3.7"), new ASN1Integer(58)); - } - else if (algorithm.startsWith("AES")) - { - int length = key.getEncoded().length * 8; - ASN1ObjectIdentifier wrapOid; - - if (length == 128) - { - wrapOid = NISTObjectIdentifiers.id_aes128_wrap; - } - else if (length == 192) - { - wrapOid = NISTObjectIdentifiers.id_aes192_wrap; - } - else if (length == 256) - { - wrapOid = NISTObjectIdentifiers.id_aes256_wrap; - } - else - { - throw new IllegalArgumentException("illegal keysize in AES"); - } - - return new AlgorithmIdentifier(wrapOid); // parameters absent - } - else if (algorithm.startsWith("SEED")) - { - // parameters absent - return new AlgorithmIdentifier( - KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap); - } - else if (algorithm.startsWith("Camellia")) - { - int length = key.getEncoded().length * 8; - ASN1ObjectIdentifier wrapOid; - - if (length == 128) - { - wrapOid = NTTObjectIdentifiers.id_camellia128_wrap; - } - else if (length == 192) - { - wrapOid = NTTObjectIdentifiers.id_camellia192_wrap; - } - else if (length == 256) - { - wrapOid = NTTObjectIdentifiers.id_camellia256_wrap; - } - else - { - throw new IllegalArgumentException( - "illegal keysize in Camellia"); - } - - return new AlgorithmIdentifier(wrapOid); // parameters must be - // absent - } - else - { - throw new IllegalArgumentException("unknown algorithm"); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java b/pkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java deleted file mode 100644 index 2e3ea666..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java +++ /dev/null @@ -1,433 +0,0 @@ -package 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 org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.bsi.BSIObjectIdentifiers; -import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; -import org.bouncycastle.asn1.eac.EACObjectIdentifiers; -import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.RSASSAPSSparams; -import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.jcajce.util.JcaJceHelper; -import org.bouncycastle.jcajce.util.JcaJceUtils; -import org.bouncycastle.operator.OperatorCreationException; - -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(); - - 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"); - 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"); - - oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA"); - oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA"); - oids.put(new ASN1ObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA"); - oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WITHECDSA"); - oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA"); - oids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256WITHECDSA"); - oids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384WITHECDSA"); - oids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512WITHECDSA"); - oids.put(OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA"); - oids.put(OIWObjectIdentifiers.dsaWithSHA1, "SHA1WITHDSA"); - oids.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WITHDSA"); - oids.put(NISTObjectIdentifiers.dsa_with_sha256, "SHA256WITHDSA"); - - 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"); - - 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; - } - - 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(JcaJceUtils.getDigestAlgName(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; - } - } - - 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); - - JcaJceUtils.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 JcaJceUtils.getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "WITHRSAANDMGF1"; - } - } - - if (oids.containsKey(sigAlgId.getAlgorithm())) - { - return (String)oids.get(sigAlgId.getAlgorithm()); - } - - return sigAlgId.getAlgorithm().getId(); - } - - 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 (NoSuchAlgorithmException e) - { - throw new OpCertificateException("cannot create certificate factory: " + 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(); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorUtils.java b/pkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorUtils.java deleted file mode 100644 index 6c41d960..00000000 --- a/pkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorUtils.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.bouncycastle.operator.jcajce; - -import java.security.Key; - -import javax.crypto.spec.SecretKeySpec; - -import org.bouncycastle.operator.GenericKey; - -class OperatorUtils -{ - static Key getJceKey(GenericKey key) - { - if (key.getRepresentation() instanceof Key) - { - return (Key)key.getRepresentation(); - } - - if (key.getRepresentation() instanceof byte[]) - { - return new SecretKeySpec((byte[])key.getRepresentation(), "ENC"); - } - - throw new IllegalArgumentException("unknown generic key type"); - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/MacDataGenerator.java b/pkix/src/main/java/org/bouncycastle/pkcs/MacDataGenerator.java deleted file mode 100644 index 7b9daa8b..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/MacDataGenerator.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.bouncycastle.pkcs; - - -import java.io.IOException; -import java.io.OutputStream; - -import org.bouncycastle.asn1.pkcs.MacData; -import org.bouncycastle.asn1.pkcs.PKCS12PBEParams; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.DigestInfo; -import org.bouncycastle.operator.MacCalculator; - -class MacDataGenerator -{ - private PKCS12MacCalculatorBuilder builder; - - MacDataGenerator(PKCS12MacCalculatorBuilder builder) - { - this.builder = builder; - } - - public MacData build(char[] password, byte[] data) - throws PKCSException - { - MacCalculator macCalculator; - - try - { - macCalculator = builder.build(password); - - OutputStream out = macCalculator.getOutputStream(); - - out.write(data); - - out.close(); - } - catch (Exception e) - { - throw new PKCSException("unable to process data: " + e.getMessage(), e); - } - - AlgorithmIdentifier algId = macCalculator.getAlgorithmIdentifier(); - - DigestInfo dInfo = new DigestInfo(builder.getDigestAlgorithmIdentifier(), macCalculator.getMac()); - PKCS12PBEParams params = PKCS12PBEParams.getInstance(algId.getParameters()); - - return new MacData(dInfo, params.getIV(), params.getIterations().intValue()); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/PKCS10CertificationRequest.java b/pkix/src/main/java/org/bouncycastle/pkcs/PKCS10CertificationRequest.java deleted file mode 100644 index 88e430d4..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/PKCS10CertificationRequest.java +++ /dev/null @@ -1,236 +0,0 @@ -package org.bouncycastle.pkcs; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.pkcs.Attribute; -import org.bouncycastle.asn1.pkcs.CertificationRequest; -import org.bouncycastle.asn1.pkcs.CertificationRequestInfo; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.operator.ContentVerifier; -import org.bouncycastle.operator.ContentVerifierProvider; - -/** - * Holding class for a PKCS#10 certification request. - */ -public class PKCS10CertificationRequest -{ - private static Attribute[] EMPTY_ARRAY = new Attribute[0]; - - private CertificationRequest certificationRequest; - - private static CertificationRequest parseBytes(byte[] encoding) - throws IOException - { - try - { - return CertificationRequest.getInstance(ASN1Primitive.fromByteArray(encoding)); - } - catch (ClassCastException e) - { - throw new PKCSIOException("malformed data: " + e.getMessage(), e); - } - catch (IllegalArgumentException e) - { - throw new PKCSIOException("malformed data: " + e.getMessage(), e); - } - } - - /** - * Create a PKCS10CertificationRequestHolder from an underlying ASN.1 structure. - * - * @param certificationRequest the underlying ASN.1 structure representing a request. - */ - public PKCS10CertificationRequest(CertificationRequest certificationRequest) - { - this.certificationRequest = certificationRequest; - } - - /** - * Create a PKCS10CertificationRequestHolder from the passed in bytes. - * - * @param encoded BER/DER encoding of the CertificationRequest structure. - * @throws IOException in the event of corrupted data, or an incorrect structure. - */ - public PKCS10CertificationRequest(byte[] encoded) - throws IOException - { - this(parseBytes(encoded)); - } - - /** - * Return the underlying ASN.1 structure for this request. - * - * @return a CertificateRequest object. - */ - public CertificationRequest toASN1Structure() - { - return certificationRequest; - } - - /** - * Return the subject on this request. - * - * @return the X500Name representing the request's subject. - */ - public X500Name getSubject() - { - return X500Name.getInstance(certificationRequest.getCertificationRequestInfo().getSubject()); - } - - /** - * Return the details of the signature algorithm used to create this request. - * - * @return the AlgorithmIdentifier describing the signature algorithm used to create this request. - */ - public AlgorithmIdentifier getSignatureAlgorithm() - { - return certificationRequest.getSignatureAlgorithm(); - } - - /** - * Return the bytes making up the signature associated with this request. - * - * @return the request signature bytes. - */ - public byte[] getSignature() - { - return certificationRequest.getSignature().getBytes(); - } - - /** - * Return the SubjectPublicKeyInfo describing the public key this request is carrying. - * - * @return the public key ASN.1 structure contained in the request. - */ - public SubjectPublicKeyInfo getSubjectPublicKeyInfo() - { - return certificationRequest.getCertificationRequestInfo().getSubjectPublicKeyInfo(); - } - - /** - * Return the attributes, if any associated with this request. - * - * @return an array of Attribute, zero length if none present. - */ - public Attribute[] getAttributes() - { - ASN1Set attrSet = certificationRequest.getCertificationRequestInfo().getAttributes(); - - if (attrSet == null) - { - return EMPTY_ARRAY; - } - - Attribute[] attrs = new Attribute[attrSet.size()]; - - for (int i = 0; i != attrSet.size(); i++) - { - attrs[i] = Attribute.getInstance(attrSet.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) - { - ASN1Set attrSet = certificationRequest.getCertificationRequestInfo().getAttributes(); - - if (attrSet == null) - { - return EMPTY_ARRAY; - } - - List list = new ArrayList(); - - for (int i = 0; i != attrSet.size(); i++) - { - Attribute attr = Attribute.getInstance(attrSet.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()]); - } - - public byte[] getEncoded() - throws IOException - { - return certificationRequest.getEncoded(); - } - - /** - * Validate the signature on the PKCS10 certification request 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 PKCSException if the signature cannot be processed or is inappropriate. - */ - public boolean isSignatureValid(ContentVerifierProvider verifierProvider) - throws PKCSException - { - CertificationRequestInfo requestInfo = certificationRequest.getCertificationRequestInfo(); - - ContentVerifier verifier; - - try - { - verifier = verifierProvider.get(certificationRequest.getSignatureAlgorithm()); - - OutputStream sOut = verifier.getOutputStream(); - - sOut.write(requestInfo.getEncoded(ASN1Encoding.DER)); - - sOut.close(); - } - catch (Exception e) - { - throw new PKCSException("unable to process signature: " + e.getMessage(), e); - } - - return verifier.verify(certificationRequest.getSignature().getBytes()); - } - - public boolean equals(Object o) - { - if (o == this) - { - return true; - } - - if (!(o instanceof PKCS10CertificationRequest)) - { - return false; - } - - PKCS10CertificationRequest other = (PKCS10CertificationRequest)o; - - return this.toASN1Structure().equals(other.toASN1Structure()); - } - - public int hashCode() - { - return this.toASN1Structure().hashCode(); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/PKCS10CertificationRequestBuilder.java b/pkix/src/main/java/org/bouncycastle/pkcs/PKCS10CertificationRequestBuilder.java deleted file mode 100644 index 851e6970..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/PKCS10CertificationRequestBuilder.java +++ /dev/null @@ -1,156 +0,0 @@ -package org.bouncycastle.pkcs; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.pkcs.Attribute; -import org.bouncycastle.asn1.pkcs.CertificationRequest; -import org.bouncycastle.asn1.pkcs.CertificationRequestInfo; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.operator.ContentSigner; - -/** - * A class for creating PKCS#10 Certification requests. - * <pre> - * CertificationRequest ::= SEQUENCE { - * certificationRequestInfo CertificationRequestInfo, - * signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }}, - * signature BIT STRING - * } - * - * CertificationRequestInfo ::= SEQUENCE { - * version INTEGER { v1(0) } (v1,...), - * subject Name, - * subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }}, - * attributes [0] Attributes{{ CRIAttributes }} - * } - * - * Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }} - * - * Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE { - * type ATTRIBUTE.&id({IOSet}), - * values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type}) - * } - * </pre> - */ -public class PKCS10CertificationRequestBuilder -{ - private SubjectPublicKeyInfo publicKeyInfo; - private X500Name subject; - private List attributes = new ArrayList(); - private boolean leaveOffEmpty = false; - - /** - * Basic constructor. - * - * @param subject the X.500 Name defining the certificate subject this request is for. - * @param publicKeyInfo the info structure for the public key to be associated with this subject. - */ - public PKCS10CertificationRequestBuilder(X500Name subject, SubjectPublicKeyInfo publicKeyInfo) - { - this.subject = subject; - this.publicKeyInfo = publicKeyInfo; - } - - /** - * Add an attribute to the certification request we are building. - * - * @param attrType the OID giving the type of the attribute. - * @param attrValue the ASN.1 structure that forms the value of the attribute. - * @return this builder object. - */ - public PKCS10CertificationRequestBuilder addAttribute(ASN1ObjectIdentifier attrType, ASN1Encodable attrValue) - { - attributes.add(new Attribute(attrType, new DERSet(attrValue))); - - return this; - } - - /** - * Add an attribute with multiple values to the certification request we are building. - * - * @param attrType the OID giving the type of the attribute. - * @param attrValues an array of ASN.1 structures that form the value of the attribute. - * @return this builder object. - */ - public PKCS10CertificationRequestBuilder addAttribute(ASN1ObjectIdentifier attrType, ASN1Encodable[] attrValues) - { - attributes.add(new Attribute(attrType, new DERSet(attrValues))); - - return this; - } - - /** - * The attributes field in PKCS10 should encoded to an empty tagged set if there are - * no attributes. Some CAs will reject requests with the attribute field present. - * - * @param leaveOffEmpty true if empty attributes should be left out of the encoding false otherwise. - * @return this builder object. - */ - public PKCS10CertificationRequestBuilder setLeaveOffEmptyAttributes(boolean leaveOffEmpty) - { - this.leaveOffEmpty = leaveOffEmpty; - - return this; - } - - /** - * Generate an PKCS#10 request based on the past in signer. - * - * @param signer the content signer to be used to generate the signature validating the certificate. - * @return a holder containing the resulting PKCS#10 certification request. - */ - public PKCS10CertificationRequest build( - ContentSigner signer) - { - CertificationRequestInfo info; - - if (attributes.isEmpty()) - { - if (leaveOffEmpty) - { - info = new CertificationRequestInfo(subject, publicKeyInfo, null); - } - else - { - info = new CertificationRequestInfo(subject, publicKeyInfo, new DERSet()); - } - } - else - { - ASN1EncodableVector v = new ASN1EncodableVector(); - - for (Iterator it = attributes.iterator(); it.hasNext();) - { - v.add(Attribute.getInstance(it.next())); - } - - info = new CertificationRequestInfo(subject, publicKeyInfo, new DERSet(v)); - } - - try - { - OutputStream sOut = signer.getOutputStream(); - - sOut.write(info.getEncoded(ASN1Encoding.DER)); - - sOut.close(); - - return new PKCS10CertificationRequest(new CertificationRequest(info, signer.getAlgorithmIdentifier(), new DERBitString(signer.getSignature()))); - } - catch (IOException e) - { - throw new IllegalStateException("cannot produce certification request signature"); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/PKCS12MacCalculatorBuilder.java b/pkix/src/main/java/org/bouncycastle/pkcs/PKCS12MacCalculatorBuilder.java deleted file mode 100644 index 7f159c6a..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/PKCS12MacCalculatorBuilder.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.bouncycastle.pkcs; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.operator.MacCalculator; -import org.bouncycastle.operator.OperatorCreationException; - -public interface PKCS12MacCalculatorBuilder -{ - MacCalculator build(char[] password) - throws OperatorCreationException; - - AlgorithmIdentifier getDigestAlgorithmIdentifier(); -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/PKCS12MacCalculatorBuilderProvider.java b/pkix/src/main/java/org/bouncycastle/pkcs/PKCS12MacCalculatorBuilderProvider.java deleted file mode 100644 index c262ac13..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/PKCS12MacCalculatorBuilderProvider.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.bouncycastle.pkcs; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -public interface PKCS12MacCalculatorBuilderProvider -{ - PKCS12MacCalculatorBuilder get(AlgorithmIdentifier algorithmIdentifier); -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/PKCS12PfxPdu.java b/pkix/src/main/java/org/bouncycastle/pkcs/PKCS12PfxPdu.java deleted file mode 100644 index e39025be..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/PKCS12PfxPdu.java +++ /dev/null @@ -1,161 +0,0 @@ -package org.bouncycastle.pkcs; - -import java.io.IOException; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.pkcs.ContentInfo; -import org.bouncycastle.asn1.pkcs.MacData; -import org.bouncycastle.asn1.pkcs.PKCS12PBEParams; -import org.bouncycastle.asn1.pkcs.Pfx; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cert.CertIOException; -import org.bouncycastle.util.Arrays; - -/** - * A holding class for the PKCS12 Pfx structure. - */ -public class PKCS12PfxPdu -{ - private Pfx pfx; - - private static Pfx parseBytes(byte[] pfxEncoding) - throws IOException - { - try - { - return Pfx.getInstance(ASN1Primitive.fromByteArray(pfxEncoding)); - } - catch (ClassCastException e) - { - throw new CertIOException("malformed data: " + e.getMessage(), e); - } - catch (IllegalArgumentException e) - { - throw new CertIOException("malformed data: " + e.getMessage(), e); - } - } - - public PKCS12PfxPdu(Pfx pfx) - { - this.pfx = pfx; - } - - public PKCS12PfxPdu(byte[] pfx) - throws IOException - { - this(parseBytes(pfx)); - } - - /** - * Return the content infos in the AuthenticatedSafe contained in this Pfx. - * - * @return an array of ContentInfo. - */ - public ContentInfo[] getContentInfos() - { - ASN1Sequence seq = ASN1Sequence.getInstance(ASN1OctetString.getInstance(this.pfx.getAuthSafe().getContent()).getOctets()); - ContentInfo[] content = new ContentInfo[seq.size()]; - - for (int i = 0; i != seq.size(); i++) - { - content[i] = ContentInfo.getInstance(seq.getObjectAt(i)); - } - - return content; - } - - /** - * Return whether or not there is MAC attached to this file. - * - * @return true if there is, false otherwise. - */ - public boolean hasMac() - { - return pfx.getMacData() != null; - } - - /** - * Return the algorithm identifier describing the MAC algorithm - * - * @return the AlgorithmIdentifier representing the MAC algorithm, null if none present. - */ - public AlgorithmIdentifier getMacAlgorithmID() - { - MacData md = pfx.getMacData(); - - if (md != null) - { - return md.getMac().getAlgorithmId(); - } - - return null; - } - - /** - * Verify the MacData attached to the PFX is consistent with what is expected. - * - * @param macCalcProviderBuilder provider builder for the calculator for the MAC - * @param password password to use - * @return true if mac data is valid, false otherwise. - * @throws PKCSException if there is a problem evaluating the MAC. - * @throws IllegalStateException if no MAC is actually present - */ - public boolean isMacValid(PKCS12MacCalculatorBuilderProvider macCalcProviderBuilder, char[] password) - throws PKCSException - { - if (hasMac()) - { - MacData pfxmData = pfx.getMacData(); - MacDataGenerator mdGen = new MacDataGenerator(macCalcProviderBuilder.get(new AlgorithmIdentifier(pfxmData.getMac().getAlgorithmId().getAlgorithm(), new PKCS12PBEParams(pfxmData.getSalt(), pfxmData.getIterationCount().intValue())))); - - try - { - MacData mData = mdGen.build( - password, - ASN1OctetString.getInstance(pfx.getAuthSafe().getContent()).getOctets()); - - return Arrays.constantTimeAreEqual(mData.getEncoded(), pfx.getMacData().getEncoded()); - } - catch (IOException e) - { - throw new PKCSException("unable to process AuthSafe: " + e.getMessage()); - } - } - - throw new IllegalStateException("no MAC present on PFX"); - } - - /** - * Return the underlying ASN.1 object. - * - * @return a Pfx object. - */ - public Pfx toASN1Structure() - { - return pfx; - } - - public byte[] getEncoded() - throws IOException - { - return toASN1Structure().getEncoded(); - } - - /** - * Return a Pfx with the outer wrapper encoded as asked for. For example, Pfx is a usually - * a BER encoded object, to get one with DefiniteLength encoding use: - * <pre> - * getEncoded(ASN1Encoding.DL) - * </pre> - * @param encoding encoding style (ASN1Encoding.DER, ASN1Encoding.DL, ASN1Encoding.BER) - * @return a byte array containing the encoded object. - * @throws IOException - */ - public byte[] getEncoded(String encoding) - throws IOException - { - return toASN1Structure().getEncoded(encoding); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/PKCS12PfxPduBuilder.java b/pkix/src/main/java/org/bouncycastle/pkcs/PKCS12PfxPduBuilder.java deleted file mode 100644 index 563ca048..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/PKCS12PfxPduBuilder.java +++ /dev/null @@ -1,179 +0,0 @@ -package org.bouncycastle.pkcs; - -import java.io.IOException; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.DLSequence; -import org.bouncycastle.asn1.pkcs.AuthenticatedSafe; -import org.bouncycastle.asn1.pkcs.ContentInfo; -import org.bouncycastle.asn1.pkcs.MacData; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.Pfx; -import org.bouncycastle.cms.CMSEncryptedDataGenerator; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.CMSProcessableByteArray; -import org.bouncycastle.operator.OutputEncryptor; - -/** - * A builder for the PKCS#12 Pfx key and certificate store. - * <p> - * For example: you can build a basic key store for the user owning privKey as follows: - * </p> - * <pre> - * X509Certificate[] chain = .... - * PublicKey pubKey = .... - * PrivateKey privKey = .... - * JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils(); - * - * PKCS12SafeBagBuilder taCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[2]); - * - * taCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Bouncy Primary Certificate")); - * - * PKCS12SafeBagBuilder caCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[1]); - * - * caCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Bouncy Intermediate Certificate")); - * - * PKCS12SafeBagBuilder eeCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[0]); - * - * eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Eric's Key")); - * eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, extUtils.createSubjectKeyIdentifier(pubKey)); - * - * PKCS12SafeBagBuilder keyBagBuilder = new JcaPKCS12SafeBagBuilder(privKey, new BcPKCS12PBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, new CBCBlockCipher(new DESedeEngine())).build(passwd)); - * - * keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Eric's Key")); - * keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, extUtils.createSubjectKeyIdentifier(pubKey)); - * - * // - * // construct the actual key store - * // - * PKCS12PfxPduBuilder pfxPduBuilder = new PKCS12PfxPduBuilder(); - * - * PKCS12SafeBag[] certs = new PKCS12SafeBag[3]; - * - * certs[0] = eeCertBagBuilder.build(); - * certs[1] = caCertBagBuilder.build(); - * certs[2] = taCertBagBuilder.build(); - * - * pfxPduBuilder.addEncryptedData(new BcPKCS12PBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC, new CBCBlockCipher(new RC2Engine())).build(passwd), certs); - * - * pfxPduBuilder.addData(keyBagBuilder.build()); - * - * PKCS12PfxPdu pfx = pfxPduBuilder.build(new BcPKCS12MacCalculatorBuilder(), passwd); - * </pre> - * - */ -public class PKCS12PfxPduBuilder -{ - private ASN1EncodableVector dataVector = new ASN1EncodableVector(); - - /** - * Add a SafeBag that is to be included as is. - * - * @param data the SafeBag to add. - * @return this builder. - * @throws IOException - */ - public PKCS12PfxPduBuilder addData(PKCS12SafeBag data) - throws IOException - { - dataVector.add(new ContentInfo(PKCSObjectIdentifiers.data, new DEROctetString(new DLSequence(data.toASN1Structure()).getEncoded()))); - - return this; - } - - /** - * Add a SafeBag that is to be wrapped in a EncryptedData object. - * - * @param dataEncryptor the encryptor to use for encoding the data. - * @param data the SafeBag to include. - * @return this builder. - * @throws IOException if a issue occurs processing the data. - */ - public PKCS12PfxPduBuilder addEncryptedData(OutputEncryptor dataEncryptor, PKCS12SafeBag data) - throws IOException - { - return addEncryptedData(dataEncryptor, new DERSequence(data.toASN1Structure())); - } - - /** - * Add a set of SafeBags that are to be wrapped in a EncryptedData object. - * - * @param dataEncryptor the encryptor to use for encoding the data. - * @param data the SafeBags to include. - * @return this builder. - * @throws IOException if a issue occurs processing the data. - */ - public PKCS12PfxPduBuilder addEncryptedData(OutputEncryptor dataEncryptor, PKCS12SafeBag[] data) - throws IOException - { - ASN1EncodableVector v = new ASN1EncodableVector(); - - for (int i = 0; i != data.length; i++) - { - v.add(data[i].toASN1Structure()); - } - - return addEncryptedData(dataEncryptor, new DLSequence(v)); - } - - private PKCS12PfxPduBuilder addEncryptedData(OutputEncryptor dataEncryptor, ASN1Sequence data) - throws IOException - { - CMSEncryptedDataGenerator envGen = new CMSEncryptedDataGenerator(); - - try - { - dataVector.add(envGen.generate(new CMSProcessableByteArray(data.getEncoded()), dataEncryptor).toASN1Structure()); - } - catch (CMSException e) - { - throw new PKCSIOException(e.getMessage(), e.getCause()); - } - - return this; - } - - /** - * Build the Pfx structure, protecting it with a MAC calculated against the passed in password. - * - * @param macCalcBuilder a builder for a PKCS12 mac calculator. - * @param password the password to use. - * @return a Pfx object. - * @throws PKCSException on a encoding or processing error. - */ - public PKCS12PfxPdu build(PKCS12MacCalculatorBuilder macCalcBuilder, char[] password) - throws PKCSException - { - AuthenticatedSafe auth = AuthenticatedSafe.getInstance(new DLSequence(dataVector)); - byte[] encAuth; - - try - { - encAuth = auth.getEncoded(); - } - catch (IOException e) - { - throw new PKCSException("unable to encode AuthenticatedSafe: " + e.getMessage(), e); - } - - ContentInfo mainInfo = new ContentInfo(PKCSObjectIdentifiers.data, new DEROctetString(encAuth)); - MacData mData = null; - - if (macCalcBuilder != null) - { - MacDataGenerator mdGen = new MacDataGenerator(macCalcBuilder); - - mData = mdGen.build(password, encAuth); - } - - // - // output the Pfx - // - Pfx pfx = new Pfx(mainInfo, mData); - - return new PKCS12PfxPdu(pfx); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/PKCS12SafeBag.java b/pkix/src/main/java/org/bouncycastle/pkcs/PKCS12SafeBag.java deleted file mode 100644 index 6f053bae..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/PKCS12SafeBag.java +++ /dev/null @@ -1,93 +0,0 @@ -package org.bouncycastle.pkcs; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.pkcs.Attribute; -import org.bouncycastle.asn1.pkcs.CRLBag; -import org.bouncycastle.asn1.pkcs.CertBag; -import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.asn1.pkcs.SafeBag; -import org.bouncycastle.asn1.x509.Certificate; -import org.bouncycastle.asn1.x509.CertificateList; -import org.bouncycastle.cert.X509CRLHolder; -import org.bouncycastle.cert.X509CertificateHolder; - -public class PKCS12SafeBag -{ - public static final ASN1ObjectIdentifier friendlyNameAttribute = PKCSObjectIdentifiers.pkcs_9_at_friendlyName; - public static final ASN1ObjectIdentifier localKeyIdAttribute = PKCSObjectIdentifiers.pkcs_9_at_localKeyId; - - private SafeBag safeBag; - - public PKCS12SafeBag(SafeBag safeBag) - { - this.safeBag = safeBag; - } - - /** - * Return the underlying ASN.1 structure for this safe bag. - * - * @return a SafeBag - */ - public SafeBag toASN1Structure() - { - return safeBag; - } - - /** - * Return the BagId giving the type of content in the bag. - * - * @return the bagId - */ - public ASN1ObjectIdentifier getType() - { - return safeBag.getBagId(); - } - - public Attribute[] getAttributes() - { - ASN1Set attrs = safeBag.getBagAttributes(); - - if (attrs == null) - { - return null; - } - - Attribute[] attributes = new Attribute[attrs.size()]; - for (int i = 0; i != attrs.size(); i++) - { - attributes[i] = Attribute.getInstance(attrs.getObjectAt(i)); - } - - return attributes; - } - - public Object getBagValue() - { - if (getType().equals(PKCSObjectIdentifiers.pkcs8ShroudedKeyBag)) - { - return new PKCS8EncryptedPrivateKeyInfo(EncryptedPrivateKeyInfo.getInstance(safeBag.getBagValue())); - } - if (getType().equals(PKCSObjectIdentifiers.certBag)) - { - CertBag certBag = CertBag.getInstance(safeBag.getBagValue()); - - return new X509CertificateHolder(Certificate.getInstance(ASN1OctetString.getInstance(certBag.getCertValue()).getOctets())); - } - if (getType().equals(PKCSObjectIdentifiers.keyBag)) - { - return PrivateKeyInfo.getInstance(safeBag.getBagValue()); - } - if (getType().equals(PKCSObjectIdentifiers.crlBag)) - { - CRLBag crlBag = CRLBag.getInstance(safeBag.getBagValue()); - - return new X509CRLHolder(CertificateList.getInstance(ASN1OctetString.getInstance(crlBag.getCRLValue()).getOctets())); - } - - return safeBag.getBagValue(); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/PKCS12SafeBagBuilder.java b/pkix/src/main/java/org/bouncycastle/pkcs/PKCS12SafeBagBuilder.java deleted file mode 100644 index 1e3a262d..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/PKCS12SafeBagBuilder.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.bouncycastle.pkcs; - -import java.io.IOException; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.pkcs.Attribute; -import org.bouncycastle.asn1.pkcs.CertBag; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.asn1.pkcs.SafeBag; -import org.bouncycastle.asn1.x509.Certificate; -import org.bouncycastle.asn1.x509.CertificateList; -import org.bouncycastle.cert.X509CRLHolder; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.operator.OutputEncryptor; - -public class PKCS12SafeBagBuilder -{ - private ASN1ObjectIdentifier bagType; - private ASN1Encodable bagValue; - private ASN1EncodableVector bagAttrs = new ASN1EncodableVector(); - - public PKCS12SafeBagBuilder(PrivateKeyInfo privateKeyInfo, OutputEncryptor encryptor) - { - this.bagType = PKCSObjectIdentifiers.pkcs8ShroudedKeyBag; - this.bagValue = new PKCS8EncryptedPrivateKeyInfoBuilder(privateKeyInfo).build(encryptor).toASN1Structure(); - } - - public PKCS12SafeBagBuilder(PrivateKeyInfo privateKeyInfo) - { - this.bagType = PKCSObjectIdentifiers.keyBag; - this.bagValue = privateKeyInfo; - } - - public PKCS12SafeBagBuilder(X509CertificateHolder certificate) - throws IOException - { - this(certificate.toASN1Structure()); - } - - public PKCS12SafeBagBuilder(X509CRLHolder crl) - throws IOException - { - this(crl.toASN1Structure()); - } - - public PKCS12SafeBagBuilder(Certificate certificate) - throws IOException - { - this.bagType = PKCSObjectIdentifiers.certBag; - this.bagValue = new CertBag(PKCSObjectIdentifiers.x509Certificate, new DEROctetString(certificate.getEncoded())); - } - - public PKCS12SafeBagBuilder(CertificateList crl) - throws IOException - { - this.bagType = PKCSObjectIdentifiers.crlBag; - this.bagValue = new CertBag(PKCSObjectIdentifiers.x509Crl, new DEROctetString(crl.getEncoded())); - } - - public PKCS12SafeBagBuilder addBagAttribute(ASN1ObjectIdentifier attrType, ASN1Encodable attrValue) - { - bagAttrs.add(new Attribute(attrType, new DERSet(attrValue))); - - return this; - } - - public PKCS12SafeBag build() - { - return new PKCS12SafeBag(new SafeBag(bagType, bagValue, new DERSet(bagAttrs))); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/PKCS12SafeBagFactory.java b/pkix/src/main/java/org/bouncycastle/pkcs/PKCS12SafeBagFactory.java deleted file mode 100644 index 27738555..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/PKCS12SafeBagFactory.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.bouncycastle.pkcs; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.pkcs.ContentInfo; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.SafeBag; -import org.bouncycastle.cms.CMSEncryptedData; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.operator.InputDecryptorProvider; - -public class PKCS12SafeBagFactory -{ - private ASN1Sequence safeBagSeq; - - public PKCS12SafeBagFactory(ContentInfo info) - { - if (info.getContentType().equals(PKCSObjectIdentifiers.encryptedData)) - { - throw new IllegalArgumentException("encryptedData requires constructor with decryptor."); - } - - this.safeBagSeq = ASN1Sequence.getInstance(ASN1OctetString.getInstance(info.getContent()).getOctets()); - } - - public PKCS12SafeBagFactory(ContentInfo info, InputDecryptorProvider inputDecryptorProvider) - throws PKCSException - { - if (info.getContentType().equals(PKCSObjectIdentifiers.encryptedData)) - { - CMSEncryptedData encData = new CMSEncryptedData(org.bouncycastle.asn1.cms.ContentInfo.getInstance(info)); - - try - { - this.safeBagSeq = ASN1Sequence.getInstance(encData.getContent(inputDecryptorProvider)); - } - catch (CMSException e) - { - throw new PKCSException("unable to extract data: " + e.getMessage(), e); - } - return; - } - - throw new IllegalArgumentException("encryptedData requires constructor with decryptor."); - } - - public PKCS12SafeBag[] getSafeBags() - { - PKCS12SafeBag[] safeBags = new PKCS12SafeBag[safeBagSeq.size()]; - - for (int i = 0; i != safeBagSeq.size(); i++) - { - safeBags[i] = new PKCS12SafeBag(SafeBag.getInstance(safeBagSeq.getObjectAt(i))); - } - - return safeBags; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/PKCS8EncryptedPrivateKeyInfo.java b/pkix/src/main/java/org/bouncycastle/pkcs/PKCS8EncryptedPrivateKeyInfo.java deleted file mode 100644 index 37f1ed84..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/PKCS8EncryptedPrivateKeyInfo.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.bouncycastle.pkcs; - -import java.io.ByteArrayInputStream; -import java.io.IOException; - -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.cert.CertIOException; -import org.bouncycastle.operator.InputDecryptor; -import org.bouncycastle.operator.InputDecryptorProvider; -import org.bouncycastle.util.io.Streams; - -/** - * Holding class for a PKCS#8 EncryptedPrivateKeyInfo structure. - */ -public class PKCS8EncryptedPrivateKeyInfo -{ - private EncryptedPrivateKeyInfo encryptedPrivateKeyInfo; - - private static EncryptedPrivateKeyInfo parseBytes(byte[] pkcs8Encoding) - throws IOException - { - try - { - return EncryptedPrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(pkcs8Encoding)); - } - catch (ClassCastException e) - { - throw new CertIOException("malformed data: " + e.getMessage(), e); - } - catch (IllegalArgumentException e) - { - throw new CertIOException("malformed data: " + e.getMessage(), e); - } - } - - public PKCS8EncryptedPrivateKeyInfo(EncryptedPrivateKeyInfo encryptedPrivateKeyInfo) - { - this.encryptedPrivateKeyInfo = encryptedPrivateKeyInfo; - } - - public PKCS8EncryptedPrivateKeyInfo(byte[] encryptedPrivateKeyInfo) - throws IOException - { - this(parseBytes(encryptedPrivateKeyInfo)); - } - - public EncryptedPrivateKeyInfo toASN1Structure() - { - return encryptedPrivateKeyInfo; - } - - public byte[] getEncoded() - throws IOException - { - return encryptedPrivateKeyInfo.getEncoded(); - } - - public PrivateKeyInfo decryptPrivateKeyInfo(InputDecryptorProvider inputDecryptorProvider) - throws PKCSException - { - try - { - InputDecryptor decrytor = inputDecryptorProvider.get(encryptedPrivateKeyInfo.getEncryptionAlgorithm()); - - ByteArrayInputStream encIn = new ByteArrayInputStream(encryptedPrivateKeyInfo.getEncryptedData()); - - return PrivateKeyInfo.getInstance(Streams.readAll(decrytor.getInputStream(encIn))); - } - catch (Exception e) - { - throw new PKCSException("unable to read encrypted data: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/PKCS8EncryptedPrivateKeyInfoBuilder.java b/pkix/src/main/java/org/bouncycastle/pkcs/PKCS8EncryptedPrivateKeyInfoBuilder.java deleted file mode 100644 index 653aa571..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/PKCS8EncryptedPrivateKeyInfoBuilder.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.bouncycastle.pkcs; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.operator.OutputEncryptor; - -/** - * A class for creating EncryptedPrivateKeyInfo structures. - * <pre> - * EncryptedPrivateKeyInfo ::= SEQUENCE { - * encryptionAlgorithm AlgorithmIdentifier {{KeyEncryptionAlgorithms}}, - * encryptedData EncryptedData - * } - * - * EncryptedData ::= OCTET STRING - * - * KeyEncryptionAlgorithms ALGORITHM-IDENTIFIER ::= { - * ... -- For local profiles - * } - * </pre> - */ -public class PKCS8EncryptedPrivateKeyInfoBuilder -{ - private PrivateKeyInfo privateKeyInfo; - - public PKCS8EncryptedPrivateKeyInfoBuilder(PrivateKeyInfo privateKeyInfo) - { - this.privateKeyInfo = privateKeyInfo; - } - - public PKCS8EncryptedPrivateKeyInfo build( - OutputEncryptor encryptor) - { - try - { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - OutputStream cOut = encryptor.getOutputStream(bOut); - - cOut.write(privateKeyInfo.getEncoded()); - - cOut.close(); - - return new PKCS8EncryptedPrivateKeyInfo(new EncryptedPrivateKeyInfo(encryptor.getAlgorithmIdentifier(), bOut.toByteArray())); - } - catch (IOException e) - { - throw new IllegalStateException("cannot encode privateKeyInfo"); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/PKCSException.java b/pkix/src/main/java/org/bouncycastle/pkcs/PKCSException.java deleted file mode 100644 index 8ee6f6fc..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/PKCSException.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.bouncycastle.pkcs; - -/** - * General checked Exception thrown in the cert package and its sub-packages. - */ -public class PKCSException - extends Exception -{ - private Throwable cause; - - public PKCSException(String msg, Throwable cause) - { - super(msg); - - this.cause = cause; - } - - public PKCSException(String msg) - { - super(msg); - } - - public Throwable getCause() - { - return cause; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/PKCSIOException.java b/pkix/src/main/java/org/bouncycastle/pkcs/PKCSIOException.java deleted file mode 100644 index c34f739a..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/PKCSIOException.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.bouncycastle.pkcs; - -import java.io.IOException; - -/** - * General IOException thrown in the cert package and its sub-packages. - */ -public class PKCSIOException - extends IOException -{ - private Throwable cause; - - public PKCSIOException(String msg, Throwable cause) - { - super(msg); - - this.cause = cause; - } - - public PKCSIOException(String msg) - { - super(msg); - } - - public Throwable getCause() - { - return cause; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS10CertificationRequest.java b/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS10CertificationRequest.java deleted file mode 100644 index 99c337c9..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS10CertificationRequest.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.bouncycastle.pkcs.bc; - -import java.io.IOException; - -import org.bouncycastle.asn1.pkcs.CertificationRequest; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.util.PublicKeyFactory; -import org.bouncycastle.pkcs.PKCS10CertificationRequest; -import org.bouncycastle.pkcs.PKCSException; - -public class BcPKCS10CertificationRequest - extends PKCS10CertificationRequest -{ - public BcPKCS10CertificationRequest(CertificationRequest certificationRequest) - { - super(certificationRequest); - } - - public BcPKCS10CertificationRequest(byte[] encoding) - throws IOException - { - super(encoding); - } - - public BcPKCS10CertificationRequest(PKCS10CertificationRequest requestHolder) - { - super(requestHolder.toASN1Structure()); - } - - public AsymmetricKeyParameter getPublicKey() - throws PKCSException - { - try - { - return PublicKeyFactory.createKey(this.getSubjectPublicKeyInfo()); - } - catch (IOException e) - { - throw new PKCSException("error extracting key encoding: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS10CertificationRequestBuilder.java b/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS10CertificationRequestBuilder.java deleted file mode 100644 index 04b0fc60..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS10CertificationRequestBuilder.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.bouncycastle.pkcs.bc; - -import java.io.IOException; - -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory; -import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder; - -/** - * Extension of the PKCS#10 builder to support AsymmetricKey objects. - */ -public class BcPKCS10CertificationRequestBuilder - extends PKCS10CertificationRequestBuilder -{ - /** - * Create a PKCS#10 builder for the passed in subject and JCA public key. - * - * @param subject an X500Name containing the subject associated with the request we are building. - * @param publicKey a JCA public key that is to be associated with the request we are building. - * @throws IOException if there is a problem encoding the public key. - */ - public BcPKCS10CertificationRequestBuilder(X500Name subject, AsymmetricKeyParameter publicKey) - throws IOException - { - super(subject, SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKey)); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS12MacCalculatorBuilder.java b/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS12MacCalculatorBuilder.java deleted file mode 100644 index d8c38b59..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS12MacCalculatorBuilder.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.bouncycastle.pkcs.bc; - -import java.security.SecureRandom; - -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCS12PBEParams; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.ExtendedDigest; -import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.operator.MacCalculator; -import org.bouncycastle.pkcs.PKCS12MacCalculatorBuilder; - -public class BcPKCS12MacCalculatorBuilder - implements PKCS12MacCalculatorBuilder -{ - private ExtendedDigest digest; - private AlgorithmIdentifier algorithmIdentifier; - - private SecureRandom random; - private int saltLength; - private int iterationCount = 1024; - - public BcPKCS12MacCalculatorBuilder() - { - this(new SHA1Digest(), new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE)); - } - - public BcPKCS12MacCalculatorBuilder(ExtendedDigest digest, AlgorithmIdentifier algorithmIdentifier) - { - this.digest = digest; - this.algorithmIdentifier = algorithmIdentifier; - this.saltLength = digest.getDigestSize(); - } - - public AlgorithmIdentifier getDigestAlgorithmIdentifier() - { - return algorithmIdentifier; - } - - public MacCalculator build(final char[] password) - { - if (random == null) - { - random = new SecureRandom(); - } - - byte[] salt = new byte[saltLength]; - - random.nextBytes(salt); - - return PKCS12PBEUtils.createMacCalculator(algorithmIdentifier.getAlgorithm(), digest, new PKCS12PBEParams(salt, iterationCount), password); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS12MacCalculatorBuilderProvider.java b/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS12MacCalculatorBuilderProvider.java deleted file mode 100644 index d6f92306..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS12MacCalculatorBuilderProvider.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.bouncycastle.pkcs.bc; - -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.pkcs.PKCS12PBEParams; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.operator.MacCalculator; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.operator.bc.BcDigestProvider; -import org.bouncycastle.pkcs.PKCS12MacCalculatorBuilder; -import org.bouncycastle.pkcs.PKCS12MacCalculatorBuilderProvider; - -public class BcPKCS12MacCalculatorBuilderProvider - implements PKCS12MacCalculatorBuilderProvider -{ - private BcDigestProvider digestProvider; - - public BcPKCS12MacCalculatorBuilderProvider(BcDigestProvider digestProvider) - { - this.digestProvider = digestProvider; - } - - public PKCS12MacCalculatorBuilder get(final AlgorithmIdentifier algorithmIdentifier) - { - return new PKCS12MacCalculatorBuilder() - { - public MacCalculator build(final char[] password) - throws OperatorCreationException - { - PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algorithmIdentifier.getParameters()); - - return PKCS12PBEUtils.createMacCalculator(algorithmIdentifier.getAlgorithm(), digestProvider.get(algorithmIdentifier), pbeParams, password); - } - - public AlgorithmIdentifier getDigestAlgorithmIdentifier() - { - return new AlgorithmIdentifier(algorithmIdentifier.getAlgorithm(), DERNull.INSTANCE); - } - }; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS12PBEInputDecryptorProviderBuilder.java b/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS12PBEInputDecryptorProviderBuilder.java deleted file mode 100644 index e578fd53..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS12PBEInputDecryptorProviderBuilder.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.bouncycastle.pkcs.bc; - -import java.io.InputStream; - -import org.bouncycastle.asn1.pkcs.PKCS12PBEParams; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.ExtendedDigest; -import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator; -import org.bouncycastle.crypto.io.CipherInputStream; -import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.InputDecryptor; -import org.bouncycastle.operator.InputDecryptorProvider; - -public class BcPKCS12PBEInputDecryptorProviderBuilder -{ - private ExtendedDigest digest; - - public BcPKCS12PBEInputDecryptorProviderBuilder() - { - this(new SHA1Digest()); - } - - public BcPKCS12PBEInputDecryptorProviderBuilder(ExtendedDigest digest) - { - this.digest = digest; - } - - public InputDecryptorProvider build(final char[] password) - { - return new InputDecryptorProvider() - { - public InputDecryptor get(final AlgorithmIdentifier algorithmIdentifier) - { - final PaddedBufferedBlockCipher engine = PKCS12PBEUtils.getEngine(algorithmIdentifier.getAlgorithm()); - - PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algorithmIdentifier.getParameters()); - - CipherParameters params = PKCS12PBEUtils.createCipherParameters(algorithmIdentifier.getAlgorithm(), digest, engine.getBlockSize(), pbeParams, password); - - engine.init(false, params); - - return new InputDecryptor() - { - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return algorithmIdentifier; - } - - public InputStream getInputStream(InputStream input) - { - return new CipherInputStream(input, engine); - } - - public GenericKey getKey() - { - return new GenericKey(PKCS12ParametersGenerator.PKCS12PasswordToBytes(password)); - } - }; - } - }; - - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS12PBEOutputEncryptorBuilder.java b/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS12PBEOutputEncryptorBuilder.java deleted file mode 100644 index 414c604f..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS12PBEOutputEncryptorBuilder.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.bouncycastle.pkcs.bc; - -import java.io.OutputStream; -import java.security.SecureRandom; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.pkcs.PKCS12PBEParams; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.BlockCipher; -import org.bouncycastle.crypto.BufferedBlockCipher; -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.ExtendedDigest; -import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator; -import org.bouncycastle.crypto.io.CipherOutputStream; -import org.bouncycastle.crypto.paddings.PKCS7Padding; -import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.OutputEncryptor; - -public class BcPKCS12PBEOutputEncryptorBuilder -{ - private ExtendedDigest digest; - - private BufferedBlockCipher engine; - private ASN1ObjectIdentifier algorithm; - private SecureRandom random; - - public BcPKCS12PBEOutputEncryptorBuilder(ASN1ObjectIdentifier algorithm, BlockCipher engine) - { - this(algorithm, engine, new SHA1Digest()); - } - - public BcPKCS12PBEOutputEncryptorBuilder(ASN1ObjectIdentifier algorithm, BlockCipher engine, ExtendedDigest pbeDigest) - { - this.algorithm = algorithm; - this.engine = new PaddedBufferedBlockCipher(engine, new PKCS7Padding()); - this.digest = pbeDigest; - } - - public OutputEncryptor build(final char[] password) - { - if (random == null) - { - random = new SecureRandom(); - } - - final byte[] salt = new byte[20]; - final int iterationCount = 1024; - - random.nextBytes(salt); - - final PKCS12PBEParams pbeParams = new PKCS12PBEParams(salt, iterationCount); - - CipherParameters params = PKCS12PBEUtils.createCipherParameters(algorithm, digest, engine.getBlockSize(), pbeParams, password); - - engine.init(true, params); - - return new OutputEncryptor() - { - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return new AlgorithmIdentifier(algorithm, pbeParams); - } - - public OutputStream getOutputStream(OutputStream out) - { - return new CipherOutputStream(out, engine); - } - - public GenericKey getKey() - { - return new GenericKey(new AlgorithmIdentifier(algorithm, pbeParams), PKCS12ParametersGenerator.PKCS12PasswordToBytes(password)); - } - }; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/bc/PKCS12PBEUtils.java b/pkix/src/main/java/org/bouncycastle/pkcs/bc/PKCS12PBEUtils.java deleted file mode 100644 index 2edce234..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/bc/PKCS12PBEUtils.java +++ /dev/null @@ -1,153 +0,0 @@ -package org.bouncycastle.pkcs.bc; - -import java.io.OutputStream; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.pkcs.PKCS12PBEParams; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.BlockCipher; -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.ExtendedDigest; -import org.bouncycastle.crypto.engines.DESedeEngine; -import org.bouncycastle.crypto.engines.RC2Engine; -import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator; -import org.bouncycastle.crypto.io.MacOutputStream; -import org.bouncycastle.crypto.macs.HMac; -import org.bouncycastle.crypto.modes.CBCBlockCipher; -import org.bouncycastle.crypto.paddings.PKCS7Padding; -import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; -import org.bouncycastle.crypto.params.DESedeParameters; -import org.bouncycastle.crypto.params.KeyParameter; -import org.bouncycastle.crypto.params.ParametersWithIV; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.MacCalculator; -import org.bouncycastle.util.Integers; - -class PKCS12PBEUtils -{ - private static Map keySizes = new HashMap(); - private static Set noIvAlgs = new HashSet(); - private static Set desAlgs = new HashSet(); - - static - { - keySizes.put(PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, Integers.valueOf(128)); - keySizes.put(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4, Integers.valueOf(40)); - keySizes.put(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, Integers.valueOf(192)); - keySizes.put(PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC, Integers.valueOf(128)); - keySizes.put(PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC, Integers.valueOf(128)); - keySizes.put(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC, Integers.valueOf(40)); - - noIvAlgs.add(PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4); - noIvAlgs.add(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4); - - desAlgs.add(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC); - desAlgs.add(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC); - } - - static int getKeySize(ASN1ObjectIdentifier algorithm) - { - return ((Integer)keySizes.get(algorithm)).intValue(); - } - - static boolean hasNoIv(ASN1ObjectIdentifier algorithm) - { - return noIvAlgs.contains(algorithm); - } - - static boolean isDesAlg(ASN1ObjectIdentifier algorithm) - { - return desAlgs.contains(algorithm); - } - - static PaddedBufferedBlockCipher getEngine(ASN1ObjectIdentifier algorithm) - { - BlockCipher engine; - - if (algorithm.equals(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC) - || algorithm.equals(PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC)) - { - engine = new DESedeEngine(); - } - else if (algorithm.equals(PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC) - || algorithm.equals(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC)) - { - engine = new RC2Engine(); - } - else - { - throw new IllegalStateException("unknown algorithm"); - } - - return new PaddedBufferedBlockCipher(new CBCBlockCipher(engine), new PKCS7Padding()); - } - - static MacCalculator createMacCalculator(final ASN1ObjectIdentifier digestAlgorithm, ExtendedDigest digest, final PKCS12PBEParams pbeParams, final char[] password) - { - PKCS12ParametersGenerator pGen = new PKCS12ParametersGenerator(digest); - - pGen.init(PKCS12ParametersGenerator.PKCS12PasswordToBytes(password), pbeParams.getIV(), pbeParams.getIterations().intValue()); - - final KeyParameter keyParam = (KeyParameter)pGen.generateDerivedMacParameters(digest.getDigestSize() * 8); - - final HMac hMac = new HMac(digest); - - hMac.init(keyParam); - - return new MacCalculator() - { - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return new AlgorithmIdentifier(digestAlgorithm, pbeParams); - } - - public OutputStream getOutputStream() - { - return new MacOutputStream(hMac); - } - - public byte[] getMac() - { - byte[] res = new byte[hMac.getMacSize()]; - - hMac.doFinal(res, 0); - - return res; - } - - public GenericKey getKey() - { - return new GenericKey(getAlgorithmIdentifier(), PKCS12ParametersGenerator.PKCS12PasswordToBytes(password)); - } - }; - } - - static CipherParameters createCipherParameters(ASN1ObjectIdentifier algorithm, ExtendedDigest digest, int blockSize, PKCS12PBEParams pbeParams, char[] password) - { - PKCS12ParametersGenerator pGen = new PKCS12ParametersGenerator(digest); - - pGen.init(PKCS12ParametersGenerator.PKCS12PasswordToBytes(password), pbeParams.getIV(), pbeParams.getIterations().intValue()); - - CipherParameters params; - - if (PKCS12PBEUtils.hasNoIv(algorithm)) - { - params = pGen.generateDerivedParameters(PKCS12PBEUtils.getKeySize(algorithm)); - } - else - { - params = pGen.generateDerivedParameters(PKCS12PBEUtils.getKeySize(algorithm), blockSize * 8); - - if (PKCS12PBEUtils.isDesAlg(algorithm)) - { - DESedeParameters.setOddParity(((KeyParameter)((ParametersWithIV)params).getParameters()).getKey()); - } - } - return params; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcaPKCS10CertificationRequest.java b/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcaPKCS10CertificationRequest.java deleted file mode 100644 index db57d0ff..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcaPKCS10CertificationRequest.java +++ /dev/null @@ -1,115 +0,0 @@ -package org.bouncycastle.pkcs.jcajce; - -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.Provider; -import java.security.PublicKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.X509EncodedKeySpec; -import java.util.Hashtable; - -import org.bouncycastle.asn1.pkcs.CertificationRequest; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; -import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.util.JcaJceHelper; -import org.bouncycastle.jcajce.util.NamedJcaJceHelper; -import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; -import org.bouncycastle.pkcs.PKCS10CertificationRequest; - -public class JcaPKCS10CertificationRequest - extends PKCS10CertificationRequest -{ - private static Hashtable keyAlgorithms = new Hashtable(); - - static - { - // - // key types - // - keyAlgorithms.put(PKCSObjectIdentifiers.rsaEncryption, "RSA"); - keyAlgorithms.put(X9ObjectIdentifiers.id_dsa, "DSA"); - } - - private JcaJceHelper helper = new DefaultJcaJceHelper(); - - public JcaPKCS10CertificationRequest(CertificationRequest certificationRequest) - { - super(certificationRequest); - } - - public JcaPKCS10CertificationRequest(byte[] encoding) - throws IOException - { - super(encoding); - } - - public JcaPKCS10CertificationRequest(PKCS10CertificationRequest requestHolder) - { - super(requestHolder.toASN1Structure()); - } - - public JcaPKCS10CertificationRequest setProvider(String providerName) - { - helper = new NamedJcaJceHelper(providerName); - - return this; - } - - public JcaPKCS10CertificationRequest setProvider(Provider provider) - { - helper = new ProviderJcaJceHelper(provider); - - return this; - } - - public PublicKey getPublicKey() - throws InvalidKeyException, NoSuchAlgorithmException - { - try - { - SubjectPublicKeyInfo keyInfo = this.getSubjectPublicKeyInfo(); - X509EncodedKeySpec xspec = new X509EncodedKeySpec(keyInfo.getEncoded()); - KeyFactory kFact; - - try - { - kFact = helper.createKeyFactory(keyInfo.getAlgorithm().getAlgorithm().getId()); - } - catch (NoSuchAlgorithmException e) - { - // - // try an alternate - // - if (keyAlgorithms.get(keyInfo.getAlgorithm().getAlgorithm()) != null) - { - String keyAlgorithm = (String)keyAlgorithms.get(keyInfo.getAlgorithm().getAlgorithm()); - - kFact = helper.createKeyFactory(keyAlgorithm); - } - else - { - throw e; - } - } - - return kFact.generatePublic(xspec); - } - catch (InvalidKeySpecException e) - { - throw new InvalidKeyException("error decoding public key"); - } - catch (IOException e) - { - throw new InvalidKeyException("error extracting key encoding"); - } - catch (NoSuchProviderException e) - { - throw new NoSuchAlgorithmException("cannot find provider: " + e.getMessage()); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcaPKCS10CertificationRequestBuilder.java b/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcaPKCS10CertificationRequestBuilder.java deleted file mode 100644 index 5466e5f7..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcaPKCS10CertificationRequestBuilder.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.bouncycastle.pkcs.jcajce; - -import java.security.PublicKey; - -import javax.security.auth.x500.X500Principal; - -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder; - -/** - * Extension of the PKCS#10 builder to support PublicKey and X500Principal objects. - */ -public class JcaPKCS10CertificationRequestBuilder - extends PKCS10CertificationRequestBuilder -{ - /** - * Create a PKCS#10 builder for the passed in subject and JCA public key. - * - * @param subject an X500Name containing the subject associated with the request we are building. - * @param publicKey a JCA public key that is to be associated with the request we are building. - */ - public JcaPKCS10CertificationRequestBuilder(X500Name subject, PublicKey publicKey) - { - super(subject, SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); - } - - /** - * Create a PKCS#10 builder for the passed in subject and JCA public key. - * - * @param subject an X500Principal containing the subject associated with the request we are building. - * @param publicKey a JCA public key that is to be associated with the request we are building. - */ - public JcaPKCS10CertificationRequestBuilder(X500Principal subject, PublicKey publicKey) - { - super(X500Name.getInstance(subject.getEncoded()), SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcaPKCS12SafeBagBuilder.java b/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcaPKCS12SafeBagBuilder.java deleted file mode 100644 index 0af510c2..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcaPKCS12SafeBagBuilder.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.bouncycastle.pkcs.jcajce; - -import java.io.IOException; -import java.security.PrivateKey; -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; - -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.asn1.x509.Certificate; -import org.bouncycastle.operator.OutputEncryptor; -import org.bouncycastle.pkcs.PKCS12SafeBagBuilder; -import org.bouncycastle.pkcs.PKCSIOException; - -public class JcaPKCS12SafeBagBuilder - extends PKCS12SafeBagBuilder -{ - public JcaPKCS12SafeBagBuilder(X509Certificate certificate) - throws IOException - { - super(convertCert(certificate)); - } - - private static Certificate convertCert(X509Certificate certificate) - throws IOException - { - try - { - return Certificate.getInstance(certificate.getEncoded()); - } - catch (CertificateEncodingException e) - { - throw new PKCSIOException("cannot encode certificate: " + e.getMessage(), e); - } - } - - public JcaPKCS12SafeBagBuilder(PrivateKey privateKey, OutputEncryptor encryptor) - { - super(PrivateKeyInfo.getInstance(privateKey.getEncoded()), encryptor); - } - - public JcaPKCS12SafeBagBuilder(PrivateKey privateKey) - { - super(PrivateKeyInfo.getInstance(privateKey.getEncoded())); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcaPKCS8EncryptedPrivateKeyInfoBuilder.java b/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcaPKCS8EncryptedPrivateKeyInfoBuilder.java deleted file mode 100644 index 691288d1..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcaPKCS8EncryptedPrivateKeyInfoBuilder.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.bouncycastle.pkcs.jcajce; - -import java.security.PrivateKey; - -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfoBuilder; - -public class JcaPKCS8EncryptedPrivateKeyInfoBuilder - extends PKCS8EncryptedPrivateKeyInfoBuilder -{ - public JcaPKCS8EncryptedPrivateKeyInfoBuilder(PrivateKey privateKey) - { - super(PrivateKeyInfo.getInstance(privateKey.getEncoded())); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcePKCS12MacCalculatorBuilder.java b/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcePKCS12MacCalculatorBuilder.java deleted file mode 100644 index eb52eae1..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcePKCS12MacCalculatorBuilder.java +++ /dev/null @@ -1,122 +0,0 @@ -package org.bouncycastle.pkcs.jcajce; - -import java.io.OutputStream; -import java.security.Provider; -import java.security.SecureRandom; - -import javax.crypto.Mac; -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.PBEParameterSpec; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCS12PBEParams; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.ExtendedDigest; -import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator; -import org.bouncycastle.jcajce.io.MacOutputStream; -import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.util.JcaJceHelper; -import org.bouncycastle.jcajce.util.NamedJcaJceHelper; -import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.MacCalculator; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.pkcs.PKCS12MacCalculatorBuilder; - -public class JcePKCS12MacCalculatorBuilder - implements PKCS12MacCalculatorBuilder -{ - private JcaJceHelper helper = new DefaultJcaJceHelper(); - private ExtendedDigest digest; - private ASN1ObjectIdentifier algorithm; - - private SecureRandom random; - private int saltLength; - private int iterationCount = 1024; - - public JcePKCS12MacCalculatorBuilder() - { - this(OIWObjectIdentifiers.idSHA1); - } - - public JcePKCS12MacCalculatorBuilder(ASN1ObjectIdentifier hashAlgorithm) - { - this.algorithm = hashAlgorithm; - } - - public JcePKCS12MacCalculatorBuilder setProvider(Provider provider) - { - this.helper = new ProviderJcaJceHelper(provider); - - return this; - } - - public JcePKCS12MacCalculatorBuilder setProvider(String providerName) - { - this.helper = new NamedJcaJceHelper(providerName); - - return this; - } - - public AlgorithmIdentifier getDigestAlgorithmIdentifier() - { - return new AlgorithmIdentifier(algorithm, DERNull.INSTANCE); - } - - public MacCalculator build(final char[] password) - throws OperatorCreationException - { - if (random == null) - { - random = new SecureRandom(); - } - - try - { - final Mac mac = helper.createMac(algorithm.getId()); - - saltLength = mac.getMacLength(); - final byte[] salt = new byte[saltLength]; - - random.nextBytes(salt); - - SecretKeyFactory keyFact = helper.createSecretKeyFactory(algorithm.getId()); - PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount); - PBEKeySpec pbeSpec = new PBEKeySpec(password); - SecretKey key = keyFact.generateSecret(pbeSpec); - - mac.init(key, defParams); - - return new MacCalculator() - { - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return new AlgorithmIdentifier(algorithm, new PKCS12PBEParams(salt, iterationCount)); - } - - public OutputStream getOutputStream() - { - return new MacOutputStream(mac); - } - - public byte[] getMac() - { - return mac.doFinal(); - } - - public GenericKey getKey() - { - return new GenericKey(getAlgorithmIdentifier(), PKCS12ParametersGenerator.PKCS12PasswordToBytes(password)); - } - }; - } - catch (Exception e) - { - throw new OperatorCreationException("unable to create MAC calculator: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcePKCS12MacCalculatorBuilderProvider.java b/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcePKCS12MacCalculatorBuilderProvider.java deleted file mode 100644 index ca666d1c..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcePKCS12MacCalculatorBuilderProvider.java +++ /dev/null @@ -1,108 +0,0 @@ -package org.bouncycastle.pkcs.jcajce; - -import java.io.OutputStream; -import java.security.Provider; - -import javax.crypto.Mac; -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.PBEParameterSpec; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.pkcs.PKCS12PBEParams; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator; -import org.bouncycastle.jcajce.io.MacOutputStream; -import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.util.JcaJceHelper; -import org.bouncycastle.jcajce.util.NamedJcaJceHelper; -import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.MacCalculator; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.pkcs.PKCS12MacCalculatorBuilder; -import org.bouncycastle.pkcs.PKCS12MacCalculatorBuilderProvider; - -public class JcePKCS12MacCalculatorBuilderProvider - implements PKCS12MacCalculatorBuilderProvider -{ - private JcaJceHelper helper = new DefaultJcaJceHelper(); - - public JcePKCS12MacCalculatorBuilderProvider() - { - } - - public JcePKCS12MacCalculatorBuilderProvider setProvider(Provider provider) - { - this.helper = new ProviderJcaJceHelper(provider); - - return this; - } - - public JcePKCS12MacCalculatorBuilderProvider setProvider(String providerName) - { - this.helper = new NamedJcaJceHelper(providerName); - - return this; - } - - public PKCS12MacCalculatorBuilder get(final AlgorithmIdentifier algorithmIdentifier) - { - return new PKCS12MacCalculatorBuilder() - { - public MacCalculator build(final char[] password) - throws OperatorCreationException - { - final PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algorithmIdentifier.getParameters()); - - try - { - final ASN1ObjectIdentifier algorithm = algorithmIdentifier.getAlgorithm(); - - final Mac mac = helper.createMac(algorithm.getId()); - - SecretKeyFactory keyFact = helper.createSecretKeyFactory(algorithm.getId()); - PBEParameterSpec defParams = new PBEParameterSpec(pbeParams.getIV(), pbeParams.getIterations().intValue()); - PBEKeySpec pbeSpec = new PBEKeySpec(password); - SecretKey key = keyFact.generateSecret(pbeSpec); - - mac.init(key, defParams); - - return new MacCalculator() - { - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return new AlgorithmIdentifier(algorithm, pbeParams); - } - - public OutputStream getOutputStream() - { - return new MacOutputStream(mac); - } - - public byte[] getMac() - { - return mac.doFinal(); - } - - public GenericKey getKey() - { - return new GenericKey(getAlgorithmIdentifier(), PKCS12ParametersGenerator.PKCS12PasswordToBytes(password)); - } - }; - } - catch (Exception e) - { - throw new OperatorCreationException("unable to create MAC calculator: " + e.getMessage(), e); - } - } - - public AlgorithmIdentifier getDigestAlgorithmIdentifier() - { - return new AlgorithmIdentifier(algorithmIdentifier.getAlgorithm(), DERNull.INSTANCE); - } - }; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcePKCSPBEInputDecryptorProviderBuilder.java b/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcePKCSPBEInputDecryptorProviderBuilder.java deleted file mode 100644 index 1b6d0669..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcePKCSPBEInputDecryptorProviderBuilder.java +++ /dev/null @@ -1,177 +0,0 @@ -package org.bouncycastle.pkcs.jcajce; - -import java.io.InputStream; -import java.security.Provider; - -import javax.crypto.Cipher; -import javax.crypto.CipherInputStream; -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.PBEParameterSpec; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.cryptopro.GOST28147Parameters; -import org.bouncycastle.asn1.pkcs.PBES2Parameters; -import org.bouncycastle.asn1.pkcs.PBKDF2Params; -import org.bouncycastle.asn1.pkcs.PKCS12PBEParams; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey; -import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec; -import org.bouncycastle.jcajce.spec.PBKDF2KeySpec; -import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.util.JcaJceHelper; -import org.bouncycastle.jcajce.util.NamedJcaJceHelper; -import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; -import org.bouncycastle.operator.DefaultSecretKeySizeProvider; -import org.bouncycastle.operator.InputDecryptor; -import org.bouncycastle.operator.InputDecryptorProvider; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.operator.SecretKeySizeProvider; - -public class JcePKCSPBEInputDecryptorProviderBuilder -{ - private JcaJceHelper helper = new DefaultJcaJceHelper(); - private boolean wrongPKCS12Zero = false; - private SecretKeySizeProvider keySizeProvider = DefaultSecretKeySizeProvider.INSTANCE; - - public JcePKCSPBEInputDecryptorProviderBuilder() - { - } - - public JcePKCSPBEInputDecryptorProviderBuilder setProvider(Provider provider) - { - this.helper = new ProviderJcaJceHelper(provider); - - return this; - } - - public JcePKCSPBEInputDecryptorProviderBuilder setProvider(String providerName) - { - this.helper = new NamedJcaJceHelper(providerName); - - return this; - } - - public JcePKCSPBEInputDecryptorProviderBuilder setTryWrongPKCS12Zero(boolean tryWrong) - { - this.wrongPKCS12Zero = tryWrong; - - return this; - } - - /** - * Set the lookup provider of AlgorithmIdentifier returning key_size_in_bits used to - * handle PKCS5 decryption. - * - * @param keySizeProvider a provider of integer secret key sizes. - * - * @return the current builder. - */ - public JcePKCSPBEInputDecryptorProviderBuilder setKeySizeProvider(SecretKeySizeProvider keySizeProvider) - { - this.keySizeProvider = keySizeProvider; - - return this; - } - - public InputDecryptorProvider build(final char[] password) - { - return new InputDecryptorProvider() - { - private Cipher cipher; - private SecretKey key; - private AlgorithmIdentifier encryptionAlg; - - public InputDecryptor get(final AlgorithmIdentifier algorithmIdentifier) - throws OperatorCreationException - { - ASN1ObjectIdentifier algorithm = algorithmIdentifier.getAlgorithm(); - - try - { - if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds)) - { - PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algorithmIdentifier.getParameters()); - - PBEKeySpec pbeSpec = new PBEKeySpec(password); - - SecretKeyFactory keyFact = helper.createSecretKeyFactory(algorithm.getId()); - - PBEParameterSpec defParams = new PBEParameterSpec( - pbeParams.getIV(), - pbeParams.getIterations().intValue()); - - key = keyFact.generateSecret(pbeSpec); - - if (key instanceof BCPBEKey) - { - ((BCPBEKey)key).setTryWrongPKCS12Zero(wrongPKCS12Zero); - } - - cipher = helper.createCipher(algorithm.getId()); - - cipher.init(Cipher.DECRYPT_MODE, key, defParams); - - encryptionAlg = algorithmIdentifier; - } - else if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2)) - { - PBES2Parameters alg = PBES2Parameters.getInstance(algorithmIdentifier.getParameters()); - PBKDF2Params func = PBKDF2Params.getInstance(alg.getKeyDerivationFunc().getParameters()); - AlgorithmIdentifier encScheme = AlgorithmIdentifier.getInstance(alg.getEncryptionScheme()); - - SecretKeyFactory keyFact = helper.createSecretKeyFactory(alg.getKeyDerivationFunc().getAlgorithm().getId()); - - if (func.isDefaultPrf()) - { - key = keyFact.generateSecret(new PBEKeySpec(password, func.getSalt(), func.getIterationCount().intValue(), keySizeProvider.getKeySize(encScheme))); - } - else - { - key = keyFact.generateSecret(new PBKDF2KeySpec(password, func.getSalt(), func.getIterationCount().intValue(), keySizeProvider.getKeySize(encScheme), func.getPrf())); - } - - cipher = helper.createCipher(alg.getEncryptionScheme().getAlgorithm().getId()); - - encryptionAlg = AlgorithmIdentifier.getInstance(alg.getEncryptionScheme()); - - ASN1Encodable encParams = alg.getEncryptionScheme().getParameters(); - if (encParams instanceof ASN1OctetString) - { - cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ASN1OctetString.getInstance(encParams).getOctets())); - } - else - { - // TODO: at the moment it's just GOST, but... - GOST28147Parameters gParams = GOST28147Parameters.getInstance(encParams); - - cipher.init(Cipher.DECRYPT_MODE, key, new GOST28147ParameterSpec(gParams.getEncryptionParamSet(), gParams.getIV())); - } - } - } - catch (Exception e) - { - throw new OperatorCreationException("unable to create InputDecryptor: " + e.getMessage(), e); - } - - return new InputDecryptor() - { - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return encryptionAlg; - } - - public InputStream getInputStream(InputStream input) - { - return new CipherInputStream(input, cipher); - } - }; - } - }; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcePKCSPBEOutputEncryptorBuilder.java b/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcePKCSPBEOutputEncryptorBuilder.java deleted file mode 100644 index 934bcc0b..00000000 --- a/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcePKCSPBEOutputEncryptorBuilder.java +++ /dev/null @@ -1,179 +0,0 @@ -package org.bouncycastle.pkcs.jcajce; - -import java.io.OutputStream; -import java.security.Provider; -import java.security.SecureRandom; - -import javax.crypto.Cipher; -import javax.crypto.CipherOutputStream; -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.PBEParameterSpec; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.bc.BCObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.EncryptionScheme; -import org.bouncycastle.asn1.pkcs.KeyDerivationFunc; -import org.bouncycastle.asn1.pkcs.PBES2Parameters; -import org.bouncycastle.asn1.pkcs.PBKDF2Params; -import org.bouncycastle.asn1.pkcs.PKCS12PBEParams; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.PBEParametersGenerator; -import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.util.JcaJceHelper; -import org.bouncycastle.jcajce.util.NamedJcaJceHelper; -import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; -import org.bouncycastle.operator.DefaultSecretKeySizeProvider; -import org.bouncycastle.operator.GenericKey; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.operator.OutputEncryptor; -import org.bouncycastle.operator.SecretKeySizeProvider; - -public class JcePKCSPBEOutputEncryptorBuilder -{ - private JcaJceHelper helper = new DefaultJcaJceHelper(); - private ASN1ObjectIdentifier algorithm; - private ASN1ObjectIdentifier keyEncAlgorithm; - private SecureRandom random; - private SecretKeySizeProvider keySizeProvider = DefaultSecretKeySizeProvider.INSTANCE; - - public JcePKCSPBEOutputEncryptorBuilder(ASN1ObjectIdentifier algorithm) - { - if (isPKCS12(algorithm)) - { - this.algorithm = algorithm; - this.keyEncAlgorithm = algorithm; - } - else - { - this.algorithm = PKCSObjectIdentifiers.id_PBES2; - this.keyEncAlgorithm = algorithm; - } - } - - public JcePKCSPBEOutputEncryptorBuilder setProvider(Provider provider) - { - this.helper = new ProviderJcaJceHelper(provider); - - return this; - } - - public JcePKCSPBEOutputEncryptorBuilder setProvider(String providerName) - { - this.helper = new NamedJcaJceHelper(providerName); - - return this; - } - - /** - * Set the lookup provider of AlgorithmIdentifier returning key_size_in_bits used to - * handle PKCS5 decryption. - * - * @param keySizeProvider a provider of integer secret key sizes. - * - * @return the current builder. - */ - public JcePKCSPBEOutputEncryptorBuilder setKeySizeProvider(SecretKeySizeProvider keySizeProvider) - { - this.keySizeProvider = keySizeProvider; - - return this; - } - - public OutputEncryptor build(final char[] password) - throws OperatorCreationException - { - final Cipher cipher; - SecretKey key; - - if (random == null) - { - random = new SecureRandom(); - } - - final AlgorithmIdentifier encryptionAlg; - final byte[] salt = new byte[20]; - final int iterationCount = 1024; - - random.nextBytes(salt); - - try - { - if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds)) - { - PBEKeySpec pbeSpec = new PBEKeySpec(password); - - SecretKeyFactory keyFact = helper.createSecretKeyFactory(algorithm.getId()); - - PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount); - - key = keyFact.generateSecret(pbeSpec); - - cipher = helper.createCipher(algorithm.getId()); - - cipher.init(Cipher.ENCRYPT_MODE, key, defParams); - - encryptionAlg = new AlgorithmIdentifier(algorithm, new PKCS12PBEParams(salt, iterationCount)); - } - else if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2)) - { - SecretKeyFactory keyFact = helper.createSecretKeyFactory(PKCSObjectIdentifiers.id_PBKDF2.getId()); - - key = keyFact.generateSecret(new PBEKeySpec(password, salt, iterationCount, keySizeProvider.getKeySize(new AlgorithmIdentifier(keyEncAlgorithm)))); - - cipher = helper.createCipher(keyEncAlgorithm.getId()); - - cipher.init(Cipher.ENCRYPT_MODE, key, random); - - PBES2Parameters algParams = new PBES2Parameters( - new KeyDerivationFunc(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(salt, iterationCount)), - new EncryptionScheme(keyEncAlgorithm, ASN1Primitive.fromByteArray(cipher.getParameters().getEncoded()))); - - encryptionAlg = new AlgorithmIdentifier(algorithm, algParams); - } - else - { - throw new OperatorCreationException("unrecognised algorithm"); - } - - return new OutputEncryptor() - { - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return encryptionAlg; - } - - public OutputStream getOutputStream(OutputStream out) - { - return new CipherOutputStream(out, cipher); - } - - public GenericKey getKey() - { - if (isPKCS12(encryptionAlg.getAlgorithm())) - { - return new GenericKey(encryptionAlg, PBEParametersGenerator.PKCS5PasswordToBytes(password)); - } - else - { - return new GenericKey(encryptionAlg, PBEParametersGenerator.PKCS12PasswordToBytes(password)); - } - } - }; - } - catch (Exception e) - { - throw new OperatorCreationException("unable to create OutputEncryptor: " + e.getMessage(), e); - } - } - - private boolean isPKCS12(ASN1ObjectIdentifier algorithm) - { - return algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds) - || algorithm.on(BCObjectIdentifiers.bc_pbe_sha1_pkcs12) - || algorithm.on(BCObjectIdentifiers.bc_pbe_sha256_pkcs12); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/tsp/GenTimeAccuracy.java b/pkix/src/main/java/org/bouncycastle/tsp/GenTimeAccuracy.java deleted file mode 100644 index 3cabb86b..00000000 --- a/pkix/src/main/java/org/bouncycastle/tsp/GenTimeAccuracy.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.bouncycastle.tsp; - -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.tsp.Accuracy; - -public class GenTimeAccuracy -{ - private Accuracy accuracy; - - public GenTimeAccuracy(Accuracy accuracy) - { - this.accuracy = accuracy; - } - - public int getSeconds() - { - return getTimeComponent(accuracy.getSeconds()); - } - - public int getMillis() - { - return getTimeComponent(accuracy.getMillis()); - } - - public int getMicros() - { - return getTimeComponent(accuracy.getMicros()); - } - - private int getTimeComponent( - ASN1Integer time) - { - if (time != null) - { - return time.getValue().intValue(); - } - - return 0; - } - - public String toString() - { // digits - return getSeconds() + "." + format(getMillis()) + format(getMicros()); - } - - private String format(int v) - { - if (v < 10) - { - return "00" + v; - } - - if (v < 100) - { - return "0" + v; - } - - return Integer.toString(v); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/tsp/TSPAlgorithms.java b/pkix/src/main/java/org/bouncycastle/tsp/TSPAlgorithms.java deleted file mode 100644 index e8b26ad5..00000000 --- a/pkix/src/main/java/org/bouncycastle/tsp/TSPAlgorithms.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.bouncycastle.tsp; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; - -/** - * Recognised hash algorithms for the time stamp protocol. - */ -public interface TSPAlgorithms -{ - public static final ASN1ObjectIdentifier MD5 = PKCSObjectIdentifiers.md5; - - public static final ASN1ObjectIdentifier SHA1 = OIWObjectIdentifiers.idSHA1; - - public static final ASN1ObjectIdentifier SHA224 = NISTObjectIdentifiers.id_sha224; - public static final ASN1ObjectIdentifier SHA256 = NISTObjectIdentifiers.id_sha256; - public static final ASN1ObjectIdentifier SHA384 = NISTObjectIdentifiers.id_sha384; - public static final ASN1ObjectIdentifier SHA512 = NISTObjectIdentifiers.id_sha512; - - public static final ASN1ObjectIdentifier RIPEMD128 = TeleTrusTObjectIdentifiers.ripemd128; - public static final ASN1ObjectIdentifier RIPEMD160 = TeleTrusTObjectIdentifiers.ripemd160; - public static final ASN1ObjectIdentifier RIPEMD256 = TeleTrusTObjectIdentifiers.ripemd256; - - public static final ASN1ObjectIdentifier GOST3411 = CryptoProObjectIdentifiers.gostR3411; - - public static final Set ALLOWED = new HashSet(Arrays.asList(new ASN1ObjectIdentifier[] { GOST3411, MD5, SHA1, SHA224, SHA256, SHA384, SHA512, RIPEMD128, RIPEMD160, RIPEMD256 })); -} diff --git a/pkix/src/main/java/org/bouncycastle/tsp/TSPException.java b/pkix/src/main/java/org/bouncycastle/tsp/TSPException.java deleted file mode 100644 index a04e5c52..00000000 --- a/pkix/src/main/java/org/bouncycastle/tsp/TSPException.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.bouncycastle.tsp; - -public class TSPException - extends Exception -{ - Throwable underlyingException; - - public TSPException(String message) - { - super(message); - } - - public TSPException(String message, Throwable e) - { - super(message); - underlyingException = e; - } - - public Exception getUnderlyingException() - { - return (Exception)underlyingException; - } - - public Throwable getCause() - { - return underlyingException; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/tsp/TSPIOException.java b/pkix/src/main/java/org/bouncycastle/tsp/TSPIOException.java deleted file mode 100644 index 0be66dbc..00000000 --- a/pkix/src/main/java/org/bouncycastle/tsp/TSPIOException.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.bouncycastle.tsp; - -import java.io.IOException; - -public class TSPIOException - extends IOException -{ - Throwable underlyingException; - - public TSPIOException(String message) - { - super(message); - } - - public TSPIOException(String message, Throwable e) - { - super(message); - underlyingException = e; - } - - public Exception getUnderlyingException() - { - return (Exception)underlyingException; - } - - public Throwable getCause() - { - return underlyingException; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/tsp/TSPUtil.java b/pkix/src/main/java/org/bouncycastle/tsp/TSPUtil.java deleted file mode 100644 index d7570717..00000000 --- a/pkix/src/main/java/org/bouncycastle/tsp/TSPUtil.java +++ /dev/null @@ -1,209 +0,0 @@ -package org.bouncycastle.tsp; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.cms.Attribute; -import org.bouncycastle.asn1.cms.AttributeTable; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; -import org.bouncycastle.asn1.x509.ExtendedKeyUsage; -import org.bouncycastle.asn1.x509.Extension; -import org.bouncycastle.asn1.x509.Extensions; -import org.bouncycastle.asn1.x509.ExtensionsGenerator; -import org.bouncycastle.asn1.x509.KeyPurposeId; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cms.SignerInformation; -import org.bouncycastle.operator.DigestCalculator; -import org.bouncycastle.operator.DigestCalculatorProvider; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Integers; - -public class TSPUtil -{ - private static List EMPTY_LIST = Collections.unmodifiableList(new ArrayList()); - - private static final Map digestLengths = new HashMap(); - private static final Map digestNames = new HashMap(); - - static - { - digestLengths.put(PKCSObjectIdentifiers.md5.getId(), Integers.valueOf(16)); - digestLengths.put(OIWObjectIdentifiers.idSHA1.getId(), Integers.valueOf(20)); - digestLengths.put(NISTObjectIdentifiers.id_sha224.getId(), Integers.valueOf(28)); - digestLengths.put(NISTObjectIdentifiers.id_sha256.getId(), Integers.valueOf(32)); - digestLengths.put(NISTObjectIdentifiers.id_sha384.getId(), Integers.valueOf(48)); - digestLengths.put(NISTObjectIdentifiers.id_sha512.getId(), Integers.valueOf(64)); - digestLengths.put(TeleTrusTObjectIdentifiers.ripemd128.getId(), Integers.valueOf(16)); - digestLengths.put(TeleTrusTObjectIdentifiers.ripemd160.getId(), Integers.valueOf(20)); - digestLengths.put(TeleTrusTObjectIdentifiers.ripemd256.getId(), Integers.valueOf(32)); - digestLengths.put(CryptoProObjectIdentifiers.gostR3411.getId(), Integers.valueOf(32)); - - digestNames.put(PKCSObjectIdentifiers.md5.getId(), "MD5"); - digestNames.put(OIWObjectIdentifiers.idSHA1.getId(), "SHA1"); - digestNames.put(NISTObjectIdentifiers.id_sha224.getId(), "SHA224"); - digestNames.put(NISTObjectIdentifiers.id_sha256.getId(), "SHA256"); - digestNames.put(NISTObjectIdentifiers.id_sha384.getId(), "SHA384"); - digestNames.put(NISTObjectIdentifiers.id_sha512.getId(), "SHA512"); - digestNames.put(PKCSObjectIdentifiers.sha1WithRSAEncryption.getId(), "SHA1"); - digestNames.put(PKCSObjectIdentifiers.sha224WithRSAEncryption.getId(), "SHA224"); - digestNames.put(PKCSObjectIdentifiers.sha256WithRSAEncryption.getId(), "SHA256"); - digestNames.put(PKCSObjectIdentifiers.sha384WithRSAEncryption.getId(), "SHA384"); - digestNames.put(PKCSObjectIdentifiers.sha512WithRSAEncryption.getId(), "SHA512"); - digestNames.put(TeleTrusTObjectIdentifiers.ripemd128.getId(), "RIPEMD128"); - digestNames.put(TeleTrusTObjectIdentifiers.ripemd160.getId(), "RIPEMD160"); - digestNames.put(TeleTrusTObjectIdentifiers.ripemd256.getId(), "RIPEMD256"); - digestNames.put(CryptoProObjectIdentifiers.gostR3411.getId(), "GOST3411"); - } - - /** - * Fetches the signature time-stamp attributes from a SignerInformation object. - * Checks that the MessageImprint for each time-stamp matches the signature field. - * (see RFC 3161 Appendix A). - * - * @param signerInfo a SignerInformation to search for time-stamps - * @param digCalcProvider provider for digest calculators - * @return a collection of TimeStampToken objects - * @throws TSPValidationException - */ - public static Collection getSignatureTimestamps(SignerInformation signerInfo, DigestCalculatorProvider digCalcProvider) - throws TSPValidationException - { - List timestamps = new ArrayList(); - - AttributeTable unsignedAttrs = signerInfo.getUnsignedAttributes(); - if (unsignedAttrs != null) - { - ASN1EncodableVector allTSAttrs = unsignedAttrs.getAll( - PKCSObjectIdentifiers.id_aa_signatureTimeStampToken); - for (int i = 0; i < allTSAttrs.size(); ++i) - { - Attribute tsAttr = (Attribute)allTSAttrs.get(i); - ASN1Set tsAttrValues = tsAttr.getAttrValues(); - for (int j = 0; j < tsAttrValues.size(); ++j) - { - try - { - ContentInfo contentInfo = ContentInfo.getInstance(tsAttrValues.getObjectAt(j)); - TimeStampToken timeStampToken = new TimeStampToken(contentInfo); - TimeStampTokenInfo tstInfo = timeStampToken.getTimeStampInfo(); - - DigestCalculator digCalc = digCalcProvider.get(tstInfo.getHashAlgorithm()); - - OutputStream dOut = digCalc.getOutputStream(); - - dOut.write(signerInfo.getSignature()); - dOut.close(); - - byte[] expectedDigest = digCalc.getDigest(); - - if (!Arrays.constantTimeAreEqual(expectedDigest, tstInfo.getMessageImprintDigest())) - { - throw new TSPValidationException("Incorrect digest in message imprint"); - } - - timestamps.add(timeStampToken); - } - catch (OperatorCreationException e) - { - throw new TSPValidationException("Unknown hash algorithm specified in timestamp"); - } - catch (Exception e) - { - throw new TSPValidationException("Timestamp could not be parsed"); - } - } - } - } - - return timestamps; - } - - /** - * Validate the passed in certificate as being of the correct type to be used - * for time stamping. To be valid it must have an ExtendedKeyUsage extension - * which has a key purpose identifier of id-kp-timeStamping. - * - * @param cert the certificate of interest. - * @throws TSPValidationException if the certificate fails on one of the check points. - */ - public static void validateCertificate( - X509CertificateHolder cert) - throws TSPValidationException - { - if (cert.toASN1Structure().getVersionNumber() != 3) - { - throw new IllegalArgumentException("Certificate must have an ExtendedKeyUsage extension."); - } - - Extension ext = cert.getExtension(Extension.extendedKeyUsage); - if (ext == null) - { - throw new TSPValidationException("Certificate must have an ExtendedKeyUsage extension."); - } - - if (!ext.isCritical()) - { - throw new TSPValidationException("Certificate must have an ExtendedKeyUsage extension marked as critical."); - } - - ExtendedKeyUsage extKey = ExtendedKeyUsage.getInstance(ext.getParsedValue()); - - if (!extKey.hasKeyPurposeId(KeyPurposeId.id_kp_timeStamping) || extKey.size() != 1) - { - throw new TSPValidationException("ExtendedKeyUsage not solely time stamping."); - } - } - - static int getDigestLength( - String digestAlgOID) - throws TSPException - { - Integer length = (Integer)digestLengths.get(digestAlgOID); - - if (length != null) - { - return length.intValue(); - } - - throw new TSPException("digest algorithm cannot be found."); - } - - static List getExtensionOIDs(Extensions extensions) - { - if (extensions == null) - { - return EMPTY_LIST; - } - - return Collections.unmodifiableList(java.util.Arrays.asList(extensions.getExtensionOIDs())); - } - - static void addExtension(ExtensionsGenerator extGenerator, ASN1ObjectIdentifier oid, boolean isCritical, ASN1Encodable value) - throws TSPIOException - { - try - { - extGenerator.addExtension(oid, isCritical, value); - } - catch (IOException e) - { - throw new TSPIOException("cannot encode extension: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/tsp/TSPValidationException.java b/pkix/src/main/java/org/bouncycastle/tsp/TSPValidationException.java deleted file mode 100644 index 552b302e..00000000 --- a/pkix/src/main/java/org/bouncycastle/tsp/TSPValidationException.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.bouncycastle.tsp; - -/** - * Exception thrown if a TSP request or response fails to validate. - * <p> - * If a failure code is associated with the exception it can be retrieved using - * the getFailureCode() method. - */ -public class TSPValidationException - extends TSPException -{ - private int failureCode = -1; - - public TSPValidationException(String message) - { - super(message); - } - - public TSPValidationException(String message, int failureCode) - { - super(message); - this.failureCode = failureCode; - } - - /** - * Return the failure code associated with this exception - if one is set. - * - * @return the failure code if set, -1 otherwise. - */ - public int getFailureCode() - { - return failureCode; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampRequest.java b/pkix/src/main/java/org/bouncycastle/tsp/TimeStampRequest.java deleted file mode 100644 index fa7c9f78..00000000 --- a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampRequest.java +++ /dev/null @@ -1,267 +0,0 @@ -package org.bouncycastle.tsp; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.math.BigInteger; -import java.util.Arrays; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.cmp.PKIFailureInfo; -import org.bouncycastle.asn1.tsp.TimeStampReq; -import org.bouncycastle.asn1.x509.Extension; -import org.bouncycastle.asn1.x509.Extensions; - -/** - * Base class for an RFC 3161 Time Stamp Request. - */ -public class TimeStampRequest -{ - private static Set EMPTY_SET = Collections.unmodifiableSet(new HashSet()); - - private TimeStampReq req; - private Extensions extensions; - - public TimeStampRequest(TimeStampReq req) - { - this.req = req; - this.extensions = req.getExtensions(); - } - - /** - * Create a TimeStampRequest from the past in byte array. - * - * @param req byte array containing the request. - * @throws IOException if the request is malformed. - */ - public TimeStampRequest(byte[] req) - throws IOException - { - this(new ByteArrayInputStream(req)); - } - - /** - * Create a TimeStampRequest from the past in input stream. - * - * @param in input stream containing the request. - * @throws IOException if the request is malformed. - */ - public TimeStampRequest(InputStream in) - throws IOException - { - this(loadRequest(in)); - } - - private static TimeStampReq loadRequest(InputStream in) - throws IOException - { - try - { - return TimeStampReq.getInstance(new ASN1InputStream(in).readObject()); - } - catch (ClassCastException e) - { - throw new IOException("malformed request: " + e); - } - catch (IllegalArgumentException e) - { - throw new IOException("malformed request: " + e); - } - } - - public int getVersion() - { - return req.getVersion().getValue().intValue(); - } - - public ASN1ObjectIdentifier getMessageImprintAlgOID() - { - return req.getMessageImprint().getHashAlgorithm().getAlgorithm(); - } - - public byte[] getMessageImprintDigest() - { - return req.getMessageImprint().getHashedMessage(); - } - - public ASN1ObjectIdentifier getReqPolicy() - { - if (req.getReqPolicy() != null) - { - return req.getReqPolicy(); - } - else - { - return null; - } - } - - public BigInteger getNonce() - { - if (req.getNonce() != null) - { - return req.getNonce().getValue(); - } - else - { - return null; - } - } - - public boolean getCertReq() - { - if (req.getCertReq() != null) - { - return req.getCertReq().isTrue(); - } - else - { - return false; - } - } - - /** - * Validate the timestamp request, checking the digest to see if it is of an - * accepted type and whether it is of the correct length for the algorithm specified. - * - * @param algorithms a set of OIDs giving accepted algorithms. - * @param policies if non-null a set of policies OIDs we are willing to sign under. - * @param extensions if non-null a set of extensions OIDs we are willing to accept. - * @throws TSPException if the request is invalid, or processing fails. - */ - public void validate( - Set algorithms, - Set policies, - Set extensions) - throws TSPException - { - algorithms = convert(algorithms); - policies = convert(policies); - extensions = convert(extensions); - - if (!algorithms.contains(this.getMessageImprintAlgOID())) - { - throw new TSPValidationException("request contains unknown algorithm.", PKIFailureInfo.badAlg); - } - - if (policies != null && this.getReqPolicy() != null && !policies.contains(this.getReqPolicy())) - { - throw new TSPValidationException("request contains unknown policy.", PKIFailureInfo.unacceptedPolicy); - } - - if (this.getExtensions() != null && extensions != null) - { - Enumeration en = this.getExtensions().oids(); - while(en.hasMoreElements()) - { - String oid = ((ASN1ObjectIdentifier)en.nextElement()).getId(); - if (!extensions.contains(oid)) - { - throw new TSPValidationException("request contains unknown extension.", PKIFailureInfo.unacceptedExtension); - } - } - } - - int digestLength = TSPUtil.getDigestLength(this.getMessageImprintAlgOID().getId()); - - if (digestLength != this.getMessageImprintDigest().length) - { - throw new TSPValidationException("imprint digest the wrong length.", PKIFailureInfo.badDataFormat); - } - } - - /** - * return the ASN.1 encoded representation of this object. - * @return the default ASN,1 byte encoding for the object. - */ - public byte[] getEncoded() throws IOException - { - return req.getEncoded(); - } - - Extensions getExtensions() - { - return extensions; - } - - public boolean hasExtensions() - { - return extensions != null; - } - - public Extension getExtension(ASN1ObjectIdentifier oid) - { - if (extensions != null) - { - return extensions.getExtension(oid); - } - - return null; - } - - public List getExtensionOIDs() - { - return TSPUtil.getExtensionOIDs(extensions); - } - - /** - * Returns a set of ASN1ObjectIdentifiers giving the non-critical extensions. - * @return a set of ASN1ObjectIdentifiers. - */ - public Set getNonCriticalExtensionOIDs() - { - if (extensions == null) - { - return EMPTY_SET; - } - - return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getNonCriticalExtensionOIDs()))); - } - - /** - * Returns a set of ASN1ObjectIdentifiers giving the critical extensions. - * @return a set of ASN1ObjectIdentifiers. - */ - public Set getCriticalExtensionOIDs() - { - if (extensions == null) - { - return EMPTY_SET; - } - - return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getCriticalExtensionOIDs()))); - } - - private Set convert(Set orig) - { - if (orig == null) - { - return orig; - } - - Set con = new HashSet(orig.size()); - - for (Iterator it = orig.iterator(); it.hasNext();) - { - Object o = it.next(); - - if (o instanceof String) - { - con.add(new ASN1ObjectIdentifier((String)o)); - } - else - { - con.add(o); - } - } - - return con; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampRequestGenerator.java b/pkix/src/main/java/org/bouncycastle/tsp/TimeStampRequestGenerator.java deleted file mode 100644 index 0f9900df..00000000 --- a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampRequestGenerator.java +++ /dev/null @@ -1,163 +0,0 @@ -package org.bouncycastle.tsp; - -import java.io.IOException; -import java.math.BigInteger; - -import org.bouncycastle.asn1.ASN1Boolean; -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.tsp.MessageImprint; -import org.bouncycastle.asn1.tsp.TimeStampReq; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.Extensions; -import org.bouncycastle.asn1.x509.ExtensionsGenerator; - -/** - * Generator for RFC 3161 Time Stamp Request objects. - */ -public class TimeStampRequestGenerator -{ - private ASN1ObjectIdentifier reqPolicy; - - private ASN1Boolean certReq; - private ExtensionsGenerator extGenerator = new ExtensionsGenerator(); - - public TimeStampRequestGenerator() - { - } - - /** - * @deprecated use method taking ASN1ObjectIdentifier - * @param reqPolicy - */ - public void setReqPolicy( - String reqPolicy) - { - this.reqPolicy= new ASN1ObjectIdentifier(reqPolicy); - } - - public void setReqPolicy( - ASN1ObjectIdentifier reqPolicy) - { - this.reqPolicy= reqPolicy; - } - - public void setCertReq( - boolean certReq) - { - this.certReq = ASN1Boolean.getInstance(certReq); - } - - /** - * add a given extension field for the standard extensions tag (tag 3) - * @throws IOException - * @deprecated use method taking ASN1ObjectIdentifier - */ - public void addExtension( - String OID, - boolean critical, - ASN1Encodable value) - throws IOException - { - this.addExtension(OID, critical, value.toASN1Primitive().getEncoded()); - } - - /** - * add a given extension field for the standard extensions tag - * The value parameter becomes the contents of the octet string associated - * with the extension. - * @deprecated use method taking ASN1ObjectIdentifier - */ - public void addExtension( - String OID, - boolean critical, - byte[] value) - { - extGenerator.addExtension(new ASN1ObjectIdentifier(OID), critical, value); - } - - /** - * add a given extension field for the standard extensions tag (tag 3) - * @throws TSPIOException - */ - public void addExtension( - ASN1ObjectIdentifier oid, - boolean isCritical, - ASN1Encodable value) - throws TSPIOException - { - TSPUtil.addExtension(extGenerator, oid, isCritical, value); - } - - /** - * add a given extension field for the standard extensions tag - * The value parameter becomes the contents of the octet string associated - * with the extension. - */ - public void addExtension( - ASN1ObjectIdentifier oid, - boolean isCritical, - byte[] value) - { - extGenerator.addExtension(oid, isCritical, value); - } - - /** - * @deprecated use method taking ANS1ObjectIdentifier - */ - public TimeStampRequest generate( - String digestAlgorithm, - byte[] digest) - { - return this.generate(digestAlgorithm, digest, null); - } - - /** - * @deprecated use method taking ANS1ObjectIdentifier - */ - public TimeStampRequest generate( - String digestAlgorithmOID, - byte[] digest, - BigInteger nonce) - { - if (digestAlgorithmOID == null) - { - throw new IllegalArgumentException("No digest algorithm specified"); - } - - ASN1ObjectIdentifier digestAlgOID = new ASN1ObjectIdentifier(digestAlgorithmOID); - - AlgorithmIdentifier algID = new AlgorithmIdentifier(digestAlgOID, DERNull.INSTANCE); - MessageImprint messageImprint = new MessageImprint(algID, digest); - - Extensions ext = null; - - if (!extGenerator.isEmpty()) - { - ext = extGenerator.generate(); - } - - if (nonce != null) - { - return new TimeStampRequest(new TimeStampReq(messageImprint, - reqPolicy, new ASN1Integer(nonce), certReq, ext)); - } - else - { - return new TimeStampRequest(new TimeStampReq(messageImprint, - reqPolicy, null, certReq, ext)); - } - } - - public TimeStampRequest generate(ASN1ObjectIdentifier digestAlgorithm, byte[] digest) - { - return generate(digestAlgorithm.getId(), digest); - } - - public TimeStampRequest generate(ASN1ObjectIdentifier digestAlgorithm, byte[] digest, BigInteger nonce) - { - return generate(digestAlgorithm.getId(), digest, nonce); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampResponse.java b/pkix/src/main/java/org/bouncycastle/tsp/TimeStampResponse.java deleted file mode 100644 index 7d135109..00000000 --- a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampResponse.java +++ /dev/null @@ -1,189 +0,0 @@ -package org.bouncycastle.tsp; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; - -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.cmp.PKIFailureInfo; -import org.bouncycastle.asn1.cmp.PKIFreeText; -import org.bouncycastle.asn1.cmp.PKIStatus; -import org.bouncycastle.asn1.cms.Attribute; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.tsp.TimeStampResp; -import org.bouncycastle.util.Arrays; - -/** - * Base class for an RFC 3161 Time Stamp Response object. - */ -public class TimeStampResponse -{ - TimeStampResp resp; - TimeStampToken timeStampToken; - - public TimeStampResponse(TimeStampResp resp) - throws TSPException, IOException - { - this.resp = resp; - - if (resp.getTimeStampToken() != null) - { - timeStampToken = new TimeStampToken(resp.getTimeStampToken()); - } - } - - /** - * Create a TimeStampResponse from a byte array containing an ASN.1 encoding. - * - * @param resp the byte array containing the encoded response. - * @throws TSPException if the response is malformed. - * @throws IOException if the byte array doesn't represent an ASN.1 encoding. - */ - public TimeStampResponse(byte[] resp) - throws TSPException, IOException - { - this(new ByteArrayInputStream(resp)); - } - - /** - * Create a TimeStampResponse from an input stream containing an ASN.1 encoding. - * - * @param in the input stream containing the encoded response. - * @throws TSPException if the response is malformed. - * @throws IOException if the stream doesn't represent an ASN.1 encoding. - */ - public TimeStampResponse(InputStream in) - throws TSPException, IOException - { - this(readTimeStampResp(in)); - } - - private static TimeStampResp readTimeStampResp( - InputStream in) - throws IOException, TSPException - { - try - { - return TimeStampResp.getInstance(new ASN1InputStream(in).readObject()); - } - catch (IllegalArgumentException e) - { - throw new TSPException("malformed timestamp response: " + e, e); - } - catch (ClassCastException e) - { - throw new TSPException("malformed timestamp response: " + e, e); - } - } - - public int getStatus() - { - return resp.getStatus().getStatus().intValue(); - } - - public String getStatusString() - { - if (resp.getStatus().getStatusString() != null) - { - StringBuffer statusStringBuf = new StringBuffer(); - PKIFreeText text = resp.getStatus().getStatusString(); - for (int i = 0; i != text.size(); i++) - { - statusStringBuf.append(text.getStringAt(i).getString()); - } - return statusStringBuf.toString(); - } - else - { - return null; - } - } - - public PKIFailureInfo getFailInfo() - { - if (resp.getStatus().getFailInfo() != null) - { - return new PKIFailureInfo(resp.getStatus().getFailInfo()); - } - - return null; - } - - public TimeStampToken getTimeStampToken() - { - return timeStampToken; - } - - /** - * Check this response against to see if it a well formed response for - * the passed in request. Validation will include checking the time stamp - * token if the response status is GRANTED or GRANTED_WITH_MODS. - * - * @param request the request to be checked against - * @throws TSPException if the request can not match this response. - */ - public void validate( - TimeStampRequest request) - throws TSPException - { - TimeStampToken tok = this.getTimeStampToken(); - - if (tok != null) - { - TimeStampTokenInfo tstInfo = tok.getTimeStampInfo(); - - if (request.getNonce() != null && !request.getNonce().equals(tstInfo.getNonce())) - { - throw new TSPValidationException("response contains wrong nonce value."); - } - - if (this.getStatus() != PKIStatus.GRANTED && this.getStatus() != PKIStatus.GRANTED_WITH_MODS) - { - throw new TSPValidationException("time stamp token found in failed request."); - } - - if (!Arrays.constantTimeAreEqual(request.getMessageImprintDigest(), tstInfo.getMessageImprintDigest())) - { - throw new TSPValidationException("response for different message imprint digest."); - } - - if (!tstInfo.getMessageImprintAlgOID().equals(request.getMessageImprintAlgOID())) - { - throw new TSPValidationException("response for different message imprint algorithm."); - } - - Attribute scV1 = tok.getSignedAttributes().get(PKCSObjectIdentifiers.id_aa_signingCertificate); - Attribute scV2 = tok.getSignedAttributes().get(PKCSObjectIdentifiers.id_aa_signingCertificateV2); - - if (scV1 == null && scV2 == null) - { - throw new TSPValidationException("no signing certificate attribute present."); - } - - if (scV1 != null && scV2 != null) - { - /* - * RFC 5035 5.4. If both attributes exist in a single message, - * they are independently evaluated. - */ - } - - if (request.getReqPolicy() != null && !request.getReqPolicy().equals(tstInfo.getPolicy())) - { - throw new TSPValidationException("TSA policy wrong for request."); - } - } - else if (this.getStatus() == PKIStatus.GRANTED || this.getStatus() == PKIStatus.GRANTED_WITH_MODS) - { - throw new TSPValidationException("no time stamp token found and one expected."); - } - } - - /** - * return the ASN.1 encoded representation of this object. - */ - public byte[] getEncoded() throws IOException - { - return resp.getEncoded(); - } -}
\ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampResponseGenerator.java b/pkix/src/main/java/org/bouncycastle/tsp/TimeStampResponseGenerator.java deleted file mode 100644 index 8ab68aa4..00000000 --- a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampResponseGenerator.java +++ /dev/null @@ -1,353 +0,0 @@ -package org.bouncycastle.tsp; - -import java.io.IOException; -import java.math.BigInteger; -import java.util.Date; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.DERUTF8String; -import org.bouncycastle.asn1.cmp.PKIFailureInfo; -import org.bouncycastle.asn1.cmp.PKIFreeText; -import org.bouncycastle.asn1.cmp.PKIStatus; -import org.bouncycastle.asn1.cmp.PKIStatusInfo; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.tsp.TimeStampResp; - -/** - * Generator for RFC 3161 Time Stamp Responses. - * <p> - * New generate methods have been introduced to give people more control over what ends up in the message. - * Unfortunately it turns out that in some cases fields like statusString must be left out otherwise a an - * otherwise valid timestamp will be rejected. - * </p> - * If you're after the most control with generating a response use: - * <pre> - * TimeStampResponse tsResp; - * - * try - * { - * tsResp = tsRespGen.generateGrantedResponse(request, new BigInteger("23"), new Date()); - * } - * catch (Exception e) - * { - * tsResp = tsRespGen.generateRejectedResponse(e); - * } - * </pre> - * The generate method does this, but provides a status string of "Operation Okay". - * <p> - * It should be pointed out that generateRejectedResponse() may also, on very rare occasions throw a TSPException. - * In the event that happens, there's a serious internal problem with your responder. - * </p> - */ -public class TimeStampResponseGenerator -{ - int status; - - ASN1EncodableVector statusStrings; - - int failInfo; - private TimeStampTokenGenerator tokenGenerator; - private Set acceptedAlgorithms; - private Set acceptedPolicies; - private Set acceptedExtensions; - - /** - * - * @param tokenGenerator - * @param acceptedAlgorithms a set of OIDs giving accepted algorithms. - */ - public TimeStampResponseGenerator( - TimeStampTokenGenerator tokenGenerator, - Set acceptedAlgorithms) - { - this(tokenGenerator, acceptedAlgorithms, null, null); - } - - /** - * - * @param tokenGenerator - * @param acceptedAlgorithms a set of OIDs giving accepted algorithms. - * @param acceptedPolicies if non-null a set of policies OIDs we are willing to sign under. - */ - public TimeStampResponseGenerator( - TimeStampTokenGenerator tokenGenerator, - Set acceptedAlgorithms, - Set acceptedPolicies) - { - this(tokenGenerator, acceptedAlgorithms, acceptedPolicies, null); - } - - /** - * - * @param tokenGenerator - * @param acceptedAlgorithms a set of OIDs giving accepted algorithms. - * @param acceptedPolicies if non-null a set of policies OIDs we are willing to sign under. - * @param acceptedExtensions if non-null a set of extensions OIDs we are willing to accept. - */ - public TimeStampResponseGenerator( - TimeStampTokenGenerator tokenGenerator, - Set acceptedAlgorithms, - Set acceptedPolicies, - Set acceptedExtensions) - { - this.tokenGenerator = tokenGenerator; - this.acceptedAlgorithms = convert(acceptedAlgorithms); - this.acceptedPolicies = convert(acceptedPolicies); - this.acceptedExtensions = convert(acceptedExtensions); - - statusStrings = new ASN1EncodableVector(); - } - - private void addStatusString(String statusString) - { - statusStrings.add(new DERUTF8String(statusString)); - } - - private void setFailInfoField(int field) - { - failInfo = failInfo | field; - } - - private PKIStatusInfo getPKIStatusInfo() - { - ASN1EncodableVector v = new ASN1EncodableVector(); - - v.add(new ASN1Integer(status)); - - if (statusStrings.size() > 0) - { - v.add(PKIFreeText.getInstance(new DERSequence(statusStrings))); - } - - if (failInfo != 0) - { - DERBitString failInfoBitString = new FailInfo(failInfo); - v.add(failInfoBitString); - } - - return PKIStatusInfo.getInstance(new DERSequence(v)); - } - - /** - * Return an appropriate TimeStampResponse. - * <p> - * If genTime is null a timeNotAvailable error response will be returned. Calling generate() is the - * equivalent of: - * <pre> - * TimeStampResponse tsResp; - * - * try - * { - * tsResp = tsRespGen.generateGrantedResponse(request, serialNumber, genTime, "Operation Okay"); - * } - * catch (Exception e) - * { - * tsResp = tsRespGen.generateRejectedResponse(e); - * } - * </pre> - * @param request the request this response is for. - * @param serialNumber serial number for the response token. - * @param genTime generation time for the response token. - * @return a TimeStampResponse. - * @throws TSPException - */ - public TimeStampResponse generate( - TimeStampRequest request, - BigInteger serialNumber, - Date genTime) - throws TSPException - { - try - { - return this.generateGrantedResponse(request, serialNumber, genTime, "Operation Okay"); - } - catch (Exception e) - { - return this.generateRejectedResponse(e); - } - } - - /** - * Return a granted response, if the passed in request passes validation. - * <p> - * If genTime is null a timeNotAvailable or a validation exception occurs a TSPValidationException will - * be thrown. The parent TSPException will only occur on some sort of system failure. - * </p> - * @param request the request this response is for. - * @param serialNumber serial number for the response token. - * @param genTime generation time for the response token. - * @return the TimeStampResponse with a status of PKIStatus.GRANTED - * @throws TSPException on validation exception or internal error. - */ - public TimeStampResponse generateGrantedResponse( - TimeStampRequest request, - BigInteger serialNumber, - Date genTime) - throws TSPException - { - return generateGrantedResponse(request, serialNumber, genTime, null); - } - - /** - * Return a granted response, if the passed in request passes validation with the passed in status string. - * <p> - * If genTime is null a timeNotAvailable or a validation exception occurs a TSPValidationException will - * be thrown. The parent TSPException will only occur on some sort of system failure. - * </p> - * @param request the request this response is for. - * @param serialNumber serial number for the response token. - * @param genTime generation time for the response token. - * @return the TimeStampResponse with a status of PKIStatus.GRANTED - * @throws TSPException on validation exception or internal error. - */ - public TimeStampResponse generateGrantedResponse( - TimeStampRequest request, - BigInteger serialNumber, - Date genTime, - String statusString) - throws TSPException - { - if (genTime == null) - { - throw new TSPValidationException("The time source is not available.", PKIFailureInfo.timeNotAvailable); - } - - request.validate(acceptedAlgorithms, acceptedPolicies, acceptedExtensions); - - status = PKIStatus.GRANTED; - statusStrings = new ASN1EncodableVector(); - - if (statusString != null) - { - this.addStatusString(statusString); - } - - PKIStatusInfo pkiStatusInfo = getPKIStatusInfo(); - - ContentInfo tstTokenContentInfo; - try - { - tstTokenContentInfo = tokenGenerator.generate(request, serialNumber, genTime).toCMSSignedData().toASN1Structure(); - } - catch (TSPException e) - { - throw e; - } - catch (Exception e) - { - throw new TSPException( - "Timestamp token received cannot be converted to ContentInfo", e); - } - - TimeStampResp resp = new TimeStampResp(pkiStatusInfo, tstTokenContentInfo); - - try - { - return new TimeStampResponse(resp); - } - catch (IOException e) - { - throw new TSPException("created badly formatted response!"); - } - } - - /** - * Generate a generic rejection response based on a TSPValidationException or - * an Exception. Exceptions which are not an instance of TSPValidationException - * will be treated as systemFailure. The return value of exception.getMessage() will - * be used as the status string for the response. - * - * @param exception the exception thrown on validating the request. - * @return a TimeStampResponse. - * @throws TSPException if a failure response cannot be generated. - */ - public TimeStampResponse generateRejectedResponse(Exception exception) - throws TSPException - { - if (exception instanceof TSPValidationException) - { - return generateFailResponse(PKIStatus.REJECTION, ((TSPValidationException)exception).getFailureCode(), exception.getMessage()); - } - else - { - return generateFailResponse(PKIStatus.REJECTION, PKIFailureInfo.systemFailure, exception.getMessage()); - } - } - - /** - * Generate a non-granted TimeStampResponse with chosen status and FailInfoField. - * - * @param status the PKIStatus to set. - * @param failInfoField the FailInfoField to set. - * @param statusString an optional string describing the failure. - * @return a TimeStampResponse with a failInfoField and optional statusString - * @throws TSPException in case the response could not be created - */ - public TimeStampResponse generateFailResponse(int status, int failInfoField, String statusString) - throws TSPException - { - this.status = status; - this.statusStrings = new ASN1EncodableVector(); - - this.setFailInfoField(failInfoField); - - if (statusString != null) - { - this.addStatusString(statusString); - } - - PKIStatusInfo pkiStatusInfo = getPKIStatusInfo(); - - TimeStampResp resp = new TimeStampResp(pkiStatusInfo, null); - - try - { - return new TimeStampResponse(resp); - } - catch (IOException e) - { - throw new TSPException("created badly formatted response!"); - } - } - - private Set convert(Set orig) - { - if (orig == null) - { - return orig; - } - - Set con = new HashSet(orig.size()); - - for (Iterator it = orig.iterator(); it.hasNext();) - { - Object o = it.next(); - - if (o instanceof String) - { - con.add(new ASN1ObjectIdentifier((String)o)); - } - else - { - con.add(o); - } - } - - return con; - } - - class FailInfo extends DERBitString - { - FailInfo(int failInfoValue) - { - super(getBytes(failInfoValue), getPadBits(failInfoValue)); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampToken.java b/pkix/src/main/java/org/bouncycastle/tsp/TimeStampToken.java deleted file mode 100644 index 04229985..00000000 --- a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampToken.java +++ /dev/null @@ -1,393 +0,0 @@ -package org.bouncycastle.tsp; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Collection; -import java.util.Date; - -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.cms.Attribute; -import org.bouncycastle.asn1.cms.AttributeTable; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.cms.IssuerAndSerialNumber; -import org.bouncycastle.asn1.ess.ESSCertID; -import org.bouncycastle.asn1.ess.ESSCertIDv2; -import org.bouncycastle.asn1.ess.SigningCertificate; -import org.bouncycastle.asn1.ess.SigningCertificateV2; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.tsp.TSTInfo; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.asn1.x509.IssuerSerial; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.CMSProcessable; -import org.bouncycastle.cms.CMSSignedData; -import org.bouncycastle.cms.SignerId; -import org.bouncycastle.cms.SignerInformation; -import org.bouncycastle.cms.SignerInformationVerifier; -import org.bouncycastle.operator.DigestCalculator; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Store; - -/** - * Carrier class for a TimeStampToken. - */ -public class TimeStampToken -{ - CMSSignedData tsToken; - - SignerInformation tsaSignerInfo; - - Date genTime; - - TimeStampTokenInfo tstInfo; - - CertID certID; - - public TimeStampToken(ContentInfo contentInfo) - throws TSPException, IOException - { - this(getSignedData(contentInfo)); - } - - private static CMSSignedData getSignedData(ContentInfo contentInfo) - throws TSPException - { - try - { - return new CMSSignedData(contentInfo); - } - catch (CMSException e) - { - throw new TSPException("TSP parsing error: " + e.getMessage(), e.getCause()); - } - } - - public TimeStampToken(CMSSignedData signedData) - throws TSPException, IOException - { - this.tsToken = signedData; - - if (!this.tsToken.getSignedContentTypeOID().equals(PKCSObjectIdentifiers.id_ct_TSTInfo.getId())) - { - throw new TSPValidationException("ContentInfo object not for a time stamp."); - } - - Collection signers = tsToken.getSignerInfos().getSigners(); - - if (signers.size() != 1) - { - throw new IllegalArgumentException("Time-stamp token signed by " - + signers.size() - + " signers, but it must contain just the TSA signature."); - } - - tsaSignerInfo = (SignerInformation)signers.iterator().next(); - - try - { - CMSProcessable content = tsToken.getSignedContent(); - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - - content.write(bOut); - - ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(bOut.toByteArray())); - - this.tstInfo = new TimeStampTokenInfo(TSTInfo.getInstance(aIn.readObject())); - - Attribute attr = tsaSignerInfo.getSignedAttributes().get(PKCSObjectIdentifiers.id_aa_signingCertificate); - - if (attr != null) - { - SigningCertificate signCert = SigningCertificate.getInstance(attr.getAttrValues().getObjectAt(0)); - - this.certID = new CertID(ESSCertID.getInstance(signCert.getCerts()[0])); - } - else - { - attr = tsaSignerInfo.getSignedAttributes().get(PKCSObjectIdentifiers.id_aa_signingCertificateV2); - - if (attr == null) - { - throw new TSPValidationException("no signing certificate attribute found, time stamp invalid."); - } - - SigningCertificateV2 signCertV2 = SigningCertificateV2.getInstance(attr.getAttrValues().getObjectAt(0)); - - this.certID = new CertID(ESSCertIDv2.getInstance(signCertV2.getCerts()[0])); - } - } - catch (CMSException e) - { - throw new TSPException(e.getMessage(), e.getUnderlyingException()); - } - } - - public TimeStampTokenInfo getTimeStampInfo() - { - return tstInfo; - } - - public SignerId getSID() - { - return tsaSignerInfo.getSID(); - } - - public AttributeTable getSignedAttributes() - { - return tsaSignerInfo.getSignedAttributes(); - } - - public AttributeTable getUnsignedAttributes() - { - return tsaSignerInfo.getUnsignedAttributes(); - } - - public Store getCertificates() - { - return tsToken.getCertificates(); - } - - public Store getCRLs() - { - return tsToken.getCRLs(); - } - - public Store getAttributeCertificates() - { - return tsToken.getAttributeCertificates(); - } - - /** - * Validate the time stamp token. - * <p> - * To be valid the token must be signed by the passed in certificate and - * the certificate must be the one referred to by the SigningCertificate - * attribute included in the hashed attributes of the token. The - * certificate must also have the ExtendedKeyUsageExtension with only - * KeyPurposeId.id_kp_timeStamping and have been valid at the time the - * timestamp was created. - * </p> - * <p> - * A successful call to validate means all the above are true. - * </p> - * - * @param sigVerifier the content verifier create the objects required to verify the CMS object in the timestamp. - * @throws TSPException if an exception occurs in processing the token. - * @throws TSPValidationException if the certificate or signature fail to be valid. - * @throws IllegalArgumentException if the sigVerifierProvider has no associated certificate. - */ - public void validate( - SignerInformationVerifier sigVerifier) - throws TSPException, TSPValidationException - { - if (!sigVerifier.hasAssociatedCertificate()) - { - throw new IllegalArgumentException("verifier provider needs an associated certificate"); - } - - try - { - X509CertificateHolder certHolder = sigVerifier.getAssociatedCertificate(); - DigestCalculator calc = sigVerifier.getDigestCalculator(certID.getHashAlgorithm()); - - OutputStream cOut = calc.getOutputStream(); - - cOut.write(certHolder.getEncoded()); - cOut.close(); - - if (!Arrays.constantTimeAreEqual(certID.getCertHash(), calc.getDigest())) - { - throw new TSPValidationException("certificate hash does not match certID hash."); - } - - if (certID.getIssuerSerial() != null) - { - IssuerAndSerialNumber issuerSerial = new IssuerAndSerialNumber(certHolder.toASN1Structure()); - - if (!certID.getIssuerSerial().getSerial().equals(issuerSerial.getSerialNumber())) - { - throw new TSPValidationException("certificate serial number does not match certID for signature."); - } - - GeneralName[] names = certID.getIssuerSerial().getIssuer().getNames(); - boolean found = false; - - for (int i = 0; i != names.length; i++) - { - if (names[i].getTagNo() == 4 && X500Name.getInstance(names[i].getName()).equals(X500Name.getInstance(issuerSerial.getName()))) - { - found = true; - break; - } - } - - if (!found) - { - throw new TSPValidationException("certificate name does not match certID for signature. "); - } - } - - TSPUtil.validateCertificate(certHolder); - - if (!certHolder.isValidOn(tstInfo.getGenTime())) - { - throw new TSPValidationException("certificate not valid when time stamp created."); - } - - if (!tsaSignerInfo.verify(sigVerifier)) - { - throw new TSPValidationException("signature not created by certificate."); - } - } - catch (CMSException e) - { - if (e.getUnderlyingException() != null) - { - throw new TSPException(e.getMessage(), e.getUnderlyingException()); - } - else - { - throw new TSPException("CMS exception: " + e, e); - } - } - catch (IOException e) - { - throw new TSPException("problem processing certificate: " + e, e); - } - catch (OperatorCreationException e) - { - throw new TSPException("unable to create digest: " + e.getMessage(), e); - } - } - - /** - * Return true if the signature on time stamp token is valid. - * <p> - * Note: this is a much weaker proof of correctness than calling validate(). - * </p> - * - * @param sigVerifier the content verifier create the objects required to verify the CMS object in the timestamp. - * @return true if the signature matches, false otherwise. - * @throws TSPException if the signature cannot be processed or the provider cannot match the algorithm. - */ - public boolean isSignatureValid( - SignerInformationVerifier sigVerifier) - throws TSPException - { - try - { - return tsaSignerInfo.verify(sigVerifier); - } - catch (CMSException e) - { - if (e.getUnderlyingException() != null) - { - throw new TSPException(e.getMessage(), e.getUnderlyingException()); - } - else - { - throw new TSPException("CMS exception: " + e, e); - } - } - } - - /** - * Return the underlying CMSSignedData object. - * - * @return the underlying CMS structure. - */ - public CMSSignedData toCMSSignedData() - { - return tsToken; - } - - /** - * Return a ASN.1 encoded byte stream representing the encoded object. - * - * @throws IOException if encoding fails. - */ - public byte[] getEncoded() - throws IOException - { - return tsToken.getEncoded(); - } - - // perhaps this should be done using an interface on the ASN.1 classes... - private class CertID - { - private ESSCertID certID; - private ESSCertIDv2 certIDv2; - - CertID(ESSCertID certID) - { - this.certID = certID; - this.certIDv2 = null; - } - - CertID(ESSCertIDv2 certID) - { - this.certIDv2 = certID; - this.certID = null; - } - - public String getHashAlgorithmName() - { - if (certID != null) - { - return "SHA-1"; - } - else - { - if (NISTObjectIdentifiers.id_sha256.equals(certIDv2.getHashAlgorithm().getAlgorithm())) - { - return "SHA-256"; - } - return certIDv2.getHashAlgorithm().getAlgorithm().getId(); - } - } - - public AlgorithmIdentifier getHashAlgorithm() - { - if (certID != null) - { - return new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1); - } - else - { - return certIDv2.getHashAlgorithm(); - } - } - - public byte[] getCertHash() - { - if (certID != null) - { - return certID.getCertHash(); - } - else - { - return certIDv2.getCertHash(); - } - } - - public IssuerSerial getIssuerSerial() - { - if (certID != null) - { - return certID.getIssuerSerial(); - } - else - { - return certIDv2.getIssuerSerial(); - } - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampTokenGenerator.java b/pkix/src/main/java/org/bouncycastle/tsp/TimeStampTokenGenerator.java deleted file mode 100644 index 91586c50..00000000 --- a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampTokenGenerator.java +++ /dev/null @@ -1,380 +0,0 @@ -package org.bouncycastle.tsp; - -import java.io.IOException; -import java.io.OutputStream; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.bouncycastle.asn1.ASN1Boolean; -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.ASN1GeneralizedTime; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.cms.AttributeTable; -import org.bouncycastle.asn1.ess.ESSCertID; -import org.bouncycastle.asn1.ess.ESSCertIDv2; -import org.bouncycastle.asn1.ess.SigningCertificate; -import org.bouncycastle.asn1.ess.SigningCertificateV2; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.tsp.Accuracy; -import org.bouncycastle.asn1.tsp.MessageImprint; -import org.bouncycastle.asn1.tsp.TSTInfo; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.asn1.x509.GeneralNames; -import org.bouncycastle.asn1.x509.IssuerSerial; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cms.CMSAttributeTableGenerationException; -import org.bouncycastle.cms.CMSAttributeTableGenerator; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.CMSProcessableByteArray; -import org.bouncycastle.cms.CMSSignedData; -import org.bouncycastle.cms.CMSSignedDataGenerator; -import org.bouncycastle.cms.SignerInfoGenerator; -import org.bouncycastle.operator.DigestCalculator; -import org.bouncycastle.util.CollectionStore; -import org.bouncycastle.util.Store; - -/** - * Currently the class supports ESSCertID by if a digest calculator based on SHA1 is passed in, otherwise it uses - * ESSCertIDv2. In the event you need to pass both types, you will need to override the SignedAttributeGenerator - * for the SignerInfoGeneratorBuilder you are using. For the default for ESSCertIDv2 the code will look something - * like the following: - * <pre> - * final ESSCertID essCertid = new ESSCertID(certHashSha1, issuerSerial); - * final ESSCertIDv2 essCertidV2 = new ESSCertIDv2(certHashSha256, issuerSerial); - * - * signerInfoGenBuilder.setSignedAttributeGenerator(new CMSAttributeTableGenerator() - * { - * public AttributeTable getAttributes(Map parameters) - * throws CMSAttributeTableGenerationException - * { - * CMSAttributeTableGenerator attrGen = new DefaultSignedAttributeTableGenerator(); - * - * AttributeTable table = attrGen.getAttributes(parameters); - * - * table = table.add(PKCSObjectIdentifiers.id_aa_signingCertificate, new SigningCertificate(essCertid)); - * table = table.add(PKCSObjectIdentifiers.id_aa_signingCertificateV2, new SigningCertificateV2(essCertidV2)); - * - * return table; - * } - * }); - * </pre> - */ -public class TimeStampTokenGenerator -{ - int accuracySeconds = -1; - - int accuracyMillis = -1; - - int accuracyMicros = -1; - - boolean ordering = false; - - GeneralName tsa = null; - - private ASN1ObjectIdentifier tsaPolicyOID; - - private List certs = new ArrayList(); - private List crls = new ArrayList(); - private List attrCerts = new ArrayList(); - private Map otherRevoc = new HashMap(); - private SignerInfoGenerator signerInfoGen; - - /** - * Basic Constructor - set up a calculator based on signerInfoGen with a ESSCertID calculated from - * the signer's associated certificate using the sha1DigestCalculator. If alternate values are required - * for id-aa-signingCertificate they should be added to the signerInfoGen object before it is passed in, - * otherwise a standard digest based value will be added. - * - * @param signerInfoGen the generator for the signer we are using. - * @param digestCalculator calculator for to use for digest of certificate. - * @param tsaPolicy tasPolicy to send. - * @throws IllegalArgumentException if calculator is not SHA-1 or there is no associated certificate for the signer, - * @throws TSPException if the signer certificate cannot be processed. - */ - public TimeStampTokenGenerator( - final SignerInfoGenerator signerInfoGen, - DigestCalculator digestCalculator, - ASN1ObjectIdentifier tsaPolicy) - throws IllegalArgumentException, TSPException - { - this(signerInfoGen, digestCalculator, tsaPolicy, false); - } - - /** - * Basic Constructor - set up a calculator based on signerInfoGen with a ESSCertID calculated from - * the signer's associated certificate using the sha1DigestCalculator. If alternate values are required - * for id-aa-signingCertificate they should be added to the signerInfoGen object before it is passed in, - * otherwise a standard digest based value will be added. - * - * @param signerInfoGen the generator for the signer we are using. - * @param digestCalculator calculator for to use for digest of certificate. - * @param tsaPolicy tasPolicy to send. - * @param isIssuerSerialIncluded should issuerSerial be included in the ESSCertIDs, true if yes, by default false. - * @throws IllegalArgumentException if calculator is not SHA-1 or there is no associated certificate for the signer, - * @throws TSPException if the signer certificate cannot be processed. - */ - public TimeStampTokenGenerator( - final SignerInfoGenerator signerInfoGen, - DigestCalculator digestCalculator, - ASN1ObjectIdentifier tsaPolicy, - boolean isIssuerSerialIncluded) - throws IllegalArgumentException, TSPException - { - this.signerInfoGen = signerInfoGen; - this.tsaPolicyOID = tsaPolicy; - - if (!signerInfoGen.hasAssociatedCertificate()) - { - throw new IllegalArgumentException("SignerInfoGenerator must have an associated certificate"); - } - - X509CertificateHolder assocCert = signerInfoGen.getAssociatedCertificate(); - TSPUtil.validateCertificate(assocCert); - - try - { - OutputStream dOut = digestCalculator.getOutputStream(); - - dOut.write(assocCert.getEncoded()); - - dOut.close(); - - if (digestCalculator.getAlgorithmIdentifier().getAlgorithm().equals(OIWObjectIdentifiers.idSHA1)) - { - final ESSCertID essCertid = new ESSCertID(digestCalculator.getDigest(), - isIssuerSerialIncluded ? new IssuerSerial(new GeneralNames(new GeneralName(assocCert.getIssuer())), assocCert.getSerialNumber()) - : null); - - this.signerInfoGen = new SignerInfoGenerator(signerInfoGen, new CMSAttributeTableGenerator() - { - public AttributeTable getAttributes(Map parameters) - throws CMSAttributeTableGenerationException - { - AttributeTable table = signerInfoGen.getSignedAttributeTableGenerator().getAttributes(parameters); - - if (table.get(PKCSObjectIdentifiers.id_aa_signingCertificate) == null) - { - return table.add(PKCSObjectIdentifiers.id_aa_signingCertificate, new SigningCertificate(essCertid)); - } - - return table; - } - }, signerInfoGen.getUnsignedAttributeTableGenerator()); - } - else - { - AlgorithmIdentifier digAlgID = new AlgorithmIdentifier(digestCalculator.getAlgorithmIdentifier().getAlgorithm()); - final ESSCertIDv2 essCertid = new ESSCertIDv2(digAlgID, digestCalculator.getDigest(), - isIssuerSerialIncluded ? new IssuerSerial(new GeneralNames(new GeneralName(assocCert.getIssuer())), new ASN1Integer(assocCert.getSerialNumber())) - : null); - - this.signerInfoGen = new SignerInfoGenerator(signerInfoGen, new CMSAttributeTableGenerator() - { - public AttributeTable getAttributes(Map parameters) - throws CMSAttributeTableGenerationException - { - AttributeTable table = signerInfoGen.getSignedAttributeTableGenerator().getAttributes(parameters); - - if (table.get(PKCSObjectIdentifiers.id_aa_signingCertificateV2) == null) - { - return table.add(PKCSObjectIdentifiers.id_aa_signingCertificateV2, new SigningCertificateV2(essCertid)); - } - - return table; - } - }, signerInfoGen.getUnsignedAttributeTableGenerator()); - } - } - catch (IOException e) - { - throw new TSPException("Exception processing certificate.", e); - } - } - - /** - * Add the store of X509 Certificates to the generator. - * - * @param certStore a Store containing X509CertificateHolder objects - */ - public void addCertificates( - Store certStore) - { - certs.addAll(certStore.getMatches(null)); - } - - /** - * - * @param crlStore a Store containing X509CRLHolder objects. - */ - public void addCRLs( - Store crlStore) - { - crls.addAll(crlStore.getMatches(null)); - } - - /** - * - * @param attrStore a Store containing X509AttributeCertificate objects. - */ - public void addAttributeCertificates( - Store attrStore) - { - attrCerts.addAll(attrStore.getMatches(null)); - } - - /** - * Add a Store of otherRevocationData to the CRL set to be included with the generated TimeStampToken. - * - * @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) - { - otherRevoc.put(otherRevocationInfoFormat, otherRevocationInfos.getMatches(null)); - } - - public void setAccuracySeconds(int accuracySeconds) - { - this.accuracySeconds = accuracySeconds; - } - - public void setAccuracyMillis(int accuracyMillis) - { - this.accuracyMillis = accuracyMillis; - } - - public void setAccuracyMicros(int accuracyMicros) - { - this.accuracyMicros = accuracyMicros; - } - - public void setOrdering(boolean ordering) - { - this.ordering = ordering; - } - - public void setTSA(GeneralName tsa) - { - this.tsa = tsa; - } - - /** - * Generate a TimeStampToken for the passed in request and serialNumber marking it with the passed in genTime. - * - * @param request the originating request. - * @param serialNumber serial number for the TimeStampToken - * @param genTime token generation time. - * @return a TimeStampToken - * @throws TSPException - */ - public TimeStampToken generate( - TimeStampRequest request, - BigInteger serialNumber, - Date genTime) - throws TSPException - { - ASN1ObjectIdentifier digestAlgOID = request.getMessageImprintAlgOID(); - - AlgorithmIdentifier algID = new AlgorithmIdentifier(digestAlgOID, DERNull.INSTANCE); - MessageImprint messageImprint = new MessageImprint(algID, request.getMessageImprintDigest()); - - Accuracy accuracy = null; - if (accuracySeconds > 0 || accuracyMillis > 0 || accuracyMicros > 0) - { - ASN1Integer seconds = null; - if (accuracySeconds > 0) - { - seconds = new ASN1Integer(accuracySeconds); - } - - ASN1Integer millis = null; - if (accuracyMillis > 0) - { - millis = new ASN1Integer(accuracyMillis); - } - - ASN1Integer micros = null; - if (accuracyMicros > 0) - { - micros = new ASN1Integer(accuracyMicros); - } - - accuracy = new Accuracy(seconds, millis, micros); - } - - ASN1Boolean derOrdering = null; - if (ordering) - { - derOrdering = new ASN1Boolean(ordering); - } - - ASN1Integer nonce = null; - if (request.getNonce() != null) - { - nonce = new ASN1Integer(request.getNonce()); - } - - ASN1ObjectIdentifier tsaPolicy = tsaPolicyOID; - if (request.getReqPolicy() != null) - { - tsaPolicy = request.getReqPolicy(); - } - - TSTInfo tstInfo = new TSTInfo(tsaPolicy, - messageImprint, new ASN1Integer(serialNumber), - new ASN1GeneralizedTime(genTime), accuracy, derOrdering, - nonce, tsa, request.getExtensions()); - - try - { - CMSSignedDataGenerator signedDataGenerator = new CMSSignedDataGenerator(); - - if (request.getCertReq()) - { - // TODO: do we need to check certs non-empty? - signedDataGenerator.addCertificates(new CollectionStore(certs)); - signedDataGenerator.addAttributeCertificates(new CollectionStore(attrCerts)); - } - - signedDataGenerator.addCRLs(new CollectionStore(crls)); - - if (!otherRevoc.isEmpty()) - { - for (Iterator it = otherRevoc.keySet().iterator(); it.hasNext();) - { - ASN1ObjectIdentifier format = (ASN1ObjectIdentifier)it.next(); - - signedDataGenerator.addOtherRevocationInfo(format, new CollectionStore((Collection)otherRevoc.get(format))); - } - } - - signedDataGenerator.addSignerInfoGenerator(signerInfoGen); - - byte[] derEncodedTSTInfo = tstInfo.getEncoded(ASN1Encoding.DER); - - CMSSignedData signedData = signedDataGenerator.generate(new CMSProcessableByteArray(PKCSObjectIdentifiers.id_ct_TSTInfo, derEncodedTSTInfo), true); - - return new TimeStampToken(signedData); - } - catch (CMSException cmsEx) - { - throw new TSPException("Error generating time-stamp token", cmsEx); - } - catch (IOException e) - { - throw new TSPException("Exception encoding info", e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampTokenInfo.java b/pkix/src/main/java/org/bouncycastle/tsp/TimeStampTokenInfo.java deleted file mode 100644 index 98011a03..00000000 --- a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampTokenInfo.java +++ /dev/null @@ -1,121 +0,0 @@ -package org.bouncycastle.tsp; - -import java.io.IOException; -import java.math.BigInteger; -import java.text.ParseException; -import java.util.Date; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.tsp.Accuracy; -import org.bouncycastle.asn1.tsp.TSTInfo; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.GeneralName; - -public class TimeStampTokenInfo -{ - TSTInfo tstInfo; - Date genTime; - - TimeStampTokenInfo(TSTInfo tstInfo) - throws TSPException, IOException - { - this.tstInfo = tstInfo; - - try - { - this.genTime = tstInfo.getGenTime().getDate(); - } - catch (ParseException e) - { - throw new TSPException("unable to parse genTime field"); - } - } - - public boolean isOrdered() - { - return tstInfo.getOrdering().isTrue(); - } - - public Accuracy getAccuracy() - { - return tstInfo.getAccuracy(); - } - - public Date getGenTime() - { - return genTime; - } - - public GenTimeAccuracy getGenTimeAccuracy() - { - if (this.getAccuracy() != null) - { - return new GenTimeAccuracy(this.getAccuracy()); - } - - return null; - } - - public ASN1ObjectIdentifier getPolicy() - { - return tstInfo.getPolicy(); - } - - public BigInteger getSerialNumber() - { - return tstInfo.getSerialNumber().getValue(); - } - - public GeneralName getTsa() - { - return tstInfo.getTsa(); - } - - /** - * @return the nonce value, null if there isn't one. - */ - public BigInteger getNonce() - { - if (tstInfo.getNonce() != null) - { - return tstInfo.getNonce().getValue(); - } - - return null; - } - - public AlgorithmIdentifier getHashAlgorithm() - { - return tstInfo.getMessageImprint().getHashAlgorithm(); - } - - public ASN1ObjectIdentifier getMessageImprintAlgOID() - { - return tstInfo.getMessageImprint().getHashAlgorithm().getAlgorithm(); - } - - public byte[] getMessageImprintDigest() - { - return tstInfo.getMessageImprint().getHashedMessage(); - } - - public byte[] getEncoded() - throws IOException - { - return tstInfo.getEncoded(); - } - - /** - * @deprecated use toASN1Structure - * @return - */ - public TSTInfo toTSTInfo() - { - return tstInfo; - } - - public TSTInfo toASN1Structure() - { - return tstInfo; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/tsp/cms/CMSTimeStampedData.java b/pkix/src/main/java/org/bouncycastle/tsp/cms/CMSTimeStampedData.java deleted file mode 100644 index 3093a6d6..00000000 --- a/pkix/src/main/java/org/bouncycastle/tsp/cms/CMSTimeStampedData.java +++ /dev/null @@ -1,204 +0,0 @@ -package org.bouncycastle.tsp.cms; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.net.URISyntaxException; - -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.DERIA5String; -import org.bouncycastle.asn1.cms.AttributeTable; -import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.cms.Evidence; -import org.bouncycastle.asn1.cms.TimeStampAndCRL; -import org.bouncycastle.asn1.cms.TimeStampTokenEvidence; -import org.bouncycastle.asn1.cms.TimeStampedData; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.operator.DigestCalculator; -import org.bouncycastle.operator.DigestCalculatorProvider; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.tsp.TimeStampToken; - -public class CMSTimeStampedData -{ - private TimeStampedData timeStampedData; - private ContentInfo contentInfo; - private TimeStampDataUtil util; - - public CMSTimeStampedData(ContentInfo contentInfo) - { - this.initialize(contentInfo); - } - - public CMSTimeStampedData(InputStream in) - throws IOException - { - try - { - initialize(ContentInfo.getInstance(new ASN1InputStream(in).readObject())); - } - catch (ClassCastException e) - { - throw new IOException("Malformed content: " + e); - } - catch (IllegalArgumentException e) - { - throw new IOException("Malformed content: " + e); - } - } - - public CMSTimeStampedData(byte[] baseData) - throws IOException - { - this(new ByteArrayInputStream(baseData)); - } - - private void initialize(ContentInfo contentInfo) - { - this.contentInfo = contentInfo; - - if (CMSObjectIdentifiers.timestampedData.equals(contentInfo.getContentType())) - { - this.timeStampedData = TimeStampedData.getInstance(contentInfo.getContent()); - } - else - { - throw new IllegalArgumentException("Malformed content - type must be " + CMSObjectIdentifiers.timestampedData.getId()); - } - - util = new TimeStampDataUtil(this.timeStampedData); - } - - public byte[] calculateNextHash(DigestCalculator calculator) - throws CMSException - { - return util.calculateNextHash(calculator); - } - - /** - * Return a new timeStampedData object with the additional token attached. - * - * @throws CMSException - */ - public CMSTimeStampedData addTimeStamp(TimeStampToken token) - throws CMSException - { - TimeStampAndCRL[] timeStamps = util.getTimeStamps(); - TimeStampAndCRL[] newTimeStamps = new TimeStampAndCRL[timeStamps.length + 1]; - - System.arraycopy(timeStamps, 0, newTimeStamps, 0, timeStamps.length); - - newTimeStamps[timeStamps.length] = new TimeStampAndCRL(token.toCMSSignedData().toASN1Structure()); - - return new CMSTimeStampedData(new ContentInfo(CMSObjectIdentifiers.timestampedData, new TimeStampedData(timeStampedData.getDataUri(), timeStampedData.getMetaData(), timeStampedData.getContent(), new Evidence(new TimeStampTokenEvidence(newTimeStamps))))); - } - - public byte[] getContent() - { - if (timeStampedData.getContent() != null) - { - return timeStampedData.getContent().getOctets(); - } - - return null; - } - - public URI getDataUri() - throws URISyntaxException - { - DERIA5String dataURI = this.timeStampedData.getDataUri(); - - if (dataURI != null) - { - return new URI(dataURI.getString()); - } - - return null; - } - - public String getFileName() - { - return util.getFileName(); - } - - public String getMediaType() - { - return util.getMediaType(); - } - - public AttributeTable getOtherMetaData() - { - return util.getOtherMetaData(); - } - - public TimeStampToken[] getTimeStampTokens() - throws CMSException - { - return util.getTimeStampTokens(); - } - - /** - * Initialise the passed in calculator with the MetaData for this message, if it is - * required as part of the initial message imprint calculation. - * - * @param calculator the digest calculator to be initialised. - * @throws CMSException if the MetaData is required and cannot be processed - */ - public void initialiseMessageImprintDigestCalculator(DigestCalculator calculator) - throws CMSException - { - util.initialiseMessageImprintDigestCalculator(calculator); - } - - /** - * Returns an appropriately initialised digest calculator based on the message imprint algorithm - * described in the first time stamp in the TemporalData for this message. If the metadata is required - * to be included in the digest calculation, the returned calculator will be pre-initialised. - * - * @param calculatorProvider a provider of DigestCalculator objects. - * @return an initialised digest calculator. - * @throws OperatorCreationException if the provider is unable to create the calculator. - */ - public DigestCalculator getMessageImprintDigestCalculator(DigestCalculatorProvider calculatorProvider) - throws OperatorCreationException - { - return util.getMessageImprintDigestCalculator(calculatorProvider); - } - - /** - * Validate the digests present in the TimeStampTokens contained in the CMSTimeStampedData. - * - * @param calculatorProvider provider for digest calculators - * @param dataDigest the calculated data digest for the message - * @throws ImprintDigestInvalidException if an imprint digest fails to compare - * @throws CMSException if an exception occurs processing the message. - */ - public void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest) - throws ImprintDigestInvalidException, CMSException - { - util.validate(calculatorProvider, dataDigest); - } - - /** - * Validate the passed in timestamp token against the tokens and data present in the message. - * - * @param calculatorProvider provider for digest calculators - * @param dataDigest the calculated data digest for the message. - * @param timeStampToken the timestamp token of interest. - * @throws ImprintDigestInvalidException if the token is not present in the message, or an imprint digest fails to compare. - * @throws CMSException if an exception occurs processing the message. - */ - public void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest, TimeStampToken timeStampToken) - throws ImprintDigestInvalidException, CMSException - { - util.validate(calculatorProvider, dataDigest, timeStampToken); - } - - public byte[] getEncoded() - throws IOException - { - return contentInfo.getEncoded(); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/tsp/cms/CMSTimeStampedDataGenerator.java b/pkix/src/main/java/org/bouncycastle/tsp/cms/CMSTimeStampedDataGenerator.java deleted file mode 100644 index e6f28302..00000000 --- a/pkix/src/main/java/org/bouncycastle/tsp/cms/CMSTimeStampedDataGenerator.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.bouncycastle.tsp.cms; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.BEROctetString; -import org.bouncycastle.asn1.DERIA5String; -import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.cms.Evidence; -import org.bouncycastle.asn1.cms.TimeStampAndCRL; -import org.bouncycastle.asn1.cms.TimeStampTokenEvidence; -import org.bouncycastle.asn1.cms.TimeStampedData; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.tsp.TimeStampToken; -import org.bouncycastle.util.io.Streams; - -public class CMSTimeStampedDataGenerator - extends CMSTimeStampedGenerator -{ - public CMSTimeStampedData generate(TimeStampToken timeStamp) throws CMSException - { - return generate(timeStamp, (InputStream)null); - } - - public CMSTimeStampedData generate(TimeStampToken timeStamp, byte[] content) throws CMSException - { - return generate(timeStamp, new ByteArrayInputStream(content)); - } - - public CMSTimeStampedData generate(TimeStampToken timeStamp, InputStream content) - throws CMSException - { - ByteArrayOutputStream contentOut = new ByteArrayOutputStream(); - - if (content != null) - { - try - { - Streams.pipeAll(content, contentOut); - } - catch (IOException e) - { - throw new CMSException("exception encapsulating content: " + e.getMessage(), e); - } - } - - ASN1OctetString encContent = null; - - if (contentOut.size() != 0) - { - encContent = new BEROctetString(contentOut.toByteArray()); - } - - TimeStampAndCRL stamp = new TimeStampAndCRL(timeStamp.toCMSSignedData().toASN1Structure()); - - DERIA5String asn1DataUri = null; - - if (dataUri != null) - { - asn1DataUri = new DERIA5String(dataUri.toString()); - } - - return new CMSTimeStampedData(new ContentInfo(CMSObjectIdentifiers.timestampedData, new TimeStampedData(asn1DataUri, metaData, encContent, new Evidence(new TimeStampTokenEvidence(stamp))))); - } -} - diff --git a/pkix/src/main/java/org/bouncycastle/tsp/cms/CMSTimeStampedDataParser.java b/pkix/src/main/java/org/bouncycastle/tsp/cms/CMSTimeStampedDataParser.java deleted file mode 100644 index 28c7e87a..00000000 --- a/pkix/src/main/java/org/bouncycastle/tsp/cms/CMSTimeStampedDataParser.java +++ /dev/null @@ -1,207 +0,0 @@ -package org.bouncycastle.tsp.cms; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.net.URISyntaxException; - -import org.bouncycastle.asn1.BERTags; -import org.bouncycastle.asn1.DERIA5String; -import org.bouncycastle.asn1.cms.AttributeTable; -import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; -import org.bouncycastle.asn1.cms.ContentInfoParser; -import org.bouncycastle.asn1.cms.TimeStampedDataParser; -import org.bouncycastle.cms.CMSContentInfoParser; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.operator.DigestCalculator; -import org.bouncycastle.operator.DigestCalculatorProvider; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.tsp.TimeStampToken; -import org.bouncycastle.util.io.Streams; - -public class CMSTimeStampedDataParser - extends CMSContentInfoParser -{ - private TimeStampedDataParser timeStampedData; - private TimeStampDataUtil util; - - public CMSTimeStampedDataParser(InputStream in) - throws CMSException - { - super(in); - - initialize(_contentInfo); - } - - public CMSTimeStampedDataParser(byte[] baseData) - throws CMSException - { - this(new ByteArrayInputStream(baseData)); - } - - private void initialize(ContentInfoParser contentInfo) - throws CMSException - { - try - { - if (CMSObjectIdentifiers.timestampedData.equals(contentInfo.getContentType())) - { - this.timeStampedData = TimeStampedDataParser.getInstance(contentInfo.getContent(BERTags.SEQUENCE)); - } - else - { - throw new IllegalArgumentException("Malformed content - type must be " + CMSObjectIdentifiers.timestampedData.getId()); - } - } - catch (IOException e) - { - throw new CMSException("parsing exception: " + e.getMessage(), e); - } - } - - public byte[] calculateNextHash(DigestCalculator calculator) - throws CMSException - { - return util.calculateNextHash(calculator); - } - - public InputStream getContent() - { - if (timeStampedData.getContent() != null) - { - return timeStampedData.getContent().getOctetStream(); - } - - return null; - } - - public URI getDataUri() - throws URISyntaxException - { - DERIA5String dataURI = this.timeStampedData.getDataUri(); - - if (dataURI != null) - { - return new URI(dataURI.getString()); - } - - return null; - } - - public String getFileName() - { - return util.getFileName(); - } - - public String getMediaType() - { - return util.getMediaType(); - } - - public AttributeTable getOtherMetaData() - { - return util.getOtherMetaData(); - } - - /** - * Initialise the passed in calculator with the MetaData for this message, if it is - * required as part of the initial message imprint calculation. - * - * @param calculator the digest calculator to be initialised. - * @throws CMSException if the MetaData is required and cannot be processed - */ - public void initialiseMessageImprintDigestCalculator(DigestCalculator calculator) - throws CMSException - { - util.initialiseMessageImprintDigestCalculator(calculator); - } - - /** - * Returns an appropriately initialised digest calculator based on the message imprint algorithm - * described in the first time stamp in the TemporalData for this message. If the metadata is required - * to be included in the digest calculation, the returned calculator will be pre-initialised. - * - * @param calculatorProvider a provider of DigestCalculator objects. - * @return an initialised digest calculator. - * @throws OperatorCreationException if the provider is unable to create the calculator. - */ - public DigestCalculator getMessageImprintDigestCalculator(DigestCalculatorProvider calculatorProvider) - throws OperatorCreationException - { - try - { - parseTimeStamps(); - } - catch (CMSException e) - { - throw new OperatorCreationException("unable to extract algorithm ID: " + e.getMessage(), e); - } - - return util.getMessageImprintDigestCalculator(calculatorProvider); - } - - public TimeStampToken[] getTimeStampTokens() - throws CMSException - { - parseTimeStamps(); - - return util.getTimeStampTokens(); - } - - /** - * Validate the digests present in the TimeStampTokens contained in the CMSTimeStampedData. - * - * @param calculatorProvider provider for digest calculators - * @param dataDigest the calculated data digest for the message - * @throws ImprintDigestInvalidException if an imprint digest fails to compare - * @throws CMSException if an exception occurs processing the message. - */ - public void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest) - throws ImprintDigestInvalidException, CMSException - { - parseTimeStamps(); - - util.validate(calculatorProvider, dataDigest); - } - - /** - * Validate the passed in timestamp token against the tokens and data present in the message. - * - * @param calculatorProvider provider for digest calculators - * @param dataDigest the calculated data digest for the message. - * @param timeStampToken the timestamp token of interest. - * @throws ImprintDigestInvalidException if the token is not present in the message, or an imprint digest fails to compare. - * @throws CMSException if an exception occurs processing the message. - */ - public void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest, TimeStampToken timeStampToken) - throws ImprintDigestInvalidException, CMSException - { - parseTimeStamps(); - - util.validate(calculatorProvider, dataDigest, timeStampToken); - } - - private void parseTimeStamps() - throws CMSException - { - try - { - if (util == null) - { - InputStream cont = this.getContent(); - - if (cont != null) - { - Streams.drain(cont); - } - - util = new TimeStampDataUtil(timeStampedData); - } - } - catch (IOException e) - { - throw new CMSException("unable to parse evidence block: " + e.getMessage(), e); - } - } -} diff --git a/pkix/src/main/java/org/bouncycastle/tsp/cms/CMSTimeStampedGenerator.java b/pkix/src/main/java/org/bouncycastle/tsp/cms/CMSTimeStampedGenerator.java deleted file mode 100644 index 5cc88668..00000000 --- a/pkix/src/main/java/org/bouncycastle/tsp/cms/CMSTimeStampedGenerator.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.bouncycastle.tsp.cms; - -import java.net.URI; - -import org.bouncycastle.asn1.ASN1Boolean; -import org.bouncycastle.asn1.DERIA5String; -import org.bouncycastle.asn1.DERUTF8String; -import org.bouncycastle.asn1.cms.Attributes; -import org.bouncycastle.asn1.cms.MetaData; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.operator.DigestCalculator; - -public class CMSTimeStampedGenerator -{ - protected MetaData metaData; - protected URI dataUri; - - /** - * Set the dataURI to be included in message. - * - * @param dataUri URI for the data the initial message imprint digest is based on. - */ - public void setDataUri(URI dataUri) - { - this.dataUri = dataUri; - } - - /** - * Set the MetaData for the generated message. - * - * @param hashProtected true if the MetaData should be included in first imprint calculation, false otherwise. - * @param fileName optional file name, may be null. - * @param mediaType optional media type, may be null. - */ - public void setMetaData(boolean hashProtected, String fileName, String mediaType) - { - setMetaData(hashProtected, fileName, mediaType, null); - } - - /** - * Set the MetaData for the generated message. - * - * @param hashProtected true if the MetaData should be included in first imprint calculation, false otherwise. - * @param fileName optional file name, may be null. - * @param mediaType optional media type, may be null. - * @param attributes optional attributes, may be null. - */ - public void setMetaData(boolean hashProtected, String fileName, String mediaType, Attributes attributes) - { - DERUTF8String asn1FileName = null; - - if (fileName != null) - { - asn1FileName = new DERUTF8String(fileName); - } - - DERIA5String asn1MediaType = null; - - if (mediaType != null) - { - asn1MediaType = new DERIA5String(mediaType); - } - - setMetaData(hashProtected, asn1FileName, asn1MediaType, attributes); - } - - private void setMetaData(boolean hashProtected, DERUTF8String fileName, DERIA5String mediaType, Attributes attributes) - { - this.metaData = new MetaData(ASN1Boolean.getInstance(hashProtected), fileName, mediaType, attributes); - } - - /** - * Initialise the passed in calculator with the MetaData for this message, if it is - * required as part of the initial message imprint calculation. After initialisation the - * calculator can then be used to calculate the initial message imprint digest for the first - * timestamp. - * - * @param calculator the digest calculator to be initialised. - * @throws CMSException if the MetaData is required and cannot be processed - */ - public void initialiseMessageImprintDigestCalculator(DigestCalculator calculator) - throws CMSException - { - MetaDataUtil util = new MetaDataUtil(metaData); - - util.initialiseMessageImprintDigestCalculator(calculator); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/tsp/cms/ImprintDigestInvalidException.java b/pkix/src/main/java/org/bouncycastle/tsp/cms/ImprintDigestInvalidException.java deleted file mode 100644 index 36999978..00000000 --- a/pkix/src/main/java/org/bouncycastle/tsp/cms/ImprintDigestInvalidException.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.bouncycastle.tsp.cms; - -import org.bouncycastle.tsp.TimeStampToken; - -public class ImprintDigestInvalidException - extends Exception -{ - private TimeStampToken token; - - public ImprintDigestInvalidException(String message, TimeStampToken token) - { - super(message); - - this.token = token; - } - - public TimeStampToken getTimeStampToken() - { - return token; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/tsp/cms/MetaDataUtil.java b/pkix/src/main/java/org/bouncycastle/tsp/cms/MetaDataUtil.java deleted file mode 100644 index b52f6699..00000000 --- a/pkix/src/main/java/org/bouncycastle/tsp/cms/MetaDataUtil.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.bouncycastle.tsp.cms; - -import java.io.IOException; - -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.ASN1String; -import org.bouncycastle.asn1.cms.Attributes; -import org.bouncycastle.asn1.cms.MetaData; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.operator.DigestCalculator; - -class MetaDataUtil -{ - private final MetaData metaData; - - MetaDataUtil(MetaData metaData) - { - this.metaData = metaData; - } - - void initialiseMessageImprintDigestCalculator(DigestCalculator calculator) - throws CMSException - { - if (metaData != null && metaData.isHashProtected()) - { - try - { - calculator.getOutputStream().write(metaData.getEncoded(ASN1Encoding.DER)); - } - catch (IOException e) - { - throw new CMSException("unable to initialise calculator from metaData: " + e.getMessage(), e); - } - } - } - - String getFileName() - { - if (metaData != null) - { - return convertString(metaData.getFileName()); - } - - return null; - } - - String getMediaType() - { - if (metaData != null) - { - return convertString(metaData.getMediaType()); - } - - return null; - } - - Attributes getOtherMetaData() - { - if (metaData != null) - { - return metaData.getOtherMetaData(); - } - - return null; - } - - private String convertString(ASN1String s) - { - if (s != null) - { - return s.toString(); - } - - return null; - } -} diff --git a/pkix/src/main/java/org/bouncycastle/tsp/cms/TimeStampDataUtil.java b/pkix/src/main/java/org/bouncycastle/tsp/cms/TimeStampDataUtil.java deleted file mode 100644 index ce115f4e..00000000 --- a/pkix/src/main/java/org/bouncycastle/tsp/cms/TimeStampDataUtil.java +++ /dev/null @@ -1,256 +0,0 @@ -package org.bouncycastle.tsp.cms; - -import java.io.IOException; -import java.io.OutputStream; - -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.cms.AttributeTable; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.cms.Evidence; -import org.bouncycastle.asn1.cms.TimeStampAndCRL; -import org.bouncycastle.asn1.cms.TimeStampedData; -import org.bouncycastle.asn1.cms.TimeStampedDataParser; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.cms.CMSException; -import org.bouncycastle.operator.DigestCalculator; -import org.bouncycastle.operator.DigestCalculatorProvider; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.tsp.TSPException; -import org.bouncycastle.tsp.TimeStampToken; -import org.bouncycastle.tsp.TimeStampTokenInfo; -import org.bouncycastle.util.Arrays; - -class TimeStampDataUtil -{ - private final TimeStampAndCRL[] timeStamps; - - private final MetaDataUtil metaDataUtil; - - TimeStampDataUtil(TimeStampedData timeStampedData) - { - this.metaDataUtil = new MetaDataUtil(timeStampedData.getMetaData()); - - Evidence evidence = timeStampedData.getTemporalEvidence(); - this.timeStamps = evidence.getTstEvidence().toTimeStampAndCRLArray(); - } - - TimeStampDataUtil(TimeStampedDataParser timeStampedData) - throws IOException - { - this.metaDataUtil = new MetaDataUtil(timeStampedData.getMetaData()); - - Evidence evidence = timeStampedData.getTemporalEvidence(); - this.timeStamps = evidence.getTstEvidence().toTimeStampAndCRLArray(); - } - - TimeStampToken getTimeStampToken(TimeStampAndCRL timeStampAndCRL) - throws CMSException - { - ContentInfo timeStampToken = timeStampAndCRL.getTimeStampToken(); - - try - { - TimeStampToken token = new TimeStampToken(timeStampToken); - return token; - } - catch (IOException e) - { - throw new CMSException("unable to parse token data: " + e.getMessage(), e); - } - catch (TSPException e) - { - if (e.getCause() instanceof CMSException) - { - throw (CMSException)e.getCause(); - } - - throw new CMSException("token data invalid: " + e.getMessage(), e); - } - catch (IllegalArgumentException e) - { - throw new CMSException("token data invalid: " + e.getMessage(), e); - } - } - - void initialiseMessageImprintDigestCalculator(DigestCalculator calculator) - throws CMSException - { - metaDataUtil.initialiseMessageImprintDigestCalculator(calculator); - } - - DigestCalculator getMessageImprintDigestCalculator(DigestCalculatorProvider calculatorProvider) - throws OperatorCreationException - { - TimeStampToken token; - - try - { - token = this.getTimeStampToken(timeStamps[0]); - - TimeStampTokenInfo info = token.getTimeStampInfo(); - ASN1ObjectIdentifier algOID = info.getMessageImprintAlgOID(); - - DigestCalculator calc = calculatorProvider.get(new AlgorithmIdentifier(algOID)); - - initialiseMessageImprintDigestCalculator(calc); - - return calc; - } - catch (CMSException e) - { - throw new OperatorCreationException("unable to extract algorithm ID: " + e.getMessage(), e); - } - } - - TimeStampToken[] getTimeStampTokens() - throws CMSException - { - TimeStampToken[] tokens = new TimeStampToken[timeStamps.length]; - for (int i = 0; i < timeStamps.length; i++) - { - tokens[i] = this.getTimeStampToken(timeStamps[i]); - } - - return tokens; - } - - TimeStampAndCRL[] getTimeStamps() - { - return timeStamps; - } - - byte[] calculateNextHash(DigestCalculator calculator) - throws CMSException - { - TimeStampAndCRL tspToken = timeStamps[timeStamps.length - 1]; - - OutputStream out = calculator.getOutputStream(); - - try - { - out.write(tspToken.getEncoded(ASN1Encoding.DER)); - - out.close(); - - return calculator.getDigest(); - } - catch (IOException e) - { - throw new CMSException("exception calculating hash: " + e.getMessage(), e); - } - } - - /** - * Validate the digests present in the TimeStampTokens contained in the CMSTimeStampedData. - */ - void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest) - throws ImprintDigestInvalidException, CMSException - { - byte[] currentDigest = dataDigest; - - for (int i = 0; i < timeStamps.length; i++) - { - try - { - TimeStampToken token = this.getTimeStampToken(timeStamps[i]); - if (i > 0) - { - TimeStampTokenInfo info = token.getTimeStampInfo(); - DigestCalculator calculator = calculatorProvider.get(info.getHashAlgorithm()); - - calculator.getOutputStream().write(timeStamps[i - 1].getEncoded(ASN1Encoding.DER)); - - currentDigest = calculator.getDigest(); - } - - this.compareDigest(token, currentDigest); - } - catch (IOException e) - { - throw new CMSException("exception calculating hash: " + e.getMessage(), e); - } - catch (OperatorCreationException e) - { - throw new CMSException("cannot create digest: " + e.getMessage(), e); - } - } - } - - void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest, TimeStampToken timeStampToken) - throws ImprintDigestInvalidException, CMSException - { - byte[] currentDigest = dataDigest; - byte[] encToken; - - try - { - encToken = timeStampToken.getEncoded(); - } - catch (IOException e) - { - throw new CMSException("exception encoding timeStampToken: " + e.getMessage(), e); - } - - for (int i = 0; i < timeStamps.length; i++) - { - try - { - TimeStampToken token = this.getTimeStampToken(timeStamps[i]); - if (i > 0) - { - TimeStampTokenInfo info = token.getTimeStampInfo(); - DigestCalculator calculator = calculatorProvider.get(info.getHashAlgorithm()); - - calculator.getOutputStream().write(timeStamps[i - 1].getEncoded(ASN1Encoding.DER)); - - currentDigest = calculator.getDigest(); - } - - this.compareDigest(token, currentDigest); - - if (Arrays.areEqual(token.getEncoded(), encToken)) - { - return; - } - } - catch (IOException e) - { - throw new CMSException("exception calculating hash: " + e.getMessage(), e); - } - catch (OperatorCreationException e) - { - throw new CMSException("cannot create digest: " + e.getMessage(), e); - } - } - - throw new ImprintDigestInvalidException("passed in token not associated with timestamps present", timeStampToken); - } - - private void compareDigest(TimeStampToken timeStampToken, byte[] digest) - throws ImprintDigestInvalidException - { - TimeStampTokenInfo info = timeStampToken.getTimeStampInfo(); - byte[] tsrMessageDigest = info.getMessageImprintDigest(); - - if (!Arrays.areEqual(digest, tsrMessageDigest)) - { - throw new ImprintDigestInvalidException("hash calculated is different from MessageImprintDigest found in TimeStampToken", timeStampToken); - } - } - - String getFileName() - { - return metaDataUtil.getFileName(); - } - - String getMediaType() - { - return metaDataUtil.getMediaType(); - } - - AttributeTable getOtherMetaData() - { - return new AttributeTable(metaDataUtil.getOtherMetaData()); - } -} diff --git a/pkix/src/main/java/org/bouncycastle/voms/VOMSAttribute.java b/pkix/src/main/java/org/bouncycastle/voms/VOMSAttribute.java deleted file mode 100644 index 9c062f34..00000000 --- a/pkix/src/main/java/org/bouncycastle/voms/VOMSAttribute.java +++ /dev/null @@ -1,242 +0,0 @@ -package org.bouncycastle.voms; - -import java.util.List; -import java.util.ArrayList; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.DERIA5String; -import org.bouncycastle.asn1.x509.IetfAttrSyntax; -import org.bouncycastle.x509.X509Attribute; -import org.bouncycastle.x509.X509AttributeCertificate; - - -/** - * Representation of the authorization information (VO, server address - * and list of Fully Qualified Attribute Names, or FQANs) contained in - * a VOMS attribute certificate. - */ -public class VOMSAttribute -{ - - /** - * The ASN.1 object identifier for VOMS attributes - */ - public static final String VOMS_ATTR_OID = "1.3.6.1.4.1.8005.100.100.4"; - private X509AttributeCertificate myAC; - private String myHostPort; - private String myVo; - private List myStringList = new ArrayList(); - private List myFQANs = new ArrayList(); - - /** - * Parses the contents of an attribute certificate.<br> - * <b>NOTE:</b> Cryptographic signatures, time stamps etc. will <b>not</b> be checked. - * - * @param ac the attribute certificate to parse for VOMS attributes - */ - public VOMSAttribute(X509AttributeCertificate ac) - { - if (ac == null) - { - throw new IllegalArgumentException("VOMSAttribute: AttributeCertificate is NULL"); - } - - myAC = ac; - - X509Attribute[] l = ac.getAttributes(VOMS_ATTR_OID); - - if (l == null) - { - return; - } - - try - { - for (int i = 0; i != l.length; i++) - { - IetfAttrSyntax attr = IetfAttrSyntax.getInstance(l[i].getValues()[0]); - - // policyAuthority is on the format <vo>/<host>:<port> - String url = ((DERIA5String)attr.getPolicyAuthority().getNames()[0].getName()).getString(); - int idx = url.indexOf("://"); - - if ((idx < 0) || (idx == (url.length() - 1))) - { - throw new IllegalArgumentException("Bad encoding of VOMS policyAuthority : [" + url + "]"); - } - - myVo = url.substring(0, idx); - myHostPort = url.substring(idx + 3); - - if (attr.getValueType() != IetfAttrSyntax.VALUE_OCTETS) - { - throw new IllegalArgumentException( - "VOMS attribute values are not encoded as octet strings, policyAuthority = " + url); - } - - ASN1OctetString[] values = (ASN1OctetString[])attr.getValues(); - for (int j = 0; j != values.length; j++) - { - String fqan = new String(values[j].getOctets()); - FQAN f = new FQAN(fqan); - - if (!myStringList.contains(fqan) && fqan.startsWith("/" + myVo + "/")) - { - myStringList.add(fqan); - myFQANs.add(f); - } - } - } - } - catch (IllegalArgumentException ie) - { - throw ie; - } - catch (Exception e) - { - throw new IllegalArgumentException("Badly encoded VOMS extension in AC issued by " + - ac.getIssuer()); - } - } - - /** - * @return The AttributeCertificate containing the VOMS information - */ - public X509AttributeCertificate getAC() - { - return myAC; - } - - /** - * @return List of String of the VOMS fully qualified - * attributes names (FQANs):<br> - * <code>/vo[/group[/group2...]][/Role=[role]][/Capability=capability]</code> - */ - public List getFullyQualifiedAttributes() - { - return myStringList; - } - - /** - * @return List of FQAN of the VOMS fully qualified - * attributes names (FQANs) - */ - public List getListOfFQAN() - { - return myFQANs; - } - - /** - * Returns the address of the issuing VOMS server, on the form <code><host>:<port></code> - * @return String - */ - public String getHostPort() - { - return myHostPort; - } - - /** - * Returns the VO name - * @return - */ - public String getVO() - { - return myVo; - } - - public String toString() - { - return "VO :" + myVo + "\n" + "HostPort:" + myHostPort + "\n" + "FQANs :" + myFQANs; - } - - /** - * Inner class providing a container of the group,role,capability - * information triplet in an FQAN. - */ - public class FQAN - { - String fqan; - String group; - String role; - String capability; - - public FQAN(String fqan) - { - this.fqan = fqan; - } - - public FQAN(String group, String role, String capability) - { - this.group = group; - this.role = role; - this.capability = capability; - } - - public String getFQAN() - { - if (fqan != null) - { - return fqan; - } - - fqan = group + "/Role=" + ((role != null) ? role : "") + - ((capability != null) ? ("/Capability=" + capability) : ""); - - return fqan; - } - - protected void split() - { - int len = fqan.length(); - int i = fqan.indexOf("/Role="); - - if (i < 0) - { - return; - } - - group = fqan.substring(0, i); - - int j = fqan.indexOf("/Capability=", i + 6); - String s = (j < 0) ? fqan.substring(i + 6) : fqan.substring(i + 6, j); - role = (s.length() == 0) ? null : s; - s = (j < 0) ? null : fqan.substring(j + 12); - capability = ((s == null) || (s.length() == 0)) ? null : s; - } - - public String getGroup() - { - if ((group == null) && (fqan != null)) - { - split(); - } - - return group; - } - - public String getRole() - { - if ((group == null) && (fqan != null)) - { - split(); - } - - return role; - } - - public String getCapability() - { - if ((group == null) && (fqan != null)) - { - split(); - } - - return capability; - } - - public String toString() - { - return getFQAN(); - } - } -} diff --git a/pkix/src/main/java/org/spongycastle/cert/AttributeCertificateHolder.java b/pkix/src/main/java/org/spongycastle/cert/AttributeCertificateHolder.java new file mode 100644 index 00000000..610cdbe7 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/AttributeCertificateHolder.java @@ -0,0 +1,357 @@ +package org.spongycastle.cert; + +import java.io.OutputStream; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.asn1.x509.GeneralNames; +import org.spongycastle.asn1.x509.Holder; +import org.spongycastle.asn1.x509.IssuerSerial; +import org.spongycastle.asn1.x509.ObjectDigestInfo; +import org.spongycastle.operator.DigestCalculator; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.util.Arrays; +import org.spongycastle.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); + } + + public AttributeCertificateHolder(X500Name issuerName, + BigInteger serialNumber) + { + holder = new Holder(new IssuerSerial( + new GeneralNames(new GeneralName(issuerName)), + new ASN1Integer(serialNumber))); + } + + public AttributeCertificateHolder(X509CertificateHolder cert) + { + holder = new Holder(new IssuerSerial(generateGeneralNames(cert.getIssuer()), + new ASN1Integer(cert.getSerialNumber()))); + } + + 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/pkix/src/main/java/org/spongycastle/cert/AttributeCertificateIssuer.java b/pkix/src/main/java/org/spongycastle/cert/AttributeCertificateIssuer.java new file mode 100644 index 00000000..e659e592 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/AttributeCertificateIssuer.java @@ -0,0 +1,147 @@ +package org.spongycastle.cert; + +import java.util.ArrayList; +import java.util.List; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.AttCertIssuer; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.asn1.x509.GeneralNames; +import org.spongycastle.asn1.x509.V2Form; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cert/CertException.java b/pkix/src/main/java/org/spongycastle/cert/CertException.java new file mode 100644 index 00000000..b394ec89 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/CertException.java @@ -0,0 +1,27 @@ +package org.spongycastle.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/pkix/src/main/java/org/spongycastle/cert/CertIOException.java b/pkix/src/main/java/org/spongycastle/cert/CertIOException.java new file mode 100644 index 00000000..f21641d6 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/CertIOException.java @@ -0,0 +1,29 @@ +package org.spongycastle.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/pkix/src/main/java/org/spongycastle/cert/CertRuntimeException.java b/pkix/src/main/java/org/spongycastle/cert/CertRuntimeException.java new file mode 100644 index 00000000..a797083e --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/CertRuntimeException.java @@ -0,0 +1,19 @@ +package org.spongycastle.cert; + +public class CertRuntimeException + extends RuntimeException +{ + private Throwable cause; + + public CertRuntimeException(String msg, Throwable cause) + { + super(msg); + + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cert/CertUtils.java b/pkix/src/main/java/org/spongycastle/cert/CertUtils.java new file mode 100644 index 00000000..d03f7843 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/CertUtils.java @@ -0,0 +1,244 @@ +package org.spongycastle.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 org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1GeneralizedTime; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERBitString; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.DEROutputStream; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.AttributeCertificate; +import org.spongycastle.asn1.x509.AttributeCertificateInfo; +import org.spongycastle.asn1.x509.Certificate; +import org.spongycastle.asn1.x509.CertificateList; +import org.spongycastle.asn1.x509.Extensions; +import org.spongycastle.asn1.x509.ExtensionsGenerator; +import org.spongycastle.asn1.x509.TBSCertList; +import org.spongycastle.asn1.x509.TBSCertificate; +import org.spongycastle.operator.ContentSigner; + +class CertUtils +{ + private static Set EMPTY_SET = Collections.unmodifiableSet(new HashSet()); + private static List EMPTY_LIST = Collections.unmodifiableList(new ArrayList()); + + 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/pkix/src/main/java/org/spongycastle/cert/X509AttributeCertificateHolder.java b/pkix/src/main/java/org/spongycastle/cert/X509AttributeCertificateHolder.java new file mode 100644 index 00000000..76c0cdf9 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/X509AttributeCertificateHolder.java @@ -0,0 +1,366 @@ +package org.spongycastle.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 org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.DEROutputStream; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.AttCertValidityPeriod; +import org.spongycastle.asn1.x509.Attribute; +import org.spongycastle.asn1.x509.AttributeCertificate; +import org.spongycastle.asn1.x509.AttributeCertificateInfo; +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.asn1.x509.Extensions; +import org.spongycastle.operator.ContentVerifier; +import org.spongycastle.operator.ContentVerifierProvider; + +/** + * Holding class for an X.509 AttributeCertificate structure. + */ +public class X509AttributeCertificateHolder +{ + 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(ASN1Primitive.fromByteArray(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().getBytes(); + } + + /** + * 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(attrCert.getSignatureValue().getBytes()); + } + + 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/pkix/src/main/java/org/spongycastle/cert/X509CRLEntryHolder.java b/pkix/src/main/java/org/spongycastle/cert/X509CRLEntryHolder.java new file mode 100644 index 00000000..da542c0e --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/X509CRLEntryHolder.java @@ -0,0 +1,144 @@ +package org.spongycastle.cert; + +import java.math.BigInteger; +import java.util.Date; +import java.util.List; +import java.util.Set; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.asn1.x509.Extensions; +import org.spongycastle.asn1.x509.GeneralNames; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cert/X509CRLHolder.java b/pkix/src/main/java/org/spongycastle/cert/X509CRLHolder.java new file mode 100644 index 00000000..e94c2c1b --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/X509CRLHolder.java @@ -0,0 +1,317 @@ +package org.spongycastle.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 org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DEROutputStream; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.CertificateList; +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.asn1.x509.Extensions; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.asn1.x509.GeneralNames; +import org.spongycastle.asn1.x509.IssuingDistributionPoint; +import org.spongycastle.asn1.x509.TBSCertList; +import org.spongycastle.operator.ContentVerifier; +import org.spongycastle.operator.ContentVerifierProvider; + +/** + * Holding class for an X.509 CRL structure. + */ +public class X509CRLHolder +{ + private CertificateList x509CRL; + private boolean isIndirect; + private Extensions extensions; + private GeneralNames issuerName; + + private static CertificateList parseStream(InputStream stream) + throws IOException + { + try + { + return CertificateList.getInstance(new ASN1InputStream(stream, true).readObject()); + } + 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().getBytes()); + } + + 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/pkix/src/main/java/org/spongycastle/cert/X509CertificateHolder.java b/pkix/src/main/java/org/spongycastle/cert/X509CertificateHolder.java new file mode 100644 index 00000000..fd53b92c --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/X509CertificateHolder.java @@ -0,0 +1,327 @@ +package org.spongycastle.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 org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.DEROutputStream; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.Certificate; +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.asn1.x509.Extensions; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.asn1.x509.TBSCertificate; +import org.spongycastle.operator.ContentVerifier; +import org.spongycastle.operator.ContentVerifierProvider; + +/** + * Holding class for an X.509 Certificate structure. + */ +public class X509CertificateHolder +{ + private Certificate x509Certificate; + private Extensions extensions; + + private static Certificate parseBytes(byte[] certEncoding) + throws IOException + { + try + { + return Certificate.getInstance(ASN1Primitive.fromByteArray(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 X509CertificateStructure 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().getBytes(); + } + + /** + * 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(x509Certificate.getSignature().getBytes()); + } + + 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/pkix/src/main/java/org/spongycastle/cert/X509ContentVerifierProviderBuilder.java b/pkix/src/main/java/org/spongycastle/cert/X509ContentVerifierProviderBuilder.java new file mode 100644 index 00000000..d8429912 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/X509ContentVerifierProviderBuilder.java @@ -0,0 +1,14 @@ +package org.spongycastle.cert; + +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.operator.ContentVerifierProvider; +import org.spongycastle.operator.OperatorCreationException; + +public interface X509ContentVerifierProviderBuilder +{ + ContentVerifierProvider build(SubjectPublicKeyInfo validatingKeyInfo) + throws OperatorCreationException; + + ContentVerifierProvider build(X509CertificateHolder validatingKeyInfo) + throws OperatorCreationException; +} diff --git a/pkix/src/main/java/org/spongycastle/cert/X509ExtensionUtils.java b/pkix/src/main/java/org/spongycastle/cert/X509ExtensionUtils.java new file mode 100644 index 00000000..96e603f8 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/X509ExtensionUtils.java @@ -0,0 +1,132 @@ +package org.spongycastle.cert; + +import java.io.IOException; +import java.io.OutputStream; +import java.math.BigInteger; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.x509.AuthorityKeyIdentifier; +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.asn1.x509.GeneralNames; +import org.spongycastle.asn1.x509.SubjectKeyIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.operator.DigestCalculator; + +/** + * General utility class for creating calculated extensions using the standard methods. + * <p> + * <b>Note:</b> This class is not thread safe! + * </p> + */ +public class X509ExtensionUtils +{ + private DigestCalculator calculator; + + public X509ExtensionUtils(DigestCalculator calculator) + { + this.calculator = calculator; + } + + public AuthorityKeyIdentifier createAuthorityKeyIdentifier( + X509CertificateHolder certHolder) + { + if (certHolder.getVersionNumber() != 3) + { + GeneralName genName = new GeneralName(certHolder.getIssuer()); + SubjectPublicKeyInfo info = certHolder.getSubjectPublicKeyInfo(); + + return new AuthorityKeyIdentifier( + calculateIdentifier(info), new GeneralNames(genName), certHolder.getSerialNumber()); + } + else + { + GeneralName genName = new GeneralName(certHolder.getIssuer()); + Extension ext = certHolder.getExtension(Extension.subjectKeyIdentifier); + + if (ext != null) + { + ASN1OctetString str = ASN1OctetString.getInstance(ext.getParsedValue()); + + return new AuthorityKeyIdentifier( + str.getOctets(), new GeneralNames(genName), certHolder.getSerialNumber()); + } + else + { + SubjectPublicKeyInfo info = certHolder.getSubjectPublicKeyInfo(); + + return new AuthorityKeyIdentifier( + calculateIdentifier(info), new GeneralNames(genName), certHolder.getSerialNumber()); + } + } + } + + public AuthorityKeyIdentifier createAuthorityKeyIdentifier(SubjectPublicKeyInfo publicKeyInfo) + { + return new AuthorityKeyIdentifier(calculateIdentifier(publicKeyInfo)); + } + + public AuthorityKeyIdentifier createAuthorityKeyIdentifier(SubjectPublicKeyInfo publicKeyInfo, GeneralNames generalNames, BigInteger serial) + { + return new AuthorityKeyIdentifier(calculateIdentifier(publicKeyInfo), generalNames, serial); + } + + /** + * Return a RFC 3280 type 1 key identifier. As in: + * <pre> + * (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the + * value of the BIT STRING subjectPublicKey (excluding the tag, + * length, and number of unused bits). + * </pre> + * @param publicKeyInfo the key info object containing the subjectPublicKey field. + * @return the key identifier. + */ + public SubjectKeyIdentifier createSubjectKeyIdentifier( + SubjectPublicKeyInfo publicKeyInfo) + { + return new SubjectKeyIdentifier(calculateIdentifier(publicKeyInfo)); + } + + /** + * Return a RFC 3280 type 2 key identifier. As in: + * <pre> + * (2) The keyIdentifier is composed of a four bit type field with + * the value 0100 followed by the least significant 60 bits of the + * SHA-1 hash of the value of the BIT STRING subjectPublicKey. + * </pre> + * @param publicKeyInfo the key info object containing the subjectPublicKey field. + * @return the key identifier. + */ + public SubjectKeyIdentifier createTruncatedSubjectKeyIdentifier(SubjectPublicKeyInfo publicKeyInfo) + { + byte[] digest = calculateIdentifier(publicKeyInfo); + byte[] id = new byte[8]; + + System.arraycopy(digest, digest.length - 8, id, 0, id.length); + + id[0] &= 0x0f; + id[0] |= 0x40; + + return new SubjectKeyIdentifier(id); + } + + private byte[] calculateIdentifier(SubjectPublicKeyInfo publicKeyInfo) + { + byte[] bytes = publicKeyInfo.getPublicKeyData().getBytes(); + + OutputStream cOut = calculator.getOutputStream(); + + try + { + cOut.write(bytes); + + cOut.close(); + } + catch (IOException e) + { // it's hard to imagine this happening, but yes it does! + throw new CertRuntimeException("unable to calculate identifier: " + e.getMessage(), e); + } + + return calculator.getDigest(); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/X509v1CertificateBuilder.java b/pkix/src/main/java/org/spongycastle/cert/X509v1CertificateBuilder.java new file mode 100644 index 00000000..083e1505 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/X509v1CertificateBuilder.java @@ -0,0 +1,101 @@ +package org.spongycastle.cert; + +import java.math.BigInteger; +import java.util.Date; +import java.util.Locale; + +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.ExtensionsGenerator; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.asn1.x509.Time; +import org.spongycastle.asn1.x509.V1TBSCertificateGenerator; +import org.spongycastle.asn1.x509.V3TBSCertificateGenerator; +import org.spongycastle.operator.ContentSigner; + + +/** + * class to produce an X.509 Version 1 certificate. + */ +public class X509v1CertificateBuilder +{ + private V1TBSCertificateGenerator tbsGen; + + /** + * Create a builder for a version 1 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 X509v1CertificateBuilder(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 1 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 X509v1CertificateBuilder(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 1 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 X509v1CertificateBuilder(X500Name issuer, BigInteger serial, Time notBefore, Time notAfter, X500Name subject, SubjectPublicKeyInfo publicKeyInfo) + { + if (issuer == null) + { + throw new IllegalArgumentException("issuer must not be null"); + } + + if (publicKeyInfo == null) + { + throw new IllegalArgumentException("publicKeyInfo must not be null"); + } + + tbsGen = new V1TBSCertificateGenerator(); + tbsGen.setSerialNumber(new ASN1Integer(serial)); + tbsGen.setIssuer(issuer); + tbsGen.setStartDate(notBefore); + tbsGen.setEndDate(notAfter); + tbsGen.setSubject(subject); + tbsGen.setSubjectPublicKeyInfo(publicKeyInfo); + } + + /** + * Generate an X509 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()); + + return CertUtils.generateFullCert(signer, tbsGen.generateTBSCertificate()); + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cert/X509v2AttributeCertificateBuilder.java b/pkix/src/main/java/org/spongycastle/cert/X509v2AttributeCertificateBuilder.java new file mode 100644 index 00000000..ffdd1567 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/X509v2AttributeCertificateBuilder.java @@ -0,0 +1,162 @@ +package org.spongycastle.cert; + +import java.math.BigInteger; +import java.util.Date; +import java.util.Locale; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1GeneralizedTime; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERSet; +import org.spongycastle.asn1.x509.AttCertIssuer; +import org.spongycastle.asn1.x509.Attribute; +import org.spongycastle.asn1.x509.ExtensionsGenerator; +import org.spongycastle.asn1.x509.V2AttributeCertificateInfoGenerator; +import org.spongycastle.operator.ContentSigner; + +/** + * class to produce an X.509 Version 2 AttributeCertificate. + */ +public class X509v2AttributeCertificateBuilder +{ + private V2AttributeCertificateInfoGenerator acInfoGen; + private ExtensionsGenerator extGenerator; + + /** + * Base constructor. + * + * @param holder holder certificate details + * @param issuer issuer of this attribute certificate. + * @param serialNumber serial number of this attribute certificate. + * @param notBefore the date before which the certificate is not valid. + * @param notAfter the date after which the certificate is not valid. + */ + public X509v2AttributeCertificateBuilder(AttributeCertificateHolder holder, AttributeCertificateIssuer issuer, BigInteger serialNumber, Date notBefore, Date notAfter) + { + acInfoGen = new V2AttributeCertificateInfoGenerator(); + extGenerator = new ExtensionsGenerator(); + + acInfoGen.setHolder(holder.holder); + acInfoGen.setIssuer(AttCertIssuer.getInstance(issuer.form)); + acInfoGen.setSerialNumber(new ASN1Integer(serialNumber)); + acInfoGen.setStartDate(new ASN1GeneralizedTime(notBefore)); + acInfoGen.setEndDate(new ASN1GeneralizedTime(notAfter)); + } + + /** + * Base constructor with locale for interpreting dates. You may need to use this constructor if the default locale + * doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations. + * + * @param holder holder certificate details + * @param issuer issuer of this attribute certificate. + * @param serialNumber serial number of this attribute certificate. + * @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. + */ + public X509v2AttributeCertificateBuilder(AttributeCertificateHolder holder, AttributeCertificateIssuer issuer, BigInteger serialNumber, Date notBefore, Date notAfter, Locale dateLocale) + { + acInfoGen = new V2AttributeCertificateInfoGenerator(); + extGenerator = new ExtensionsGenerator(); + + acInfoGen.setHolder(holder.holder); + acInfoGen.setIssuer(AttCertIssuer.getInstance(issuer.form)); + acInfoGen.setSerialNumber(new ASN1Integer(serialNumber)); + acInfoGen.setStartDate(new ASN1GeneralizedTime(notBefore, dateLocale)); + acInfoGen.setEndDate(new ASN1GeneralizedTime(notAfter, dateLocale)); + } + + /** + * Add an attribute to the certification request we are building. + * + * @param attrType the OID giving the type of the attribute. + * @param attrValue the ASN.1 structure that forms the value of the attribute. + * @return this builder object. + */ + public X509v2AttributeCertificateBuilder addAttribute(ASN1ObjectIdentifier attrType, ASN1Encodable attrValue) + { + acInfoGen.addAttribute(new Attribute(attrType, new DERSet(attrValue))); + + return this; + } + + /** + * Add an attribute with multiple values to the certification request we are building. + * + * @param attrType the OID giving the type of the attribute. + * @param attrValues an array of ASN.1 structures that form the value of the attribute. + * @return this builder object. + */ + public X509v2AttributeCertificateBuilder addAttribute(ASN1ObjectIdentifier attrType, ASN1Encodable[] attrValues) + { + acInfoGen.addAttribute(new Attribute(attrType, new DERSet(attrValues))); + + return this; + } + + public void setIssuerUniqueId( + boolean[] iui) + { + acInfoGen.setIssuerUniqueID(CertUtils.booleanToBitString(iui)); + } + + /** + * Add a given extension field for the standard extensions tag + * + * @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 X509v2AttributeCertificateBuilder 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) 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 X509v2AttributeCertificateBuilder addExtension( + ASN1ObjectIdentifier oid, + boolean isCritical, + byte[] encodedValue) + throws CertIOException + { + extGenerator.addExtension(oid, isCritical, encodedValue); + + return this; + } + + /** + * Generate an X509 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 X509AttributeCertificateHolder build( + ContentSigner signer) + { + acInfoGen.setSignature(signer.getAlgorithmIdentifier()); + + if (!extGenerator.isEmpty()) + { + acInfoGen.setExtensions(extGenerator.generate()); + } + + return CertUtils.generateFullAttrCert(signer, acInfoGen.generateAttributeCertificateInfo()); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/X509v2CRLBuilder.java b/pkix/src/main/java/org/spongycastle/cert/X509v2CRLBuilder.java new file mode 100644 index 00000000..69cb2406 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/X509v2CRLBuilder.java @@ -0,0 +1,266 @@ +package org.spongycastle.cert; + +import java.math.BigInteger; +import java.util.Date; +import java.util.Enumeration; +import java.util.Locale; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1GeneralizedTime; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.Extensions; +import org.spongycastle.asn1.x509.ExtensionsGenerator; +import org.spongycastle.asn1.x509.TBSCertList; +import org.spongycastle.asn1.x509.Time; +import org.spongycastle.asn1.x509.V2TBSCertListGenerator; +import org.spongycastle.asn1.x509.X509Extensions; +import org.spongycastle.operator.ContentSigner; + +/** + * class to produce an X.509 Version 2 CRL. + */ +public class X509v2CRLBuilder +{ + private V2TBSCertListGenerator tbsGen; + private ExtensionsGenerator extGenerator; + + /** + * Basic constructor. + * + * @param issuer the issuer this CRL is associated with. + * @param thisUpdate the date of this update. + */ + public X509v2CRLBuilder( + X500Name issuer, + Date thisUpdate) + { + tbsGen = new V2TBSCertListGenerator(); + extGenerator = new ExtensionsGenerator(); + + tbsGen.setIssuer(issuer); + tbsGen.setThisUpdate(new Time(thisUpdate)); + } + + /** + * Basic constructor with Locale. 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 issuer this CRL is associated with. + * @param thisUpdate the date of this update. + * @param dateLocale locale to be used for date interpretation. + */ + public X509v2CRLBuilder( + X500Name issuer, + Date thisUpdate, + Locale dateLocale) + { + tbsGen = new V2TBSCertListGenerator(); + extGenerator = new ExtensionsGenerator(); + + tbsGen.setIssuer(issuer); + tbsGen.setThisUpdate(new Time(thisUpdate, dateLocale)); + } + + /** + * Basic constructor. + * + * @param issuer the issuer this CRL is associated with. + * @param thisUpdate the Time of this update. + */ + public X509v2CRLBuilder( + X500Name issuer, + Time thisUpdate) + { + tbsGen = new V2TBSCertListGenerator(); + extGenerator = new ExtensionsGenerator(); + + tbsGen.setIssuer(issuer); + tbsGen.setThisUpdate(thisUpdate); + } + + /** + * Set the date by which the next CRL will become available. + * + * @param date date of next CRL update. + * @return the current builder. + */ + public X509v2CRLBuilder setNextUpdate( + Date date) + { + return this.setNextUpdate(new Time(date)); + } + + /** + * Set the date by which the next CRL will become available. + * + * @param date date of next CRL update. + * @param dateLocale locale to be used for date interpretation. + * @return the current builder. + */ + public X509v2CRLBuilder setNextUpdate( + Date date, + Locale dateLocale) + { + return this.setNextUpdate(new Time(date, dateLocale)); + } + + /** + * Set the date by which the next CRL will become available. + * + * @param date date of next CRL update. + * @return the current builder. + */ + public X509v2CRLBuilder setNextUpdate( + Time date) + { + tbsGen.setNextUpdate(date); + + return this; + } + + /** + * Add a CRL entry with the just reasonCode extension. + * + * @param userCertificateSerial serial number of revoked certificate. + * @param revocationDate date of certificate revocation. + * @param reason the reason code, as indicated in CRLReason, i.e CRLReason.keyCompromise, or 0 if not to be used. + * @return the current builder. + */ + public X509v2CRLBuilder addCRLEntry(BigInteger userCertificateSerial, Date revocationDate, int reason) + { + tbsGen.addCRLEntry(new ASN1Integer(userCertificateSerial), new Time(revocationDate), reason); + + return this; + } + + /** + * Add a CRL entry with an invalidityDate extension as well as a reasonCode extension. This is used + * where the date of revocation might be after issues with the certificate may have occurred. + * + * @param userCertificateSerial serial number of revoked certificate. + * @param revocationDate date of certificate revocation. + * @param reason the reason code, as indicated in CRLReason, i.e CRLReason.keyCompromise, or 0 if not to be used. + * @param invalidityDate the date on which the private key for the certificate became compromised or the certificate otherwise became invalid. + * @return the current builder. + */ + public X509v2CRLBuilder addCRLEntry(BigInteger userCertificateSerial, Date revocationDate, int reason, Date invalidityDate) + { + tbsGen.addCRLEntry(new ASN1Integer(userCertificateSerial), new Time(revocationDate), reason, new ASN1GeneralizedTime(invalidityDate)); + + return this; + } + + /** + * Add a CRL entry with extensions. + * + * @param userCertificateSerial serial number of revoked certificate. + * @param revocationDate date of certificate revocation. + * @param extensions extension set to be associated with this CRLEntry. + * @return the current builder. + * @deprecated use method taking Extensions + */ + public X509v2CRLBuilder addCRLEntry(BigInteger userCertificateSerial, Date revocationDate, X509Extensions extensions) + { + tbsGen.addCRLEntry(new ASN1Integer(userCertificateSerial), new Time(revocationDate), Extensions.getInstance(extensions)); + + return this; + } + + /** + * Add a CRL entry with extensions. + * + * @param userCertificateSerial serial number of revoked certificate. + * @param revocationDate date of certificate revocation. + * @param extensions extension set to be associated with this CRLEntry. + * @return the current builder. + */ + public X509v2CRLBuilder addCRLEntry(BigInteger userCertificateSerial, Date revocationDate, Extensions extensions) + { + tbsGen.addCRLEntry(new ASN1Integer(userCertificateSerial), new Time(revocationDate), extensions); + + return this; + } + + /** + * Add the CRLEntry objects contained in a previous CRL. + * + * @param other the X509CRLHolder to source the other entries from. + * @return the current builder. + */ + public X509v2CRLBuilder addCRL(X509CRLHolder other) + { + TBSCertList revocations = other.toASN1Structure().getTBSCertList(); + + if (revocations != null) + { + for (Enumeration en = revocations.getRevokedCertificateEnumeration(); en.hasMoreElements();) + { + tbsGen.addCRLEntry(ASN1Sequence.getInstance(((ASN1Encodable)en.nextElement()).toASN1Primitive())); + } + } + + 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 X509v2CRLBuilder 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) 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 X509v2CRLBuilder addExtension( + ASN1ObjectIdentifier oid, + boolean isCritical, + byte[] encodedValue) + throws CertIOException + { + extGenerator.addExtension(oid, isCritical, encodedValue); + + return this; + } + + /** + * Generate an X.509 CRL, 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 X509CRLHolder build( + ContentSigner signer) + { + tbsGen.setSignature(signer.getAlgorithmIdentifier()); + + if (!extGenerator.isEmpty()) + { + tbsGen.setExtensions(extGenerator.generate()); + } + + return CertUtils.generateFullCRL(signer, tbsGen.generateTBSCertList()); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/X509v3CertificateBuilder.java b/pkix/src/main/java/org/spongycastle/cert/X509v3CertificateBuilder.java new file mode 100644 index 00000000..0b55b2aa --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/X509v3CertificateBuilder.java @@ -0,0 +1,195 @@ +package org.spongycastle.cert; + +import java.math.BigInteger; +import java.util.Date; +import java.util.Locale; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.Certificate; +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.asn1.x509.ExtensionsGenerator; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.asn1.x509.Time; +import org.spongycastle.asn1.x509.V3TBSCertificateGenerator; +import org.spongycastle.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) 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/pkix/src/main/java/org/spongycastle/cert/bc/BcX509ExtensionUtils.java b/pkix/src/main/java/org/spongycastle/cert/bc/BcX509ExtensionUtils.java new file mode 100644 index 00000000..6d4dc217 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/bc/BcX509ExtensionUtils.java @@ -0,0 +1,91 @@ +package org.spongycastle.cert.bc; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.AuthorityKeyIdentifier; +import org.spongycastle.asn1.x509.SubjectKeyIdentifier; +import org.spongycastle.cert.X509ExtensionUtils; +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.params.AsymmetricKeyParameter; +import org.spongycastle.crypto.util.SubjectPublicKeyInfoFactory; +import org.spongycastle.operator.DigestCalculator; + +public class BcX509ExtensionUtils + extends X509ExtensionUtils +{ + /** + * Create a utility class pre-configured with a SHA-1 digest calculator based on the + * BC implementation. + */ + public BcX509ExtensionUtils() + { + super(new SHA1DigestCalculator()); + } + + public BcX509ExtensionUtils(DigestCalculator calculator) + { + super(calculator); + } + + public AuthorityKeyIdentifier createAuthorityKeyIdentifier( + AsymmetricKeyParameter publicKey) + throws IOException + { + return super.createAuthorityKeyIdentifier(SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKey)); + } + + /** + * Return a RFC 3280 type 1 key identifier. As in: + * <pre> + * (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the + * value of the BIT STRING subjectPublicKey (excluding the tag, + * length, and number of unused bits). + * </pre> + * @param publicKey the key object containing the key identifier is to be based on. + * @return the key identifier. + */ + public SubjectKeyIdentifier createSubjectKeyIdentifier( + AsymmetricKeyParameter publicKey) + throws IOException + { + return super.createSubjectKeyIdentifier(SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKey)); + } + + private static class SHA1DigestCalculator + implements DigestCalculator + { + private ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1); + } + + public OutputStream getOutputStream() + { + return bOut; + } + + public byte[] getDigest() + { + byte[] bytes = bOut.toByteArray(); + + bOut.reset(); + + Digest sha1 = new SHA1Digest(); + + sha1.update(bytes, 0, bytes.length); + + byte[] digest = new byte[sha1.getDigestSize()]; + + sha1.doFinal(digest, 0); + + return digest; + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/bc/BcX509v1CertificateBuilder.java b/pkix/src/main/java/org/spongycastle/cert/bc/BcX509v1CertificateBuilder.java new file mode 100644 index 00000000..2036d5d5 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/bc/BcX509v1CertificateBuilder.java @@ -0,0 +1,33 @@ +package org.spongycastle.cert.bc; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.Date; + +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.cert.X509v1CertificateBuilder; +import org.spongycastle.crypto.params.AsymmetricKeyParameter; +import org.spongycastle.crypto.util.SubjectPublicKeyInfoFactory; + +/** + * JCA helper class to allow BC lightweight objects to be used in the construction of a Version 1 certificate. + */ +public class BcX509v1CertificateBuilder + extends X509v1CertificateBuilder +{ + /** + * Initialise the builder using an AsymmetricKeyParameter. + * + * @param issuer X500Name representing the issuer of this certificate. + * @param serial the serial number for the certificate. + * @param notBefore date before which the certificate is not valid. + * @param notAfter date after which the certificate is not valid. + * @param subject X500Name representing the subject of this certificate. + * @param publicKey the public key to be associated with the certificate. + */ + public BcX509v1CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, AsymmetricKeyParameter publicKey) + throws IOException + { + super(issuer, serial, notBefore, notAfter, subject, SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKey)); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/bc/BcX509v3CertificateBuilder.java b/pkix/src/main/java/org/spongycastle/cert/bc/BcX509v3CertificateBuilder.java new file mode 100644 index 00000000..28264101 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/bc/BcX509v3CertificateBuilder.java @@ -0,0 +1,51 @@ +package org.spongycastle.cert.bc; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.Date; + +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.cert.X509v3CertificateBuilder; +import org.spongycastle.crypto.params.AsymmetricKeyParameter; +import org.spongycastle.crypto.util.SubjectPublicKeyInfoFactory; + +/** + * JCA helper class to allow BC lightweight objects to be used in the construction of a Version 3 certificate. + */ +public class BcX509v3CertificateBuilder + extends X509v3CertificateBuilder +{ + /** + * Initialise the builder using a PublicKey. + * + * @param issuer X500Name representing the issuer of this certificate. + * @param serial the serial number for the certificate. + * @param notBefore date before which the certificate is not valid. + * @param notAfter date after which the certificate is not valid. + * @param subject X500Name representing the subject of this certificate. + * @param publicKey the public key to be associated with the certificate. + */ + public BcX509v3CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, AsymmetricKeyParameter publicKey) + throws IOException + { + super(issuer, serial, notBefore, notAfter, subject, SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKey)); + } + + /** + * Initialise the builder using the subject from the passed in issuerCert as the issuer, as well as + * passing through and converting the other objects provided. + * + * @param issuerCert holder for certificate who's subject is the issuer of the certificate we are building. + * @param serial the serial number for the certificate. + * @param notBefore date before which the certificate is not valid. + * @param notAfter date after which the certificate is not valid. + * @param subject principal representing the subject of this certificate. + * @param publicKey the public key to be associated with the certificate. + */ + public BcX509v3CertificateBuilder(X509CertificateHolder issuerCert, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, AsymmetricKeyParameter publicKey) + throws IOException + { + super(issuerCert.getSubject(), serial, notBefore, notAfter, subject, SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKey)); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/cmp/CMPException.java b/pkix/src/main/java/org/spongycastle/cert/cmp/CMPException.java new file mode 100644 index 00000000..dc02a03b --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/cmp/CMPException.java @@ -0,0 +1,24 @@ +package org.spongycastle.cert.cmp; + +public class CMPException + extends Exception +{ + private Throwable cause; + + public CMPException(String msg, Throwable cause) + { + super(msg); + + this.cause = cause; + } + + public CMPException(String msg) + { + super(msg); + } + + public Throwable getCause() + { + return cause; + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cert/cmp/CMPRuntimeException.java b/pkix/src/main/java/org/spongycastle/cert/cmp/CMPRuntimeException.java new file mode 100644 index 00000000..07f5b819 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/cmp/CMPRuntimeException.java @@ -0,0 +1,19 @@ +package org.spongycastle.cert.cmp; + +public class CMPRuntimeException + extends RuntimeException +{ + private Throwable cause; + + public CMPRuntimeException(String msg, Throwable cause) + { + super(msg); + + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cert/cmp/CMPUtil.java b/pkix/src/main/java/org/spongycastle/cert/cmp/CMPUtil.java new file mode 100644 index 00000000..6198ca84 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/cmp/CMPUtil.java @@ -0,0 +1,26 @@ +package org.spongycastle.cert.cmp; + +import java.io.IOException; +import java.io.OutputStream; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.DEROutputStream; + +class CMPUtil +{ + static void derEncodeToStream(ASN1Encodable obj, OutputStream stream) + { + DEROutputStream dOut = new DEROutputStream(stream); + + try + { + dOut.writeObject(obj); + + dOut.close(); + } + catch (IOException e) + { + throw new CMPRuntimeException("unable to DER encode object: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/cmp/CertificateConfirmationContent.java b/pkix/src/main/java/org/spongycastle/cert/cmp/CertificateConfirmationContent.java new file mode 100644 index 00000000..0f860341 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/cmp/CertificateConfirmationContent.java @@ -0,0 +1,41 @@ +package org.spongycastle.cert.cmp; + +import org.spongycastle.asn1.cmp.CertConfirmContent; +import org.spongycastle.asn1.cmp.CertStatus; +import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder; +import org.spongycastle.operator.DigestAlgorithmIdentifierFinder; + +public class CertificateConfirmationContent +{ + private DigestAlgorithmIdentifierFinder digestAlgFinder; + private CertConfirmContent content; + + public CertificateConfirmationContent(CertConfirmContent content) + { + this(content, new DefaultDigestAlgorithmIdentifierFinder()); + } + + public CertificateConfirmationContent(CertConfirmContent content, DigestAlgorithmIdentifierFinder digestAlgFinder) + { + this.digestAlgFinder = digestAlgFinder; + this.content = content; + } + + public CertConfirmContent toASN1Structure() + { + return content; + } + + public CertificateStatus[] getStatusMessages() + { + CertStatus[] statusArray = content.toCertStatusArray(); + CertificateStatus[] ret = new CertificateStatus[statusArray.length]; + + for (int i = 0; i != ret.length; i++) + { + ret[i] = new CertificateStatus(digestAlgFinder, statusArray[i]); + } + + return ret; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/cmp/CertificateConfirmationContentBuilder.java b/pkix/src/main/java/org/spongycastle/cert/cmp/CertificateConfirmationContentBuilder.java new file mode 100644 index 00000000..106b3e24 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/cmp/CertificateConfirmationContentBuilder.java @@ -0,0 +1,78 @@ +package org.spongycastle.cert.cmp; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.cmp.CertConfirmContent; +import org.spongycastle.asn1.cmp.CertStatus; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder; +import org.spongycastle.operator.DigestAlgorithmIdentifierFinder; +import org.spongycastle.operator.DigestCalculator; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.operator.OperatorCreationException; + +public class CertificateConfirmationContentBuilder +{ + private DigestAlgorithmIdentifierFinder digestAlgFinder; + private List acceptedCerts = new ArrayList(); + private List acceptedReqIds = new ArrayList(); + + public CertificateConfirmationContentBuilder() + { + this(new DefaultDigestAlgorithmIdentifierFinder()); + } + + public CertificateConfirmationContentBuilder(DigestAlgorithmIdentifierFinder digestAlgFinder) + { + this.digestAlgFinder = digestAlgFinder; + } + + public CertificateConfirmationContentBuilder addAcceptedCertificate(X509CertificateHolder certHolder, BigInteger certReqID) + { + acceptedCerts.add(certHolder); + acceptedReqIds.add(certReqID); + + return this; + } + + public CertificateConfirmationContent build(DigestCalculatorProvider digesterProvider) + throws CMPException + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (int i = 0; i != acceptedCerts.size(); i++) + { + X509CertificateHolder certHolder = (X509CertificateHolder)acceptedCerts.get(i); + BigInteger reqID = (BigInteger)acceptedReqIds.get(i); + + AlgorithmIdentifier digAlg = digestAlgFinder.find(certHolder.toASN1Structure().getSignatureAlgorithm()); + if (digAlg == null) + { + throw new CMPException("cannot find algorithm for digest from signature"); + } + + DigestCalculator digester; + + try + { + digester = digesterProvider.get(digAlg); + } + catch (OperatorCreationException e) + { + throw new CMPException("unable to create digest: " + e.getMessage(), e); + } + + CMPUtil.derEncodeToStream(certHolder.toASN1Structure(), digester.getOutputStream()); + + v.add(new CertStatus(digester.getDigest(), reqID)); + } + + return new CertificateConfirmationContent(CertConfirmContent.getInstance(new DERSequence(v)), digestAlgFinder); + } + +} diff --git a/pkix/src/main/java/org/spongycastle/cert/cmp/CertificateStatus.java b/pkix/src/main/java/org/spongycastle/cert/cmp/CertificateStatus.java new file mode 100644 index 00000000..f2923878 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/cmp/CertificateStatus.java @@ -0,0 +1,60 @@ +package org.spongycastle.cert.cmp; + +import java.math.BigInteger; + +import org.spongycastle.asn1.cmp.CertStatus; +import org.spongycastle.asn1.cmp.PKIStatusInfo; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.operator.DigestAlgorithmIdentifierFinder; +import org.spongycastle.operator.DigestCalculator; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.util.Arrays; + +public class CertificateStatus +{ + private DigestAlgorithmIdentifierFinder digestAlgFinder; + private CertStatus certStatus; + + CertificateStatus(DigestAlgorithmIdentifierFinder digestAlgFinder, CertStatus certStatus) + { + this.digestAlgFinder = digestAlgFinder; + this.certStatus = certStatus; + } + + public PKIStatusInfo getStatusInfo() + { + return certStatus.getStatusInfo(); + } + + public BigInteger getCertRequestID() + { + return certStatus.getCertReqId().getValue(); + } + + public boolean isVerified(X509CertificateHolder certHolder, DigestCalculatorProvider digesterProvider) + throws CMPException + { + AlgorithmIdentifier digAlg = digestAlgFinder.find(certHolder.toASN1Structure().getSignatureAlgorithm()); + if (digAlg == null) + { + throw new CMPException("cannot find algorithm for digest from signature"); + } + + DigestCalculator digester; + + try + { + digester = digesterProvider.get(digAlg); + } + catch (OperatorCreationException e) + { + throw new CMPException("unable to create digester: " + e.getMessage(), e); + } + + CMPUtil.derEncodeToStream(certHolder.toASN1Structure(), digester.getOutputStream()); + + return Arrays.areEqual(certStatus.getCertHash().getOctets(), digester.getDigest()); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/cmp/GeneralPKIMessage.java b/pkix/src/main/java/org/spongycastle/cert/cmp/GeneralPKIMessage.java new file mode 100644 index 00000000..5bd49907 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/cmp/GeneralPKIMessage.java @@ -0,0 +1,82 @@ +package org.spongycastle.cert.cmp; + +import java.io.IOException; + +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.cmp.PKIBody; +import org.spongycastle.asn1.cmp.PKIHeader; +import org.spongycastle.asn1.cmp.PKIMessage; +import org.spongycastle.cert.CertIOException; + +/** + * General wrapper for a generic PKIMessage + */ +public class GeneralPKIMessage +{ + private final PKIMessage pkiMessage; + + private static PKIMessage parseBytes(byte[] encoding) + throws IOException + { + try + { + return PKIMessage.getInstance(ASN1Primitive.fromByteArray(encoding)); + } + catch (ClassCastException e) + { + throw new CertIOException("malformed data: " + e.getMessage(), e); + } + catch (IllegalArgumentException e) + { + throw new CertIOException("malformed data: " + e.getMessage(), e); + } + } + + /** + * Create a PKIMessage from the passed in bytes. + * + * @param encoding BER/DER encoding of the PKIMessage + * @throws IOException in the event of corrupted data, or an incorrect structure. + */ + public GeneralPKIMessage(byte[] encoding) + throws IOException + { + this(parseBytes(encoding)); + } + + /** + * Wrap a PKIMessage ASN.1 structure. + * + * @param pkiMessage base PKI message. + */ + public GeneralPKIMessage(PKIMessage pkiMessage) + { + this.pkiMessage = pkiMessage; + } + + public PKIHeader getHeader() + { + return pkiMessage.getHeader(); + } + + public PKIBody getBody() + { + return pkiMessage.getBody(); + } + + /** + * Return true if this message has protection bits on it. A return value of true + * indicates the message can be used to construct a ProtectedPKIMessage. + * + * @return true if message has protection, false otherwise. + */ + public boolean hasProtection() + { + return pkiMessage.getHeader().getProtectionAlg() != null; + } + + public PKIMessage toASN1Structure() + { + return pkiMessage; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessage.java b/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessage.java new file mode 100644 index 00000000..b5dbb980 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessage.java @@ -0,0 +1,198 @@ +package org.spongycastle.cert.cmp; + +import java.io.IOException; +import java.io.OutputStream; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.cmp.CMPCertificate; +import org.spongycastle.asn1.cmp.CMPObjectIdentifiers; +import org.spongycastle.asn1.cmp.PBMParameter; +import org.spongycastle.asn1.cmp.PKIBody; +import org.spongycastle.asn1.cmp.PKIHeader; +import org.spongycastle.asn1.cmp.PKIMessage; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.cert.crmf.PKMACBuilder; +import org.spongycastle.operator.ContentVerifier; +import org.spongycastle.operator.ContentVerifierProvider; +import org.spongycastle.operator.MacCalculator; +import org.spongycastle.util.Arrays; + +/** + * Wrapper for a PKIMessage with protection attached to it. + */ +public class ProtectedPKIMessage +{ + private PKIMessage pkiMessage; + + /** + * Base constructor. + * + * @param pkiMessage a GeneralPKIMessage with + */ + public ProtectedPKIMessage(GeneralPKIMessage pkiMessage) + { + if (!pkiMessage.hasProtection()) + { + throw new IllegalArgumentException("PKIMessage not protected"); + } + + this.pkiMessage = pkiMessage.toASN1Structure(); + } + + ProtectedPKIMessage(PKIMessage pkiMessage) + { + if (pkiMessage.getHeader().getProtectionAlg() == null) + { + throw new IllegalArgumentException("PKIMessage not protected"); + } + + this.pkiMessage = pkiMessage; + } + + /** + * Return the message header. + * + * @return the message's PKIHeader structure. + */ + public PKIHeader getHeader() + { + return pkiMessage.getHeader(); + } + + /** + * Return the message body. + * + * @return the message's PKIBody structure. + */ + public PKIBody getBody() + { + return pkiMessage.getBody(); + } + + /** + * Return the underlying ASN.1 structure contained in this object. + * + * @return a PKIMessage structure. + */ + public PKIMessage toASN1Structure() + { + return pkiMessage; + } + + /** + * Determine whether the message is protected by a password based MAC. Use verify(PKMACBuilder, char[]) + * to verify the message if this method returns true. + * + * @return true if protection MAC PBE based, false otherwise. + */ + public boolean hasPasswordBasedMacProtection() + { + return pkiMessage.getHeader().getProtectionAlg().getAlgorithm().equals(CMPObjectIdentifiers.passwordBasedMac); + } + + /** + * Return the extra certificates associated with this message. + * + * @return an array of extra certificates, zero length if none present. + */ + public X509CertificateHolder[] getCertificates() + { + CMPCertificate[] certs = pkiMessage.getExtraCerts(); + + if (certs == null) + { + return new X509CertificateHolder[0]; + } + + X509CertificateHolder[] res = new X509CertificateHolder[certs.length]; + for (int i = 0; i != certs.length; i++) + { + res[i] = new X509CertificateHolder(certs[i].getX509v3PKCert()); + } + + return res; + } + + /** + * Verify a message with a public key based signature attached. + * + * @param verifierProvider a provider of signature verifiers. + * @return true if the provider is able to create a verifier that validates + * the signature, false otherwise. + * @throws CMPException if an exception is thrown trying to verify the signature. + */ + public boolean verify(ContentVerifierProvider verifierProvider) + throws CMPException + { + ContentVerifier verifier; + try + { + verifier = verifierProvider.get(pkiMessage.getHeader().getProtectionAlg()); + + return verifySignature(pkiMessage.getProtection().getBytes(), verifier); + } + catch (Exception e) + { + throw new CMPException("unable to verify signature: " + e.getMessage(), e); + } + } + + /** + * Verify a message with password based MAC protection. + * + * @param pkMacBuilder MAC builder that can be used to construct the appropriate MacCalculator + * @param password the MAC password + * @return true if the passed in password and MAC builder verify the message, false otherwise. + * @throws CMPException if algorithm not MAC based, or an exception is thrown verifying the MAC. + */ + public boolean verify(PKMACBuilder pkMacBuilder, char[] password) + throws CMPException + { + if (!CMPObjectIdentifiers.passwordBasedMac.equals(pkiMessage.getHeader().getProtectionAlg().getAlgorithm())) + { + throw new CMPException("protection algorithm not mac based"); + } + + try + { + pkMacBuilder.setParameters(PBMParameter.getInstance(pkiMessage.getHeader().getProtectionAlg().getParameters())); + MacCalculator calculator = pkMacBuilder.build(password); + + OutputStream macOut = calculator.getOutputStream(); + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(pkiMessage.getHeader()); + v.add(pkiMessage.getBody()); + + macOut.write(new DERSequence(v).getEncoded(ASN1Encoding.DER)); + + macOut.close(); + + return Arrays.areEqual(calculator.getMac(), pkiMessage.getProtection().getBytes()); + } + catch (Exception e) + { + throw new CMPException("unable to verify MAC: " + e.getMessage(), e); + } + } + + private boolean verifySignature(byte[] signature, ContentVerifier verifier) + throws IOException + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(pkiMessage.getHeader()); + v.add(pkiMessage.getBody()); + + OutputStream sOut = verifier.getOutputStream(); + + sOut.write(new DERSequence(v).getEncoded(ASN1Encoding.DER)); + + sOut.close(); + + return verifier.verify(signature); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessageBuilder.java b/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessageBuilder.java new file mode 100644 index 00000000..8d5228d1 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessageBuilder.java @@ -0,0 +1,306 @@ +package org.spongycastle.cert.cmp; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1GeneralizedTime; +import org.spongycastle.asn1.DERBitString; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.cmp.CMPCertificate; +import org.spongycastle.asn1.cmp.InfoTypeAndValue; +import org.spongycastle.asn1.cmp.PKIBody; +import org.spongycastle.asn1.cmp.PKIFreeText; +import org.spongycastle.asn1.cmp.PKIHeader; +import org.spongycastle.asn1.cmp.PKIHeaderBuilder; +import org.spongycastle.asn1.cmp.PKIMessage; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.operator.ContentSigner; +import org.spongycastle.operator.MacCalculator; + +/** + * Builder for creating a protected PKI message. + */ +public class ProtectedPKIMessageBuilder +{ + private PKIHeaderBuilder hdrBuilder; + private PKIBody body; + private List generalInfos = new ArrayList(); + private List extraCerts = new ArrayList(); + + /** + * Commence a message with the header version CMP_2000. + * + * @param sender message sender. + * @param recipient intended recipient. + */ + public ProtectedPKIMessageBuilder(GeneralName sender, GeneralName recipient) + { + this(PKIHeader.CMP_2000, sender, recipient); + } + + /** + * Commence a message with a specific header type. + * + * @param pvno the version CMP_1999 or CMP_2000. + * @param sender message sender. + * @param recipient intended recipient. + */ + public ProtectedPKIMessageBuilder(int pvno, GeneralName sender, GeneralName recipient) + { + hdrBuilder = new PKIHeaderBuilder(pvno, sender, recipient); + } + + /** + * Set the identifier for the transaction the new message will belong to. + * + * @param tid the transaction ID. + * @return the current builder instance. + */ + public ProtectedPKIMessageBuilder setTransactionID(byte[] tid) + { + hdrBuilder.setTransactionID(tid); + + return this; + } + + /** + * Include a human-readable message in the new message. + * + * @param freeText the contents of the human readable message, + * @return the current builder instance. + */ + public ProtectedPKIMessageBuilder setFreeText(PKIFreeText freeText) + { + hdrBuilder.setFreeText(freeText); + + return this; + } + + /** + * Add a generalInfo data record to the header of the new message. + * + * @param genInfo the generalInfo data to be added. + * @return the current builder instance. + */ + public ProtectedPKIMessageBuilder addGeneralInfo(InfoTypeAndValue genInfo) + { + generalInfos.add(genInfo); + + return this; + } + + /** + * Set the creation time for the new message. + * + * @param time the message creation time. + * @return the current builder instance. + */ + public ProtectedPKIMessageBuilder setMessageTime(Date time) + { + hdrBuilder.setMessageTime(new ASN1GeneralizedTime(time)); + + return this; + } + + /** + * Set the recipient key identifier for the key to be used to verify the new message. + * + * @param kid a key identifier. + * @return the current builder instance. + */ + public ProtectedPKIMessageBuilder setRecipKID(byte[] kid) + { + hdrBuilder.setRecipKID(kid); + + return this; + } + + /** + * Set the recipient nonce field on the new message. + * + * @param nonce a NONCE, typically copied from the sender nonce of the previous message. + * @return the current builder instance. + */ + public ProtectedPKIMessageBuilder setRecipNonce(byte[] nonce) + { + hdrBuilder.setRecipNonce(nonce); + + return this; + } + + /** + * Set the sender key identifier for the key used to protect the new message. + * + * @param kid a key identifier. + * @return the current builder instance. + */ + public ProtectedPKIMessageBuilder setSenderKID(byte[] kid) + { + hdrBuilder.setSenderKID(kid); + + return this; + } + + /** + * Set the sender nonce field on the new message. + * + * @param nonce a NONCE, typically 128 bits of random data. + * @return the current builder instance. + */ + public ProtectedPKIMessageBuilder setSenderNonce(byte[] nonce) + { + hdrBuilder.setSenderNonce(nonce); + + return this; + } + + /** + * Set the body for the new message + * + * @param body the message body. + * @return the current builder instance. + */ + public ProtectedPKIMessageBuilder setBody(PKIBody body) + { + this.body = body; + + return this; + } + + /** + * Add an "extra certificate" to the message. + * + * @param extraCert the extra certificate to add. + * @return the current builder instance. + */ + public ProtectedPKIMessageBuilder addCMPCertificate(X509CertificateHolder extraCert) + { + extraCerts.add(extraCert); + + return this; + } + + /** + * Build a protected PKI message which has MAC based integrity protection. + * + * @param macCalculator MAC calculator. + * @return the resulting protected PKI message. + * @throws CMPException if the protection MAC cannot be calculated. + */ + public ProtectedPKIMessage build(MacCalculator macCalculator) + throws CMPException + { + finaliseHeader(macCalculator.getAlgorithmIdentifier()); + + PKIHeader header = hdrBuilder.build(); + + try + { + DERBitString protection = new DERBitString(calculateMac(macCalculator, header, body)); + + return finaliseMessage(header, protection); + } + catch (IOException e) + { + throw new CMPException("unable to encode MAC input: " + e.getMessage(), e); + } + } + + /** + * Build a protected PKI message which has MAC based integrity protection. + * + * @param signer the ContentSigner to be used to calculate the signature. + * @return the resulting protected PKI message. + * @throws CMPException if the protection signature cannot be calculated. + */ + public ProtectedPKIMessage build(ContentSigner signer) + throws CMPException + { + finaliseHeader(signer.getAlgorithmIdentifier()); + + PKIHeader header = hdrBuilder.build(); + + try + { + DERBitString protection = new DERBitString(calculateSignature(signer, header, body)); + + return finaliseMessage(header, protection); + } + catch (IOException e) + { + throw new CMPException("unable to encode signature input: " + e.getMessage(), e); + } + } + + private void finaliseHeader(AlgorithmIdentifier algorithmIdentifier) + { + hdrBuilder.setProtectionAlg(algorithmIdentifier); + + if (!generalInfos.isEmpty()) + { + InfoTypeAndValue[] genInfos = new InfoTypeAndValue[generalInfos.size()]; + + hdrBuilder.setGeneralInfo((InfoTypeAndValue[])generalInfos.toArray(genInfos)); + } + } + + private ProtectedPKIMessage finaliseMessage(PKIHeader header, DERBitString protection) + { + if (!extraCerts.isEmpty()) + { + CMPCertificate[] cmpCerts = new CMPCertificate[extraCerts.size()]; + + for (int i = 0; i != cmpCerts.length; i++) + { + cmpCerts[i] = new CMPCertificate(((X509CertificateHolder)extraCerts.get(i)).toASN1Structure()); + } + + return new ProtectedPKIMessage(new PKIMessage(header, body, protection, cmpCerts)); + } + else + { + return new ProtectedPKIMessage(new PKIMessage(header, body, protection)); + } + } + + private byte[] calculateSignature(ContentSigner signer, PKIHeader header, PKIBody body) + throws IOException + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(header); + v.add(body); + + OutputStream sOut = signer.getOutputStream(); + + sOut.write(new DERSequence(v).getEncoded(ASN1Encoding.DER)); + + sOut.close(); + + return signer.getSignature(); + } + + private byte[] calculateMac(MacCalculator macCalculator, PKIHeader header, PKIBody body) + throws IOException + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(header); + v.add(body); + + OutputStream sOut = macCalculator.getOutputStream(); + + sOut.write(new DERSequence(v).getEncoded(ASN1Encoding.DER)); + + sOut.close(); + + return macCalculator.getMac(); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/cmp/RevocationDetails.java b/pkix/src/main/java/org/spongycastle/cert/cmp/RevocationDetails.java new file mode 100644 index 00000000..a9c4993c --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/cmp/RevocationDetails.java @@ -0,0 +1,36 @@ +package org.spongycastle.cert.cmp; + +import java.math.BigInteger; + +import org.spongycastle.asn1.cmp.RevDetails; +import org.spongycastle.asn1.x500.X500Name; + +public class RevocationDetails +{ + private RevDetails revDetails; + + public RevocationDetails(RevDetails revDetails) + { + this.revDetails = revDetails; + } + + public X500Name getSubject() + { + return revDetails.getCertDetails().getSubject(); + } + + public X500Name getIssuer() + { + return revDetails.getCertDetails().getIssuer(); + } + + public BigInteger getSerialNumber() + { + return revDetails.getCertDetails().getSerialNumber().getValue(); + } + + public RevDetails toASN1Structure() + { + return revDetails; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/cmp/RevocationDetailsBuilder.java b/pkix/src/main/java/org/spongycastle/cert/cmp/RevocationDetailsBuilder.java new file mode 100644 index 00000000..bc7eaa04 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/cmp/RevocationDetailsBuilder.java @@ -0,0 +1,59 @@ +package org.spongycastle.cert.cmp; + +import java.math.BigInteger; + +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.cmp.RevDetails; +import org.spongycastle.asn1.crmf.CertTemplateBuilder; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; + +public class RevocationDetailsBuilder +{ + private CertTemplateBuilder templateBuilder = new CertTemplateBuilder(); + + public RevocationDetailsBuilder setPublicKey(SubjectPublicKeyInfo publicKey) + { + if (publicKey != null) + { + templateBuilder.setPublicKey(publicKey); + } + + return this; + } + + public RevocationDetailsBuilder setIssuer(X500Name issuer) + { + if (issuer != null) + { + templateBuilder.setIssuer(issuer); + } + + return this; + } + + public RevocationDetailsBuilder setSerialNumber(BigInteger serialNumber) + { + if (serialNumber != null) + { + templateBuilder.setSerialNumber(new ASN1Integer(serialNumber)); + } + + return this; + } + + public RevocationDetailsBuilder setSubject(X500Name subject) + { + if (subject != null) + { + templateBuilder.setSubject(subject); + } + + return this; + } + + public RevocationDetails build() + { + return new RevocationDetails(new RevDetails(templateBuilder.build())); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/AuthenticatorControl.java b/pkix/src/main/java/org/spongycastle/cert/crmf/AuthenticatorControl.java new file mode 100644 index 00000000..58e6c63a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/AuthenticatorControl.java @@ -0,0 +1,57 @@ +package org.spongycastle.cert.crmf; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERUTF8String; +import org.spongycastle.asn1.crmf.CRMFObjectIdentifiers; + +/** + * Carrier for an authenticator control. + */ +public class AuthenticatorControl + implements Control +{ + private static final ASN1ObjectIdentifier type = CRMFObjectIdentifiers.id_regCtrl_authenticator; + + private final DERUTF8String token; + + /** + * Basic constructor - build from a UTF-8 string representing the token. + * + * @param token UTF-8 string representing the token. + */ + public AuthenticatorControl(DERUTF8String token) + { + this.token = token; + } + + /** + * Basic constructor - build from a string representing the token. + * + * @param token string representing the token. + */ + public AuthenticatorControl(String token) + { + this.token = new DERUTF8String(token); + } + + /** + * Return the type of this control. + * + * @return CRMFObjectIdentifiers.id_regCtrl_authenticator + */ + public ASN1ObjectIdentifier getType() + { + return type; + } + + /** + * Return the token associated with this control (a UTF8String). + * + * @return a UTF8String. + */ + public ASN1Encodable getValue() + { + return token; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/CRMFException.java b/pkix/src/main/java/org/spongycastle/cert/crmf/CRMFException.java new file mode 100644 index 00000000..14aa0ad2 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/CRMFException.java @@ -0,0 +1,19 @@ +package org.spongycastle.cert.crmf; + +public class CRMFException + extends Exception +{ + private Throwable cause; + + public CRMFException(String msg, Throwable cause) + { + super(msg); + + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/CRMFRuntimeException.java b/pkix/src/main/java/org/spongycastle/cert/crmf/CRMFRuntimeException.java new file mode 100644 index 00000000..cde484c4 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/CRMFRuntimeException.java @@ -0,0 +1,19 @@ +package org.spongycastle.cert.crmf; + +public class CRMFRuntimeException + extends RuntimeException +{ + private Throwable cause; + + public CRMFRuntimeException(String msg, Throwable cause) + { + super(msg); + + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/CRMFUtil.java b/pkix/src/main/java/org/spongycastle/cert/crmf/CRMFUtil.java new file mode 100644 index 00000000..eb6771e6 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/CRMFUtil.java @@ -0,0 +1,42 @@ +package org.spongycastle.cert.crmf; + +import java.io.IOException; +import java.io.OutputStream; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DEROutputStream; +import org.spongycastle.asn1.x509.ExtensionsGenerator; +import org.spongycastle.cert.CertIOException; + +class CRMFUtil +{ + static void derEncodeToStream(ASN1Encodable obj, OutputStream stream) + { + DEROutputStream dOut = new DEROutputStream(stream); + + try + { + dOut.writeObject(obj); + + dOut.close(); + } + catch (IOException e) + { + throw new CRMFRuntimeException("unable to DER encode object: " + e.getMessage(), e); + } + } + + 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); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/CertificateRequestMessage.java b/pkix/src/main/java/org/spongycastle/cert/crmf/CertificateRequestMessage.java new file mode 100644 index 00000000..987b6b37 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/CertificateRequestMessage.java @@ -0,0 +1,309 @@ +package org.spongycastle.cert.crmf; + +import java.io.IOException; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.DERUTF8String; +import org.spongycastle.asn1.crmf.AttributeTypeAndValue; +import org.spongycastle.asn1.crmf.CRMFObjectIdentifiers; +import org.spongycastle.asn1.crmf.CertReqMsg; +import org.spongycastle.asn1.crmf.CertTemplate; +import org.spongycastle.asn1.crmf.Controls; +import org.spongycastle.asn1.crmf.PKIArchiveOptions; +import org.spongycastle.asn1.crmf.PKMACValue; +import org.spongycastle.asn1.crmf.POPOSigningKey; +import org.spongycastle.asn1.crmf.ProofOfPossession; +import org.spongycastle.cert.CertIOException; +import org.spongycastle.operator.ContentVerifier; +import org.spongycastle.operator.ContentVerifierProvider; +import org.spongycastle.operator.OperatorCreationException; + +/** + * Carrier for a CRMF CertReqMsg. + */ +public class CertificateRequestMessage +{ + public static final int popRaVerified = ProofOfPossession.TYPE_RA_VERIFIED; + public static final int popSigningKey = ProofOfPossession.TYPE_SIGNING_KEY; + public static final int popKeyEncipherment = ProofOfPossession.TYPE_KEY_ENCIPHERMENT; + public static final int popKeyAgreement = ProofOfPossession.TYPE_KEY_AGREEMENT; + + private final CertReqMsg certReqMsg; + private final Controls controls; + + private static CertReqMsg parseBytes(byte[] encoding) + throws IOException + { + try + { + return CertReqMsg.getInstance(ASN1Primitive.fromByteArray(encoding)); + } + catch (ClassCastException e) + { + throw new CertIOException("malformed data: " + e.getMessage(), e); + } + catch (IllegalArgumentException e) + { + throw new CertIOException("malformed data: " + e.getMessage(), e); + } + } + + /** + * Create a CertificateRequestMessage from the passed in bytes. + * + * @param certReqMsg BER/DER encoding of the CertReqMsg structure. + * @throws IOException in the event of corrupted data, or an incorrect structure. + */ + public CertificateRequestMessage(byte[] certReqMsg) + throws IOException + { + this(parseBytes(certReqMsg)); + } + + public CertificateRequestMessage(CertReqMsg certReqMsg) + { + this.certReqMsg = certReqMsg; + this.controls = certReqMsg.getCertReq().getControls(); + } + + /** + * Return the underlying ASN.1 object defining this CertificateRequestMessage object. + * + * @return a CertReqMsg. + */ + public CertReqMsg toASN1Structure() + { + return certReqMsg; + } + + /** + * Return the certificate template contained in this message. + * + * @return a CertTemplate structure. + */ + public CertTemplate getCertTemplate() + { + return this.certReqMsg.getCertReq().getCertTemplate(); + } + + /** + * Return whether or not this request has control values associated with it. + * + * @return true if there are control values present, false otherwise. + */ + public boolean hasControls() + { + return controls != null; + } + + /** + * Return whether or not this request has a specific type of control value. + * + * @param type the type OID for the control value we are checking for. + * @return true if a control value of type is present, false otherwise. + */ + public boolean hasControl(ASN1ObjectIdentifier type) + { + return findControl(type) != null; + } + + /** + * Return a control value of the specified type. + * + * @param type the type OID for the control value we are checking for. + * @return the control value if present, null otherwise. + */ + public Control getControl(ASN1ObjectIdentifier type) + { + AttributeTypeAndValue found = findControl(type); + + if (found != null) + { + if (found.getType().equals(CRMFObjectIdentifiers.id_regCtrl_pkiArchiveOptions)) + { + return new PKIArchiveControl(PKIArchiveOptions.getInstance(found.getValue())); + } + if (found.getType().equals(CRMFObjectIdentifiers.id_regCtrl_regToken)) + { + return new RegTokenControl(DERUTF8String.getInstance(found.getValue())); + } + if (found.getType().equals(CRMFObjectIdentifiers.id_regCtrl_authenticator)) + { + return new AuthenticatorControl(DERUTF8String.getInstance(found.getValue())); + } + } + + return null; + } + + private AttributeTypeAndValue findControl(ASN1ObjectIdentifier type) + { + if (controls == null) + { + return null; + } + + AttributeTypeAndValue[] tAndVs = controls.toAttributeTypeAndValueArray(); + AttributeTypeAndValue found = null; + + for (int i = 0; i != tAndVs.length; i++) + { + if (tAndVs[i].getType().equals(type)) + { + found = tAndVs[i]; + break; + } + } + + return found; + } + + /** + * Return whether or not this request message has a proof-of-possession field in it. + * + * @return true if proof-of-possession is present, false otherwise. + */ + public boolean hasProofOfPossession() + { + return this.certReqMsg.getPopo() != null; + } + + /** + * Return the type of the proof-of-possession this request message provides. + * + * @return one of: popRaVerified, popSigningKey, popKeyEncipherment, popKeyAgreement + */ + public int getProofOfPossessionType() + { + return this.certReqMsg.getPopo().getType(); + } + + /** + * Return whether or not the proof-of-possession (POP) is of the type popSigningKey and + * it has a public key MAC associated with it. + * + * @return true if POP is popSigningKey and a PKMAC is present, false otherwise. + */ + public boolean hasSigningKeyProofOfPossessionWithPKMAC() + { + ProofOfPossession pop = certReqMsg.getPopo(); + + if (pop.getType() == popSigningKey) + { + POPOSigningKey popoSign = POPOSigningKey.getInstance(pop.getObject()); + + return popoSign.getPoposkInput().getPublicKeyMAC() != null; + } + + return false; + } + + /** + * Return whether or not a signing key proof-of-possession (POP) is valid. + * + * @param verifierProvider a provider that can produce content verifiers for the signature contained in this POP. + * @return true if the POP is valid, false otherwise. + * @throws CRMFException if there is a problem in verification or content verifier creation. + * @throws IllegalStateException if POP not appropriate. + */ + public boolean isValidSigningKeyPOP(ContentVerifierProvider verifierProvider) + throws CRMFException, IllegalStateException + { + ProofOfPossession pop = certReqMsg.getPopo(); + + if (pop.getType() == popSigningKey) + { + POPOSigningKey popoSign = POPOSigningKey.getInstance(pop.getObject()); + + if (popoSign.getPoposkInput() != null && popoSign.getPoposkInput().getPublicKeyMAC() != null) + { + throw new IllegalStateException("verification requires password check"); + } + + return verifySignature(verifierProvider, popoSign); + } + else + { + throw new IllegalStateException("not Signing Key type of proof of possession"); + } + } + + /** + * Return whether or not a signing key proof-of-possession (POP), with an associated PKMAC, is valid. + * + * @param verifierProvider a provider that can produce content verifiers for the signature contained in this POP. + * @param macBuilder a suitable PKMACBuilder to create the MAC verifier. + * @param password the password used to key the MAC calculation. + * @return true if the POP is valid, false otherwise. + * @throws CRMFException if there is a problem in verification or content verifier creation. + * @throws IllegalStateException if POP not appropriate. + */ + public boolean isValidSigningKeyPOP(ContentVerifierProvider verifierProvider, PKMACBuilder macBuilder, char[] password) + throws CRMFException, IllegalStateException + { + ProofOfPossession pop = certReqMsg.getPopo(); + + if (pop.getType() == popSigningKey) + { + POPOSigningKey popoSign = POPOSigningKey.getInstance(pop.getObject()); + + if (popoSign.getPoposkInput() == null || popoSign.getPoposkInput().getSender() != null) + { + throw new IllegalStateException("no PKMAC present in proof of possession"); + } + + PKMACValue pkMAC = popoSign.getPoposkInput().getPublicKeyMAC(); + PKMACValueVerifier macVerifier = new PKMACValueVerifier(macBuilder); + + if (macVerifier.isValid(pkMAC, password, this.getCertTemplate().getPublicKey())) + { + return verifySignature(verifierProvider, popoSign); + } + + return false; + } + else + { + throw new IllegalStateException("not Signing Key type of proof of possession"); + } + } + + private boolean verifySignature(ContentVerifierProvider verifierProvider, POPOSigningKey popoSign) + throws CRMFException + { + ContentVerifier verifier; + + try + { + verifier = verifierProvider.get(popoSign.getAlgorithmIdentifier()); + } + catch (OperatorCreationException e) + { + throw new CRMFException("unable to create verifier: " + e.getMessage(), e); + } + + if (popoSign.getPoposkInput() != null) + { + CRMFUtil.derEncodeToStream(popoSign.getPoposkInput(), verifier.getOutputStream()); + } + else + { + CRMFUtil.derEncodeToStream(certReqMsg.getCertReq(), verifier.getOutputStream()); + } + + return verifier.verify(popoSign.getSignature().getBytes()); + } + + /** + * Return the ASN.1 encoding of the certReqMsg we wrap. + * + * @return a byte array containing the binary encoding of the certReqMsg. + * @throws IOException if there is an exception creating the encoding. + */ + public byte[] getEncoded() + throws IOException + { + return certReqMsg.getEncoded(); + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/CertificateRequestMessageBuilder.java b/pkix/src/main/java/org/spongycastle/cert/crmf/CertificateRequestMessageBuilder.java new file mode 100644 index 00000000..4bfd6451 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/CertificateRequestMessageBuilder.java @@ -0,0 +1,279 @@ +package org.spongycastle.cert.crmf; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1Null; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.crmf.AttributeTypeAndValue; +import org.spongycastle.asn1.crmf.CertReqMsg; +import org.spongycastle.asn1.crmf.CertRequest; +import org.spongycastle.asn1.crmf.CertTemplate; +import org.spongycastle.asn1.crmf.CertTemplateBuilder; +import org.spongycastle.asn1.crmf.OptionalValidity; +import org.spongycastle.asn1.crmf.POPOPrivKey; +import org.spongycastle.asn1.crmf.ProofOfPossession; +import org.spongycastle.asn1.crmf.SubsequentMessage; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.ExtensionsGenerator; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.asn1.x509.Time; +import org.spongycastle.cert.CertIOException; +import org.spongycastle.operator.ContentSigner; + +public class CertificateRequestMessageBuilder +{ + private final BigInteger certReqId; + + private ExtensionsGenerator extGenerator; + private CertTemplateBuilder templateBuilder; + private List controls; + private ContentSigner popSigner; + private PKMACBuilder pkmacBuilder; + private char[] password; + private GeneralName sender; + private POPOPrivKey popoPrivKey; + private ASN1Null popRaVerified; + + public CertificateRequestMessageBuilder(BigInteger certReqId) + { + this.certReqId = certReqId; + + this.extGenerator = new ExtensionsGenerator(); + this.templateBuilder = new CertTemplateBuilder(); + this.controls = new ArrayList(); + } + + public CertificateRequestMessageBuilder setPublicKey(SubjectPublicKeyInfo publicKey) + { + if (publicKey != null) + { + templateBuilder.setPublicKey(publicKey); + } + + return this; + } + + public CertificateRequestMessageBuilder setIssuer(X500Name issuer) + { + if (issuer != null) + { + templateBuilder.setIssuer(issuer); + } + + return this; + } + + public CertificateRequestMessageBuilder setSubject(X500Name subject) + { + if (subject != null) + { + templateBuilder.setSubject(subject); + } + + return this; + } + + public CertificateRequestMessageBuilder setSerialNumber(BigInteger serialNumber) + { + if (serialNumber != null) + { + templateBuilder.setSerialNumber(new ASN1Integer(serialNumber)); + } + + return this; + } + + /** + * Request a validity period for the certificate. Either, but not both, of the date parameters may be null. + * + * @param notBeforeDate not before date for certificate requested. + * @param notAfterDate not after date for the certificate requested. + * + * @return the current builder. + */ + public CertificateRequestMessageBuilder setValidity(Date notBeforeDate, Date notAfterDate) + { + templateBuilder.setValidity(new OptionalValidity(createTime(notBeforeDate), createTime(notAfterDate))); + + return this; + } + + private Time createTime(Date date) + { + if (date != null) + { + return new Time(date); + } + + return null; + } + + public CertificateRequestMessageBuilder addExtension( + ASN1ObjectIdentifier oid, + boolean critical, + ASN1Encodable value) + throws CertIOException + { + CRMFUtil.addExtension(extGenerator, oid, critical, value); + + return this; + } + + public CertificateRequestMessageBuilder addExtension( + ASN1ObjectIdentifier oid, + boolean critical, + byte[] value) + { + extGenerator.addExtension(oid, critical, value); + + return this; + } + + public CertificateRequestMessageBuilder addControl(Control control) + { + controls.add(control); + + return this; + } + + public CertificateRequestMessageBuilder setProofOfPossessionSigningKeySigner(ContentSigner popSigner) + { + if (popoPrivKey != null || popRaVerified != null) + { + throw new IllegalStateException("only one proof of possession allowed"); + } + + this.popSigner = popSigner; + + return this; + } + + public CertificateRequestMessageBuilder setProofOfPossessionSubsequentMessage(SubsequentMessage msg) + { + if (popSigner != null || popRaVerified != null) + { + throw new IllegalStateException("only one proof of possession allowed"); + } + + this.popoPrivKey = new POPOPrivKey(msg); + + return this; + } + + public CertificateRequestMessageBuilder setProofOfPossessionRaVerified() + { + if (popSigner != null || popoPrivKey != null) + { + throw new IllegalStateException("only one proof of possession allowed"); + } + + this.popRaVerified = DERNull.INSTANCE; + + return this; + } + + public CertificateRequestMessageBuilder setAuthInfoPKMAC(PKMACBuilder pkmacBuilder, char[] password) + { + this.pkmacBuilder = pkmacBuilder; + this.password = password; + + return this; + } + + public CertificateRequestMessageBuilder setAuthInfoSender(X500Name sender) + { + return setAuthInfoSender(new GeneralName(sender)); + } + + public CertificateRequestMessageBuilder setAuthInfoSender(GeneralName sender) + { + this.sender = sender; + + return this; + } + + public CertificateRequestMessage build() + throws CRMFException + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(certReqId)); + + if (!extGenerator.isEmpty()) + { + templateBuilder.setExtensions(extGenerator.generate()); + } + + v.add(templateBuilder.build()); + + if (!controls.isEmpty()) + { + ASN1EncodableVector controlV = new ASN1EncodableVector(); + + for (Iterator it = controls.iterator(); it.hasNext();) + { + Control control = (Control)it.next(); + + controlV.add(new AttributeTypeAndValue(control.getType(), control.getValue())); + } + + v.add(new DERSequence(controlV)); + } + + CertRequest request = CertRequest.getInstance(new DERSequence(v)); + + v = new ASN1EncodableVector(); + + v.add(request); + + if (popSigner != null) + { + CertTemplate template = request.getCertTemplate(); + + if (template.getSubject() == null || template.getPublicKey() == null) + { + SubjectPublicKeyInfo pubKeyInfo = request.getCertTemplate().getPublicKey(); + ProofOfPossessionSigningKeyBuilder builder = new ProofOfPossessionSigningKeyBuilder(pubKeyInfo); + + if (sender != null) + { + builder.setSender(sender); + } + else + { + PKMACValueGenerator pkmacGenerator = new PKMACValueGenerator(pkmacBuilder); + + builder.setPublicKeyMac(pkmacGenerator, password); + } + + v.add(new ProofOfPossession(builder.build(popSigner))); + } + else + { + ProofOfPossessionSigningKeyBuilder builder = new ProofOfPossessionSigningKeyBuilder(request); + + v.add(new ProofOfPossession(builder.build(popSigner))); + } + } + else if (popoPrivKey != null) + { + v.add(new ProofOfPossession(ProofOfPossession.TYPE_KEY_ENCIPHERMENT, popoPrivKey)); + } + else if (popRaVerified != null) + { + v.add(new ProofOfPossession()); + } + + return new CertificateRequestMessage(CertReqMsg.getInstance(new DERSequence(v))); + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/Control.java b/pkix/src/main/java/org/spongycastle/cert/crmf/Control.java new file mode 100644 index 00000000..4454f7e7 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/Control.java @@ -0,0 +1,24 @@ +package org.spongycastle.cert.crmf; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1ObjectIdentifier; + +/** + * Generic interface for a CertificateRequestMessage control value. + */ +public interface Control +{ + /** + * Return the type of this control. + * + * @return an ASN1ObjectIdentifier representing the type. + */ + ASN1ObjectIdentifier getType(); + + /** + * Return the value contained in this control object. + * + * @return the value of the control. + */ + ASN1Encodable getValue(); +} diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/EncryptedValueBuilder.java b/pkix/src/main/java/org/spongycastle/cert/crmf/EncryptedValueBuilder.java new file mode 100644 index 00000000..6a34f49c --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/EncryptedValueBuilder.java @@ -0,0 +1,133 @@ +package org.spongycastle.cert.crmf; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.DERBitString; +import org.spongycastle.asn1.crmf.EncryptedValue; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.operator.KeyWrapper; +import org.spongycastle.operator.OperatorException; +import org.spongycastle.operator.OutputEncryptor; +import org.spongycastle.util.Strings; + +/** + * Builder for EncryptedValue structures. + */ +public class EncryptedValueBuilder +{ + private KeyWrapper wrapper; + private OutputEncryptor encryptor; + private EncryptedValuePadder padder; + + /** + * Create a builder that makes EncryptedValue structures. + * + * @param wrapper a wrapper for key used to encrypt the actual data contained in the EncryptedValue. + * @param encryptor an output encryptor to encrypt the actual data contained in the EncryptedValue. + */ + public EncryptedValueBuilder(KeyWrapper wrapper, OutputEncryptor encryptor) + { + this(wrapper, encryptor, null); + } + + /** + * Create a builder that makes EncryptedValue structures with fixed length blocks padded using the passed in padder. + * + * @param wrapper a wrapper for key used to encrypt the actual data contained in the EncryptedValue. + * @param encryptor an output encryptor to encrypt the actual data contained in the EncryptedValue. + * @param padder a padder to ensure that the EncryptedValue created will always be a constant length. + */ + public EncryptedValueBuilder(KeyWrapper wrapper, OutputEncryptor encryptor, EncryptedValuePadder padder) + { + this.wrapper = wrapper; + this.encryptor = encryptor; + this.padder = padder; + } + + /** + * Build an EncryptedValue structure containing the passed in pass phrase. + * + * @param revocationPassphrase a revocation pass phrase. + * @return an EncryptedValue containing the encrypted pass phrase. + * @throws CRMFException on a failure to encrypt the data, or wrap the symmetric key for this value. + */ + public EncryptedValue build(char[] revocationPassphrase) + throws CRMFException + { + return encryptData(padData(Strings.toUTF8ByteArray(revocationPassphrase))); + } + + /** + * Build an EncryptedValue structure containing the certificate contained in + * the passed in holder. + * + * @param holder a holder containing a certificate. + * @return an EncryptedValue containing the encrypted certificate. + * @throws CRMFException on a failure to encrypt the data, or wrap the symmetric key for this value. + */ + public EncryptedValue build(X509CertificateHolder holder) + throws CRMFException + { + try + { + return encryptData(padData(holder.getEncoded())); + } + catch (IOException e) + { + throw new CRMFException("cannot encode certificate: " + e.getMessage(), e); + } + } + + private EncryptedValue encryptData(byte[] data) + throws CRMFException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + OutputStream eOut = encryptor.getOutputStream(bOut); + + try + { + eOut.write(data); + + eOut.close(); + } + catch (IOException e) + { + throw new CRMFException("cannot process data: " + e.getMessage(), e); + } + + AlgorithmIdentifier intendedAlg = null; + AlgorithmIdentifier symmAlg = encryptor.getAlgorithmIdentifier(); + DERBitString encSymmKey; + + try + { + wrapper.generateWrappedKey(encryptor.getKey()); + encSymmKey = new DERBitString(wrapper.generateWrappedKey(encryptor.getKey())); + } + catch (OperatorException e) + { + throw new CRMFException("cannot wrap key: " + e.getMessage(), e); + } + + AlgorithmIdentifier keyAlg = wrapper.getAlgorithmIdentifier(); + ASN1OctetString valueHint = null; + DERBitString encValue = new DERBitString(bOut.toByteArray()); + + return new EncryptedValue(intendedAlg, symmAlg, encSymmKey, keyAlg, valueHint, encValue); + } + + private byte[] padData(byte[] data) + { + if (padder != null) + { + return padder.getPaddedData(data); + } + + return data; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/EncryptedValuePadder.java b/pkix/src/main/java/org/spongycastle/cert/crmf/EncryptedValuePadder.java new file mode 100644 index 00000000..d00b5b62 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/EncryptedValuePadder.java @@ -0,0 +1,24 @@ +package org.spongycastle.cert.crmf; + +/** + * An encrypted value padder is used to make sure that prior to a value been + * encrypted the data is padded to a standard length. + */ +public interface EncryptedValuePadder +{ + /** + * Return a byte array of padded data. + * + * @param data the data to be padded. + * @return a padded byte array containing data. + */ + byte[] getPaddedData(byte[] data); + + /** + * Return a byte array of with padding removed. + * + * @param paddedData the data to be padded. + * @return an array containing the original unpadded data. + */ + byte[] getUnpaddedData(byte[] paddedData); +} diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/EncryptedValueParser.java b/pkix/src/main/java/org/spongycastle/cert/crmf/EncryptedValueParser.java new file mode 100644 index 00000000..80804993 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/EncryptedValueParser.java @@ -0,0 +1,103 @@ +package org.spongycastle.cert.crmf; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.spongycastle.asn1.crmf.EncryptedValue; +import org.spongycastle.asn1.x509.Certificate; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.operator.InputDecryptor; +import org.spongycastle.util.Strings; +import org.spongycastle.util.io.Streams; + +/** + * Parser for EncryptedValue structures. + */ +public class EncryptedValueParser +{ + private EncryptedValue value; + private EncryptedValuePadder padder; + + /** + * Basic constructor - create a parser to read the passed in value. + * + * @param value the value to be parsed. + */ + public EncryptedValueParser(EncryptedValue value) + { + this.value = value; + } + + /** + * Create a parser to read the passed in value, assuming the padder was + * applied to the data prior to encryption. + * + * @param value the value to be parsed. + * @param padder the padder to be used to remove padding from the decrypted value.. + */ + public EncryptedValueParser(EncryptedValue value, EncryptedValuePadder padder) + { + this.value = value; + this.padder = padder; + } + + private byte[] decryptValue(ValueDecryptorGenerator decGen) + throws CRMFException + { + if (value.getIntendedAlg() != null) + { + throw new UnsupportedOperationException(); + } + if (value.getValueHint() != null) + { + throw new UnsupportedOperationException(); + } + + InputDecryptor decryptor = decGen.getValueDecryptor(value.getKeyAlg(), + value.getSymmAlg(), value.getEncSymmKey().getBytes()); + InputStream dataIn = decryptor.getInputStream(new ByteArrayInputStream( + value.getEncValue().getBytes())); + try + { + byte[] data = Streams.readAll(dataIn); + + if (padder != null) + { + return padder.getUnpaddedData(data); + } + + return data; + } + catch (IOException e) + { + throw new CRMFException("Cannot parse decrypted data: " + e.getMessage(), e); + } + } + + /** + * Read a X.509 certificate. + * + * @param decGen the decryptor generator to decrypt the encrypted value. + * @return an X509CertificateHolder containing the certificate read. + * @throws CRMFException if the decrypted data cannot be parsed, or a decryptor cannot be generated. + */ + public X509CertificateHolder readCertificateHolder(ValueDecryptorGenerator decGen) + throws CRMFException + { + return new X509CertificateHolder(Certificate.getInstance(decryptValue(decGen))); + } + + /** + * Read a pass phrase. + * + * @param decGen the decryptor generator to decrypt the encrypted value. + * @return a pass phrase as recovered from the encrypted value. + * @throws CRMFException if the decrypted data cannot be parsed, or a decryptor cannot be generated. + */ + public char[] readPassphrase(ValueDecryptorGenerator decGen) + throws CRMFException + { + return Strings.fromUTF8ByteArray(decryptValue(decGen)).toCharArray(); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/PKIArchiveControl.java b/pkix/src/main/java/org/spongycastle/cert/crmf/PKIArchiveControl.java new file mode 100644 index 00000000..0c9bd985 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/PKIArchiveControl.java @@ -0,0 +1,104 @@ +package org.spongycastle.cert.crmf; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.cms.CMSObjectIdentifiers; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.cms.EnvelopedData; +import org.spongycastle.asn1.crmf.CRMFObjectIdentifiers; +import org.spongycastle.asn1.crmf.EncryptedKey; +import org.spongycastle.asn1.crmf.PKIArchiveOptions; +import org.spongycastle.cms.CMSEnvelopedData; +import org.spongycastle.cms.CMSException; + +/** + * Carrier for a PKIArchiveOptions structure. + */ +public class PKIArchiveControl + implements Control +{ + public static final int encryptedPrivKey = PKIArchiveOptions.encryptedPrivKey; + public static final int keyGenParameters = PKIArchiveOptions.keyGenParameters; + public static final int archiveRemGenPrivKey = PKIArchiveOptions.archiveRemGenPrivKey; + + private static final ASN1ObjectIdentifier type = CRMFObjectIdentifiers.id_regCtrl_pkiArchiveOptions; + + private final PKIArchiveOptions pkiArchiveOptions; + + /** + * Basic constructor - build from an PKIArchiveOptions structure. + * + * @param pkiArchiveOptions the ASN.1 structure that will underlie this control. + */ + public PKIArchiveControl(PKIArchiveOptions pkiArchiveOptions) + { + this.pkiArchiveOptions = pkiArchiveOptions; + } + + /** + * Return the type of this control. + * + * @return CRMFObjectIdentifiers.id_regCtrl_pkiArchiveOptions + */ + public ASN1ObjectIdentifier getType() + { + return type; + } + + /** + * Return the underlying ASN.1 object. + * + * @return a PKIArchiveOptions structure. + */ + public ASN1Encodable getValue() + { + return pkiArchiveOptions; + } + + /** + * Return the archive control type, one of: encryptedPrivKey,keyGenParameters,or archiveRemGenPrivKey. + * + * @return the archive control type. + */ + public int getArchiveType() + { + return pkiArchiveOptions.getType(); + } + + /** + * Return whether this control contains enveloped data. + * + * @return true if the control contains enveloped data, false otherwise. + */ + public boolean isEnvelopedData() + { + EncryptedKey encKey = EncryptedKey.getInstance(pkiArchiveOptions.getValue()); + + return !encKey.isEncryptedValue(); + } + + /** + * Return the enveloped data structure contained in this control. + * + * @return a CMSEnvelopedData object. + */ + public CMSEnvelopedData getEnvelopedData() + throws CRMFException + { + try + { + EncryptedKey encKey = EncryptedKey.getInstance(pkiArchiveOptions.getValue()); + EnvelopedData data = EnvelopedData.getInstance(encKey.getValue()); + + return new CMSEnvelopedData(new ContentInfo(CMSObjectIdentifiers.envelopedData, data)); + } + catch (CMSException e) + { + throw new CRMFException("CMS parsing error: " + e.getMessage(), e.getCause()); + } + catch (Exception e) + { + throw new CRMFException("CRMF parsing error: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/PKIArchiveControlBuilder.java b/pkix/src/main/java/org/spongycastle/cert/crmf/PKIArchiveControlBuilder.java new file mode 100644 index 00000000..1ca860cb --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/PKIArchiveControlBuilder.java @@ -0,0 +1,78 @@ +package org.spongycastle.cert.crmf; + +import java.io.IOException; + +import org.spongycastle.asn1.cms.EnvelopedData; +import org.spongycastle.asn1.crmf.CRMFObjectIdentifiers; +import org.spongycastle.asn1.crmf.EncKeyWithID; +import org.spongycastle.asn1.crmf.EncryptedKey; +import org.spongycastle.asn1.crmf.PKIArchiveOptions; +import org.spongycastle.asn1.pkcs.PrivateKeyInfo; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.cms.CMSEnvelopedData; +import org.spongycastle.cms.CMSEnvelopedDataGenerator; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.CMSProcessableByteArray; +import org.spongycastle.cms.RecipientInfoGenerator; +import org.spongycastle.operator.OutputEncryptor; + +/** + * Builder for a PKIArchiveControl structure. + */ +public class PKIArchiveControlBuilder +{ + private CMSEnvelopedDataGenerator envGen; + private CMSProcessableByteArray keyContent; + + /** + * Basic constructor - specify the contents of the PKIArchiveControl structure. + * + * @param privateKeyInfo the private key to be archived. + * @param generalName the general name to be associated with the private key. + */ + public PKIArchiveControlBuilder(PrivateKeyInfo privateKeyInfo, GeneralName generalName) + { + EncKeyWithID encKeyWithID = new EncKeyWithID(privateKeyInfo, generalName); + + try + { + this.keyContent = new CMSProcessableByteArray(CRMFObjectIdentifiers.id_ct_encKeyWithID, encKeyWithID.getEncoded()); + } + catch (IOException e) + { + throw new IllegalStateException("unable to encode key and general name info"); + } + + this.envGen = new CMSEnvelopedDataGenerator(); + } + + /** + * Add a recipient generator to this control. + * + * @param recipientGen recipient generator created for a specific recipient. + * @return this builder object. + */ + public PKIArchiveControlBuilder addRecipientGenerator(RecipientInfoGenerator recipientGen) + { + envGen.addRecipientInfoGenerator(recipientGen); + + return this; + } + + /** + * Build the PKIArchiveControl using the passed in encryptor to encrypt its contents. + * + * @param contentEncryptor a suitable content encryptor. + * @return a PKIArchiveControl object. + * @throws CMSException in the event the build fails. + */ + public PKIArchiveControl build(OutputEncryptor contentEncryptor) + throws CMSException + { + CMSEnvelopedData envContent = envGen.generate(keyContent, contentEncryptor); + + EnvelopedData envD = EnvelopedData.getInstance(envContent.toASN1Structure().getContent()); + + return new PKIArchiveControl(new PKIArchiveOptions(new EncryptedKey(envD))); + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACBuilder.java b/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACBuilder.java new file mode 100644 index 00000000..54e9cd91 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACBuilder.java @@ -0,0 +1,199 @@ +package org.spongycastle.cert.crmf; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.security.SecureRandom; + +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.cmp.CMPObjectIdentifiers; +import org.spongycastle.asn1.cmp.PBMParameter; +import org.spongycastle.asn1.iana.IANAObjectIdentifiers; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.MacCalculator; +import org.spongycastle.operator.RuntimeOperatorException; +import org.spongycastle.util.Strings; + +public class PKMACBuilder +{ + private AlgorithmIdentifier owf; + private int iterationCount; + private AlgorithmIdentifier mac; + private int saltLength = 20; + private SecureRandom random; + private PKMACValuesCalculator calculator; + private PBMParameter parameters; + private int maxIterations; + + public PKMACBuilder(PKMACValuesCalculator calculator) + { + this(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1), 1000, new AlgorithmIdentifier(IANAObjectIdentifiers.hmacSHA1, DERNull.INSTANCE), calculator); + } + + /** + * Create a PKMAC builder enforcing a ceiling on the maximum iteration count. + * + * @param calculator supporting calculator + * @param maxIterations max allowable value for iteration count. + */ + public PKMACBuilder(PKMACValuesCalculator calculator, int maxIterations) + { + this.maxIterations = maxIterations; + this.calculator = calculator; + } + + private PKMACBuilder(AlgorithmIdentifier hashAlgorithm, int iterationCount, AlgorithmIdentifier macAlgorithm, PKMACValuesCalculator calculator) + { + this.owf = hashAlgorithm; + this.iterationCount = iterationCount; + this.mac = macAlgorithm; + this.calculator = calculator; + } + + /** + * Set the salt length in octets. + * + * @param saltLength length in octets of the salt to be generated. + * @return the generator + */ + public PKMACBuilder setSaltLength(int saltLength) + { + if (saltLength < 8) + { + throw new IllegalArgumentException("salt length must be at least 8 bytes"); + } + + this.saltLength = saltLength; + + return this; + } + + public PKMACBuilder setIterationCount(int iterationCount) + { + if (iterationCount < 100) + { + throw new IllegalArgumentException("iteration count must be at least 100"); + } + checkIterationCountCeiling(iterationCount); + + this.iterationCount = iterationCount; + + return this; + } + + public PKMACBuilder setSecureRandom(SecureRandom random) + { + this.random = random; + + return this; + } + + public PKMACBuilder setParameters(PBMParameter parameters) + { + checkIterationCountCeiling(parameters.getIterationCount().getValue().intValue()); + + this.parameters = parameters; + + return this; + } + + public MacCalculator build(char[] password) + throws CRMFException + { + if (parameters != null) + { + return genCalculator(parameters, password); + } + else + { + byte[] salt = new byte[saltLength]; + + if (random == null) + { + this.random = new SecureRandom(); + } + + random.nextBytes(salt); + + return genCalculator(new PBMParameter(salt, owf, iterationCount, mac), password); + } + } + + private void checkIterationCountCeiling(int iterationCount) + { + if (maxIterations > 0 && iterationCount > maxIterations) + { + throw new IllegalArgumentException("iteration count exceeds limit (" + iterationCount + " > " + maxIterations + ")"); + } + } + + private MacCalculator genCalculator(final PBMParameter params, char[] password) + throws CRMFException + { + // From RFC 4211 + // + // 1. Generate a random salt value S + // + // 2. Append the salt to the pw. K = pw || salt. + // + // 3. Hash the value of K. K = HASH(K) + // + // 4. Iter = Iter - 1. If Iter is greater than zero. Goto step 3. + // + // 5. Compute an HMAC as documented in [HMAC]. + // + // MAC = HASH( K XOR opad, HASH( K XOR ipad, data) ) + // + // Where opad and ipad are defined in [HMAC]. + byte[] pw = Strings.toUTF8ByteArray(password); + byte[] salt = params.getSalt().getOctets(); + byte[] K = new byte[pw.length + salt.length]; + + System.arraycopy(pw, 0, K, 0, pw.length); + System.arraycopy(salt, 0, K, pw.length, salt.length); + + calculator.setup(params.getOwf(), params.getMac()); + + int iter = params.getIterationCount().getValue().intValue(); + do + { + K = calculator.calculateDigest(K); + } + while (--iter > 0); + + final byte[] key = K; + + return new MacCalculator() + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return new AlgorithmIdentifier(CMPObjectIdentifiers.passwordBasedMac, params); + } + + public GenericKey getKey() + { + return new GenericKey(getAlgorithmIdentifier(), key); + } + + public OutputStream getOutputStream() + { + return bOut; + } + + public byte[] getMac() + { + try + { + return calculator.calculateMac(key, bOut.toByteArray()); + } + catch (CRMFException e) + { + throw new RuntimeOperatorException("exception calculating mac: " + e.getMessage(), e); + } + } + }; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACValueGenerator.java b/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACValueGenerator.java new file mode 100644 index 00000000..eaf215ff --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACValueGenerator.java @@ -0,0 +1,41 @@ +package org.spongycastle.cert.crmf; + +import java.io.IOException; +import java.io.OutputStream; + +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.DERBitString; +import org.spongycastle.asn1.crmf.PKMACValue; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.operator.MacCalculator; + +class PKMACValueGenerator +{ + private PKMACBuilder builder; + + public PKMACValueGenerator(PKMACBuilder builder) + { + this.builder = builder; + } + + public PKMACValue generate(char[] password, SubjectPublicKeyInfo keyInfo) + throws CRMFException + { + MacCalculator calculator = builder.build(password); + + OutputStream macOut = calculator.getOutputStream(); + + try + { + macOut.write(keyInfo.getEncoded(ASN1Encoding.DER)); + + macOut.close(); + } + catch (IOException e) + { + throw new CRMFException("exception encoding mac input: " + e.getMessage(), e); + } + + return new PKMACValue(calculator.getAlgorithmIdentifier(), new DERBitString(calculator.getMac())); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACValueVerifier.java b/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACValueVerifier.java new file mode 100644 index 00000000..a65ff61d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACValueVerifier.java @@ -0,0 +1,43 @@ +package org.spongycastle.cert.crmf; + +import java.io.IOException; +import java.io.OutputStream; + +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.cmp.PBMParameter; +import org.spongycastle.asn1.crmf.PKMACValue; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.operator.MacCalculator; +import org.spongycastle.util.Arrays; + +class PKMACValueVerifier +{ + private final PKMACBuilder builder; + + public PKMACValueVerifier(PKMACBuilder builder) + { + this.builder = builder; + } + + public boolean isValid(PKMACValue value, char[] password, SubjectPublicKeyInfo keyInfo) + throws CRMFException + { + builder.setParameters(PBMParameter.getInstance(value.getAlgId().getParameters())); + MacCalculator calculator = builder.build(password); + + OutputStream macOut = calculator.getOutputStream(); + + try + { + macOut.write(keyInfo.getEncoded(ASN1Encoding.DER)); + + macOut.close(); + } + catch (IOException e) + { + throw new CRMFException("exception encoding mac input: " + e.getMessage(), e); + } + + return Arrays.areEqual(calculator.getMac(), value.getValue().getBytes()); + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACValuesCalculator.java b/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACValuesCalculator.java new file mode 100644 index 00000000..0b4f1407 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACValuesCalculator.java @@ -0,0 +1,15 @@ +package org.spongycastle.cert.crmf; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +public interface PKMACValuesCalculator +{ + void setup(AlgorithmIdentifier digestAlg, AlgorithmIdentifier macAlg) + throws CRMFException; + + byte[] calculateDigest(byte[] data) + throws CRMFException; + + byte[] calculateMac(byte[] pwd, byte[] data) + throws CRMFException; +} diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/ProofOfPossessionSigningKeyBuilder.java b/pkix/src/main/java/org/spongycastle/cert/crmf/ProofOfPossessionSigningKeyBuilder.java new file mode 100644 index 00000000..07659593 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/ProofOfPossessionSigningKeyBuilder.java @@ -0,0 +1,75 @@ +package org.spongycastle.cert.crmf; + +import org.spongycastle.asn1.DERBitString; +import org.spongycastle.asn1.crmf.CertRequest; +import org.spongycastle.asn1.crmf.PKMACValue; +import org.spongycastle.asn1.crmf.POPOSigningKey; +import org.spongycastle.asn1.crmf.POPOSigningKeyInput; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.operator.ContentSigner; + +public class ProofOfPossessionSigningKeyBuilder +{ + private CertRequest certRequest; + private SubjectPublicKeyInfo pubKeyInfo; + private GeneralName name; + private PKMACValue publicKeyMAC; + + public ProofOfPossessionSigningKeyBuilder(CertRequest certRequest) + { + this.certRequest = certRequest; + } + + + public ProofOfPossessionSigningKeyBuilder(SubjectPublicKeyInfo pubKeyInfo) + { + this.pubKeyInfo = pubKeyInfo; + } + + public ProofOfPossessionSigningKeyBuilder setSender(GeneralName name) + { + this.name = name; + + return this; + } + + public ProofOfPossessionSigningKeyBuilder setPublicKeyMac(PKMACValueGenerator generator, char[] password) + throws CRMFException + { + this.publicKeyMAC = generator.generate(password, pubKeyInfo); + + return this; + } + + public POPOSigningKey build(ContentSigner signer) + { + if (name != null && publicKeyMAC != null) + { + throw new IllegalStateException("name and publicKeyMAC cannot both be set."); + } + + POPOSigningKeyInput popo; + + if (certRequest != null) + { + popo = null; + + CRMFUtil.derEncodeToStream(certRequest, signer.getOutputStream()); + } + else if (name != null) + { + popo = new POPOSigningKeyInput(name, pubKeyInfo); + + CRMFUtil.derEncodeToStream(popo, signer.getOutputStream()); + } + else + { + popo = new POPOSigningKeyInput(publicKeyMAC, pubKeyInfo); + + CRMFUtil.derEncodeToStream(popo, signer.getOutputStream()); + } + + return new POPOSigningKey(popo, signer.getAlgorithmIdentifier(), new DERBitString(signer.getSignature())); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/RegTokenControl.java b/pkix/src/main/java/org/spongycastle/cert/crmf/RegTokenControl.java new file mode 100644 index 00000000..b1a6eb7e --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/RegTokenControl.java @@ -0,0 +1,57 @@ +package org.spongycastle.cert.crmf; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERUTF8String; +import org.spongycastle.asn1.crmf.CRMFObjectIdentifiers; + +/** + * Carrier for a registration token control. + */ +public class RegTokenControl + implements Control +{ + private static final ASN1ObjectIdentifier type = CRMFObjectIdentifiers.id_regCtrl_regToken; + + private final DERUTF8String token; + + /** + * Basic constructor - build from a UTF-8 string representing the token. + * + * @param token UTF-8 string representing the token. + */ + public RegTokenControl(DERUTF8String token) + { + this.token = token; + } + + /** + * Basic constructor - build from a string representing the token. + * + * @param token string representing the token. + */ + public RegTokenControl(String token) + { + this.token = new DERUTF8String(token); + } + + /** + * Return the type of this control. + * + * @return CRMFObjectIdentifiers.id_regCtrl_regToken + */ + public ASN1ObjectIdentifier getType() + { + return type; + } + + /** + * Return the token associated with this control (a UTF8String). + * + * @return a UTF8String. + */ + public ASN1Encodable getValue() + { + return token; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/ValueDecryptorGenerator.java b/pkix/src/main/java/org/spongycastle/cert/crmf/ValueDecryptorGenerator.java new file mode 100644 index 00000000..3fcee4eb --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/ValueDecryptorGenerator.java @@ -0,0 +1,10 @@ +package org.spongycastle.cert.crmf; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.operator.InputDecryptor; + +public interface ValueDecryptorGenerator +{ + InputDecryptor getValueDecryptor(AlgorithmIdentifier keyAlg, AlgorithmIdentifier symmAlg, byte[] encKey) + throws CRMFException; +} diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/bc/BcFixedLengthMGF1Padder.java b/pkix/src/main/java/org/spongycastle/cert/crmf/bc/BcFixedLengthMGF1Padder.java new file mode 100644 index 00000000..756acd7d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/bc/BcFixedLengthMGF1Padder.java @@ -0,0 +1,121 @@ +package org.spongycastle.cert.crmf.bc; + +import java.security.SecureRandom; + +import org.spongycastle.cert.crmf.EncryptedValuePadder; +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.generators.MGF1BytesGenerator; +import org.spongycastle.crypto.params.MGFParameters; + +/** + * An encrypted value padder that uses MGF1 as the basis of the padding. + */ +public class BcFixedLengthMGF1Padder + implements EncryptedValuePadder +{ + private int length; + private SecureRandom random; + private Digest dig = new SHA1Digest(); + + /** + * Create a padder to so that padded output will always be at least + * length bytes long. + * + * @param length fixed length for padded output. + */ + public BcFixedLengthMGF1Padder(int length) + { + this(length, null); + } + + /** + * Create a padder to so that padded output will always be at least + * length bytes long, using the passed in source of randomness to + * provide the random material for the padder. + * + * @param length fixed length for padded output. + * @param random a source of randomness. + */ + public BcFixedLengthMGF1Padder(int length, SecureRandom random) + { + this.length = length; + this.random = random; + } + + public byte[] getPaddedData(byte[] data) + { + byte[] bytes = new byte[length]; + byte[] seed = new byte[dig.getDigestSize()]; + byte[] mask = new byte[length - dig.getDigestSize()]; + + if (random == null) + { + random = new SecureRandom(); + } + + random.nextBytes(seed); + + MGF1BytesGenerator maskGen = new MGF1BytesGenerator(dig); + + maskGen.init(new MGFParameters(seed)); + + maskGen.generateBytes(mask, 0, mask.length); + + System.arraycopy(seed, 0, bytes, 0, seed.length); + System.arraycopy(data, 0, bytes, seed.length, data.length); + + for (int i = seed.length + data.length + 1; i != bytes.length; i++) + { + bytes[i] = (byte)(1 + random.nextInt(255)); + } + + for (int i = 0; i != mask.length; i++) + { + bytes[i + seed.length] ^= mask[i]; + } + + return bytes; + } + + public byte[] getUnpaddedData(byte[] paddedData) + { + byte[] seed = new byte[dig.getDigestSize()]; + byte[] mask = new byte[length - dig.getDigestSize()]; + + System.arraycopy(paddedData, 0, seed, 0, seed.length); + + MGF1BytesGenerator maskGen = new MGF1BytesGenerator(dig); + + maskGen.init(new MGFParameters(seed)); + + maskGen.generateBytes(mask, 0, mask.length); + + for (int i = 0; i != mask.length; i++) + { + paddedData[i + seed.length] ^= mask[i]; + } + + int end = 0; + + for (int i = paddedData.length - 1; i != seed.length; i--) + { + if (paddedData[i] == 0) + { + end = i; + break; + } + } + + if (end == 0) + { + throw new IllegalStateException("bad padding in encoding"); + } + + byte[] data = new byte[end - seed.length]; + + System.arraycopy(paddedData, seed.length, data, 0, data.length); + + return data; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/CRMFHelper.java b/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/CRMFHelper.java new file mode 100644 index 00000000..92d7faa6 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/CRMFHelper.java @@ -0,0 +1,450 @@ +package org.spongycastle.cert.crmf.jcajce; + +import java.io.IOException; +import java.security.AlgorithmParameterGenerator; +import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.InvalidParameterSpecException; +import java.security.spec.X509EncodedKeySpec; +import java.util.HashMap; +import java.util.Map; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.RC2ParameterSpec; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1Null; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.iana.IANAObjectIdentifiers; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.asn1.x9.X9ObjectIdentifiers; +import org.spongycastle.cert.crmf.CRMFException; +import org.spongycastle.cms.CMSAlgorithm; +import org.spongycastle.jcajce.util.JcaJceHelper; +import org.spongycastle.jcajce.util.JcaJceUtils; + +class CRMFHelper +{ + protected static final Map BASE_CIPHER_NAMES = new HashMap(); + protected static final Map CIPHER_ALG_NAMES = new HashMap(); + protected static final Map DIGEST_ALG_NAMES = new HashMap(); + protected static final Map KEY_ALG_NAMES = new HashMap(); + protected static final Map MAC_ALG_NAMES = new HashMap(); + + static + { + BASE_CIPHER_NAMES.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESEDE"); + BASE_CIPHER_NAMES.put(NISTObjectIdentifiers.id_aes128_CBC, "AES"); + BASE_CIPHER_NAMES.put(NISTObjectIdentifiers.id_aes192_CBC, "AES"); + BASE_CIPHER_NAMES.put(NISTObjectIdentifiers.id_aes256_CBC, "AES"); + + CIPHER_ALG_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDE/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(CMSAlgorithm.AES128_CBC, "AES/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(CMSAlgorithm.AES192_CBC, "AES/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(CMSAlgorithm.AES256_CBC, "AES/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(new ASN1ObjectIdentifier(PKCSObjectIdentifiers.rsaEncryption.getId()), "RSA/ECB/PKCS1Padding"); + + DIGEST_ALG_NAMES.put(OIWObjectIdentifiers.idSHA1, "SHA1"); + DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha224, "SHA224"); + DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha256, "SHA256"); + DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha384, "SHA384"); + DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha512, "SHA512"); + + MAC_ALG_NAMES.put(IANAObjectIdentifiers.hmacSHA1, "HMACSHA1"); + MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA1, "HMACSHA1"); + MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA224, "HMACSHA224"); + MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA256, "HMACSHA256"); + MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA384, "HMACSHA384"); + MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA512, "HMACSHA512"); + + KEY_ALG_NAMES.put(PKCSObjectIdentifiers.rsaEncryption, "RSA"); + KEY_ALG_NAMES.put(X9ObjectIdentifiers.id_dsa, "DSA"); + } + + private JcaJceHelper helper; + + CRMFHelper(JcaJceHelper helper) + { + this.helper = helper; + } + + PublicKey toPublicKey(SubjectPublicKeyInfo subjectPublicKeyInfo) + throws CRMFException + { + try + { + X509EncodedKeySpec xspec = new X509EncodedKeySpec(subjectPublicKeyInfo.getEncoded()); + AlgorithmIdentifier keyAlg = subjectPublicKeyInfo.getAlgorithm(); + + return createKeyFactory(keyAlg.getAlgorithm()).generatePublic(xspec); + } + catch (Exception e) + { + throw new CRMFException("invalid key: " + e.getMessage(), e); + } + } + + Cipher createCipher(ASN1ObjectIdentifier algorithm) + throws CRMFException + { + try + { + String cipherName = (String)CIPHER_ALG_NAMES.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 CRMFException("cannot create cipher: " + e.getMessage(), e); + } + } + + public KeyGenerator createKeyGenerator(ASN1ObjectIdentifier algorithm) + throws CRMFException + { + try + { + String cipherName = (String)BASE_CIPHER_NAMES.get(algorithm); + + if (cipherName != null) + { + try + { + // this is reversed as the Sun policy files now allow unlimited strength RSA + return helper.createKeyGenerator(cipherName); + } + catch (NoSuchAlgorithmException e) + { + // Ignore + } + } + return helper.createKeyGenerator(algorithm.getId()); + } + catch (GeneralSecurityException e) + { + throw new CRMFException("cannot create key generator: " + e.getMessage(), e); + } + } + + + + Cipher createContentCipher(final Key sKey, final AlgorithmIdentifier encryptionAlgID) + throws CRMFException + { + return (Cipher)execute(new JCECallback() + { + public Object doInJCE() + throws CRMFException, InvalidAlgorithmParameterException, + InvalidKeyException, InvalidParameterSpecException, NoSuchAlgorithmException, + NoSuchPaddingException, NoSuchProviderException + { + Cipher cipher = createCipher(encryptionAlgID.getAlgorithm()); + ASN1Primitive sParams = (ASN1Primitive)encryptionAlgID.getParameters(); + ASN1ObjectIdentifier encAlg = encryptionAlgID.getAlgorithm(); + + if (sParams != null && !(sParams instanceof ASN1Null)) + { + try + { + AlgorithmParameters params = createAlgorithmParameters(encryptionAlgID.getAlgorithm()); + + try + { + JcaJceUtils.loadParameters(params, sParams); + } + catch (IOException e) + { + throw new CRMFException("error decoding algorithm parameters.", e); + } + + cipher.init(Cipher.DECRYPT_MODE, sKey, params); + } + catch (NoSuchAlgorithmException e) + { + if (encAlg.equals(CMSAlgorithm.DES_EDE3_CBC) + || encAlg.equals(CMSAlgorithm.IDEA_CBC) + || encAlg.equals(CMSAlgorithm.AES128_CBC) + || encAlg.equals(CMSAlgorithm.AES192_CBC) + || encAlg.equals(CMSAlgorithm.AES256_CBC)) + { + cipher.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec( + ASN1OctetString.getInstance(sParams).getOctets())); + } + else + { + throw e; + } + } + } + else + { + if (encAlg.equals(CMSAlgorithm.DES_EDE3_CBC) + || encAlg.equals(CMSAlgorithm.IDEA_CBC) + || encAlg.equals(CMSAlgorithm.CAST5_CBC)) + { + cipher.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec(new byte[8])); + } + else + { + cipher.init(Cipher.DECRYPT_MODE, sKey); + } + } + + return cipher; + } + }); + } + + AlgorithmParameters createAlgorithmParameters(ASN1ObjectIdentifier algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + String algorithmName = (String)BASE_CIPHER_NAMES.get(algorithm); + + if (algorithmName != null) + { + try + { + // this is reversed as the Sun policy files now allow unlimited strength RSA + return helper.createAlgorithmParameters(algorithmName); + } + catch (NoSuchAlgorithmException e) + { + // Ignore + } + } + return helper.createAlgorithmParameters(algorithm.getId()); + } + + KeyFactory createKeyFactory(ASN1ObjectIdentifier algorithm) + throws CRMFException + { + try + { + String algName = (String)KEY_ALG_NAMES.get(algorithm); + + if (algName != null) + { + try + { + // this is reversed as the Sun policy files now allow unlimited strength RSA + return helper.createKeyFactory(algName); + } + catch (NoSuchAlgorithmException e) + { + // Ignore + } + } + return helper.createKeyFactory(algorithm.getId()); + } + catch (GeneralSecurityException e) + { + throw new CRMFException("cannot create cipher: " + e.getMessage(), e); + } + } + + MessageDigest createDigest(ASN1ObjectIdentifier algorithm) + throws CRMFException + { + try + { + String digestName = (String)DIGEST_ALG_NAMES.get(algorithm); + + if (digestName != null) + { + try + { + // this is reversed as the Sun policy files now allow unlimited strength RSA + return helper.createDigest(digestName); + } + catch (NoSuchAlgorithmException e) + { + // Ignore + } + } + return helper.createDigest(algorithm.getId()); + } + catch (GeneralSecurityException e) + { + throw new CRMFException("cannot create cipher: " + e.getMessage(), e); + } + } + + Mac createMac(ASN1ObjectIdentifier algorithm) + throws CRMFException + { + try + { + String macName = (String)MAC_ALG_NAMES.get(algorithm); + + if (macName != null) + { + try + { + // this is reversed as the Sun policy files now allow unlimited strength RSA + return helper.createMac(macName); + } + catch (NoSuchAlgorithmException e) + { + // Ignore + } + } + return helper.createMac(algorithm.getId()); + } + catch (GeneralSecurityException e) + { + throw new CRMFException("cannot create mac: " + e.getMessage(), e); + } + } + + AlgorithmParameterGenerator createAlgorithmParameterGenerator(ASN1ObjectIdentifier algorithm) + throws GeneralSecurityException + { + String algorithmName = (String)BASE_CIPHER_NAMES.get(algorithm); + + if (algorithmName != null) + { + try + { + // this is reversed as the Sun policy files now allow unlimited strength RSA + return helper.createAlgorithmParameterGenerator(algorithmName); + } + catch (NoSuchAlgorithmException e) + { + // Ignore + } + } + return helper.createAlgorithmParameterGenerator(algorithm.getId()); + } + + AlgorithmParameters generateParameters(ASN1ObjectIdentifier encryptionOID, SecretKey encKey, SecureRandom rand) + throws CRMFException + { + try + { + AlgorithmParameterGenerator pGen = createAlgorithmParameterGenerator(encryptionOID); + + if (encryptionOID.equals(CMSAlgorithm.RC2_CBC)) + { + byte[] iv = new byte[8]; + + rand.nextBytes(iv); + + try + { + pGen.init(new RC2ParameterSpec(encKey.getEncoded().length * 8, iv), rand); + } + catch (InvalidAlgorithmParameterException e) + { + throw new CRMFException("parameters generation error: " + e, e); + } + } + + return pGen.generateParameters(); + } + catch (NoSuchAlgorithmException e) + { + return null; + } + catch (GeneralSecurityException e) + { + throw new CRMFException("exception creating algorithm parameter generator: " + e, e); + } + } + + AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier encryptionOID, AlgorithmParameters params) + throws CRMFException + { + ASN1Encodable asn1Params; + if (params != null) + { + try + { + asn1Params = JcaJceUtils.extractParameters(params); + } + catch (IOException e) + { + throw new CRMFException("cannot encode parameters: " + e.getMessage(), e); + } + } + else + { + asn1Params = DERNull.INSTANCE; + } + + return new AlgorithmIdentifier( + encryptionOID, + asn1Params); + } + + static Object execute(JCECallback callback) throws CRMFException + { + try + { + return callback.doInJCE(); + } + catch (NoSuchAlgorithmException e) + { + throw new CRMFException("can't find algorithm.", e); + } + catch (InvalidKeyException e) + { + throw new CRMFException("key invalid in message.", e); + } + catch (NoSuchProviderException e) + { + throw new CRMFException("can't find provider.", e); + } + catch (NoSuchPaddingException e) + { + throw new CRMFException("required padding not supported.", e); + } + catch (InvalidAlgorithmParameterException e) + { + throw new CRMFException("algorithm parameters invalid.", e); + } + catch (InvalidParameterSpecException e) + { + throw new CRMFException("MAC algorithm parameter spec invalid.", e); + } + } + + static interface JCECallback + { + Object doInJCE() + throws CRMFException, InvalidAlgorithmParameterException, InvalidKeyException, InvalidParameterSpecException, + NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaCertificateRequestMessage.java b/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaCertificateRequestMessage.java new file mode 100644 index 00000000..9b10e78e --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaCertificateRequestMessage.java @@ -0,0 +1,84 @@ +package org.spongycastle.cert.crmf.jcajce; + +import java.io.IOException; +import java.security.Provider; +import java.security.PublicKey; + +import javax.security.auth.x500.X500Principal; + +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.crmf.CertReqMsg; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.cert.crmf.CRMFException; +import org.spongycastle.cert.crmf.CertificateRequestMessage; +import org.spongycastle.jcajce.util.DefaultJcaJceHelper; +import org.spongycastle.jcajce.util.NamedJcaJceHelper; +import org.spongycastle.jcajce.util.ProviderJcaJceHelper; + +public class JcaCertificateRequestMessage + extends CertificateRequestMessage +{ + private CRMFHelper helper = new CRMFHelper(new DefaultJcaJceHelper()); + + public JcaCertificateRequestMessage(byte[] certReqMsg) + { + this(CertReqMsg.getInstance(certReqMsg)); + } + + public JcaCertificateRequestMessage(CertificateRequestMessage certReqMsg) + { + this(certReqMsg.toASN1Structure()); + } + + public JcaCertificateRequestMessage(CertReqMsg certReqMsg) + { + super(certReqMsg); + } + + public JcaCertificateRequestMessage setProvider(String providerName) + { + this.helper = new CRMFHelper(new NamedJcaJceHelper(providerName)); + + return this; + } + + public JcaCertificateRequestMessage setProvider(Provider provider) + { + this.helper = new CRMFHelper(new ProviderJcaJceHelper(provider)); + + return this; + } + + public X500Principal getSubjectX500Principal() + { + X500Name subject = this.getCertTemplate().getSubject(); + + if (subject != null) + { + try + { + return new X500Principal(subject.getEncoded(ASN1Encoding.DER)); + } + catch (IOException e) + { + throw new IllegalStateException("unable to construct DER encoding of name: " + e.getMessage()); + } + } + + return null; + } + + public PublicKey getPublicKey() + throws CRMFException + { + SubjectPublicKeyInfo subjectPublicKeyInfo = getCertTemplate().getPublicKey(); + + if (subjectPublicKeyInfo != null) + { + return helper.toPublicKey(subjectPublicKeyInfo); + } + + return null; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaCertificateRequestMessageBuilder.java b/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaCertificateRequestMessageBuilder.java new file mode 100644 index 00000000..1d9318dd --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaCertificateRequestMessageBuilder.java @@ -0,0 +1,57 @@ +package org.spongycastle.cert.crmf.jcajce; + +import java.math.BigInteger; +import java.security.PublicKey; + +import javax.security.auth.x500.X500Principal; + +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.cert.crmf.CertificateRequestMessageBuilder; + +public class JcaCertificateRequestMessageBuilder + extends CertificateRequestMessageBuilder +{ + public JcaCertificateRequestMessageBuilder(BigInteger certReqId) + { + super(certReqId); + } + + public JcaCertificateRequestMessageBuilder setIssuer(X500Principal issuer) + { + if (issuer != null) + { + setIssuer(X500Name.getInstance(issuer.getEncoded())); + } + + return this; + } + + public JcaCertificateRequestMessageBuilder setSubject(X500Principal subject) + { + if (subject != null) + { + setSubject(X500Name.getInstance(subject.getEncoded())); + } + + return this; + } + + public JcaCertificateRequestMessageBuilder setAuthInfoSender(X500Principal sender) + { + if (sender != null) + { + setAuthInfoSender(new GeneralName(X500Name.getInstance(sender.getEncoded()))); + } + + return this; + } + + public JcaCertificateRequestMessageBuilder setPublicKey(PublicKey publicKey) + { + setPublicKey(SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); + + return this; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaEncryptedValueBuilder.java b/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaEncryptedValueBuilder.java new file mode 100644 index 00000000..bed393dc --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaEncryptedValueBuilder.java @@ -0,0 +1,26 @@ +package org.spongycastle.cert.crmf.jcajce; + +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; + +import org.spongycastle.asn1.crmf.EncryptedValue; +import org.spongycastle.cert.crmf.CRMFException; +import org.spongycastle.cert.crmf.EncryptedValueBuilder; +import org.spongycastle.cert.jcajce.JcaX509CertificateHolder; +import org.spongycastle.operator.KeyWrapper; +import org.spongycastle.operator.OutputEncryptor; + +public class JcaEncryptedValueBuilder + extends EncryptedValueBuilder +{ + public JcaEncryptedValueBuilder(KeyWrapper wrapper, OutputEncryptor encryptor) + { + super(wrapper, encryptor); + } + + public EncryptedValue build(X509Certificate certificate) + throws CertificateEncodingException, CRMFException + { + return build(new JcaX509CertificateHolder(certificate)); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaPKIArchiveControlBuilder.java b/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaPKIArchiveControlBuilder.java new file mode 100644 index 00000000..de527e07 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaPKIArchiveControlBuilder.java @@ -0,0 +1,29 @@ +package org.spongycastle.cert.crmf.jcajce; + +import java.security.PrivateKey; + +import javax.security.auth.x500.X500Principal; + +import org.spongycastle.asn1.pkcs.PrivateKeyInfo; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.cert.crmf.PKIArchiveControlBuilder; + +public class JcaPKIArchiveControlBuilder + extends PKIArchiveControlBuilder +{ + public JcaPKIArchiveControlBuilder(PrivateKey privateKey, X500Name name) + { + this(privateKey, new GeneralName(name)); + } + + public JcaPKIArchiveControlBuilder(PrivateKey privateKey, X500Principal name) + { + this(privateKey, X500Name.getInstance(name.getEncoded())); + } + + public JcaPKIArchiveControlBuilder(PrivateKey privateKey, GeneralName generalName) + { + super(PrivateKeyInfo.getInstance(privateKey.getEncoded()), generalName); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JceAsymmetricValueDecryptorGenerator.java b/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JceAsymmetricValueDecryptorGenerator.java new file mode 100644 index 00000000..8ad510bb --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JceAsymmetricValueDecryptorGenerator.java @@ -0,0 +1,120 @@ +package org.spongycastle.cert.crmf.jcajce; + +import java.io.InputStream; +import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.ProviderException; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.spec.SecretKeySpec; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cert.crmf.CRMFException; +import org.spongycastle.cert.crmf.ValueDecryptorGenerator; +import org.spongycastle.jcajce.util.DefaultJcaJceHelper; +import org.spongycastle.jcajce.util.NamedJcaJceHelper; +import org.spongycastle.jcajce.util.ProviderJcaJceHelper; +import org.spongycastle.operator.InputDecryptor; + +public class JceAsymmetricValueDecryptorGenerator + implements ValueDecryptorGenerator +{ + private PrivateKey recipientKey; + private CRMFHelper helper = new CRMFHelper(new DefaultJcaJceHelper()); + + public JceAsymmetricValueDecryptorGenerator(PrivateKey recipientKey) + { + this.recipientKey = recipientKey; + } + + public JceAsymmetricValueDecryptorGenerator setProvider(Provider provider) + { + this.helper = new CRMFHelper(new ProviderJcaJceHelper(provider)); + + return this; + } + + public JceAsymmetricValueDecryptorGenerator setProvider(String providerName) + { + this.helper = new CRMFHelper(new NamedJcaJceHelper(providerName)); + + return this; + } + + private Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey) + throws CRMFException + { + try + { + Key sKey = null; + + Cipher keyCipher = helper.createCipher(keyEncryptionAlgorithm.getAlgorithm()); + + try + { + keyCipher.init(Cipher.UNWRAP_MODE, recipientKey); + sKey = keyCipher.unwrap(encryptedContentEncryptionKey, contentEncryptionAlgorithm.getAlgorithm().getId(), Cipher.SECRET_KEY); + } + catch (GeneralSecurityException e) + { + } + catch (IllegalStateException e) + { + } + catch (UnsupportedOperationException e) + { + } + catch (ProviderException e) + { + } + + // some providers do not support UNWRAP (this appears to be only for asymmetric algorithms) + if (sKey == null) + { + keyCipher.init(Cipher.DECRYPT_MODE, recipientKey); + sKey = new SecretKeySpec(keyCipher.doFinal(encryptedContentEncryptionKey), contentEncryptionAlgorithm.getAlgorithm().getId()); + } + + return sKey; + } + catch (InvalidKeyException e) + { + throw new CRMFException("key invalid in message.", e); + } + catch (IllegalBlockSizeException e) + { + throw new CRMFException("illegal blocksize in message.", e); + } + catch (BadPaddingException e) + { + throw new CRMFException("bad padding in message.", e); + } + } + + public InputDecryptor getValueDecryptor(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey) + throws CRMFException + { + Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, encryptedContentEncryptionKey); + + final Cipher dataCipher = helper.createContentCipher(secretKey, contentEncryptionAlgorithm); + + return new InputDecryptor() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return contentEncryptionAlgorithm; + } + + public InputStream getInputStream(InputStream dataIn) + { + return new CipherInputStream(dataIn, dataCipher); + } + }; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JceCRMFEncryptorBuilder.java b/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JceCRMFEncryptorBuilder.java new file mode 100644 index 00000000..6147184f --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JceCRMFEncryptorBuilder.java @@ -0,0 +1,136 @@ +package org.spongycastle.cert.crmf.jcajce; + +import java.io.OutputStream; +import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; +import java.security.Provider; +import java.security.SecureRandom; + +import javax.crypto.Cipher; +import javax.crypto.CipherOutputStream; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cert.crmf.CRMFException; +import org.spongycastle.jcajce.util.DefaultJcaJceHelper; +import org.spongycastle.jcajce.util.NamedJcaJceHelper; +import org.spongycastle.jcajce.util.ProviderJcaJceHelper; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.OutputEncryptor; +import org.spongycastle.operator.jcajce.JceGenericKey; + +public class JceCRMFEncryptorBuilder +{ + private final ASN1ObjectIdentifier encryptionOID; + private final int keySize; + + private CRMFHelper helper = new CRMFHelper(new DefaultJcaJceHelper()); + private SecureRandom random; + + public JceCRMFEncryptorBuilder(ASN1ObjectIdentifier encryptionOID) + { + this(encryptionOID, -1); + } + + public JceCRMFEncryptorBuilder(ASN1ObjectIdentifier encryptionOID, int keySize) + { + this.encryptionOID = encryptionOID; + this.keySize = keySize; + } + + public JceCRMFEncryptorBuilder setProvider(Provider provider) + { + this.helper = new CRMFHelper(new ProviderJcaJceHelper(provider)); + + return this; + } + + public JceCRMFEncryptorBuilder setProvider(String providerName) + { + this.helper = new CRMFHelper(new NamedJcaJceHelper(providerName)); + + return this; + } + + public JceCRMFEncryptorBuilder setSecureRandom(SecureRandom random) + { + this.random = random; + + return this; + } + + public OutputEncryptor build() + throws CRMFException + { + return new CRMFOutputEncryptor(encryptionOID, keySize, random); + } + + private class CRMFOutputEncryptor + implements OutputEncryptor + { + private SecretKey encKey; + private AlgorithmIdentifier algorithmIdentifier; + private Cipher cipher; + + CRMFOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, SecureRandom random) + throws CRMFException + { + KeyGenerator keyGen = helper.createKeyGenerator(encryptionOID); + + if (random == null) + { + random = new SecureRandom(); + } + + if (keySize < 0) + { + keyGen.init(random); + } + else + { + keyGen.init(keySize, random); + } + + cipher = helper.createCipher(encryptionOID); + encKey = keyGen.generateKey(); + AlgorithmParameters params = helper.generateParameters(encryptionOID, encKey, random); + + try + { + cipher.init(Cipher.ENCRYPT_MODE, encKey, params, random); + } + catch (GeneralSecurityException e) + { + throw new CRMFException("unable to initialize cipher: " + e.getMessage(), e); + } + + // + // If params are null we try and second guess on them as some providers don't provide + // algorithm parameter generation explicity but instead generate them under the hood. + // + if (params == null) + { + params = cipher.getParameters(); + } + + algorithmIdentifier = helper.getAlgorithmIdentifier(encryptionOID, params); + } + + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return algorithmIdentifier; + } + + public OutputStream getOutputStream(OutputStream dOut) + { + return new CipherOutputStream(dOut, cipher); + } + + public GenericKey getKey() + { + return new JceGenericKey(algorithmIdentifier, encKey); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcePKMACValuesCalculator.java b/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcePKMACValuesCalculator.java new file mode 100644 index 00000000..ceaf78cb --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcePKMACValuesCalculator.java @@ -0,0 +1,69 @@ +package org.spongycastle.cert.crmf.jcajce; + +import java.security.GeneralSecurityException; +import java.security.MessageDigest; +import java.security.Provider; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cert.crmf.CRMFException; +import org.spongycastle.cert.crmf.PKMACValuesCalculator; +import org.spongycastle.jcajce.util.DefaultJcaJceHelper; +import org.spongycastle.jcajce.util.NamedJcaJceHelper; +import org.spongycastle.jcajce.util.ProviderJcaJceHelper; + +public class JcePKMACValuesCalculator + implements PKMACValuesCalculator +{ + private MessageDigest digest; + private Mac mac; + private CRMFHelper helper; + + public JcePKMACValuesCalculator() + { + this.helper = new CRMFHelper(new DefaultJcaJceHelper()); + } + + public JcePKMACValuesCalculator setProvider(Provider provider) + { + this.helper = new CRMFHelper(new ProviderJcaJceHelper(provider)); + + return this; + } + + public JcePKMACValuesCalculator setProvider(String providerName) + { + this.helper = new CRMFHelper(new NamedJcaJceHelper(providerName)); + + return this; + } + + public void setup(AlgorithmIdentifier digAlg, AlgorithmIdentifier macAlg) + throws CRMFException + { + digest = helper.createDigest(digAlg.getAlgorithm()); + mac = helper.createMac(macAlg.getAlgorithm()); + } + + public byte[] calculateDigest(byte[] data) + { + return digest.digest(data); + } + + public byte[] calculateMac(byte[] pwd, byte[] data) + throws CRMFException + { + try + { + mac.init(new SecretKeySpec(pwd, mac.getAlgorithm())); + + return mac.doFinal(data); + } + catch (GeneralSecurityException e) + { + throw new CRMFException("failure in setup: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/jcajce/CertHelper.java b/pkix/src/main/java/org/spongycastle/cert/jcajce/CertHelper.java new file mode 100644 index 00000000..1c5679bf --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/jcajce/CertHelper.java @@ -0,0 +1,17 @@ +package org.spongycastle.cert.jcajce; + +import java.security.NoSuchProviderException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; + +abstract class CertHelper +{ + public CertificateFactory getCertificateFactory(String type) + throws NoSuchProviderException, CertificateException + { + return createCertificateFactory(type); + } + + protected abstract CertificateFactory createCertificateFactory(String type) + throws CertificateException, NoSuchProviderException; +} diff --git a/pkix/src/main/java/org/spongycastle/cert/jcajce/DefaultCertHelper.java b/pkix/src/main/java/org/spongycastle/cert/jcajce/DefaultCertHelper.java new file mode 100644 index 00000000..d8713bf3 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/jcajce/DefaultCertHelper.java @@ -0,0 +1,14 @@ +package org.spongycastle.cert.jcajce; + +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; + +class DefaultCertHelper + extends CertHelper +{ + protected CertificateFactory createCertificateFactory(String type) + throws CertificateException + { + return CertificateFactory.getInstance(type); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaAttrCertStore.java b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaAttrCertStore.java new file mode 100644 index 00000000..ed354335 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaAttrCertStore.java @@ -0,0 +1,62 @@ +package org.spongycastle.cert.jcajce; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.spongycastle.util.CollectionStore; +import org.spongycastle.x509.X509AttributeCertificate; + +/** + * Class for storing Attribute Certificates for later lookup. + * <p> + * The class will convert X509AttributeCertificate objects into X509AttributeCertificateHolder objects. + * </p> + */ +public class JcaAttrCertStore + extends CollectionStore +{ + /** + * Basic constructor. + * + * @param collection - initial contents for the store, this is copied. + */ + public JcaAttrCertStore(Collection collection) + throws IOException + { + super(convertCerts(collection)); + } + + public JcaAttrCertStore(X509AttributeCertificate attrCert) + throws IOException + { + this(Collections.singletonList(attrCert)); + } + + private static Collection convertCerts(Collection collection) + throws IOException + { + List list = new ArrayList(collection.size()); + + for (Iterator it = collection.iterator(); it.hasNext();) + { + Object o = it.next(); + + if (o instanceof X509AttributeCertificate) + { + X509AttributeCertificate cert = (X509AttributeCertificate)o; + + list.add(new JcaX509AttributeCertificateHolder(cert)); + } + else + { + list.add(o); + } + } + + return list; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaAttributeCertificateIssuer.java b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaAttributeCertificateIssuer.java new file mode 100644 index 00000000..54ee46ee --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaAttributeCertificateIssuer.java @@ -0,0 +1,32 @@ +package org.spongycastle.cert.jcajce; + +import java.security.cert.X509Certificate; + +import javax.security.auth.x500.X500Principal; + +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.cert.AttributeCertificateIssuer; + +public class JcaAttributeCertificateIssuer + extends AttributeCertificateIssuer +{ + /** + * Base constructor. + * + * @param issuerCert certificate for the issuer of the attribute certificate. + */ + public JcaAttributeCertificateIssuer(X509Certificate issuerCert) + { + this(issuerCert.getIssuerX500Principal()); + } + + /** + * Base constructor. + * + * @param issuerDN X.500 DN for the issuer of the attribute certificate. + */ + public JcaAttributeCertificateIssuer(X500Principal issuerDN) + { + super(X500Name.getInstance(issuerDN.getEncoded())); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaCRLStore.java b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaCRLStore.java new file mode 100644 index 00000000..08493d13 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaCRLStore.java @@ -0,0 +1,63 @@ +package org.spongycastle.cert.jcajce; + +import java.io.IOException; +import java.security.cert.CRLException; +import java.security.cert.X509CRL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.spongycastle.cert.X509CRLHolder; +import org.spongycastle.util.CollectionStore; + +/** + * Class for storing CRLs for later lookup. + * <p> + * The class will convert X509CRL objects into X509CRLHolder objects. + * </p> + */ +public class JcaCRLStore + extends CollectionStore +{ + /** + * Basic constructor. + * + * @param collection - initial contents for the store, this is copied. + */ + public JcaCRLStore(Collection collection) + throws CRLException + { + super(convertCRLs(collection)); + } + + private static Collection convertCRLs(Collection collection) + throws CRLException + { + List list = new ArrayList(collection.size()); + + for (Iterator it = collection.iterator(); it.hasNext();) + { + Object crl = it.next(); + + if (crl instanceof X509CRL) + { + try + { + list.add(new X509CRLHolder(((X509CRL)crl).getEncoded())); + } + catch (IOException e) + { + throw new CRLException("cannot read encoding: " + e.getMessage()); + + } + } + else + { + list.add((X509CRLHolder)crl); + } + } + + return list; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaCertStore.java b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaCertStore.java new file mode 100644 index 00000000..49766814 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaCertStore.java @@ -0,0 +1,64 @@ +package org.spongycastle.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 org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaCertStoreBuilder.java b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaCertStoreBuilder.java new file mode 100644 index 00000000..fbb26cb4 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaCertStoreBuilder.java @@ -0,0 +1,148 @@ +package org.spongycastle.cert.jcajce; + +import java.security.GeneralSecurityException; +import java.security.Provider; +import java.security.cert.CRLException; +import java.security.cert.CertStore; +import java.security.cert.CertificateException; +import java.security.cert.CollectionCertStoreParameters; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.spongycastle.cert.X509CRLHolder; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.util.Store; + +/** + * Builder to create a CertStore from certificate and CRL stores. + */ +public class JcaCertStoreBuilder +{ + private List certs = new ArrayList(); + private List crls = new ArrayList(); + private Object provider; + private JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter(); + private JcaX509CRLConverter crlConverter = new JcaX509CRLConverter(); + private String type = "Collection"; + + /** + * Add a store full of X509CertificateHolder objects. + * + * @param certStore a store of X509CertificateHolder objects. + */ + public JcaCertStoreBuilder addCertificates(Store certStore) + { + certs.addAll(certStore.getMatches(null)); + + return this; + } + + /** + * Add a single certificate. + * + * @param cert the X509 certificate holder containing the certificate. + */ + public JcaCertStoreBuilder addCertificate(X509CertificateHolder cert) + { + certs.add(cert); + + return this; + } + + /** + * Add a store full of X509CRLHolder objects. + * @param crlStore a store of X509CRLHolder objects. + */ + public JcaCertStoreBuilder addCRLs(Store crlStore) + { + crls.addAll(crlStore.getMatches(null)); + + return this; + } + + /** + * Add a single CRL. + * + * @param crl the X509 CRL holder containing the CRL. + */ + public JcaCertStoreBuilder addCRL(X509CRLHolder crl) + { + crls.add(crl); + + return this; + } + + public JcaCertStoreBuilder setProvider(String providerName) + { + certificateConverter.setProvider(providerName); + crlConverter.setProvider(providerName); + this.provider = providerName; + + return this; + } + + public JcaCertStoreBuilder setProvider(Provider provider) + { + certificateConverter.setProvider(provider); + crlConverter.setProvider(provider); + this.provider = provider; + + return this; + } + + /** + * Set the type of the CertStore generated. By default it is "Collection". + * + * @param type type of CertStore passed to CertStore.getInstance(). + * @return the current builder. + */ + public JcaCertStoreBuilder setType(String type) + { + this.type = type; + + return this; + } + + /** + * Build the CertStore from the current inputs. + * + * @return a CertStore. + * @throws GeneralSecurityException + */ + public CertStore build() + throws GeneralSecurityException + { + CollectionCertStoreParameters params = convertHolders(certificateConverter, crlConverter); + + if (provider instanceof String) + { + return CertStore.getInstance(type, params, (String)provider); + } + + if (provider instanceof Provider) + { + return CertStore.getInstance(type, params, (Provider)provider); + } + + return CertStore.getInstance(type, params); + } + + private CollectionCertStoreParameters convertHolders(JcaX509CertificateConverter certificateConverter, JcaX509CRLConverter crlConverter) + throws CertificateException, CRLException + { + List jcaObjs = new ArrayList(certs.size() + crls.size()); + + for (Iterator it = certs.iterator(); it.hasNext();) + { + jcaObjs.add(certificateConverter.getCertificate((X509CertificateHolder)it.next())); + } + + for (Iterator it = crls.iterator(); it.hasNext();) + { + jcaObjs.add(crlConverter.getCRL((X509CRLHolder)it.next())); + } + + return new CollectionCertStoreParameters(jcaObjs); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX500NameUtil.java b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX500NameUtil.java new file mode 100644 index 00000000..d6b6ae89 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX500NameUtil.java @@ -0,0 +1,29 @@ +package org.spongycastle.cert.jcajce; + +import java.security.cert.X509Certificate; + +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x500.X500NameStyle; + +public class JcaX500NameUtil +{ + public static X500Name getIssuer(X509Certificate certificate) + { + return X500Name.getInstance(certificate.getIssuerX500Principal().getEncoded()); + } + + public static X500Name getSubject(X509Certificate certificate) + { + return X500Name.getInstance(certificate.getSubjectX500Principal().getEncoded()); + } + + public static X500Name getIssuer(X500NameStyle style, X509Certificate certificate) + { + return X500Name.getInstance(style, certificate.getIssuerX500Principal().getEncoded()); + } + + public static X500Name getSubject(X500NameStyle style, X509Certificate certificate) + { + return X500Name.getInstance(style, certificate.getSubjectX500Principal().getEncoded()); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509AttributeCertificateHolder.java b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509AttributeCertificateHolder.java new file mode 100644 index 00000000..35076252 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509AttributeCertificateHolder.java @@ -0,0 +1,26 @@ +package org.spongycastle.cert.jcajce; + +import java.io.IOException; + +import org.spongycastle.asn1.x509.AttributeCertificate; +import org.spongycastle.cert.X509AttributeCertificateHolder; +import org.spongycastle.x509.X509AttributeCertificate; + +/** + * JCA helper class for converting an old style X509AttributeCertificate into a X509AttributeCertificateHolder object. + */ +public class JcaX509AttributeCertificateHolder + extends X509AttributeCertificateHolder +{ + /** + * Base constructor. + * + * @param cert AttributeCertificate to be used a the source for the holder creation. + * @throws IOException if there is a problem extracting the attribute certificate information. + */ + public JcaX509AttributeCertificateHolder(X509AttributeCertificate cert) + throws IOException + { + super(AttributeCertificate.getInstance(cert.getEncoded())); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CRLConverter.java b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CRLConverter.java new file mode 100644 index 00000000..7040f1aa --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CRLConverter.java @@ -0,0 +1,103 @@ +package org.spongycastle.cert.jcajce; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.cert.CRLException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509CRL; + +import org.spongycastle.cert.X509CRLHolder; + +/** + * Class for converting an X509CRLHolder into a corresponding X509CRL object tied to a + * particular JCA provider. + */ +public class JcaX509CRLConverter +{ + private CertHelper helper = new DefaultCertHelper(); + + /** + * Base constructor, configure with the default provider. + */ + public JcaX509CRLConverter() + { + this.helper = new DefaultCertHelper(); + } + + /** + * Set the provider to use from a Provider object. + * + * @param provider the provider to use. + * @return the converter instance. + */ + public JcaX509CRLConverter setProvider(Provider provider) + { + this.helper = new ProviderCertHelper(provider); + + return this; + } + + /** + * Set the provider to use by name. + * + * @param providerName name of the provider to use. + * @return the converter instance. + */ + public JcaX509CRLConverter setProvider(String providerName) + { + this.helper = new NamedCertHelper(providerName); + + return this; + } + + /** + * Use the configured converter to produce a X509CRL object from a X509CRLHolder object. + * + * @param crlHolder the holder to be converted + * @return a X509CRL object + * @throws CRLException if the conversion is unable to be made. + */ + public X509CRL getCRL(X509CRLHolder crlHolder) + throws CRLException + { + try + { + CertificateFactory cFact = helper.getCertificateFactory("X.509"); + + return (X509CRL)cFact.generateCRL(new ByteArrayInputStream(crlHolder.getEncoded())); + } + catch (IOException e) + { + throw new ExCRLException("exception parsing certificate: " + e.getMessage(), e); + } + catch (NoSuchProviderException e) + { + throw new ExCRLException("cannot find required provider:" + e.getMessage(), e); + } + catch (CertificateException e) + { + throw new ExCRLException("cannot create factory: " + e.getMessage(), e); + } + } + + private class ExCRLException + extends CRLException + { + private Throwable cause; + + public ExCRLException(String msg, Throwable cause) + { + super(msg); + + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CRLHolder.java b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CRLHolder.java new file mode 100644 index 00000000..91bcd88d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CRLHolder.java @@ -0,0 +1,26 @@ +package org.spongycastle.cert.jcajce; + +import java.security.cert.CRLException; +import java.security.cert.X509CRL; + +import org.spongycastle.asn1.x509.CertificateList; +import org.spongycastle.cert.X509CRLHolder; + +/** + * JCA helper class for converting an X509CRL into a X509CRLHolder object. + */ +public class JcaX509CRLHolder + extends X509CRLHolder +{ + /** + * Base constructor. + * + * @param crl CRL to be used a the source for the holder creation. + * @throws CRLException if there is a problem extracting the CRL information. + */ + public JcaX509CRLHolder(X509CRL crl) + throws CRLException + { + super(CertificateList.getInstance(crl.getEncoded())); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CertificateConverter.java b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CertificateConverter.java new file mode 100644 index 00000000..5e46a17d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CertificateConverter.java @@ -0,0 +1,116 @@ +package org.spongycastle.cert.jcajce; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; + +import org.spongycastle.cert.X509CertificateHolder; + +/** + * Converter for producing X509Certificate objects tied to a specific provider from X509CertificateHolder objects. + */ +public class JcaX509CertificateConverter +{ + private CertHelper helper = new DefaultCertHelper(); + + /** + * Base constructor, configure with the default provider. + */ + public JcaX509CertificateConverter() + { + this.helper = new DefaultCertHelper(); + } + + /** + * Set the provider to use from a Provider object. + * + * @param provider the provider to use. + * @return the converter instance. + */ + public JcaX509CertificateConverter setProvider(Provider provider) + { + this.helper = new ProviderCertHelper(provider); + + return this; + } + + /** + * Set the provider to use by name. + * + * @param providerName name of the provider to use. + * @return the converter instance. + */ + public JcaX509CertificateConverter setProvider(String providerName) + { + this.helper = new NamedCertHelper(providerName); + + return this; + } + + /** + * Use the configured converter to produce a X509Certificate object from a X509CertificateHolder object. + * + * @param certHolder the holder to be converted + * @return a X509Certificate object + * @throws CertificateException if the conversion is unable to be made. + */ + public X509Certificate getCertificate(X509CertificateHolder certHolder) + throws CertificateException + { + try + { + CertificateFactory cFact = helper.getCertificateFactory("X.509"); + + return (X509Certificate)cFact.generateCertificate(new ByteArrayInputStream(certHolder.getEncoded())); + } + catch (IOException e) + { + throw new ExCertificateParsingException("exception parsing certificate: " + e.getMessage(), e); + } + catch (NoSuchProviderException e) + { + throw new ExCertificateException("cannot find required provider:" + e.getMessage(), e); + } + } + + private class ExCertificateParsingException + extends CertificateParsingException + { + private Throwable cause; + + public ExCertificateParsingException(String msg, Throwable cause) + { + super(msg); + + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } + } + + private class ExCertificateException + extends CertificateException + { + private Throwable cause; + + public ExCertificateException(String msg, Throwable cause) + { + super(msg); + + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CertificateHolder.java b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CertificateHolder.java new file mode 100644 index 00000000..a523f975 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CertificateHolder.java @@ -0,0 +1,26 @@ +package org.spongycastle.cert.jcajce; + +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; + +import org.spongycastle.asn1.x509.Certificate; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509ContentVerifierProviderBuilder.java b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509ContentVerifierProviderBuilder.java new file mode 100644 index 00000000..46eb3b43 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509ContentVerifierProviderBuilder.java @@ -0,0 +1,50 @@ +package org.spongycastle.cert.jcajce; + +import java.security.Provider; +import java.security.cert.CertificateException; + +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.cert.X509ContentVerifierProviderBuilder; +import org.spongycastle.operator.ContentVerifierProvider; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.operator.jcajce.JcaContentVerifierProviderBuilder; + +public class JcaX509ContentVerifierProviderBuilder + implements X509ContentVerifierProviderBuilder +{ + private JcaContentVerifierProviderBuilder builder = new JcaContentVerifierProviderBuilder(); + + public JcaX509ContentVerifierProviderBuilder setProvider(Provider provider) + { + this.builder.setProvider(provider); + + return this; + } + + public JcaX509ContentVerifierProviderBuilder setProvider(String providerName) + { + this.builder.setProvider(providerName); + + return this; + } + + public ContentVerifierProvider build(SubjectPublicKeyInfo validatingKeyInfo) + throws OperatorCreationException + { + return builder.build(validatingKeyInfo); + } + + public ContentVerifierProvider build(X509CertificateHolder validatingKeyInfo) + throws OperatorCreationException + { + try + { + return builder.build(validatingKeyInfo); + } + catch (CertificateException e) + { + throw new OperatorCreationException("Unable to process certificate: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509ExtensionUtils.java b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509ExtensionUtils.java new file mode 100644 index 00000000..b601e24e --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509ExtensionUtils.java @@ -0,0 +1,145 @@ +package org.spongycastle.cert.jcajce; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; + +import javax.security.auth.x500.X500Principal; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.AuthorityKeyIdentifier; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.asn1.x509.GeneralNames; +import org.spongycastle.asn1.x509.SubjectKeyIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.cert.X509ExtensionUtils; +import org.spongycastle.operator.DigestCalculator; + +public class JcaX509ExtensionUtils + extends X509ExtensionUtils +{ + /** + * Create a utility class pre-configured with a SHA-1 digest calculator based on the + * default implementation. + * + * @throws NoSuchAlgorithmException + */ + public JcaX509ExtensionUtils() + throws NoSuchAlgorithmException + { + super(new SHA1DigestCalculator(MessageDigest.getInstance("SHA1"))); + } + + public JcaX509ExtensionUtils(DigestCalculator calculator) + { + super(calculator); + } + + public AuthorityKeyIdentifier createAuthorityKeyIdentifier( + X509Certificate cert) + throws CertificateEncodingException + { + return super.createAuthorityKeyIdentifier(new JcaX509CertificateHolder(cert)); + } + + public AuthorityKeyIdentifier createAuthorityKeyIdentifier( + PublicKey pubKey) + { + return super.createAuthorityKeyIdentifier(SubjectPublicKeyInfo.getInstance(pubKey.getEncoded())); + } + + public AuthorityKeyIdentifier createAuthorityKeyIdentifier(PublicKey pubKey, X500Principal name, BigInteger serial) + { + return super.createAuthorityKeyIdentifier(SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()), new GeneralNames(new GeneralName(X500Name.getInstance(name.getEncoded()))), serial); + } + + public AuthorityKeyIdentifier createAuthorityKeyIdentifier(PublicKey pubKey, GeneralNames generalNames, BigInteger serial) + { + return super.createAuthorityKeyIdentifier(SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()), generalNames, serial); + } + + /** + * Return a RFC 3280 type 1 key identifier. As in: + * <pre> + * (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the + * value of the BIT STRING subjectPublicKey (excluding the tag, + * length, and number of unused bits). + * </pre> + * @param publicKey the key object containing the key identifier is to be based on. + * @return the key identifier. + */ + public SubjectKeyIdentifier createSubjectKeyIdentifier( + PublicKey publicKey) + { + return super.createSubjectKeyIdentifier(SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); + } + + /** + * Return a RFC 3280 type 2 key identifier. As in: + * <pre> + * (2) The keyIdentifier is composed of a four bit type field with + * the value 0100 followed by the least significant 60 bits of the + * SHA-1 hash of the value of the BIT STRING subjectPublicKey. + * </pre> + * @param publicKey the key object of interest. + * @return the key identifier. + */ + public SubjectKeyIdentifier createTruncatedSubjectKeyIdentifier(PublicKey publicKey) + { + return super.createSubjectKeyIdentifier(SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); + } + + /** + * Return the ASN.1 object contained in a byte[] returned by a getExtensionValue() call. + * + * @param encExtValue DER encoded OCTET STRING containing the DER encoded extension object. + * @return an ASN.1 object + * @throws java.io.IOException on a parsing error. + */ + public static ASN1Primitive parseExtensionValue(byte[] encExtValue) + throws IOException + { + return ASN1Primitive.fromByteArray(ASN1OctetString.getInstance(encExtValue).getOctets()); + } + + private static class SHA1DigestCalculator + implements DigestCalculator + { + private ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + private MessageDigest digest; + + public SHA1DigestCalculator(MessageDigest digest) + { + this.digest = digest; + } + + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1); + } + + public OutputStream getOutputStream() + { + return bOut; + } + + public byte[] getDigest() + { + byte[] bytes = digest.digest(bOut.toByteArray()); + + bOut.reset(); + + return bytes; + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509v1CertificateBuilder.java b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509v1CertificateBuilder.java new file mode 100644 index 00000000..e5e4f83d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509v1CertificateBuilder.java @@ -0,0 +1,48 @@ +package org.spongycastle.cert.jcajce; + +import java.math.BigInteger; +import java.security.PublicKey; +import java.util.Date; + +import javax.security.auth.x500.X500Principal; + +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.cert.X509v1CertificateBuilder; + +/** + * JCA helper class to allow JCA objects to be used in the construction of a Version 1 certificate. + */ +public class JcaX509v1CertificateBuilder + extends X509v1CertificateBuilder +{ + /** + * Initialise the builder using a PublicKey. + * + * @param issuer X500Name representing the issuer of this certificate. + * @param serial the serial number for the certificate. + * @param notBefore date before which the certificate is not valid. + * @param notAfter date after which the certificate is not valid. + * @param subject X500Name representing the subject of this certificate. + * @param publicKey the public key to be associated with the certificate. + */ + public JcaX509v1CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, PublicKey publicKey) + { + super(issuer, serial, notBefore, notAfter, subject, SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); + } + + /** + * Initialise the builder using X500Principal objects and a PublicKey. + * + * @param issuer principal representing the issuer of this certificate. + * @param serial the serial number for the certificate. + * @param notBefore date before which the certificate is not valid. + * @param notAfter date after which the certificate is not valid. + * @param subject principal representing the subject of this certificate. + * @param publicKey the public key to be associated with the certificate. + */ + public JcaX509v1CertificateBuilder(X500Principal issuer, BigInteger serial, Date notBefore, Date notAfter, X500Principal subject, PublicKey publicKey) + { + super(X500Name.getInstance(issuer.getEncoded()), serial, notBefore, notAfter, X500Name.getInstance(subject.getEncoded()), SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509v2CRLBuilder.java b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509v2CRLBuilder.java new file mode 100644 index 00000000..97d544bd --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509v2CRLBuilder.java @@ -0,0 +1,23 @@ +package org.spongycastle.cert.jcajce; + +import java.security.cert.X509Certificate; +import java.util.Date; + +import javax.security.auth.x500.X500Principal; + +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.cert.X509v2CRLBuilder; + +public class JcaX509v2CRLBuilder + extends X509v2CRLBuilder +{ + public JcaX509v2CRLBuilder(X500Principal issuer, Date now) + { + super(X500Name.getInstance(issuer.getEncoded()), now); + } + + public JcaX509v2CRLBuilder(X509Certificate issuerCert, Date now) + { + this(issuerCert.getSubjectX500Principal(), now); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509v3CertificateBuilder.java b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509v3CertificateBuilder.java new file mode 100644 index 00000000..238edbe8 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509v3CertificateBuilder.java @@ -0,0 +1,119 @@ +package org.spongycastle.cert.jcajce; + +import java.math.BigInteger; +import java.security.PublicKey; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.util.Date; + +import javax.security.auth.x500.X500Principal; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.asn1.x509.Time; +import org.spongycastle.cert.X509v3CertificateBuilder; + +/** + * JCA helper class to allow JCA objects to be used in the construction of a Version 3 certificate. + */ +public class JcaX509v3CertificateBuilder + extends X509v3CertificateBuilder +{ + /** + * Initialise the builder using a PublicKey. + * + * @param issuer X500Name representing the issuer of this certificate. + * @param serial the serial number for the certificate. + * @param notBefore date before which the certificate is not valid. + * @param notAfter date after which the certificate is not valid. + * @param subject X500Name representing the subject of this certificate. + * @param publicKey the public key to be associated with the certificate. + */ + public JcaX509v3CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, PublicKey publicKey) + { + super(issuer, serial, notBefore, notAfter, subject, SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); + } + + /** + * Initialise the builder using a PublicKey. + * + * @param issuer X500Name representing the issuer of this certificate. + * @param serial the serial number for the certificate. + * @param notBefore Time before which the certificate is not valid. + * @param notAfter Time after which the certificate is not valid. + * @param subject X500Name representing the subject of this certificate. + * @param publicKey the public key to be associated with the certificate. + */ + public JcaX509v3CertificateBuilder(X500Name issuer, BigInteger serial, Time notBefore, Time notAfter, X500Name subject, PublicKey publicKey) + { + super(issuer, serial, notBefore, notAfter, subject, SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); + } + + /** + * Initialise the builder using X500Principal objects and a PublicKey. + * + * @param issuer principal representing the issuer of this certificate. + * @param serial the serial number for the certificate. + * @param notBefore date before which the certificate is not valid. + * @param notAfter date after which the certificate is not valid. + * @param subject principal representing the subject of this certificate. + * @param publicKey the public key to be associated with the certificate. + */ + public JcaX509v3CertificateBuilder(X500Principal issuer, BigInteger serial, Date notBefore, Date notAfter, X500Principal subject, PublicKey publicKey) + { + super(X500Name.getInstance(issuer.getEncoded()), serial, notBefore, notAfter, X500Name.getInstance(subject.getEncoded()), SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); + } + + /** + * Initialise the builder using the subject from the passed in issuerCert as the issuer, as well as + * passing through and converting the other objects provided. + * + * @param issuerCert certificate who's subject is the issuer of the certificate we are building. + * @param serial the serial number for the certificate. + * @param notBefore date before which the certificate is not valid. + * @param notAfter date after which the certificate is not valid. + * @param subject principal representing the subject of this certificate. + * @param publicKey the public key to be associated with the certificate. + */ + public JcaX509v3CertificateBuilder(X509Certificate issuerCert, BigInteger serial, Date notBefore, Date notAfter, X500Principal subject, PublicKey publicKey) + { + this(issuerCert.getSubjectX500Principal(), serial, notBefore, notAfter, subject, publicKey); + } + + /** + * Initialise the builder using the subject from the passed in issuerCert as the issuer, as well as + * passing through and converting the other objects provided. + * + * @param issuerCert certificate who's subject is the issuer of the certificate we are building. + * @param serial the serial number for the certificate. + * @param notBefore date before which the certificate is not valid. + * @param notAfter date after which the certificate is not valid. + * @param subject principal representing the subject of this certificate. + * @param publicKey the public key to be associated with the certificate. + */ + public JcaX509v3CertificateBuilder(X509Certificate issuerCert, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, PublicKey publicKey) + { + this(X500Name.getInstance(issuerCert.getSubjectX500Principal().getEncoded()), serial, notBefore, notAfter, subject, publicKey); + } + + /** + * Add a given extension field for the standard extensions tag (tag 3) + * copying the extension value from another certificate. + * + * @param oid the type of the extension to be copied. + * @param critical true if the extension is to be marked critical, false otherwise. + * @param certificate the source of the extension to be copied. + * @return the builder instance. + */ + public JcaX509v3CertificateBuilder copyAndAddExtension( + ASN1ObjectIdentifier oid, + boolean critical, + X509Certificate certificate) + throws CertificateEncodingException + { + this.copyAndAddExtension(oid, critical, new JcaX509CertificateHolder(certificate)); + + return this; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/jcajce/NamedCertHelper.java b/pkix/src/main/java/org/spongycastle/cert/jcajce/NamedCertHelper.java new file mode 100644 index 00000000..89584138 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/jcajce/NamedCertHelper.java @@ -0,0 +1,22 @@ +package org.spongycastle.cert.jcajce; + +import java.security.NoSuchProviderException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; + +class NamedCertHelper + extends CertHelper +{ + private final String providerName; + + NamedCertHelper(String providerName) + { + this.providerName = providerName; + } + + protected CertificateFactory createCertificateFactory(String type) + throws CertificateException, NoSuchProviderException + { + return CertificateFactory.getInstance(type, providerName); + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cert/jcajce/ProviderCertHelper.java b/pkix/src/main/java/org/spongycastle/cert/jcajce/ProviderCertHelper.java new file mode 100644 index 00000000..ffe37e9b --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/jcajce/ProviderCertHelper.java @@ -0,0 +1,22 @@ +package org.spongycastle.cert.jcajce; + +import java.security.Provider; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; + +class ProviderCertHelper + extends CertHelper +{ + private final Provider provider; + + ProviderCertHelper(Provider provider) + { + this.provider = provider; + } + + protected CertificateFactory createCertificateFactory(String type) + throws CertificateException + { + return CertificateFactory.getInstance(type, provider); + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cert/ocsp/BasicOCSPResp.java b/pkix/src/main/java/org/spongycastle/cert/ocsp/BasicOCSPResp.java new file mode 100644 index 00000000..f3c65670 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/ocsp/BasicOCSPResp.java @@ -0,0 +1,212 @@ +package org.spongycastle.cert.ocsp; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Date; +import java.util.List; +import java.util.Set; + +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.ocsp.BasicOCSPResponse; +import org.spongycastle.asn1.ocsp.ResponseData; +import org.spongycastle.asn1.ocsp.SingleResponse; +import org.spongycastle.asn1.x509.Certificate; +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.asn1.x509.Extensions; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.operator.ContentVerifier; +import org.spongycastle.operator.ContentVerifierProvider; + +/** + * <pre> + * BasicOCSPResponse ::= SEQUENCE { + * tbsResponseData ResponseData, + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING, + * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } + * </pre> + */ +public class BasicOCSPResp +{ + 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; + } + } + + 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().getBytes(); + } + + 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/pkix/src/main/java/org/spongycastle/cert/ocsp/BasicOCSPRespBuilder.java b/pkix/src/main/java/org/spongycastle/cert/ocsp/BasicOCSPRespBuilder.java new file mode 100644 index 00000000..ac759de6 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/ocsp/BasicOCSPRespBuilder.java @@ -0,0 +1,264 @@ +package org.spongycastle.cert.ocsp; + +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1GeneralizedTime; +import org.spongycastle.asn1.DERBitString; +import org.spongycastle.asn1.DERGeneralizedTime; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.ocsp.BasicOCSPResponse; +import org.spongycastle.asn1.ocsp.CertStatus; +import org.spongycastle.asn1.ocsp.ResponseData; +import org.spongycastle.asn1.ocsp.RevokedInfo; +import org.spongycastle.asn1.ocsp.SingleResponse; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.CRLReason; +import org.spongycastle.asn1.x509.Extensions; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.operator.ContentSigner; +import org.spongycastle.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.toASN1Object(), 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) + { + list.add(new ResponseObject(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) + { + list.add(new ResponseObject(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) + { + list.add(new ResponseObject(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 + * @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.toASN1Object(), 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/pkix/src/main/java/org/spongycastle/cert/ocsp/CertificateID.java b/pkix/src/main/java/org/spongycastle/cert/ocsp/CertificateID.java new file mode 100644 index 00000000..aac029ca --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/ocsp/CertificateID.java @@ -0,0 +1,156 @@ +package org.spongycastle.cert.ocsp; + +import java.io.OutputStream; +import java.math.BigInteger; + +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.ocsp.CertID; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.operator.DigestCalculator; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.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 toASN1Object() + { + 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/pkix/src/main/java/org/spongycastle/cert/ocsp/CertificateStatus.java b/pkix/src/main/java/org/spongycastle/cert/ocsp/CertificateStatus.java new file mode 100644 index 00000000..ba84b8f8 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/ocsp/CertificateStatus.java @@ -0,0 +1,6 @@ +package org.spongycastle.cert.ocsp; + +public interface CertificateStatus +{ + public static final CertificateStatus GOOD = null; +} diff --git a/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPException.java b/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPException.java new file mode 100644 index 00000000..be91e3d8 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPException.java @@ -0,0 +1,27 @@ +package org.spongycastle.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/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPReq.java b/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPReq.java new file mode 100644 index 00000000..17089673 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPReq.java @@ -0,0 +1,259 @@ +package org.spongycastle.cert.ocsp; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; +import java.util.Set; + +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1Exception; +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OutputStream; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.ocsp.OCSPRequest; +import org.spongycastle.asn1.ocsp.Request; +import org.spongycastle.asn1.x509.Certificate; +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.asn1.x509.Extensions; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.cert.CertIOException; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.operator.ContentVerifier; +import org.spongycastle.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().getBytes(); + } + + 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/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPReqBuilder.java b/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPReqBuilder.java new file mode 100644 index 00000000..2bc0a6d1 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPReqBuilder.java @@ -0,0 +1,199 @@ +package org.spongycastle.cert.ocsp; + +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.DERBitString; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.ocsp.OCSPRequest; +import org.spongycastle.asn1.ocsp.Request; +import org.spongycastle.asn1.ocsp.Signature; +import org.spongycastle.asn1.ocsp.TBSRequest; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.Extensions; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.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.toASN1Object(), 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 X500Principal + * + * @param requestorName a X500Principal 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 org.spongycastle.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/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPResp.java b/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPResp.java new file mode 100644 index 00000000..0b587f70 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPResp.java @@ -0,0 +1,141 @@ +package org.spongycastle.cert.ocsp; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.spongycastle.asn1.ASN1Exception; +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ocsp.BasicOCSPResponse; +import org.spongycastle.asn1.ocsp.OCSPObjectIdentifiers; +import org.spongycastle.asn1.ocsp.OCSPResponse; +import org.spongycastle.asn1.ocsp.ResponseBytes; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPRespBuilder.java b/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPRespBuilder.java new file mode 100644 index 00000000..fe2da11d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPRespBuilder.java @@ -0,0 +1,59 @@ +package org.spongycastle.cert.ocsp; + +import java.io.IOException; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.ocsp.OCSPObjectIdentifiers; +import org.spongycastle.asn1.ocsp.OCSPResponse; +import org.spongycastle.asn1.ocsp.OCSPResponseStatus; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPUtils.java b/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPUtils.java new file mode 100644 index 00000000..a58ca071 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPUtils.java @@ -0,0 +1,64 @@ +package org.spongycastle.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 org.spongycastle.asn1.ASN1GeneralizedTime; +import org.spongycastle.asn1.x509.Extensions; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cert/ocsp/Req.java b/pkix/src/main/java/org/spongycastle/cert/ocsp/Req.java new file mode 100644 index 00000000..52c174dd --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/ocsp/Req.java @@ -0,0 +1,25 @@ +package org.spongycastle.cert.ocsp; + +import org.spongycastle.asn1.ocsp.Request; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cert/ocsp/RespData.java b/pkix/src/main/java/org/spongycastle/cert/ocsp/RespData.java new file mode 100644 index 00000000..3db55a3e --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/ocsp/RespData.java @@ -0,0 +1,52 @@ +package org.spongycastle.cert.ocsp; + +import java.util.Date; + +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.ocsp.ResponseData; +import org.spongycastle.asn1.ocsp.SingleResponse; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cert/ocsp/RespID.java b/pkix/src/main/java/org/spongycastle/cert/ocsp/RespID.java new file mode 100644 index 00000000..7510200d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/ocsp/RespID.java @@ -0,0 +1,89 @@ +package org.spongycastle.cert.ocsp; + +import java.io.OutputStream; + +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.ocsp.ResponderID; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.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"); + } + + 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 toASN1Object() + { + 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/pkix/src/main/java/org/spongycastle/cert/ocsp/RevokedStatus.java b/pkix/src/main/java/org/spongycastle/cert/ocsp/RevokedStatus.java new file mode 100644 index 00000000..0842ea58 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/ocsp/RevokedStatus.java @@ -0,0 +1,55 @@ +package org.spongycastle.cert.ocsp; + +import java.util.Date; + +import org.spongycastle.asn1.ASN1GeneralizedTime; +import org.spongycastle.asn1.ocsp.RevokedInfo; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cert/ocsp/SingleResp.java b/pkix/src/main/java/org/spongycastle/cert/ocsp/SingleResp.java new file mode 100644 index 00000000..98beb8b3 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/ocsp/SingleResp.java @@ -0,0 +1,102 @@ +package org.spongycastle.cert.ocsp; + +import java.util.Date; +import java.util.List; +import java.util.Set; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ocsp.CertStatus; +import org.spongycastle.asn1.ocsp.RevokedInfo; +import org.spongycastle.asn1.ocsp.SingleResponse; +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cert/ocsp/UnknownStatus.java b/pkix/src/main/java/org/spongycastle/cert/ocsp/UnknownStatus.java new file mode 100644 index 00000000..42eda721 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/ocsp/UnknownStatus.java @@ -0,0 +1,12 @@ +package org.spongycastle.cert.ocsp; + +/** + * wrapper for the UnknownInfo object + */ +public class UnknownStatus + implements CertificateStatus +{ + public UnknownStatus() + { + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/ocsp/jcajce/JcaBasicOCSPRespBuilder.java b/pkix/src/main/java/org/spongycastle/cert/ocsp/jcajce/JcaBasicOCSPRespBuilder.java new file mode 100644 index 00000000..cbd591db --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/ocsp/jcajce/JcaBasicOCSPRespBuilder.java @@ -0,0 +1,18 @@ +package org.spongycastle.cert.ocsp.jcajce; + +import java.security.PublicKey; + +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.cert.ocsp.BasicOCSPRespBuilder; +import org.spongycastle.cert.ocsp.OCSPException; +import org.spongycastle.operator.DigestCalculator; + +public class JcaBasicOCSPRespBuilder + extends BasicOCSPRespBuilder +{ + public JcaBasicOCSPRespBuilder(PublicKey key, DigestCalculator digCalc) + throws OCSPException + { + super(SubjectPublicKeyInfo.getInstance(key.getEncoded()), digCalc); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/ocsp/jcajce/JcaCertificateID.java b/pkix/src/main/java/org/spongycastle/cert/ocsp/jcajce/JcaCertificateID.java new file mode 100644 index 00000000..d59e7e04 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/ocsp/jcajce/JcaCertificateID.java @@ -0,0 +1,20 @@ +package org.spongycastle.cert.ocsp.jcajce; + +import java.math.BigInteger; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; + +import org.spongycastle.cert.jcajce.JcaX509CertificateHolder; +import org.spongycastle.cert.ocsp.CertificateID; +import org.spongycastle.cert.ocsp.OCSPException; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cert/ocsp/jcajce/JcaRespID.java b/pkix/src/main/java/org/spongycastle/cert/ocsp/jcajce/JcaRespID.java new file mode 100644 index 00000000..55a390be --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/ocsp/jcajce/JcaRespID.java @@ -0,0 +1,26 @@ +package org.spongycastle.cert.ocsp.jcajce; + +import java.security.PublicKey; + +import javax.security.auth.x500.X500Principal; + +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.cert.ocsp.OCSPException; +import org.spongycastle.cert.ocsp.RespID; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cert/path/CertPath.java b/pkix/src/main/java/org/spongycastle/cert/path/CertPath.java new file mode 100644 index 00000000..bbb20a4d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/path/CertPath.java @@ -0,0 +1,80 @@ +package org.spongycastle.cert.path; + +import org.spongycastle.cert.X509CertificateHolder; + +public class CertPath +{ + private final X509CertificateHolder[] certificates; + + public CertPath(X509CertificateHolder[] certificates) + { + this.certificates = copyArray(certificates); + } + + public X509CertificateHolder[] getCertificates() + { + return copyArray(certificates); + } + + public CertPathValidationResult validate(CertPathValidation[] ruleSet) + { + CertPathValidationContext context = new CertPathValidationContext(CertPathUtils.getCriticalExtensionsOIDs(certificates)); + + for (int i = 0; i != ruleSet.length; i++) + { + for (int j = certificates.length - 1; j >= 0; j--) + { + try + { + context.setIsEndEntity(j == 0); + ruleSet[i].validate(context, certificates[j]); + } + catch (CertPathValidationException e) + { // TODO: introduce object to hold (i and e) + return new CertPathValidationResult(context, j, i, e); + } + } + } + + return new CertPathValidationResult(context); + } + + public CertPathValidationResult evaluate(CertPathValidation[] ruleSet) + { + CertPathValidationContext context = new CertPathValidationContext(CertPathUtils.getCriticalExtensionsOIDs(certificates)); + + CertPathValidationResultBuilder builder = new CertPathValidationResultBuilder(); + + for (int i = 0; i != ruleSet.length; i++) + { + for (int j = certificates.length - 1; j >= 0; j--) + { + try + { + context.setIsEndEntity(j == 0); + ruleSet[i].validate(context, certificates[j]); + } + catch (CertPathValidationException e) + { + builder.addException(e); + } + } + } + + return builder.build(); + } + + private X509CertificateHolder[] copyArray(X509CertificateHolder[] array) + { + X509CertificateHolder[] rv = new X509CertificateHolder[array.length]; + + System.arraycopy(array, 0, rv, 0, rv.length); + + return rv; + } + + public int length() + { + return certificates.length; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/path/CertPathUtils.java b/pkix/src/main/java/org/spongycastle/cert/path/CertPathUtils.java new file mode 100644 index 00000000..257e0bb8 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/path/CertPathUtils.java @@ -0,0 +1,21 @@ +package org.spongycastle.cert.path; + +import java.util.HashSet; +import java.util.Set; + +import org.spongycastle.cert.X509CertificateHolder; + +class CertPathUtils +{ + static Set getCriticalExtensionsOIDs(X509CertificateHolder[] certificates) + { + Set criticalExtensions = new HashSet(); + + for (int i = 0; i != certificates.length; i++) + { + criticalExtensions.addAll(certificates[i].getCriticalExtensionOIDs()); + } + + return criticalExtensions; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidation.java b/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidation.java new file mode 100644 index 00000000..11f48367 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidation.java @@ -0,0 +1,11 @@ +package org.spongycastle.cert.path; + +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.util.Memoable; + +public interface CertPathValidation + extends Memoable +{ + public void validate(CertPathValidationContext context, X509CertificateHolder certificate) + throws CertPathValidationException; +} diff --git a/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationContext.java b/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationContext.java new file mode 100644 index 00000000..010b4ef6 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationContext.java @@ -0,0 +1,61 @@ +package org.spongycastle.cert.path; + +import java.util.HashSet; +import java.util.Set; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.util.Memoable; + +public class CertPathValidationContext + implements Memoable +{ + private Set criticalExtensions; + + private Set handledExtensions = new HashSet(); + private boolean endEntity; + private int index; + + public CertPathValidationContext(Set criticalExtensionsOIDs) + { + this.criticalExtensions = criticalExtensionsOIDs; + } + + public void addHandledExtension(ASN1ObjectIdentifier extensionIdentifier) + { + this.handledExtensions.add(extensionIdentifier); + } + + public void setIsEndEntity(boolean isEndEntity) + { + this.endEntity = isEndEntity; + } + + public Set getUnhandledCriticalExtensionOIDs() + { + Set rv = new HashSet(criticalExtensions); + + rv.removeAll(handledExtensions); + + return rv; + } + + /** + * Returns true if the current certificate is the end-entity certificate. + * + * @return if current cert end-entity, false otherwise. + */ + public boolean isEndEntity() + { + return endEntity; + } + + public Memoable copy() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public void reset(Memoable other) + { + //To change body of implemented methods use File | Settings | File Templates. + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationException.java b/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationException.java new file mode 100644 index 00000000..0a1188d1 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationException.java @@ -0,0 +1,24 @@ +package org.spongycastle.cert.path; + +public class CertPathValidationException + extends Exception +{ + private final Exception cause; + + public CertPathValidationException(String msg) + { + this(msg, null); + } + + public CertPathValidationException(String msg, Exception cause) + { + super(msg); + + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationResult.java b/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationResult.java new file mode 100644 index 00000000..276ef8d4 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationResult.java @@ -0,0 +1,66 @@ +package org.spongycastle.cert.path; + +import java.util.Collections; +import java.util.Set; + +public class CertPathValidationResult +{ + private final boolean isValid; + private final CertPathValidationException cause; + private final Set unhandledCriticalExtensionOIDs; + + private int[] certIndexes; + + public CertPathValidationResult(CertPathValidationContext context) + { + this.unhandledCriticalExtensionOIDs = Collections.unmodifiableSet(context.getUnhandledCriticalExtensionOIDs()); + this.isValid = this.unhandledCriticalExtensionOIDs.isEmpty(); + cause = null; + } + + public CertPathValidationResult(CertPathValidationContext context, int certIndex, int ruleIndex, CertPathValidationException cause) + { + this.unhandledCriticalExtensionOIDs = Collections.unmodifiableSet(context.getUnhandledCriticalExtensionOIDs()); + this.isValid = false; + this.cause = cause; + } + + public CertPathValidationResult(CertPathValidationContext context, int[] certIndexes, int[] ruleIndexes, CertPathValidationException[] cause) + { + // TODO + this.unhandledCriticalExtensionOIDs = Collections.unmodifiableSet(context.getUnhandledCriticalExtensionOIDs()); + this.isValid = false; + this.cause = cause[0]; + this.certIndexes = certIndexes; + } + + public boolean isValid() + { + return isValid; + } + + public Exception getCause() + { + if (cause != null) + { + return cause; + } + + if (!unhandledCriticalExtensionOIDs.isEmpty()) + { + return new CertPathValidationException("Unhandled Critical Extensions"); + } + + return null; + } + + public Set getUnhandledCriticalExtensionOIDs() + { + return unhandledCriticalExtensionOIDs; + } + + public boolean isDetailed() + { + return this.certIndexes != null; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationResultBuilder.java b/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationResultBuilder.java new file mode 100644 index 00000000..80bf7ff2 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationResultBuilder.java @@ -0,0 +1,14 @@ +package org.spongycastle.cert.path; + +class CertPathValidationResultBuilder +{ + public CertPathValidationResult build() + { + return new CertPathValidationResult(null, 0, 0, null); + } + + public void addException(CertPathValidationException exception) + { + //To change body of created methods use File | Settings | File Templates. + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/path/validations/BasicConstraintsValidation.java b/pkix/src/main/java/org/spongycastle/cert/path/validations/BasicConstraintsValidation.java new file mode 100644 index 00000000..bfe0f1a4 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/path/validations/BasicConstraintsValidation.java @@ -0,0 +1,103 @@ +package org.spongycastle.cert.path.validations; + +import java.math.BigInteger; + +import org.spongycastle.asn1.x509.BasicConstraints; +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.cert.path.CertPathValidation; +import org.spongycastle.cert.path.CertPathValidationContext; +import org.spongycastle.cert.path.CertPathValidationException; +import org.spongycastle.util.Memoable; + +public class BasicConstraintsValidation + implements CertPathValidation +{ + private boolean isMandatory; + private BasicConstraints bc; + private int maxPathLength; + + public BasicConstraintsValidation() + { + this(true); + } + + public BasicConstraintsValidation(boolean isMandatory) + { + this.isMandatory = isMandatory; + } + + public void validate(CertPathValidationContext context, X509CertificateHolder certificate) + throws CertPathValidationException + { + if (maxPathLength < 0) + { + throw new CertPathValidationException("BasicConstraints path length exceeded"); + } + + context.addHandledExtension(Extension.basicConstraints); + + BasicConstraints certBC = BasicConstraints.fromExtensions(certificate.getExtensions()); + + if (certBC != null) + { + if (bc != null) + { + if (certBC.isCA()) + { + BigInteger pathLengthConstraint = certBC.getPathLenConstraint(); + + if (pathLengthConstraint != null) + { + int plc = pathLengthConstraint.intValue(); + + if (plc < maxPathLength) + { + maxPathLength = plc; + bc = certBC; + } + } + } + } + else + { + bc = certBC; + if (certBC.isCA()) + { + maxPathLength = certBC.getPathLenConstraint().intValue(); + } + } + } + else + { + if (bc != null) + { + maxPathLength--; + } + } + + if (isMandatory && bc == null) + { + throw new CertPathValidationException("BasicConstraints not present in path"); + } + } + + public Memoable copy() + { + BasicConstraintsValidation v = new BasicConstraintsValidation(isMandatory); + + v.bc = this.bc; + v.maxPathLength = this.maxPathLength; + + return v; + } + + public void reset(Memoable other) + { + BasicConstraintsValidation v = (BasicConstraintsValidation)other; + + this.isMandatory = v.isMandatory; + this.bc = v.bc; + this.maxPathLength = v.maxPathLength; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/path/validations/CRLValidation.java b/pkix/src/main/java/org/spongycastle/cert/path/validations/CRLValidation.java new file mode 100644 index 00000000..325126e1 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/path/validations/CRLValidation.java @@ -0,0 +1,78 @@ +package org.spongycastle.cert.path.validations; + +import java.util.Collection; +import java.util.Iterator; + +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.cert.X509CRLHolder; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.cert.path.CertPathValidation; +import org.spongycastle.cert.path.CertPathValidationContext; +import org.spongycastle.cert.path.CertPathValidationException; +import org.spongycastle.util.Memoable; +import org.spongycastle.util.Selector; +import org.spongycastle.util.Store; + +public class CRLValidation + implements CertPathValidation +{ + private Store crls; + private X500Name workingIssuerName; + + public CRLValidation(X500Name trustAnchorName, Store crls) + { + this.workingIssuerName = trustAnchorName; + this.crls = crls; + } + + public void validate(CertPathValidationContext context, X509CertificateHolder certificate) + throws CertPathValidationException + { + // TODO: add handling of delta CRLs + Collection matches = crls.getMatches(new Selector() + { + public boolean match(Object obj) + { + X509CRLHolder crl = (X509CRLHolder)obj; + + return (crl.getIssuer().equals(workingIssuerName)); + } + + public Object clone() + { + return this; + } + }); + + if (matches.isEmpty()) + { + throw new CertPathValidationException("CRL for " + workingIssuerName + " not found"); + } + + for (Iterator it = matches.iterator(); it.hasNext();) + { + X509CRLHolder crl = (X509CRLHolder)it.next(); + + // TODO: not quite right! + if (crl.getRevokedCertificate(certificate.getSerialNumber()) != null) + { + throw new CertPathValidationException("Certificate revoked"); + } + } + + this.workingIssuerName = certificate.getSubject(); + } + + public Memoable copy() + { + return new CRLValidation(workingIssuerName, crls); + } + + public void reset(Memoable other) + { + CRLValidation v = (CRLValidation)other; + + this.workingIssuerName = v.workingIssuerName; + this.crls = v.crls; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/path/validations/CertificatePoliciesValidation.java b/pkix/src/main/java/org/spongycastle/cert/path/validations/CertificatePoliciesValidation.java new file mode 100644 index 00000000..7015adb0 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/path/validations/CertificatePoliciesValidation.java @@ -0,0 +1,146 @@ +package org.spongycastle.cert.path.validations; + +import java.math.BigInteger; + +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.asn1.x509.PolicyConstraints; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.cert.path.CertPathValidation; +import org.spongycastle.cert.path.CertPathValidationContext; +import org.spongycastle.cert.path.CertPathValidationException; +import org.spongycastle.util.Memoable; + +public class CertificatePoliciesValidation + implements CertPathValidation +{ + private int explicitPolicy; + private int policyMapping; + private int inhibitAnyPolicy; + + CertificatePoliciesValidation(int pathLength) + { + this(pathLength, false, false, false); + } + + CertificatePoliciesValidation(int pathLength, boolean isExplicitPolicyRequired, boolean isAnyPolicyInhibited, boolean isPolicyMappingInhibited) + { + // + // (d) + // + + if (isExplicitPolicyRequired) + { + explicitPolicy = 0; + } + else + { + explicitPolicy = pathLength + 1; + } + + // + // (e) + // + if (isAnyPolicyInhibited) + { + inhibitAnyPolicy = 0; + } + else + { + inhibitAnyPolicy = pathLength + 1; + } + + // + // (f) + // + if (isPolicyMappingInhibited) + { + policyMapping = 0; + } + else + { + policyMapping = pathLength + 1; + } + } + + public void validate(CertPathValidationContext context, X509CertificateHolder certificate) + throws CertPathValidationException + { + context.addHandledExtension(Extension.policyConstraints); + context.addHandledExtension(Extension.inhibitAnyPolicy); + + if (!context.isEndEntity()) + { + if (!ValidationUtils.isSelfIssued(certificate)) + { + // + // H (1), (2), (3) + // + explicitPolicy = countDown(explicitPolicy); + policyMapping = countDown(policyMapping); + inhibitAnyPolicy = countDown(inhibitAnyPolicy); + + // + // I (1), (2) + // + PolicyConstraints policyConstraints = PolicyConstraints.fromExtensions(certificate.getExtensions()); + + if (policyConstraints != null) + { + BigInteger requireExplicitPolicyMapping = policyConstraints.getRequireExplicitPolicyMapping(); + if (requireExplicitPolicyMapping != null) + { + if (requireExplicitPolicyMapping.intValue() < explicitPolicy) + { + explicitPolicy = requireExplicitPolicyMapping.intValue(); + } + } + + BigInteger inhibitPolicyMapping = policyConstraints.getInhibitPolicyMapping(); + if (inhibitPolicyMapping != null) + { + if (inhibitPolicyMapping.intValue() < policyMapping) + { + policyMapping = inhibitPolicyMapping.intValue(); + } + } + } + + // + // J + // + Extension ext = certificate.getExtension(Extension.inhibitAnyPolicy); + + if (ext != null) + { + int extValue = ASN1Integer.getInstance(ext.getParsedValue()).getValue().intValue(); + + if (extValue < inhibitAnyPolicy) + { + inhibitAnyPolicy = extValue; + } + } + } + } + } + + private int countDown(int policyCounter) + { + if (policyCounter != 0) + { + return policyCounter - 1; + } + + return 0; + } + + public Memoable copy() + { + return new CertificatePoliciesValidation(0); // TODO: + } + + public void reset(Memoable other) + { + CertificatePoliciesValidation v = (CertificatePoliciesValidation)other; // TODO: + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/path/validations/CertificatePoliciesValidationBuilder.java b/pkix/src/main/java/org/spongycastle/cert/path/validations/CertificatePoliciesValidationBuilder.java new file mode 100644 index 00000000..44817b61 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/path/validations/CertificatePoliciesValidationBuilder.java @@ -0,0 +1,35 @@ +package org.spongycastle.cert.path.validations; + +import org.spongycastle.cert.path.CertPath; + +public class CertificatePoliciesValidationBuilder +{ + private boolean isExplicitPolicyRequired; + private boolean isAnyPolicyInhibited; + private boolean isPolicyMappingInhibited; + + public void setAnyPolicyInhibited(boolean anyPolicyInhibited) + { + isAnyPolicyInhibited = anyPolicyInhibited; + } + + public void setExplicitPolicyRequired(boolean explicitPolicyRequired) + { + isExplicitPolicyRequired = explicitPolicyRequired; + } + + public void setPolicyMappingInhibited(boolean policyMappingInhibited) + { + isPolicyMappingInhibited = policyMappingInhibited; + } + + public CertificatePoliciesValidation build(int pathLen) + { + return new CertificatePoliciesValidation(pathLen, isExplicitPolicyRequired, isAnyPolicyInhibited, isPolicyMappingInhibited); + } + + public CertificatePoliciesValidation build(CertPath path) + { + return build(path.length()); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/path/validations/KeyUsageValidation.java b/pkix/src/main/java/org/spongycastle/cert/path/validations/KeyUsageValidation.java new file mode 100644 index 00000000..7211b7cd --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/path/validations/KeyUsageValidation.java @@ -0,0 +1,63 @@ +package org.spongycastle.cert.path.validations; + +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.asn1.x509.KeyUsage; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.cert.path.CertPathValidation; +import org.spongycastle.cert.path.CertPathValidationContext; +import org.spongycastle.cert.path.CertPathValidationException; +import org.spongycastle.util.Memoable; + +public class KeyUsageValidation + implements CertPathValidation +{ + private boolean isMandatory; + + public KeyUsageValidation() + { + this(true); + } + + public KeyUsageValidation(boolean isMandatory) + { + this.isMandatory = isMandatory; + } + + public void validate(CertPathValidationContext context, X509CertificateHolder certificate) + throws CertPathValidationException + { + context.addHandledExtension(Extension.keyUsage); + + if (!context.isEndEntity()) + { + KeyUsage usage = KeyUsage.fromExtensions(certificate.getExtensions()); + + if (usage != null) + { + if (!usage.hasUsages(KeyUsage.keyCertSign)) + { + throw new CertPathValidationException("Issuer certificate KeyUsage extension does not permit key signing"); + } + } + else + { + if (isMandatory) + { + throw new CertPathValidationException("KeyUsage extension not present in CA certificate"); + } + } + } + } + + public Memoable copy() + { + return new KeyUsageValidation(isMandatory); + } + + public void reset(Memoable other) + { + KeyUsageValidation v = (KeyUsageValidation)other; + + this.isMandatory = v.isMandatory; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/path/validations/ParentCertIssuedValidation.java b/pkix/src/main/java/org/spongycastle/cert/path/validations/ParentCertIssuedValidation.java new file mode 100644 index 00000000..dff47fb7 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/path/validations/ParentCertIssuedValidation.java @@ -0,0 +1,127 @@ +package org.spongycastle.cert.path.validations; + +import java.io.IOException; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1Null; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.cert.CertException; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.cert.X509ContentVerifierProviderBuilder; +import org.spongycastle.cert.path.CertPathValidation; +import org.spongycastle.cert.path.CertPathValidationContext; +import org.spongycastle.cert.path.CertPathValidationException; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.util.Memoable; + +public class ParentCertIssuedValidation + implements CertPathValidation +{ + private X509ContentVerifierProviderBuilder contentVerifierProvider; + + private X500Name workingIssuerName; + private SubjectPublicKeyInfo workingPublicKey; + private AlgorithmIdentifier workingAlgId; + + public ParentCertIssuedValidation(X509ContentVerifierProviderBuilder contentVerifierProvider) + { + this.contentVerifierProvider = contentVerifierProvider; + } + + public void validate(CertPathValidationContext context, X509CertificateHolder certificate) + throws CertPathValidationException + { + if (workingIssuerName != null) + { + if (!workingIssuerName.equals(certificate.getIssuer())) + { + throw new CertPathValidationException("Certificate issue does not match parent"); + } + } + + if (workingPublicKey != null) + { + try + { + SubjectPublicKeyInfo validatingKeyInfo; + + if (workingPublicKey.getAlgorithm().equals(workingAlgId)) + { + validatingKeyInfo = workingPublicKey; + } + else + { + validatingKeyInfo = new SubjectPublicKeyInfo(workingAlgId, workingPublicKey.parsePublicKey()); + } + + if (!certificate.isSignatureValid(contentVerifierProvider.build(validatingKeyInfo))) + { + throw new CertPathValidationException("Certificate signature not for public key in parent"); + } + } + catch (OperatorCreationException e) + { + throw new CertPathValidationException("Unable to create verifier: " + e.getMessage(), e); + } + catch (CertException e) + { + throw new CertPathValidationException("Unable to validate signature: " + e.getMessage(), e); + } + catch (IOException e) + { + throw new CertPathValidationException("Unable to build public key: " + e.getMessage(), e); + } + } + + workingIssuerName = certificate.getSubject(); + workingPublicKey = certificate.getSubjectPublicKeyInfo(); + + if (workingAlgId != null) + { + // check for inherited parameters + if (workingPublicKey.getAlgorithm().getAlgorithm().equals(workingAlgId.getAlgorithm())) + { + if (!isNull(workingPublicKey.getAlgorithm().getParameters())) + { + workingAlgId = workingPublicKey.getAlgorithm(); + } + } + else + { + workingAlgId = workingPublicKey.getAlgorithm(); + } + } + else + { + workingAlgId = workingPublicKey.getAlgorithm(); + } + } + + private boolean isNull(ASN1Encodable obj) + { + return obj == null || obj instanceof ASN1Null; + } + + public Memoable copy() + { + ParentCertIssuedValidation v = new ParentCertIssuedValidation(contentVerifierProvider); + + v.workingAlgId = this.workingAlgId; + v.workingIssuerName = this.workingIssuerName; + v.workingPublicKey = this.workingPublicKey; + + return v; + } + + public void reset(Memoable other) + { + ParentCertIssuedValidation v = (ParentCertIssuedValidation)other; + + this.contentVerifierProvider = v.contentVerifierProvider; + this.workingAlgId = v.workingAlgId; + this.workingIssuerName = v.workingIssuerName; + this.workingPublicKey = v.workingPublicKey; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/path/validations/ValidationUtils.java b/pkix/src/main/java/org/spongycastle/cert/path/validations/ValidationUtils.java new file mode 100644 index 00000000..5dbf495a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/path/validations/ValidationUtils.java @@ -0,0 +1,11 @@ +package org.spongycastle.cert.path.validations; + +import org.spongycastle.cert.X509CertificateHolder; + +class ValidationUtils +{ + static boolean isSelfIssued(X509CertificateHolder cert) + { + return cert.getSubject().equals(cert.getIssuer()); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/selector/MSOutlookKeyIdCalculator.java b/pkix/src/main/java/org/spongycastle/cert/selector/MSOutlookKeyIdCalculator.java new file mode 100644 index 00000000..23748ac3 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/selector/MSOutlookKeyIdCalculator.java @@ -0,0 +1,422 @@ +package org.spongycastle.cert.selector; + +import java.io.IOException; + +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cert/selector/X509AttributeCertificateHolderSelector.java b/pkix/src/main/java/org/spongycastle/cert/selector/X509AttributeCertificateHolderSelector.java new file mode 100644 index 00000000..3ae30b33 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/selector/X509AttributeCertificateHolderSelector.java @@ -0,0 +1,268 @@ +package org.spongycastle.cert.selector; + +import java.math.BigInteger; +import java.util.Collection; +import java.util.Date; + +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.asn1.x509.Target; +import org.spongycastle.asn1.x509.TargetInformation; +import org.spongycastle.asn1.x509.Targets; +import org.spongycastle.cert.AttributeCertificateHolder; +import org.spongycastle.cert.AttributeCertificateIssuer; +import org.spongycastle.cert.X509AttributeCertificateHolder; +import org.spongycastle.util.Selector; + +/** + * This class is an <code>Selector</code> like implementation to select + * attribute certificates from a given set of criteria. + */ +public class X509AttributeCertificateHolderSelector + implements Selector +{ + + // TODO: name constraints??? + + private final AttributeCertificateHolder holder; + + private final AttributeCertificateIssuer issuer; + + private final BigInteger serialNumber; + + private final Date attributeCertificateValid; + + private final X509AttributeCertificateHolder attributeCert; + + private final Collection targetNames; + + private final Collection targetGroups; + + X509AttributeCertificateHolderSelector( + AttributeCertificateHolder holder, + AttributeCertificateIssuer issuer, + BigInteger serialNumber, + Date attributeCertificateValid, + X509AttributeCertificateHolder attributeCert, + Collection targetNames, + Collection targetGroups) + { + this.holder = holder; + this.issuer = issuer; + this.serialNumber = serialNumber; + this.attributeCertificateValid = attributeCertificateValid; + this.attributeCert = attributeCert; + this.targetNames = targetNames; + this.targetGroups = targetGroups; + } + + /** + * Decides if the given attribute certificate should be selected. + * + * @param obj The X509AttributeCertificateHolder which should be checked. + * @return <code>true</code> if the attribute certificate is a match + * <code>false</code> otherwise. + */ + public boolean match(Object obj) + { + if (!(obj instanceof X509AttributeCertificateHolder)) + { + return false; + } + + X509AttributeCertificateHolder attrCert = (X509AttributeCertificateHolder)obj; + + if (this.attributeCert != null) + { + if (!this.attributeCert.equals(attrCert)) + { + return false; + } + } + if (serialNumber != null) + { + if (!attrCert.getSerialNumber().equals(serialNumber)) + { + return false; + } + } + if (holder != null) + { + if (!attrCert.getHolder().equals(holder)) + { + return false; + } + } + if (issuer != null) + { + if (!attrCert.getIssuer().equals(issuer)) + { + return false; + } + } + + if (attributeCertificateValid != null) + { + if (!attrCert.isValidOn(attributeCertificateValid)) + { + return false; + } + } + if (!targetNames.isEmpty() || !targetGroups.isEmpty()) + { + Extension targetInfoExt = attrCert.getExtension(Extension.targetInformation); + if (targetInfoExt != null) + { + TargetInformation targetinfo; + try + { + targetinfo = TargetInformation.getInstance(targetInfoExt.getParsedValue()); + } + catch (IllegalArgumentException e) + { + return false; + } + Targets[] targetss = targetinfo.getTargetsObjects(); + if (!targetNames.isEmpty()) + { + boolean found = false; + + for (int i=0; i<targetss.length; i++) + { + Targets t = targetss[i]; + Target[] targets = t.getTargets(); + for (int j=0; j<targets.length; j++) + { + if (targetNames.contains(GeneralName.getInstance(targets[j] + .getTargetName()))) + { + found = true; + break; + } + } + } + if (!found) + { + return false; + } + } + if (!targetGroups.isEmpty()) + { + boolean found = false; + + for (int i=0; i<targetss.length; i++) + { + Targets t = targetss[i]; + Target[] targets = t.getTargets(); + for (int j=0; j<targets.length; j++) + { + if (targetGroups.contains(GeneralName.getInstance(targets[j] + .getTargetGroup()))) + { + found = true; + break; + } + } + } + if (!found) + { + return false; + } + } + } + } + return true; + } + + /** + * Returns a clone of this object. + * + * @return the clone. + */ + public Object clone() + { + X509AttributeCertificateHolderSelector sel = new X509AttributeCertificateHolderSelector( + holder, issuer, serialNumber, attributeCertificateValid, attributeCert, targetNames, targetGroups); + + return sel; + } + + /** + * Returns the attribute certificate holder which must be matched. + * + * @return Returns an X509AttributeCertificateHolder + */ + public X509AttributeCertificateHolder getAttributeCert() + { + return attributeCert; + } + + /** + * Get the criteria for the validity. + * + * @return Returns the attributeCertificateValid. + */ + public Date getAttributeCertificateValid() + { + if (attributeCertificateValid != null) + { + return new Date(attributeCertificateValid.getTime()); + } + + return null; + } + + /** + * Gets the holder. + * + * @return Returns the holder. + */ + public AttributeCertificateHolder getHolder() + { + return holder; + } + + /** + * Returns the issuer criterion. + * + * @return Returns the issuer. + */ + public AttributeCertificateIssuer getIssuer() + { + return issuer; + } + + /** + * Gets the serial number the attribute certificate must have. + * + * @return Returns the serialNumber. + */ + public BigInteger getSerialNumber() + { + return serialNumber; + } + + /** + * Gets the target names. The collection consists of GeneralName objects. + * <p> + * The returned collection is immutable. + * + * @return The collection of target names + */ + public Collection getTargetNames() + { + return targetNames; + } + + /** + * Gets the target groups. The collection consists of GeneralName objects. + * <p> + * The returned collection is immutable. + * + * @return The collection of target groups. + */ + public Collection getTargetGroups() + { + return targetGroups; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/selector/X509AttributeCertificateHolderSelectorBuilder.java b/pkix/src/main/java/org/spongycastle/cert/selector/X509AttributeCertificateHolderSelectorBuilder.java new file mode 100644 index 00000000..35df571d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/selector/X509AttributeCertificateHolderSelectorBuilder.java @@ -0,0 +1,194 @@ +package org.spongycastle.cert.selector; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.cert.AttributeCertificateHolder; +import org.spongycastle.cert.AttributeCertificateIssuer; +import org.spongycastle.cert.X509AttributeCertificateHolder; + +/** + * This class builds selectors according to the set criteria. + */ +public class X509AttributeCertificateHolderSelectorBuilder +{ + + // TODO: name constraints??? + + private AttributeCertificateHolder holder; + + private AttributeCertificateIssuer issuer; + + private BigInteger serialNumber; + + private Date attributeCertificateValid; + + private X509AttributeCertificateHolder attributeCert; + + private Collection targetNames = new HashSet(); + + private Collection targetGroups = new HashSet(); + + public X509AttributeCertificateHolderSelectorBuilder() + { + } + + /** + * Set the attribute certificate to be matched. If <code>null</code> is + * given any will do. + * + * @param attributeCert The attribute certificate holder to set. + */ + public void setAttributeCert(X509AttributeCertificateHolder attributeCert) + { + this.attributeCert = attributeCert; + } + + /** + * Set the time, when the certificate must be valid. If <code>null</code> + * is given any will do. + * + * @param attributeCertificateValid The attribute certificate validation + * time to set. + */ + public void setAttributeCertificateValid(Date attributeCertificateValid) + { + if (attributeCertificateValid != null) + { + this.attributeCertificateValid = new Date(attributeCertificateValid + .getTime()); + } + else + { + this.attributeCertificateValid = null; + } + } + + /** + * Sets the holder. If <code>null</code> is given any will do. + * + * @param holder The holder to set. + */ + public void setHolder(AttributeCertificateHolder holder) + { + this.holder = holder; + } + + /** + * Sets the issuer the attribute certificate must have. If <code>null</code> + * is given any will do. + * + * @param issuer The issuer to set. + */ + public void setIssuer(AttributeCertificateIssuer issuer) + { + this.issuer = issuer; + } + + /** + * Sets the serial number the attribute certificate must have. If + * <code>null</code> is given any will do. + * + * @param serialNumber The serialNumber to set. + */ + public void setSerialNumber(BigInteger serialNumber) + { + this.serialNumber = serialNumber; + } + + /** + * Adds a target name criterion for the attribute certificate to the target + * information extension criteria. The <code>X509AttributeCertificateHolder</code> + * must contain at least one of the specified target names. + * <p> + * Each attribute certificate may contain a target information extension + * limiting the servers where this attribute certificate can be used. If + * this extension is not present, the attribute certificate is not targeted + * and may be accepted by any server. + * + * @param name The name as a GeneralName (not <code>null</code>) + */ + public void addTargetName(GeneralName name) + { + targetNames.add(name); + } + + /** + * Adds a collection with target names criteria. If <code>null</code> is + * given any will do. + * <p> + * The collection consists of either GeneralName objects or byte[] arrays representing + * DER encoded GeneralName structures. + * + * @param names A collection of target names. + * @throws java.io.IOException if a parsing error occurs. + * @see #addTargetName(org.spongycastle.asn1.x509.GeneralName) + */ + public void setTargetNames(Collection names) throws IOException + { + targetNames = extractGeneralNames(names); + } + + /** + * Adds a target group criterion for the attribute certificate to the target + * information extension criteria. The <code>X509AttributeCertificateHolder</code> + * must contain at least one of the specified target groups. + * <p> + * Each attribute certificate may contain a target information extension + * limiting the servers where this attribute certificate can be used. If + * this extension is not present, the attribute certificate is not targeted + * and may be accepted by any server. + * + * @param group The group as GeneralName form (not <code>null</code>) + */ + public void addTargetGroup(GeneralName group) + { + targetGroups.add(group); + } + + /** + * Adds a collection with target groups criteria. If <code>null</code> is + * given any will do. + * <p> + * The collection consists of <code>GeneralName</code> objects or <code>byte[]</code representing DER + * encoded GeneralNames. + * + * @param names A collection of target groups. + * @throws java.io.IOException if a parsing error occurs. + * @see #addTargetGroup(org.spongycastle.asn1.x509.GeneralName) + */ + public void setTargetGroups(Collection names) throws IOException + { + targetGroups = extractGeneralNames(names); + } + + private Set extractGeneralNames(Collection names) + throws IOException + { + if (names == null || names.isEmpty()) + { + return new HashSet(); + } + Set temp = new HashSet(); + for (Iterator it = names.iterator(); it.hasNext();) + { + temp.add(GeneralName.getInstance(it.next())); + } + return temp; + } + + public X509AttributeCertificateHolderSelector build() + { + X509AttributeCertificateHolderSelector sel = new X509AttributeCertificateHolderSelector( + holder, issuer, serialNumber, attributeCertificateValid, attributeCert, Collections.unmodifiableCollection(new HashSet(targetNames)), Collections.unmodifiableCollection(new HashSet(targetGroups))); + + return sel; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/selector/X509CertificateHolderSelector.java b/pkix/src/main/java/org/spongycastle/cert/selector/X509CertificateHolderSelector.java new file mode 100644 index 00000000..8b6b88e3 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/selector/X509CertificateHolderSelector.java @@ -0,0 +1,152 @@ +package org.spongycastle.cert.selector; + +import java.math.BigInteger; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.cms.IssuerAndSerialNumber; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.util.Arrays; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaSelectorConverter.java b/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaSelectorConverter.java new file mode 100644 index 00000000..551000b0 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaSelectorConverter.java @@ -0,0 +1,35 @@ +package org.spongycastle.cert.selector.jcajce; + +import java.io.IOException; +import java.security.cert.X509CertSelector; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.cert.selector.X509CertificateHolderSelector; + +public class JcaSelectorConverter +{ + public JcaSelectorConverter() + { + + } + + public X509CertificateHolderSelector getCertificateHolderSelector(X509CertSelector certSelector) + { + try + { + if (certSelector.getSubjectKeyIdentifier() != null) + { + return new X509CertificateHolderSelector(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber(), ASN1OctetString.getInstance(certSelector.getSubjectKeyIdentifier()).getOctets()); + } + else + { + return new X509CertificateHolderSelector(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber()); + } + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to convert issuer: " + e.getMessage()); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaX509CertSelectorConverter.java b/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaX509CertSelectorConverter.java new file mode 100644 index 00000000..6dbcef43 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaX509CertSelectorConverter.java @@ -0,0 +1,57 @@ +package org.spongycastle.cert.selector.jcajce; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.cert.X509CertSelector; + +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.cert.selector.X509CertificateHolderSelector; + +public class JcaX509CertSelectorConverter +{ + public JcaX509CertSelectorConverter() + { + } + + protected X509CertSelector doConversion(X500Name issuer, BigInteger serialNumber, byte[] subjectKeyIdentifier) + { + X509CertSelector selector = new X509CertSelector(); + + if (issuer != null) + { + try + { + selector.setIssuer(issuer.getEncoded()); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to convert issuer: " + e.getMessage()); + } + } + + if (serialNumber != null) + { + selector.setSerialNumber(serialNumber); + } + + if (subjectKeyIdentifier != null) + { + try + { + selector.setSubjectKeyIdentifier(new DEROctetString(subjectKeyIdentifier).getEncoded()); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to convert issuer: " + e.getMessage()); + } + } + + return selector; + } + + public X509CertSelector getCertSelector(X509CertificateHolderSelector holderSelector) + { + return doConversion(holderSelector.getIssuer(), holderSelector.getSerialNumber(), holderSelector.getSubjectKeyIdentifier()); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaX509CertificateHolderSelector.java b/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaX509CertificateHolderSelector.java new file mode 100644 index 00000000..fd73a9fa --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaX509CertificateHolderSelector.java @@ -0,0 +1,72 @@ +package org.spongycastle.cert.selector.jcajce; + +import java.math.BigInteger; +import java.security.cert.X509Certificate; + +import javax.security.auth.x500.X500Principal; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.cert.selector.X509CertificateHolderSelector; + +public class JcaX509CertificateHolderSelector + extends X509CertificateHolderSelector +{ + /** + * Construct a signer identifier based on the issuer, serial number and subject key identifier (if present) of the passed in + * certificate. + * + * @param certificate certificate providing the issue and serial number and subject key identifier. + */ + public JcaX509CertificateHolderSelector(X509Certificate certificate) + { + super(convertPrincipal(certificate.getIssuerX500Principal()), certificate.getSerialNumber(), getSubjectKeyId(certificate)); + } + + /** + * Construct a signer identifier based on the provided issuer and serial number.. + * + * @param issuer the issuer to use. + * @param serialNumber the serial number to use. + */ + public JcaX509CertificateHolderSelector(X500Principal issuer, BigInteger serialNumber) + { + super(convertPrincipal(issuer), serialNumber); + } + + /** + * Construct a signer identifier based on the provided issuer, serial number, and subjectKeyId.. + * + * @param issuer the issuer to use. + * @param serialNumber the serial number to use. + * @param subjectKeyId the subject key ID to use. + */ + public JcaX509CertificateHolderSelector(X500Principal issuer, BigInteger serialNumber, byte[] subjectKeyId) + { + super(convertPrincipal(issuer), serialNumber, subjectKeyId); + } + + private static X500Name convertPrincipal(X500Principal issuer) + { + if (issuer == null) + { + return null; + } + return X500Name.getInstance(issuer.getEncoded()); + } + + private static byte[] getSubjectKeyId(X509Certificate cert) + { + byte[] ext = cert.getExtensionValue(Extension.subjectKeyIdentifier.getId()); + + if (ext != null) + { + return ASN1OctetString.getInstance(ASN1OctetString.getInstance(ext).getOctets()).getOctets(); + } + else + { + return null; + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/AuthAttributesProvider.java b/pkix/src/main/java/org/spongycastle/cms/AuthAttributesProvider.java new file mode 100644 index 00000000..d2f14c5b --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/AuthAttributesProvider.java @@ -0,0 +1,8 @@ +package org.spongycastle.cms; + +import org.spongycastle.asn1.ASN1Set; + +interface AuthAttributesProvider +{ + ASN1Set getAuthAttributes(); +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSAbsentContent.java b/pkix/src/main/java/org/spongycastle/cms/CMSAbsentContent.java new file mode 100644 index 00000000..59409ea1 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSAbsentContent.java @@ -0,0 +1,49 @@ +package org.spongycastle.cms; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.cms.CMSObjectIdentifiers; + +/** + * a class representing null or absent content. + */ +public class CMSAbsentContent + implements CMSTypedData, CMSReadable +{ + private final ASN1ObjectIdentifier type; + + public CMSAbsentContent() + { + this(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId())); + } + + 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/pkix/src/main/java/org/spongycastle/cms/CMSAlgorithm.java b/pkix/src/main/java/org/spongycastle/cms/CMSAlgorithm.java new file mode 100644 index 00000000..aa04a47d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSAlgorithm.java @@ -0,0 +1,51 @@ +package org.spongycastle.cms; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import org.spongycastle.asn1.kisa.KISAObjectIdentifiers; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.ntt.NTTObjectIdentifiers; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import org.spongycastle.asn1.x9.X9ObjectIdentifiers; + +public class CMSAlgorithm +{ + public static final ASN1ObjectIdentifier DES_CBC = OIWObjectIdentifiers.desCBC; + public static final ASN1ObjectIdentifier DES_EDE3_CBC = PKCSObjectIdentifiers.des_EDE3_CBC; + public static final ASN1ObjectIdentifier RC2_CBC = PKCSObjectIdentifiers.RC2_CBC; + public static final ASN1ObjectIdentifier IDEA_CBC = new ASN1ObjectIdentifier("1.3.6.1.4.1.188.7.1.1.2"); + public static final ASN1ObjectIdentifier CAST5_CBC = new ASN1ObjectIdentifier("1.2.840.113533.7.66.10"); + public static final ASN1ObjectIdentifier AES128_CBC = NISTObjectIdentifiers.id_aes128_CBC; + public static final ASN1ObjectIdentifier AES192_CBC = NISTObjectIdentifiers.id_aes192_CBC; + public static final ASN1ObjectIdentifier AES256_CBC = NISTObjectIdentifiers.id_aes256_CBC; + public static final ASN1ObjectIdentifier CAMELLIA128_CBC = NTTObjectIdentifiers.id_camellia128_cbc; + public static final ASN1ObjectIdentifier CAMELLIA192_CBC = NTTObjectIdentifiers.id_camellia192_cbc; + public static final ASN1ObjectIdentifier CAMELLIA256_CBC = NTTObjectIdentifiers.id_camellia256_cbc; + public static final ASN1ObjectIdentifier SEED_CBC = KISAObjectIdentifiers.id_seedCBC; + + public static final ASN1ObjectIdentifier DES_EDE3_WRAP = PKCSObjectIdentifiers.id_alg_CMS3DESwrap; + public static final ASN1ObjectIdentifier AES128_WRAP = NISTObjectIdentifiers.id_aes128_wrap; + public static final ASN1ObjectIdentifier AES192_WRAP = NISTObjectIdentifiers.id_aes192_wrap; + public static final ASN1ObjectIdentifier AES256_WRAP = NISTObjectIdentifiers.id_aes256_wrap; + public static final ASN1ObjectIdentifier CAMELLIA128_WRAP = NTTObjectIdentifiers.id_camellia128_wrap; + public static final ASN1ObjectIdentifier CAMELLIA192_WRAP = NTTObjectIdentifiers.id_camellia192_wrap; + public static final ASN1ObjectIdentifier CAMELLIA256_WRAP = NTTObjectIdentifiers.id_camellia256_wrap; + public static final ASN1ObjectIdentifier SEED_WRAP = KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap; + + public static final ASN1ObjectIdentifier ECDH_SHA1KDF = X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme; + public static final ASN1ObjectIdentifier ECMQV_SHA1KDF = X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme; + + public static final ASN1ObjectIdentifier SHA1 = OIWObjectIdentifiers.idSHA1; + public static final ASN1ObjectIdentifier SHA224 = NISTObjectIdentifiers.id_sha224; + public static final ASN1ObjectIdentifier SHA256 = NISTObjectIdentifiers.id_sha256; + public static final ASN1ObjectIdentifier SHA384 = NISTObjectIdentifiers.id_sha384; + public static final ASN1ObjectIdentifier SHA512 = NISTObjectIdentifiers.id_sha512; + public static final ASN1ObjectIdentifier MD5 = PKCSObjectIdentifiers.md5; + public static final ASN1ObjectIdentifier GOST3411 = CryptoProObjectIdentifiers.gostR3411; + public static final ASN1ObjectIdentifier RIPEMD128 = TeleTrusTObjectIdentifiers.ripemd128; + public static final ASN1ObjectIdentifier RIPEMD160 = TeleTrusTObjectIdentifiers.ripemd160; + public static final ASN1ObjectIdentifier RIPEMD256 = TeleTrusTObjectIdentifiers.ripemd256; + +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSAttributeTableGenerationException.java b/pkix/src/main/java/org/spongycastle/cms/CMSAttributeTableGenerationException.java new file mode 100644 index 00000000..e328f8e5 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSAttributeTableGenerationException.java @@ -0,0 +1,32 @@ +package org.spongycastle.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/pkix/src/main/java/org/spongycastle/cms/CMSAttributeTableGenerator.java b/pkix/src/main/java/org/spongycastle/cms/CMSAttributeTableGenerator.java new file mode 100644 index 00000000..9c44be36 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSAttributeTableGenerator.java @@ -0,0 +1,19 @@ +package org.spongycastle.cms; + +import org.spongycastle.asn1.cms.AttributeTable; + +import java.util.Map; + +/** + * Note: The SIGNATURE parameter is only available when generating unsigned attributes. + */ +public interface CMSAttributeTableGenerator +{ + static final String CONTENT_TYPE = "contentType"; + static final String DIGEST = "digest"; + static final String SIGNATURE = "encryptedDigest"; + static final String DIGEST_ALGORITHM_IDENTIFIER = "digestAlgID"; + + AttributeTable getAttributes(Map parameters) + throws CMSAttributeTableGenerationException; +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSAuthEnvelopedData.java b/pkix/src/main/java/org/spongycastle/cms/CMSAuthEnvelopedData.java new file mode 100644 index 00000000..df3ab5cf --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSAuthEnvelopedData.java @@ -0,0 +1,78 @@ +package org.spongycastle.cms; + +import java.io.IOException; +import java.io.InputStream; + +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.cms.AuthEnvelopedData; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.cms.EncryptedContentInfo; +import org.spongycastle.asn1.cms.OriginatorInfo; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +/** + * containing class for an CMS AuthEnveloped Data object + */ +class CMSAuthEnvelopedData +{ + RecipientInformationStore recipientInfoStore; + ContentInfo contentInfo; + + private OriginatorInfo originator; + private AlgorithmIdentifier authEncAlg; + private ASN1Set authAttrs; + private byte[] mac; + private ASN1Set unauthAttrs; + + public CMSAuthEnvelopedData(byte[] authEnvData) throws CMSException + { + this(CMSUtils.readContentInfo(authEnvData)); + } + + public CMSAuthEnvelopedData(InputStream authEnvData) throws CMSException + { + this(CMSUtils.readContentInfo(authEnvData)); + } + + public CMSAuthEnvelopedData(ContentInfo contentInfo) throws CMSException + { + this.contentInfo = contentInfo; + + AuthEnvelopedData authEnvData = AuthEnvelopedData.getInstance(contentInfo.getContent()); + + this.originator = authEnvData.getOriginatorInfo(); + + // + // read the recipients + // + ASN1Set recipientInfos = authEnvData.getRecipientInfos(); + + // + // read the auth-encrypted content info + // + EncryptedContentInfo authEncInfo = authEnvData.getAuthEncryptedContentInfo(); + this.authEncAlg = authEncInfo.getContentEncryptionAlgorithm(); +// final CMSProcessable processable = new CMSProcessableByteArray( +// authEncInfo.getEncryptedContent().getOctets()); + CMSSecureReadable secureReadable = new CMSSecureReadable() + { + + public InputStream getInputStream() + throws IOException, CMSException + { + return null; + } + }; + + // + // build the RecipientInformationStore + // + this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore( + recipientInfos, this.authEncAlg, secureReadable); + + // FIXME These need to be passed to the AEAD cipher as AAD (Additional Authenticated Data) + this.authAttrs = authEnvData.getAuthAttrs(); + this.mac = authEnvData.getMac().getOctets(); + this.unauthAttrs = authEnvData.getUnauthAttrs(); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSAuthEnvelopedGenerator.java b/pkix/src/main/java/org/spongycastle/cms/CMSAuthEnvelopedGenerator.java new file mode 100644 index 00000000..f3a802cd --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSAuthEnvelopedGenerator.java @@ -0,0 +1,13 @@ +package org.spongycastle.cms; + +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; + +class CMSAuthEnvelopedGenerator +{ + public static final String AES128_CCM = NISTObjectIdentifiers.id_aes128_CCM.getId(); + public static final String AES192_CCM = NISTObjectIdentifiers.id_aes192_CCM.getId(); + public static final String AES256_CCM = NISTObjectIdentifiers.id_aes256_CCM.getId(); + public static final String AES128_GCM = NISTObjectIdentifiers.id_aes128_GCM.getId(); + public static final String AES192_GCM = NISTObjectIdentifiers.id_aes192_GCM.getId(); + public static final String AES256_GCM = NISTObjectIdentifiers.id_aes256_GCM.getId(); +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedData.java b/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedData.java new file mode 100644 index 00000000..898d5c0c --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedData.java @@ -0,0 +1,260 @@ +package org.spongycastle.cms; + +import java.io.IOException; +import java.io.InputStream; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.cms.AttributeTable; +import org.spongycastle.asn1.cms.AuthenticatedData; +import org.spongycastle.asn1.cms.CMSAttributes; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.util.Arrays; + +/** + * containing class for an CMS Authenticated Data object + */ +public class CMSAuthenticatedData +{ + RecipientInformationStore recipientInfoStore; + ContentInfo contentInfo; + + private AlgorithmIdentifier macAlg; + private ASN1Set authAttrs; + private ASN1Set unauthAttrs; + private byte[] mac; + private OriginatorInformation originatorInfo; + + public CMSAuthenticatedData( + byte[] authData) + throws CMSException + { + this(CMSUtils.readContentInfo(authData)); + } + + public CMSAuthenticatedData( + byte[] authData, + DigestCalculatorProvider digestCalculatorProvider) + throws CMSException + { + this(CMSUtils.readContentInfo(authData), digestCalculatorProvider); + } + + public CMSAuthenticatedData( + InputStream authData) + throws CMSException + { + this(CMSUtils.readContentInfo(authData)); + } + + public CMSAuthenticatedData( + InputStream authData, + DigestCalculatorProvider digestCalculatorProvider) + throws CMSException + { + this(CMSUtils.readContentInfo(authData), digestCalculatorProvider); + } + + public CMSAuthenticatedData( + ContentInfo contentInfo) + throws CMSException + { + this(contentInfo, null); + } + + public CMSAuthenticatedData( + ContentInfo contentInfo, + DigestCalculatorProvider digestCalculatorProvider) + throws CMSException + { + this.contentInfo = contentInfo; + + AuthenticatedData authData = AuthenticatedData.getInstance(contentInfo.getContent()); + + if (authData.getOriginatorInfo() != null) + { + this.originatorInfo = new OriginatorInformation(authData.getOriginatorInfo()); + } + + // + // read the recipients + // + ASN1Set recipientInfos = authData.getRecipientInfos(); + + this.macAlg = authData.getMacAlgorithm(); + + + this.authAttrs = authData.getAuthAttrs(); + this.mac = authData.getMac().getOctets(); + this.unauthAttrs = authData.getUnauthAttrs(); + + // + // read the authenticated content info + // + ContentInfo encInfo = authData.getEncapsulatedContentInfo(); + CMSReadable readable = new CMSProcessableByteArray( + ASN1OctetString.getInstance(encInfo.getContent()).getOctets()); + + // + // build the RecipientInformationStore + // + if (authAttrs != null) + { + if (digestCalculatorProvider == null) + { + throw new CMSException("a digest calculator provider is required if authenticated attributes are present"); + } + + try + { + CMSSecureReadable secureReadable = new CMSEnvelopedHelper.CMSDigestAuthenticatedSecureReadable(digestCalculatorProvider.get(authData.getDigestAlgorithm()), readable); + + this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore(recipientInfos, this.macAlg, secureReadable, new AuthAttributesProvider() + { + public ASN1Set getAuthAttributes() + { + return authAttrs; + } + }); + } + catch (OperatorCreationException e) + { + throw new CMSException("unable to create digest calculator: " + e.getMessage(), e); + } + } + else + { + CMSSecureReadable secureReadable = new CMSEnvelopedHelper.CMSAuthenticatedSecureReadable(this.macAlg, readable); + + this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore(recipientInfos, this.macAlg, secureReadable); + } + } + + /** + * Return the originator information associated with this message if present. + * + * @return OriginatorInformation, null if not present. + */ + public OriginatorInformation getOriginatorInfo() + { + return originatorInfo; + } + + public byte[] getMac() + { + return Arrays.clone(mac); + } + + private byte[] encodeObj( + ASN1Encodable obj) + throws IOException + { + if (obj != null) + { + return obj.toASN1Primitive().getEncoded(); + } + + return null; + } + + /** + * Return the MAC algorithm details for the MAC associated with the data in this object. + * + * @return AlgorithmIdentifier representing the MAC algorithm. + */ + public AlgorithmIdentifier getMacAlgorithm() + { + return macAlg; + } + + /** + * return the object identifier for the content MAC algorithm. + */ + public String getMacAlgOID() + { + return macAlg.getAlgorithm().getId(); + } + + /** + * return the ASN.1 encoded MAC algorithm parameters, or null if + * there aren't any. + */ + public byte[] getMacAlgParams() + { + try + { + return encodeObj(macAlg.getParameters()); + } + catch (Exception e) + { + throw new RuntimeException("exception getting encryption parameters " + e); + } + } + + /** + * return a store of the intended recipients for this message + */ + public RecipientInformationStore getRecipientInfos() + { + return recipientInfoStore; + } + + /** + * return the ContentInfo + */ + public ContentInfo getContentInfo() + { + return contentInfo; + } + + /** + * return a table of the digested attributes indexed by + * the OID of the attribute. + */ + public AttributeTable getAuthAttrs() + { + if (authAttrs == null) + { + return null; + } + + return new AttributeTable(authAttrs); + } + + /** + * return a table of the undigested attributes indexed by + * the OID of the attribute. + */ + public AttributeTable getUnauthAttrs() + { + if (unauthAttrs == null) + { + return null; + } + + return new AttributeTable(unauthAttrs); + } + + /** + * return the ASN.1 encoded representation of this object. + */ + public byte[] getEncoded() + throws IOException + { + return contentInfo.getEncoded(); + } + + public byte[] getContentDigest() + { + if (authAttrs != null) + { + return ASN1OctetString.getInstance(getAuthAttrs().get(CMSAttributes.messageDigest).getAttrValues().getObjectAt(0)).getOctets(); + } + + return null; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedDataGenerator.java b/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedDataGenerator.java new file mode 100644 index 00000000..ca1f95a5 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedDataGenerator.java @@ -0,0 +1,181 @@ +package org.spongycastle.cms; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.BEROctetString; +import org.spongycastle.asn1.BERSet; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.DERSet; +import org.spongycastle.asn1.cms.AuthenticatedData; +import org.spongycastle.asn1.cms.CMSObjectIdentifiers; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.operator.DigestCalculator; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.operator.MacCalculator; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.util.io.TeeOutputStream; + +/** + * General class for generating a CMS authenticated-data message. + * + * A simple example of usage. + * + * <pre> + * CMSAuthenticatedDataGenerator fact = new CMSAuthenticatedDataGenerator(); + * + * adGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(recipientCert).setProvider("SC")); + * + * CMSAuthenticatedData data = fact.generate(new CMSProcessableByteArray(data), + * new JceCMSMacCalculatorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build())); + * </pre> + */ +public class CMSAuthenticatedDataGenerator + extends CMSAuthenticatedGenerator +{ + /** + * base constructor + */ + public CMSAuthenticatedDataGenerator() + { + } + + /** + * Generate an authenticated data object from the passed in typedData and MacCalculator. + * + * @param typedData the data to have a MAC attached. + * @param macCalculator the calculator of the MAC to be attached. + * @return the resulting CMSAuthenticatedData object. + * @throws CMSException on failure in encoding data or processing recipients. + */ + public CMSAuthenticatedData generate(CMSTypedData typedData, MacCalculator macCalculator) + throws CMSException + { + return generate(typedData, macCalculator, null); + } + + /** + * Generate an authenticated data object from the passed in typedData and MacCalculator. + * + * @param typedData the data to have a MAC attached. + * @param macCalculator the calculator of the MAC to be attached. + * @param digestCalculator calculator for computing digest of the encapsulated data. + * @return the resulting CMSAuthenticatedData object. + * @throws CMSException on failure in encoding data or processing recipients. + */ + public CMSAuthenticatedData generate(CMSTypedData typedData, MacCalculator macCalculator, final DigestCalculator digestCalculator) + throws CMSException + { + ASN1EncodableVector recipientInfos = new ASN1EncodableVector(); + ASN1OctetString encContent; + ASN1OctetString macResult; + + for (Iterator it = recipientInfoGenerators.iterator(); it.hasNext();) + { + RecipientInfoGenerator recipient = (RecipientInfoGenerator)it.next(); + + recipientInfos.add(recipient.generate(macCalculator.getKey())); + } + + AuthenticatedData authData; + + if (digestCalculator != null) + { + try + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OutputStream out = new TeeOutputStream(digestCalculator.getOutputStream(), bOut); + + typedData.write(out); + + out.close(); + + encContent = new BEROctetString(bOut.toByteArray()); + } + catch (IOException e) + { + throw new CMSException("unable to perform digest calculation: " + e.getMessage(), e); + } + + Map parameters = getBaseParameters(typedData.getContentType(), digestCalculator.getAlgorithmIdentifier(), digestCalculator.getDigest()); + + if (authGen == null) + { + authGen = new DefaultAuthenticatedAttributeTableGenerator(); + } + ASN1Set authed = new DERSet(authGen.getAttributes(Collections.unmodifiableMap(parameters)).toASN1EncodableVector()); + + try + { + OutputStream mOut = macCalculator.getOutputStream(); + + mOut.write(authed.getEncoded(ASN1Encoding.DER)); + + mOut.close(); + + macResult = new DEROctetString(macCalculator.getMac()); + } + catch (IOException e) + { + throw new CMSException("exception decoding algorithm parameters.", e); + } + ASN1Set unauthed = (unauthGen != null) ? new BERSet(unauthGen.getAttributes(Collections.unmodifiableMap(parameters)).toASN1EncodableVector()) : null; + + ContentInfo eci = new ContentInfo( + CMSObjectIdentifiers.data, + encContent); + + authData = new AuthenticatedData(originatorInfo, new DERSet(recipientInfos), macCalculator.getAlgorithmIdentifier(), digestCalculator.getAlgorithmIdentifier(), eci, authed, macResult, unauthed); + } + else + { + try + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OutputStream mOut = new TeeOutputStream(bOut, macCalculator.getOutputStream()); + + typedData.write(mOut); + + mOut.close(); + + encContent = new BEROctetString(bOut.toByteArray()); + + macResult = new DEROctetString(macCalculator.getMac()); + } + catch (IOException e) + { + throw new CMSException("exception decoding algorithm parameters.", e); + } + + ASN1Set unauthed = (unauthGen != null) ? new BERSet(unauthGen.getAttributes(new HashMap()).toASN1EncodableVector()) : null; + + ContentInfo eci = new ContentInfo( + CMSObjectIdentifiers.data, + encContent); + + authData = new AuthenticatedData(originatorInfo, new DERSet(recipientInfos), macCalculator.getAlgorithmIdentifier(), null, eci, null, macResult, unauthed); + } + + ContentInfo contentInfo = new ContentInfo( + CMSObjectIdentifiers.authenticatedData, authData); + + return new CMSAuthenticatedData(contentInfo, new DigestCalculatorProvider() + { + public DigestCalculator get(AlgorithmIdentifier digestAlgorithmIdentifier) + throws OperatorCreationException + { + return digestCalculator; + } + }); + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedDataParser.java b/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedDataParser.java new file mode 100644 index 00000000..61a95e53 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedDataParser.java @@ -0,0 +1,348 @@ +package org.spongycastle.cms; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1OctetStringParser; +import org.spongycastle.asn1.ASN1SequenceParser; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.ASN1SetParser; +import org.spongycastle.asn1.BERTags; +import org.spongycastle.asn1.DERSet; +import org.spongycastle.asn1.cms.AttributeTable; +import org.spongycastle.asn1.cms.AuthenticatedDataParser; +import org.spongycastle.asn1.cms.CMSAttributes; +import org.spongycastle.asn1.cms.ContentInfoParser; +import org.spongycastle.asn1.cms.OriginatorInfo; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.util.Arrays; + +/** + * Parsing class for an CMS Authenticated Data object from an input stream. + * <p> + * Note: that because we are in a streaming mode only one recipient can be tried and it is important + * that the methods on the parser are called in the appropriate order. + * </p> + * <p> + * Example of use - assuming the first recipient matches the private key we have. + * <pre> + * CMSAuthenticatedDataParser ad = new CMSAuthenticatedDataParser(inputStream); + * + * RecipientInformationStore recipients = ad.getRecipientInfos(); + * + * Collection c = recipients.getRecipients(); + * Iterator it = c.iterator(); + * + * if (it.hasNext()) + * { + * RecipientInformation recipient = (RecipientInformation)it.next(); + * + * CMSTypedStream recData = recipient.getContentStream(new JceKeyTransAuthenticatedRecipient(privateKey).setProvider("SC")); + * + * processDataStream(recData.getContentStream()); + * + * if (!Arrays.equals(ad.getMac(), recipient.getMac()) + * { + * System.err.println("Data corrupted!!!!"); + * } + * } + * </pre> + * Note: this class does not introduce buffering - if you are processing large files you should create + * the parser with: + * <pre> + * CMSAuthenticatedDataParser ep = new CMSAuthenticatedDataParser(new BufferedInputStream(inputStream, bufSize)); + * </pre> + * where bufSize is a suitably large buffer size. + */ +public class CMSAuthenticatedDataParser + extends CMSContentInfoParser +{ + RecipientInformationStore recipientInfoStore; + AuthenticatedDataParser authData; + + private AlgorithmIdentifier macAlg; + private byte[] mac; + private AttributeTable authAttrs; + private ASN1Set authAttrSet; + private AttributeTable unauthAttrs; + + private boolean authAttrNotRead; + private boolean unauthAttrNotRead; + private OriginatorInformation originatorInfo; + + public CMSAuthenticatedDataParser( + byte[] envelopedData) + throws CMSException, IOException + { + this(new ByteArrayInputStream(envelopedData)); + } + + public CMSAuthenticatedDataParser( + byte[] envelopedData, + DigestCalculatorProvider digestCalculatorProvider) + throws CMSException, IOException + { + this(new ByteArrayInputStream(envelopedData), digestCalculatorProvider); + } + + public CMSAuthenticatedDataParser( + InputStream envelopedData) + throws CMSException, IOException + { + this(envelopedData, null); + } + + public CMSAuthenticatedDataParser( + InputStream envelopedData, + DigestCalculatorProvider digestCalculatorProvider) + throws CMSException, IOException + { + super(envelopedData); + + this.authAttrNotRead = true; + this.authData = new AuthenticatedDataParser((ASN1SequenceParser)_contentInfo.getContent(BERTags.SEQUENCE)); + + // TODO Validate version? + //ASN1Integer version = this.authData.getVersion(); + + OriginatorInfo info = authData.getOriginatorInfo(); + + if (info != null) + { + this.originatorInfo = new OriginatorInformation(info); + } + // + // read the recipients + // + ASN1Set recipientInfos = ASN1Set.getInstance(authData.getRecipientInfos().toASN1Primitive()); + + this.macAlg = authData.getMacAlgorithm(); + + // + // build the RecipientInformationStore + // + AlgorithmIdentifier digestAlgorithm = authData.getDigestAlgorithm(); + + if (digestAlgorithm != null) + { + if (digestCalculatorProvider == null) + { + throw new CMSException("a digest calculator provider is required if authenticated attributes are present"); + } + + // + // read the authenticated content info + // + ContentInfoParser data = authData.getEncapsulatedContentInfo(); + CMSReadable readable = new CMSProcessableInputStream( + ((ASN1OctetStringParser)data.getContent(BERTags.OCTET_STRING)).getOctetStream()); + + try + { + CMSSecureReadable secureReadable = new CMSEnvelopedHelper.CMSDigestAuthenticatedSecureReadable(digestCalculatorProvider.get(digestAlgorithm), readable); + + this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore(recipientInfos, this.macAlg, secureReadable, new AuthAttributesProvider() + { + public ASN1Set getAuthAttributes() + { + try + { + return getAuthAttrSet(); + } + catch (IOException e) + { + throw new IllegalStateException("can't parse authenticated attributes!"); + } + } + }); + } + catch (OperatorCreationException e) + { + throw new CMSException("unable to create digest calculator: " + e.getMessage(), e); + } + } + else + { + // + // read the authenticated content info + // + ContentInfoParser data = authData.getEncapsulatedContentInfo(); + CMSReadable readable = new CMSProcessableInputStream( + ((ASN1OctetStringParser)data.getContent(BERTags.OCTET_STRING)).getOctetStream()); + + CMSSecureReadable secureReadable = new CMSEnvelopedHelper.CMSAuthenticatedSecureReadable(this.macAlg, readable); + + this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore(recipientInfos, this.macAlg, secureReadable); + } + + + } + + /** + * Return the originator information associated with this message if present. + * + * @return OriginatorInformation, null if not present. + */ + public OriginatorInformation getOriginatorInfo() + { + return originatorInfo; + } + + /** + * Return the MAC algorithm details for the MAC associated with the data in this object. + * + * @return AlgorithmIdentifier representing the MAC algorithm. + */ + public AlgorithmIdentifier getMacAlgorithm() + { + return macAlg; + } + + /** + * return the object identifier for the mac algorithm. + */ + public String getMacAlgOID() + { + return macAlg.getAlgorithm().toString(); + } + + /** + * return the ASN.1 encoded encryption algorithm parameters, or null if + * there aren't any. + */ + public byte[] getMacAlgParams() + { + try + { + return encodeObj(macAlg.getParameters()); + } + catch (Exception e) + { + throw new RuntimeException("exception getting encryption parameters " + e); + } + } + + /** + * return a store of the intended recipients for this message + */ + public RecipientInformationStore getRecipientInfos() + { + return recipientInfoStore; + } + + public byte[] getMac() + throws IOException + { + if (mac == null) + { + getAuthAttrs(); + mac = authData.getMac().getOctets(); + } + return Arrays.clone(mac); + } + + private ASN1Set getAuthAttrSet() + throws IOException + { + if (authAttrs == null && authAttrNotRead) + { + ASN1SetParser set = authData.getAuthAttrs(); + + if (set != null) + { + authAttrSet = (ASN1Set)set.toASN1Primitive(); + } + + authAttrNotRead = false; + } + + return authAttrSet; + } + + /** + * return a table of the unauthenticated attributes indexed by + * the OID of the attribute. + * @exception java.io.IOException + */ + public AttributeTable getAuthAttrs() + throws IOException + { + if (authAttrs == null && authAttrNotRead) + { + ASN1Set set = getAuthAttrSet(); + + if (set != null) + { + authAttrs = new AttributeTable(set); + } + } + + return authAttrs; + } + + /** + * return a table of the unauthenticated attributes indexed by + * the OID of the attribute. + * @exception java.io.IOException + */ + public AttributeTable getUnauthAttrs() + throws IOException + { + if (unauthAttrs == null && unauthAttrNotRead) + { + ASN1SetParser set = authData.getUnauthAttrs(); + + unauthAttrNotRead = false; + + if (set != null) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1Encodable o; + + while ((o = set.readObject()) != null) + { + ASN1SequenceParser seq = (ASN1SequenceParser)o; + + v.add(seq.toASN1Primitive()); + } + + unauthAttrs = new AttributeTable(new DERSet(v)); + } + } + + return unauthAttrs; + } + + private byte[] encodeObj( + ASN1Encodable obj) + throws IOException + { + if (obj != null) + { + return obj.toASN1Primitive().getEncoded(); + } + + return null; + } + + /** + * This will only be valid after the content has been read. + * + * @return the contents of the messageDigest attribute, if available. Null if not present. + */ + public byte[] getContentDigest() + { + if (authAttrs != null) + { + return ASN1OctetString.getInstance(authAttrs.get(CMSAttributes.messageDigest).getAttrValues().getObjectAt(0)).getOctets(); + } + + return null; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedDataStreamGenerator.java b/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedDataStreamGenerator.java new file mode 100644 index 00000000..14fbaa20 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedDataStreamGenerator.java @@ -0,0 +1,310 @@ +package org.spongycastle.cms; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.BERSequenceGenerator; +import org.spongycastle.asn1.BERSet; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.DERSet; +import org.spongycastle.asn1.DERTaggedObject; +import org.spongycastle.asn1.cms.AuthenticatedData; +import org.spongycastle.asn1.cms.CMSObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.operator.DigestCalculator; +import org.spongycastle.operator.MacCalculator; +import org.spongycastle.util.io.TeeOutputStream; + +/** + * General class for generating a CMS authenticated-data message stream. + * <p> + * A simple example of usage. + * <pre> + * CMSAuthenticatedDataStreamGenerator edGen = new CMSAuthenticatedDataStreamGenerator(); + * + * edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(cert).setProvider("SC")); + * + * ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + * + * OutputStream out = edGen.open( + * bOut, new JceCMSMacCalculatorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider("SC").build());* + * out.write(data); + * + * out.close(); + * </pre> + */ +public class CMSAuthenticatedDataStreamGenerator + extends CMSAuthenticatedGenerator +{ + // Currently not handled +// private Object _originatorInfo = null; +// private Object _unprotectedAttributes = null; + private int bufferSize; + private boolean berEncodeRecipientSet; + private MacCalculator macCalculator; + + /** + * base constructor + */ + public CMSAuthenticatedDataStreamGenerator() + { + } + + /** + * Set the underlying string size for encapsulated data + * + * @param bufferSize length of octet strings to buffer the data. + */ + public void setBufferSize( + int bufferSize) + { + this.bufferSize = bufferSize; + } + + /** + * Use a BER Set to store the recipient information. By default recipients are + * stored in a DER encoding. + * + * @param useBerEncodingForRecipients true if a BER set should be used, false if DER. + */ + public void setBEREncodeRecipients( + boolean useBerEncodingForRecipients) + { + berEncodeRecipientSet = useBerEncodingForRecipients; + } + + /** + * generate an authenticated data structure with the encapsulated bytes marked as DATA. + * + * @param out the stream to store the authenticated structure in. + * @param macCalculator calculator for the MAC to be attached to the data. + */ + public OutputStream open( + OutputStream out, + MacCalculator macCalculator) + throws CMSException + { + return open(CMSObjectIdentifiers.data, out, macCalculator); + } + + public OutputStream open( + OutputStream out, + MacCalculator macCalculator, + DigestCalculator digestCalculator) + throws CMSException + { + return open(CMSObjectIdentifiers.data, out, macCalculator, digestCalculator); + } + + /** + * generate an authenticated data structure with the encapsulated bytes marked as type dataType. + * + * @param dataType the type of the data been written to the object. + * @param out the stream to store the authenticated structure in. + * @param macCalculator calculator for the MAC to be attached to the data. + */ + public OutputStream open( + ASN1ObjectIdentifier dataType, + OutputStream out, + MacCalculator macCalculator) + throws CMSException + { + return open(dataType, out, macCalculator, null); + } + + /** + * generate an authenticated data structure with the encapsulated bytes marked as type dataType. + * + * @param dataType the type of the data been written to the object. + * @param out the stream to store the authenticated structure in. + * @param macCalculator calculator for the MAC to be attached to the data. + * @param digestCalculator calculator for computing digest of the encapsulated data. + */ + public OutputStream open( + ASN1ObjectIdentifier dataType, + OutputStream out, + MacCalculator macCalculator, + DigestCalculator digestCalculator) + throws CMSException + { + this.macCalculator = macCalculator; + + try + { + ASN1EncodableVector recipientInfos = new ASN1EncodableVector(); + + for (Iterator it = recipientInfoGenerators.iterator(); it.hasNext();) + { + RecipientInfoGenerator recipient = (RecipientInfoGenerator)it.next(); + + recipientInfos.add(recipient.generate(macCalculator.getKey())); + } + + // + // ContentInfo + // + BERSequenceGenerator cGen = new BERSequenceGenerator(out); + + cGen.addObject(CMSObjectIdentifiers.authenticatedData); + + // + // Authenticated Data + // + BERSequenceGenerator authGen = new BERSequenceGenerator(cGen.getRawOutputStream(), 0, true); + + authGen.addObject(new ASN1Integer(AuthenticatedData.calculateVersion(originatorInfo))); + + if (originatorInfo != null) + { + authGen.addObject(new DERTaggedObject(false, 0, originatorInfo)); + } + + if (berEncodeRecipientSet) + { + authGen.getRawOutputStream().write(new BERSet(recipientInfos).getEncoded()); + } + else + { + authGen.getRawOutputStream().write(new DERSet(recipientInfos).getEncoded()); + } + + AlgorithmIdentifier macAlgId = macCalculator.getAlgorithmIdentifier(); + + authGen.getRawOutputStream().write(macAlgId.getEncoded()); + + if (digestCalculator != null) + { + authGen.addObject(new DERTaggedObject(false, 1, digestCalculator.getAlgorithmIdentifier())); + } + + BERSequenceGenerator eiGen = new BERSequenceGenerator(authGen.getRawOutputStream()); + + eiGen.addObject(dataType); + + OutputStream octetStream = CMSUtils.createBEROctetOutputStream( + eiGen.getRawOutputStream(), 0, false, bufferSize); + + OutputStream mOut; + + if (digestCalculator != null) + { + mOut = new TeeOutputStream(octetStream, digestCalculator.getOutputStream()); + } + else + { + mOut = new TeeOutputStream(octetStream, macCalculator.getOutputStream()); + } + + return new CmsAuthenticatedDataOutputStream(macCalculator, digestCalculator, dataType, mOut, cGen, authGen, eiGen); + } + catch (IOException e) + { + throw new CMSException("exception decoding algorithm parameters.", e); + } + } + + private class CmsAuthenticatedDataOutputStream + extends OutputStream + { + private OutputStream dataStream; + private BERSequenceGenerator cGen; + private BERSequenceGenerator envGen; + private BERSequenceGenerator eiGen; + private MacCalculator macCalculator; + private DigestCalculator digestCalculator; + private ASN1ObjectIdentifier contentType; + + public CmsAuthenticatedDataOutputStream( + MacCalculator macCalculator, + DigestCalculator digestCalculator, + ASN1ObjectIdentifier contentType, + OutputStream dataStream, + BERSequenceGenerator cGen, + BERSequenceGenerator envGen, + BERSequenceGenerator eiGen) + { + this.macCalculator = macCalculator; + this.digestCalculator = digestCalculator; + this.contentType = contentType; + this.dataStream = dataStream; + this.cGen = cGen; + this.envGen = envGen; + this.eiGen = eiGen; + } + + public void write( + int b) + throws IOException + { + dataStream.write(b); + } + + public void write( + byte[] bytes, + int off, + int len) + throws IOException + { + dataStream.write(bytes, off, len); + } + + public void write( + byte[] bytes) + throws IOException + { + dataStream.write(bytes); + } + + public void close() + throws IOException + { + dataStream.close(); + eiGen.close(); + + Map parameters; + + if (digestCalculator != null) + { + parameters = Collections.unmodifiableMap(getBaseParameters(contentType, digestCalculator.getAlgorithmIdentifier(), digestCalculator.getDigest())); + + if (authGen == null) + { + authGen = new DefaultAuthenticatedAttributeTableGenerator(); + } + + ASN1Set authed = new DERSet(authGen.getAttributes(parameters).toASN1EncodableVector()); + + OutputStream mOut = macCalculator.getOutputStream(); + + mOut.write(authed.getEncoded(ASN1Encoding.DER)); + + mOut.close(); + + envGen.addObject(new DERTaggedObject(false, 2, authed)); + } + else + { + parameters = Collections.unmodifiableMap(new HashMap()); + } + + envGen.addObject(new DEROctetString(macCalculator.getMac())); + + if (unauthGen != null) + { + envGen.addObject(new DERTaggedObject(false, 3, new BERSet(unauthGen.getAttributes(parameters).toASN1EncodableVector()))); + } + + envGen.close(); + cGen.close(); + } + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedGenerator.java b/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedGenerator.java new file mode 100644 index 00000000..718b09c0 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedGenerator.java @@ -0,0 +1,41 @@ +package org.spongycastle.cms; + +import java.util.HashMap; +import java.util.Map; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.util.Arrays; + +public class CMSAuthenticatedGenerator + extends CMSEnvelopedGenerator +{ + protected CMSAttributeTableGenerator authGen; + protected CMSAttributeTableGenerator unauthGen; + + /** + * base constructor + */ + public CMSAuthenticatedGenerator() + { + } + + public void setAuthenticatedAttributeGenerator(CMSAttributeTableGenerator authGen) + { + this.authGen = authGen; + } + + public void setUnauthenticatedAttributeGenerator(CMSAttributeTableGenerator unauthGen) + { + this.unauthGen = unauthGen; + } + + 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; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSCompressedData.java b/pkix/src/main/java/org/spongycastle/cms/CMSCompressedData.java new file mode 100644 index 00000000..f6aa02d1 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSCompressedData.java @@ -0,0 +1,107 @@ +package org.spongycastle.cms; + +import java.io.IOException; +import java.io.InputStream; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.cms.CompressedData; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.operator.InputExpander; +import org.spongycastle.operator.InputExpanderProvider; + +/** + * containing class for an CMS Compressed Data object + * <pre> + * CMSCompressedData cd = new CMSCompressedData(inputStream); + * + * process(cd.getContent(new ZlibExpanderProvider())); + * </pre> + */ +public class CMSCompressedData +{ + ContentInfo contentInfo; + CompressedData comData; + + public CMSCompressedData( + byte[] compressedData) + throws CMSException + { + this(CMSUtils.readContentInfo(compressedData)); + } + + public CMSCompressedData( + InputStream compressedData) + throws CMSException + { + this(CMSUtils.readContentInfo(compressedData)); + } + + public CMSCompressedData( + ContentInfo contentInfo) + throws CMSException + { + this.contentInfo = contentInfo; + + try + { + this.comData = CompressedData.getInstance(contentInfo.getContent()); + } + catch (ClassCastException e) + { + throw new CMSException("Malformed content.", e); + } + catch (IllegalArgumentException e) + { + throw new CMSException("Malformed content.", e); + } + } + + public ASN1ObjectIdentifier getContentType() + { + return contentInfo.getContentType(); + } + + /** + * Return the uncompressed content. + * + * @param expanderProvider a provider of expander algorithm implementations. + * @return the uncompressed content + * @throws CMSException if there is an exception un-compressing the data. + */ + public byte[] getContent(InputExpanderProvider expanderProvider) + throws CMSException + { + ContentInfo content = comData.getEncapContentInfo(); + + ASN1OctetString bytes = (ASN1OctetString)content.getContent(); + InputExpander expander = expanderProvider.get(comData.getCompressionAlgorithmIdentifier()); + InputStream zIn = expander.getInputStream(bytes.getOctetStream()); + + try + { + return CMSUtils.streamToByteArray(zIn); + } + catch (IOException e) + { + throw new CMSException("exception reading compressed stream.", e); + } + } + + /** + * 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(); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSCompressedDataGenerator.java b/pkix/src/main/java/org/spongycastle/cms/CMSCompressedDataGenerator.java new file mode 100644 index 00000000..b26e84a3 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSCompressedDataGenerator.java @@ -0,0 +1,74 @@ +package org.spongycastle.cms; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.BEROctetString; +import org.spongycastle.asn1.cms.CMSObjectIdentifiers; +import org.spongycastle.asn1.cms.CompressedData; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.operator.OutputCompressor; + +/** + * General class for generating a compressed CMS message. + * <p> + * A simple example of usage. + * <p> + * <pre> + * CMSCompressedDataGenerator fact = new CMSCompressedDataGenerator(); + * + * CMSCompressedData data = fact.generate(content, new ZlibCompressor()); + * </pre> + */ +public class CMSCompressedDataGenerator +{ + public static final String ZLIB = "1.2.840.113549.1.9.16.3.8"; + + /** + * base constructor + */ + public CMSCompressedDataGenerator() + { + } + + /** + * generate an object that contains an CMS Compressed Data + */ + public CMSCompressedData generate( + CMSTypedData content, + OutputCompressor compressor) + throws CMSException + { + AlgorithmIdentifier comAlgId; + ASN1OctetString comOcts; + + try + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OutputStream zOut = compressor.getOutputStream(bOut); + + content.write(zOut); + + zOut.close(); + + comAlgId = compressor.getAlgorithmIdentifier(); + comOcts = new BEROctetString(bOut.toByteArray()); + } + catch (IOException e) + { + throw new CMSException("exception encoding data.", e); + } + + ContentInfo comContent = new ContentInfo( + content.getContentType(), comOcts); + + ContentInfo contentInfo = new ContentInfo( + CMSObjectIdentifiers.compressedData, + new CompressedData(comAlgId, comContent)); + + return new CMSCompressedData(contentInfo); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSCompressedDataParser.java b/pkix/src/main/java/org/spongycastle/cms/CMSCompressedDataParser.java new file mode 100644 index 00000000..bc853f2a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSCompressedDataParser.java @@ -0,0 +1,72 @@ +package org.spongycastle.cms; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.spongycastle.asn1.ASN1OctetStringParser; +import org.spongycastle.asn1.ASN1SequenceParser; +import org.spongycastle.asn1.BERTags; +import org.spongycastle.asn1.cms.CompressedDataParser; +import org.spongycastle.asn1.cms.ContentInfoParser; +import org.spongycastle.operator.InputExpander; +import org.spongycastle.operator.InputExpanderProvider; + +/** + * Class for reading a CMS Compressed Data stream. + * <pre> + * CMSCompressedDataParser cp = new CMSCompressedDataParser(inputStream); + * + * process(cp.getContent(new ZlibExpanderProvider()).getContentStream()); + * </pre> + * Note: this class does not introduce buffering - if you are processing large files you should create + * the parser with: + * <pre> + * CMSCompressedDataParser ep = new CMSCompressedDataParser(new BufferedInputStream(inputStream, bufSize)); + * </pre> + * where bufSize is a suitably large buffer size. + */ +public class CMSCompressedDataParser + extends CMSContentInfoParser +{ + public CMSCompressedDataParser( + byte[] compressedData) + throws CMSException + { + this(new ByteArrayInputStream(compressedData)); + } + + public CMSCompressedDataParser( + InputStream compressedData) + throws CMSException + { + super(compressedData); + } + + /** + * Return a typed stream which will allow the reading of the compressed content in + * expanded form. + * + * @param expanderProvider a provider of expander algorithm implementations. + * @return a type stream which will yield the un-compressed content. + * @throws CMSException if there is an exception parsing the CompressedData object. + */ + public CMSTypedStream getContent(InputExpanderProvider expanderProvider) + throws CMSException + { + try + { + CompressedDataParser comData = new CompressedDataParser((ASN1SequenceParser)_contentInfo.getContent(BERTags.SEQUENCE)); + ContentInfoParser content = comData.getEncapContentInfo(); + InputExpander expander = expanderProvider.get(comData.getCompressionAlgorithmIdentifier()); + + ASN1OctetStringParser bytes = (ASN1OctetStringParser)content.getContent(BERTags.OCTET_STRING); + + return new CMSTypedStream(content.getContentType().getId(), expander.getInputStream(bytes.getOctetStream())); + } + catch (IOException e) + { + throw new CMSException("IOException reading compressed content.", e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSCompressedDataStreamGenerator.java b/pkix/src/main/java/org/spongycastle/cms/CMSCompressedDataStreamGenerator.java new file mode 100644 index 00000000..47af9b4f --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSCompressedDataStreamGenerator.java @@ -0,0 +1,165 @@ +package org.spongycastle.cms; + +import java.io.IOException; +import java.io.OutputStream; + +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.BERSequenceGenerator; +import org.spongycastle.asn1.cms.CMSObjectIdentifiers; +import org.spongycastle.operator.OutputCompressor; + +/** + * General class for generating a compressed CMS message stream. + * <p> + * A simple example of usage. + * </p> + * <pre> + * CMSCompressedDataStreamGenerator gen = new CMSCompressedDataStreamGenerator(); + * + * OutputStream cOut = gen.open(outputStream, new ZlibCompressor()); + * + * cOut.write(data); + * + * cOut.close(); + * </pre> + */ +public class CMSCompressedDataStreamGenerator +{ + public static final String ZLIB = "1.2.840.113549.1.9.16.3.8"; + + private int _bufferSize; + + /** + * base constructor + */ + public CMSCompressedDataStreamGenerator() + { + } + + /** + * Set the underlying string size for encapsulated data + * + * @param bufferSize length of octet strings to buffer the data. + */ + public void setBufferSize( + int bufferSize) + { + _bufferSize = bufferSize; + } + + /** + * Open a compressing output stream with the PKCS#7 content type OID of "data". + * + * @param out the stream to encode to. + * @param compressor the type of compressor to use. + * @return an output stream to write the data be compressed to. + * @throws IOException + */ + public OutputStream open( + OutputStream out, + OutputCompressor compressor) + throws IOException + { + return open(CMSObjectIdentifiers.data, out, compressor); + } + + /** + * Open a compressing output stream. + * + * @param contentOID the content type OID. + * @param out the stream to encode to. + * @param compressor the type of compressor to use. + * @return an output stream to write the data be compressed to. + * @throws IOException + */ + public OutputStream open( + ASN1ObjectIdentifier contentOID, + OutputStream out, + OutputCompressor compressor) + throws IOException + { + BERSequenceGenerator sGen = new BERSequenceGenerator(out); + + sGen.addObject(CMSObjectIdentifiers.compressedData); + + // + // Compressed Data + // + BERSequenceGenerator cGen = new BERSequenceGenerator(sGen.getRawOutputStream(), 0, true); + + cGen.addObject(new ASN1Integer(0)); + + // + // AlgorithmIdentifier + // + cGen.addObject(compressor.getAlgorithmIdentifier()); + + // + // Encapsulated ContentInfo + // + BERSequenceGenerator eiGen = new BERSequenceGenerator(cGen.getRawOutputStream()); + + eiGen.addObject(contentOID); + + OutputStream octetStream = CMSUtils.createBEROctetOutputStream( + eiGen.getRawOutputStream(), 0, true, _bufferSize); + + return new CmsCompressedOutputStream( + compressor.getOutputStream(octetStream), sGen, cGen, eiGen); + } + + private class CmsCompressedOutputStream + extends OutputStream + { + private OutputStream _out; + private BERSequenceGenerator _sGen; + private BERSequenceGenerator _cGen; + private BERSequenceGenerator _eiGen; + + CmsCompressedOutputStream( + OutputStream out, + BERSequenceGenerator sGen, + BERSequenceGenerator cGen, + BERSequenceGenerator eiGen) + { + _out = out; + _sGen = sGen; + _cGen = cGen; + _eiGen = eiGen; + } + + public void write( + int b) + throws IOException + { + _out.write(b); + } + + + public void write( + byte[] bytes, + int off, + int len) + throws IOException + { + _out.write(bytes, off, len); + } + + public void write( + byte[] bytes) + throws IOException + { + _out.write(bytes); + } + + public void close() + throws IOException + { + _out.close(); + _eiGen.close(); + _cGen.close(); + _sGen.close(); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSConfig.java b/pkix/src/main/java/org/spongycastle/cms/CMSConfig.java new file mode 100644 index 00000000..d53a984f --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSConfig.java @@ -0,0 +1,34 @@ +package org.spongycastle.cms; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; + +public class CMSConfig +{ + /** + * 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. + */ + public static void setSigningEncryptionAlgorithmMapping(String oid, String algorithmName) + { + ASN1ObjectIdentifier id = new ASN1ObjectIdentifier(oid); + + CMSSignedHelper.INSTANCE.setSigningEncryptionAlgorithmMapping(id, 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. + */ + public static void setSigningDigestAlgorithmMapping(String oid, String algorithmName) + { + ASN1ObjectIdentifier id = new ASN1ObjectIdentifier(oid); + + CMSSignedHelper.INSTANCE.setSigningDigestAlgorithmMapping(id, algorithmName); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSContentInfoParser.java b/pkix/src/main/java/org/spongycastle/cms/CMSContentInfoParser.java new file mode 100644 index 00000000..10ef9ffd --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSContentInfoParser.java @@ -0,0 +1,45 @@ +package org.spongycastle.cms; + +import java.io.IOException; +import java.io.InputStream; + +import org.spongycastle.asn1.ASN1SequenceParser; +import org.spongycastle.asn1.ASN1StreamParser; +import org.spongycastle.asn1.cms.ContentInfoParser; + +public class CMSContentInfoParser +{ + protected ContentInfoParser _contentInfo; + protected InputStream _data; + + protected CMSContentInfoParser( + InputStream data) + throws CMSException + { + _data = data; + + try + { + ASN1StreamParser in = new ASN1StreamParser(data); + + _contentInfo = new ContentInfoParser((ASN1SequenceParser)in.readObject()); + } + catch (IOException e) + { + throw new CMSException("IOException reading content.", e); + } + catch (ClassCastException e) + { + throw new CMSException("Unexpected object reading content.", e); + } + } + + /** + * Close the underlying data stream. + * @throws IOException if the close fails. + */ + public void close() throws IOException + { + _data.close(); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSDigestedData.java b/pkix/src/main/java/org/spongycastle/cms/CMSDigestedData.java new file mode 100644 index 00000000..fb07fb53 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSDigestedData.java @@ -0,0 +1,136 @@ +package org.spongycastle.cms; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.cms.DigestedData; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.operator.DigestCalculator; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.util.Arrays; + +/** + * containing class for an CMS Digested Data object + * <pre> + * CMSDigestedData cd = new CMSDigestedData(inputStream); + * + * + * process(cd.getContent()); + * </pre> + */ +public class CMSDigestedData +{ + private ContentInfo contentInfo; + private DigestedData digestedData; + + public CMSDigestedData( + byte[] compressedData) + throws CMSException + { + this(CMSUtils.readContentInfo(compressedData)); + } + + public CMSDigestedData( + InputStream compressedData) + throws CMSException + { + this(CMSUtils.readContentInfo(compressedData)); + } + + public CMSDigestedData( + ContentInfo contentInfo) + throws CMSException + { + this.contentInfo = contentInfo; + + try + { + this.digestedData = DigestedData.getInstance(contentInfo.getContent()); + } + catch (ClassCastException e) + { + throw new CMSException("Malformed content.", e); + } + catch (IllegalArgumentException e) + { + throw new CMSException("Malformed content.", e); + } + } + + public ASN1ObjectIdentifier getContentType() + { + return contentInfo.getContentType(); + } + + public AlgorithmIdentifier getDigestAlgorithm() + { + return digestedData.getDigestAlgorithm(); + } + + /** + * Return the digested content + * + * @return the digested content + * @throws CMSException if there is an exception un-compressing the data. + */ + public CMSProcessable getDigestedContent() + throws CMSException + { + ContentInfo content = digestedData.getEncapContentInfo(); + + try + { + return new CMSProcessableByteArray(content.getContentType(), ((ASN1OctetString)content.getContent()).getOctets()); + } + catch (Exception e) + { + throw new CMSException("exception reading digested stream.", e); + } + } + + /** + * 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(); + } + + public boolean verify(DigestCalculatorProvider calculatorProvider) + throws CMSException + { + try + { + ContentInfo content = digestedData.getEncapContentInfo(); + DigestCalculator calc = calculatorProvider.get(digestedData.getDigestAlgorithm()); + + OutputStream dOut = calc.getOutputStream(); + + dOut.write(((ASN1OctetString)content.getContent()).getOctets()); + + return Arrays.areEqual(digestedData.getDigest(), calc.getDigest()); + } + catch (OperatorCreationException e) + { + throw new CMSException("unable to create digest calculator: " + e.getMessage(), e); + } + catch (IOException e) + { + throw new CMSException("unable process content: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSEncryptedData.java b/pkix/src/main/java/org/spongycastle/cms/CMSEncryptedData.java new file mode 100644 index 00000000..c833610a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSEncryptedData.java @@ -0,0 +1,62 @@ +package org.spongycastle.cms; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.cms.EncryptedContentInfo; +import org.spongycastle.asn1.cms.EncryptedData; +import org.spongycastle.operator.InputDecryptor; +import org.spongycastle.operator.InputDecryptorProvider; + +public class CMSEncryptedData +{ + private ContentInfo contentInfo; + private EncryptedData encryptedData; + + public CMSEncryptedData(ContentInfo contentInfo) + { + this.contentInfo = contentInfo; + + this.encryptedData = EncryptedData.getInstance(contentInfo.getContent()); + } + + public byte[] getContent(InputDecryptorProvider inputDecryptorProvider) + throws CMSException + { + try + { + return CMSUtils.streamToByteArray(getContentStream(inputDecryptorProvider).getContentStream()); + } + catch (IOException e) + { + throw new CMSException("unable to parse internal stream: " + e.getMessage(), e); + } + } + + public CMSTypedStream getContentStream(InputDecryptorProvider inputDecryptorProvider) + throws CMSException + { + try + { + EncryptedContentInfo encContentInfo = encryptedData.getEncryptedContentInfo(); + InputDecryptor decrytor = inputDecryptorProvider.get(encContentInfo.getContentEncryptionAlgorithm()); + + ByteArrayInputStream encIn = new ByteArrayInputStream(encContentInfo.getEncryptedContent().getOctets()); + + return new CMSTypedStream(encContentInfo.getContentType(), decrytor.getInputStream(encIn)); + } + catch (Exception e) + { + throw new CMSException("unable to create stream: " + e.getMessage(), e); + } + } + + /** + * return the ContentInfo + */ + public ContentInfo toASN1Structure() + { + return contentInfo; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSEncryptedDataGenerator.java b/pkix/src/main/java/org/spongycastle/cms/CMSEncryptedDataGenerator.java new file mode 100644 index 00000000..b2a75087 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSEncryptedDataGenerator.java @@ -0,0 +1,109 @@ +package org.spongycastle.cms; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.HashMap; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.BEROctetString; +import org.spongycastle.asn1.BERSet; +import org.spongycastle.asn1.cms.AttributeTable; +import org.spongycastle.asn1.cms.CMSObjectIdentifiers; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.cms.EncryptedContentInfo; +import org.spongycastle.asn1.cms.EncryptedData; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.operator.OutputEncryptor; + +/** + * General class for generating a CMS enveloped-data message. + * + * A simple example of usage. + * + * <pre> + * CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes()); + * + * CMSEncryptedDataGenerator edGen = new CMSEnvelopedDataGenerator(); + * + * CMSEncryptedData ed = edGen.generate( + * msg, + * new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC) + * .setProvider("SC").build()); + * + * </pre> + */ +public class CMSEncryptedDataGenerator + extends CMSEncryptedGenerator +{ + /** + * base constructor + */ + public CMSEncryptedDataGenerator() + { + } + + private CMSEncryptedData doGenerate( + CMSTypedData content, + OutputEncryptor contentEncryptor) + throws CMSException + { + AlgorithmIdentifier encAlgId; + ASN1OctetString encContent; + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + try + { + OutputStream cOut = contentEncryptor.getOutputStream(bOut); + + content.write(cOut); + + cOut.close(); + } + catch (IOException e) + { + throw new CMSException(""); + } + + byte[] encryptedContent = bOut.toByteArray(); + + encAlgId = contentEncryptor.getAlgorithmIdentifier(); + + encContent = new BEROctetString(encryptedContent); + + EncryptedContentInfo eci = new EncryptedContentInfo( + content.getContentType(), + encAlgId, + encContent); + + ASN1Set unprotectedAttrSet = null; + if (unprotectedAttributeGenerator != null) + { + AttributeTable attrTable = unprotectedAttributeGenerator.getAttributes(new HashMap()); + + unprotectedAttrSet = new BERSet(attrTable.toASN1EncodableVector()); + } + + ContentInfo contentInfo = new ContentInfo( + CMSObjectIdentifiers.encryptedData, + new EncryptedData(eci, unprotectedAttrSet)); + + return new CMSEncryptedData(contentInfo); + } + + /** + * generate an encrypted object that contains an CMS Encrypted Data structure. + * + * @param content the content to be encrypted + * @param contentEncryptor the symmetric key based encryptor to encrypt the content with. + */ + public CMSEncryptedData generate( + CMSTypedData content, + OutputEncryptor contentEncryptor) + throws CMSException + { + return doGenerate(content, contentEncryptor); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSEncryptedGenerator.java b/pkix/src/main/java/org/spongycastle/cms/CMSEncryptedGenerator.java new file mode 100644 index 00000000..cce7a6d4 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSEncryptedGenerator.java @@ -0,0 +1,21 @@ +package org.spongycastle.cms; + +/** + * General class for generating a CMS encrypted-data message. + */ +public class CMSEncryptedGenerator +{ + protected CMSAttributeTableGenerator unprotectedAttributeGenerator = null; + + /** + * base constructor + */ + protected CMSEncryptedGenerator() + { + } + + public void setUnprotectedAttributeGenerator(CMSAttributeTableGenerator unprotectedAttributeGenerator) + { + this.unprotectedAttributeGenerator = unprotectedAttributeGenerator; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedData.java b/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedData.java new file mode 100644 index 00000000..cc4cd30c --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedData.java @@ -0,0 +1,206 @@ +package org.spongycastle.cms; + +import java.io.IOException; +import java.io.InputStream; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.cms.AttributeTable; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.cms.EncryptedContentInfo; +import org.spongycastle.asn1.cms.EnvelopedData; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +/** + * containing class for an CMS Enveloped Data object + * <p> + * Example of use - assuming the first recipient matches the private key we have. + * <pre> + * CMSEnvelopedData ed = new CMSEnvelopedData(inputStream); + * + * RecipientInformationStore recipients = ed.getRecipientInfos(); + * + * Collection c = recipients.getRecipients(); + * Iterator it = c.iterator(); + * + * if (it.hasNext()) + * { + * RecipientInformation recipient = (RecipientInformation)it.next(); + * + * byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(privateKey).setProvider("SC")); + * + * processData(recData); + * } + * </pre> + */ +public class CMSEnvelopedData +{ + RecipientInformationStore recipientInfoStore; + ContentInfo contentInfo; + + private AlgorithmIdentifier encAlg; + private ASN1Set unprotectedAttributes; + private OriginatorInformation originatorInfo; + + public CMSEnvelopedData( + byte[] envelopedData) + throws CMSException + { + this(CMSUtils.readContentInfo(envelopedData)); + } + + public CMSEnvelopedData( + InputStream envelopedData) + throws CMSException + { + this(CMSUtils.readContentInfo(envelopedData)); + } + + /** + * Construct a CMSEnvelopedData object from a content info object. + * + * @param contentInfo the contentInfo containing the CMS EnvelopedData object. + * @throws CMSException in the case where malformed content is encountered. + */ + public CMSEnvelopedData( + ContentInfo contentInfo) + throws CMSException + { + this.contentInfo = contentInfo; + + try + { + EnvelopedData envData = EnvelopedData.getInstance(contentInfo.getContent()); + + if (envData.getOriginatorInfo() != null) + { + originatorInfo = new OriginatorInformation(envData.getOriginatorInfo()); + } + + // + // read the recipients + // + ASN1Set recipientInfos = envData.getRecipientInfos(); + + // + // read the encrypted content info + // + EncryptedContentInfo encInfo = envData.getEncryptedContentInfo(); + this.encAlg = encInfo.getContentEncryptionAlgorithm(); + CMSReadable readable = new CMSProcessableByteArray(encInfo.getEncryptedContent().getOctets()); + CMSSecureReadable secureReadable = new CMSEnvelopedHelper.CMSEnvelopedSecureReadable( + this.encAlg, readable); + + // + // build the RecipientInformationStore + // + this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore( + recipientInfos, this.encAlg, secureReadable); + + this.unprotectedAttributes = envData.getUnprotectedAttrs(); + } + catch (ClassCastException e) + { + throw new CMSException("Malformed content.", e); + } + catch (IllegalArgumentException e) + { + throw new CMSException("Malformed content.", e); + } + } + + private byte[] encodeObj( + ASN1Encodable obj) + throws IOException + { + if (obj != null) + { + return obj.toASN1Primitive().getEncoded(); + } + + return null; + } + + /** + * Return the originator information associated with this message if present. + * + * @return OriginatorInformation, null if not present. + */ + public OriginatorInformation getOriginatorInfo() + { + return originatorInfo; + } + + /** + * Return the content encryption algorithm details for the data in this object. + * + * @return AlgorithmIdentifier representing the content encryption algorithm. + */ + public AlgorithmIdentifier getContentEncryptionAlgorithm() + { + return encAlg; + } + + /** + * return the object identifier for the content encryption algorithm. + */ + public String getEncryptionAlgOID() + { + return encAlg.getAlgorithm().getId(); + } + + /** + * return the ASN.1 encoded encryption algorithm parameters, or null if + * there aren't any. + */ + public byte[] getEncryptionAlgParams() + { + try + { + return encodeObj(encAlg.getParameters()); + } + catch (Exception e) + { + throw new RuntimeException("exception getting encryption parameters " + e); + } + } + + /** + * return a store of the intended recipients for this message + */ + public RecipientInformationStore getRecipientInfos() + { + return recipientInfoStore; + } + + /** + * return the ContentInfo + */ + public ContentInfo toASN1Structure() + { + return contentInfo; + } + + /** + * return a table of the unprotected attributes indexed by + * the OID of the attribute. + */ + public AttributeTable getUnprotectedAttributes() + { + if (unprotectedAttributes == null) + { + return null; + } + + return new AttributeTable(unprotectedAttributes); + } + + /** + * return the ASN.1 encoded representation of this object. + */ + public byte[] getEncoded() + throws IOException + { + return contentInfo.getEncoded(); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedDataGenerator.java b/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedDataGenerator.java new file mode 100644 index 00000000..b23a8254 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedDataGenerator.java @@ -0,0 +1,131 @@ +package org.spongycastle.cms; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Iterator; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.BEROctetString; +import org.spongycastle.asn1.BERSet; +import org.spongycastle.asn1.DERSet; +import org.spongycastle.asn1.cms.AttributeTable; +import org.spongycastle.asn1.cms.CMSObjectIdentifiers; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.cms.EncryptedContentInfo; +import org.spongycastle.asn1.cms.EnvelopedData; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.OutputEncryptor; + +/** + * General class for generating a CMS enveloped-data message. + * + * A simple example of usage. + * + * <pre> + * CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes()); + * + * CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator(); + * + * edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(recipientCert).setProvider("SC")); + * + * CMSEnvelopedData ed = edGen.generate( + * msg, + * new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC) + * .setProvider("SC").build()); + * + * </pre> + */ +public class CMSEnvelopedDataGenerator + extends CMSEnvelopedGenerator +{ + /** + * base constructor + */ + public CMSEnvelopedDataGenerator() + { + } + + private CMSEnvelopedData doGenerate( + CMSTypedData content, + OutputEncryptor contentEncryptor) + throws CMSException + { + if (!oldRecipientInfoGenerators.isEmpty()) + { + throw new IllegalStateException("can only use addRecipientGenerator() with this method"); + } + + ASN1EncodableVector recipientInfos = new ASN1EncodableVector(); + AlgorithmIdentifier encAlgId; + ASN1OctetString encContent; + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + try + { + OutputStream cOut = contentEncryptor.getOutputStream(bOut); + + content.write(cOut); + + cOut.close(); + } + catch (IOException e) + { + throw new CMSException(""); + } + + byte[] encryptedContent = bOut.toByteArray(); + + encAlgId = contentEncryptor.getAlgorithmIdentifier(); + + encContent = new BEROctetString(encryptedContent); + + GenericKey encKey = contentEncryptor.getKey(); + + for (Iterator it = recipientInfoGenerators.iterator(); it.hasNext();) + { + RecipientInfoGenerator recipient = (RecipientInfoGenerator)it.next(); + + recipientInfos.add(recipient.generate(encKey)); + } + + EncryptedContentInfo eci = new EncryptedContentInfo( + content.getContentType(), + encAlgId, + encContent); + + ASN1Set unprotectedAttrSet = null; + if (unprotectedAttributeGenerator != null) + { + AttributeTable attrTable = unprotectedAttributeGenerator.getAttributes(new HashMap()); + + unprotectedAttrSet = new BERSet(attrTable.toASN1EncodableVector()); + } + + ContentInfo contentInfo = new ContentInfo( + CMSObjectIdentifiers.envelopedData, + new EnvelopedData(originatorInfo, new DERSet(recipientInfos), eci, unprotectedAttrSet)); + + return new CMSEnvelopedData(contentInfo); + } + + /** + * generate an enveloped object that contains an CMS Enveloped Data + * object using the given provider. + * + * @param content the content to be encrypted + * @param contentEncryptor the symmetric key based encryptor to encrypt the content with. + */ + public CMSEnvelopedData generate( + CMSTypedData content, + OutputEncryptor contentEncryptor) + throws CMSException + { + return doGenerate(content, contentEncryptor); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedDataParser.java b/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedDataParser.java new file mode 100644 index 00000000..ae821a6a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedDataParser.java @@ -0,0 +1,208 @@ +package org.spongycastle.cms; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1OctetStringParser; +import org.spongycastle.asn1.ASN1SequenceParser; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.ASN1SetParser; +import org.spongycastle.asn1.BERTags; +import org.spongycastle.asn1.DERSet; +import org.spongycastle.asn1.cms.AttributeTable; +import org.spongycastle.asn1.cms.EncryptedContentInfoParser; +import org.spongycastle.asn1.cms.EnvelopedDataParser; +import org.spongycastle.asn1.cms.OriginatorInfo; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +/** + * Parsing class for an CMS Enveloped Data object from an input stream. + * <p> + * Note: that because we are in a streaming mode only one recipient can be tried and it is important + * that the methods on the parser are called in the appropriate order. + * </p> + * <p> + * Example of use - assuming the first recipient matches the private key we have. + * <pre> + * CMSEnvelopedDataParser ep = new CMSEnvelopedDataParser(inputStream); + * + * RecipientInformationStore recipients = ep.getRecipientInfos(); + * + * Collection c = recipients.getRecipients(); + * Iterator it = c.iterator(); + * + * if (it.hasNext()) + * { + * RecipientInformation recipient = (RecipientInformation)it.next(); + * + * CMSTypedStream recData = recipient.getContentStream(new JceKeyTransEnvelopedRecipient(privateKey).setProvider("SC")); + * + * processDataStream(recData.getContentStream()); + * } + * </pre> + * Note: this class does not introduce buffering - if you are processing large files you should create + * the parser with: + * <pre> + * CMSEnvelopedDataParser ep = new CMSEnvelopedDataParser(new BufferedInputStream(inputStream, bufSize)); + * </pre> + * where bufSize is a suitably large buffer size. + */ +public class CMSEnvelopedDataParser + extends CMSContentInfoParser +{ + RecipientInformationStore recipientInfoStore; + EnvelopedDataParser envelopedData; + + private AlgorithmIdentifier encAlg; + private AttributeTable unprotectedAttributes; + private boolean attrNotRead; + private OriginatorInformation originatorInfo; + + public CMSEnvelopedDataParser( + byte[] envelopedData) + throws CMSException, IOException + { + this(new ByteArrayInputStream(envelopedData)); + } + + public CMSEnvelopedDataParser( + InputStream envelopedData) + throws CMSException, IOException + { + super(envelopedData); + + this.attrNotRead = true; + this.envelopedData = new EnvelopedDataParser((ASN1SequenceParser)_contentInfo.getContent(BERTags.SEQUENCE)); + + // TODO Validate version? + //ASN1Integer version = this._envelopedData.getVersion(); + + OriginatorInfo info = this.envelopedData.getOriginatorInfo(); + + if (info != null) + { + this.originatorInfo = new OriginatorInformation(info); + } + + // + // read the recipients + // + ASN1Set recipientInfos = ASN1Set.getInstance(this.envelopedData.getRecipientInfos().toASN1Primitive()); + + // + // read the encrypted content info + // + EncryptedContentInfoParser encInfo = this.envelopedData.getEncryptedContentInfo(); + this.encAlg = encInfo.getContentEncryptionAlgorithm(); + CMSReadable readable = new CMSProcessableInputStream( + ((ASN1OctetStringParser)encInfo.getEncryptedContent(BERTags.OCTET_STRING)).getOctetStream()); + CMSSecureReadable secureReadable = new CMSEnvelopedHelper.CMSEnvelopedSecureReadable( + this.encAlg, readable); + + // + // build the RecipientInformationStore + // + this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore( + recipientInfos, this.encAlg, secureReadable); + } + + /** + * return the object identifier for the content encryption algorithm. + */ + public String getEncryptionAlgOID() + { + return encAlg.getAlgorithm().toString(); + } + + /** + * return the ASN.1 encoded encryption algorithm parameters, or null if + * there aren't any. + */ + public byte[] getEncryptionAlgParams() + { + try + { + return encodeObj(encAlg.getParameters()); + } + catch (Exception e) + { + throw new RuntimeException("exception getting encryption parameters " + e); + } + } + + /** + * Return the content encryption algorithm details for the data in this object. + * + * @return AlgorithmIdentifier representing the content encryption algorithm. + */ + public AlgorithmIdentifier getContentEncryptionAlgorithm() + { + return encAlg; + } + + /** + * Return the originator information associated with this message if present. + * + * @return OriginatorInformation, null if not present. + */ + public OriginatorInformation getOriginatorInfo() + { + return originatorInfo; + } + + /** + * return a store of the intended recipients for this message + */ + public RecipientInformationStore getRecipientInfos() + { + return recipientInfoStore; + } + + /** + * return a table of the unprotected attributes indexed by + * the OID of the attribute. + * @exception IOException + */ + public AttributeTable getUnprotectedAttributes() + throws IOException + { + if (unprotectedAttributes == null && attrNotRead) + { + ASN1SetParser set = envelopedData.getUnprotectedAttrs(); + + attrNotRead = false; + + if (set != null) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1Encodable o; + + while ((o = set.readObject()) != null) + { + ASN1SequenceParser seq = (ASN1SequenceParser)o; + + v.add(seq.toASN1Primitive()); + } + + unprotectedAttributes = new AttributeTable(new DERSet(v)); + } + } + + return unprotectedAttributes; + } + + private byte[] encodeObj( + ASN1Encodable obj) + throws IOException + { + if (obj != null) + { + return obj.toASN1Primitive().getEncoded(); + } + + return null; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedDataStreamGenerator.java b/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedDataStreamGenerator.java new file mode 100644 index 00000000..86f0a7c5 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedDataStreamGenerator.java @@ -0,0 +1,305 @@ +package org.spongycastle.cms; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Iterator; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.BERSequenceGenerator; +import org.spongycastle.asn1.BERSet; +import org.spongycastle.asn1.DERSet; +import org.spongycastle.asn1.DERTaggedObject; +import org.spongycastle.asn1.cms.AttributeTable; +import org.spongycastle.asn1.cms.CMSObjectIdentifiers; +import org.spongycastle.asn1.cms.EnvelopedData; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.OutputEncryptor; + +/** + * General class for generating a CMS enveloped-data message stream. + * <p> + * A simple example of usage. + * <pre> + * CMSEnvelopedDataStreamGenerator edGen = new CMSEnvelopedDataStreamGenerator(); + * + * edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(recipientCert).setProvider("SC")); + * + * ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + * + * OutputStream out = edGen.open( + * bOut, new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC) + * .setProvider("SC").build()); + * out.write(data); + * + * out.close(); + * </pre> + */ +public class CMSEnvelopedDataStreamGenerator + extends CMSEnvelopedGenerator +{ + private ASN1Set _unprotectedAttributes = null; + private int _bufferSize; + private boolean _berEncodeRecipientSet; + + /** + * base constructor + */ + public CMSEnvelopedDataStreamGenerator() + { + } + + /** + * Set the underlying string size for encapsulated data + * + * @param bufferSize length of octet strings to buffer the data. + */ + public void setBufferSize( + int bufferSize) + { + _bufferSize = bufferSize; + } + + /** + * Use a BER Set to store the recipient information + */ + public void setBEREncodeRecipients( + boolean berEncodeRecipientSet) + { + _berEncodeRecipientSet = berEncodeRecipientSet; + } + + private ASN1Integer getVersion() + { + if (originatorInfo != null || _unprotectedAttributes != null) + { + return new ASN1Integer(2); + } + else + { + return new ASN1Integer(0); + } + } + + private OutputStream doOpen( + ASN1ObjectIdentifier dataType, + OutputStream out, + OutputEncryptor encryptor) + throws IOException, CMSException + { + ASN1EncodableVector recipientInfos = new ASN1EncodableVector(); + GenericKey encKey = encryptor.getKey(); + Iterator it = recipientInfoGenerators.iterator(); + + while (it.hasNext()) + { + RecipientInfoGenerator recipient = (RecipientInfoGenerator)it.next(); + + recipientInfos.add(recipient.generate(encKey)); + } + + return open(dataType, out, recipientInfos, encryptor); + } + + protected OutputStream open( + ASN1ObjectIdentifier dataType, + OutputStream out, + ASN1EncodableVector recipientInfos, + OutputEncryptor encryptor) + throws IOException + { + // + // ContentInfo + // + BERSequenceGenerator cGen = new BERSequenceGenerator(out); + + cGen.addObject(CMSObjectIdentifiers.envelopedData); + + // + // Encrypted Data + // + BERSequenceGenerator envGen = new BERSequenceGenerator(cGen.getRawOutputStream(), 0, true); + + envGen.addObject(getVersion()); + + if (originatorInfo != null) + { + envGen.addObject(new DERTaggedObject(false, 0, originatorInfo)); + } + + if (_berEncodeRecipientSet) + { + envGen.getRawOutputStream().write(new BERSet(recipientInfos).getEncoded()); + } + else + { + envGen.getRawOutputStream().write(new DERSet(recipientInfos).getEncoded()); + } + + BERSequenceGenerator eiGen = new BERSequenceGenerator(envGen.getRawOutputStream()); + + eiGen.addObject(dataType); + + AlgorithmIdentifier encAlgId = encryptor.getAlgorithmIdentifier(); + + eiGen.getRawOutputStream().write(encAlgId.getEncoded()); + + OutputStream octetStream = CMSUtils.createBEROctetOutputStream( + eiGen.getRawOutputStream(), 0, false, _bufferSize); + + OutputStream cOut = encryptor.getOutputStream(octetStream); + + return new CmsEnvelopedDataOutputStream(cOut, cGen, envGen, eiGen); + } + + protected OutputStream open( + OutputStream out, + ASN1EncodableVector recipientInfos, + OutputEncryptor encryptor) + throws CMSException + { + try + { + // + // ContentInfo + // + BERSequenceGenerator cGen = new BERSequenceGenerator(out); + + cGen.addObject(CMSObjectIdentifiers.envelopedData); + + // + // Encrypted Data + // + BERSequenceGenerator envGen = new BERSequenceGenerator(cGen.getRawOutputStream(), 0, true); + + ASN1Set recipients; + if (_berEncodeRecipientSet) + { + recipients = new BERSet(recipientInfos); + } + else + { + recipients = new DERSet(recipientInfos); + } + + envGen.addObject(new ASN1Integer(EnvelopedData.calculateVersion(originatorInfo, recipients, _unprotectedAttributes))); + + if (originatorInfo != null) + { + envGen.addObject(new DERTaggedObject(false, 0, originatorInfo)); + } + + envGen.getRawOutputStream().write(recipients.getEncoded()); + + BERSequenceGenerator eiGen = new BERSequenceGenerator(envGen.getRawOutputStream()); + + eiGen.addObject(CMSObjectIdentifiers.data); + + AlgorithmIdentifier encAlgId = encryptor.getAlgorithmIdentifier(); + + eiGen.getRawOutputStream().write(encAlgId.getEncoded()); + + OutputStream octetStream = CMSUtils.createBEROctetOutputStream( + eiGen.getRawOutputStream(), 0, false, _bufferSize); + + return new CmsEnvelopedDataOutputStream(encryptor.getOutputStream(octetStream), cGen, envGen, eiGen); + } + catch (IOException e) + { + throw new CMSException("exception decoding algorithm parameters.", e); + } + } + + /** + * generate an enveloped object that contains an CMS Enveloped Data + * object using the given encryptor. + */ + public OutputStream open( + OutputStream out, + OutputEncryptor encryptor) + throws CMSException, IOException + { + return doOpen(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()), out, encryptor); + } + + /** + * generate an enveloped object that contains an CMS Enveloped Data + * object using the given encryptor and marking the data as being of the passed + * in type. + */ + public OutputStream open( + ASN1ObjectIdentifier dataType, + OutputStream out, + OutputEncryptor encryptor) + throws CMSException, IOException + { + return doOpen(dataType, out, encryptor); + } + + private class CmsEnvelopedDataOutputStream + extends OutputStream + { + private OutputStream _out; + private BERSequenceGenerator _cGen; + private BERSequenceGenerator _envGen; + private BERSequenceGenerator _eiGen; + + public CmsEnvelopedDataOutputStream( + OutputStream out, + BERSequenceGenerator cGen, + BERSequenceGenerator envGen, + BERSequenceGenerator eiGen) + { + _out = out; + _cGen = cGen; + _envGen = envGen; + _eiGen = eiGen; + } + + public void write( + int b) + throws IOException + { + _out.write(b); + } + + public void write( + byte[] bytes, + int off, + int len) + throws IOException + { + _out.write(bytes, off, len); + } + + public void write( + byte[] bytes) + throws IOException + { + _out.write(bytes); + } + + public void close() + throws IOException + { + _out.close(); + _eiGen.close(); + + if (unprotectedAttributeGenerator != null) + { + AttributeTable attrTable = unprotectedAttributeGenerator.getAttributes(new HashMap()); + + ASN1Set unprotectedAttrs = new BERSet(attrTable.toASN1EncodableVector()); + + _envGen.addObject(new DERTaggedObject(false, 1, unprotectedAttrs)); + } + + _envGen.close(); + _cGen.close(); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedGenerator.java b/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedGenerator.java new file mode 100644 index 00000000..c8702240 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedGenerator.java @@ -0,0 +1,75 @@ +package org.spongycastle.cms; + +import java.util.ArrayList; +import java.util.List; + +import org.spongycastle.asn1.cms.OriginatorInfo; +import org.spongycastle.asn1.kisa.KISAObjectIdentifiers; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.ntt.NTTObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.x9.X9ObjectIdentifiers; + +/** + * General class for generating a CMS enveloped-data message. + */ +public class CMSEnvelopedGenerator +{ + public static final String DES_EDE3_CBC = PKCSObjectIdentifiers.des_EDE3_CBC.getId(); + public static final String RC2_CBC = PKCSObjectIdentifiers.RC2_CBC.getId(); + public static final String IDEA_CBC = "1.3.6.1.4.1.188.7.1.1.2"; + public static final String CAST5_CBC = "1.2.840.113533.7.66.10"; + public static final String AES128_CBC = NISTObjectIdentifiers.id_aes128_CBC.getId(); + public static final String AES192_CBC = NISTObjectIdentifiers.id_aes192_CBC.getId(); + public static final String AES256_CBC = NISTObjectIdentifiers.id_aes256_CBC.getId(); + public static final String CAMELLIA128_CBC = NTTObjectIdentifiers.id_camellia128_cbc.getId(); + public static final String CAMELLIA192_CBC = NTTObjectIdentifiers.id_camellia192_cbc.getId(); + public static final String CAMELLIA256_CBC = NTTObjectIdentifiers.id_camellia256_cbc.getId(); + public static final String SEED_CBC = KISAObjectIdentifiers.id_seedCBC.getId(); + + public static final String DES_EDE3_WRAP = PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId(); + public static final String AES128_WRAP = NISTObjectIdentifiers.id_aes128_wrap.getId(); + public static final String AES192_WRAP = NISTObjectIdentifiers.id_aes192_wrap.getId(); + public static final String AES256_WRAP = NISTObjectIdentifiers.id_aes256_wrap.getId(); + public static final String CAMELLIA128_WRAP = NTTObjectIdentifiers.id_camellia128_wrap.getId(); + public static final String CAMELLIA192_WRAP = NTTObjectIdentifiers.id_camellia192_wrap.getId(); + public static final String CAMELLIA256_WRAP = NTTObjectIdentifiers.id_camellia256_wrap.getId(); + public static final String SEED_WRAP = KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap.getId(); + + public static final String ECDH_SHA1KDF = X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme.getId(); + public static final String ECMQV_SHA1KDF = X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme.getId(); + + final List oldRecipientInfoGenerators = new ArrayList(); + final List recipientInfoGenerators = new ArrayList(); + + protected CMSAttributeTableGenerator unprotectedAttributeGenerator = null; + + protected OriginatorInfo originatorInfo; + + /** + * base constructor + */ + public CMSEnvelopedGenerator() + { + } + + public void setUnprotectedAttributeGenerator(CMSAttributeTableGenerator unprotectedAttributeGenerator) + { + this.unprotectedAttributeGenerator = unprotectedAttributeGenerator; + } + + public void setOriginatorInfo(OriginatorInformation originatorInfo) + { + this.originatorInfo = originatorInfo.toASN1Structure(); + } + + /** + * Add a generator to produce the recipient info required. + * + * @param recipientGenerator a generator of a recipient info object. + */ + public void addRecipientInfoGenerator(RecipientInfoGenerator recipientGenerator) + { + recipientInfoGenerators.add(recipientGenerator); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedHelper.java b/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedHelper.java new file mode 100644 index 00000000..e0a71f93 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedHelper.java @@ -0,0 +1,203 @@ +package org.spongycastle.cms; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.cms.KEKRecipientInfo; +import org.spongycastle.asn1.cms.KeyAgreeRecipientInfo; +import org.spongycastle.asn1.cms.KeyTransRecipientInfo; +import org.spongycastle.asn1.cms.PasswordRecipientInfo; +import org.spongycastle.asn1.cms.RecipientInfo; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.operator.DigestCalculator; +import org.spongycastle.util.Integers; + +class CMSEnvelopedHelper +{ + static final CMSEnvelopedHelper INSTANCE = new CMSEnvelopedHelper(); + + private static final Map KEYSIZES = new HashMap(); + private static final Map BASE_CIPHER_NAMES = new HashMap(); + private static final Map CIPHER_ALG_NAMES = new HashMap(); + private static final Map MAC_ALG_NAMES = new HashMap(); + + static + { + KEYSIZES.put(CMSEnvelopedGenerator.DES_EDE3_CBC, Integers.valueOf(192)); + KEYSIZES.put(CMSEnvelopedGenerator.AES128_CBC, Integers.valueOf(128)); + KEYSIZES.put(CMSEnvelopedGenerator.AES192_CBC, Integers.valueOf(192)); + KEYSIZES.put(CMSEnvelopedGenerator.AES256_CBC, Integers.valueOf(256)); + + BASE_CIPHER_NAMES.put(CMSEnvelopedGenerator.DES_EDE3_CBC, "DESEDE"); + BASE_CIPHER_NAMES.put(CMSEnvelopedGenerator.AES128_CBC, "AES"); + BASE_CIPHER_NAMES.put(CMSEnvelopedGenerator.AES192_CBC, "AES"); + BASE_CIPHER_NAMES.put(CMSEnvelopedGenerator.AES256_CBC, "AES"); + + CIPHER_ALG_NAMES.put(CMSEnvelopedGenerator.DES_EDE3_CBC, "DESEDE/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(CMSEnvelopedGenerator.AES128_CBC, "AES/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(CMSEnvelopedGenerator.AES192_CBC, "AES/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(CMSEnvelopedGenerator.AES256_CBC, "AES/CBC/PKCS5Padding"); + + MAC_ALG_NAMES.put(CMSEnvelopedGenerator.DES_EDE3_CBC, "DESEDEMac"); + MAC_ALG_NAMES.put(CMSEnvelopedGenerator.AES128_CBC, "AESMac"); + MAC_ALG_NAMES.put(CMSEnvelopedGenerator.AES192_CBC, "AESMac"); + MAC_ALG_NAMES.put(CMSEnvelopedGenerator.AES256_CBC, "AESMac"); + } + + + + int getKeySize(String oid) + { + Integer keySize = (Integer)KEYSIZES.get(oid); + + if (keySize == null) + { + throw new IllegalArgumentException("no keysize for " + oid); + } + + return keySize.intValue(); + } + + + + static RecipientInformationStore buildRecipientInformationStore( + ASN1Set recipientInfos, AlgorithmIdentifier messageAlgorithm, CMSSecureReadable secureReadable) + { + return buildRecipientInformationStore(recipientInfos, messageAlgorithm, secureReadable, null); + } + + static RecipientInformationStore buildRecipientInformationStore( + ASN1Set recipientInfos, AlgorithmIdentifier messageAlgorithm, CMSSecureReadable secureReadable, AuthAttributesProvider additionalData) + { + List infos = new ArrayList(); + for (int i = 0; i != recipientInfos.size(); i++) + { + RecipientInfo info = RecipientInfo.getInstance(recipientInfos.getObjectAt(i)); + + readRecipientInfo(infos, info, messageAlgorithm, secureReadable, additionalData); + } + return new RecipientInformationStore(infos); + } + + private static void readRecipientInfo( + List infos, RecipientInfo info, AlgorithmIdentifier messageAlgorithm, CMSSecureReadable secureReadable, AuthAttributesProvider additionalData) + { + ASN1Encodable recipInfo = info.getInfo(); + if (recipInfo instanceof KeyTransRecipientInfo) + { + infos.add(new KeyTransRecipientInformation( + (KeyTransRecipientInfo)recipInfo, messageAlgorithm, secureReadable, additionalData)); + } + else if (recipInfo instanceof KEKRecipientInfo) + { + infos.add(new KEKRecipientInformation( + (KEKRecipientInfo)recipInfo, messageAlgorithm, secureReadable, additionalData)); + } + else if (recipInfo instanceof KeyAgreeRecipientInfo) + { + KeyAgreeRecipientInformation.readRecipientInfo(infos, + (KeyAgreeRecipientInfo)recipInfo, messageAlgorithm, secureReadable, additionalData); + } + else if (recipInfo instanceof PasswordRecipientInfo) + { + infos.add(new PasswordRecipientInformation( + (PasswordRecipientInfo)recipInfo, messageAlgorithm, secureReadable, additionalData)); + } + } + + static class CMSDigestAuthenticatedSecureReadable + implements CMSSecureReadable + { + private DigestCalculator digestCalculator; + private CMSReadable readable; + + public CMSDigestAuthenticatedSecureReadable(DigestCalculator digestCalculator, CMSReadable readable) + { + this.digestCalculator = digestCalculator; + this.readable = readable; + } + + public InputStream getInputStream() + throws IOException, CMSException + { + return new FilterInputStream(readable.getInputStream()) + { + public int read() + throws IOException + { + int b = in.read(); + + if (b >= 0) + { + digestCalculator.getOutputStream().write(b); + } + + return b; + } + + public int read(byte[] inBuf, int inOff, int inLen) + throws IOException + { + int n = in.read(inBuf, inOff, inLen); + + if (n >= 0) + { + digestCalculator.getOutputStream().write(inBuf, inOff, n); + } + + return n; + } + }; + } + + public byte[] getDigest() + { + return digestCalculator.getDigest(); + } + } + + static class CMSAuthenticatedSecureReadable implements CMSSecureReadable + { + private AlgorithmIdentifier algorithm; + private CMSReadable readable; + + CMSAuthenticatedSecureReadable(AlgorithmIdentifier algorithm, CMSReadable readable) + { + this.algorithm = algorithm; + this.readable = readable; + } + + public InputStream getInputStream() + throws IOException, CMSException + { + return readable.getInputStream(); + } + + } + + static class CMSEnvelopedSecureReadable implements CMSSecureReadable + { + private AlgorithmIdentifier algorithm; + private CMSReadable readable; + + CMSEnvelopedSecureReadable(AlgorithmIdentifier algorithm, CMSReadable readable) + { + this.algorithm = algorithm; + this.readable = readable; + } + + public InputStream getInputStream() + throws IOException, CMSException + { + return readable.getInputStream(); + } + + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSException.java b/pkix/src/main/java/org/spongycastle/cms/CMSException.java new file mode 100644 index 00000000..dd840120 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSException.java @@ -0,0 +1,32 @@ +package org.spongycastle.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/pkix/src/main/java/org/spongycastle/cms/CMSProcessable.java b/pkix/src/main/java/org/spongycastle/cms/CMSProcessable.java new file mode 100644 index 00000000..ed27eb15 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSProcessable.java @@ -0,0 +1,21 @@ +package org.spongycastle.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/pkix/src/main/java/org/spongycastle/cms/CMSProcessableByteArray.java b/pkix/src/main/java/org/spongycastle/cms/CMSProcessableByteArray.java new file mode 100644 index 00000000..2732a26e --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSProcessableByteArray.java @@ -0,0 +1,55 @@ +package org.spongycastle.cms; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.cms.CMSObjectIdentifiers; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cms/CMSProcessableFile.java b/pkix/src/main/java/org/spongycastle/cms/CMSProcessableFile.java new file mode 100644 index 00000000..6415dd5d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSProcessableFile.java @@ -0,0 +1,80 @@ +package org.spongycastle.cms; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.cms.CMSObjectIdentifiers; + +/** + * a holding class for a file of data to be processed. + */ +public class CMSProcessableFile + implements CMSTypedData, CMSReadable +{ + private static final int DEFAULT_BUF_SIZE = 32 * 1024; + + private final ASN1ObjectIdentifier type; + private final File file; + private final byte[] buf; + + public CMSProcessableFile( + File file) + { + this(file, DEFAULT_BUF_SIZE); + } + + public CMSProcessableFile( + File file, + int bufSize) + { + this(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()), file, bufSize); + } + + public CMSProcessableFile( + ASN1ObjectIdentifier type, + File file, + int bufSize) + { + this.type = type; + this.file = file; + buf = new byte[bufSize]; + } + + public InputStream getInputStream() + throws IOException, CMSException + { + return new BufferedInputStream(new FileInputStream(file), DEFAULT_BUF_SIZE); + } + + public void write(OutputStream zOut) + throws IOException, CMSException + { + FileInputStream fIn = new FileInputStream(file); + int len; + + while ((len = fIn.read(buf, 0, buf.length)) > 0) + { + zOut.write(buf, 0, len); + } + + fIn.close(); + } + + /** + * Return the file handle. + */ + public Object getContent() + { + return file; + } + + public ASN1ObjectIdentifier getContentType() + { + return type; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSProcessableInputStream.java b/pkix/src/main/java/org/spongycastle/cms/CMSProcessableInputStream.java new file mode 100644 index 00000000..fc644c95 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSProcessableInputStream.java @@ -0,0 +1,50 @@ +package org.spongycastle.cms; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.spongycastle.util.io.Streams; + +class CMSProcessableInputStream implements CMSProcessable, CMSReadable +{ + private InputStream input; + private boolean used = false; + + public CMSProcessableInputStream( + InputStream input) + { + this.input = input; + } + + public InputStream getInputStream() + { + checkSingleUsage(); + + return input; + } + + public void write(OutputStream zOut) + throws IOException, CMSException + { + checkSingleUsage(); + + Streams.pipeAll(input, zOut); + input.close(); + } + + public Object getContent() + { + return getInputStream(); + } + + private synchronized void checkSingleUsage() + { + if (used) + { + throw new IllegalStateException("CMSProcessableInputStream can only be used once"); + } + + used = true; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSReadable.java b/pkix/src/main/java/org/spongycastle/cms/CMSReadable.java new file mode 100644 index 00000000..ecf79a43 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSReadable.java @@ -0,0 +1,10 @@ +package org.spongycastle.cms; + +import java.io.IOException; +import java.io.InputStream; + +interface CMSReadable +{ + public InputStream getInputStream() + throws IOException, CMSException; +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSRuntimeException.java b/pkix/src/main/java/org/spongycastle/cms/CMSRuntimeException.java new file mode 100644 index 00000000..29805bb2 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSRuntimeException.java @@ -0,0 +1,32 @@ +package org.spongycastle.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/pkix/src/main/java/org/spongycastle/cms/CMSSecureReadable.java b/pkix/src/main/java/org/spongycastle/cms/CMSSecureReadable.java new file mode 100644 index 00000000..b16aef11 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSSecureReadable.java @@ -0,0 +1,10 @@ +package org.spongycastle.cms; + +import java.io.IOException; +import java.io.InputStream; + +interface CMSSecureReadable +{ + InputStream getInputStream() + throws IOException, CMSException; +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSSignatureAlgorithmNameGenerator.java b/pkix/src/main/java/org/spongycastle/cms/CMSSignatureAlgorithmNameGenerator.java new file mode 100644 index 00000000..8941a90b --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSSignatureAlgorithmNameGenerator.java @@ -0,0 +1,15 @@ +package org.spongycastle.cms; + +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cms/CMSSignatureEncryptionAlgorithmFinder.java b/pkix/src/main/java/org/spongycastle/cms/CMSSignatureEncryptionAlgorithmFinder.java new file mode 100644 index 00000000..886b4101 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSSignatureEncryptionAlgorithmFinder.java @@ -0,0 +1,17 @@ +package org.spongycastle.cms; + +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cms/CMSSignedData.java b/pkix/src/main/java/org/spongycastle/cms/CMSSignedData.java new file mode 100644 index 00000000..f8127d6d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSSignedData.java @@ -0,0 +1,543 @@ +package org.spongycastle.cms; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.BERSequence; +import org.spongycastle.asn1.DERSet; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.cms.SignedData; +import org.spongycastle.asn1.cms.SignerInfo; +import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.operator.SignatureAlgorithmIdentifierFinder; +import org.spongycastle.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("SC").build(cert))) + * { + * verified++; + * } + * } + * </pre> + */ +public class CMSSignedData +{ + 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. + // + if (signedData.getEncapContentInfo().getContent() != null) + { + this.signedContent = new CMSProcessableByteArray(signedData.getEncapContentInfo().getContentType(), + ((ASN1OctetString)(signedData.getEncapContentInfo() + .getContent())).getOctets()); + } + 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(); + SignatureAlgorithmIdentifierFinder sigAlgFinder = new DefaultSignatureAlgorithmIdentifierFinder(); + + 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 any X.509 certificate objects in this SignedData structure as a Store of X509CertificateHolder objects. + * + * @return a Store of X509CertificateHolder objects. + */ + public Store 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 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 getAttributeCertificates() + { + return HELPER.getAttributeCertificates(signedData.getCertificates()); + } + + /** + * 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()); + } + + /** + * 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(); + } + + /** + * 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();) + { + SignerInformation counterSigner = (SignerInformation)cIt.next(); + SignerInformationVerifier counterVerifier = verifierProvider.get(signer.getSID()); + + if (!counterSigner.verify(counterVerifier)) + { + return false; + } + } + } + } + catch (OperatorCreationException e) + { + throw new CMSException("failure in verifier provider: " + e.getMessage(), e); + } + } + + return true; + } + + /** + * 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/pkix/src/main/java/org/spongycastle/cms/CMSSignedDataGenerator.java b/pkix/src/main/java/org/spongycastle/cms/CMSSignedDataGenerator.java new file mode 100644 index 00000000..70dce12a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSSignedDataGenerator.java @@ -0,0 +1,232 @@ +package org.spongycastle.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 org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.BEROctetString; +import org.spongycastle.asn1.DERSet; +import org.spongycastle.asn1.cms.CMSObjectIdentifiers; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.cms.SignedData; +import org.spongycastle.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("SC").build(signKP.getPrivate()); + * + * gen.addSignerInfoGenerator( + * new JcaSignerInfoGeneratorBuilder( + * new JcaDigestCalculatorProviderBuilder().setProvider("SC").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/pkix/src/main/java/org/spongycastle/cms/CMSSignedDataParser.java b/pkix/src/main/java/org/spongycastle/cms/CMSSignedDataParser.java new file mode 100644 index 00000000..89edf873 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSSignedDataParser.java @@ -0,0 +1,624 @@ +package org.spongycastle.cms; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Generator; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetStringParser; +import org.spongycastle.asn1.ASN1SequenceParser; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.ASN1SetParser; +import org.spongycastle.asn1.ASN1StreamParser; +import org.spongycastle.asn1.BERSequenceGenerator; +import org.spongycastle.asn1.BERSetParser; +import org.spongycastle.asn1.BERTaggedObject; +import org.spongycastle.asn1.BERTags; +import org.spongycastle.asn1.DERSet; +import org.spongycastle.asn1.DERTaggedObject; +import org.spongycastle.asn1.cms.CMSObjectIdentifiers; +import org.spongycastle.asn1.cms.ContentInfoParser; +import org.spongycastle.asn1.cms.SignedDataParser; +import org.spongycastle.asn1.cms.SignerInfo; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.operator.DigestCalculator; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.util.Store; +import org.spongycastle.util.io.Streams; + +/** + * Parsing class for an CMS Signed Data object from an input stream. + * <p> + * Note: that because we are in a streaming mode only one signer can be tried and it is important + * that the methods on the parser are called in the appropriate order. + * </p> + * <p> + * A simple example of usage for an encapsulated signature. + * </p> + * <p> + * Two notes: first, in the example below the validity of + * the certificate isn't verified, just the fact that one of the certs + * matches the given signer, and, second, because we are in a streaming + * mode the order of the operations is important. + * </p> + * <pre> + * CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider("SC").build(), encapSigData); + * + * sp.getSignedContent().drain(); + * + * Store certStore = sp.getCertificates(); + * SignerInformationStore signers = sp.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(); + * + * System.out.println("verify returns: " + signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("SC").build(cert))); + * } + * </pre> + * Note also: this class does not introduce buffering - if you are processing large files you should create + * the parser with: + * <pre> + * CMSSignedDataParser ep = new CMSSignedDataParser(new BufferedInputStream(encapSigData, bufSize)); + * </pre> + * where bufSize is a suitably large buffer size. + */ +public class CMSSignedDataParser + extends CMSContentInfoParser +{ + private static final CMSSignedHelper HELPER = CMSSignedHelper.INSTANCE; + + private SignedDataParser _signedData; + private ASN1ObjectIdentifier _signedContentType; + private CMSTypedStream _signedContent; + private Map digests; + + private SignerInformationStore _signerInfoStore; + private ASN1Set _certSet, _crlSet; + private boolean _isCertCrlParsed; + + public CMSSignedDataParser( + DigestCalculatorProvider digestCalculatorProvider, + byte[] sigBlock) + throws CMSException + { + this(digestCalculatorProvider, new ByteArrayInputStream(sigBlock)); + } + + public CMSSignedDataParser( + DigestCalculatorProvider digestCalculatorProvider, + CMSTypedStream signedContent, + byte[] sigBlock) + throws CMSException + { + this(digestCalculatorProvider, signedContent, new ByteArrayInputStream(sigBlock)); + } + + /** + * base constructor - with encapsulated content + */ + public CMSSignedDataParser( + DigestCalculatorProvider digestCalculatorProvider, + InputStream sigData) + throws CMSException + { + this(digestCalculatorProvider, null, sigData); + } + + /** + * base constructor + * + * @param digestCalculatorProvider for generating accumulating digests + * @param signedContent the content that was signed. + * @param sigData the signature object stream. + */ + public CMSSignedDataParser( + DigestCalculatorProvider digestCalculatorProvider, + CMSTypedStream signedContent, + InputStream sigData) + throws CMSException + { + super(sigData); + + try + { + _signedContent = signedContent; + _signedData = SignedDataParser.getInstance(_contentInfo.getContent(BERTags.SEQUENCE)); + digests = new HashMap(); + + ASN1SetParser digAlgs = _signedData.getDigestAlgorithms(); + ASN1Encodable o; + + while ((o = digAlgs.readObject()) != null) + { + AlgorithmIdentifier algId = AlgorithmIdentifier.getInstance(o); + try + { + DigestCalculator calculator = digestCalculatorProvider.get(algId); + + if (calculator != null) + { + this.digests.put(algId.getAlgorithm(), calculator); + } + } + catch (OperatorCreationException e) + { + // ignore + } + } + + // + // If the message is simply a certificate chain message getContent() may return null. + // + ContentInfoParser cont = _signedData.getEncapContentInfo(); + ASN1OctetStringParser octs = (ASN1OctetStringParser) + cont.getContent(BERTags.OCTET_STRING); + + if (octs != null) + { + CMSTypedStream ctStr = new CMSTypedStream( + cont.getContentType().getId(), octs.getOctetStream()); + + if (_signedContent == null) + { + _signedContent = ctStr; + } + else + { + // + // content passed in, need to read past empty encapsulated content info object if present + // + ctStr.drain(); + } + } + + if (signedContent == null) + { + _signedContentType = cont.getContentType(); + } + else + { + _signedContentType = _signedContent.getContentType(); + } + } + catch (IOException e) + { + throw new CMSException("io exception: " + e.getMessage(), e); + } + } + + /** + * Return the version number for the SignedData object + * + * @return the version number + */ + public int getVersion() + { + return _signedData.getVersion().getValue().intValue(); + } + + /** + * return the collection of signers that are associated with the + * signatures for the message. + * @throws CMSException + */ + public SignerInformationStore getSignerInfos() + throws CMSException + { + if (_signerInfoStore == null) + { + populateCertCrlSets(); + + List signerInfos = new ArrayList(); + Map hashes = new HashMap(); + + Iterator it = digests.keySet().iterator(); + while (it.hasNext()) + { + Object digestKey = it.next(); + + hashes.put(digestKey, ((DigestCalculator)digests.get(digestKey)).getDigest()); + } + + try + { + ASN1SetParser s = _signedData.getSignerInfos(); + ASN1Encodable o; + + while ((o = s.readObject()) != null) + { + SignerInfo info = SignerInfo.getInstance(o.toASN1Primitive()); + + byte[] hash = (byte[])hashes.get(info.getDigestAlgorithm().getAlgorithm()); + + signerInfos.add(new SignerInformation(info, _signedContentType, null, hash)); + } + } + catch (IOException e) + { + throw new CMSException("io exception: " + e.getMessage(), e); + } + + _signerInfoStore = new SignerInformationStore(signerInfos); + } + + return _signerInfoStore; + } + + /** + * Return any X.509 certificate objects in this SignedData structure as a Store of X509CertificateHolder objects. + * + * @return a Store of X509CertificateHolder objects. + */ + public Store getCertificates() + throws CMSException + { + populateCertCrlSets(); + + return HELPER.getCertificates(_certSet); + } + + /** + * Return any X.509 CRL objects in this SignedData structure as a Store of X509CRLHolder objects. + * + * @return a Store of X509CRLHolder objects. + */ + public Store getCRLs() + throws CMSException + { + populateCertCrlSets(); + + return HELPER.getCRLs(_crlSet); + } + + /** + * 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 getAttributeCertificates() + throws CMSException + { + populateCertCrlSets(); + + return HELPER.getAttributeCertificates(_certSet); + } + + /** + * 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) + throws CMSException + { + populateCertCrlSets(); + + return HELPER.getOtherRevocationInfo(otherRevocationInfoFormat, _crlSet); + } + + private void populateCertCrlSets() + throws CMSException + { + if (_isCertCrlParsed) + { + return; + } + + _isCertCrlParsed = true; + + try + { + // care! Streaming - these must be done in exactly this order. + _certSet = getASN1Set(_signedData.getCertificates()); + _crlSet = getASN1Set(_signedData.getCrls()); + } + catch (IOException e) + { + throw new CMSException("problem parsing cert/crl sets", e); + } + } + + /** + * 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 _signedContentType.getId(); + } + + public CMSTypedStream getSignedContent() + { + if (_signedContent == null) + { + return null; + } + + InputStream digStream = CMSUtils.attachDigestsToInputStream( + digests.values(), _signedContent.getContentStream()); + + return new CMSTypedStream(_signedContent.getContentType(), digStream); + } + + /** + * Replace the signerinformation store associated with the passed + * in message contained in the stream original 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. + * <p> + * The output stream is returned unclosed. + * </p> + * @param original the signed data stream to be used as a base. + * @param signerInformationStore the new signer information store to use. + * @param out the stream to write the new signed data object to. + * @return out. + */ + public static OutputStream replaceSigners( + InputStream original, + SignerInformationStore signerInformationStore, + OutputStream out) + throws CMSException, IOException + { + ASN1StreamParser in = new ASN1StreamParser(original); + ContentInfoParser contentInfo = new ContentInfoParser((ASN1SequenceParser)in.readObject()); + SignedDataParser signedData = SignedDataParser.getInstance(contentInfo.getContent(BERTags.SEQUENCE)); + + BERSequenceGenerator sGen = new BERSequenceGenerator(out); + + sGen.addObject(CMSObjectIdentifiers.signedData); + + BERSequenceGenerator sigGen = new BERSequenceGenerator(sGen.getRawOutputStream(), 0, true); + + // version number + sigGen.addObject(signedData.getVersion()); + + // digests + signedData.getDigestAlgorithms().toASN1Primitive(); // skip old ones + + ASN1EncodableVector digestAlgs = new ASN1EncodableVector(); + + for (Iterator it = signerInformationStore.getSigners().iterator(); it.hasNext();) + { + SignerInformation signer = (SignerInformation)it.next(); + digestAlgs.add(CMSSignedHelper.INSTANCE.fixAlgID(signer.getDigestAlgorithmID())); + } + + sigGen.getRawOutputStream().write(new DERSet(digestAlgs).getEncoded()); + + // encap content info + ContentInfoParser encapContentInfo = signedData.getEncapContentInfo(); + + BERSequenceGenerator eiGen = new BERSequenceGenerator(sigGen.getRawOutputStream()); + + eiGen.addObject(encapContentInfo.getContentType()); + + pipeEncapsulatedOctetString(encapContentInfo, eiGen.getRawOutputStream()); + + eiGen.close(); + + + writeSetToGeneratorTagged(sigGen, signedData.getCertificates(), 0); + writeSetToGeneratorTagged(sigGen, signedData.getCrls(), 1); + + + ASN1EncodableVector signerInfos = new ASN1EncodableVector(); + for (Iterator it = signerInformationStore.getSigners().iterator(); it.hasNext();) + { + SignerInformation signer = (SignerInformation)it.next(); + + signerInfos.add(signer.toASN1Structure()); + } + + sigGen.getRawOutputStream().write(new DERSet(signerInfos).getEncoded()); + + sigGen.close(); + + sGen.close(); + + return out; + } + + /** + * Replace the certificate and CRL information associated with this + * CMSSignedData object with the new one passed in. + * <p> + * The output stream is returned unclosed. + * </p> + * @param original the signed data stream to be used as a base. + * @param certs new certificates to be used, if any. + * @param crls new CRLs to be used, if any. + * @param attrCerts new attribute certificates to be used, if any. + * @param out the stream to write the new signed data object to. + * @return out. + * @exception CMSException if there is an error processing the CertStore + */ + public static OutputStream replaceCertificatesAndCRLs( + InputStream original, + Store certs, + Store crls, + Store attrCerts, + OutputStream out) + throws CMSException, IOException + { + ASN1StreamParser in = new ASN1StreamParser(original); + ContentInfoParser contentInfo = new ContentInfoParser((ASN1SequenceParser)in.readObject()); + SignedDataParser signedData = SignedDataParser.getInstance(contentInfo.getContent(BERTags.SEQUENCE)); + + BERSequenceGenerator sGen = new BERSequenceGenerator(out); + + sGen.addObject(CMSObjectIdentifiers.signedData); + + BERSequenceGenerator sigGen = new BERSequenceGenerator(sGen.getRawOutputStream(), 0, true); + + // version number + sigGen.addObject(signedData.getVersion()); + + // digests + sigGen.getRawOutputStream().write(signedData.getDigestAlgorithms().toASN1Primitive().getEncoded()); + + // encap content info + ContentInfoParser encapContentInfo = signedData.getEncapContentInfo(); + + BERSequenceGenerator eiGen = new BERSequenceGenerator(sigGen.getRawOutputStream()); + + eiGen.addObject(encapContentInfo.getContentType()); + + pipeEncapsulatedOctetString(encapContentInfo, eiGen.getRawOutputStream()); + + eiGen.close(); + + // + // skip existing certs and CRLs + // + getASN1Set(signedData.getCertificates()); + getASN1Set(signedData.getCrls()); + + // + // replace the certs and crls in the SignedData object + // + if (certs != null || attrCerts != null) + { + List certificates = new ArrayList(); + + if (certs != null) + { + certificates.addAll(CMSUtils.getCertificatesFromStore(certs)); + } + if (attrCerts != null) + { + certificates.addAll(CMSUtils.getAttributeCertificatesFromStore(attrCerts)); + } + + ASN1Set asn1Certs = CMSUtils.createBerSetFromList(certificates); + + if (asn1Certs.size() > 0) + { + sigGen.getRawOutputStream().write(new DERTaggedObject(false, 0, asn1Certs).getEncoded()); + } + } + + if (crls != null) + { + ASN1Set asn1Crls = CMSUtils.createBerSetFromList(CMSUtils.getCRLsFromStore(crls)); + + if (asn1Crls.size() > 0) + { + sigGen.getRawOutputStream().write(new DERTaggedObject(false, 1, asn1Crls).getEncoded()); + } + } + + sigGen.getRawOutputStream().write(signedData.getSignerInfos().toASN1Primitive().getEncoded()); + + sigGen.close(); + + sGen.close(); + + return out; + } + + private static void writeSetToGeneratorTagged( + ASN1Generator asn1Gen, + ASN1SetParser asn1SetParser, + int tagNo) + throws IOException + { + ASN1Set asn1Set = getASN1Set(asn1SetParser); + + if (asn1Set != null) + { + if (asn1SetParser instanceof BERSetParser) + { + asn1Gen.getRawOutputStream().write(new BERTaggedObject(false, tagNo, asn1Set).getEncoded()); + } + else + { + asn1Gen.getRawOutputStream().write(new DERTaggedObject(false, tagNo, asn1Set).getEncoded()); + } + } + } + + private static ASN1Set getASN1Set( + ASN1SetParser asn1SetParser) + { + return asn1SetParser == null + ? null + : ASN1Set.getInstance(asn1SetParser.toASN1Primitive()); + } + + private static void pipeEncapsulatedOctetString(ContentInfoParser encapContentInfo, + OutputStream rawOutputStream) throws IOException + { + ASN1OctetStringParser octs = (ASN1OctetStringParser) + encapContentInfo.getContent(BERTags.OCTET_STRING); + + if (octs != null) + { + pipeOctetString(octs, rawOutputStream); + } + +// BERTaggedObjectParser contentObject = (BERTaggedObjectParser)encapContentInfo.getContentObject(); +// if (contentObject != null) +// { +// // Handle IndefiniteLengthInputStream safely +// InputStream input = ASN1StreamParser.getSafeRawInputStream(contentObject.getContentStream(true)); +// +// // TODO BerTaggedObjectGenerator? +// BEROutputStream berOut = new BEROutputStream(rawOutputStream); +// berOut.write(DERTags.CONSTRUCTED | DERTags.TAGGED | 0); +// berOut.write(0x80); +// +// pipeRawOctetString(input, rawOutputStream); +// +// berOut.write(0x00); +// berOut.write(0x00); +// +// input.close(); +// } + } + + private static void pipeOctetString( + ASN1OctetStringParser octs, + OutputStream output) + throws IOException + { + // TODO Allow specification of a specific fragment size? + OutputStream outOctets = CMSUtils.createBEROctetOutputStream( + output, 0, true, 0); + Streams.pipeAll(octs.getOctetStream(), outOctets); + outOctets.close(); + } + +// private static void pipeRawOctetString( +// InputStream rawInput, +// OutputStream rawOutput) +// throws IOException +// { +// InputStream tee = new TeeInputStream(rawInput, rawOutput); +// ASN1StreamParser sp = new ASN1StreamParser(tee); +// ASN1OctetStringParser octs = (ASN1OctetStringParser)sp.readObject(); +// Streams.drain(octs.getOctetStream()); +// } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSSignedDataStreamGenerator.java b/pkix/src/main/java/org/spongycastle/cms/CMSSignedDataStreamGenerator.java new file mode 100644 index 00000000..15a94bf5 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSSignedDataStreamGenerator.java @@ -0,0 +1,486 @@ +package org.spongycastle.cms; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Iterator; +import java.util.List; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.ASN1TaggedObject; +import org.spongycastle.asn1.BERSequenceGenerator; +import org.spongycastle.asn1.BERTaggedObject; +import org.spongycastle.asn1.DERSet; +import org.spongycastle.asn1.cms.CMSObjectIdentifiers; +import org.spongycastle.asn1.cms.SignerInfo; + +/** + * General class for generating a pkcs7-signature message stream. + * <p> + * A simple example of usage. + * </p> + * <pre> + * X509Certificate signCert = ... + * certList.add(signCert); + * + * Store certs = new JcaCertStore(certList); + * ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("SC").build(signKP.getPrivate()); + * + * CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator(); + * + * gen.addSignerInfoGenerator( + * new JcaSignerInfoGeneratorBuilder( + * new JcaDigestCalculatorProviderBuilder().setProvider("SC").build()) + * .build(sha1Signer, signCert)); + * + * gen.addCertificates(certs); + * + * OutputStream sigOut = gen.open(bOut); + * + * sigOut.write("Hello World!".getBytes()); + * + * sigOut.close(); + * </pre> + */ +public class CMSSignedDataStreamGenerator + extends CMSSignedGenerator +{ + private int _bufferSize; + + /** + * base constructor + */ + public CMSSignedDataStreamGenerator() + { + } + + /** + * Set the underlying string size for encapsulated data + * + * @param bufferSize length of octet strings to buffer the data. + */ + public void setBufferSize( + int bufferSize) + { + _bufferSize = bufferSize; + } + + /** + * generate a signed object that for a CMS Signed Data + * object using the given provider. + */ + public OutputStream open( + OutputStream out) + throws IOException + { + return open(out, false); + } + + /** + * generate a signed object that for a CMS Signed Data + * object using the given provider - if encapsulate is true a copy + * of the message will be included in the signature with the + * default content type "data". + */ + public OutputStream open( + OutputStream out, + boolean encapsulate) + throws IOException + { + return open(CMSObjectIdentifiers.data, out, encapsulate); + } + + /** + * generate a signed object that for a CMS Signed Data + * object using the given provider - if encapsulate is true a copy + * of the message will be included in the signature with the + * default content type "data". If dataOutputStream is non null the data + * being signed will be written to the stream as it is processed. + * @param out stream the CMS object is to be written to. + * @param encapsulate true if data should be encapsulated. + * @param dataOutputStream output stream to copy the data being signed to. + */ + public OutputStream open( + OutputStream out, + boolean encapsulate, + OutputStream dataOutputStream) + throws IOException + { + return open(CMSObjectIdentifiers.data, out, encapsulate, dataOutputStream); + } + + /** + * generate a signed object that for a CMS Signed Data + * object using the given provider - if encapsulate is true a copy + * of the message will be included in the signature. The content type + * is set according to the OID represented by the string signedContentType. + */ + public OutputStream open( + ASN1ObjectIdentifier eContentType, + OutputStream out, + boolean encapsulate) + throws IOException + { + return open(eContentType, out, encapsulate, null); + } + + /** + * generate a signed object that for a CMS Signed Data + * object using the given provider - if encapsulate is true a copy + * of the message will be included in the signature. The content type + * is set according to the OID represented by the string signedContentType. + * @param eContentType OID for data to be signed. + * @param out stream the CMS object is to be written to. + * @param encapsulate true if data should be encapsulated. + * @param dataOutputStream output stream to copy the data being signed to. + */ + public OutputStream open( + ASN1ObjectIdentifier eContentType, + OutputStream out, + boolean encapsulate, + OutputStream dataOutputStream) + throws IOException + { + // 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 +// } + + // + // ContentInfo + // + BERSequenceGenerator sGen = new BERSequenceGenerator(out); + + sGen.addObject(CMSObjectIdentifiers.signedData); + + // + // Signed Data + // + BERSequenceGenerator sigGen = new BERSequenceGenerator(sGen.getRawOutputStream(), 0, true); + + sigGen.addObject(calculateVersion(eContentType)); + + ASN1EncodableVector digestAlgs = new ASN1EncodableVector(); + + // + // add the precalculated SignerInfo digest algorithms. + // + for (Iterator it = _signers.iterator(); it.hasNext();) + { + SignerInformation signer = (SignerInformation)it.next(); + digestAlgs.add(CMSSignedHelper.INSTANCE.fixAlgID(signer.getDigestAlgorithmID())); + } + + // + // add the new digests + // + + for (Iterator it = signerGens.iterator(); it.hasNext();) + { + SignerInfoGenerator signerGen = (SignerInfoGenerator)it.next(); + + digestAlgs.add(signerGen.getDigestAlgorithm()); + } + + sigGen.getRawOutputStream().write(new DERSet(digestAlgs).getEncoded()); + + BERSequenceGenerator eiGen = new BERSequenceGenerator(sigGen.getRawOutputStream()); + eiGen.addObject(eContentType); + + // If encapsulating, add the data as an octet string in the sequence + OutputStream encapStream = encapsulate + ? CMSUtils.createBEROctetOutputStream(eiGen.getRawOutputStream(), 0, true, _bufferSize) + : null; + + // Also send the data to 'dataOutputStream' if necessary + OutputStream contentStream = CMSUtils.getSafeTeeOutputStream(dataOutputStream, encapStream); + + // Let all the signers see the data as it is written + OutputStream sigStream = CMSUtils.attachSignersToOutputStream(signerGens, contentStream); + + return new CmsSignedDataOutputStream(sigStream, eContentType, sGen, sigGen, eiGen); + } + + // RFC3852, section 5.1: + // IF ((certificates is present) AND + // (any certificates with a type of other are present)) OR + // ((crls is present) AND + // (any crls with a type of other are present)) + // THEN version MUST be 5 + // ELSE + // IF (certificates is present) AND + // (any version 2 attribute certificates are present) + // THEN version MUST be 4 + // ELSE + // IF ((certificates is present) AND + // (any version 1 attribute certificates are present)) OR + // (any SignerInfo structures are version 3) OR + // (encapContentInfo eContentType is other than id-data) + // THEN version MUST be 3 + // ELSE version MUST be 1 + // + private ASN1Integer calculateVersion( + ASN1ObjectIdentifier contentOid) + { + boolean otherCert = false; + boolean otherCrl = false; + boolean attrCertV1Found = false; + boolean attrCertV2Found = false; + + if (certs != null) + { + for (Iterator it = certs.iterator(); it.hasNext();) + { + Object obj = it.next(); + if (obj instanceof ASN1TaggedObject) + { + ASN1TaggedObject tagged = (ASN1TaggedObject)obj; + + if (tagged.getTagNo() == 1) + { + attrCertV1Found = true; + } + else if (tagged.getTagNo() == 2) + { + attrCertV2Found = true; + } + else if (tagged.getTagNo() == 3) + { + otherCert = true; + } + } + } + } + + if (otherCert) + { + return new ASN1Integer(5); + } + + if (crls != null) // no need to check if otherCert is true + { + for (Iterator it = crls.iterator(); it.hasNext();) + { + Object obj = it.next(); + if (obj instanceof ASN1TaggedObject) + { + otherCrl = true; + } + } + } + + if (otherCrl) + { + return new ASN1Integer(5); + } + + if (attrCertV2Found) + { + return new ASN1Integer(4); + } + + if (attrCertV1Found) + { + return new ASN1Integer(3); + } + + if (checkForVersion3(_signers, signerGens)) + { + return new ASN1Integer(3); + } + + if (!CMSObjectIdentifiers.data.equals(contentOid)) + { + return new ASN1Integer(3); + } + + return new ASN1Integer(1); + } + + private boolean checkForVersion3(List signerInfos, List signerInfoGens) + { + for (Iterator it = signerInfos.iterator(); it.hasNext();) + { + SignerInfo s = SignerInfo.getInstance(((SignerInformation)it.next()).toASN1Structure()); + + if (s.getVersion().getValue().intValue() == 3) + { + return true; + } + } + + for (Iterator it = signerInfoGens.iterator(); it.hasNext();) + { + SignerInfoGenerator s = (SignerInfoGenerator)it.next(); + + if (s.getGeneratedVersion() == 3) + { + return true; + } + } + + return false; + } + + private class CmsSignedDataOutputStream + extends OutputStream + { + private OutputStream _out; + private ASN1ObjectIdentifier _contentOID; + private BERSequenceGenerator _sGen; + private BERSequenceGenerator _sigGen; + private BERSequenceGenerator _eiGen; + + public CmsSignedDataOutputStream( + OutputStream out, + ASN1ObjectIdentifier contentOID, + BERSequenceGenerator sGen, + BERSequenceGenerator sigGen, + BERSequenceGenerator eiGen) + { + _out = out; + _contentOID = contentOID; + _sGen = sGen; + _sigGen = sigGen; + _eiGen = eiGen; + } + + public void write( + int b) + throws IOException + { + _out.write(b); + } + + public void write( + byte[] bytes, + int off, + int len) + throws IOException + { + _out.write(bytes, off, len); + } + + public void write( + byte[] bytes) + throws IOException + { + _out.write(bytes); + } + + public void close() + throws IOException + { + _out.close(); + _eiGen.close(); + + digests.clear(); // clear the current preserved digest state + + if (certs.size() != 0) + { + ASN1Set certSet = CMSUtils.createBerSetFromList(certs); + + _sigGen.getRawOutputStream().write(new BERTaggedObject(false, 0, certSet).getEncoded()); + } + + if (crls.size() != 0) + { + ASN1Set crlSet = CMSUtils.createBerSetFromList(crls); + + _sigGen.getRawOutputStream().write(new BERTaggedObject(false, 1, crlSet).getEncoded()); + } + + // + // collect all the SignerInfo objects + // + ASN1EncodableVector signerInfos = new ASN1EncodableVector(); + + // + // add the generated SignerInfo objects + // + + for (Iterator it = signerGens.iterator(); it.hasNext();) + { + SignerInfoGenerator sigGen = (SignerInfoGenerator)it.next(); + + + try + { + signerInfos.add(sigGen.generate(_contentOID)); + + byte[] calculatedDigest = sigGen.getCalculatedDigest(); + + digests.put(sigGen.getDigestAlgorithm().getAlgorithm().getId(), calculatedDigest); + } + catch (CMSException e) + { + throw new CMSStreamException("exception generating signers: " + e.getMessage(), e); + } + } + + // + // add the precalculated SignerInfo objects + // + { + Iterator it = _signers.iterator(); + while (it.hasNext()) + { + SignerInformation signer = (SignerInformation)it.next(); + + // TODO Verify the content type and calculated digest match the precalculated SignerInfo +// if (!signer.getContentType().equals(_contentOID)) +// { +// // TODO The precalculated content type did not match - error? +// } +// +// byte[] calculatedDigest = (byte[])_digests.get(signer.getDigestAlgOID()); +// if (calculatedDigest == null) +// { +// // TODO We can't confirm this digest because we didn't calculate it - error? +// } +// else +// { +// if (!Arrays.areEqual(signer.getContentDigest(), calculatedDigest)) +// { +// // TODO The precalculated digest did not match - error? +// } +// } + + signerInfos.add(signer.toASN1Structure()); + } + } + + _sigGen.getRawOutputStream().write(new DERSet(signerInfos).getEncoded()); + + _sigGen.close(); + _sGen.close(); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSSignedGenerator.java b/pkix/src/main/java/org/spongycastle/cms/CMSSignedGenerator.java new file mode 100644 index 00000000..b2747d9f --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSSignedGenerator.java @@ -0,0 +1,239 @@ +package org.spongycastle.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 org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERTaggedObject; +import org.spongycastle.asn1.cms.CMSObjectIdentifiers; +import org.spongycastle.asn1.cms.OtherRevocationInfoFormat; +import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x9.X9ObjectIdentifiers; +import org.spongycastle.cert.X509AttributeCertificateHolder; +import org.spongycastle.cert.X509CRLHolder; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.util.Arrays; +import org.spongycastle.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(); + 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(); + + 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(); + public static final String ENCRYPTION_GOST3410 = CryptoProObjectIdentifiers.gostR3410_94.getId(); + public static final String ENCRYPTION_ECGOST3410 = CryptoProObjectIdentifiers.gostR3410_2001.getId(); + + 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)); + } + + /** + * 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)); + } + + /** + * 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/pkix/src/main/java/org/spongycastle/cms/CMSSignedHelper.java b/pkix/src/main/java/org/spongycastle/cms/CMSSignedHelper.java new file mode 100644 index 00000000..1f4187bc --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSSignedHelper.java @@ -0,0 +1,253 @@ +package org.spongycastle.cms; + +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.ASN1TaggedObject; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.cms.OtherRevocationInfoFormat; +import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import org.spongycastle.asn1.eac.EACObjectIdentifiers; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.AttributeCertificate; +import org.spongycastle.asn1.x509.Certificate; +import org.spongycastle.asn1.x509.CertificateList; +import org.spongycastle.asn1.x509.X509ObjectIdentifiers; +import org.spongycastle.asn1.x9.X9ObjectIdentifiers; +import org.spongycastle.cert.X509AttributeCertificateHolder; +import org.spongycastle.cert.X509CRLHolder; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.util.CollectionStore; +import org.spongycastle.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"); + addEntries(OIWObjectIdentifiers.md4WithRSA, "MD4", "RSA"); + addEntries(OIWObjectIdentifiers.md4WithRSAEncryption, "MD4", "RSA"); + addEntries(OIWObjectIdentifiers.md5WithRSA, "MD5", "RSA"); + addEntries(OIWObjectIdentifiers.sha1WithRSA, "SHA1", "RSA"); + addEntries(PKCSObjectIdentifiers.md2WithRSAEncryption, "MD2", "RSA"); + addEntries(PKCSObjectIdentifiers.md4WithRSAEncryption, "MD4", "RSA"); + 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"); + 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"); + 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"); + 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"); + + 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()); + } + + 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()); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSSignerDigestMismatchException.java b/pkix/src/main/java/org/spongycastle/cms/CMSSignerDigestMismatchException.java new file mode 100644 index 00000000..c2bf8a26 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSSignerDigestMismatchException.java @@ -0,0 +1,11 @@ +package org.spongycastle.cms; + +public class CMSSignerDigestMismatchException + extends CMSException +{ + public CMSSignerDigestMismatchException( + String msg) + { + super(msg); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSStreamException.java b/pkix/src/main/java/org/spongycastle/cms/CMSStreamException.java new file mode 100644 index 00000000..65550353 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSStreamException.java @@ -0,0 +1,26 @@ +package org.spongycastle.cms; + +import java.io.IOException; + +public class CMSStreamException + extends IOException +{ + private final Throwable underlying; + + CMSStreamException(String msg) + { + super(msg); + this.underlying = null; + } + + CMSStreamException(String msg, Throwable underlying) + { + super(msg); + this.underlying = underlying; + } + + public Throwable getCause() + { + return underlying; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSTypedData.java b/pkix/src/main/java/org/spongycastle/cms/CMSTypedData.java new file mode 100644 index 00000000..eb044d95 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSTypedData.java @@ -0,0 +1,9 @@ +package org.spongycastle.cms; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; + +public interface CMSTypedData + extends CMSProcessable +{ + ASN1ObjectIdentifier getContentType(); +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSTypedStream.java b/pkix/src/main/java/org/spongycastle/cms/CMSTypedStream.java new file mode 100644 index 00000000..74984427 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSTypedStream.java @@ -0,0 +1,86 @@ +package org.spongycastle.cms; + +import java.io.BufferedInputStream; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.util.io.Streams; + +public class CMSTypedStream +{ + private static final int BUF_SIZ = 32 * 1024; + + private final ASN1ObjectIdentifier _oid; + private final InputStream _in; + + public CMSTypedStream( + InputStream in) + { + this(PKCSObjectIdentifiers.data.getId(), in, BUF_SIZ); + } + + public CMSTypedStream( + String oid, + InputStream in) + { + this(new ASN1ObjectIdentifier(oid), in, BUF_SIZ); + } + + public CMSTypedStream( + String oid, + InputStream in, + int bufSize) + { + this(new ASN1ObjectIdentifier(oid), in, bufSize); + } + + public CMSTypedStream( + ASN1ObjectIdentifier oid, + InputStream in) + { + this(oid, in, BUF_SIZ); + } + + public CMSTypedStream( + ASN1ObjectIdentifier oid, + InputStream in, + int bufSize) + { + _oid = oid; + _in = new FullReaderStream(new BufferedInputStream(in, bufSize)); + } + + public ASN1ObjectIdentifier getContentType() + { + return _oid; + } + + public InputStream getContentStream() + { + return _in; + } + + public void drain() + throws IOException + { + Streams.drain(_in); + _in.close(); + } + + private static class FullReaderStream extends FilterInputStream + { + FullReaderStream(InputStream in) + { + super(in); + } + + public int read(byte[] buf, int off, int len) throws IOException + { + int totalRead = Streams.readFully(super.in, buf, off, len); + return totalRead > 0 ? totalRead : -1; + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/CMSUtils.java b/pkix/src/main/java/org/spongycastle/cms/CMSUtils.java new file mode 100644 index 00000000..eaaadf86 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSUtils.java @@ -0,0 +1,335 @@ +package org.spongycastle.cms; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.ASN1TaggedObject; +import org.spongycastle.asn1.BEROctetStringGenerator; +import org.spongycastle.asn1.BERSet; +import org.spongycastle.asn1.DERSet; +import org.spongycastle.asn1.DERTaggedObject; +import org.spongycastle.asn1.cms.CMSObjectIdentifiers; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.cms.OtherRevocationInfoFormat; +import org.spongycastle.asn1.ocsp.OCSPResponse; +import org.spongycastle.asn1.ocsp.OCSPResponseStatus; +import org.spongycastle.cert.X509AttributeCertificateHolder; +import org.spongycastle.cert.X509CRLHolder; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.operator.DigestCalculator; +import org.spongycastle.util.Store; +import org.spongycastle.util.Strings; +import org.spongycastle.util.io.Streams; +import org.spongycastle.util.io.TeeInputStream; +import org.spongycastle.util.io.TeeOutputStream; + +class CMSUtils +{ + 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()); + } + else if (rev instanceof OtherRevocationInfoFormat) + { + OtherRevocationInfoFormat infoFormat = OtherRevocationInfoFormat.getInstance(rev); + + validateInfoFormat(infoFormat); + + crls.add(new DERTaggedObject(false, 1, infoFormat)); + } + else if (rev instanceof ASN1TaggedObject) + { + crls.add(rev); + } + } + + return crls; + } + catch (ClassCastException e) + { + throw new CMSException("error processing certs", e); + } + } + + 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; + } + + 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 + { + return ContentInfo.getInstance(in.readObject()); + } + 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); + } + } + + static byte[] getPasswordBytes(int scheme, char[] password) + { + if (scheme == PasswordRecipient.PKCS5_SCHEME2) + { + return PKCS5PasswordToBytes(password); + } + + return PKCS5PasswordToUTF8Bytes(password); + } + + /** + * converts a password to a byte array according to the scheme in + * PKCS5 (ascii, no padding) + * + * @param password a character array representing the password. + * @return a byte array representing the password. + */ + private static byte[] PKCS5PasswordToBytes( + char[] password) + { + if (password != null) + { + byte[] bytes = new byte[password.length]; + + for (int i = 0; i != bytes.length; i++) + { + bytes[i] = (byte)password[i]; + } + + return bytes; + } + else + { + return new byte[0]; + } + } + + /** + * converts a password to a byte array according to the scheme in + * PKCS5 (UTF-8, no padding) + * + * @param password a character array representing the password. + * @return a byte array representing the password. + */ + private static byte[] PKCS5PasswordToUTF8Bytes( + char[] password) + { + if (password != null) + { + return Strings.toUTF8ByteArray(password); + } + else + { + return new byte[0]; + } + } + + 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/pkix/src/main/java/org/spongycastle/cms/CMSVerifierCertificateNotValidException.java b/pkix/src/main/java/org/spongycastle/cms/CMSVerifierCertificateNotValidException.java new file mode 100644 index 00000000..bdcf131b --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/CMSVerifierCertificateNotValidException.java @@ -0,0 +1,11 @@ +package org.spongycastle.cms; + +public class CMSVerifierCertificateNotValidException + extends CMSException +{ + public CMSVerifierCertificateNotValidException( + String msg) + { + super(msg); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/DefaultAuthenticatedAttributeTableGenerator.java b/pkix/src/main/java/org/spongycastle/cms/DefaultAuthenticatedAttributeTableGenerator.java new file mode 100644 index 00000000..ab3628d5 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/DefaultAuthenticatedAttributeTableGenerator.java @@ -0,0 +1,99 @@ +package org.spongycastle.cms; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Map; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.DERSet; +import org.spongycastle.asn1.cms.Attribute; +import org.spongycastle.asn1.cms.AttributeTable; +import org.spongycastle.asn1.cms.CMSAttributes; + +/** + * Default authenticated attributes generator. + */ +public class DefaultAuthenticatedAttributeTableGenerator + implements CMSAttributeTableGenerator +{ + private final Hashtable table; + + /** + * Initialise to use all defaults + */ + public DefaultAuthenticatedAttributeTableGenerator() + { + table = new Hashtable(); + } + + /** + * Initialise with some extra attributes or overrides. + * + * @param attributeTable initial attribute table to use. + */ + public DefaultAuthenticatedAttributeTableGenerator( + 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 and messageDigest. If the constructor + * using an AttributeTable was used, entries in it for contentType 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 = new Hashtable(); + + for (Enumeration en = table.keys(); en.hasMoreElements();) + { + Object key = en.nextElement(); + + std.put(key, table.get(key)); + } + + if (!std.containsKey(CMSAttributes.contentType)) + { + ASN1ObjectIdentifier contentType = ASN1ObjectIdentifier.getInstance( + parameters.get(CMSAttributeTableGenerator.CONTENT_TYPE)); + Attribute attr = new Attribute(CMSAttributes.contentType, + new DERSet(contentType)); + 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); + } + + return std; + } + + /** + * @param parameters source parameters + * @return the populated attribute table + */ + public AttributeTable getAttributes(Map parameters) + { + return new AttributeTable(createStandardAttributeTable(parameters)); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java b/pkix/src/main/java/org/spongycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java new file mode 100644 index 00000000..1975968b --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java @@ -0,0 +1,161 @@ +package org.spongycastle.cms; + +import java.util.HashMap; +import java.util.Map; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.bsi.BSIObjectIdentifiers; +import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import org.spongycastle.asn1.eac.EACObjectIdentifiers; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.X509ObjectIdentifiers; +import org.spongycastle.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"); + addEntries(OIWObjectIdentifiers.md4WithRSA, "MD4", "RSA"); + addEntries(OIWObjectIdentifiers.md4WithRSAEncryption, "MD4", "RSA"); + addEntries(OIWObjectIdentifiers.md5WithRSA, "MD5", "RSA"); + addEntries(OIWObjectIdentifiers.sha1WithRSA, "SHA1", "RSA"); + addEntries(PKCSObjectIdentifiers.md2WithRSAEncryption, "MD2", "RSA"); + addEntries(PKCSObjectIdentifiers.md4WithRSAEncryption, "MD4", "RSA"); + 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"); + 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"); + + 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"); + 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"); + 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"); + 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"); + } + + /** + * 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) + { + return getDigestAlgName(digestAlg.getAlgorithm()) + "with" + getEncryptionAlgName(encryptionAlg.getAlgorithm()); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java b/pkix/src/main/java/org/spongycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java new file mode 100644 index 00000000..4608bb10 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java @@ -0,0 +1,46 @@ +package org.spongycastle.cms; + +import java.util.HashSet; +import java.util.Set; + +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +public class DefaultCMSSignatureEncryptionAlgorithmFinder + implements CMSSignatureEncryptionAlgorithmFinder +{ + private static final Set RSA_PKCS1d5 = new HashSet(); + + static + { + RSA_PKCS1d5.add(PKCSObjectIdentifiers.md2WithRSAEncryption); + RSA_PKCS1d5.add(PKCSObjectIdentifiers.md4WithRSAEncryption); + RSA_PKCS1d5.add(PKCSObjectIdentifiers.md5WithRSAEncryption); + RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha1WithRSAEncryption); + RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha224WithRSAEncryption); + RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha256WithRSAEncryption); + RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha384WithRSAEncryption); + RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha512WithRSAEncryption); + RSA_PKCS1d5.add(OIWObjectIdentifiers.md4WithRSAEncryption); + RSA_PKCS1d5.add(OIWObjectIdentifiers.md4WithRSA); + RSA_PKCS1d5.add(OIWObjectIdentifiers.md5WithRSA); + RSA_PKCS1d5.add(OIWObjectIdentifiers.sha1WithRSA); + RSA_PKCS1d5.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128); + RSA_PKCS1d5.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160); + RSA_PKCS1d5.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256); + } + + public AlgorithmIdentifier findEncryptionAlgorithm(AlgorithmIdentifier signatureAlgorithm) + { + // RFC3370 section 3.2 + if (RSA_PKCS1d5.contains(signatureAlgorithm.getAlgorithm())) + { + return new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE); + } + + return signatureAlgorithm; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/DefaultSignedAttributeTableGenerator.java b/pkix/src/main/java/org/spongycastle/cms/DefaultSignedAttributeTableGenerator.java new file mode 100644 index 00000000..ba570c28 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/DefaultSignedAttributeTableGenerator.java @@ -0,0 +1,121 @@ +package org.spongycastle.cms; + +import java.util.Date; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Map; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.DERSet; +import org.spongycastle.asn1.cms.Attribute; +import org.spongycastle.asn1.cms.AttributeTable; +import org.spongycastle.asn1.cms.CMSAttributes; +import org.spongycastle.asn1.cms.Time; + +/** + * 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, and messageDigest. 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); + } + + 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/pkix/src/main/java/org/spongycastle/cms/KEKRecipient.java b/pkix/src/main/java/org/spongycastle/cms/KEKRecipient.java new file mode 100644 index 00000000..3b14a89d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/KEKRecipient.java @@ -0,0 +1,10 @@ +package org.spongycastle.cms; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +public interface KEKRecipient + extends Recipient +{ + RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncAlg, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentKey) + throws CMSException; +} diff --git a/pkix/src/main/java/org/spongycastle/cms/KEKRecipientId.java b/pkix/src/main/java/org/spongycastle/cms/KEKRecipientId.java new file mode 100644 index 00000000..2025c7c1 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/KEKRecipientId.java @@ -0,0 +1,63 @@ +package org.spongycastle.cms; + +import org.spongycastle.util.Arrays; + +public class KEKRecipientId + extends RecipientId +{ + private byte[] keyIdentifier; + + /** + * Construct a recipient ID with the key identifier of a KEK recipient. + * + * @param keyIdentifier a subjectKeyId + */ + public KEKRecipientId(byte[] keyIdentifier) + { + super(kek); + + this.keyIdentifier = keyIdentifier; + } + + public int hashCode() + { + return Arrays.hashCode(keyIdentifier); + } + + public boolean equals( + Object o) + { + if (!(o instanceof KEKRecipientId)) + { + return false; + } + + KEKRecipientId id = (KEKRecipientId)o; + + return Arrays.areEqual(keyIdentifier, id.keyIdentifier); + } + + public byte[] getKeyIdentifier() + { + return Arrays.clone(keyIdentifier); + } + + public Object clone() + { + return new KEKRecipientId(keyIdentifier); + } + + public boolean match(Object obj) + { + if (obj instanceof byte[]) + { + return Arrays.areEqual(keyIdentifier, (byte[])obj); + } + else if (obj instanceof KEKRecipientInformation) + { + return ((KEKRecipientInformation)obj).getRID().equals(this); + } + + return false; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/KEKRecipientInfoGenerator.java b/pkix/src/main/java/org/spongycastle/cms/KEKRecipientInfoGenerator.java new file mode 100644 index 00000000..480fb5fe --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/KEKRecipientInfoGenerator.java @@ -0,0 +1,39 @@ +package org.spongycastle.cms; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.cms.KEKIdentifier; +import org.spongycastle.asn1.cms.KEKRecipientInfo; +import org.spongycastle.asn1.cms.RecipientInfo; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.OperatorException; +import org.spongycastle.operator.SymmetricKeyWrapper; + +public abstract class KEKRecipientInfoGenerator + implements RecipientInfoGenerator +{ + private final KEKIdentifier kekIdentifier; + + protected final SymmetricKeyWrapper wrapper; + + protected KEKRecipientInfoGenerator(KEKIdentifier kekIdentifier, SymmetricKeyWrapper wrapper) + { + this.kekIdentifier = kekIdentifier; + this.wrapper = wrapper; + } + + public final RecipientInfo generate(GenericKey contentEncryptionKey) + throws CMSException + { + try + { + ASN1OctetString encryptedKey = new DEROctetString(wrapper.generateWrappedKey(contentEncryptionKey)); + + return new RecipientInfo(new KEKRecipientInfo(kekIdentifier, wrapper.getAlgorithmIdentifier(), encryptedKey)); + } + catch (OperatorException e) + { + throw new CMSException("exception wrapping content key: " + e.getMessage(), e); + } + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cms/KEKRecipientInformation.java b/pkix/src/main/java/org/spongycastle/cms/KEKRecipientInformation.java new file mode 100644 index 00000000..3388d6fa --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/KEKRecipientInformation.java @@ -0,0 +1,38 @@ +package org.spongycastle.cms; + +import java.io.IOException; + +import org.spongycastle.asn1.cms.KEKIdentifier; +import org.spongycastle.asn1.cms.KEKRecipientInfo; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +/** + * the RecipientInfo class for a recipient who has been sent a message + * encrypted using a secret key known to the other side. + */ +public class KEKRecipientInformation + extends RecipientInformation +{ + private KEKRecipientInfo info; + + KEKRecipientInformation( + KEKRecipientInfo info, + AlgorithmIdentifier messageAlgorithm, + CMSSecureReadable secureReadable, + AuthAttributesProvider additionalData) + { + super(info.getKeyEncryptionAlgorithm(), messageAlgorithm, secureReadable, additionalData); + + this.info = info; + + KEKIdentifier kekId = info.getKekid(); + + this.rid = new KEKRecipientId(kekId.getKeyIdentifier().getOctets()); + } + + protected RecipientOperator getRecipientOperator(Recipient recipient) + throws CMSException, IOException + { + return ((KEKRecipient)recipient).getRecipientOperator(keyEncAlg, messageAlgorithm, info.getEncryptedKey().getOctets()); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipient.java b/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipient.java new file mode 100644 index 00000000..ab3a7451 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipient.java @@ -0,0 +1,14 @@ +package org.spongycastle.cms; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; + +public interface KeyAgreeRecipient + extends Recipient +{ + RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncAlg, AlgorithmIdentifier contentEncryptionAlgorithm, SubjectPublicKeyInfo senderPublicKey, ASN1OctetString userKeyingMaterial, byte[] encryptedContentKey) + throws CMSException; + + AlgorithmIdentifier getPrivateKeyAlgorithmIdentifier(); +} diff --git a/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipientId.java b/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipientId.java new file mode 100644 index 00000000..c5f2aa14 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipientId.java @@ -0,0 +1,89 @@ +package org.spongycastle.cms; + +import java.math.BigInteger; + +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.cert.selector.X509CertificateHolderSelector; + +public class KeyAgreeRecipientId + extends RecipientId +{ + private X509CertificateHolderSelector baseSelector; + + private KeyAgreeRecipientId(X509CertificateHolderSelector baseSelector) + { + super(keyAgree); + + this.baseSelector = baseSelector; + } + + /** + * Construct a key agree recipient ID with the value of a public key's subjectKeyId. + * + * @param subjectKeyId a subjectKeyId + */ + public KeyAgreeRecipientId(byte[] subjectKeyId) + { + this(null, null, subjectKeyId); + } + + /** + * Construct a key agree recipient ID based on the issuer and serial number of the recipient's associated + * certificate. + * + * @param issuer the issuer of the recipient's associated certificate. + * @param serialNumber the serial number of the recipient's associated certificate. + */ + public KeyAgreeRecipientId(X500Name issuer, BigInteger serialNumber) + { + this(issuer, serialNumber, null); + } + + public KeyAgreeRecipientId(X500Name issuer, BigInteger serialNumber, byte[] subjectKeyId) + { + this(new X509CertificateHolderSelector(issuer, serialNumber, subjectKeyId)); + } + + 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 KeyAgreeRecipientId)) + { + return false; + } + + KeyAgreeRecipientId id = (KeyAgreeRecipientId)o; + + return this.baseSelector.equals(id.baseSelector); + } + + public Object clone() + { + return new KeyAgreeRecipientId(baseSelector); + } + + public boolean match(Object obj) + { + if (obj instanceof KeyAgreeRecipientInformation) + { + return ((KeyAgreeRecipientInformation)obj).getRID().equals(this); + } + + return baseSelector.match(obj); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipientInfoGenerator.java b/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipientInfoGenerator.java new file mode 100644 index 00000000..b80ec375 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipientInfoGenerator.java @@ -0,0 +1,80 @@ +package org.spongycastle.cms; + +import java.io.IOException; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.cms.KeyAgreeRecipientInfo; +import org.spongycastle.asn1.cms.OriginatorIdentifierOrKey; +import org.spongycastle.asn1.cms.OriginatorPublicKey; +import org.spongycastle.asn1.cms.RecipientInfo; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.operator.GenericKey; + +public abstract class KeyAgreeRecipientInfoGenerator + implements RecipientInfoGenerator +{ + private ASN1ObjectIdentifier keyAgreementOID; + private ASN1ObjectIdentifier keyEncryptionOID; + private SubjectPublicKeyInfo originatorKeyInfo; + + protected KeyAgreeRecipientInfoGenerator(ASN1ObjectIdentifier keyAgreementOID, SubjectPublicKeyInfo originatorKeyInfo, ASN1ObjectIdentifier keyEncryptionOID) + { + this.originatorKeyInfo = originatorKeyInfo; + this.keyAgreementOID = keyAgreementOID; + this.keyEncryptionOID = keyEncryptionOID; + } + + public RecipientInfo generate(GenericKey contentEncryptionKey) + throws CMSException + { + OriginatorIdentifierOrKey originator = new OriginatorIdentifierOrKey( + createOriginatorPublicKey(originatorKeyInfo)); + + ASN1EncodableVector params = new ASN1EncodableVector(); + params.add(keyEncryptionOID); + params.add(DERNull.INSTANCE); + AlgorithmIdentifier keyEncAlg = new AlgorithmIdentifier(keyEncryptionOID, DERNull.INSTANCE); + AlgorithmIdentifier keyAgreeAlg = new AlgorithmIdentifier(keyAgreementOID, keyEncAlg); + + ASN1Sequence recipients = generateRecipientEncryptedKeys(keyAgreeAlg, keyEncAlg, contentEncryptionKey); + ASN1Encodable userKeyingMaterial = getUserKeyingMaterial(keyAgreeAlg); + + if (userKeyingMaterial != null) + { + try + { + return new RecipientInfo(new KeyAgreeRecipientInfo(originator, new DEROctetString(userKeyingMaterial), + keyAgreeAlg, recipients)); + } + catch (IOException e) + { + throw new CMSException("unable to encode userKeyingMaterial: " + e.getMessage(), e); + } + } + else + { + return new RecipientInfo(new KeyAgreeRecipientInfo(originator, null, + keyAgreeAlg, recipients)); + } + } + + protected OriginatorPublicKey createOriginatorPublicKey(SubjectPublicKeyInfo originatorKeyInfo) + { + return new OriginatorPublicKey( + new AlgorithmIdentifier(originatorKeyInfo.getAlgorithm().getAlgorithm(), DERNull.INSTANCE), + originatorKeyInfo.getPublicKeyData().getBytes()); + } + + protected abstract ASN1Sequence generateRecipientEncryptedKeys(AlgorithmIdentifier keyAgreeAlgorithm, AlgorithmIdentifier keyEncAlgorithm, GenericKey contentEncryptionKey) + throws CMSException; + + protected abstract ASN1Encodable getUserKeyingMaterial(AlgorithmIdentifier keyAgreeAlgorithm) + throws CMSException; + +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipientInformation.java b/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipientInformation.java new file mode 100644 index 00000000..c00dcdf3 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipientInformation.java @@ -0,0 +1,131 @@ +package org.spongycastle.cms; + +import java.io.IOException; +import java.util.List; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.cms.IssuerAndSerialNumber; +import org.spongycastle.asn1.cms.KeyAgreeRecipientIdentifier; +import org.spongycastle.asn1.cms.KeyAgreeRecipientInfo; +import org.spongycastle.asn1.cms.OriginatorIdentifierOrKey; +import org.spongycastle.asn1.cms.OriginatorPublicKey; +import org.spongycastle.asn1.cms.RecipientEncryptedKey; +import org.spongycastle.asn1.cms.RecipientKeyIdentifier; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectKeyIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; + +/** + * the RecipientInfo class for a recipient who has been sent a message + * encrypted using key agreement. + */ +public class KeyAgreeRecipientInformation + extends RecipientInformation +{ + private KeyAgreeRecipientInfo info; + private ASN1OctetString encryptedKey; + + static void readRecipientInfo(List infos, KeyAgreeRecipientInfo info, + AlgorithmIdentifier messageAlgorithm, CMSSecureReadable secureReadable, AuthAttributesProvider additionalData) + { + ASN1Sequence s = info.getRecipientEncryptedKeys(); + + for (int i = 0; i < s.size(); ++i) + { + RecipientEncryptedKey id = RecipientEncryptedKey.getInstance( + s.getObjectAt(i)); + + RecipientId rid; + + KeyAgreeRecipientIdentifier karid = id.getIdentifier(); + IssuerAndSerialNumber iAndSN = karid.getIssuerAndSerialNumber(); + + if (iAndSN != null) + { + rid = new KeyAgreeRecipientId(iAndSN.getName(), iAndSN.getSerialNumber().getValue()); + } + else + { + RecipientKeyIdentifier rKeyID = karid.getRKeyID(); + + // Note: 'date' and 'other' fields of RecipientKeyIdentifier appear to be only informational + + rid = new KeyAgreeRecipientId(rKeyID.getSubjectKeyIdentifier().getOctets()); + } + + infos.add(new KeyAgreeRecipientInformation(info, rid, id.getEncryptedKey(), messageAlgorithm, + secureReadable, additionalData)); + } + } + + KeyAgreeRecipientInformation( + KeyAgreeRecipientInfo info, + RecipientId rid, + ASN1OctetString encryptedKey, + AlgorithmIdentifier messageAlgorithm, + CMSSecureReadable secureReadable, + AuthAttributesProvider additionalData) + { + super(info.getKeyEncryptionAlgorithm(), messageAlgorithm, secureReadable, additionalData); + + this.info = info; + this.rid = rid; + this.encryptedKey = encryptedKey; + } + + private SubjectPublicKeyInfo getSenderPublicKeyInfo(AlgorithmIdentifier recKeyAlgId, + OriginatorIdentifierOrKey originator) + throws CMSException, IOException + { + OriginatorPublicKey opk = originator.getOriginatorKey(); + if (opk != null) + { + return getPublicKeyInfoFromOriginatorPublicKey(recKeyAlgId, opk); + } + + OriginatorId origID; + + IssuerAndSerialNumber iAndSN = originator.getIssuerAndSerialNumber(); + if (iAndSN != null) + { + origID = new OriginatorId(iAndSN.getName(), iAndSN.getSerialNumber().getValue()); + } + else + { + SubjectKeyIdentifier ski = originator.getSubjectKeyIdentifier(); + + origID = new OriginatorId(ski.getKeyIdentifier()); + } + + return getPublicKeyInfoFromOriginatorId(origID); + } + + private SubjectPublicKeyInfo getPublicKeyInfoFromOriginatorPublicKey(AlgorithmIdentifier recKeyAlgId, + OriginatorPublicKey originatorPublicKey) + { + SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo( + recKeyAlgId, + originatorPublicKey.getPublicKey().getBytes()); + + return pubInfo; + } + + private SubjectPublicKeyInfo getPublicKeyInfoFromOriginatorId(OriginatorId origID) + throws CMSException + { + // TODO Support all alternatives for OriginatorIdentifierOrKey + // see RFC 3852 6.2.2 + throw new CMSException("No support for 'originator' as IssuerAndSerialNumber or SubjectKeyIdentifier"); + } + + protected RecipientOperator getRecipientOperator(Recipient recipient) + throws CMSException, IOException + { + KeyAgreeRecipient agreeRecipient = (KeyAgreeRecipient)recipient; + AlgorithmIdentifier recKeyAlgId = agreeRecipient.getPrivateKeyAlgorithmIdentifier(); + + return ((KeyAgreeRecipient)recipient).getRecipientOperator(keyEncAlg, messageAlgorithm, getSenderPublicKeyInfo(recKeyAlgId, + info.getOriginator()), info.getUserKeyingMaterial(), encryptedKey.getOctets()); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipient.java b/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipient.java new file mode 100644 index 00000000..04201d0d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipient.java @@ -0,0 +1,10 @@ +package org.spongycastle.cms; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +public interface KeyTransRecipient + extends Recipient +{ + RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncAlg, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentKey) + throws CMSException; +} diff --git a/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipientId.java b/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipientId.java new file mode 100644 index 00000000..b76e19f4 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipientId.java @@ -0,0 +1,102 @@ +package org.spongycastle.cms; + +import java.math.BigInteger; + +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.cert.selector.X509CertificateHolderSelector; + +public class KeyTransRecipientId + extends RecipientId +{ + private X509CertificateHolderSelector baseSelector; + + private KeyTransRecipientId(X509CertificateHolderSelector baseSelector) + { + super(keyTrans); + + this.baseSelector = baseSelector; + } + + /** + * Construct a key trans recipient ID with the value of a public key's subjectKeyId. + * + * @param subjectKeyId a subjectKeyId + */ + public KeyTransRecipientId(byte[] subjectKeyId) + { + this(null, null, subjectKeyId); + } + + /** + * Construct a key trans recipient ID based on the issuer and serial number of the recipient's associated + * certificate. + * + * @param issuer the issuer of the recipient's associated certificate. + * @param serialNumber the serial number of the recipient's associated certificate. + */ + public KeyTransRecipientId(X500Name issuer, BigInteger serialNumber) + { + this(issuer, serialNumber, null); + } + + /** + * Construct a key trans recipient ID based on the issuer and serial number of the recipient's associated + * certificate. + * + * @param issuer the issuer of the recipient's associated certificate. + * @param serialNumber the serial number of the recipient's associated certificate. + * @param subjectKeyId the subject key identifier to use to match the recipients associated certificate. + */ + public KeyTransRecipientId(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 KeyTransRecipientId)) + { + return false; + } + + KeyTransRecipientId id = (KeyTransRecipientId)o; + + return this.baseSelector.equals(id.baseSelector); + } + + public Object clone() + { + return new KeyTransRecipientId(this.baseSelector); + } + + public boolean match(Object obj) + { + if (obj instanceof KeyTransRecipientInformation) + { + return ((KeyTransRecipientInformation)obj).getRID().equals(this); + } + + return baseSelector.match(obj); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipientInfoGenerator.java b/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipientInfoGenerator.java new file mode 100644 index 00000000..c78a4ff8 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipientInfoGenerator.java @@ -0,0 +1,58 @@ +package org.spongycastle.cms; + +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.cms.IssuerAndSerialNumber; +import org.spongycastle.asn1.cms.KeyTransRecipientInfo; +import org.spongycastle.asn1.cms.RecipientIdentifier; +import org.spongycastle.asn1.cms.RecipientInfo; +import org.spongycastle.operator.AsymmetricKeyWrapper; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.OperatorException; + +public abstract class KeyTransRecipientInfoGenerator + implements RecipientInfoGenerator +{ + protected final AsymmetricKeyWrapper wrapper; + + private IssuerAndSerialNumber issuerAndSerial; + private byte[] subjectKeyIdentifier; + + protected KeyTransRecipientInfoGenerator(IssuerAndSerialNumber issuerAndSerial, AsymmetricKeyWrapper wrapper) + { + this.issuerAndSerial = issuerAndSerial; + this.wrapper = wrapper; + } + + protected KeyTransRecipientInfoGenerator(byte[] subjectKeyIdentifier, AsymmetricKeyWrapper wrapper) + { + this.subjectKeyIdentifier = subjectKeyIdentifier; + this.wrapper = wrapper; + } + + public final RecipientInfo generate(GenericKey contentEncryptionKey) + throws CMSException + { + byte[] encryptedKeyBytes; + try + { + encryptedKeyBytes = wrapper.generateWrappedKey(contentEncryptionKey); + } + catch (OperatorException e) + { + throw new CMSException("exception wrapping content key: " + e.getMessage(), e); + } + + RecipientIdentifier recipId; + if (issuerAndSerial != null) + { + recipId = new RecipientIdentifier(issuerAndSerial); + } + else + { + recipId = new RecipientIdentifier(new DEROctetString(subjectKeyIdentifier)); + } + + return new RecipientInfo(new KeyTransRecipientInfo(recipId, wrapper.getAlgorithmIdentifier(), + new DEROctetString(encryptedKeyBytes))); + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipientInformation.java b/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipientInformation.java new file mode 100644 index 00000000..f671b8cd --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipientInformation.java @@ -0,0 +1,50 @@ +package org.spongycastle.cms; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.cms.IssuerAndSerialNumber; +import org.spongycastle.asn1.cms.KeyTransRecipientInfo; +import org.spongycastle.asn1.cms.RecipientIdentifier; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +/** + * the KeyTransRecipientInformation class for a recipient who has been sent a secret + * key encrypted using their public key that needs to be used to + * extract the message. + */ +public class KeyTransRecipientInformation + extends RecipientInformation +{ + private KeyTransRecipientInfo info; + + KeyTransRecipientInformation( + KeyTransRecipientInfo info, + AlgorithmIdentifier messageAlgorithm, + CMSSecureReadable secureReadable, + AuthAttributesProvider additionalData) + { + super(info.getKeyEncryptionAlgorithm(), messageAlgorithm, secureReadable, additionalData); + + this.info = info; + + RecipientIdentifier r = info.getRecipientIdentifier(); + + if (r.isTagged()) + { + ASN1OctetString octs = ASN1OctetString.getInstance(r.getId()); + + rid = new KeyTransRecipientId(octs.getOctets()); + } + else + { + IssuerAndSerialNumber iAnds = IssuerAndSerialNumber.getInstance(r.getId()); + + rid = new KeyTransRecipientId(iAnds.getName(), iAnds.getSerialNumber().getValue()); + } + } + + protected RecipientOperator getRecipientOperator(Recipient recipient) + throws CMSException + { + return ((KeyTransRecipient)recipient).getRecipientOperator(keyEncAlg, messageAlgorithm, info.getEncryptedKey().getOctets()); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/NullOutputStream.java b/pkix/src/main/java/org/spongycastle/cms/NullOutputStream.java new file mode 100644 index 00000000..c5ccd4ec --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/NullOutputStream.java @@ -0,0 +1,28 @@ +/** + * + */ +package org.spongycastle.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/pkix/src/main/java/org/spongycastle/cms/OriginatorId.java b/pkix/src/main/java/org/spongycastle/cms/OriginatorId.java new file mode 100644 index 00000000..eee06cea --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/OriginatorId.java @@ -0,0 +1,118 @@ +package org.spongycastle.cms; + +import java.math.BigInteger; + +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.Selector; + +/** + * a basic index for an originator. + */ +class OriginatorId + implements Selector +{ + private byte[] subjectKeyId; + + private X500Name issuer; + private BigInteger serialNumber; + + /** + * Construct a signer ID with the value of a public key's subjectKeyId. + * + * @param subjectKeyId a subjectKeyId + */ + public OriginatorId(byte[] subjectKeyId) + { + setSubjectKeyID(subjectKeyId); + } + + private void setSubjectKeyID(byte[] subjectKeyId) + { + this.subjectKeyId = 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 OriginatorId(X500Name issuer, BigInteger serialNumber) + { + setIssuerAndSerial(issuer, serialNumber); + } + + private void setIssuerAndSerial(X500Name issuer, BigInteger serialNumber) + { + this.issuer = issuer; + this.serialNumber = serialNumber; + } + + /** + * 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 OriginatorId(X500Name issuer, BigInteger serialNumber, byte[] subjectKeyId) + { + setIssuerAndSerial(issuer, serialNumber); + setSubjectKeyID(subjectKeyId); + } + + public X500Name getIssuer() + { + return issuer; + } + + public Object clone() + { + return new OriginatorId(this.issuer, this.serialNumber, this.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 OriginatorId)) + { + return false; + } + + OriginatorId id = (OriginatorId)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) + { + return false; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/OriginatorInfoGenerator.java b/pkix/src/main/java/org/spongycastle/cms/OriginatorInfoGenerator.java new file mode 100644 index 00000000..fd70ab52 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/OriginatorInfoGenerator.java @@ -0,0 +1,54 @@ +package org.spongycastle.cms; + +import java.util.ArrayList; +import java.util.List; + +import org.spongycastle.asn1.cms.OriginatorInfo; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.util.Store; + +public class OriginatorInfoGenerator +{ + private final List origCerts; + private final List origCRLs; + + public OriginatorInfoGenerator(X509CertificateHolder origCert) + { + this.origCerts = new ArrayList(1); + this.origCRLs = null; + origCerts.add(origCert.toASN1Structure()); + } + + public OriginatorInfoGenerator(Store origCerts) + throws CMSException + { + this(origCerts, null); + } + + public OriginatorInfoGenerator(Store origCerts, Store origCRLs) + throws CMSException + { + this.origCerts = CMSUtils.getCertificatesFromStore(origCerts); + + if (origCRLs != null) + { + this.origCRLs = CMSUtils.getCRLsFromStore(origCRLs); + } + else + { + this.origCRLs = null; + } + } + + public OriginatorInformation generate() + { + if (origCRLs != null) + { + return new OriginatorInformation(new OriginatorInfo(CMSUtils.createDerSetFromList(origCerts), CMSUtils.createDerSetFromList(origCRLs))); + } + else + { + return new OriginatorInformation(new OriginatorInfo(CMSUtils.createDerSetFromList(origCerts), null)); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/OriginatorInformation.java b/pkix/src/main/java/org/spongycastle/cms/OriginatorInformation.java new file mode 100644 index 00000000..4db9a10a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/OriginatorInformation.java @@ -0,0 +1,95 @@ +package org.spongycastle.cms; + +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.cms.OriginatorInfo; +import org.spongycastle.asn1.x509.Certificate; +import org.spongycastle.asn1.x509.CertificateList; +import org.spongycastle.cert.X509CRLHolder; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.util.CollectionStore; +import org.spongycastle.util.Store; + +public class OriginatorInformation +{ + private OriginatorInfo originatorInfo; + + OriginatorInformation(OriginatorInfo originatorInfo) + { + this.originatorInfo = originatorInfo; + } + + /** + * Return the certificates stored in the underlying OriginatorInfo object. + * + * @return a Store of X509CertificateHolder objects. + */ + public Store getCertificates() + { + ASN1Set certSet = originatorInfo.getCertificates(); + + 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()); + } + + /** + * Return the CRLs stored in the underlying OriginatorInfo object. + * + * @return a Store of X509CRLHolder objects. + */ + public Store getCRLs() + { + ASN1Set crlSet = originatorInfo.getCRLs(); + + 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()); + } + + /** + * Return the underlying ASN.1 object defining this SignerInformation object. + * + * @return a OriginatorInfo. + */ + public OriginatorInfo toASN1Structure() + { + return originatorInfo; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/PasswordRecipient.java b/pkix/src/main/java/org/spongycastle/cms/PasswordRecipient.java new file mode 100644 index 00000000..616f25ca --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/PasswordRecipient.java @@ -0,0 +1,20 @@ +package org.spongycastle.cms; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +public interface PasswordRecipient + extends Recipient +{ + public static final int PKCS5_SCHEME2 = 0; + public static final int PKCS5_SCHEME2_UTF8 = 1; + + byte[] calculateDerivedKey(byte[] encodedPassword, 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/pkix/src/main/java/org/spongycastle/cms/PasswordRecipientId.java b/pkix/src/main/java/org/spongycastle/cms/PasswordRecipientId.java new file mode 100644 index 00000000..d3efe2f5 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/PasswordRecipientId.java @@ -0,0 +1,44 @@ +package org.spongycastle.cms; + +public class PasswordRecipientId + extends RecipientId +{ + /** + * Construct a recipient ID of the password type. + */ + public PasswordRecipientId() + { + super(password); + } + + public int hashCode() + { + return password; + } + + public boolean equals( + Object o) + { + if (!(o instanceof PasswordRecipientId)) + { + return false; + } + + return true; + } + + public Object clone() + { + return new PasswordRecipientId(); + } + + public boolean match(Object obj) + { + if (obj instanceof PasswordRecipientInformation) + { + return true; + } + + return false; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/PasswordRecipientInfoGenerator.java b/pkix/src/main/java/org/spongycastle/cms/PasswordRecipientInfoGenerator.java new file mode 100644 index 00000000..33c34b7a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/PasswordRecipientInfoGenerator.java @@ -0,0 +1,122 @@ +package org.spongycastle.cms; + +import java.security.SecureRandom; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.cms.PasswordRecipientInfo; +import org.spongycastle.asn1.cms.RecipientInfo; +import org.spongycastle.asn1.pkcs.PBKDF2Params; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.operator.GenericKey; + +public abstract class PasswordRecipientInfoGenerator + implements RecipientInfoGenerator +{ + private char[] password; + private AlgorithmIdentifier keyDerivationAlgorithm; + private ASN1ObjectIdentifier kekAlgorithm; + private SecureRandom random; + private int schemeID; + private int keySize; + private int blockSize; + + protected PasswordRecipientInfoGenerator(ASN1ObjectIdentifier kekAlgorithm, char[] password) + { + this(kekAlgorithm, password, getKeySize(kekAlgorithm), ((Integer)PasswordRecipientInformation.BLOCKSIZES.get(kekAlgorithm)).intValue()); + } + + protected PasswordRecipientInfoGenerator(ASN1ObjectIdentifier kekAlgorithm, char[] password, int keySize, int blockSize) + { + this.password = password; + this.schemeID = PasswordRecipient.PKCS5_SCHEME2_UTF8; + this.kekAlgorithm = kekAlgorithm; + this.keySize = keySize; + this.blockSize = blockSize; + } + + private static int getKeySize(ASN1ObjectIdentifier kekAlgorithm) + { + Integer size = (Integer)PasswordRecipientInformation.KEYSIZES.get(kekAlgorithm); + + if (size == null) + { + throw new IllegalArgumentException("cannot find key size for algorithm: " + kekAlgorithm); + } + + return size.intValue(); + } + + public PasswordRecipientInfoGenerator setPasswordConversionScheme(int schemeID) + { + this.schemeID = schemeID; + + return this; + } + + public PasswordRecipientInfoGenerator setSaltAndIterationCount(byte[] salt, int iterationCount) + { + this.keyDerivationAlgorithm = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(salt, iterationCount)); + + return this; + } + + public PasswordRecipientInfoGenerator setSecureRandom(SecureRandom random) + { + this.random = random; + + return this; + } + + public RecipientInfo generate(GenericKey contentEncryptionKey) + throws CMSException + { + byte[] iv = new byte[blockSize]; /// TODO: set IV size properly! + + if (random == null) + { + random = new SecureRandom(); + } + + random.nextBytes(iv); + + if (keyDerivationAlgorithm == null) + { + byte[] salt = new byte[20]; + + random.nextBytes(salt); + + keyDerivationAlgorithm = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(salt, 1024)); + } + + byte[] encodedPassword = CMSUtils.getPasswordBytes(schemeID, password); + + byte[] derivedKey = calculateDerivedKey(encodedPassword, keyDerivationAlgorithm, keySize); + + AlgorithmIdentifier kekAlgorithmId = new AlgorithmIdentifier(kekAlgorithm, new DEROctetString(iv)); + + byte[] encryptedKeyBytes = generateEncryptedBytes(kekAlgorithmId, derivedKey, contentEncryptionKey); + + ASN1OctetString encryptedKey = new DEROctetString(encryptedKeyBytes); + + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(kekAlgorithm); + v.add(new DEROctetString(iv)); + + AlgorithmIdentifier keyEncryptionAlgorithm = new AlgorithmIdentifier( + PKCSObjectIdentifiers.id_alg_PWRI_KEK, new DERSequence(v)); + + return new RecipientInfo(new PasswordRecipientInfo(keyDerivationAlgorithm, + keyEncryptionAlgorithm, encryptedKey)); + } + + protected abstract byte[] calculateDerivedKey(byte[] encodedPassword, AlgorithmIdentifier derivationAlgorithm, int keySize) + throws CMSException; + + protected abstract byte[] generateEncryptedBytes(AlgorithmIdentifier algorithm, byte[] derivedKey, GenericKey contentEncryptionKey) + throws CMSException; +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cms/PasswordRecipientInformation.java b/pkix/src/main/java/org/spongycastle/cms/PasswordRecipientInformation.java new file mode 100644 index 00000000..2c9efbac --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/PasswordRecipientInformation.java @@ -0,0 +1,116 @@ +package org.spongycastle.cms; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.cms.PasswordRecipientInfo; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.util.Integers; + +/** + * the RecipientInfo class for a recipient who has been sent a message + * encrypted using a password. + */ +public class PasswordRecipientInformation + extends RecipientInformation +{ + static Map KEYSIZES = new HashMap(); + static Map BLOCKSIZES = new HashMap(); + + static + { + BLOCKSIZES.put(CMSAlgorithm.DES_EDE3_CBC, Integers.valueOf(8)); + BLOCKSIZES.put(CMSAlgorithm.AES128_CBC, Integers.valueOf(16)); + BLOCKSIZES.put(CMSAlgorithm.AES192_CBC, Integers.valueOf(16)); + BLOCKSIZES.put(CMSAlgorithm.AES256_CBC, Integers.valueOf(16)); + + KEYSIZES.put(CMSAlgorithm.DES_EDE3_CBC, Integers.valueOf(192)); + KEYSIZES.put(CMSAlgorithm.AES128_CBC, Integers.valueOf(128)); + KEYSIZES.put(CMSAlgorithm.AES192_CBC, Integers.valueOf(192)); + KEYSIZES.put(CMSAlgorithm.AES256_CBC, Integers.valueOf(256)); + } + + private PasswordRecipientInfo info; + + PasswordRecipientInformation( + PasswordRecipientInfo info, + AlgorithmIdentifier messageAlgorithm, + CMSSecureReadable secureReadable, + AuthAttributesProvider additionalData) + { + super(info.getKeyEncryptionAlgorithm(), messageAlgorithm, secureReadable, additionalData); + + this.info = info; + this.rid = new PasswordRecipientId(); + } + + /** + * return the object identifier for the key derivation algorithm, or null + * if there is none present. + * + * @return OID for key derivation algorithm, if present. + */ + public String getKeyDerivationAlgOID() + { + if (info.getKeyDerivationAlgorithm() != null) + { + return info.getKeyDerivationAlgorithm().getAlgorithm().getId(); + } + + return null; + } + + /** + * return the ASN.1 encoded key derivation algorithm parameters, or null if + * there aren't any. + * @return ASN.1 encoding of key derivation algorithm parameters. + */ + public byte[] getKeyDerivationAlgParams() + { + try + { + if (info.getKeyDerivationAlgorithm() != null) + { + ASN1Encodable params = info.getKeyDerivationAlgorithm().getParameters(); + if (params != null) + { + return params.toASN1Primitive().getEncoded(); + } + } + + return null; + } + catch (Exception e) + { + throw new RuntimeException("exception getting encryption parameters " + e); + } + } + + /** + * Return the key derivation algorithm details for the key in this recipient. + * + * @return AlgorithmIdentifier representing the key derivation algorithm. + */ + public AlgorithmIdentifier getKeyDerivationAlgorithm() + { + return info.getKeyDerivationAlgorithm(); + } + + protected RecipientOperator getRecipientOperator(Recipient recipient) + throws CMSException, IOException + { + PasswordRecipient pbeRecipient = (PasswordRecipient)recipient; + AlgorithmIdentifier kekAlg = AlgorithmIdentifier.getInstance(info.getKeyEncryptionAlgorithm()); + AlgorithmIdentifier kekAlgParams = AlgorithmIdentifier.getInstance(kekAlg.getParameters()); + + byte[] passwordBytes = CMSUtils.getPasswordBytes(pbeRecipient.getPasswordConversionScheme(), pbeRecipient.getPassword()); + + int keySize = ((Integer)KEYSIZES.get(kekAlgParams.getAlgorithm())).intValue(); + + byte[] derivedKey = pbeRecipient.calculateDerivedKey(passwordBytes, this.getKeyDerivationAlgorithm(), keySize); + + return pbeRecipient.getRecipientOperator(kekAlgParams, messageAlgorithm, derivedKey, info.getEncryptedKey().getOctets()); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/Recipient.java b/pkix/src/main/java/org/spongycastle/cms/Recipient.java new file mode 100644 index 00000000..17a3e4f8 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/Recipient.java @@ -0,0 +1,5 @@ +package org.spongycastle.cms; + +public interface Recipient +{ +} diff --git a/pkix/src/main/java/org/spongycastle/cms/RecipientId.java b/pkix/src/main/java/org/spongycastle/cms/RecipientId.java new file mode 100644 index 00000000..78a4bc22 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/RecipientId.java @@ -0,0 +1,31 @@ +package org.spongycastle.cms; + +import org.spongycastle.util.Selector; + +public abstract class RecipientId + implements Selector +{ + public static final int keyTrans = 0; + public static final int kek = 1; + public static final int keyAgree = 2; + public static final int password = 3; + + private final int type; + + protected RecipientId(int type) + { + this.type = type; + } + + /** + * Return the type code for this recipient ID. + * + * @return one of keyTrans, kek, keyAgree, password + */ + public int getType() + { + return type; + } + + public abstract Object clone(); +} diff --git a/pkix/src/main/java/org/spongycastle/cms/RecipientInfoGenerator.java b/pkix/src/main/java/org/spongycastle/cms/RecipientInfoGenerator.java new file mode 100644 index 00000000..f61b3d97 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/RecipientInfoGenerator.java @@ -0,0 +1,10 @@ +package org.spongycastle.cms; + +import org.spongycastle.asn1.cms.RecipientInfo; +import org.spongycastle.operator.GenericKey; + +public interface RecipientInfoGenerator +{ + RecipientInfo generate(GenericKey contentEncryptionKey) + throws CMSException; +} diff --git a/pkix/src/main/java/org/spongycastle/cms/RecipientInformation.java b/pkix/src/main/java/org/spongycastle/cms/RecipientInformation.java new file mode 100644 index 00000000..c083baa9 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/RecipientInformation.java @@ -0,0 +1,181 @@ +package org.spongycastle.cms; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.util.io.Streams; + +public abstract class RecipientInformation +{ + protected RecipientId rid; + protected AlgorithmIdentifier keyEncAlg; + protected AlgorithmIdentifier messageAlgorithm; + protected CMSSecureReadable secureReadable; + + private AuthAttributesProvider additionalData; + + private byte[] resultMac; + private RecipientOperator operator; + + RecipientInformation( + AlgorithmIdentifier keyEncAlg, + AlgorithmIdentifier messageAlgorithm, + CMSSecureReadable secureReadable, + AuthAttributesProvider additionalData) + { + this.keyEncAlg = keyEncAlg; + this.messageAlgorithm = messageAlgorithm; + this.secureReadable = secureReadable; + this.additionalData = additionalData; + } + + public RecipientId getRID() + { + return rid; + } + + private byte[] encodeObj( + ASN1Encodable obj) + throws IOException + { + if (obj != null) + { + return obj.toASN1Primitive().getEncoded(); + } + + return null; + } + + /** + * Return the key encryption algorithm details for the key in this recipient. + * + * @return AlgorithmIdentifier representing the key encryption algorithm. + */ + public AlgorithmIdentifier getKeyEncryptionAlgorithm() + { + return keyEncAlg; + } + + /** + * return the object identifier for the key encryption algorithm. + * + * @return OID for key encryption algorithm. + */ + public String getKeyEncryptionAlgOID() + { + return keyEncAlg.getAlgorithm().getId(); + } + + /** + * return the ASN.1 encoded key encryption algorithm parameters, or null if + * there aren't any. + * + * @return ASN.1 encoding of key encryption algorithm parameters. + */ + public byte[] getKeyEncryptionAlgParams() + { + try + { + return encodeObj(keyEncAlg.getParameters()); + } + catch (Exception e) + { + throw new RuntimeException("exception getting encryption parameters " + e); + } + } + + /** + * Return the content digest calculated during the read of the content if one has been generated. This will + * only happen if we are dealing with authenticated data and authenticated attributes are present. + * + * @return byte array containing the digest. + */ + public byte[] getContentDigest() + { + if (secureReadable instanceof CMSEnvelopedHelper.CMSDigestAuthenticatedSecureReadable) + { + return ((CMSEnvelopedHelper.CMSDigestAuthenticatedSecureReadable)secureReadable).getDigest(); + } + + return null; + } + + /** + * Return the MAC calculated for the recipient. Note: this call is only meaningful once all + * the content has been read. + * + * @return byte array containing the mac. + */ + public byte[] getMac() + { + if (resultMac == null) + { + if (operator.isMacBased()) + { + if (additionalData != null) + { + try + { + Streams.drain(operator.getInputStream(new ByteArrayInputStream(additionalData.getAuthAttributes().getEncoded(ASN1Encoding.DER)))); + } + catch (IOException e) + { + throw new IllegalStateException("unable to drain input: " + e.getMessage()); + } + } + resultMac = operator.getMac(); + } + } + + return resultMac; + } + + /** + * Return the decrypted/encapsulated content in the EnvelopedData after recovering the content + * encryption/MAC key using the passed in Recipient. + * + * @param recipient recipient object to use to recover content encryption key + * @return the content inside the EnvelopedData this RecipientInformation is associated with. + * @throws CMSException if the content-encryption/MAC key cannot be recovered. + */ + public byte[] getContent( + Recipient recipient) + throws CMSException + { + try + { + return CMSUtils.streamToByteArray(getContentStream(recipient).getContentStream()); + } + catch (IOException e) + { + throw new CMSException("unable to parse internal stream: " + e.getMessage(), e); + } + } + + /** + * Return a CMSTypedStream representing the content in the EnvelopedData after recovering the content + * encryption/MAC key using the passed in Recipient. + * + * @param recipient recipient object to use to recover content encryption key + * @return the content inside the EnvelopedData this RecipientInformation is associated with. + * @throws CMSException if the content-encryption/MAC key cannot be recovered. + */ + public CMSTypedStream getContentStream(Recipient recipient) + throws CMSException, IOException + { + operator = getRecipientOperator(recipient); + + if (additionalData != null) + { + return new CMSTypedStream(secureReadable.getInputStream()); + } + + return new CMSTypedStream(operator.getInputStream(secureReadable.getInputStream())); + } + + protected abstract RecipientOperator getRecipientOperator(Recipient recipient) + throws CMSException, IOException; +} diff --git a/pkix/src/main/java/org/spongycastle/cms/RecipientInformationStore.java b/pkix/src/main/java/org/spongycastle/cms/RecipientInformationStore.java new file mode 100644 index 00000000..f995874c --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/RecipientInformationStore.java @@ -0,0 +1,115 @@ +package org.spongycastle.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 org.spongycastle.asn1.x500.X500Name; + +public class RecipientInformationStore +{ + private final List all; //ArrayList[RecipientInformation] + private final Map table = new HashMap(); // HashMap[RecipientID, ArrayList[RecipientInformation]] + + public RecipientInformationStore( + Collection recipientInfos) + { + Iterator it = recipientInfos.iterator(); + + while (it.hasNext()) + { + RecipientInformation recipientInformation = (RecipientInformation)it.next(); + RecipientId rid = recipientInformation.getRID(); + + List list = (ArrayList)table.get(rid); + if (list == null) + { + list = new ArrayList(1); + table.put(rid, list); + } + + list.add(recipientInformation); + } + + this.all = new ArrayList(recipientInfos); + } + + /** + * Return the first RecipientInformation object that matches the + * passed in selector. Null if there are no matches. + * + * @param selector to identify a recipient + * @return a single RecipientInformation object. Null if none matches. + */ + public RecipientInformation get( + RecipientId selector) + { + Collection list = getRecipients(selector); + + return list.size() == 0 ? null : (RecipientInformation)list.iterator().next(); + } + + /** + * Return the number of recipients in the collection. + * + * @return number of recipients identified. + */ + public int size() + { + return all.size(); + } + + /** + * Return all recipients in the collection + * + * @return a collection of recipients. + */ + public Collection getRecipients() + { + return new ArrayList(all); + } + + /** + * Return possible empty collection with recipients matching the passed in RecipientId + * + * @param selector a recipient id to select against. + * @return a collection of RecipientInformation objects. + */ + public Collection getRecipients( + RecipientId selector) + { + if (selector instanceof KeyTransRecipientId) + { + KeyTransRecipientId keyTrans = (KeyTransRecipientId)selector; + + X500Name issuer = keyTrans.getIssuer(); + byte[] subjectKeyId = keyTrans.getSubjectKeyIdentifier(); + + if (issuer != null && subjectKeyId != null) + { + List results = new ArrayList(); + + Collection match1 = getRecipients(new KeyTransRecipientId(issuer, keyTrans.getSerialNumber())); + if (match1 != null) + { + results.addAll(match1); + } + + Collection match2 = getRecipients(new KeyTransRecipientId(subjectKeyId)); + if (match2 != null) + { + results.addAll(match2); + } + + return results; + } + } + + List list = (ArrayList)table.get(selector); + + return list == null ? new ArrayList() : new ArrayList(list); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/RecipientOperator.java b/pkix/src/main/java/org/spongycastle/cms/RecipientOperator.java new file mode 100644 index 00000000..c254dbf3 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/RecipientOperator.java @@ -0,0 +1,48 @@ +package org.spongycastle.cms; + +import java.io.InputStream; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.operator.InputDecryptor; +import org.spongycastle.operator.MacCalculator; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cms/SignerId.java b/pkix/src/main/java/org/spongycastle/cms/SignerId.java new file mode 100644 index 00000000..a7434f8a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/SignerId.java @@ -0,0 +1,104 @@ +package org.spongycastle.cms; + +import java.math.BigInteger; + +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.cert.selector.X509CertificateHolderSelector; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cms/SignerInfoGenerator.java b/pkix/src/main/java/org/spongycastle/cms/SignerInfoGenerator.java new file mode 100644 index 00000000..6e5a8088 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/SignerInfoGenerator.java @@ -0,0 +1,291 @@ +package org.spongycastle.cms; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.DERSet; +import org.spongycastle.asn1.cms.AttributeTable; +import org.spongycastle.asn1.cms.SignerIdentifier; +import org.spongycastle.asn1.cms.SignerInfo; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.operator.ContentSigner; +import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder; +import org.spongycastle.operator.DigestAlgorithmIdentifierFinder; +import org.spongycastle.operator.DigestCalculator; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.util.Arrays; +import org.spongycastle.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 digestAlg = null; + + if (sAttrGen != null) + { + digestAlg = digester.getAlgorithmIdentifier(); + calculatedDigest = digester.getDigest(); + Map parameters = getBaseParameters(contentType, digester.getAlgorithmIdentifier(), 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, calculatedDigest); + parameters.put(CMSAttributeTableGenerator.SIGNATURE, Arrays.clone(sigBytes)); + + AttributeTable unsigned = unsAttrGen.getAttributes(Collections.unmodifiableMap(parameters)); + + unsignedAttr = getAttributeSet(unsigned); + } + + AlgorithmIdentifier digestEncryptionAlgorithm = sigEncAlgFinder.findEncryptionAlgorithm(signer.getAlgorithmIdentifier()); + + 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, 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.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/pkix/src/main/java/org/spongycastle/cms/SignerInfoGeneratorBuilder.java b/pkix/src/main/java/org/spongycastle/cms/SignerInfoGeneratorBuilder.java new file mode 100644 index 00000000..a33005e0 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/SignerInfoGeneratorBuilder.java @@ -0,0 +1,139 @@ +package org.spongycastle.cms; + +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.cms.IssuerAndSerialNumber; +import org.spongycastle.asn1.cms.SignerIdentifier; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.operator.ContentSigner; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.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. + * + * @param digestProvider a provider of digest calculators for the algorithms required in the signature and attribute calculations. + */ + 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/pkix/src/main/java/org/spongycastle/cms/SignerInformation.java b/pkix/src/main/java/org/spongycastle/cms/SignerInformation.java new file mode 100644 index 00000000..353f27e6 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/SignerInformation.java @@ -0,0 +1,680 @@ +package org.spongycastle.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 org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.DERSet; +import org.spongycastle.asn1.cms.Attribute; +import org.spongycastle.asn1.cms.AttributeTable; +import org.spongycastle.asn1.cms.CMSAttributes; +import org.spongycastle.asn1.cms.IssuerAndSerialNumber; +import org.spongycastle.asn1.cms.SignerIdentifier; +import org.spongycastle.asn1.cms.SignerInfo; +import org.spongycastle.asn1.cms.Time; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.DigestInfo; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.operator.ContentVerifier; +import org.spongycastle.operator.DigestCalculator; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.operator.RawContentVerifier; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.io.TeeOutputStream; + +/** + * an expanded SignerInfo block from a CMS Signed message + */ +public class SignerInformation +{ + private SignerId sid; + private SignerInfo info; + private AlgorithmIdentifier digestAlgorithm; + private AlgorithmIdentifier encryptionAlgorithm; + private final ASN1Set signedAttributeSet; + private final ASN1Set unsignedAttributeSet; + private CMSProcessable content; + private byte[] signature; + private ASN1ObjectIdentifier contentType; + private byte[] resultDigest; + + // Derived + private AttributeTable signedAttributeValues; + private AttributeTable unsignedAttributeValues; + private boolean isCounterSignature; + + 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; + } + + 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(); + } + + 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"); + } + } + } + + // 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) + { + AttributeTable signedAttrTable = this.getSignedAttributes(); + 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)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 org.spongycastle.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 org.spongycastle.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/pkix/src/main/java/org/spongycastle/cms/SignerInformationStore.java b/pkix/src/main/java/org/spongycastle/cms/SignerInformationStore.java new file mode 100644 index 00000000..df3bb968 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/SignerInformationStore.java @@ -0,0 +1,109 @@ +package org.spongycastle.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; + +public class SignerInformationStore +{ + private List all = new ArrayList(); + private Map table = new HashMap(); + + public SignerInformationStore( + Collection 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 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 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); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/SignerInformationVerifier.java b/pkix/src/main/java/org/spongycastle/cms/SignerInformationVerifier.java new file mode 100644 index 00000000..ea9de675 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/SignerInformationVerifier.java @@ -0,0 +1,50 @@ +package org.spongycastle.cms; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.operator.ContentVerifier; +import org.spongycastle.operator.ContentVerifierProvider; +import org.spongycastle.operator.DigestCalculator; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.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); + + return verifierProvider.get(sigAlgorithmFinder.find(signatureName)); + } + + public DigestCalculator getDigestCalculator(AlgorithmIdentifier algorithmIdentifier) + throws OperatorCreationException + { + return digestProvider.get(algorithmIdentifier); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/SignerInformationVerifierProvider.java b/pkix/src/main/java/org/spongycastle/cms/SignerInformationVerifierProvider.java new file mode 100644 index 00000000..d6e7d6e5 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/SignerInformationVerifierProvider.java @@ -0,0 +1,16 @@ +package org.spongycastle.cms; + +import org.spongycastle.operator.OperatorCreationException; + +public interface SignerInformationVerifierProvider +{ + /** + * Return a SignerInformationVerifierProvider suitable for the passed in SID. + * + * @param sid the SignerId we are trying to match for. + * @return a verifier if one is available, null otherwise. + * @throws OperatorCreationException if creation of the verifier fails when it should suceed. + */ + public SignerInformationVerifier get(SignerId sid) + throws OperatorCreationException; +} diff --git a/pkix/src/main/java/org/spongycastle/cms/SimpleAttributeTableGenerator.java b/pkix/src/main/java/org/spongycastle/cms/SimpleAttributeTableGenerator.java new file mode 100644 index 00000000..25c55b78 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/SimpleAttributeTableGenerator.java @@ -0,0 +1,25 @@ +package org.spongycastle.cms; + +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cms/bc/BcCMSContentEncryptorBuilder.java b/pkix/src/main/java/org/spongycastle/cms/bc/BcCMSContentEncryptorBuilder.java new file mode 100644 index 00000000..22f79fb7 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/bc/BcCMSContentEncryptorBuilder.java @@ -0,0 +1,124 @@ +package org.spongycastle.cms.bc; + +import java.io.OutputStream; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Map; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSAlgorithm; +import org.spongycastle.cms.CMSException; +import org.spongycastle.crypto.BufferedBlockCipher; +import org.spongycastle.crypto.CipherKeyGenerator; +import org.spongycastle.crypto.StreamCipher; +import org.spongycastle.crypto.io.CipherOutputStream; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.OutputEncryptor; +import org.spongycastle.util.Integers; + +public class BcCMSContentEncryptorBuilder +{ + private static Map keySizes = new HashMap(); + + static + { + keySizes.put(CMSAlgorithm.AES128_CBC, Integers.valueOf(128)); + keySizes.put(CMSAlgorithm.AES192_CBC, Integers.valueOf(192)); + keySizes.put(CMSAlgorithm.AES256_CBC, Integers.valueOf(256)); + + keySizes.put(CMSAlgorithm.CAMELLIA128_CBC, Integers.valueOf(128)); + keySizes.put(CMSAlgorithm.CAMELLIA192_CBC, Integers.valueOf(192)); + keySizes.put(CMSAlgorithm.CAMELLIA256_CBC, Integers.valueOf(256)); + } + + private static int getKeySize(ASN1ObjectIdentifier oid) + { + Integer size = (Integer)keySizes.get(oid); + + if (size != null) + { + return size.intValue(); + } + + return -1; + } + + private final ASN1ObjectIdentifier encryptionOID; + private final int keySize; + + private EnvelopedDataHelper helper = new EnvelopedDataHelper(); + private SecureRandom random; + + public BcCMSContentEncryptorBuilder(ASN1ObjectIdentifier encryptionOID) + { + this(encryptionOID, getKeySize(encryptionOID)); + } + + public BcCMSContentEncryptorBuilder(ASN1ObjectIdentifier encryptionOID, int keySize) + { + this.encryptionOID = encryptionOID; + this.keySize = keySize; + } + + public BcCMSContentEncryptorBuilder setSecureRandom(SecureRandom random) + { + this.random = random; + + return this; + } + + public OutputEncryptor build() + throws CMSException + { + return new CMSOutputEncryptor(encryptionOID, keySize, random); + } + + private class CMSOutputEncryptor + implements OutputEncryptor + { + private KeyParameter encKey; + private AlgorithmIdentifier algorithmIdentifier; + private Object cipher; + + CMSOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, SecureRandom random) + throws CMSException + { + if (random == null) + { + random = new SecureRandom(); + } + + CipherKeyGenerator keyGen = helper.createKeyGenerator(encryptionOID, random); + + encKey = new KeyParameter(keyGen.generateKey()); + + algorithmIdentifier = helper.generateAlgorithmIdentifier(encryptionOID, encKey, random); + + cipher = helper.createContentCipher(true, encKey, algorithmIdentifier); + } + + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return algorithmIdentifier; + } + + public OutputStream getOutputStream(OutputStream dOut) + { + if (cipher instanceof BufferedBlockCipher) + { + return new CipherOutputStream(dOut, (BufferedBlockCipher)cipher); + } + else + { + return new CipherOutputStream(dOut, (StreamCipher)cipher); + } + } + + public GenericKey getKey() + { + return new GenericKey(algorithmIdentifier, encKey.getKey()); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/bc/BcKEKEnvelopedRecipient.java b/pkix/src/main/java/org/spongycastle/cms/bc/BcKEKEnvelopedRecipient.java new file mode 100644 index 00000000..afde8a02 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/bc/BcKEKEnvelopedRecipient.java @@ -0,0 +1,49 @@ +package org.spongycastle.cms.bc; + +import java.io.InputStream; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.RecipientOperator; +import org.spongycastle.crypto.BufferedBlockCipher; +import org.spongycastle.crypto.StreamCipher; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.operator.InputDecryptor; +import org.spongycastle.operator.bc.BcSymmetricKeyUnwrapper; + +public class BcKEKEnvelopedRecipient + extends BcKEKRecipient +{ + public BcKEKEnvelopedRecipient(BcSymmetricKeyUnwrapper unwrapper) + { + super(unwrapper); + } + + public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey) + throws CMSException + { + KeyParameter secretKey = (KeyParameter)extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, encryptedContentEncryptionKey); + + final Object dataCipher = EnvelopedDataHelper.createContentCipher(false, secretKey, contentEncryptionAlgorithm); + + return new RecipientOperator(new InputDecryptor() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return contentEncryptionAlgorithm; + } + + public InputStream getInputStream(InputStream dataOut) + { + if (dataCipher instanceof BufferedBlockCipher) + { + return new org.spongycastle.crypto.io.CipherInputStream(dataOut, (BufferedBlockCipher)dataCipher); + } + else + { + return new org.spongycastle.crypto.io.CipherInputStream(dataOut, (StreamCipher)dataCipher); + } + } + }); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/bc/BcKEKRecipient.java b/pkix/src/main/java/org/spongycastle/cms/bc/BcKEKRecipient.java new file mode 100644 index 00000000..066deaa6 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/bc/BcKEKRecipient.java @@ -0,0 +1,33 @@ +package org.spongycastle.cms.bc; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.KEKRecipient; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.operator.OperatorException; +import org.spongycastle.operator.SymmetricKeyUnwrapper; +import org.spongycastle.operator.bc.BcSymmetricKeyUnwrapper; + +public abstract class BcKEKRecipient + implements KEKRecipient +{ + private SymmetricKeyUnwrapper unwrapper; + + public BcKEKRecipient(BcSymmetricKeyUnwrapper unwrapper) + { + this.unwrapper = unwrapper; + } + + protected CipherParameters extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey) + throws CMSException + { + try + { + return CMSUtils.getBcKey(unwrapper.generateUnwrappedKey(contentEncryptionAlgorithm, encryptedContentEncryptionKey)); + } + catch (OperatorException e) + { + throw new CMSException("exception unwrapping key: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/bc/BcKEKRecipientInfoGenerator.java b/pkix/src/main/java/org/spongycastle/cms/bc/BcKEKRecipientInfoGenerator.java new file mode 100644 index 00000000..2a2ad9e7 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/bc/BcKEKRecipientInfoGenerator.java @@ -0,0 +1,19 @@ +package org.spongycastle.cms.bc; + +import org.spongycastle.asn1.cms.KEKIdentifier; +import org.spongycastle.cms.KEKRecipientInfoGenerator; +import org.spongycastle.operator.bc.BcSymmetricKeyWrapper; + +public class BcKEKRecipientInfoGenerator + extends KEKRecipientInfoGenerator +{ + public BcKEKRecipientInfoGenerator(KEKIdentifier kekIdentifier, BcSymmetricKeyWrapper kekWrapper) + { + super(kekIdentifier, kekWrapper); + } + + public BcKEKRecipientInfoGenerator(byte[] keyIdentifier, BcSymmetricKeyWrapper kekWrapper) + { + this(new KEKIdentifier(keyIdentifier, null, null), kekWrapper); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/bc/BcKeyTransRecipient.java b/pkix/src/main/java/org/spongycastle/cms/bc/BcKeyTransRecipient.java new file mode 100644 index 00000000..ab50269d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/bc/BcKeyTransRecipient.java @@ -0,0 +1,36 @@ +package org.spongycastle.cms.bc; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.KeyTransRecipient; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.params.AsymmetricKeyParameter; +import org.spongycastle.operator.AsymmetricKeyUnwrapper; +import org.spongycastle.operator.OperatorException; +import org.spongycastle.operator.bc.BcRSAAsymmetricKeyUnwrapper; + +public abstract class BcKeyTransRecipient + implements KeyTransRecipient +{ + private AsymmetricKeyParameter recipientKey; + + public BcKeyTransRecipient(AsymmetricKeyParameter recipientKey) + { + this.recipientKey = recipientKey; + } + + protected CipherParameters extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedEncryptionKey) + throws CMSException + { + AsymmetricKeyUnwrapper unwrapper = new BcRSAAsymmetricKeyUnwrapper(keyEncryptionAlgorithm, recipientKey); + + try + { + return CMSUtils.getBcKey(unwrapper.generateUnwrappedKey(encryptedKeyAlgorithm, encryptedEncryptionKey)); + } + catch (OperatorException e) + { + throw new CMSException("exception unwrapping key: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/bc/BcKeyTransRecipientInfoGenerator.java b/pkix/src/main/java/org/spongycastle/cms/bc/BcKeyTransRecipientInfoGenerator.java new file mode 100644 index 00000000..c987d5a2 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/bc/BcKeyTransRecipientInfoGenerator.java @@ -0,0 +1,20 @@ +package org.spongycastle.cms.bc; + +import org.spongycastle.asn1.cms.IssuerAndSerialNumber; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.cms.KeyTransRecipientInfoGenerator; +import org.spongycastle.operator.bc.BcAsymmetricKeyWrapper; + +public abstract class BcKeyTransRecipientInfoGenerator + extends KeyTransRecipientInfoGenerator +{ + public BcKeyTransRecipientInfoGenerator(X509CertificateHolder recipientCert, BcAsymmetricKeyWrapper wrapper) + { + super(new IssuerAndSerialNumber(recipientCert.toASN1Structure()), wrapper); + } + + public BcKeyTransRecipientInfoGenerator(byte[] subjectKeyIdentifier, BcAsymmetricKeyWrapper wrapper) + { + super(subjectKeyIdentifier, wrapper); + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cms/bc/BcPasswordEnvelopedRecipient.java b/pkix/src/main/java/org/spongycastle/cms/bc/BcPasswordEnvelopedRecipient.java new file mode 100644 index 00000000..0b9a529f --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/bc/BcPasswordEnvelopedRecipient.java @@ -0,0 +1,49 @@ +package org.spongycastle.cms.bc; + +import java.io.InputStream; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.RecipientOperator; +import org.spongycastle.crypto.BufferedBlockCipher; +import org.spongycastle.crypto.StreamCipher; +import org.spongycastle.crypto.io.CipherInputStream; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.operator.InputDecryptor; + +public class BcPasswordEnvelopedRecipient + extends BcPasswordRecipient +{ + public BcPasswordEnvelopedRecipient(char[] password) + { + super(password); + } + + public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, byte[] derivedKey, byte[] encryptedContentEncryptionKey) + throws CMSException + { + KeyParameter secretKey = extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, derivedKey, encryptedContentEncryptionKey); + + final Object dataCipher = EnvelopedDataHelper.createContentCipher(false, secretKey, contentEncryptionAlgorithm); + + return new RecipientOperator(new InputDecryptor() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return contentEncryptionAlgorithm; + } + + public InputStream getInputStream(InputStream dataOut) + { + if (dataCipher instanceof BufferedBlockCipher) + { + return new CipherInputStream(dataOut, (BufferedBlockCipher)dataCipher); + } + else + { + return new CipherInputStream(dataOut, (StreamCipher)dataCipher); + } + } + }); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/bc/BcPasswordRecipient.java b/pkix/src/main/java/org/spongycastle/cms/bc/BcPasswordRecipient.java new file mode 100644 index 00000000..679f4144 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/bc/BcPasswordRecipient.java @@ -0,0 +1,75 @@ +package org.spongycastle.cms.bc; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.pkcs.PBKDF2Params; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.PasswordRecipient; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.Wrapper; +import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; + +/** + * the RecipientInfo class for a recipient who has been sent a message + * encrypted using a password. + */ +public abstract class BcPasswordRecipient + implements PasswordRecipient +{ + private int schemeID = PasswordRecipient.PKCS5_SCHEME2_UTF8; + private char[] password; + + BcPasswordRecipient( + char[] password) + { + this.password = password; + } + + public BcPasswordRecipient setPasswordConversionScheme(int schemeID) + { + this.schemeID = schemeID; + + return this; + } + + protected KeyParameter extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] derivedKey, byte[] encryptedContentEncryptionKey) + throws CMSException + { + Wrapper keyEncryptionCipher = EnvelopedDataHelper.createRFC3211Wrapper(keyEncryptionAlgorithm.getAlgorithm()); + + keyEncryptionCipher.init(false, new ParametersWithIV(new KeyParameter(derivedKey), ASN1OctetString.getInstance(keyEncryptionAlgorithm.getParameters()).getOctets())); + + try + { + return new KeyParameter(keyEncryptionCipher.unwrap(encryptedContentEncryptionKey, 0, encryptedContentEncryptionKey.length)); + } + catch (InvalidCipherTextException e) + { + throw new CMSException("unable to unwrap key: " + e.getMessage(), e); + } + } + + public byte[] calculateDerivedKey(byte[] encodedPassword, AlgorithmIdentifier derivationAlgorithm, int keySize) + throws CMSException + { + PBKDF2Params params = PBKDF2Params.getInstance(derivationAlgorithm.getParameters()); + + PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(); + + gen.init(encodedPassword, params.getSalt(), params.getIterationCount().intValue()); + + return ((KeyParameter)gen.generateDerivedParameters(keySize)).getKey(); + } + + public int getPasswordConversionScheme() + { + return schemeID; + } + + public char[] getPassword() + { + return password; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/bc/BcPasswordRecipientInfoGenerator.java b/pkix/src/main/java/org/spongycastle/cms/bc/BcPasswordRecipientInfoGenerator.java new file mode 100644 index 00000000..4ea5cdfd --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/bc/BcPasswordRecipientInfoGenerator.java @@ -0,0 +1,45 @@ +package org.spongycastle.cms.bc; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.pkcs.PBKDF2Params; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.PasswordRecipientInfoGenerator; +import org.spongycastle.crypto.Wrapper; +import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.operator.GenericKey; + +public class BcPasswordRecipientInfoGenerator + extends PasswordRecipientInfoGenerator +{ + public BcPasswordRecipientInfoGenerator(ASN1ObjectIdentifier kekAlgorithm, char[] password) + { + super(kekAlgorithm, password); + } + + protected byte[] calculateDerivedKey(byte[] encodedPassword, AlgorithmIdentifier derivationAlgorithm, int keySize) + throws CMSException + { + PBKDF2Params params = PBKDF2Params.getInstance(derivationAlgorithm.getParameters()); + + PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(); + + gen.init(encodedPassword, params.getSalt(), params.getIterationCount().intValue()); + + return ((KeyParameter)gen.generateDerivedParameters(keySize)).getKey(); + } + + public byte[] generateEncryptedBytes(AlgorithmIdentifier keyEncryptionAlgorithm, byte[] derivedKey, GenericKey contentEncryptionKey) + throws CMSException + { + byte[] contentEncryptionKeySpec = ((KeyParameter)CMSUtils.getBcKey(contentEncryptionKey)).getKey(); + Wrapper keyEncryptionCipher = EnvelopedDataHelper.createRFC3211Wrapper(keyEncryptionAlgorithm.getAlgorithm()); + + keyEncryptionCipher.init(true, new ParametersWithIV(new KeyParameter(derivedKey), ASN1OctetString.getInstance(keyEncryptionAlgorithm.getParameters()).getOctets())); + + return keyEncryptionCipher.wrap(contentEncryptionKeySpec, 0, contentEncryptionKeySpec.length); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/bc/BcRSAKeyTransEnvelopedRecipient.java b/pkix/src/main/java/org/spongycastle/cms/bc/BcRSAKeyTransEnvelopedRecipient.java new file mode 100644 index 00000000..601de841 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/bc/BcRSAKeyTransEnvelopedRecipient.java @@ -0,0 +1,50 @@ +package org.spongycastle.cms.bc; + +import java.io.InputStream; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.RecipientOperator; +import org.spongycastle.crypto.BufferedBlockCipher; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.StreamCipher; +import org.spongycastle.crypto.io.CipherInputStream; +import org.spongycastle.crypto.params.AsymmetricKeyParameter; +import org.spongycastle.operator.InputDecryptor; + +public class BcRSAKeyTransEnvelopedRecipient + extends BcKeyTransRecipient +{ + public BcRSAKeyTransEnvelopedRecipient(AsymmetricKeyParameter key) + { + super(key); + } + + public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey) + throws CMSException + { + CipherParameters secretKey = extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, encryptedContentEncryptionKey); + + final Object dataCipher = EnvelopedDataHelper.createContentCipher(false, secretKey, contentEncryptionAlgorithm); + + return new RecipientOperator(new InputDecryptor() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return contentEncryptionAlgorithm; + } + + public InputStream getInputStream(InputStream dataIn) + { + if (dataCipher instanceof BufferedBlockCipher) + { + return new CipherInputStream(dataIn, (BufferedBlockCipher)dataCipher); + } + else + { + return new CipherInputStream(dataIn, (StreamCipher)dataCipher); + } + } + }); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/bc/BcRSAKeyTransRecipientInfoGenerator.java b/pkix/src/main/java/org/spongycastle/cms/bc/BcRSAKeyTransRecipientInfoGenerator.java new file mode 100644 index 00000000..09f7f8d0 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/bc/BcRSAKeyTransRecipientInfoGenerator.java @@ -0,0 +1,23 @@ +package org.spongycastle.cms.bc; + +import java.io.IOException; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.crypto.params.AsymmetricKeyParameter; +import org.spongycastle.operator.bc.BcRSAAsymmetricKeyWrapper; + +public class BcRSAKeyTransRecipientInfoGenerator + extends BcKeyTransRecipientInfoGenerator +{ + public BcRSAKeyTransRecipientInfoGenerator(byte[] subjectKeyIdentifier, AlgorithmIdentifier encAlgId, AsymmetricKeyParameter publicKey) + { + super(subjectKeyIdentifier, new BcRSAAsymmetricKeyWrapper(encAlgId, publicKey)); + } + + public BcRSAKeyTransRecipientInfoGenerator(X509CertificateHolder recipientCert) + throws IOException + { + super(recipientCert, new BcRSAAsymmetricKeyWrapper(recipientCert.getSubjectPublicKeyInfo().getAlgorithmId(), recipientCert.getSubjectPublicKeyInfo())); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/bc/BcRSASignerInfoVerifierBuilder.java b/pkix/src/main/java/org/spongycastle/cms/bc/BcRSASignerInfoVerifierBuilder.java new file mode 100644 index 00000000..26028e1a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/bc/BcRSASignerInfoVerifierBuilder.java @@ -0,0 +1,39 @@ +package org.spongycastle.cms.bc; + +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.cms.CMSSignatureAlgorithmNameGenerator; +import org.spongycastle.cms.SignerInformationVerifier; +import org.spongycastle.crypto.params.AsymmetricKeyParameter; +import org.spongycastle.operator.DigestAlgorithmIdentifierFinder; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.operator.SignatureAlgorithmIdentifierFinder; +import org.spongycastle.operator.bc.BcRSAContentVerifierProviderBuilder; + +public class BcRSASignerInfoVerifierBuilder +{ + private BcRSAContentVerifierProviderBuilder contentVerifierProviderBuilder; + private DigestCalculatorProvider digestCalculatorProvider; + private CMSSignatureAlgorithmNameGenerator sigAlgNameGen; + private SignatureAlgorithmIdentifierFinder sigAlgIdFinder; + + public BcRSASignerInfoVerifierBuilder(CMSSignatureAlgorithmNameGenerator sigAlgNameGen, SignatureAlgorithmIdentifierFinder sigAlgIdFinder, DigestAlgorithmIdentifierFinder digestAlgorithmFinder, DigestCalculatorProvider digestCalculatorProvider) + { + this.sigAlgNameGen = sigAlgNameGen; + this.sigAlgIdFinder = sigAlgIdFinder; + this.contentVerifierProviderBuilder = new BcRSAContentVerifierProviderBuilder(digestAlgorithmFinder); + this.digestCalculatorProvider = digestCalculatorProvider; + } + + public SignerInformationVerifier build(X509CertificateHolder certHolder) + throws OperatorCreationException + { + return new SignerInformationVerifier(sigAlgNameGen, sigAlgIdFinder, contentVerifierProviderBuilder.build(certHolder), digestCalculatorProvider); + } + + public SignerInformationVerifier build(AsymmetricKeyParameter pubKey) + throws OperatorCreationException + { + return new SignerInformationVerifier(sigAlgNameGen, sigAlgIdFinder, contentVerifierProviderBuilder.build(pubKey), digestCalculatorProvider); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/bc/CMSUtils.java b/pkix/src/main/java/org/spongycastle/cms/bc/CMSUtils.java new file mode 100644 index 00000000..90035ec1 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/bc/CMSUtils.java @@ -0,0 +1,23 @@ +package org.spongycastle.cms.bc; + +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.operator.GenericKey; + +class CMSUtils +{ + static CipherParameters getBcKey(GenericKey key) + { + if (key.getRepresentation() instanceof CipherParameters) + { + return (CipherParameters)key.getRepresentation(); + } + + if (key.getRepresentation() instanceof byte[]) + { + return new KeyParameter((byte[])key.getRepresentation()); + } + + throw new IllegalArgumentException("unknown generic key type"); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/bc/EnvelopedDataHelper.java b/pkix/src/main/java/org/spongycastle/cms/bc/EnvelopedDataHelper.java new file mode 100644 index 00000000..db65fd09 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/bc/EnvelopedDataHelper.java @@ -0,0 +1,378 @@ +package org.spongycastle.cms.bc; + +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Map; + +import org.spongycastle.asn1.ASN1Null; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.kisa.KISAObjectIdentifiers; +import org.spongycastle.asn1.misc.CAST5CBCParameters; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.ntt.NTTObjectIdentifiers; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.pkcs.RC2CBCParameter; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSAlgorithm; +import org.spongycastle.cms.CMSException; +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.BufferedBlockCipher; +import org.spongycastle.crypto.CipherKeyGenerator; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.KeyGenerationParameters; +import org.spongycastle.crypto.StreamCipher; +import org.spongycastle.crypto.Wrapper; +import org.spongycastle.crypto.engines.AESEngine; +import org.spongycastle.crypto.engines.DESEngine; +import org.spongycastle.crypto.engines.DESedeEngine; +import org.spongycastle.crypto.engines.RC2Engine; +import org.spongycastle.crypto.engines.RC4Engine; +import org.spongycastle.crypto.engines.RFC3211WrapEngine; +import org.spongycastle.crypto.generators.DESKeyGenerator; +import org.spongycastle.crypto.generators.DESedeKeyGenerator; +import org.spongycastle.crypto.modes.CBCBlockCipher; +import org.spongycastle.crypto.paddings.PKCS7Padding; +import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.crypto.params.RC2Parameters; + +class EnvelopedDataHelper +{ + protected static final Map BASE_CIPHER_NAMES = new HashMap(); + protected static final Map CIPHER_ALG_NAMES = new HashMap(); + protected static final Map MAC_ALG_NAMES = new HashMap(); + + static + { + BASE_CIPHER_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDE"); + BASE_CIPHER_NAMES.put(CMSAlgorithm.AES128_CBC, "AES"); + BASE_CIPHER_NAMES.put(CMSAlgorithm.AES192_CBC, "AES"); + BASE_CIPHER_NAMES.put(CMSAlgorithm.AES256_CBC, "AES"); + + CIPHER_ALG_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDE/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(CMSAlgorithm.AES128_CBC, "AES/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(CMSAlgorithm.AES192_CBC, "AES/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(CMSAlgorithm.AES256_CBC, "AES/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(new ASN1ObjectIdentifier(PKCSObjectIdentifiers.rsaEncryption.getId()), "RSA/ECB/PKCS1Padding"); + CIPHER_ALG_NAMES.put(CMSAlgorithm.CAST5_CBC, "CAST5/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(CMSAlgorithm.CAMELLIA128_CBC, "Camellia/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(CMSAlgorithm.CAMELLIA192_CBC, "Camellia/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(CMSAlgorithm.CAMELLIA256_CBC, "Camellia/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(CMSAlgorithm.SEED_CBC, "SEED/CBC/PKCS5Padding"); + + MAC_ALG_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDEMac"); + MAC_ALG_NAMES.put(CMSAlgorithm.AES128_CBC, "AESMac"); + MAC_ALG_NAMES.put(CMSAlgorithm.AES192_CBC, "AESMac"); + MAC_ALG_NAMES.put(CMSAlgorithm.AES256_CBC, "AESMac"); + MAC_ALG_NAMES.put(CMSAlgorithm.RC2_CBC, "RC2Mac"); + } + + private static final short[] rc2Table = { + 0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0, + 0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a, + 0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36, + 0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c, + 0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60, + 0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa, + 0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e, + 0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf, + 0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6, + 0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3, + 0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c, + 0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2, + 0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5, + 0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5, + 0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f, + 0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab + }; + + private static final short[] rc2Ekb = { + 0x5d, 0xbe, 0x9b, 0x8b, 0x11, 0x99, 0x6e, 0x4d, 0x59, 0xf3, 0x85, 0xa6, 0x3f, 0xb7, 0x83, 0xc5, + 0xe4, 0x73, 0x6b, 0x3a, 0x68, 0x5a, 0xc0, 0x47, 0xa0, 0x64, 0x34, 0x0c, 0xf1, 0xd0, 0x52, 0xa5, + 0xb9, 0x1e, 0x96, 0x43, 0x41, 0xd8, 0xd4, 0x2c, 0xdb, 0xf8, 0x07, 0x77, 0x2a, 0xca, 0xeb, 0xef, + 0x10, 0x1c, 0x16, 0x0d, 0x38, 0x72, 0x2f, 0x89, 0xc1, 0xf9, 0x80, 0xc4, 0x6d, 0xae, 0x30, 0x3d, + 0xce, 0x20, 0x63, 0xfe, 0xe6, 0x1a, 0xc7, 0xb8, 0x50, 0xe8, 0x24, 0x17, 0xfc, 0x25, 0x6f, 0xbb, + 0x6a, 0xa3, 0x44, 0x53, 0xd9, 0xa2, 0x01, 0xab, 0xbc, 0xb6, 0x1f, 0x98, 0xee, 0x9a, 0xa7, 0x2d, + 0x4f, 0x9e, 0x8e, 0xac, 0xe0, 0xc6, 0x49, 0x46, 0x29, 0xf4, 0x94, 0x8a, 0xaf, 0xe1, 0x5b, 0xc3, + 0xb3, 0x7b, 0x57, 0xd1, 0x7c, 0x9c, 0xed, 0x87, 0x40, 0x8c, 0xe2, 0xcb, 0x93, 0x14, 0xc9, 0x61, + 0x2e, 0xe5, 0xcc, 0xf6, 0x5e, 0xa8, 0x5c, 0xd6, 0x75, 0x8d, 0x62, 0x95, 0x58, 0x69, 0x76, 0xa1, + 0x4a, 0xb5, 0x55, 0x09, 0x78, 0x33, 0x82, 0xd7, 0xdd, 0x79, 0xf5, 0x1b, 0x0b, 0xde, 0x26, 0x21, + 0x28, 0x74, 0x04, 0x97, 0x56, 0xdf, 0x3c, 0xf0, 0x37, 0x39, 0xdc, 0xff, 0x06, 0xa4, 0xea, 0x42, + 0x08, 0xda, 0xb4, 0x71, 0xb0, 0xcf, 0x12, 0x7a, 0x4e, 0xfa, 0x6c, 0x1d, 0x84, 0x00, 0xc8, 0x7f, + 0x91, 0x45, 0xaa, 0x2b, 0xc2, 0xb1, 0x8f, 0xd5, 0xba, 0xf2, 0xad, 0x19, 0xb2, 0x67, 0x36, 0xf7, + 0x0f, 0x0a, 0x92, 0x7d, 0xe3, 0x9d, 0xe9, 0x90, 0x3e, 0x23, 0x27, 0x66, 0x13, 0xec, 0x81, 0x15, + 0xbd, 0x22, 0xbf, 0x9f, 0x7e, 0xa9, 0x51, 0x4b, 0x4c, 0xfb, 0x02, 0xd3, 0x70, 0x86, 0x31, 0xe7, + 0x3b, 0x05, 0x03, 0x54, 0x60, 0x48, 0x65, 0x18, 0xd2, 0xcd, 0x5f, 0x32, 0x88, 0x0e, 0x35, 0xfd + }; + + EnvelopedDataHelper() + { + } + + String getBaseCipherName(ASN1ObjectIdentifier algorithm) + { + String name = (String)BASE_CIPHER_NAMES.get(algorithm); + + if (name == null) + { + return algorithm.getId(); + } + + return name; + } + + static BufferedBlockCipher createCipher(ASN1ObjectIdentifier algorithm) + throws CMSException + { + BlockCipher cipher; + + if (NISTObjectIdentifiers.id_aes128_CBC.equals(algorithm) + || NISTObjectIdentifiers.id_aes192_CBC.equals(algorithm) + || NISTObjectIdentifiers.id_aes256_CBC.equals(algorithm)) + { + cipher = new CBCBlockCipher(new AESEngine()); + } + else if (PKCSObjectIdentifiers.des_EDE3_CBC.equals(algorithm)) + { + cipher = new CBCBlockCipher(new DESedeEngine()); + } + else if (OIWObjectIdentifiers.desCBC.equals(algorithm)) + { + cipher = new CBCBlockCipher(new DESEngine()); + } + else if (PKCSObjectIdentifiers.RC2_CBC.equals(algorithm)) + { + cipher = new CBCBlockCipher(new RC2Engine()); + } + else + { + throw new CMSException("cannot recognise cipher: " + algorithm); + } + + return new PaddedBufferedBlockCipher(cipher, new PKCS7Padding()); + } + + static Wrapper createRFC3211Wrapper(ASN1ObjectIdentifier algorithm) + throws CMSException + { + if (NISTObjectIdentifiers.id_aes128_CBC.equals(algorithm) + || NISTObjectIdentifiers.id_aes192_CBC.equals(algorithm) + || NISTObjectIdentifiers.id_aes256_CBC.equals(algorithm)) + { + return new RFC3211WrapEngine(new AESEngine()); + } + else if (PKCSObjectIdentifiers.des_EDE3_CBC.equals(algorithm)) + { + return new RFC3211WrapEngine(new DESedeEngine()); + } + else if (OIWObjectIdentifiers.desCBC.equals(algorithm)) + { + return new RFC3211WrapEngine(new DESEngine()); + } + else if (PKCSObjectIdentifiers.RC2_CBC.equals(algorithm)) + { + return new RFC3211WrapEngine(new RC2Engine()); + } + else + { + throw new CMSException("cannot recognise wrapper: " + algorithm); + } + } + + static Object createContentCipher(boolean forEncryption, CipherParameters encKey, AlgorithmIdentifier encryptionAlgID) + throws CMSException + { + ASN1ObjectIdentifier encAlg = encryptionAlgID.getAlgorithm(); + + if (encAlg.equals(PKCSObjectIdentifiers.rc4)) + { + StreamCipher cipher = new RC4Engine(); + + cipher.init(forEncryption, encKey); + + return cipher; + } + else + { + BufferedBlockCipher cipher = createCipher(encryptionAlgID.getAlgorithm()); + ASN1Primitive sParams = encryptionAlgID.getParameters().toASN1Primitive(); + + if (sParams != null && !(sParams instanceof ASN1Null)) + { + if (encAlg.equals(CMSAlgorithm.DES_EDE3_CBC) + || encAlg.equals(CMSAlgorithm.IDEA_CBC) + || encAlg.equals(CMSAlgorithm.AES128_CBC) + || encAlg.equals(CMSAlgorithm.AES192_CBC) + || encAlg.equals(CMSAlgorithm.AES256_CBC) + || encAlg.equals(CMSAlgorithm.CAMELLIA128_CBC) + || encAlg.equals(CMSAlgorithm.CAMELLIA192_CBC) + || encAlg.equals(CMSAlgorithm.CAMELLIA256_CBC) + || encAlg.equals(CMSAlgorithm.SEED_CBC) + || encAlg.equals(OIWObjectIdentifiers.desCBC)) + { + cipher.init(forEncryption, new ParametersWithIV(encKey, + ASN1OctetString.getInstance(sParams).getOctets())); + } + else if (encAlg.equals(CMSAlgorithm.CAST5_CBC)) + { + CAST5CBCParameters cbcParams = CAST5CBCParameters.getInstance(sParams); + + cipher.init(forEncryption, new ParametersWithIV(encKey, cbcParams.getIV())); + } + else if (encAlg.equals(CMSAlgorithm.RC2_CBC)) + { + RC2CBCParameter cbcParams = RC2CBCParameter.getInstance(sParams); + + cipher.init(forEncryption, new ParametersWithIV(new RC2Parameters(((KeyParameter)encKey).getKey(), rc2Ekb[cbcParams.getRC2ParameterVersion().intValue()]), cbcParams.getIV())); + } + else + { + throw new CMSException("cannot match parameters"); + } + } + else + { + if (encAlg.equals(CMSAlgorithm.DES_EDE3_CBC) + || encAlg.equals(CMSAlgorithm.IDEA_CBC) + || encAlg.equals(CMSAlgorithm.CAST5_CBC)) + { + cipher.init(forEncryption, new ParametersWithIV(encKey, new byte[8])); + } + else + { + cipher.init(forEncryption, encKey); + } + } + + return cipher; + } + } + + AlgorithmIdentifier generateAlgorithmIdentifier(ASN1ObjectIdentifier encryptionOID, CipherParameters encKey, SecureRandom random) + throws CMSException + { + if (encryptionOID.equals(CMSAlgorithm.AES128_CBC) + || encryptionOID.equals(CMSAlgorithm.AES192_CBC) + || encryptionOID.equals(CMSAlgorithm.AES256_CBC) + || encryptionOID.equals(CMSAlgorithm.CAMELLIA128_CBC) + || encryptionOID.equals(CMSAlgorithm.CAMELLIA192_CBC) + || encryptionOID.equals(CMSAlgorithm.CAMELLIA256_CBC) + || encryptionOID.equals(CMSAlgorithm.SEED_CBC)) + { + byte[] iv = new byte[16]; + + random.nextBytes(iv); + + return new AlgorithmIdentifier(encryptionOID, new DEROctetString(iv)); + } + else if (encryptionOID.equals(CMSAlgorithm.DES_EDE3_CBC) + || encryptionOID.equals(CMSAlgorithm.IDEA_CBC) + || encryptionOID.equals(OIWObjectIdentifiers.desCBC)) + { + byte[] iv = new byte[8]; + + random.nextBytes(iv); + + return new AlgorithmIdentifier(encryptionOID, new DEROctetString(iv)); + } + else if (encryptionOID.equals(CMSAlgorithm.CAST5_CBC)) + { + byte[] iv = new byte[8]; + + random.nextBytes(iv); + + CAST5CBCParameters cbcParams = new CAST5CBCParameters(iv, ((KeyParameter)encKey).getKey().length * 8); + + return new AlgorithmIdentifier(encryptionOID, cbcParams); + } + else if (encryptionOID.equals(PKCSObjectIdentifiers.rc4)) + { + return new AlgorithmIdentifier(encryptionOID, DERNull.INSTANCE); + } + else + { + throw new CMSException("unable to match algorithm"); + } + } + + CipherKeyGenerator createKeyGenerator(ASN1ObjectIdentifier algorithm, SecureRandom random) + throws CMSException + { + if (NISTObjectIdentifiers.id_aes128_CBC.equals(algorithm)) + { + return createCipherKeyGenerator(random, 128); + } + else if (NISTObjectIdentifiers.id_aes192_CBC.equals(algorithm)) + { + return createCipherKeyGenerator(random, 192); + } + else if (NISTObjectIdentifiers.id_aes256_CBC.equals(algorithm)) + { + return createCipherKeyGenerator(random, 256); + } + else if (PKCSObjectIdentifiers.des_EDE3_CBC.equals(algorithm)) + { + DESedeKeyGenerator keyGen = new DESedeKeyGenerator(); + + keyGen.init(new KeyGenerationParameters(random, 192)); + + return keyGen; + } + else if (NTTObjectIdentifiers.id_camellia128_cbc.equals(algorithm)) + { + return createCipherKeyGenerator(random, 128); + } + else if (NTTObjectIdentifiers.id_camellia192_cbc.equals(algorithm)) + { + return createCipherKeyGenerator(random, 192); + } + else if (NTTObjectIdentifiers.id_camellia256_cbc.equals(algorithm)) + { + return createCipherKeyGenerator(random, 256); + } + else if (KISAObjectIdentifiers.id_seedCBC.equals(algorithm)) + { + return createCipherKeyGenerator(random, 128); + } + else if (CMSAlgorithm.CAST5_CBC.equals(algorithm)) + { + return createCipherKeyGenerator(random, 128); + } + else if (OIWObjectIdentifiers.desCBC.equals(algorithm)) + { + DESKeyGenerator keyGen = new DESKeyGenerator(); + + keyGen.init(new KeyGenerationParameters(random, 64)); + + return keyGen; + } + else if (PKCSObjectIdentifiers.rc4.equals(algorithm)) + { + return createCipherKeyGenerator(random, 128); + } +// else if (PKCSObjectIdentifiers.RC2_CBC.equals(algorithm)) +// { +// cipher = new CBCBlockCipher(new RC2Engine()); +// } + else + { + throw new CMSException("cannot recognise cipher: " + algorithm); + } + + } + + private CipherKeyGenerator createCipherKeyGenerator(SecureRandom random, int keySize) + { + CipherKeyGenerator keyGen = new CipherKeyGenerator(); + + keyGen.init(new KeyGenerationParameters(random, keySize)); + + return keyGen; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/CMSUtils.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/CMSUtils.java new file mode 100644 index 00000000..9337a424 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/CMSUtils.java @@ -0,0 +1,99 @@ +package org.spongycastle.cms.jcajce; + +import java.io.IOException; +import java.security.AlgorithmParameters; +import java.security.Provider; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.cms.IssuerAndSerialNumber; +import org.spongycastle.asn1.x509.Certificate; +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.asn1.x509.TBSCertificateStructure; +import org.spongycastle.cms.CMSException; +import org.spongycastle.jcajce.util.JcaJceUtils; + +class CMSUtils +{ + static TBSCertificateStructure getTBSCertificateStructure( + X509Certificate cert) + throws CertificateEncodingException + { + return TBSCertificateStructure.getInstance(cert.getTBSCertificate()); + } + + static IssuerAndSerialNumber getIssuerAndSerialNumber(X509Certificate cert) + throws CertificateEncodingException + { + Certificate certStruct = Certificate.getInstance(cert.getEncoded()); + + return new IssuerAndSerialNumber(certStruct.getIssuer(), cert.getSerialNumber()); + } + + + static byte[] getSubjectKeyId(X509Certificate cert) + { + byte[] ext = cert.getExtensionValue(Extension.subjectKeyIdentifier.getId()); + + if (ext != null) + { + return ASN1OctetString.getInstance(ASN1OctetString.getInstance(ext).getOctets()).getOctets(); + } + else + { + return null; + } + } + + static EnvelopedDataHelper createContentHelper(Provider provider) + { + if (provider != null) + { + return new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); + } + else + { + return new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); + } + } + + static EnvelopedDataHelper createContentHelper(String providerName) + { + if (providerName != null) + { + return new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); + } + else + { + return new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); + } + } + + static ASN1Encodable extractParameters(AlgorithmParameters params) + throws CMSException + { + try + { + return JcaJceUtils.extractParameters(params); + } + catch (IOException e) + { + throw new CMSException("cannot extract parameters: " + e.getMessage(), e); + } + } + + static void loadParameters(AlgorithmParameters params, ASN1Encodable sParams) + throws CMSException + { + try + { + JcaJceUtils.loadParameters(params, sParams); + } + catch (IOException e) + { + throw new CMSException("error encoding algorithm parameters.", e); + } + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/DefaultJcaJceExtHelper.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/DefaultJcaJceExtHelper.java new file mode 100644 index 00000000..1285ff07 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/DefaultJcaJceExtHelper.java @@ -0,0 +1,26 @@ +package org.spongycastle.cms.jcajce; + +import java.security.PrivateKey; + +import javax.crypto.SecretKey; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.jcajce.util.DefaultJcaJceHelper; +import org.spongycastle.operator.SymmetricKeyUnwrapper; +import org.spongycastle.operator.jcajce.JceAsymmetricKeyUnwrapper; +import org.spongycastle.operator.jcajce.JceSymmetricKeyUnwrapper; + +class DefaultJcaJceExtHelper + extends DefaultJcaJceHelper + implements JcaJceExtHelper +{ + public JceAsymmetricKeyUnwrapper createAsymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, PrivateKey keyEncryptionKey) + { + return new JceAsymmetricKeyUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey); + } + + public SymmetricKeyUnwrapper createSymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, SecretKey keyEncryptionKey) + { + return new JceSymmetricKeyUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/EnvelopedDataHelper.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/EnvelopedDataHelper.java new file mode 100644 index 00000000..93de500e --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/EnvelopedDataHelper.java @@ -0,0 +1,668 @@ +package org.spongycastle.cms.jcajce; + +import java.security.AlgorithmParameterGenerator; +import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; +import java.util.HashMap; +import java.util.Map; + +import javax.crypto.Cipher; +import javax.crypto.KeyAgreement; +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.RC2ParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1Null; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.pkcs.RC2CBCParameter; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSAlgorithm; +import org.spongycastle.cms.CMSEnvelopedDataGenerator; +import org.spongycastle.cms.CMSException; +import org.spongycastle.operator.DefaultSecretKeySizeProvider; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.SecretKeySizeProvider; +import org.spongycastle.operator.SymmetricKeyUnwrapper; +import org.spongycastle.operator.jcajce.JceAsymmetricKeyUnwrapper; + +public class EnvelopedDataHelper +{ + protected static final SecretKeySizeProvider KEY_SIZE_PROVIDER = DefaultSecretKeySizeProvider.INSTANCE; + + protected static final Map BASE_CIPHER_NAMES = new HashMap(); + protected static final Map CIPHER_ALG_NAMES = new HashMap(); + protected static final Map MAC_ALG_NAMES = new HashMap(); + + static + { + BASE_CIPHER_NAMES.put(CMSAlgorithm.DES_CBC, "DES"); + BASE_CIPHER_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDE"); + BASE_CIPHER_NAMES.put(CMSAlgorithm.AES128_CBC, "AES"); + BASE_CIPHER_NAMES.put(CMSAlgorithm.AES192_CBC, "AES"); + BASE_CIPHER_NAMES.put(CMSAlgorithm.AES256_CBC, "AES"); + BASE_CIPHER_NAMES.put(CMSAlgorithm.RC2_CBC, "RC2"); + BASE_CIPHER_NAMES.put(CMSAlgorithm.CAST5_CBC, "CAST5"); + BASE_CIPHER_NAMES.put(CMSAlgorithm.CAMELLIA128_CBC, "Camellia"); + BASE_CIPHER_NAMES.put(CMSAlgorithm.CAMELLIA192_CBC, "Camellia"); + BASE_CIPHER_NAMES.put(CMSAlgorithm.CAMELLIA256_CBC, "Camellia"); + BASE_CIPHER_NAMES.put(CMSAlgorithm.SEED_CBC, "SEED"); + BASE_CIPHER_NAMES.put(PKCSObjectIdentifiers.rc4, "RC4"); + + CIPHER_ALG_NAMES.put(CMSAlgorithm.DES_CBC, "DES/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(CMSAlgorithm.RC2_CBC, "RC2/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDE/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(CMSAlgorithm.AES128_CBC, "AES/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(CMSAlgorithm.AES192_CBC, "AES/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(CMSAlgorithm.AES256_CBC, "AES/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(PKCSObjectIdentifiers.rsaEncryption, "RSA/ECB/PKCS1Padding"); + CIPHER_ALG_NAMES.put(CMSAlgorithm.CAST5_CBC, "CAST5/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(CMSAlgorithm.CAMELLIA128_CBC, "Camellia/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(CMSAlgorithm.CAMELLIA192_CBC, "Camellia/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(CMSAlgorithm.CAMELLIA256_CBC, "Camellia/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(CMSAlgorithm.SEED_CBC, "SEED/CBC/PKCS5Padding"); + CIPHER_ALG_NAMES.put(PKCSObjectIdentifiers.rc4, "RC4"); + + MAC_ALG_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDEMac"); + MAC_ALG_NAMES.put(CMSAlgorithm.AES128_CBC, "AESMac"); + MAC_ALG_NAMES.put(CMSAlgorithm.AES192_CBC, "AESMac"); + MAC_ALG_NAMES.put(CMSAlgorithm.AES256_CBC, "AESMac"); + MAC_ALG_NAMES.put(CMSAlgorithm.RC2_CBC, "RC2Mac"); + } + + private static final short[] rc2Table = { + 0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0, + 0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a, + 0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36, + 0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c, + 0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60, + 0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa, + 0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e, + 0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf, + 0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6, + 0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3, + 0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c, + 0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2, + 0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5, + 0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5, + 0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f, + 0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab + }; + + private static final short[] rc2Ekb = { + 0x5d, 0xbe, 0x9b, 0x8b, 0x11, 0x99, 0x6e, 0x4d, 0x59, 0xf3, 0x85, 0xa6, 0x3f, 0xb7, 0x83, 0xc5, + 0xe4, 0x73, 0x6b, 0x3a, 0x68, 0x5a, 0xc0, 0x47, 0xa0, 0x64, 0x34, 0x0c, 0xf1, 0xd0, 0x52, 0xa5, + 0xb9, 0x1e, 0x96, 0x43, 0x41, 0xd8, 0xd4, 0x2c, 0xdb, 0xf8, 0x07, 0x77, 0x2a, 0xca, 0xeb, 0xef, + 0x10, 0x1c, 0x16, 0x0d, 0x38, 0x72, 0x2f, 0x89, 0xc1, 0xf9, 0x80, 0xc4, 0x6d, 0xae, 0x30, 0x3d, + 0xce, 0x20, 0x63, 0xfe, 0xe6, 0x1a, 0xc7, 0xb8, 0x50, 0xe8, 0x24, 0x17, 0xfc, 0x25, 0x6f, 0xbb, + 0x6a, 0xa3, 0x44, 0x53, 0xd9, 0xa2, 0x01, 0xab, 0xbc, 0xb6, 0x1f, 0x98, 0xee, 0x9a, 0xa7, 0x2d, + 0x4f, 0x9e, 0x8e, 0xac, 0xe0, 0xc6, 0x49, 0x46, 0x29, 0xf4, 0x94, 0x8a, 0xaf, 0xe1, 0x5b, 0xc3, + 0xb3, 0x7b, 0x57, 0xd1, 0x7c, 0x9c, 0xed, 0x87, 0x40, 0x8c, 0xe2, 0xcb, 0x93, 0x14, 0xc9, 0x61, + 0x2e, 0xe5, 0xcc, 0xf6, 0x5e, 0xa8, 0x5c, 0xd6, 0x75, 0x8d, 0x62, 0x95, 0x58, 0x69, 0x76, 0xa1, + 0x4a, 0xb5, 0x55, 0x09, 0x78, 0x33, 0x82, 0xd7, 0xdd, 0x79, 0xf5, 0x1b, 0x0b, 0xde, 0x26, 0x21, + 0x28, 0x74, 0x04, 0x97, 0x56, 0xdf, 0x3c, 0xf0, 0x37, 0x39, 0xdc, 0xff, 0x06, 0xa4, 0xea, 0x42, + 0x08, 0xda, 0xb4, 0x71, 0xb0, 0xcf, 0x12, 0x7a, 0x4e, 0xfa, 0x6c, 0x1d, 0x84, 0x00, 0xc8, 0x7f, + 0x91, 0x45, 0xaa, 0x2b, 0xc2, 0xb1, 0x8f, 0xd5, 0xba, 0xf2, 0xad, 0x19, 0xb2, 0x67, 0x36, 0xf7, + 0x0f, 0x0a, 0x92, 0x7d, 0xe3, 0x9d, 0xe9, 0x90, 0x3e, 0x23, 0x27, 0x66, 0x13, 0xec, 0x81, 0x15, + 0xbd, 0x22, 0xbf, 0x9f, 0x7e, 0xa9, 0x51, 0x4b, 0x4c, 0xfb, 0x02, 0xd3, 0x70, 0x86, 0x31, 0xe7, + 0x3b, 0x05, 0x03, 0x54, 0x60, 0x48, 0x65, 0x18, 0xd2, 0xcd, 0x5f, 0x32, 0x88, 0x0e, 0x35, 0xfd + }; + + private JcaJceExtHelper helper; + + EnvelopedDataHelper(JcaJceExtHelper helper) + { + this.helper = helper; + } + + String getBaseCipherName(ASN1ObjectIdentifier algorithm) + { + String name = (String)BASE_CIPHER_NAMES.get(algorithm); + + if (name == null) + { + return algorithm.getId(); + } + + return name; + } + + Key getJceKey(GenericKey key) + { + if (key.getRepresentation() instanceof Key) + { + return (Key)key.getRepresentation(); + } + + if (key.getRepresentation() instanceof byte[]) + { + return new SecretKeySpec((byte[])key.getRepresentation(), "ENC"); + } + + throw new IllegalArgumentException("unknown generic key type"); + } + + public Key getJceKey(ASN1ObjectIdentifier algorithm, GenericKey key) + { + if (key.getRepresentation() instanceof Key) + { + return (Key)key.getRepresentation(); + } + + if (key.getRepresentation() instanceof byte[]) + { + return new SecretKeySpec((byte[])key.getRepresentation(), getBaseCipherName(algorithm)); + } + + throw new IllegalArgumentException("unknown generic key type"); + } + + public void keySizeCheck(AlgorithmIdentifier keyAlgorithm, Key key) + throws CMSException + { + int expectedKeySize = EnvelopedDataHelper.KEY_SIZE_PROVIDER.getKeySize(keyAlgorithm); + if (expectedKeySize > 0) + { + byte[] keyEnc = null; + + try + { + keyEnc = key.getEncoded(); + } + catch (Exception e) + { + // ignore - we're using a HSM... + } + + if (keyEnc != null) + { + if (keyEnc.length * 8 != expectedKeySize) + { + throw new CMSException("Expected key size for algorithm OID not found in recipient."); + } + } + } + } + + Cipher createCipher(ASN1ObjectIdentifier algorithm) + throws CMSException + { + try + { + String cipherName = (String)CIPHER_ALG_NAMES.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 CMSException("cannot create cipher: " + e.getMessage(), e); + } + } + + Mac createMac(ASN1ObjectIdentifier algorithm) + throws CMSException + { + try + { + String macName = (String)MAC_ALG_NAMES.get(algorithm); + + if (macName != null) + { + try + { + // this is reversed as the Sun policy files now allow unlimited strength RSA + return helper.createMac(macName); + } + catch (NoSuchAlgorithmException e) + { + // Ignore + } + } + return helper.createMac(algorithm.getId()); + } + catch (GeneralSecurityException e) + { + throw new CMSException("cannot create mac: " + e.getMessage(), e); + } + } + + Cipher createRFC3211Wrapper(ASN1ObjectIdentifier algorithm) + throws CMSException + { + String cipherName = (String)BASE_CIPHER_NAMES.get(algorithm); + + if (cipherName == null) + { + throw new CMSException("no name for " + algorithm); + } + + cipherName += "RFC3211Wrap"; + + try + { + return helper.createCipher(cipherName); + } + catch (GeneralSecurityException e) + { + throw new CMSException("cannot create cipher: " + e.getMessage(), e); + } + } + + KeyAgreement createKeyAgreement(ASN1ObjectIdentifier algorithm) + throws CMSException + { + try + { + String agreementName = (String)BASE_CIPHER_NAMES.get(algorithm); + + if (agreementName != null) + { + try + { + // this is reversed as the Sun policy files now allow unlimited strength RSA + return helper.createKeyAgreement(agreementName); + } + catch (NoSuchAlgorithmException e) + { + // Ignore + } + } + return helper.createKeyAgreement(algorithm.getId()); + } + catch (GeneralSecurityException e) + { + throw new CMSException("cannot create key pair generator: " + e.getMessage(), e); + } + } + + AlgorithmParameterGenerator createAlgorithmParameterGenerator(ASN1ObjectIdentifier algorithm) + throws GeneralSecurityException + { + String algorithmName = (String)BASE_CIPHER_NAMES.get(algorithm); + + if (algorithmName != null) + { + try + { + // this is reversed as the Sun policy files now allow unlimited strength RSA + return helper.createAlgorithmParameterGenerator(algorithmName); + } + catch (NoSuchAlgorithmException e) + { + // Ignore + } + } + return helper.createAlgorithmParameterGenerator(algorithm.getId()); + } + + public Cipher createContentCipher(final Key sKey, final AlgorithmIdentifier encryptionAlgID) + throws CMSException + { + return (Cipher)execute(new JCECallback() + { + public Object doInJCE() + throws CMSException, InvalidAlgorithmParameterException, + InvalidKeyException, InvalidParameterSpecException, NoSuchAlgorithmException, + NoSuchPaddingException, NoSuchProviderException + { + Cipher cipher = createCipher(encryptionAlgID.getAlgorithm()); + ASN1Encodable sParams = encryptionAlgID.getParameters(); + String encAlg = encryptionAlgID.getAlgorithm().getId(); + + if (sParams != null && !(sParams instanceof ASN1Null)) + { + try + { + AlgorithmParameters params = createAlgorithmParameters(encryptionAlgID.getAlgorithm()); + + CMSUtils.loadParameters(params, sParams); + + cipher.init(Cipher.DECRYPT_MODE, sKey, params); + } + catch (NoSuchAlgorithmException e) + { + if (encAlg.equals(CMSAlgorithm.DES_CBC.getId()) + || encAlg.equals(CMSEnvelopedDataGenerator.DES_EDE3_CBC) + || encAlg.equals(CMSEnvelopedDataGenerator.IDEA_CBC) + || encAlg.equals(CMSEnvelopedDataGenerator.AES128_CBC) + || encAlg.equals(CMSEnvelopedDataGenerator.AES192_CBC) + || encAlg.equals(CMSEnvelopedDataGenerator.AES256_CBC)) + { + cipher.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec( + ASN1OctetString.getInstance(sParams).getOctets())); + } + else + { + throw e; + } + } + } + else + { + if (encAlg.equals(CMSAlgorithm.DES_CBC.getId()) + || encAlg.equals(CMSEnvelopedDataGenerator.DES_EDE3_CBC) + || encAlg.equals(CMSEnvelopedDataGenerator.IDEA_CBC) + || encAlg.equals(CMSEnvelopedDataGenerator.CAST5_CBC)) + { + cipher.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec(new byte[8])); + } + else + { + cipher.init(Cipher.DECRYPT_MODE, sKey); + } + } + + return cipher; + } + }); + } + + Mac createContentMac(final Key sKey, final AlgorithmIdentifier macAlgId) + throws CMSException + { + return (Mac)execute(new JCECallback() + { + public Object doInJCE() + throws CMSException, InvalidAlgorithmParameterException, + InvalidKeyException, InvalidParameterSpecException, NoSuchAlgorithmException, + NoSuchPaddingException, NoSuchProviderException + { + Mac mac = createMac(macAlgId.getAlgorithm()); + ASN1Encodable sParams = macAlgId.getParameters(); + String macAlg = macAlgId.getAlgorithm().getId(); + + if (sParams != null && !(sParams instanceof ASN1Null)) + { + try + { + AlgorithmParameters params = createAlgorithmParameters(macAlgId.getAlgorithm()); + + CMSUtils.loadParameters(params, sParams); + + mac.init(sKey, params.getParameterSpec(IvParameterSpec.class)); + } + catch (NoSuchAlgorithmException e) + { + throw e; + } + } + else + { + mac.init(sKey); + } + + return mac; + } + }); + } + + AlgorithmParameters createAlgorithmParameters(ASN1ObjectIdentifier algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + String algorithmName = (String)BASE_CIPHER_NAMES.get(algorithm); + + if (algorithmName != null) + { + try + { + // this is reversed as the Sun policy files now allow unlimited strength RSA + return helper.createAlgorithmParameters(algorithmName); + } + catch (NoSuchAlgorithmException e) + { + // Ignore + } + } + return helper.createAlgorithmParameters(algorithm.getId()); + } + + + KeyPairGenerator createKeyPairGenerator(ASN1ObjectIdentifier algorithm) + throws CMSException + { + try + { + String cipherName = (String)BASE_CIPHER_NAMES.get(algorithm); + + if (cipherName != null) + { + try + { + // this is reversed as the Sun policy files now allow unlimited strength RSA + return helper.createKeyPairGenerator(cipherName); + } + catch (NoSuchAlgorithmException e) + { + // Ignore + } + } + return helper.createKeyPairGenerator(algorithm.getId()); + } + catch (GeneralSecurityException e) + { + throw new CMSException("cannot create key pair generator: " + e.getMessage(), e); + } + } + + public KeyGenerator createKeyGenerator(ASN1ObjectIdentifier algorithm) + throws CMSException + { + try + { + String cipherName = (String)BASE_CIPHER_NAMES.get(algorithm); + + if (cipherName != null) + { + try + { + // this is reversed as the Sun policy files now allow unlimited strength RSA + return helper.createKeyGenerator(cipherName); + } + catch (NoSuchAlgorithmException e) + { + // Ignore + } + } + return helper.createKeyGenerator(algorithm.getId()); + } + catch (GeneralSecurityException e) + { + throw new CMSException("cannot create key generator: " + e.getMessage(), e); + } + } + + AlgorithmParameters generateParameters(ASN1ObjectIdentifier encryptionOID, SecretKey encKey, SecureRandom rand) + throws CMSException + { + try + { + AlgorithmParameterGenerator pGen = createAlgorithmParameterGenerator(encryptionOID); + + if (encryptionOID.equals(CMSAlgorithm.RC2_CBC)) + { + byte[] iv = new byte[8]; + + rand.nextBytes(iv); + + try + { + pGen.init(new RC2ParameterSpec(encKey.getEncoded().length * 8, iv), rand); + } + catch (InvalidAlgorithmParameterException e) + { + throw new CMSException("parameters generation error: " + e, e); + } + } + + return pGen.generateParameters(); + } + catch (NoSuchAlgorithmException e) + { + return null; + } + catch (GeneralSecurityException e) + { + throw new CMSException("exception creating algorithm parameter generator: " + e, e); + } + } + + AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier encryptionOID, AlgorithmParameters params) + throws CMSException + { + ASN1Encodable asn1Params; + if (params != null) + { + asn1Params = CMSUtils.extractParameters(params); + } + else + { + asn1Params = DERNull.INSTANCE; + } + + return new AlgorithmIdentifier( + encryptionOID, + asn1Params); + } + + static Object execute(JCECallback callback) throws CMSException + { + try + { + return callback.doInJCE(); + } + catch (NoSuchAlgorithmException e) + { + throw new CMSException("can't find algorithm.", e); + } + catch (InvalidKeyException e) + { + throw new CMSException("key invalid in message.", e); + } + catch (NoSuchProviderException e) + { + throw new CMSException("can't find provider.", e); + } + catch (NoSuchPaddingException e) + { + throw new CMSException("required padding not supported.", e); + } + catch (InvalidAlgorithmParameterException e) + { + throw new CMSException("algorithm parameters invalid.", e); + } + catch (InvalidParameterSpecException e) + { + throw new CMSException("MAC algorithm parameter spec invalid.", e); + } + } + + public KeyFactory createKeyFactory(ASN1ObjectIdentifier algorithm) + throws CMSException + { + try + { + String cipherName = (String)BASE_CIPHER_NAMES.get(algorithm); + + if (cipherName != null) + { + try + { + // this is reversed as the Sun policy files now allow unlimited strength RSA + return helper.createKeyFactory(cipherName); + } + catch (NoSuchAlgorithmException e) + { + // Ignore + } + } + return helper.createKeyFactory(algorithm.getId()); + } + catch (GeneralSecurityException e) + { + throw new CMSException("cannot create key factory: " + e.getMessage(), e); + } + } + + public JceAsymmetricKeyUnwrapper createAsymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, PrivateKey keyEncryptionKey) + { + return helper.createAsymmetricUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey); + } + + public SymmetricKeyUnwrapper createSymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, SecretKey keyEncryptionKey) + { + return helper.createSymmetricUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey); + } + + public AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier macOID, AlgorithmParameterSpec paramSpec) + { + if (paramSpec instanceof IvParameterSpec) + { + return new AlgorithmIdentifier(macOID, new DEROctetString(((IvParameterSpec)paramSpec).getIV())); + } + + if (paramSpec instanceof RC2ParameterSpec) + { + RC2ParameterSpec rc2Spec = (RC2ParameterSpec)paramSpec; + + int effKeyBits = ((RC2ParameterSpec)paramSpec).getEffectiveKeyBits(); + + if (effKeyBits != -1) + { + int parameterVersion; + + if (effKeyBits < 256) + { + parameterVersion = rc2Table[effKeyBits]; + } + else + { + parameterVersion = effKeyBits; + } + + return new AlgorithmIdentifier(macOID, new RC2CBCParameter(parameterVersion, rc2Spec.getIV())); + } + + return new AlgorithmIdentifier(macOID, new RC2CBCParameter(rc2Spec.getIV())); + } + + throw new IllegalStateException("unknown parameter spec: " + paramSpec); + } + + static interface JCECallback + { + Object doInJCE() + throws CMSException, InvalidAlgorithmParameterException, InvalidKeyException, InvalidParameterSpecException, + NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaJceExtHelper.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaJceExtHelper.java new file mode 100644 index 00000000..e29f1bd9 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaJceExtHelper.java @@ -0,0 +1,18 @@ +package org.spongycastle.cms.jcajce; + +import java.security.PrivateKey; + +import javax.crypto.SecretKey; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.jcajce.util.JcaJceHelper; +import org.spongycastle.operator.SymmetricKeyUnwrapper; +import org.spongycastle.operator.jcajce.JceAsymmetricKeyUnwrapper; + +public interface JcaJceExtHelper + extends JcaJceHelper +{ + JceAsymmetricKeyUnwrapper createAsymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, PrivateKey keyEncryptionKey); + + SymmetricKeyUnwrapper createSymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, SecretKey keyEncryptionKey); +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSelectorConverter.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSelectorConverter.java new file mode 100644 index 00000000..6dc5c9a8 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSelectorConverter.java @@ -0,0 +1,55 @@ +package org.spongycastle.cms.jcajce; + +import java.io.IOException; +import java.security.cert.X509CertSelector; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.cms.KeyTransRecipientId; +import org.spongycastle.cms.SignerId; + +public class JcaSelectorConverter +{ + public JcaSelectorConverter() + { + + } + + public SignerId getSignerId(X509CertSelector certSelector) + { + try + { + if (certSelector.getSubjectKeyIdentifier() != null) + { + return new SignerId(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber(), ASN1OctetString.getInstance(certSelector.getSubjectKeyIdentifier()).getOctets()); + } + else + { + return new SignerId(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber()); + } + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to convert issuer: " + e.getMessage()); + } + } + + public KeyTransRecipientId getKeyTransRecipientId(X509CertSelector certSelector) + { + try + { + if (certSelector.getSubjectKeyIdentifier() != null) + { + return new KeyTransRecipientId(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber(), ASN1OctetString.getInstance(certSelector.getSubjectKeyIdentifier()).getOctets()); + } + else + { + return new KeyTransRecipientId(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber()); + } + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to convert issuer: " + e.getMessage()); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSignerId.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSignerId.java new file mode 100644 index 00000000..27934bf6 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSignerId.java @@ -0,0 +1,56 @@ +package org.spongycastle.cms.jcajce; + +import java.math.BigInteger; +import java.security.cert.X509Certificate; + +import javax.security.auth.x500.X500Principal; + +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.cms.SignerId; + +public class JcaSignerId + extends SignerId +{ + /** + * Construct a signer identifier based on the issuer, serial number and subject key identifier (if present) of the passed in + * certificate. + * + * @param certificate certificate providing the issue and serial number and subject key identifier. + */ + public JcaSignerId(X509Certificate certificate) + { + super(convertPrincipal(certificate.getIssuerX500Principal()), certificate.getSerialNumber(), CMSUtils.getSubjectKeyId(certificate)); + } + + /** + * Construct a signer identifier based on the provided issuer and serial number.. + * + * @param issuer the issuer to use. + * @param serialNumber the serial number to use. + */ + public JcaSignerId(X500Principal issuer, BigInteger serialNumber) + { + super(convertPrincipal(issuer), serialNumber); + } + + /** + * Construct a signer identifier based on the provided issuer, serial number, and subjectKeyId.. + * + * @param issuer the issuer to use. + * @param serialNumber the serial number to use. + * @param subjectKeyId the subject key ID to use. + */ + public JcaSignerId(X500Principal issuer, BigInteger serialNumber, byte[] subjectKeyId) + { + super(convertPrincipal(issuer), serialNumber, subjectKeyId); + } + + private static X500Name convertPrincipal(X500Principal issuer) + { + if (issuer == null) + { + return null; + } + return X500Name.getInstance(issuer.getEncoded()); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSignerInfoGeneratorBuilder.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSignerInfoGeneratorBuilder.java new file mode 100644 index 00000000..79ad9070 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSignerInfoGeneratorBuilder.java @@ -0,0 +1,68 @@ +package org.spongycastle.cms.jcajce; + +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; + +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.cert.jcajce.JcaX509CertificateHolder; +import org.spongycastle.cms.CMSAttributeTableGenerator; +import org.spongycastle.cms.SignerInfoGenerator; +import org.spongycastle.cms.SignerInfoGeneratorBuilder; +import org.spongycastle.operator.ContentSigner; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.operator.OperatorCreationException; + +public class JcaSignerInfoGeneratorBuilder +{ + private SignerInfoGeneratorBuilder builder; + + public JcaSignerInfoGeneratorBuilder(DigestCalculatorProvider digestProvider) + { + builder = new SignerInfoGeneratorBuilder(digestProvider); + } + + /** + * 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/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSignerInfoVerifierBuilder.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSignerInfoVerifierBuilder.java new file mode 100644 index 00000000..c5077819 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSignerInfoVerifierBuilder.java @@ -0,0 +1,180 @@ +package org.spongycastle.cms.jcajce; + +import java.security.Provider; +import java.security.PublicKey; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.cms.CMSSignatureAlgorithmNameGenerator; +import org.spongycastle.cms.DefaultCMSSignatureAlgorithmNameGenerator; +import org.spongycastle.cms.SignerInformationVerifier; +import org.spongycastle.operator.ContentVerifierProvider; +import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.operator.SignatureAlgorithmIdentifierFinder; +import org.spongycastle.operator.jcajce.JcaContentVerifierProviderBuilder; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSimpleSignerInfoGeneratorBuilder.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSimpleSignerInfoGeneratorBuilder.java new file mode 100644 index 00000000..87aca5c7 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSimpleSignerInfoGeneratorBuilder.java @@ -0,0 +1,202 @@ +package org.spongycastle.cms.jcajce; + +import java.security.PrivateKey; +import java.security.Provider; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; + +import org.spongycastle.asn1.cms.AttributeTable; +import org.spongycastle.cert.jcajce.JcaX509CertificateHolder; +import org.spongycastle.cms.CMSAttributeTableGenerator; +import org.spongycastle.cms.DefaultSignedAttributeTableGenerator; +import org.spongycastle.cms.SignerInfoGenerator; +import org.spongycastle.cms.SignerInfoGeneratorBuilder; +import org.spongycastle.operator.ContentSigner; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.operator.jcajce.JcaContentSignerBuilder; +import org.spongycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; + +/** + * Use this class if you are using a provider that has all the facilities you + * need. + * <p> + * For example: + * <pre> + * CMSSignedDataGenerator gen = new CMSSignedDataGenerator(); + * ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("SC").build(signKP.getPrivate()); + * + * gen.addSignerInfoGenerator( + * new JcaSignerInfoGeneratorBuilder( + * new JcaDigestCalculatorProviderBuilder().setProvider("SC").build()) + * .build(sha1Signer, signCert)); + * </pre> + * becomes: + * <pre> + * CMSSignedDataGenerator gen = new CMSSignedDataGenerator(); + * + * gen.addSignerInfoGenerator( + * new JcaSimpleSignerInfoGeneratorBuilder() + * .setProvider("SC") + * .build("SHA1withRSA", signKP.getPrivate(), signCert)); + * </pre> + */ +public class JcaSimpleSignerInfoGeneratorBuilder +{ + private Helper helper; + + private boolean hasNoSignedAttributes; + private CMSAttributeTableGenerator signedGen; + private CMSAttributeTableGenerator unsignedGen; + + public JcaSimpleSignerInfoGeneratorBuilder() + throws OperatorCreationException + { + this.helper = new Helper(); + } + + public JcaSimpleSignerInfoGeneratorBuilder setProvider(String providerName) + throws OperatorCreationException + { + this.helper = new NamedHelper(providerName); + + return this; + } + + public JcaSimpleSignerInfoGeneratorBuilder setProvider(Provider provider) + throws OperatorCreationException + { + this.helper = new ProviderHelper(provider); + + return this; + } + + /** + * 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 JcaSimpleSignerInfoGeneratorBuilder setDirectSignature(boolean hasNoSignedAttributes) + { + this.hasNoSignedAttributes = hasNoSignedAttributes; + + return this; + } + + public JcaSimpleSignerInfoGeneratorBuilder setSignedAttributeGenerator(CMSAttributeTableGenerator signedGen) + { + this.signedGen = signedGen; + + return this; + } + + /** + * set up a DefaultSignedAttributeTableGenerator primed with the passed in AttributeTable. + * + * @param attrTable table of attributes for priming generator + * @return this. + */ + public JcaSimpleSignerInfoGeneratorBuilder setSignedAttributeGenerator(AttributeTable attrTable) + { + this.signedGen = new DefaultSignedAttributeTableGenerator(attrTable); + + return this; + } + + public JcaSimpleSignerInfoGeneratorBuilder setUnsignedAttributeGenerator(CMSAttributeTableGenerator unsignedGen) + { + this.unsignedGen = unsignedGen; + + return this; + } + + public SignerInfoGenerator build(String algorithmName, PrivateKey privateKey, X509Certificate certificate) + throws OperatorCreationException, CertificateEncodingException + { + ContentSigner contentSigner = helper.createContentSigner(algorithmName, privateKey); + + return configureAndBuild().build(contentSigner, new JcaX509CertificateHolder(certificate)); + } + + public SignerInfoGenerator build(String algorithmName, PrivateKey privateKey, byte[] keyIdentifier) + throws OperatorCreationException, CertificateEncodingException + { + ContentSigner contentSigner = helper.createContentSigner(algorithmName, privateKey); + + return configureAndBuild().build(contentSigner, keyIdentifier); + } + + private SignerInfoGeneratorBuilder configureAndBuild() + throws OperatorCreationException + { + SignerInfoGeneratorBuilder infoGeneratorBuilder = new SignerInfoGeneratorBuilder(helper.createDigestCalculatorProvider()); + + infoGeneratorBuilder.setDirectSignature(hasNoSignedAttributes); + infoGeneratorBuilder.setSignedAttributeGenerator(signedGen); + infoGeneratorBuilder.setUnsignedAttributeGenerator(unsignedGen); + + return infoGeneratorBuilder; + } + + private class Helper + { + ContentSigner createContentSigner(String algorithm, PrivateKey privateKey) + throws OperatorCreationException + { + return new JcaContentSignerBuilder(algorithm).build(privateKey); + } + + DigestCalculatorProvider createDigestCalculatorProvider() + throws OperatorCreationException + { + return new JcaDigestCalculatorProviderBuilder().build(); + } + } + + private class NamedHelper + extends Helper + { + private final String providerName; + + public NamedHelper(String providerName) + { + this.providerName = providerName; + } + + ContentSigner createContentSigner(String algorithm, PrivateKey privateKey) + throws OperatorCreationException + { + return new JcaContentSignerBuilder(algorithm).setProvider(providerName).build(privateKey); + } + + DigestCalculatorProvider createDigestCalculatorProvider() + throws OperatorCreationException + { + return new JcaDigestCalculatorProviderBuilder().setProvider(providerName).build(); + } + } + + private class ProviderHelper + extends Helper + { + private final Provider provider; + + public ProviderHelper(Provider provider) + { + this.provider = provider; + } + + ContentSigner createContentSigner(String algorithm, PrivateKey privateKey) + throws OperatorCreationException + { + return new JcaContentSignerBuilder(algorithm).setProvider(provider).build(privateKey); + } + + DigestCalculatorProvider createDigestCalculatorProvider() + throws OperatorCreationException + { + return new JcaDigestCalculatorProviderBuilder().setProvider(provider).build(); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSimpleSignerInfoVerifierBuilder.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSimpleSignerInfoVerifierBuilder.java new file mode 100644 index 00000000..4463b065 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSimpleSignerInfoVerifierBuilder.java @@ -0,0 +1,150 @@ +package org.spongycastle.cms.jcajce; + +import java.security.Provider; +import java.security.PublicKey; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.cms.DefaultCMSSignatureAlgorithmNameGenerator; +import org.spongycastle.cms.SignerInformationVerifier; +import org.spongycastle.operator.ContentVerifierProvider; +import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.operator.jcajce.JcaContentVerifierProviderBuilder; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaX509CertSelectorConverter.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaX509CertSelectorConverter.java new file mode 100644 index 00000000..ceb138ed --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaX509CertSelectorConverter.java @@ -0,0 +1,24 @@ +package org.spongycastle.cms.jcajce; + +import java.security.cert.X509CertSelector; + +import org.spongycastle.cms.KeyTransRecipientId; +import org.spongycastle.cms.SignerId; + +public class JcaX509CertSelectorConverter + extends org.spongycastle.cert.selector.jcajce.JcaX509CertSelectorConverter +{ + public JcaX509CertSelectorConverter() + { + } + + public X509CertSelector getCertSelector(KeyTransRecipientId recipientId) + { + return doConversion(recipientId.getIssuer(), recipientId.getSerialNumber(), recipientId.getSubjectKeyIdentifier()); + } + + public X509CertSelector getCertSelector(SignerId signerId) + { + return doConversion(signerId.getIssuer(), signerId.getSerialNumber(), signerId.getSubjectKeyIdentifier()); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JceAlgorithmIdentifierConverter.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceAlgorithmIdentifierConverter.java new file mode 100644 index 00000000..32007919 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceAlgorithmIdentifierConverter.java @@ -0,0 +1,64 @@ +package org.spongycastle.cms.jcajce; + + +import java.security.AlgorithmParameters; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.SecureRandom; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSException; + +public class JceAlgorithmIdentifierConverter +{ + private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); + private SecureRandom random; + + public JceAlgorithmIdentifierConverter() + { + } + + public JceAlgorithmIdentifierConverter setProvider(Provider provider) + { + this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); + + return this; + } + + public JceAlgorithmIdentifierConverter setProvider(String providerName) + { + this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); + + return this; + } + + public AlgorithmParameters getAlgorithmParameters(AlgorithmIdentifier algorithmIdentifier) + throws CMSException + { + ASN1Encodable parameters = algorithmIdentifier.getParameters(); + + if (parameters == null) + { + return null; + } + + try + { + AlgorithmParameters params = helper.createAlgorithmParameters(algorithmIdentifier.getAlgorithm()); + + CMSUtils.loadParameters(params, algorithmIdentifier.getParameters()); + + return params; + } + catch (NoSuchAlgorithmException e) + { + throw new CMSException("can't find parameters for algorithm", e); + } + catch (NoSuchProviderException e) + { + throw new CMSException("can't find provider for algorithm", e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java new file mode 100644 index 00000000..5711df3d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java @@ -0,0 +1,160 @@ +package org.spongycastle.cms.jcajce; + +import java.io.OutputStream; +import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; +import java.security.Provider; +import java.security.SecureRandom; + +import javax.crypto.Cipher; +import javax.crypto.CipherOutputStream; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSException; +import org.spongycastle.operator.DefaultSecretKeySizeProvider; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.OutputEncryptor; +import org.spongycastle.operator.SecretKeySizeProvider; +import org.spongycastle.operator.jcajce.JceGenericKey; + +public class JceCMSContentEncryptorBuilder +{ + private static final SecretKeySizeProvider KEY_SIZE_PROVIDER = DefaultSecretKeySizeProvider.INSTANCE; + + + private final ASN1ObjectIdentifier encryptionOID; + private final int keySize; + + private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); + private SecureRandom random; + + public JceCMSContentEncryptorBuilder(ASN1ObjectIdentifier encryptionOID) + { + this(encryptionOID, KEY_SIZE_PROVIDER.getKeySize(encryptionOID)); + } + + public JceCMSContentEncryptorBuilder(ASN1ObjectIdentifier encryptionOID, int keySize) + { + this.encryptionOID = encryptionOID; + this.keySize = keySize; + + int fixedSize = KEY_SIZE_PROVIDER.getKeySize(encryptionOID); + + if (encryptionOID.equals(PKCSObjectIdentifiers.des_EDE3_CBC)) + { + if (keySize != 168 && keySize != fixedSize) + { + throw new IllegalArgumentException("incorrect keySize for encryptionOID passed to builder."); + } + } + else + { + if (fixedSize > 0 && fixedSize != keySize) + { + throw new IllegalArgumentException("incorrect keySize for encryptionOID passed to builder."); + } + } + } + + public JceCMSContentEncryptorBuilder setProvider(Provider provider) + { + this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); + + return this; + } + + public JceCMSContentEncryptorBuilder setProvider(String providerName) + { + this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); + + return this; + } + + public JceCMSContentEncryptorBuilder setSecureRandom(SecureRandom random) + { + this.random = random; + + return this; + } + + public OutputEncryptor build() + throws CMSException + { + return new CMSOutputEncryptor(encryptionOID, keySize, random); + } + + private class CMSOutputEncryptor + implements OutputEncryptor + { + private SecretKey encKey; + private AlgorithmIdentifier algorithmIdentifier; + private Cipher cipher; + + CMSOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, SecureRandom random) + throws CMSException + { + KeyGenerator keyGen = helper.createKeyGenerator(encryptionOID); + + if (random == null) + { + random = new SecureRandom(); + } + + if (keySize < 0) + { + keyGen.init(random); + } + else + { + if (encryptionOID.equals(PKCSObjectIdentifiers.des_EDE3_CBC) && keySize == 192) + { + keySize = 168; + } + keyGen.init(keySize, random); + } + + cipher = helper.createCipher(encryptionOID); + encKey = keyGen.generateKey(); + AlgorithmParameters params = helper.generateParameters(encryptionOID, encKey, random); + + try + { + cipher.init(Cipher.ENCRYPT_MODE, encKey, params, random); + } + catch (GeneralSecurityException e) + { + throw new CMSException("unable to initialize cipher: " + e.getMessage(), e); + } + + // + // If params are null we try and second guess on them as some providers don't provide + // algorithm parameter generation explicity but instead generate them under the hood. + // + if (params == null) + { + params = cipher.getParameters(); + } + + algorithmIdentifier = helper.getAlgorithmIdentifier(encryptionOID, params); + } + + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return algorithmIdentifier; + } + + public OutputStream getOutputStream(OutputStream dOut) + { + return new CipherOutputStream(dOut, cipher); + } + + public GenericKey getKey() + { + return new JceGenericKey(algorithmIdentifier, encKey); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java new file mode 100644 index 00000000..d6097471 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java @@ -0,0 +1,155 @@ +package org.spongycastle.cms.jcajce; + +import java.io.OutputStream; +import java.security.AlgorithmParameterGenerator; +import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.RC2ParameterSpec; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSException; +import org.spongycastle.jcajce.io.MacOutputStream; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.MacCalculator; +import org.spongycastle.operator.jcajce.JceGenericKey; + +public class JceCMSMacCalculatorBuilder +{ + private final ASN1ObjectIdentifier macOID; + private final int keySize; + + private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); + private SecureRandom random; + + public JceCMSMacCalculatorBuilder(ASN1ObjectIdentifier macOID) + { + this(macOID, -1); + } + + public JceCMSMacCalculatorBuilder(ASN1ObjectIdentifier macOID, int keySize) + { + this.macOID = macOID; + this.keySize = keySize; + } + + public JceCMSMacCalculatorBuilder setProvider(Provider provider) + { + this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); + + return this; + } + + public JceCMSMacCalculatorBuilder setProvider(String providerName) + { + this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); + + return this; + } + + public JceCMSMacCalculatorBuilder setSecureRandom(SecureRandom random) + { + this.random = random; + + return this; + } + + public MacCalculator build() + throws CMSException + { + return new CMSMacCalculator(macOID, keySize, random); + } + + private class CMSMacCalculator + implements MacCalculator + { + private SecretKey encKey; + private AlgorithmIdentifier algorithmIdentifier; + private Mac mac; + private SecureRandom random; + + CMSMacCalculator(ASN1ObjectIdentifier macOID, int keySize, SecureRandom random) + throws CMSException + { + KeyGenerator keyGen = helper.createKeyGenerator(macOID); + + if (random == null) + { + random = new SecureRandom(); + } + + this.random = random; + + if (keySize < 0) + { + keyGen.init(random); + } + else + { + keyGen.init(keySize, random); + } + + encKey = keyGen.generateKey(); + + AlgorithmParameterSpec paramSpec = generateParameterSpec(macOID, encKey); + + algorithmIdentifier = helper.getAlgorithmIdentifier(macOID, paramSpec); + mac = helper.createContentMac(encKey, algorithmIdentifier); + } + + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return algorithmIdentifier; + } + + public OutputStream getOutputStream() + { + return new MacOutputStream(mac); + } + + public byte[] getMac() + { + return mac.doFinal(); + } + + public GenericKey getKey() + { + return new JceGenericKey(algorithmIdentifier, encKey); + } + + protected AlgorithmParameterSpec generateParameterSpec(ASN1ObjectIdentifier macOID, SecretKey encKey) + throws CMSException + { + try + { + if (macOID.equals(PKCSObjectIdentifiers.RC2_CBC)) + { + byte[] iv = new byte[8]; + + random.nextBytes(iv); + + return new RC2ParameterSpec(encKey.getEncoded().length * 8, iv); + } + + AlgorithmParameterGenerator pGen = helper.createAlgorithmParameterGenerator(macOID); + + AlgorithmParameters p = pGen.generateParameters(); + + return p.getParameterSpec(IvParameterSpec.class); + } + catch (GeneralSecurityException e) + { + return null; + } + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKAuthenticatedRecipient.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKAuthenticatedRecipient.java new file mode 100644 index 00000000..55a19d54 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKAuthenticatedRecipient.java @@ -0,0 +1,61 @@ +package org.spongycastle.cms.jcajce; + +import java.io.OutputStream; +import java.security.Key; + +import javax.crypto.Mac; +import javax.crypto.SecretKey; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.RecipientOperator; +import org.spongycastle.jcajce.io.MacOutputStream; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.MacCalculator; +import org.spongycastle.operator.jcajce.JceGenericKey; + + +/** + * the KeyTransRecipientInformation class for a recipient who has been sent a secret + * key encrypted using their public key that needs to be used to + * extract the message. + */ +public class JceKEKAuthenticatedRecipient + extends JceKEKRecipient +{ + public JceKEKAuthenticatedRecipient(SecretKey recipientKey) + { + super(recipientKey); + } + + public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentMacAlgorithm, byte[] encryptedContentEncryptionKey) + throws CMSException + { + final Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentMacAlgorithm, encryptedContentEncryptionKey); + + final Mac dataMac = contentHelper.createContentMac(secretKey, contentMacAlgorithm); + + return new RecipientOperator(new MacCalculator() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return contentMacAlgorithm; + } + + public GenericKey getKey() + { + return new JceGenericKey(contentMacAlgorithm, secretKey); + } + + public OutputStream getOutputStream() + { + return new MacOutputStream(dataMac); + } + + public byte[] getMac() + { + return dataMac.doFinal(); + } + }); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKEnvelopedRecipient.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKEnvelopedRecipient.java new file mode 100644 index 00000000..8bf94006 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKEnvelopedRecipient.java @@ -0,0 +1,43 @@ +package org.spongycastle.cms.jcajce; + +import java.io.InputStream; +import java.security.Key; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.SecretKey; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.RecipientOperator; +import org.spongycastle.operator.InputDecryptor; + +public class JceKEKEnvelopedRecipient + extends JceKEKRecipient +{ + public JceKEKEnvelopedRecipient(SecretKey recipientKey) + { + super(recipientKey); + } + + public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey) + throws CMSException + { + Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, encryptedContentEncryptionKey); + + final Cipher dataCipher = contentHelper.createContentCipher(secretKey, contentEncryptionAlgorithm); + + return new RecipientOperator(new InputDecryptor() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return contentEncryptionAlgorithm; + } + + public InputStream getInputStream(InputStream dataOut) + { + return new CipherInputStream(dataOut, dataCipher); + } + }); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKRecipient.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKRecipient.java new file mode 100644 index 00000000..84ad638f --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKRecipient.java @@ -0,0 +1,119 @@ +package org.spongycastle.cms.jcajce; + +import java.security.Key; +import java.security.Provider; + +import javax.crypto.SecretKey; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.KEKRecipient; +import org.spongycastle.operator.OperatorException; +import org.spongycastle.operator.SymmetricKeyUnwrapper; + +public abstract class JceKEKRecipient + implements KEKRecipient +{ + private SecretKey recipientKey; + + protected EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); + protected EnvelopedDataHelper contentHelper = helper; + protected boolean validateKeySize = false; + + public JceKEKRecipient(SecretKey recipientKey) + { + this.recipientKey = recipientKey; + } + + /** + * Set the provider to use for key recovery and content processing. + * + * @param provider provider to use. + * @return this recipient. + */ + public JceKEKRecipient setProvider(Provider provider) + { + this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); + this.contentHelper = helper; + + return this; + } + + /** + * Set the provider to use for key recovery and content processing. + * + * @param providerName the name of the provider to use. + * @return this recipient. + */ + public JceKEKRecipient setProvider(String providerName) + { + this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); + this.contentHelper = helper; + + return this; + } + + /** + * Set the provider to use for content processing. + * + * @param provider the provider to use. + * @return this recipient. + */ + public JceKEKRecipient setContentProvider(Provider provider) + { + this.contentHelper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); + + return this; + } + + /** + * Set the provider to use for content processing. + * + * @param providerName the name of the provider to use. + * @return this recipient. + */ + public JceKEKRecipient setContentProvider(String providerName) + { + this.contentHelper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); + + return this; + } + + /** + * Set validation of retrieved key sizes against the algorithm parameters for the encrypted key where possible - default is off. + * <p> + * This setting will not have any affect if the encryption algorithm in the recipient does not specify a particular key size, or + * if the unwrapper is a HSM and the byte encoding of the unwrapped secret key is not available. + * </p> + * @param doValidate true if unwrapped key's should be validated against the content encryption algorithm, false otherwise. + * @return this recipient. + */ + public JceKEKRecipient setKeySizeValidation(boolean doValidate) + { + this.validateKeySize = doValidate; + + return this; + } + + protected Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedContentEncryptionKey) + throws CMSException + { + SymmetricKeyUnwrapper unwrapper = helper.createSymmetricUnwrapper(keyEncryptionAlgorithm, recipientKey); + + try + { + Key key = helper.getJceKey(encryptedKeyAlgorithm.getAlgorithm(), unwrapper.generateUnwrappedKey(encryptedKeyAlgorithm, encryptedContentEncryptionKey)); + + if (validateKeySize) + { + helper.keySizeCheck(encryptedKeyAlgorithm, key); + } + + return key; + } + catch (OperatorException e) + { + throw new CMSException("exception unwrapping key: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKRecipientInfoGenerator.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKRecipientInfoGenerator.java new file mode 100644 index 00000000..7a67de4a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKRecipientInfoGenerator.java @@ -0,0 +1,45 @@ +package org.spongycastle.cms.jcajce; + +import java.security.Provider; +import java.security.SecureRandom; + +import javax.crypto.SecretKey; + +import org.spongycastle.asn1.cms.KEKIdentifier; +import org.spongycastle.cms.KEKRecipientInfoGenerator; +import org.spongycastle.operator.jcajce.JceSymmetricKeyWrapper; + +public class JceKEKRecipientInfoGenerator + extends KEKRecipientInfoGenerator +{ + public JceKEKRecipientInfoGenerator(KEKIdentifier kekIdentifier, SecretKey keyEncryptionKey) + { + super(kekIdentifier, new JceSymmetricKeyWrapper(keyEncryptionKey)); + } + + public JceKEKRecipientInfoGenerator(byte[] keyIdentifier, SecretKey keyEncryptionKey) + { + this(new KEKIdentifier(keyIdentifier, null, null), keyEncryptionKey); + } + + public JceKEKRecipientInfoGenerator setProvider(Provider provider) + { + ((JceSymmetricKeyWrapper)this.wrapper).setProvider(provider); + + return this; + } + + public JceKEKRecipientInfoGenerator setProvider(String providerName) + { + ((JceSymmetricKeyWrapper)this.wrapper).setProvider(providerName); + + return this; + } + + public JceKEKRecipientInfoGenerator setSecureRandom(SecureRandom random) + { + ((JceSymmetricKeyWrapper)this.wrapper).setSecureRandom(random); + + return this; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeAuthenticatedRecipient.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeAuthenticatedRecipient.java new file mode 100644 index 00000000..3186b561 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeAuthenticatedRecipient.java @@ -0,0 +1,57 @@ +package org.spongycastle.cms.jcajce; + +import java.io.OutputStream; +import java.security.Key; +import java.security.PrivateKey; + +import javax.crypto.Mac; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.RecipientOperator; +import org.spongycastle.jcajce.io.MacOutputStream; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.MacCalculator; +import org.spongycastle.operator.jcajce.JceGenericKey; + +public class JceKeyAgreeAuthenticatedRecipient + extends JceKeyAgreeRecipient +{ + public JceKeyAgreeAuthenticatedRecipient(PrivateKey recipientKey) + { + super(recipientKey); + } + + public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentMacAlgorithm, SubjectPublicKeyInfo senderPublicKey, ASN1OctetString userKeyingMaterial, byte[] encryptedContentKey) + throws CMSException + { + final Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentMacAlgorithm, senderPublicKey, userKeyingMaterial, encryptedContentKey); + + final Mac dataMac = contentHelper.createContentMac(secretKey, contentMacAlgorithm); + + return new RecipientOperator(new MacCalculator() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return contentMacAlgorithm; + } + + public GenericKey getKey() + { + return new JceGenericKey(contentMacAlgorithm, secretKey); + } + + public OutputStream getOutputStream() + { + return new MacOutputStream(dataMac); + } + + public byte[] getMac() + { + return dataMac.doFinal(); + } + }); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeEnvelopedRecipient.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeEnvelopedRecipient.java new file mode 100644 index 00000000..274d8ed9 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeEnvelopedRecipient.java @@ -0,0 +1,45 @@ +package org.spongycastle.cms.jcajce; + +import java.io.InputStream; +import java.security.Key; +import java.security.PrivateKey; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.RecipientOperator; +import org.spongycastle.operator.InputDecryptor; + +public class JceKeyAgreeEnvelopedRecipient + extends JceKeyAgreeRecipient +{ + public JceKeyAgreeEnvelopedRecipient(PrivateKey recipientKey) + { + super(recipientKey); + } + + public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, SubjectPublicKeyInfo senderPublicKey, ASN1OctetString userKeyingMaterial, byte[] encryptedContentKey) + throws CMSException + { + Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, senderPublicKey, userKeyingMaterial, encryptedContentKey); + + final Cipher dataCipher = contentHelper.createContentCipher(secretKey, contentEncryptionAlgorithm); + + return new RecipientOperator(new InputDecryptor() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return contentEncryptionAlgorithm; + } + + public InputStream getInputStream(InputStream dataOut) + { + return new CipherInputStream(dataOut, dataCipher); + } + }); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeRecipient.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeRecipient.java new file mode 100644 index 00000000..1beea382 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeRecipient.java @@ -0,0 +1,184 @@ +package org.spongycastle.cms.jcajce; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; + +import javax.crypto.Cipher; +import javax.crypto.KeyAgreement; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.cms.ecc.MQVuserKeyingMaterial; +import org.spongycastle.asn1.pkcs.PrivateKeyInfo; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.cms.CMSEnvelopedGenerator; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.KeyAgreeRecipient; +import org.spongycastle.jce.spec.MQVPrivateKeySpec; +import org.spongycastle.jce.spec.MQVPublicKeySpec; + +public abstract class JceKeyAgreeRecipient + implements KeyAgreeRecipient +{ + private PrivateKey recipientKey; + protected EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); + protected EnvelopedDataHelper contentHelper = helper; + + public JceKeyAgreeRecipient(PrivateKey recipientKey) + { + this.recipientKey = recipientKey; + } + + /** + * Set the provider to use for key recovery and content processing. + * + * @param provider provider to use. + * @return this recipient. + */ + public JceKeyAgreeRecipient setProvider(Provider provider) + { + this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); + this.contentHelper = helper; + + return this; + } + + /** + * Set the provider to use for key recovery and content processing. + * + * @param providerName the name of the provider to use. + * @return this recipient. + */ + public JceKeyAgreeRecipient setProvider(String providerName) + { + this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); + this.contentHelper = helper; + + return this; + } + + /** + * Set the provider to use for content processing. If providerName is null a "no provider" search will be + * used to satisfy getInstance calls. + * + * @param provider the provider to use. + * @return this recipient. + */ + public JceKeyAgreeRecipient setContentProvider(Provider provider) + { + this.contentHelper = CMSUtils.createContentHelper(provider); + + return this; + } + + /** + * Set the provider to use for content processing. If providerName is null a "no provider" search will be + * used to satisfy getInstance calls. + * + * @param providerName the name of the provider to use. + * @return this recipient. + */ + public JceKeyAgreeRecipient setContentProvider(String providerName) + { + this.contentHelper = CMSUtils.createContentHelper(providerName); + + return this; + } + + private SecretKey calculateAgreedWrapKey(AlgorithmIdentifier keyEncAlg, ASN1ObjectIdentifier wrapAlg, + PublicKey senderPublicKey, ASN1OctetString userKeyingMaterial, PrivateKey receiverPrivateKey) + throws CMSException, GeneralSecurityException, IOException + { + String agreeAlg = keyEncAlg.getAlgorithm().getId(); + + if (agreeAlg.equals(CMSEnvelopedGenerator.ECMQV_SHA1KDF)) + { + byte[] ukmEncoding = userKeyingMaterial.getOctets(); + MQVuserKeyingMaterial ukm = MQVuserKeyingMaterial.getInstance( + ASN1Primitive.fromByteArray(ukmEncoding)); + + SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo( + getPrivateKeyAlgorithmIdentifier(), + ukm.getEphemeralPublicKey().getPublicKey().getBytes()); + + X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubInfo.getEncoded()); + KeyFactory fact = helper.createKeyFactory(keyEncAlg.getAlgorithm()); + PublicKey ephemeralKey = fact.generatePublic(pubSpec); + + senderPublicKey = new MQVPublicKeySpec(senderPublicKey, ephemeralKey); + receiverPrivateKey = new MQVPrivateKeySpec(receiverPrivateKey, receiverPrivateKey); + } + + KeyAgreement agreement = helper.createKeyAgreement(keyEncAlg.getAlgorithm()); + + agreement.init(receiverPrivateKey); + agreement.doPhase(senderPublicKey, true); + + return agreement.generateSecret(wrapAlg.getId()); + } + + private Key unwrapSessionKey(ASN1ObjectIdentifier wrapAlg, SecretKey agreedKey, ASN1ObjectIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey) + throws CMSException, InvalidKeyException, NoSuchAlgorithmException + { + Cipher keyCipher = helper.createCipher(wrapAlg); + keyCipher.init(Cipher.UNWRAP_MODE, agreedKey); + return keyCipher.unwrap(encryptedContentEncryptionKey, helper.getBaseCipherName(contentEncryptionAlgorithm), Cipher.SECRET_KEY); + } + + protected Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier contentEncryptionAlgorithm, SubjectPublicKeyInfo senderKey, ASN1OctetString userKeyingMaterial, byte[] encryptedContentEncryptionKey) + throws CMSException + { + try + { + ASN1ObjectIdentifier wrapAlg = + AlgorithmIdentifier.getInstance(keyEncryptionAlgorithm.getParameters()).getAlgorithm(); + + X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(senderKey.getEncoded()); + KeyFactory fact = helper.createKeyFactory(keyEncryptionAlgorithm.getAlgorithm()); + PublicKey senderPublicKey = fact.generatePublic(pubSpec); + + SecretKey agreedWrapKey = calculateAgreedWrapKey(keyEncryptionAlgorithm, wrapAlg, + senderPublicKey, userKeyingMaterial, recipientKey); + + return unwrapSessionKey(wrapAlg, agreedWrapKey, contentEncryptionAlgorithm.getAlgorithm(), encryptedContentEncryptionKey); + } + catch (NoSuchAlgorithmException e) + { + throw new CMSException("can't find algorithm.", e); + } + catch (InvalidKeyException e) + { + throw new CMSException("key invalid in message.", e); + } + catch (InvalidKeySpecException e) + { + throw new CMSException("originator key spec invalid.", e); + } + catch (NoSuchPaddingException e) + { + throw new CMSException("required padding not supported.", e); + } + catch (Exception e) + { + throw new CMSException("originator key invalid.", e); + } + } + + public AlgorithmIdentifier getPrivateKeyAlgorithmIdentifier() + { + return PrivateKeyInfo.getInstance(recipientKey.getEncoded()).getPrivateKeyAlgorithm(); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientId.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientId.java new file mode 100644 index 00000000..1774b394 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientId.java @@ -0,0 +1,23 @@ +package org.spongycastle.cms.jcajce; + +import java.math.BigInteger; +import java.security.cert.X509Certificate; + +import javax.security.auth.x500.X500Principal; + +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.cms.KeyAgreeRecipientId; + +public class JceKeyAgreeRecipientId + extends KeyAgreeRecipientId +{ + public JceKeyAgreeRecipientId(X509Certificate certificate) + { + this(certificate.getIssuerX500Principal(), certificate.getSerialNumber()); + } + + public JceKeyAgreeRecipientId(X500Principal issuer, BigInteger serialNumber) + { + super(X500Name.getInstance(issuer.getEncoded()), serialNumber); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java new file mode 100644 index 00000000..eb9699f5 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java @@ -0,0 +1,215 @@ +package org.spongycastle.cms.jcajce; + +import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECParameterSpec; +import java.util.ArrayList; +import java.util.List; + +import javax.crypto.Cipher; +import javax.crypto.KeyAgreement; +import javax.crypto.SecretKey; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.cms.KeyAgreeRecipientIdentifier; +import org.spongycastle.asn1.cms.RecipientEncryptedKey; +import org.spongycastle.asn1.cms.RecipientKeyIdentifier; +import org.spongycastle.asn1.cms.ecc.MQVuserKeyingMaterial; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.cms.CMSAlgorithm; +import org.spongycastle.cms.CMSEnvelopedGenerator; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.KeyAgreeRecipientInfoGenerator; +import org.spongycastle.jce.spec.MQVPrivateKeySpec; +import org.spongycastle.jce.spec.MQVPublicKeySpec; +import org.spongycastle.operator.GenericKey; + +public class JceKeyAgreeRecipientInfoGenerator + extends KeyAgreeRecipientInfoGenerator +{ + private List recipientIDs = new ArrayList(); + private List recipientKeys = new ArrayList(); + private PublicKey senderPublicKey; + private PrivateKey senderPrivateKey; + + private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); + private SecureRandom random; + private KeyPair ephemeralKP; + + public JceKeyAgreeRecipientInfoGenerator(ASN1ObjectIdentifier keyAgreementOID, PrivateKey senderPrivateKey, PublicKey senderPublicKey, ASN1ObjectIdentifier keyEncryptionOID) + { + super(keyAgreementOID, SubjectPublicKeyInfo.getInstance(senderPublicKey.getEncoded()), keyEncryptionOID); + + this.senderPublicKey = senderPublicKey; + this.senderPrivateKey = senderPrivateKey; + } + + public JceKeyAgreeRecipientInfoGenerator setProvider(Provider provider) + { + this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); + + return this; + } + + public JceKeyAgreeRecipientInfoGenerator setProvider(String providerName) + { + this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); + + return this; + } + + public JceKeyAgreeRecipientInfoGenerator setSecureRandom(SecureRandom random) + { + this.random = random; + + return this; + } + + /** + * Add a recipient based on the passed in certificate's public key and its issuer and serial number. + * + * @param recipientCert recipient's certificate + * @return the current instance. + * @throws CertificateEncodingException if the necessary data cannot be extracted from the certificate. + */ + public JceKeyAgreeRecipientInfoGenerator addRecipient(X509Certificate recipientCert) + throws CertificateEncodingException + { + recipientIDs.add(new KeyAgreeRecipientIdentifier(CMSUtils.getIssuerAndSerialNumber(recipientCert))); + recipientKeys.add(recipientCert.getPublicKey()); + + return this; + } + + /** + * Add a recipient identified by the passed in subjectKeyID and the for the passed in public key. + * + * @param subjectKeyID identifier actual recipient will use to match the private key. + * @param publicKey the public key for encrypting the secret key. + * @return the current instance. + * @throws CertificateEncodingException + */ + public JceKeyAgreeRecipientInfoGenerator addRecipient(byte[] subjectKeyID, PublicKey publicKey) + throws CertificateEncodingException + { + recipientIDs.add(new KeyAgreeRecipientIdentifier(new RecipientKeyIdentifier(subjectKeyID))); + recipientKeys.add(publicKey); + + return this; + } + + public ASN1Sequence generateRecipientEncryptedKeys(AlgorithmIdentifier keyAgreeAlgorithm, AlgorithmIdentifier keyEncryptionAlgorithm, GenericKey contentEncryptionKey) + throws CMSException + { + init(keyAgreeAlgorithm.getAlgorithm()); + + PrivateKey senderPrivateKey = this.senderPrivateKey; + + ASN1ObjectIdentifier keyAgreementOID = keyAgreeAlgorithm.getAlgorithm(); + + if (keyAgreementOID.getId().equals(CMSEnvelopedGenerator.ECMQV_SHA1KDF)) + { + senderPrivateKey = new MQVPrivateKeySpec( + senderPrivateKey, ephemeralKP.getPrivate(), ephemeralKP.getPublic()); + } + + ASN1EncodableVector recipientEncryptedKeys = new ASN1EncodableVector(); + for (int i = 0; i != recipientIDs.size(); i++) + { + PublicKey recipientPublicKey = (PublicKey)recipientKeys.get(i); + KeyAgreeRecipientIdentifier karId = (KeyAgreeRecipientIdentifier)recipientIDs.get(i); + + if (keyAgreementOID.getId().equals(CMSEnvelopedGenerator.ECMQV_SHA1KDF)) + { + recipientPublicKey = new MQVPublicKeySpec(recipientPublicKey, recipientPublicKey); + } + + try + { + // Use key agreement to choose a wrap key for this recipient + KeyAgreement keyAgreement = helper.createKeyAgreement(keyAgreementOID); + keyAgreement.init(senderPrivateKey, random); + keyAgreement.doPhase(recipientPublicKey, true); + SecretKey keyEncryptionKey = keyAgreement.generateSecret(keyEncryptionAlgorithm.getAlgorithm().getId()); + + // Wrap the content encryption key with the agreement key + Cipher keyEncryptionCipher = helper.createCipher(keyEncryptionAlgorithm.getAlgorithm()); + + keyEncryptionCipher.init(Cipher.WRAP_MODE, keyEncryptionKey, random); + + byte[] encryptedKeyBytes = keyEncryptionCipher.wrap(helper.getJceKey(contentEncryptionKey)); + + ASN1OctetString encryptedKey = new DEROctetString(encryptedKeyBytes); + + recipientEncryptedKeys.add(new RecipientEncryptedKey(karId, encryptedKey)); + } + catch (GeneralSecurityException e) + { + throw new CMSException("cannot perform agreement step: " + e.getMessage(), e); + } + } + + return new DERSequence(recipientEncryptedKeys); + } + + protected ASN1Encodable getUserKeyingMaterial(AlgorithmIdentifier keyAgreeAlg) + throws CMSException + { + init(keyAgreeAlg.getAlgorithm()); + + if (ephemeralKP != null) + { + return new MQVuserKeyingMaterial( + createOriginatorPublicKey(SubjectPublicKeyInfo.getInstance(ephemeralKP.getPublic().getEncoded())), null); + } + + return null; + } + + private void init(ASN1ObjectIdentifier keyAgreementOID) + throws CMSException + { + if (random == null) + { + random = new SecureRandom(); + } + + if (keyAgreementOID.equals(CMSAlgorithm.ECMQV_SHA1KDF)) + { + if (ephemeralKP == null) + { + try + { + ECParameterSpec ecParamSpec = ((ECPublicKey)senderPublicKey).getParams(); + + KeyPairGenerator ephemKPG = helper.createKeyPairGenerator(keyAgreementOID); + + ephemKPG.initialize(ecParamSpec, random); + + ephemeralKP = ephemKPG.generateKeyPair(); + } + catch (InvalidAlgorithmParameterException e) + { + throw new CMSException( + "cannot determine MQV ephemeral key pair parameters from public key: " + e); + } + } + } + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransAuthenticatedRecipient.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransAuthenticatedRecipient.java new file mode 100644 index 00000000..31b38303 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransAuthenticatedRecipient.java @@ -0,0 +1,60 @@ +package org.spongycastle.cms.jcajce; + +import java.io.OutputStream; +import java.security.Key; +import java.security.PrivateKey; + +import javax.crypto.Mac; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.RecipientOperator; +import org.spongycastle.jcajce.io.MacOutputStream; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.MacCalculator; + + +/** + * the KeyTransRecipientInformation class for a recipient who has been sent a secret + * key encrypted using their public key that needs to be used to + * extract the message. + */ +public class JceKeyTransAuthenticatedRecipient + extends JceKeyTransRecipient +{ + public JceKeyTransAuthenticatedRecipient(PrivateKey recipientKey) + { + super(recipientKey); + } + + public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentMacAlgorithm, byte[] encryptedContentEncryptionKey) + throws CMSException + { + final Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentMacAlgorithm, encryptedContentEncryptionKey); + + final Mac dataMac = contentHelper.createContentMac(secretKey, contentMacAlgorithm); + + return new RecipientOperator(new MacCalculator() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return contentMacAlgorithm; + } + + public GenericKey getKey() + { + return new GenericKey(secretKey); + } + + public OutputStream getOutputStream() + { + return new MacOutputStream(dataMac); + } + + public byte[] getMac() + { + return dataMac.doFinal(); + } + }); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransEnvelopedRecipient.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransEnvelopedRecipient.java new file mode 100644 index 00000000..8ccc6bf7 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransEnvelopedRecipient.java @@ -0,0 +1,43 @@ +package org.spongycastle.cms.jcajce; + +import java.io.InputStream; +import java.security.Key; +import java.security.PrivateKey; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.RecipientOperator; +import org.spongycastle.operator.InputDecryptor; + +public class JceKeyTransEnvelopedRecipient + extends JceKeyTransRecipient +{ + public JceKeyTransEnvelopedRecipient(PrivateKey recipientKey) + { + super(recipientKey); + } + + public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey) + throws CMSException + { + Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, encryptedContentEncryptionKey); + + final Cipher dataCipher = contentHelper.createContentCipher(secretKey, contentEncryptionAlgorithm); + + return new RecipientOperator(new InputDecryptor() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return contentEncryptionAlgorithm; + } + + public InputStream getInputStream(InputStream dataIn) + { + return new CipherInputStream(dataIn, dataCipher); + } + }); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransRecipient.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransRecipient.java new file mode 100644 index 00000000..e3939611 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransRecipient.java @@ -0,0 +1,156 @@ +package org.spongycastle.cms.jcajce; + +import java.security.Key; +import java.security.PrivateKey; +import java.security.Provider; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.KeyTransRecipient; +import org.spongycastle.operator.OperatorException; +import org.spongycastle.operator.jcajce.JceAsymmetricKeyUnwrapper; + +public abstract class JceKeyTransRecipient + implements KeyTransRecipient +{ + private PrivateKey recipientKey; + + protected EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); + protected EnvelopedDataHelper contentHelper = helper; + protected Map extraMappings = new HashMap(); + protected boolean validateKeySize = false; + + public JceKeyTransRecipient(PrivateKey recipientKey) + { + this.recipientKey = recipientKey; + } + + /** + * Set the provider to use for key recovery and content processing. + * + * @param provider provider to use. + * @return this recipient. + */ + public JceKeyTransRecipient setProvider(Provider provider) + { + this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); + this.contentHelper = helper; + + return this; + } + + /** + * Set the provider to use for key recovery and content processing. + * + * @param providerName the name of the provider to use. + * @return this recipient. + */ + public JceKeyTransRecipient setProvider(String providerName) + { + this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); + this.contentHelper = helper; + + return this; + } + + /** + * Internally algorithm ids are converted into cipher names using a lookup table. For some providers + * the standard lookup table won't work. Use this method to establish a specific mapping from an + * algorithm identifier to a specific algorithm. + * <p> + * For example: + * <pre> + * unwrapper.setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA"); + * </pre> + * </p> + * @param algorithm OID of algorithm in recipient. + * @param algorithmName JCE algorithm name to use. + * @return the current Recipient. + */ + public JceKeyTransRecipient setAlgorithmMapping(ASN1ObjectIdentifier algorithm, String algorithmName) + { + extraMappings.put(algorithm, algorithmName); + + return this; + } + + /** + * Set the provider to use for content processing. If providerName is null a "no provider" search will be + * used to satisfy getInstance calls. + * + * @param provider the provider to use. + * @return this recipient. + */ + public JceKeyTransRecipient setContentProvider(Provider provider) + { + this.contentHelper = CMSUtils.createContentHelper(provider); + + return this; + } + + /** + * Set the provider to use for content processing. If providerName is null a "no provider" search will be + * used to satisfy getInstance calls. + * + * @param providerName the name of the provider to use. + * @return this recipient. + */ + public JceKeyTransRecipient setContentProvider(String providerName) + { + this.contentHelper = CMSUtils.createContentHelper(providerName); + + return this; + } + + /** + * Set validation of retrieved key sizes against the algorithm parameters for the encrypted key where possible - default is off. + * <p> + * This setting will not have any affect if the encryption algorithm in the recipient does not specify a particular key size, or + * if the unwrapper is a HSM and the byte encoding of the unwrapped secret key is not available. + * </p> + * @param doValidate true if unwrapped key's should be validated against the content encryption algorithm, false otherwise. + * @return this recipient. + */ + public JceKeyTransRecipient setKeySizeValidation(boolean doValidate) + { + this.validateKeySize = doValidate; + + return this; + } + + protected Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedEncryptionKey) + throws CMSException + { + JceAsymmetricKeyUnwrapper unwrapper = helper.createAsymmetricUnwrapper(keyEncryptionAlgorithm, recipientKey); + + if (!extraMappings.isEmpty()) + { + for (Iterator it = extraMappings.keySet().iterator(); it.hasNext();) + { + ASN1ObjectIdentifier algorithm = (ASN1ObjectIdentifier)it.next(); + + unwrapper.setAlgorithmMapping(algorithm, (String)extraMappings.get(algorithm)); + } + } + + try + { + Key key = helper.getJceKey(encryptedKeyAlgorithm.getAlgorithm(), unwrapper.generateUnwrappedKey(encryptedKeyAlgorithm, encryptedEncryptionKey)); + + if (validateKeySize) + { + helper.keySizeCheck(encryptedKeyAlgorithm, key); + } + + return key; + } + catch (OperatorException e) + { + throw new CMSException("exception unwrapping key: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransRecipientId.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransRecipientId.java new file mode 100644 index 00000000..62ce1fea --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransRecipientId.java @@ -0,0 +1,57 @@ +package org.spongycastle.cms.jcajce; + +import java.math.BigInteger; +import java.security.cert.X509Certificate; + +import javax.security.auth.x500.X500Principal; + +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.cms.KeyTransRecipientId; + +public class JceKeyTransRecipientId + extends KeyTransRecipientId +{ + /** + * Construct a recipient id based on the issuer, serial number and subject key identifier (if present) of the passed in + * certificate. + * + * @param certificate certificate providing the issue and serial number and subject key identifier. + */ + public JceKeyTransRecipientId(X509Certificate certificate) + { + super(convertPrincipal(certificate.getIssuerX500Principal()), certificate.getSerialNumber(), CMSUtils.getSubjectKeyId(certificate)); + } + + /** + * Construct a recipient id based on the provided issuer and serial number.. + * + * @param issuer the issuer to use. + * @param serialNumber the serial number to use. + */ + public JceKeyTransRecipientId(X500Principal issuer, BigInteger serialNumber) + { + super(convertPrincipal(issuer), serialNumber); + } + + /** + * Construct a recipient id based on the provided issuer, serial number, and subjectKeyId.. + * + * @param issuer the issuer to use. + * @param serialNumber the serial number to use. + * @param subjectKeyId the subject key ID to use. + */ + public JceKeyTransRecipientId(X500Principal issuer, BigInteger serialNumber, byte[] subjectKeyId) + { + super(convertPrincipal(issuer), serialNumber, subjectKeyId); + } + + private static X500Name convertPrincipal(X500Principal issuer) + { + if (issuer == null) + { + return null; + } + + return X500Name.getInstance(issuer.getEncoded()); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransRecipientInfoGenerator.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransRecipientInfoGenerator.java new file mode 100644 index 00000000..c3cf5693 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransRecipientInfoGenerator.java @@ -0,0 +1,87 @@ +package org.spongycastle.cms.jcajce; + +import java.security.Provider; +import java.security.PublicKey; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.cms.IssuerAndSerialNumber; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cert.jcajce.JcaX509CertificateHolder; +import org.spongycastle.cms.KeyTransRecipientInfoGenerator; +import org.spongycastle.operator.jcajce.JceAsymmetricKeyWrapper; + +public class JceKeyTransRecipientInfoGenerator + extends KeyTransRecipientInfoGenerator +{ + public JceKeyTransRecipientInfoGenerator(X509Certificate recipientCert) + throws CertificateEncodingException + { + super(new IssuerAndSerialNumber(new JcaX509CertificateHolder(recipientCert).toASN1Structure()), new JceAsymmetricKeyWrapper(recipientCert)); + } + + public JceKeyTransRecipientInfoGenerator(byte[] subjectKeyIdentifier, PublicKey publicKey) + { + super(subjectKeyIdentifier, new JceAsymmetricKeyWrapper(publicKey)); + } + + /** + * Create a generator overriding the algorithm type implied by the public key in the certificate passed in. + * + * @param recipientCert certificate carrying the public key. + * @param algorithmIdentifier the identifier and parameters for the encryption algorithm to be used. + */ + public JceKeyTransRecipientInfoGenerator(X509Certificate recipientCert, AlgorithmIdentifier algorithmIdentifier) + throws CertificateEncodingException + { + super(new IssuerAndSerialNumber(new JcaX509CertificateHolder(recipientCert).toASN1Structure()), new JceAsymmetricKeyWrapper(algorithmIdentifier, recipientCert.getPublicKey())); + } + + /** + * Create a generator overriding the algorithm type implied by the public key passed in. + * + * @param subjectKeyIdentifier the subject key identifier value to associate with the public key. + * @param algorithmIdentifier the identifier and parameters for the encryption algorithm to be used. + * @param publicKey the public key to use. + */ + public JceKeyTransRecipientInfoGenerator(byte[] subjectKeyIdentifier, AlgorithmIdentifier algorithmIdentifier, PublicKey publicKey) + { + super(subjectKeyIdentifier, new JceAsymmetricKeyWrapper(algorithmIdentifier, publicKey)); + } + + public JceKeyTransRecipientInfoGenerator setProvider(String providerName) + { + ((JceAsymmetricKeyWrapper)this.wrapper).setProvider(providerName); + + return this; + } + + public JceKeyTransRecipientInfoGenerator setProvider(Provider provider) + { + ((JceAsymmetricKeyWrapper)this.wrapper).setProvider(provider); + + return this; + } + + /** + * Internally algorithm ids are converted into cipher names using a lookup table. For some providers + * the standard lookup table won't work. Use this method to establish a specific mapping from an + * algorithm identifier to a specific algorithm. + * <p> + * For example: + * <pre> + * unwrapper.setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA"); + * </pre> + * </p> + * @param algorithm OID of algorithm in recipient. + * @param algorithmName JCE algorithm name to use. + * @return the current RecipientInfoGenerator. + */ + public JceKeyTransRecipientInfoGenerator setAlgorithmMapping(ASN1ObjectIdentifier algorithm, String algorithmName) + { + ((JceAsymmetricKeyWrapper)this.wrapper).setAlgorithmMapping(algorithm, algorithmName); + + return this; + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordAuthenticatedRecipient.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordAuthenticatedRecipient.java new file mode 100644 index 00000000..12b8c362 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordAuthenticatedRecipient.java @@ -0,0 +1,54 @@ +package org.spongycastle.cms.jcajce; + +import java.io.OutputStream; +import java.security.Key; + +import javax.crypto.Mac; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.RecipientOperator; +import org.spongycastle.jcajce.io.MacOutputStream; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.MacCalculator; +import org.spongycastle.operator.jcajce.JceGenericKey; + +public class JcePasswordAuthenticatedRecipient + extends JcePasswordRecipient +{ + public JcePasswordAuthenticatedRecipient(char[] password) + { + super(password); + } + + public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentMacAlgorithm, byte[] derivedKey, byte[] encryptedContentEncryptionKey) + throws CMSException + { + final Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentMacAlgorithm, derivedKey, encryptedContentEncryptionKey); + + final Mac dataMac = helper.createContentMac(secretKey, contentMacAlgorithm); + + return new RecipientOperator(new MacCalculator() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return contentMacAlgorithm; + } + + public GenericKey getKey() + { + return new JceGenericKey(contentMacAlgorithm, secretKey); + } + + public OutputStream getOutputStream() + { + return new MacOutputStream(dataMac); + } + + public byte[] getMac() + { + return dataMac.doFinal(); + } + }); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordEnvelopedRecipient.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordEnvelopedRecipient.java new file mode 100644 index 00000000..e46c8ddb --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordEnvelopedRecipient.java @@ -0,0 +1,42 @@ +package org.spongycastle.cms.jcajce; + +import java.io.InputStream; +import java.security.Key; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.RecipientOperator; +import org.spongycastle.operator.InputDecryptor; + +public class JcePasswordEnvelopedRecipient + extends JcePasswordRecipient +{ + public JcePasswordEnvelopedRecipient(char[] password) + { + super(password); + } + + public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, byte[] derivedKey, byte[] encryptedContentEncryptionKey) + throws CMSException + { + Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, derivedKey, encryptedContentEncryptionKey); + + final Cipher dataCipher = helper.createContentCipher(secretKey, contentEncryptionAlgorithm); + + return new RecipientOperator(new InputDecryptor() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return contentEncryptionAlgorithm; + } + + public InputStream getInputStream(InputStream dataOut) + { + return new CipherInputStream(dataOut, dataCipher); + } + }); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordRecipient.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordRecipient.java new file mode 100644 index 00000000..b70651b1 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordRecipient.java @@ -0,0 +1,97 @@ +package org.spongycastle.cms.jcajce; + +import java.security.GeneralSecurityException; +import java.security.Key; +import java.security.Provider; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.pkcs.PBKDF2Params; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.PasswordRecipient; +import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator; +import org.spongycastle.crypto.params.KeyParameter; + +/** + * the RecipientInfo class for a recipient who has been sent a message + * encrypted using a password. + */ +public abstract class JcePasswordRecipient + implements PasswordRecipient +{ + private int schemeID = PasswordRecipient.PKCS5_SCHEME2_UTF8; + protected EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); + private char[] password; + + JcePasswordRecipient( + char[] password) + { + this.password = password; + } + + public JcePasswordRecipient setPasswordConversionScheme(int schemeID) + { + this.schemeID = schemeID; + + return this; + } + + public JcePasswordRecipient setProvider(Provider provider) + { + this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); + + return this; + } + + public JcePasswordRecipient setProvider(String providerName) + { + this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); + + return this; + } + + protected Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] derivedKey, byte[] encryptedContentEncryptionKey) + throws CMSException + { + Cipher keyEncryptionCipher = helper.createRFC3211Wrapper(keyEncryptionAlgorithm.getAlgorithm()); + + try + { + IvParameterSpec ivSpec = new IvParameterSpec(ASN1OctetString.getInstance(keyEncryptionAlgorithm.getParameters()).getOctets()); + + keyEncryptionCipher.init(Cipher.UNWRAP_MODE, new SecretKeySpec(derivedKey, keyEncryptionCipher.getAlgorithm()), ivSpec); + + return keyEncryptionCipher.unwrap(encryptedContentEncryptionKey, contentEncryptionAlgorithm.getAlgorithm().getId(), Cipher.SECRET_KEY); + } + catch (GeneralSecurityException e) + { + throw new CMSException("cannot process content encryption key: " + e.getMessage(), e); + } + } + + public byte[] calculateDerivedKey(byte[] encodedPassword, AlgorithmIdentifier derivationAlgorithm, int keySize) + throws CMSException + { + PBKDF2Params params = PBKDF2Params.getInstance(derivationAlgorithm.getParameters()); + + PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(); + + gen.init(encodedPassword, params.getSalt(), params.getIterationCount().intValue()); + + return ((KeyParameter)gen.generateDerivedParameters(keySize)).getKey(); + } + + public int getPasswordConversionScheme() + { + return schemeID; + } + + public char[] getPassword() + { + return password; + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordRecipientInfoGenerator.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordRecipientInfoGenerator.java new file mode 100644 index 00000000..d29fbab3 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordRecipientInfoGenerator.java @@ -0,0 +1,76 @@ +package org.spongycastle.cms.jcajce; + +import java.security.GeneralSecurityException; +import java.security.Key; +import java.security.Provider; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.pkcs.PBKDF2Params; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.PasswordRecipientInfoGenerator; +import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.operator.GenericKey; + +public class JcePasswordRecipientInfoGenerator + extends PasswordRecipientInfoGenerator +{ + private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper()); + + public JcePasswordRecipientInfoGenerator(ASN1ObjectIdentifier kekAlgorithm, char[] password) + { + super(kekAlgorithm, password); + } + + public JcePasswordRecipientInfoGenerator setProvider(Provider provider) + { + this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider)); + + return this; + } + + public JcePasswordRecipientInfoGenerator setProvider(String providerName) + { + this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName)); + + return this; + } + + protected byte[] calculateDerivedKey(byte[] encodedPassword, AlgorithmIdentifier derivationAlgorithm, int keySize) + throws CMSException + { + PBKDF2Params params = PBKDF2Params.getInstance(derivationAlgorithm.getParameters()); + + PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(); + + gen.init(encodedPassword, params.getSalt(), params.getIterationCount().intValue()); + + return ((KeyParameter)gen.generateDerivedParameters(keySize)).getKey(); + } + + public byte[] generateEncryptedBytes(AlgorithmIdentifier keyEncryptionAlgorithm, byte[] derivedKey, GenericKey contentEncryptionKey) + throws CMSException + { + Key contentEncryptionKeySpec = helper.getJceKey(contentEncryptionKey); + Cipher keyEncryptionCipher = helper.createRFC3211Wrapper(keyEncryptionAlgorithm.getAlgorithm()); + + try + { + IvParameterSpec ivSpec = new IvParameterSpec(ASN1OctetString.getInstance(keyEncryptionAlgorithm.getParameters()).getOctets()); + + keyEncryptionCipher.init(Cipher.WRAP_MODE, new SecretKeySpec(derivedKey, keyEncryptionCipher.getAlgorithm()), ivSpec); + + return keyEncryptionCipher.wrap(contentEncryptionKeySpec); + } + catch (GeneralSecurityException e) + { + throw new CMSException("cannot process content encryption key: " + e.getMessage(), e); + } + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/NamedJcaJceExtHelper.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/NamedJcaJceExtHelper.java new file mode 100644 index 00000000..c5589320 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/NamedJcaJceExtHelper.java @@ -0,0 +1,31 @@ +package org.spongycastle.cms.jcajce; + +import java.security.PrivateKey; + +import javax.crypto.SecretKey; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.jcajce.util.NamedJcaJceHelper; +import org.spongycastle.operator.SymmetricKeyUnwrapper; +import org.spongycastle.operator.jcajce.JceAsymmetricKeyUnwrapper; +import org.spongycastle.operator.jcajce.JceSymmetricKeyUnwrapper; + +class NamedJcaJceExtHelper + extends NamedJcaJceHelper + implements JcaJceExtHelper +{ + public NamedJcaJceExtHelper(String providerName) + { + super(providerName); + } + + public JceAsymmetricKeyUnwrapper createAsymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, PrivateKey keyEncryptionKey) + { + return new JceAsymmetricKeyUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey).setProvider(providerName); + } + + public SymmetricKeyUnwrapper createSymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, SecretKey keyEncryptionKey) + { + return new JceSymmetricKeyUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey).setProvider(providerName); + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/ProviderJcaJceExtHelper.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/ProviderJcaJceExtHelper.java new file mode 100644 index 00000000..25075a1f --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/ProviderJcaJceExtHelper.java @@ -0,0 +1,32 @@ +package org.spongycastle.cms.jcajce; + +import java.security.PrivateKey; +import java.security.Provider; + +import javax.crypto.SecretKey; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.jcajce.util.ProviderJcaJceHelper; +import org.spongycastle.operator.SymmetricKeyUnwrapper; +import org.spongycastle.operator.jcajce.JceAsymmetricKeyUnwrapper; +import org.spongycastle.operator.jcajce.JceSymmetricKeyUnwrapper; + +class ProviderJcaJceExtHelper + extends ProviderJcaJceHelper + implements JcaJceExtHelper +{ + public ProviderJcaJceExtHelper(Provider provider) + { + super(provider); + } + + public JceAsymmetricKeyUnwrapper createAsymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, PrivateKey keyEncryptionKey) + { + return new JceAsymmetricKeyUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey).setProvider(provider); + } + + public SymmetricKeyUnwrapper createSymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, SecretKey keyEncryptionKey) + { + return new JceSymmetricKeyUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey).setProvider(provider); + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/ZlibCompressor.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/ZlibCompressor.java new file mode 100644 index 00000000..a4787f45 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/ZlibCompressor.java @@ -0,0 +1,24 @@ +package org.spongycastle.cms.jcajce; + +import java.io.OutputStream; +import java.util.zip.DeflaterOutputStream; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.operator.OutputCompressor; + +public class ZlibCompressor + implements OutputCompressor +{ + private static final String ZLIB = "1.2.840.113549.1.9.16.3.8"; + + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return new AlgorithmIdentifier(new ASN1ObjectIdentifier(ZLIB)); + } + + public OutputStream getOutputStream(OutputStream comOut) + { + return new DeflaterOutputStream(comOut); + } +} diff --git a/pkix/src/main/java/org/spongycastle/cms/jcajce/ZlibExpanderProvider.java b/pkix/src/main/java/org/spongycastle/cms/jcajce/ZlibExpanderProvider.java new file mode 100644 index 00000000..adc01206 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cms/jcajce/ZlibExpanderProvider.java @@ -0,0 +1,116 @@ +package org.spongycastle.cms.jcajce; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.InflaterInputStream; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.operator.InputExpander; +import org.spongycastle.operator.InputExpanderProvider; +import org.spongycastle.util.io.StreamOverflowException; + +public class ZlibExpanderProvider + implements InputExpanderProvider +{ + private final long limit; + + /** + * Base constructor. Create an expander which will not limit the size of any objects expanded in the stream. + */ + public ZlibExpanderProvider() + { + this.limit = -1; + } + + /** + * Create a provider which caps the number of expanded bytes that can be produced when the + * compressed stream is parsed. + * + * @param limit max number of bytes allowed in an expanded stream. + */ + public ZlibExpanderProvider(long limit) + { + this.limit = limit; + } + + public InputExpander get(final AlgorithmIdentifier algorithm) + { + return new InputExpander() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return algorithm; + } + + public InputStream getInputStream(InputStream comIn) + { + InputStream s = new InflaterInputStream(comIn); + if (limit >= 0) + { + s = new LimitedInputStream(s, limit); + } + return s; + } + }; + } + + private static class LimitedInputStream + extends FilterInputStream + { + private long remaining; + + public LimitedInputStream(InputStream input, long limit) + { + super(input); + + this.remaining = limit; + } + + public int read() + throws IOException + { + // Only a single 'extra' byte will ever be read + if (remaining >= 0) + { + int b = super.in.read(); + if (b < 0 || --remaining >= 0) + { + return b; + } + } + + throw new StreamOverflowException("expanded byte limit exceeded"); + } + + public int read(byte[] buf, int off, int len) + throws IOException + { + if (len < 1) + { + // This will give correct exceptions/returns for strange lengths + return super.read(buf, off, len); + } + + if (remaining < 1) + { + // Will either return EOF or throw exception + read(); + return -1; + } + + /* + * Limit the underlying request to 'remaining' bytes. This ensures the + * caller will see the full 'limit' bytes before getting an exception. + * Also, only one extra byte will ever be read. + */ + int actualLen = (remaining > len ? len : (int)remaining); + int numRead = super.in.read(buf, off, actualLen); + if (numRead > 0) + { + remaining -= numRead; + } + return numRead; + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/dvcs/CCPDRequestBuilder.java b/pkix/src/main/java/org/spongycastle/dvcs/CCPDRequestBuilder.java new file mode 100644 index 00000000..e48dd2a3 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/dvcs/CCPDRequestBuilder.java @@ -0,0 +1,32 @@ +package org.spongycastle.dvcs; + +import org.spongycastle.asn1.dvcs.DVCSRequestInformationBuilder; +import org.spongycastle.asn1.dvcs.Data; +import org.spongycastle.asn1.dvcs.ServiceType; + +/** + * Builder of CCPD requests (Certify Claim of Possession of Data). + */ +public class CCPDRequestBuilder + extends DVCSRequestBuilder +{ + public CCPDRequestBuilder() + { + super(new DVCSRequestInformationBuilder(ServiceType.CCPD)); + } + + /** + * Builds CCPD request. + * + * @param messageImprint - the message imprint to include. + * @return + * @throws DVCSException + */ + public DVCSRequest build(MessageImprint messageImprint) + throws DVCSException + { + Data data = new Data(messageImprint.toASN1Structure()); + + return createDVCRequest(data); + } +} diff --git a/pkix/src/main/java/org/spongycastle/dvcs/CCPDRequestData.java b/pkix/src/main/java/org/spongycastle/dvcs/CCPDRequestData.java new file mode 100644 index 00000000..202dd774 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/dvcs/CCPDRequestData.java @@ -0,0 +1,48 @@ +package org.spongycastle.dvcs; + +import org.spongycastle.asn1.dvcs.Data; + +/** + * Data piece of DVCRequest for CCPD service (Certify Claim of Possession of Data). + * It contains CCPD-specific selector interface. + * <p/> + * This objects are constructed internally, + * to build DVCS request to CCPD service use CCPDRequestBuilder. + */ +public class CCPDRequestData + extends DVCSRequestData +{ + /** + * Construct from corresponding ASN.1 Data structure. + * Note, that data should have messageImprint choice, + * otherwise DVCSConstructionException is thrown. + * + * @param data + * @throws DVCSConstructionException + */ + CCPDRequestData(Data data) + throws DVCSConstructionException + { + super(data); + initDigest(); + } + + private void initDigest() + throws DVCSConstructionException + { + if (data.getMessageImprint() == null) + { + throw new DVCSConstructionException("DVCSRequest.data.messageImprint should be specified for CCPD service"); + } + } + + /** + * Get MessageImprint value + * + * @return + */ + public MessageImprint getMessageImprint() + { + return new MessageImprint(data.getMessageImprint()); + } +} diff --git a/pkix/src/main/java/org/spongycastle/dvcs/CPDRequestBuilder.java b/pkix/src/main/java/org/spongycastle/dvcs/CPDRequestBuilder.java new file mode 100644 index 00000000..0b0b8189 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/dvcs/CPDRequestBuilder.java @@ -0,0 +1,34 @@ +package org.spongycastle.dvcs; + +import java.io.IOException; + +import org.spongycastle.asn1.dvcs.DVCSRequestInformationBuilder; +import org.spongycastle.asn1.dvcs.Data; +import org.spongycastle.asn1.dvcs.ServiceType; + +/** + * Builder of DVCSRequests to CPD service (Certify Possession of Data). + */ +public class CPDRequestBuilder + extends DVCSRequestBuilder +{ + public CPDRequestBuilder() + { + super(new DVCSRequestInformationBuilder(ServiceType.CPD)); + } + + /** + * Build CPD request. + * + * @param messageBytes - data to be certified + * @return + * @throws DVCSException + */ + public DVCSRequest build(byte[] messageBytes) + throws DVCSException, IOException + { + Data data = new Data(messageBytes); + + return createDVCRequest(data); + } +} diff --git a/pkix/src/main/java/org/spongycastle/dvcs/CPDRequestData.java b/pkix/src/main/java/org/spongycastle/dvcs/CPDRequestData.java new file mode 100644 index 00000000..a7c1f5a8 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/dvcs/CPDRequestData.java @@ -0,0 +1,40 @@ +package org.spongycastle.dvcs; + +import org.spongycastle.asn1.dvcs.Data; + +/** + * Data piece of DVCRequest for CPD service (Certify Possession of Data). + * It contains CPD-specific selector interface. + * <p/> + * This objects are constructed internally, + * to build DVCS request to CPD service use CPDRequestBuilder. + */ +public class CPDRequestData + extends DVCSRequestData +{ + CPDRequestData(Data data) + throws DVCSConstructionException + { + super(data); + initMessage(); + } + + private void initMessage() + throws DVCSConstructionException + { + if (data.getMessage() == null) + { + throw new DVCSConstructionException("DVCSRequest.data.message should be specified for CPD service"); + } + } + + /** + * Get contained message (data to be certified). + * + * @return + */ + public byte[] getMessage() + { + return data.getMessage().getOctets(); + } +} diff --git a/pkix/src/main/java/org/spongycastle/dvcs/DVCSConstructionException.java b/pkix/src/main/java/org/spongycastle/dvcs/DVCSConstructionException.java new file mode 100644 index 00000000..73e6b0dc --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/dvcs/DVCSConstructionException.java @@ -0,0 +1,20 @@ +package org.spongycastle.dvcs; + +/** + * Exception thrown when failed to initialize some DVCS-related staff. + */ +public class DVCSConstructionException + extends DVCSException +{ + private static final long serialVersionUID = 660035299653583980L; + + public DVCSConstructionException(String message) + { + super(message); + } + + public DVCSConstructionException(String message, Throwable cause) + { + super(message, cause); + } +} diff --git a/pkix/src/main/java/org/spongycastle/dvcs/DVCSException.java b/pkix/src/main/java/org/spongycastle/dvcs/DVCSException.java new file mode 100644 index 00000000..5aa8f51e --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/dvcs/DVCSException.java @@ -0,0 +1,28 @@ +package org.spongycastle.dvcs; + +/** + * General DVCSException. + */ +public class DVCSException + extends Exception +{ + private static final long serialVersionUID = 389345256020131488L; + + private Throwable cause; + + public DVCSException(String message) + { + super(message); + } + + public DVCSException(String message, Throwable cause) + { + super(message); + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/pkix/src/main/java/org/spongycastle/dvcs/DVCSMessage.java b/pkix/src/main/java/org/spongycastle/dvcs/DVCSMessage.java new file mode 100644 index 00000000..6758f359 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/dvcs/DVCSMessage.java @@ -0,0 +1,22 @@ +package org.spongycastle.dvcs; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.cms.ContentInfo; + +public abstract class DVCSMessage +{ + private final ContentInfo contentInfo; + + protected DVCSMessage(ContentInfo contentInfo) + { + this.contentInfo = contentInfo; + } + + public ASN1ObjectIdentifier getContentType() + { + return contentInfo.getContentType(); + } + + public abstract ASN1Encodable getContent(); +} diff --git a/pkix/src/main/java/org/spongycastle/dvcs/DVCSParsingException.java b/pkix/src/main/java/org/spongycastle/dvcs/DVCSParsingException.java new file mode 100644 index 00000000..e1452576 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/dvcs/DVCSParsingException.java @@ -0,0 +1,20 @@ +package org.spongycastle.dvcs; + +/** + * DVCS parsing exception - thrown when failed to parse DVCS message. + */ +public class DVCSParsingException + extends DVCSException +{ + private static final long serialVersionUID = -7895880961377691266L; + + public DVCSParsingException(String message) + { + super(message); + } + + public DVCSParsingException(String message, Throwable cause) + { + super(message, cause); + } +} diff --git a/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequest.java b/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequest.java new file mode 100644 index 00000000..f8658ab5 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequest.java @@ -0,0 +1,134 @@ +package org.spongycastle.dvcs; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.cms.SignedData; +import org.spongycastle.asn1.dvcs.DVCSObjectIdentifiers; +import org.spongycastle.asn1.dvcs.ServiceType; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.cms.CMSSignedData; + +/** + * DVCRequest is general request to DVCS (RFC 3029). + * It represents requests for all types of services. + * Requests for different services differ in DVCData structure. + */ +public class DVCSRequest + extends DVCSMessage +{ + private org.spongycastle.asn1.dvcs.DVCSRequest asn1; + private DVCSRequestInfo reqInfo; + private DVCSRequestData data; + + /** + * Constructs DVCRequest from CMS SignedData object. + * + * @param signedData the CMS SignedData object containing the request + * @throws DVCSConstructionException + */ + public DVCSRequest(CMSSignedData signedData) + throws DVCSConstructionException + { + this(SignedData.getInstance(signedData.toASN1Structure().getContent()).getEncapContentInfo()); + } + + /** + * Construct a DVCS Request from a ContentInfo + * + * @param contentInfo the contentInfo representing the DVCSRequest + * @throws DVCSConstructionException + */ + public DVCSRequest(ContentInfo contentInfo) + throws DVCSConstructionException + { + super(contentInfo); + + if (!DVCSObjectIdentifiers.id_ct_DVCSRequestData.equals(contentInfo.getContentType())) + { + throw new DVCSConstructionException("ContentInfo not a DVCS Request"); + } + + try + { + if (contentInfo.getContent().toASN1Primitive() instanceof ASN1Sequence) + { + this.asn1 = org.spongycastle.asn1.dvcs.DVCSRequest.getInstance(contentInfo.getContent()); + } + else + { + this.asn1 = org.spongycastle.asn1.dvcs.DVCSRequest.getInstance(ASN1OctetString.getInstance(contentInfo.getContent()).getOctets()); + } + } + catch (Exception e) + { + throw new DVCSConstructionException("Unable to parse content: " + e.getMessage(), e); + } + + this.reqInfo = new DVCSRequestInfo(asn1.getRequestInformation()); + + int service = reqInfo.getServiceType(); + if (service == ServiceType.CPD.getValue().intValue()) + { + this.data = new CPDRequestData(asn1.getData()); + } + else if (service == ServiceType.VSD.getValue().intValue()) + { + this.data = new VSDRequestData(asn1.getData()); + } + else if (service == ServiceType.VPKC.getValue().intValue()) + { + this.data = new VPKCRequestData(asn1.getData()); + } + else if (service == ServiceType.CCPD.getValue().intValue()) + { + this.data = new CCPDRequestData(asn1.getData()); + } + else + { + throw new DVCSConstructionException("Unknown service type: " + service); + } + } + + /** + * Return the ASN.1 DVCSRequest structure making up the body of this request. + * + * @return an org.spongycastle.asn1.dvcs.DVCSRequest object. + */ + public ASN1Encodable getContent() + { + return asn1; + } + + /** + * Get RequestInformation envelope. + * + * @return the request info object. + */ + public DVCSRequestInfo getRequestInfo() + { + return reqInfo; + } + + /** + * Get data of DVCRequest. + * Depending on type of the request it could be different subclasses of DVCRequestData. + * + * @return the request Data object. + */ + public DVCSRequestData getData() + { + return data; + } + + /** + * Get the transaction identifier of request. + * + * @return the GeneralName representing the Transaction Identifier. + */ + public GeneralName getTransactionIdentifier() + { + return asn1.getTransactionIdentifier(); + } +} diff --git a/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestBuilder.java b/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestBuilder.java new file mode 100644 index 00000000..f1982b91 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestBuilder.java @@ -0,0 +1,131 @@ +package org.spongycastle.dvcs; + +import java.io.IOException; +import java.math.BigInteger; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.dvcs.DVCSObjectIdentifiers; +import org.spongycastle.asn1.dvcs.DVCSRequestInformationBuilder; +import org.spongycastle.asn1.dvcs.Data; +import org.spongycastle.asn1.x509.ExtensionsGenerator; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.asn1.x509.GeneralNames; +import org.spongycastle.cms.CMSSignedDataGenerator; + +/** + * Common base class for client DVCRequest builders. + * This class aims at DVCSRequestInformation and TransactionIdentifier construction, + * and its subclasses - for Data field construction (as it is specific for the requested service). + */ +public abstract class DVCSRequestBuilder +{ + private final ExtensionsGenerator extGenerator = new ExtensionsGenerator(); + private final CMSSignedDataGenerator signedDataGen = new CMSSignedDataGenerator(); + + protected final DVCSRequestInformationBuilder requestInformationBuilder; + + protected DVCSRequestBuilder(DVCSRequestInformationBuilder requestInformationBuilder) + { + this.requestInformationBuilder = requestInformationBuilder; + } + + /** + * Set a nonce for this request, + * + * @param nonce + */ + public void setNonce(BigInteger nonce) + { + requestInformationBuilder.setNonce(nonce); + } + + /** + * Set requester name. + * + * @param requester + */ + public void setRequester(GeneralName requester) + { + requestInformationBuilder.setRequester(requester); + } + + /** + * Set DVCS name to generated requests. + * + * @param dvcs + */ + public void setDVCS(GeneralName dvcs) + { + requestInformationBuilder.setDVCS(dvcs); + } + + /** + * Set DVCS name to generated requests. + * + * @param dvcs + */ + public void setDVCS(GeneralNames dvcs) + { + requestInformationBuilder.setDVCS(dvcs); + } + + /** + * Set data location to generated requests. + * + * @param dataLocation + */ + public void setDataLocations(GeneralName dataLocation) + { + requestInformationBuilder.setDataLocations(dataLocation); + } + + /** + * Set data location to generated requests. + * + * @param dataLocations + */ + public void setDataLocations(GeneralNames dataLocations) + { + requestInformationBuilder.setDataLocations(dataLocations); + } + + /** + * Add a given extension field. + * + * @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. + * @throws DVCSException if there is an issue encoding the extension for adding. + */ + public void addExtension( + ASN1ObjectIdentifier oid, + boolean isCritical, + ASN1Encodable value) + throws DVCSException + { + try + { + extGenerator.addExtension(oid, isCritical, value); + } + catch (IOException e) + { + throw new DVCSException("cannot encode extension: " + e.getMessage(), e); + } + } + + protected DVCSRequest createDVCRequest(Data data) + throws DVCSException + { + if (!extGenerator.isEmpty()) + { + requestInformationBuilder.setExtensions(extGenerator.generate()); + } + + org.spongycastle.asn1.dvcs.DVCSRequest request = new org.spongycastle.asn1.dvcs.DVCSRequest(requestInformationBuilder.build(), data); + + return new DVCSRequest(new ContentInfo(DVCSObjectIdentifiers.id_ct_DVCSRequestData, request)); + } +} diff --git a/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestData.java b/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestData.java new file mode 100644 index 00000000..35cdd325 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestData.java @@ -0,0 +1,38 @@ +package org.spongycastle.dvcs; + +import org.spongycastle.asn1.dvcs.Data; + +/** + * Data piece of DVCRequest object (DVCS Data structure). + * Its contents depend on the service type. + * Its subclasses define the service-specific interface. + * <p/> + * The concrete objects of DVCRequestData are created by buildDVCRequestData static method. + */ +public abstract class DVCSRequestData +{ + /** + * The underlying data object is accessible by subclasses. + */ + protected Data data; + + /** + * The constructor is accessible by subclasses. + * + * @param data + */ + protected DVCSRequestData(Data data) + { + this.data = data; + } + + /** + * Convert to ASN.1 structure (Data). + * + * @return + */ + public Data toASN1Structure() + { + return data; + } +} diff --git a/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestInfo.java b/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestInfo.java new file mode 100644 index 00000000..1f51e3e6 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestInfo.java @@ -0,0 +1,237 @@ +package org.spongycastle.dvcs; + +import java.math.BigInteger; +import java.util.Date; + +import org.spongycastle.asn1.dvcs.DVCSRequestInformation; +import org.spongycastle.asn1.dvcs.DVCSTime; +import org.spongycastle.asn1.x509.GeneralNames; +import org.spongycastle.asn1.x509.PolicyInformation; +import org.spongycastle.tsp.TimeStampToken; +import org.spongycastle.util.Arrays; + +/** + * Information piece of DVCS requests. + * It is common for all types of DVCS requests. + */ +public class DVCSRequestInfo +{ + private DVCSRequestInformation data; + + /** + * Constructs DVCRequestInfo from byte array (DER encoded DVCSRequestInformation). + * + * @param in + */ + public DVCSRequestInfo(byte[] in) + { + this(DVCSRequestInformation.getInstance(in)); + } + + /** + * Constructs DVCRequestInfo from DVCSRequestInformation ASN.1 structure. + * + * @param data + */ + public DVCSRequestInfo(DVCSRequestInformation data) + { + this.data = data; + } + + /** + * Converts to corresponding ASN.1 structure (DVCSRequestInformation). + * + * @return + */ + public DVCSRequestInformation toASN1Structure() + { + return data; + } + + // + // DVCRequestInfo selector interface + // + + /** + * Get DVCS version of request. + * + * @return + */ + public int getVersion() + { + return data.getVersion(); + } + + /** + * Get requested service type. + * + * @return one of CPD, VSD, VPKC, CCPD (see constants). + */ + public int getServiceType() + { + return data.getService().getValue().intValue(); + } + + /** + * Get nonce if it is set. + * Note: this field can be set (if not present) or extended (if present) by DVCS. + * + * @return nonce value, or null if it is not set. + */ + public BigInteger getNonce() + { + return data.getNonce(); + } + + /** + * Get request generation time if it is set. + * + * @return time of request, or null if it is not set. + * @throws DVCSParsingException if a request time is present but cannot be extracted. + */ + public Date getRequestTime() + throws DVCSParsingException + { + DVCSTime time = data.getRequestTime(); + + if (time == null) + { + return null; + } + + try + { + if (time.getGenTime() != null) + { + return time.getGenTime().getDate(); + } + else + { + TimeStampToken token = new TimeStampToken(time.getTimeStampToken()); + + return token.getTimeStampInfo().getGenTime(); + } + } + catch (Exception e) + { + throw new DVCSParsingException("unable to extract time: " + e.getMessage(), e); + } + } + + /** + * Get names of requesting entity, if set. + * + * @return + */ + public GeneralNames getRequester() + { + return data.getRequester(); + } + + /** + * Get policy, under which the validation is requested. + * + * @return policy identifier or null, if any policy is acceptable. + */ + public PolicyInformation getRequestPolicy() + { + if (data.getRequestPolicy() != null) + { + return data.getRequestPolicy(); + } + return null; + } + + /** + * Get names of DVCS servers. + * Note: this field can be set by DVCS. + * + * @return + */ + public GeneralNames getDVCSNames() + { + return data.getDVCS(); + } + + /** + * Get data locations, where the copy of request Data can be obtained. + * Note: the exact meaning of field is up to applications. + * Note: this field can be set by DVCS. + * + * @return + */ + public GeneralNames getDataLocations() + { + return data.getDataLocations(); + } + + /** + * Compares two DVCRequestInfo structures: one from DVCRequest, and one from DVCResponse. + * This function implements RFC 3029, 9.1 checks of reqInfo. + * + * @param requestInfo - DVCRequestInfo of DVCRequest + * @param responseInfo - DVCRequestInfo of DVCResponse + * @return true if server's requestInfo matches client's requestInfo + */ + public static boolean validate(DVCSRequestInfo requestInfo, DVCSRequestInfo responseInfo) + { + // RFC 3029, 9.1 + // The DVCS MAY modify the fields: + // 'dvcs', 'requester', 'dataLocations', and 'nonce' of the ReqInfo structure. + + DVCSRequestInformation clientInfo = requestInfo.data; + DVCSRequestInformation serverInfo = responseInfo.data; + + if (clientInfo.getVersion() != serverInfo.getVersion()) + { + return false; + } + if (!clientEqualsServer(clientInfo.getService(), serverInfo.getService())) + { + return false; + } + if (!clientEqualsServer(clientInfo.getRequestTime(), serverInfo.getRequestTime())) + { + return false; + } + if (!clientEqualsServer(clientInfo.getRequestPolicy(), serverInfo.getRequestPolicy())) + { + return false; + } + if (!clientEqualsServer(clientInfo.getExtensions(), serverInfo.getExtensions())) + { + return false; + } + + // RFC 3029, 9.1. The only modification allowed to a 'nonce' + // is the inclusion of a new field if it was not present, + // or to concatenate other data to the end (right) of an existing value. + + if (clientInfo.getNonce() != null) + { + if (serverInfo.getNonce() == null) + { + return false; + } + byte[] clientNonce = clientInfo.getNonce().toByteArray(); + byte[] serverNonce = serverInfo.getNonce().toByteArray(); + if (serverNonce.length < clientNonce.length) + { + return false; + } + if (!Arrays.areEqual(clientNonce, Arrays.copyOfRange(serverNonce, 0, clientNonce.length))) + { + return false; + } + } + + return true; + } + + // null-protected compare of any two objects + private static boolean clientEqualsServer(Object client, Object server) + { + return (client == null && server == null) || (client != null && client.equals(server)); + } +} + diff --git a/pkix/src/main/java/org/spongycastle/dvcs/DVCSResponse.java b/pkix/src/main/java/org/spongycastle/dvcs/DVCSResponse.java new file mode 100644 index 00000000..f7185519 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/dvcs/DVCSResponse.java @@ -0,0 +1,74 @@ +package org.spongycastle.dvcs; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.cms.SignedData; +import org.spongycastle.asn1.dvcs.DVCSObjectIdentifiers; +import org.spongycastle.cms.CMSSignedData; + +/** + * DVCResponse is general response to DVCS (RFC 3029). + * It represents responses for all types of services. + */ +public class DVCSResponse + extends DVCSMessage +{ + private org.spongycastle.asn1.dvcs.DVCSResponse asn1; + + /** + * Constructs DVCRequest from CMS SignedData object. + * + * @param signedData the CMS SignedData object containing the request + * @throws org.spongycastle.dvcs.DVCSConstructionException + */ + public DVCSResponse(CMSSignedData signedData) + throws DVCSConstructionException + { + this(SignedData.getInstance(signedData.toASN1Structure().getContent()).getEncapContentInfo()); + } + + /** + * Construct a DVCS Request from a ContentInfo + * + * @param contentInfo the contentInfo representing the DVCSRequest + * @throws org.spongycastle.dvcs.DVCSConstructionException + */ + public DVCSResponse(ContentInfo contentInfo) + throws DVCSConstructionException + { + super(contentInfo); + + if (!DVCSObjectIdentifiers.id_ct_DVCSResponseData.equals(contentInfo.getContentType())) + { + throw new DVCSConstructionException("ContentInfo not a DVCS Request"); + } + + try + { + if (contentInfo.getContent().toASN1Primitive() instanceof ASN1Sequence) + { + this.asn1 = org.spongycastle.asn1.dvcs.DVCSResponse.getInstance(contentInfo.getContent()); + } + else + { + this.asn1 = org.spongycastle.asn1.dvcs.DVCSResponse.getInstance(ASN1OctetString.getInstance(contentInfo.getContent()).getOctets()); + } + } + catch (Exception e) + { + throw new DVCSConstructionException("Unable to parse content: " + e.getMessage(), e); + } + } + + /** + * Return the ASN.1 DVCSResponse structure making up the body of this response. + * + * @return an org.spongycastle.asn1.dvcs.DVCSResponse object. + */ + public ASN1Encodable getContent() + { + return asn1; + } +} diff --git a/pkix/src/main/java/org/spongycastle/dvcs/MessageImprint.java b/pkix/src/main/java/org/spongycastle/dvcs/MessageImprint.java new file mode 100644 index 00000000..c9793880 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/dvcs/MessageImprint.java @@ -0,0 +1,38 @@ +package org.spongycastle.dvcs; + +import org.spongycastle.asn1.x509.DigestInfo; + +public class MessageImprint +{ + private final DigestInfo messageImprint; + + public MessageImprint(DigestInfo messageImprint) + { + this.messageImprint = messageImprint; + } + + public DigestInfo toASN1Structure() + { + return messageImprint; + } + + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + + if (o instanceof MessageImprint) + { + return messageImprint.equals(((MessageImprint)o).messageImprint); + } + + return false; + } + + public int hashCode() + { + return messageImprint.hashCode(); + } +} diff --git a/pkix/src/main/java/org/spongycastle/dvcs/MessageImprintBuilder.java b/pkix/src/main/java/org/spongycastle/dvcs/MessageImprintBuilder.java new file mode 100644 index 00000000..f7dc987e --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/dvcs/MessageImprintBuilder.java @@ -0,0 +1,35 @@ +package org.spongycastle.dvcs; + +import java.io.OutputStream; + +import org.spongycastle.asn1.x509.DigestInfo; +import org.spongycastle.operator.DigestCalculator; + +public class MessageImprintBuilder +{ + private final DigestCalculator digestCalculator; + + public MessageImprintBuilder(DigestCalculator digestCalculator) + { + this.digestCalculator = digestCalculator; + } + + public MessageImprint build(byte[] message) + throws DVCSException + { + try + { + OutputStream dOut = digestCalculator.getOutputStream(); + + dOut.write(message); + + dOut.close(); + + return new MessageImprint(new DigestInfo(digestCalculator.getAlgorithmIdentifier(), digestCalculator.getDigest())); + } + catch (Exception e) + { + throw new DVCSException("unable to build MessageImprint: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/dvcs/SignedDVCSMessageGenerator.java b/pkix/src/main/java/org/spongycastle/dvcs/SignedDVCSMessageGenerator.java new file mode 100644 index 00000000..2378bcf2 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/dvcs/SignedDVCSMessageGenerator.java @@ -0,0 +1,45 @@ +package org.spongycastle.dvcs; + +import java.io.IOException; + +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.CMSProcessableByteArray; +import org.spongycastle.cms.CMSSignedData; +import org.spongycastle.cms.CMSSignedDataGenerator; + +public class SignedDVCSMessageGenerator +{ + private final CMSSignedDataGenerator signedDataGen; + + public SignedDVCSMessageGenerator(CMSSignedDataGenerator signedDataGen) + { + this.signedDataGen = signedDataGen; + } + + /** + * Creates a CMSSignedData object containing the passed in DVCSMessage + * + * @param message the request to be signed. + * @return an encapsulating SignedData object. + * @throws DVCSException in the event of failure to encode the request or sign it. + */ + public CMSSignedData build(DVCSMessage message) + throws DVCSException + { + try + { + byte[] encapsulatedData = message.getContent().toASN1Primitive().getEncoded(ASN1Encoding.DER); + + return signedDataGen.generate(new CMSProcessableByteArray(message.getContentType(), encapsulatedData), true); + } + catch (CMSException e) + { + throw new DVCSException("Could not sign DVCS request", e); + } + catch (IOException e) + { + throw new DVCSException("Could not encode DVCS request", e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/dvcs/TargetChain.java b/pkix/src/main/java/org/spongycastle/dvcs/TargetChain.java new file mode 100644 index 00000000..d45714f3 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/dvcs/TargetChain.java @@ -0,0 +1,18 @@ +package org.spongycastle.dvcs; + +import org.spongycastle.asn1.dvcs.TargetEtcChain; + +public class TargetChain +{ + private final TargetEtcChain certs; + + public TargetChain(TargetEtcChain certs) + { + this.certs = certs; + } + + public TargetEtcChain toASN1Structure() + { + return certs; + } +} diff --git a/pkix/src/main/java/org/spongycastle/dvcs/VPKCRequestBuilder.java b/pkix/src/main/java/org/spongycastle/dvcs/VPKCRequestBuilder.java new file mode 100644 index 00000000..9a68b7d3 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/dvcs/VPKCRequestBuilder.java @@ -0,0 +1,76 @@ +package org.spongycastle.dvcs; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.spongycastle.asn1.dvcs.CertEtcToken; +import org.spongycastle.asn1.dvcs.DVCSRequestInformationBuilder; +import org.spongycastle.asn1.dvcs.DVCSTime; +import org.spongycastle.asn1.dvcs.Data; +import org.spongycastle.asn1.dvcs.ServiceType; +import org.spongycastle.asn1.dvcs.TargetEtcChain; +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.cert.X509CertificateHolder; + +/** + * Builder of DVC requests to VPKC service (Verify Public Key Certificates). + */ +public class VPKCRequestBuilder + extends DVCSRequestBuilder +{ + private List chains = new ArrayList(); + + public VPKCRequestBuilder() + { + super(new DVCSRequestInformationBuilder(ServiceType.VPKC)); + } + + /** + * Adds a TargetChain representing a X.509 certificate to the request. + * + * @param cert the certificate to be added + */ + public void addTargetChain(X509CertificateHolder cert) + { + chains.add(new TargetEtcChain(new CertEtcToken(CertEtcToken.TAG_CERTIFICATE, cert.toASN1Structure()))); + } + + /** + * Adds a TargetChain representing a single X.509 Extension to the request + * + * @param extension the extension to be added. + */ + public void addTargetChain(Extension extension) + { + chains.add(new TargetEtcChain(new CertEtcToken(extension))); + } + + /** + * Adds a X.509 certificate to the request. + * + * @param targetChain the CertChain object to be added. + */ + public void addTargetChain(TargetChain targetChain) + { + chains.add(targetChain.toASN1Structure()); + } + + public void setRequestTime(Date requestTime) + { + requestInformationBuilder.setRequestTime(new DVCSTime(requestTime)); + } + + /** + * Build DVCS request to VPKC service. + * + * @throws DVCSException + */ + public DVCSRequest build() + throws DVCSException + { + Data data = new Data((TargetEtcChain[])chains.toArray(new TargetEtcChain[chains.size()])); + + return createDVCRequest(data); + } +} diff --git a/pkix/src/main/java/org/spongycastle/dvcs/VPKCRequestData.java b/pkix/src/main/java/org/spongycastle/dvcs/VPKCRequestData.java new file mode 100644 index 00000000..561f93bf --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/dvcs/VPKCRequestData.java @@ -0,0 +1,51 @@ +package org.spongycastle.dvcs; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.spongycastle.asn1.dvcs.Data; +import org.spongycastle.asn1.dvcs.TargetEtcChain; + +/** + * Data piece of DVCS request to VPKC service (Verify Public Key Certificates). + * It contains VPKC-specific interface. + * <p/> + * This objects are constructed internally, + * to build DVCS request to VPKC service use VPKCRequestBuilder. + */ +public class VPKCRequestData + extends DVCSRequestData +{ + private List chains; + + VPKCRequestData(Data data) + throws DVCSConstructionException + { + super(data); + + TargetEtcChain[] certs = data.getCerts(); + + if (certs == null) + { + throw new DVCSConstructionException("DVCSRequest.data.certs should be specified for VPKC service"); + } + + chains = new ArrayList(certs.length); + + for (int i = 0; i != certs.length; i++) + { + chains.add(new TargetChain(certs[i])); + } + } + + /** + * Get contained certs choice data.. + * + * @return a list of CertChain objects. + */ + public List getCerts() + { + return Collections.unmodifiableList(chains); + } +} diff --git a/pkix/src/main/java/org/spongycastle/dvcs/VSDRequestBuilder.java b/pkix/src/main/java/org/spongycastle/dvcs/VSDRequestBuilder.java new file mode 100644 index 00000000..f2f7df54 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/dvcs/VSDRequestBuilder.java @@ -0,0 +1,49 @@ +package org.spongycastle.dvcs; + +import java.io.IOException; +import java.util.Date; + +import org.spongycastle.asn1.dvcs.DVCSRequestInformationBuilder; +import org.spongycastle.asn1.dvcs.DVCSTime; +import org.spongycastle.asn1.dvcs.Data; +import org.spongycastle.asn1.dvcs.ServiceType; +import org.spongycastle.cms.CMSSignedData; + +/** + * Builder of DVCS requests to VSD service (Verify Signed Document). + */ +public class VSDRequestBuilder + extends DVCSRequestBuilder +{ + public VSDRequestBuilder() + { + super(new DVCSRequestInformationBuilder(ServiceType.VSD)); + } + + public void setRequestTime(Date requestTime) + { + requestInformationBuilder.setRequestTime(new DVCSTime(requestTime)); + } + + /** + * Build VSD request from CMS SignedData object. + * + * @param document + * @return + * @throws DVCSException + */ + public DVCSRequest build(CMSSignedData document) + throws DVCSException + { + try + { + Data data = new Data(document.getEncoded()); + + return createDVCRequest(data); + } + catch (IOException e) + { + throw new DVCSException("Failed to encode CMS signed data", e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/dvcs/VSDRequestData.java b/pkix/src/main/java/org/spongycastle/dvcs/VSDRequestData.java new file mode 100644 index 00000000..21adaa3f --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/dvcs/VSDRequestData.java @@ -0,0 +1,66 @@ +package org.spongycastle.dvcs; + +import org.spongycastle.asn1.dvcs.Data; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.CMSSignedData; + +/** + * Data piece of DVCS request to VSD service (Verify Signed Document). + * It contains VSD-specific selector interface. + * Note: the request should contain CMS SignedData object as message. + * <p/> + * This objects are constructed internally, + * to build DVCS request to VSD service use VSDRequestBuilder. + */ +public class VSDRequestData + extends DVCSRequestData +{ + private CMSSignedData doc; + + VSDRequestData(Data data) + throws DVCSConstructionException + { + super(data); + initDocument(); + } + + private void initDocument() + throws DVCSConstructionException + { + if (doc == null) + { + if (data.getMessage() == null) + { + throw new DVCSConstructionException("DVCSRequest.data.message should be specified for VSD service"); + } + try + { + doc = new CMSSignedData(data.getMessage().getOctets()); + } + catch (CMSException e) + { + throw new DVCSConstructionException("Can't read CMS SignedData from input", e); + } + } + } + + /** + * Get contained message (data to be certified). + * + * @return + */ + public byte[] getMessage() + { + return data.getMessage().getOctets(); + } + + /** + * Get the CMS SignedData object represented by the encoded message. + * + * @return + */ + public CMSSignedData getParsedMessage() + { + return doc; + } +} diff --git a/pkix/src/main/java/org/spongycastle/eac/EACCertificateBuilder.java b/pkix/src/main/java/org/spongycastle/eac/EACCertificateBuilder.java new file mode 100644 index 00000000..b3ca48e8 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/eac/EACCertificateBuilder.java @@ -0,0 +1,83 @@ +package org.spongycastle.eac; + +import java.io.OutputStream; + +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.DERApplicationSpecific; +import org.spongycastle.asn1.eac.CVCertificate; +import org.spongycastle.asn1.eac.CertificateBody; +import org.spongycastle.asn1.eac.CertificateHolderAuthorization; +import org.spongycastle.asn1.eac.CertificateHolderReference; +import org.spongycastle.asn1.eac.CertificationAuthorityReference; +import org.spongycastle.asn1.eac.EACTags; +import org.spongycastle.asn1.eac.PackedDate; +import org.spongycastle.asn1.eac.PublicKeyDataObject; +import org.spongycastle.eac.operator.EACSigner; + +public class EACCertificateBuilder +{ + private static final byte [] ZeroArray = new byte [] {0}; + + private PublicKeyDataObject publicKey; + private CertificateHolderAuthorization certificateHolderAuthorization; + private PackedDate certificateEffectiveDate; + private PackedDate certificateExpirationDate; + private CertificateHolderReference certificateHolderReference; + private CertificationAuthorityReference certificationAuthorityReference; + + public EACCertificateBuilder( + CertificationAuthorityReference certificationAuthorityReference, + PublicKeyDataObject publicKey, + CertificateHolderReference certificateHolderReference, + CertificateHolderAuthorization certificateHolderAuthorization, + PackedDate certificateEffectiveDate, + PackedDate certificateExpirationDate) + { + this.certificationAuthorityReference = certificationAuthorityReference; + this.publicKey = publicKey; + this.certificateHolderReference = certificateHolderReference; + this.certificateHolderAuthorization = certificateHolderAuthorization; + this.certificateEffectiveDate = certificateEffectiveDate; + this.certificateExpirationDate = certificateExpirationDate; + } + + private CertificateBody buildBody() + { + DERApplicationSpecific certificateProfileIdentifier; + + certificateProfileIdentifier = new DERApplicationSpecific( + EACTags.INTERCHANGE_PROFILE, ZeroArray); + + CertificateBody body = new CertificateBody( + certificateProfileIdentifier, + certificationAuthorityReference, + publicKey, + certificateHolderReference, + certificateHolderAuthorization, + certificateEffectiveDate, + certificateExpirationDate); + + return body; + } + + public EACCertificateHolder build(EACSigner signer) + throws EACException + { + try + { + CertificateBody body = buildBody(); + + OutputStream vOut = signer.getOutputStream(); + + vOut.write(body.getEncoded(ASN1Encoding.DER)); + + vOut.close(); + + return new EACCertificateHolder(new CVCertificate(body, signer.getSignature())); + } + catch (Exception e) + { + throw new EACException("unable to process signature: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/eac/EACCertificateHolder.java b/pkix/src/main/java/org/spongycastle/eac/EACCertificateHolder.java new file mode 100644 index 00000000..edc75a6d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/eac/EACCertificateHolder.java @@ -0,0 +1,88 @@ +package org.spongycastle.eac; + +import java.io.IOException; +import java.io.OutputStream; + +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1ParsingException; +import org.spongycastle.asn1.eac.CVCertificate; +import org.spongycastle.asn1.eac.PublicKeyDataObject; +import org.spongycastle.eac.operator.EACSignatureVerifier; + +public class EACCertificateHolder +{ + private CVCertificate cvCertificate; + + private static CVCertificate parseBytes(byte[] certEncoding) + throws IOException + { + try + { + return CVCertificate.getInstance(certEncoding); + } + catch (ClassCastException e) + { + throw new EACIOException("malformed data: " + e.getMessage(), e); + } + catch (IllegalArgumentException e) + { + throw new EACIOException("malformed data: " + e.getMessage(), e); + } + catch (ASN1ParsingException e) + { + if (e.getCause() instanceof IOException) + { + throw (IOException)e.getCause(); + } + else + { + throw new EACIOException("malformed data: " + e.getMessage(), e); + } + } + } + + public EACCertificateHolder(byte[] certEncoding) + throws IOException + { + this(parseBytes(certEncoding)); + } + + public EACCertificateHolder(CVCertificate cvCertificate) + { + this.cvCertificate = cvCertificate; + } + + /** + * Return the underlying ASN.1 structure for the certificate in this holder. + * + * @return a X509CertificateStructure object. + */ + public CVCertificate toASN1Structure() + { + return cvCertificate; + } + + public PublicKeyDataObject getPublicKeyDataObject() + { + return cvCertificate.getBody().getPublicKey(); + } + + public boolean isSignatureValid(EACSignatureVerifier verifier) + throws EACException + { + try + { + OutputStream vOut = verifier.getOutputStream(); + + vOut.write(cvCertificate.getBody().getEncoded(ASN1Encoding.DER)); + + vOut.close(); + + return verifier.verify(cvCertificate.getSignature()); + } + catch (Exception e) + { + throw new EACException("unable to process signature: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/eac/EACCertificateRequestHolder.java b/pkix/src/main/java/org/spongycastle/eac/EACCertificateRequestHolder.java new file mode 100644 index 00000000..77b01e4d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/eac/EACCertificateRequestHolder.java @@ -0,0 +1,88 @@ +package org.spongycastle.eac; + +import java.io.IOException; +import java.io.OutputStream; + +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1ParsingException; +import org.spongycastle.asn1.eac.CVCertificateRequest; +import org.spongycastle.asn1.eac.PublicKeyDataObject; +import org.spongycastle.eac.operator.EACSignatureVerifier; + +public class EACCertificateRequestHolder +{ + private CVCertificateRequest request; + + private static CVCertificateRequest parseBytes(byte[] requestEncoding) + throws IOException + { + try + { + return CVCertificateRequest.getInstance(requestEncoding); + } + catch (ClassCastException e) + { + throw new EACIOException("malformed data: " + e.getMessage(), e); + } + catch (IllegalArgumentException e) + { + throw new EACIOException("malformed data: " + e.getMessage(), e); + } + catch (ASN1ParsingException e) + { + if (e.getCause() instanceof IOException) + { + throw (IOException)e.getCause(); + } + else + { + throw new EACIOException("malformed data: " + e.getMessage(), e); + } + } + } + + public EACCertificateRequestHolder(byte[] certEncoding) + throws IOException + { + this(parseBytes(certEncoding)); + } + + public EACCertificateRequestHolder(CVCertificateRequest request) + { + this.request = request; + } + + /** + * Return the underlying ASN.1 structure for the certificate in this holder. + * + * @return a X509CertificateStructure object. + */ + public CVCertificateRequest toASN1Structure() + { + return request; + } + + public PublicKeyDataObject getPublicKeyDataObject() + { + return request.getPublicKey(); + } + + public boolean isInnerSignatureValid(EACSignatureVerifier verifier) + throws EACException + { + try + { + OutputStream vOut = verifier.getOutputStream(); + + vOut.write(request.getCertificateBody().getEncoded(ASN1Encoding.DER)); + + vOut.close(); + + return verifier.verify(request.getInnerSignature()); + } + catch (Exception e) + { + throw new EACException("unable to process signature: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/eac/EACException.java b/pkix/src/main/java/org/spongycastle/eac/EACException.java new file mode 100644 index 00000000..d8e1612a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/eac/EACException.java @@ -0,0 +1,27 @@ +package org.spongycastle.eac; + +/** + * General checked Exception thrown in the cert package and its sub-packages. + */ +public class EACException + extends Exception +{ + private Throwable cause; + + public EACException(String msg, Throwable cause) + { + super(msg); + + this.cause = cause; + } + + public EACException(String msg) + { + super(msg); + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/pkix/src/main/java/org/spongycastle/eac/EACIOException.java b/pkix/src/main/java/org/spongycastle/eac/EACIOException.java new file mode 100644 index 00000000..857a6f6a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/eac/EACIOException.java @@ -0,0 +1,29 @@ +package org.spongycastle.eac; + +import java.io.IOException; + +/** + * General IOException thrown in the cert package and its sub-packages. + */ +public class EACIOException + extends IOException +{ + private Throwable cause; + + public EACIOException(String msg, Throwable cause) + { + super(msg); + + this.cause = cause; + } + + public EACIOException(String msg) + { + super(msg); + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/pkix/src/main/java/org/spongycastle/eac/jcajce/DefaultEACHelper.java b/pkix/src/main/java/org/spongycastle/eac/jcajce/DefaultEACHelper.java new file mode 100644 index 00000000..703e1405 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/eac/jcajce/DefaultEACHelper.java @@ -0,0 +1,14 @@ +package org.spongycastle.eac.jcajce; + +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; + +class DefaultEACHelper + implements EACHelper +{ + public KeyFactory createKeyFactory(String type) + throws NoSuchAlgorithmException + { + return KeyFactory.getInstance(type); + } +} diff --git a/pkix/src/main/java/org/spongycastle/eac/jcajce/EACHelper.java b/pkix/src/main/java/org/spongycastle/eac/jcajce/EACHelper.java new file mode 100644 index 00000000..c6f3ffb2 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/eac/jcajce/EACHelper.java @@ -0,0 +1,11 @@ +package org.spongycastle.eac.jcajce; + +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; + +interface EACHelper +{ + KeyFactory createKeyFactory(String type) + throws NoSuchProviderException, NoSuchAlgorithmException; +} diff --git a/pkix/src/main/java/org/spongycastle/eac/jcajce/JcaPublicKeyConverter.java b/pkix/src/main/java/org/spongycastle/eac/jcajce/JcaPublicKeyConverter.java new file mode 100644 index 00000000..9e6a7eca --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/eac/jcajce/JcaPublicKeyConverter.java @@ -0,0 +1,168 @@ +package org.spongycastle.eac.jcajce; + +import java.math.BigInteger; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.PublicKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECField; +import java.security.spec.ECFieldFp; +import java.security.spec.EllipticCurve; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.RSAPublicKeySpec; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.eac.EACObjectIdentifiers; +import org.spongycastle.asn1.eac.ECDSAPublicKey; +import org.spongycastle.asn1.eac.PublicKeyDataObject; +import org.spongycastle.asn1.eac.RSAPublicKey; +import org.spongycastle.eac.EACException; +import org.spongycastle.jce.spec.ECParameterSpec; +import org.spongycastle.jce.spec.ECPublicKeySpec; +import org.spongycastle.math.ec.ECCurve; +import org.spongycastle.math.ec.ECPoint; + +public class JcaPublicKeyConverter +{ + private EACHelper helper = new DefaultEACHelper(); + + public JcaPublicKeyConverter setProvider(String providerName) + { + this.helper = new NamedEACHelper(providerName); + + return this; + } + + public JcaPublicKeyConverter setProvider(Provider provider) + { + this.helper = new ProviderEACHelper(provider); + + return this; + } + + public PublicKey getKey(PublicKeyDataObject publicKeyDataObject) + throws EACException, InvalidKeySpecException + { + if (publicKeyDataObject.getUsage().on(EACObjectIdentifiers.id_TA_ECDSA)) + { + return getECPublicKeyPublicKey((ECDSAPublicKey)publicKeyDataObject); + } + else + { + RSAPublicKey pubKey = (RSAPublicKey)publicKeyDataObject; + RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(pubKey.getModulus(), pubKey.getPublicExponent()); + + try + { + KeyFactory factk = helper.createKeyFactory("RSA"); + + return factk.generatePublic(pubKeySpec); + } + catch (NoSuchProviderException e) + { + throw new EACException("cannot find provider: " + e.getMessage(), e); + } + catch (NoSuchAlgorithmException e) + { + throw new EACException("cannot find algorithm ECDSA: " + e.getMessage(), e); + } + } + } + + private PublicKey getECPublicKeyPublicKey(ECDSAPublicKey key) + throws EACException, InvalidKeySpecException + { + ECParameterSpec spec = getParams(key); + ECCurve curve = spec.getCurve(); + + ECPoint point = curve.decodePoint(key.getPublicPointY()); + ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, spec); + + KeyFactory factk; + try + { + factk = helper.createKeyFactory("ECDSA"); + } + catch (NoSuchProviderException e) + { + throw new EACException("cannot find provider: " + e.getMessage(), e); + } + catch (NoSuchAlgorithmException e) + { + throw new EACException("cannot find algorithm ECDSA: " + e.getMessage(), e); + } + + return factk.generatePublic(pubKeySpec); + } + + private ECParameterSpec getParams(ECDSAPublicKey key) + { + if (!key.hasParameters()) + { + throw new IllegalArgumentException("Public key does not contains EC Params"); + } + + BigInteger p = key.getPrimeModulusP(); + ECCurve.Fp curve = new ECCurve.Fp(p, key.getFirstCoefA(), key.getSecondCoefB()); + + ECPoint G = curve.decodePoint(key.getBasePointG()); + + BigInteger order = key.getOrderOfBasePointR(); + BigInteger coFactor = key.getCofactorF(); + // TODO: update to use JDK 1.5 EC API + ECParameterSpec ecspec = new ECParameterSpec(curve, G, order, coFactor); + + return ecspec; + } + + public PublicKeyDataObject getPublicKeyDataObject(ASN1ObjectIdentifier usage, PublicKey publicKey) + { + if (publicKey instanceof java.security.interfaces.RSAPublicKey) + { + java.security.interfaces.RSAPublicKey pubKey = (java.security.interfaces.RSAPublicKey)publicKey; + + return new RSAPublicKey(usage, pubKey.getModulus(), pubKey.getPublicExponent()); + } + else + { + ECPublicKey pubKey = (ECPublicKey)publicKey; + java.security.spec.ECParameterSpec params = pubKey.getParams(); + + return new ECDSAPublicKey( + usage, + ((ECFieldFp)params.getCurve().getField()).getP(), + params.getCurve().getA(), params.getCurve().getB(), + convertPoint(convertCurve(params.getCurve()), params.getGenerator(), false).getEncoded(), + params.getOrder(), + convertPoint(convertCurve(params.getCurve()), pubKey.getW(), false).getEncoded(), + params.getCofactor()); + } + } + + private static org.spongycastle.math.ec.ECPoint convertPoint( + ECCurve curve, + java.security.spec.ECPoint point, + boolean withCompression) + { + return curve.createPoint(point.getAffineX(), point.getAffineY(), withCompression); + } + + private static ECCurve convertCurve( + EllipticCurve ec) + { + ECField field = ec.getField(); + BigInteger a = ec.getA(); + BigInteger b = ec.getB(); + + if (field instanceof ECFieldFp) + { + return new ECCurve.Fp(((ECFieldFp)field).getP(), a, b); + } + else + { + throw new IllegalStateException("not implemented yet!!!"); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/eac/jcajce/NamedEACHelper.java b/pkix/src/main/java/org/spongycastle/eac/jcajce/NamedEACHelper.java new file mode 100644 index 00000000..7e85142d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/eac/jcajce/NamedEACHelper.java @@ -0,0 +1,22 @@ +package org.spongycastle.eac.jcajce; + +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; + +class NamedEACHelper + implements EACHelper +{ + private final String providerName; + + NamedEACHelper(String providerName) + { + this.providerName = providerName; + } + + public KeyFactory createKeyFactory(String type) + throws NoSuchProviderException, NoSuchAlgorithmException + { + return KeyFactory.getInstance(type, providerName); + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/eac/jcajce/ProviderEACHelper.java b/pkix/src/main/java/org/spongycastle/eac/jcajce/ProviderEACHelper.java new file mode 100644 index 00000000..2cda60a2 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/eac/jcajce/ProviderEACHelper.java @@ -0,0 +1,22 @@ +package org.spongycastle.eac.jcajce; + +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; + +class ProviderEACHelper + implements EACHelper +{ + private final Provider provider; + + ProviderEACHelper(Provider provider) + { + this.provider = provider; + } + + public KeyFactory createKeyFactory(String type) + throws NoSuchAlgorithmException + { + return KeyFactory.getInstance(type, provider); + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/eac/operator/EACSignatureVerifier.java b/pkix/src/main/java/org/spongycastle/eac/operator/EACSignatureVerifier.java new file mode 100644 index 00000000..3dd967b9 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/eac/operator/EACSignatureVerifier.java @@ -0,0 +1,30 @@ +package org.spongycastle.eac.operator; + +import java.io.OutputStream; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; + +public interface EACSignatureVerifier +{ + /** + * Return the usage OID specifying the signature type. + * + * @return algorithm oid. + */ + ASN1ObjectIdentifier getUsageIdentifier(); + + /** + * Returns a stream that will accept data for the purpose of calculating + * a signature for later verification. Use org.spongycastle.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/pkix/src/main/java/org/spongycastle/eac/operator/EACSigner.java b/pkix/src/main/java/org/spongycastle/eac/operator/EACSigner.java new file mode 100644 index 00000000..9a53685a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/eac/operator/EACSigner.java @@ -0,0 +1,27 @@ +package org.spongycastle.eac.operator; + +import java.io.OutputStream; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; + +public interface EACSigner +{ + ASN1ObjectIdentifier getUsageIdentifier(); + + /** + * Returns a stream that will accept data for the purpose of calculating + * a signature. Use org.spongycastle.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/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/DefaultEACHelper.java b/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/DefaultEACHelper.java new file mode 100644 index 00000000..3aab0585 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/DefaultEACHelper.java @@ -0,0 +1,14 @@ +package org.spongycastle.eac.operator.jcajce; + +import java.security.NoSuchAlgorithmException; +import java.security.Signature; + +class DefaultEACHelper + extends EACHelper +{ + protected Signature createSignature(String type) + throws NoSuchAlgorithmException + { + return Signature.getInstance(type); + } +} diff --git a/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/EACHelper.java b/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/EACHelper.java new file mode 100644 index 00000000..21369981 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/EACHelper.java @@ -0,0 +1,39 @@ +package org.spongycastle.eac.operator.jcajce; + +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Signature; +import java.util.Hashtable; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.eac.EACObjectIdentifiers; + +abstract class EACHelper +{ + private static final Hashtable sigNames = new Hashtable(); + + static + { + sigNames.put(EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_1, "SHA1withRSA"); + sigNames.put(EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_256, "SHA256withRSA"); + sigNames.put(EACObjectIdentifiers.id_TA_RSA_PSS_SHA_1, "SHA1withRSAandMGF1"); + sigNames.put(EACObjectIdentifiers.id_TA_RSA_PSS_SHA_256, "SHA256withRSAandMGF1"); + sigNames.put(EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_512, "SHA512withRSA"); + sigNames.put(EACObjectIdentifiers.id_TA_RSA_PSS_SHA_512, "SHA512withRSAandMGF1"); + + sigNames.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_1, "SHA1withECDSA"); + sigNames.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224withECDSA"); + sigNames.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_256, "SHA256withECDSA"); + sigNames.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_384, "SHA384withECDSA"); + sigNames.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_512, "SHA512withECDSA"); + } + + public Signature getSignature(ASN1ObjectIdentifier oid) + throws NoSuchProviderException, NoSuchAlgorithmException + { + return createSignature((String)sigNames.get(oid)); + } + + protected abstract Signature createSignature(String type) + throws NoSuchProviderException, NoSuchAlgorithmException; +} diff --git a/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/EACUtil.java b/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/EACUtil.java new file mode 100644 index 00000000..c21178a5 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/EACUtil.java @@ -0,0 +1,5 @@ +package org.spongycastle.eac.operator.jcajce; + +class EACUtil +{ +} diff --git a/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/JcaEACSignatureVerifierBuilder.java b/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/JcaEACSignatureVerifierBuilder.java new file mode 100644 index 00000000..7ffdb79a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/JcaEACSignatureVerifierBuilder.java @@ -0,0 +1,181 @@ +package org.spongycastle.eac.operator.jcajce; + +import java.io.IOException; +import java.io.OutputStream; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.eac.EACObjectIdentifiers; +import org.spongycastle.eac.operator.EACSignatureVerifier; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.operator.OperatorStreamException; +import org.spongycastle.operator.RuntimeOperatorException; + +public class JcaEACSignatureVerifierBuilder +{ + private EACHelper helper = new DefaultEACHelper(); + + public JcaEACSignatureVerifierBuilder setProvider(String providerName) + { + this.helper = new NamedEACHelper(providerName); + + return this; + } + + public JcaEACSignatureVerifierBuilder setProvider(Provider provider) + { + this.helper = new ProviderEACHelper(provider); + + return this; + } + + public EACSignatureVerifier build(final ASN1ObjectIdentifier usageOid, PublicKey pubKey) + throws OperatorCreationException + { + Signature sig; + try + { + sig = helper.getSignature(usageOid); + + sig.initVerify(pubKey); + } + catch (NoSuchAlgorithmException e) + { + throw new OperatorCreationException("unable to find algorithm: " + e.getMessage(), e); + } + catch (NoSuchProviderException e) + { + throw new OperatorCreationException("unable to find provider: " + e.getMessage(), e); + } + catch (InvalidKeyException e) + { + throw new OperatorCreationException("invalid key: " + e.getMessage(), e); + } + + final SignatureOutputStream sigStream = new SignatureOutputStream(sig); + + return new EACSignatureVerifier() + { + public ASN1ObjectIdentifier getUsageIdentifier() + { + return usageOid; + } + + public OutputStream getOutputStream() + { + return sigStream; + } + + public boolean verify(byte[] expected) + { + try + { + if (usageOid.on(EACObjectIdentifiers.id_TA_ECDSA)) + { + try + { + byte[] reencoded = derEncode(expected); + + return sigStream.verify(reencoded); + } + catch (Exception e) + { + return false; + } + } + else + { + return sigStream.verify(expected); + } + } + catch (SignatureException e) + { + throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e); + } + } + }; + } + + private static byte[] derEncode(byte[] rawSign) throws IOException + { + int len = rawSign.length / 2; + + byte[] r = new byte[len]; + byte[] s = new byte[len]; + System.arraycopy(rawSign, 0, r, 0, len); + System.arraycopy(rawSign, len, s, 0, len); + + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(new ASN1Integer(new BigInteger(1, r))); + v.add(new ASN1Integer(new BigInteger(1, s))); + + DERSequence seq = new DERSequence(v); + return seq.getEncoded(); + } + + 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); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/JcaEACSignerBuilder.java b/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/JcaEACSignerBuilder.java new file mode 100644 index 00000000..460bb5cf --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/JcaEACSignerBuilder.java @@ -0,0 +1,234 @@ +package org.spongycastle.eac.operator.jcajce; + +import java.io.IOException; +import java.io.OutputStream; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.Signature; +import java.security.SignatureException; +import java.util.Arrays; +import java.util.Hashtable; + +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.eac.EACObjectIdentifiers; +import org.spongycastle.eac.operator.EACSigner; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.operator.OperatorStreamException; +import org.spongycastle.operator.RuntimeOperatorException; + +public class JcaEACSignerBuilder +{ + private static final Hashtable sigNames = new Hashtable(); + + static + { + sigNames.put("SHA1withRSA", EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_1); + sigNames.put("SHA256withRSA", EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_256); + sigNames.put("SHA1withRSAandMGF1", EACObjectIdentifiers.id_TA_RSA_PSS_SHA_1); + sigNames.put("SHA256withRSAandMGF1", EACObjectIdentifiers.id_TA_RSA_PSS_SHA_256); + sigNames.put("SHA512withRSA", EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_512); + sigNames.put("SHA512withRSAandMGF1", EACObjectIdentifiers.id_TA_RSA_PSS_SHA_512); + + sigNames.put("SHA1withECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1); + sigNames.put("SHA224withECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_224); + sigNames.put("SHA256withECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_256); + sigNames.put("SHA384withECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_384); + sigNames.put("SHA512withECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_512); + } + + private EACHelper helper = new DefaultEACHelper(); + + public JcaEACSignerBuilder setProvider(String providerName) + { + this.helper = new NamedEACHelper(providerName); + + return this; + } + + public JcaEACSignerBuilder setProvider(Provider provider) + { + this.helper = new ProviderEACHelper(provider); + + return this; + } + + public EACSigner build(String algorithm, PrivateKey privKey) + throws OperatorCreationException + { + return build((ASN1ObjectIdentifier)sigNames.get(algorithm), privKey); + } + + public EACSigner build(final ASN1ObjectIdentifier usageOid, PrivateKey privKey) + throws OperatorCreationException + { + Signature sig; + try + { + sig = helper.getSignature(usageOid); + + sig.initSign(privKey); + } + catch (NoSuchAlgorithmException e) + { + throw new OperatorCreationException("unable to find algorithm: " + e.getMessage(), e); + } + catch (NoSuchProviderException e) + { + throw new OperatorCreationException("unable to find provider: " + e.getMessage(), e); + } + catch (InvalidKeyException e) + { + throw new OperatorCreationException("invalid key: " + e.getMessage(), e); + } + + final SignatureOutputStream sigStream = new SignatureOutputStream(sig); + + return new EACSigner() + { + public ASN1ObjectIdentifier getUsageIdentifier() + { + return usageOid; + } + + public OutputStream getOutputStream() + { + return sigStream; + } + + public byte[] getSignature() + { + try + { + byte[] signature = sigStream.getSignature(); + + if (usageOid.on(EACObjectIdentifiers.id_TA_ECDSA)) + { + return reencode(signature); + } + + return signature; + } + catch (SignatureException e) + { + throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e); + } + } + }; + } + + public static int max(int el1, int el2) + { + return el1 > el2 ? el1 : el2; + } + + private static byte[] reencode(byte[] rawSign) + { + ASN1Sequence sData = ASN1Sequence.getInstance(rawSign); + + BigInteger r = ASN1Integer.getInstance(sData.getObjectAt(0)).getValue(); + BigInteger s = ASN1Integer.getInstance(sData.getObjectAt(1)).getValue(); + + byte[] rB = r.toByteArray(); + byte[] sB = s.toByteArray(); + + int rLen = unsignedIntLength(rB); + int sLen = unsignedIntLength(sB); + + byte[] ret; + int len = max(rLen, sLen); + + ret = new byte[len * 2]; + Arrays.fill(ret, (byte)0); + + copyUnsignedInt(rB, ret, len - rLen); + copyUnsignedInt(sB, ret, 2 * len - sLen); + + return ret; + } + + private static int unsignedIntLength(byte[] i) + { + int len = i.length; + if (i[0] == 0) + { + len--; + } + + return len; + } + + private static void copyUnsignedInt(byte[] src, byte[] dst, int offset) + { + int len = src.length; + int readoffset = 0; + if (src[0] == 0) + { + len--; + readoffset = 1; + } + + System.arraycopy(src, readoffset, dst, offset, len); + } + + 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/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/NamedEACHelper.java b/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/NamedEACHelper.java new file mode 100644 index 00000000..129356c2 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/NamedEACHelper.java @@ -0,0 +1,22 @@ +package org.spongycastle.eac.operator.jcajce; + +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Signature; + +class NamedEACHelper + extends EACHelper +{ + private final String providerName; + + NamedEACHelper(String providerName) + { + this.providerName = providerName; + } + + protected Signature createSignature(String type) + throws NoSuchProviderException, NoSuchAlgorithmException + { + return Signature.getInstance(type, providerName); + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/ProviderEACHelper.java b/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/ProviderEACHelper.java new file mode 100644 index 00000000..e222dbdb --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/ProviderEACHelper.java @@ -0,0 +1,22 @@ +package org.spongycastle.eac.operator.jcajce; + +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Signature; + +class ProviderEACHelper + extends EACHelper +{ + private final Provider provider; + + ProviderEACHelper(Provider provider) + { + this.provider = provider; + } + + protected Signature createSignature(String type) + throws NoSuchAlgorithmException + { + return Signature.getInstance(type, provider); + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/mozilla/SignedPublicKeyAndChallenge.java b/pkix/src/main/java/org/spongycastle/mozilla/SignedPublicKeyAndChallenge.java new file mode 100644 index 00000000..3244663a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/mozilla/SignedPublicKeyAndChallenge.java @@ -0,0 +1,139 @@ +package org.spongycastle.mozilla; + +import java.io.ByteArrayInputStream; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.spec.X509EncodedKeySpec; + +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1Object; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.DERBitString; +import org.spongycastle.asn1.mozilla.PublicKeyAndChallenge; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; + +/** + * This is designed to parse the SignedPublicKeyAndChallenge created by the + * KEYGEN tag included by Mozilla based browsers. + * <pre> + * PublicKeyAndChallenge ::= SEQUENCE { + * spki SubjectPublicKeyInfo, + * challenge IA5STRING + * } + * + * SignedPublicKeyAndChallenge ::= SEQUENCE { + * publicKeyAndChallenge PublicKeyAndChallenge, + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING + * } + * </pre> + */ +public class SignedPublicKeyAndChallenge + extends ASN1Object +{ + private static ASN1Sequence toDERSequence(byte[] bytes) + { + try + { + ByteArrayInputStream bIn = new ByteArrayInputStream(bytes); + ASN1InputStream aIn = new ASN1InputStream(bIn); + + return (ASN1Sequence)aIn.readObject(); + } + catch (Exception e) + { + throw new IllegalArgumentException("badly encoded request"); + } + } + + private ASN1Sequence spkacSeq; + private PublicKeyAndChallenge pkac; + private AlgorithmIdentifier signatureAlgorithm; + private DERBitString signature; + + public SignedPublicKeyAndChallenge(byte[] bytes) + { + spkacSeq = toDERSequence(bytes); + pkac = PublicKeyAndChallenge.getInstance(spkacSeq.getObjectAt(0)); + signatureAlgorithm = + AlgorithmIdentifier.getInstance(spkacSeq.getObjectAt(1)); + signature = (DERBitString)spkacSeq.getObjectAt(2); + } + + public ASN1Primitive toASN1Primitive() + { + return spkacSeq; + } + + public PublicKeyAndChallenge getPublicKeyAndChallenge() + { + return pkac; + } + + public boolean verify() + throws NoSuchAlgorithmException, SignatureException, + NoSuchProviderException, InvalidKeyException + { + return verify(null); + } + + public boolean verify(String provider) + throws NoSuchAlgorithmException, SignatureException, + NoSuchProviderException, InvalidKeyException + { + Signature sig = null; + if (provider == null) + { + sig = Signature.getInstance(signatureAlgorithm.getAlgorithm().getId()); + } + else + { + sig = Signature.getInstance(signatureAlgorithm.getAlgorithm().getId(), provider); + } + PublicKey pubKey = this.getPublicKey(provider); + sig.initVerify(pubKey); + try + { + DERBitString pkBytes = new DERBitString(pkac); + sig.update(pkBytes.getBytes()); + + return sig.verify(signature.getBytes()); + } + catch (Exception e) + { + throw new InvalidKeyException("error encoding public key"); + } + } + + public PublicKey getPublicKey(String provider) + throws NoSuchAlgorithmException, NoSuchProviderException, + InvalidKeyException + { + SubjectPublicKeyInfo subjectPKInfo = pkac.getSubjectPublicKeyInfo(); + try + { + DERBitString bStr = new DERBitString(subjectPKInfo); + X509EncodedKeySpec xspec = new X509EncodedKeySpec(bStr.getBytes()); + + + AlgorithmIdentifier keyAlg = subjectPKInfo.getAlgorithm(); + + KeyFactory factory = + KeyFactory.getInstance(keyAlg.getAlgorithm().getId(),provider); + + return factory.generatePublic(xspec); + + } + catch (Exception e) + { + throw new InvalidKeyException("error encoding public key"); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/EncryptionException.java b/pkix/src/main/java/org/spongycastle/openssl/EncryptionException.java new file mode 100644 index 00000000..64ef73eb --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/EncryptionException.java @@ -0,0 +1,23 @@ +package org.spongycastle.openssl; + +public class EncryptionException + extends PEMException +{ + private Throwable cause; + + public EncryptionException(String msg) + { + super(msg); + } + + public EncryptionException(String msg, Throwable ex) + { + super(msg); + this.cause = ex; + } + + public Throwable getCause() + { + return cause; + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/openssl/MiscPEMGenerator.java b/pkix/src/main/java/org/spongycastle/openssl/MiscPEMGenerator.java new file mode 100644 index 00000000..995bf7b5 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/MiscPEMGenerator.java @@ -0,0 +1,209 @@ +package org.spongycastle.openssl; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PrivateKeyInfo; +import org.spongycastle.asn1.x509.DSAParameter; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.asn1.x9.X9ObjectIdentifiers; +import org.spongycastle.cert.X509AttributeCertificateHolder; +import org.spongycastle.cert.X509CRLHolder; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.pkcs.PKCS10CertificationRequest; +import org.spongycastle.util.Strings; +import org.spongycastle.util.io.pem.PemGenerationException; +import org.spongycastle.util.io.pem.PemHeader; +import org.spongycastle.util.io.pem.PemObject; +import org.spongycastle.util.io.pem.PemObjectGenerator; + +/** + * PEM generator for the original set of PEM objects used in Open SSL. + */ +public class MiscPEMGenerator + implements PemObjectGenerator +{ + private static final ASN1ObjectIdentifier[] dsaOids = + { + X9ObjectIdentifiers.id_dsa, + OIWObjectIdentifiers.dsaWithSHA1 + }; + + private static final byte[] hexEncodingTable = + { + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', + (byte)'8', (byte)'9', (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F' + }; + + private final Object obj; + private final PEMEncryptor encryptor; + + public MiscPEMGenerator(Object o) + { + this.obj = o; // use of this confuses some earlier JDKs. + this.encryptor = null; + } + + public MiscPEMGenerator(Object o, PEMEncryptor encryptor) + { + this.obj = o; + this.encryptor = encryptor; + } + + private PemObject createPemObject(Object o) + throws IOException + { + String type; + byte[] encoding; + + if (o instanceof PemObject) + { + return (PemObject)o; + } + if (o instanceof PemObjectGenerator) + { + return ((PemObjectGenerator)o).generate(); + } + if (o instanceof X509CertificateHolder) + { + type = "CERTIFICATE"; + + encoding = ((X509CertificateHolder)o).getEncoded(); + } + else if (o instanceof X509CRLHolder) + { + type = "X509 CRL"; + + encoding = ((X509CRLHolder)o).getEncoded(); + } + else if (o instanceof PrivateKeyInfo) + { + PrivateKeyInfo info = (PrivateKeyInfo)o; + ASN1ObjectIdentifier algOID = info.getPrivateKeyAlgorithm().getAlgorithm(); + + if (algOID.equals(PKCSObjectIdentifiers.rsaEncryption)) + { + type = "RSA PRIVATE KEY"; + + encoding = info.parsePrivateKey().toASN1Primitive().getEncoded(); + } + else if (algOID.equals(dsaOids[0]) || algOID.equals(dsaOids[1])) + { + type = "DSA PRIVATE KEY"; + + DSAParameter p = DSAParameter.getInstance(info.getPrivateKeyAlgorithm().getParameters()); + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(0)); + v.add(new ASN1Integer(p.getP())); + v.add(new ASN1Integer(p.getQ())); + v.add(new ASN1Integer(p.getG())); + + BigInteger x = ASN1Integer.getInstance(info.parsePrivateKey()).getValue(); + BigInteger y = p.getG().modPow(x, p.getP()); + + v.add(new ASN1Integer(y)); + v.add(new ASN1Integer(x)); + + encoding = new DERSequence(v).getEncoded(); + } + else if (algOID.equals(X9ObjectIdentifiers.id_ecPublicKey)) + { + type = "EC PRIVATE KEY"; + + encoding = info.parsePrivateKey().toASN1Primitive().getEncoded(); + } + else + { + throw new IOException("Cannot identify private key"); + } + } + else if (o instanceof SubjectPublicKeyInfo) + { + type = "PUBLIC KEY"; + + encoding = ((SubjectPublicKeyInfo)o).getEncoded(); + } + else if (o instanceof X509AttributeCertificateHolder) + { + type = "ATTRIBUTE CERTIFICATE"; + encoding = ((X509AttributeCertificateHolder)o).getEncoded(); + } + else if (o instanceof org.spongycastle.pkcs.PKCS10CertificationRequest) + { + type = "CERTIFICATE REQUEST"; + encoding = ((PKCS10CertificationRequest)o).getEncoded(); + } + else if (o instanceof ContentInfo) + { + type = "PKCS7"; + encoding = ((ContentInfo)o).getEncoded(); + } + else + { + throw new PemGenerationException("unknown object passed - can't encode."); + } + + if (encryptor != null) + { + String dekAlgName = Strings.toUpperCase(encryptor.getAlgorithm()); + + // Note: For backward compatibility + if (dekAlgName.equals("DESEDE")) + { + dekAlgName = "DES-EDE3-CBC"; + } + + + byte[] iv = encryptor.getIV(); + + byte[] encData = encryptor.encrypt(encoding); + + List headers = new ArrayList(2); + + headers.add(new PemHeader("Proc-Type", "4,ENCRYPTED")); + headers.add(new PemHeader("DEK-Info", dekAlgName + "," + getHexEncoded(iv))); + + return new PemObject(type, headers, encData); + } + return new PemObject(type, encoding); + } + + private String getHexEncoded(byte[] bytes) + throws IOException + { + char[] chars = new char[bytes.length * 2]; + + for (int i = 0; i != bytes.length; i++) + { + int v = bytes[i] & 0xff; + + chars[2 * i] = (char)(hexEncodingTable[(v >>> 4)]); + chars[2 * i + 1] = (char)(hexEncodingTable[v & 0xf]); + } + + return new String(chars); + } + + public PemObject generate() + throws PemGenerationException + { + try + { + return createPemObject(obj); + } + catch (IOException e) + { + throw new PemGenerationException("encoding exception: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/PEMDecryptor.java b/pkix/src/main/java/org/spongycastle/openssl/PEMDecryptor.java new file mode 100644 index 00000000..3bd54df6 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/PEMDecryptor.java @@ -0,0 +1,7 @@ +package org.spongycastle.openssl; + +public interface PEMDecryptor +{ + byte[] decrypt(byte[] keyBytes, byte[] iv) + throws PEMException; +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/PEMDecryptorProvider.java b/pkix/src/main/java/org/spongycastle/openssl/PEMDecryptorProvider.java new file mode 100644 index 00000000..0d0b1e5c --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/PEMDecryptorProvider.java @@ -0,0 +1,9 @@ +package org.spongycastle.openssl; + +import org.spongycastle.operator.OperatorCreationException; + +public interface PEMDecryptorProvider +{ + PEMDecryptor get(String dekAlgName) + throws OperatorCreationException; +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/PEMEncryptedKeyPair.java b/pkix/src/main/java/org/spongycastle/openssl/PEMEncryptedKeyPair.java new file mode 100644 index 00000000..4a04de14 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/PEMEncryptedKeyPair.java @@ -0,0 +1,44 @@ +package org.spongycastle.openssl; + +import java.io.IOException; + +import org.spongycastle.operator.OperatorCreationException; + +public class PEMEncryptedKeyPair +{ + private final String dekAlgName; + private final byte[] iv; + private final byte[] keyBytes; + private final PEMKeyPairParser parser; + + PEMEncryptedKeyPair(String dekAlgName, byte[] iv, byte[] keyBytes, PEMKeyPairParser parser) + { + this.dekAlgName = dekAlgName; + this.iv = iv; + this.keyBytes = keyBytes; + this.parser = parser; + } + + public PEMKeyPair decryptKeyPair(PEMDecryptorProvider keyDecryptorProvider) + throws IOException + { + try + { + PEMDecryptor keyDecryptor = keyDecryptorProvider.get(dekAlgName); + + return parser.parse(keyDecryptor.decrypt(keyBytes, iv)); + } + catch (IOException e) + { + throw e; + } + catch (OperatorCreationException e) + { + throw new PEMException("cannot create extraction operator: " + e.getMessage(), e); + } + catch (Exception e) + { + throw new PEMException("exception processing key pair: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/PEMEncryptor.java b/pkix/src/main/java/org/spongycastle/openssl/PEMEncryptor.java new file mode 100644 index 00000000..63b42b2d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/PEMEncryptor.java @@ -0,0 +1,11 @@ +package org.spongycastle.openssl; + +public interface PEMEncryptor +{ + String getAlgorithm(); + + byte[] getIV(); + + byte[] encrypt(byte[] encoding) + throws PEMException; +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/PEMException.java b/pkix/src/main/java/org/spongycastle/openssl/PEMException.java new file mode 100644 index 00000000..5df7b5f5 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/PEMException.java @@ -0,0 +1,34 @@ +package org.spongycastle.openssl; + +import java.io.IOException; + +public class PEMException + extends IOException +{ + Exception underlying; + + public PEMException( + String message) + { + super(message); + } + + public PEMException( + String message, + Exception underlying) + { + super(message); + this.underlying = underlying; + } + + public Exception getUnderlyingException() + { + return underlying; + } + + + public Throwable getCause() + { + return underlying; + } +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/PEMKeyPair.java b/pkix/src/main/java/org/spongycastle/openssl/PEMKeyPair.java new file mode 100644 index 00000000..ad010634 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/PEMKeyPair.java @@ -0,0 +1,26 @@ +package org.spongycastle.openssl; + +import org.spongycastle.asn1.pkcs.PrivateKeyInfo; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; + +public class PEMKeyPair +{ + private final SubjectPublicKeyInfo publicKeyInfo; + private final PrivateKeyInfo privateKeyInfo; + + public PEMKeyPair(SubjectPublicKeyInfo publicKeyInfo, PrivateKeyInfo privateKeyInfo) + { + this.publicKeyInfo = publicKeyInfo; + this.privateKeyInfo = privateKeyInfo; + } + + public PrivateKeyInfo getPrivateKeyInfo() + { + return privateKeyInfo; + } + + public SubjectPublicKeyInfo getPublicKeyInfo() + { + return publicKeyInfo; + } +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/PEMKeyPairParser.java b/pkix/src/main/java/org/spongycastle/openssl/PEMKeyPairParser.java new file mode 100644 index 00000000..32583fd9 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/PEMKeyPairParser.java @@ -0,0 +1,9 @@ +package org.spongycastle.openssl; + +import java.io.IOException; + +interface PEMKeyPairParser +{ + PEMKeyPair parse(byte[] encoding) + throws IOException; +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/PEMParser.java b/pkix/src/main/java/org/spongycastle/openssl/PEMParser.java new file mode 100644 index 00000000..bafe2126 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/PEMParser.java @@ -0,0 +1,510 @@ +package org.spongycastle.openssl; + +import java.io.IOException; +import java.io.Reader; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PrivateKeyInfo; +import org.spongycastle.asn1.pkcs.RSAPublicKey; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.DSAParameter; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.asn1.x9.X9ECParameters; +import org.spongycastle.asn1.x9.X9ObjectIdentifiers; +import org.spongycastle.cert.X509AttributeCertificateHolder; +import org.spongycastle.cert.X509CRLHolder; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.pkcs.PKCS10CertificationRequest; +import org.spongycastle.pkcs.PKCS8EncryptedPrivateKeyInfo; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.io.pem.PemHeader; +import org.spongycastle.util.io.pem.PemObject; +import org.spongycastle.util.io.pem.PemObjectParser; +import org.spongycastle.util.io.pem.PemReader; + +/** + * Class for parsing OpenSSL PEM encoded streams containing + * X509 certificates, PKCS8 encoded keys and PKCS7 objects. + * <p> + * In the case of PKCS7 objects the reader will return a CMS ContentInfo object. Public keys will be returned as + * well formed SubjectPublicKeyInfo objects, private keys will be returned as well formed PrivateKeyInfo objects. In the + * case of a private key a PEMKeyPair will normally be returned if the encoding contains both the private and public + * key definition. CRLs, Certificates, PKCS#10 requests, and Attribute Certificates will generate the appropriate BC holder class. + * </p> + */ +public class PEMParser + extends PemReader +{ + private final Map parsers = new HashMap(); + + /** + * Create a new PEMReader + * + * @param reader the Reader + */ + public PEMParser( + Reader reader) + { + super(reader); + + parsers.put("CERTIFICATE REQUEST", new PKCS10CertificationRequestParser()); + parsers.put("NEW CERTIFICATE REQUEST", new PKCS10CertificationRequestParser()); + parsers.put("CERTIFICATE", new X509CertificateParser()); + parsers.put("TRUSTED CERTIFICATE", new X509CertificateParser()); + parsers.put("X509 CERTIFICATE", new X509CertificateParser()); + parsers.put("X509 CRL", new X509CRLParser()); + parsers.put("PKCS7", new PKCS7Parser()); + parsers.put("ATTRIBUTE CERTIFICATE", new X509AttributeCertificateParser()); + parsers.put("EC PARAMETERS", new ECCurveParamsParser()); + parsers.put("PUBLIC KEY", new PublicKeyParser()); + parsers.put("RSA PUBLIC KEY", new RSAPublicKeyParser()); + parsers.put("RSA PRIVATE KEY", new KeyPairParser(new RSAKeyPairParser())); + parsers.put("DSA PRIVATE KEY", new KeyPairParser(new DSAKeyPairParser())); + parsers.put("EC PRIVATE KEY", new KeyPairParser(new ECDSAKeyPairParser())); + parsers.put("ENCRYPTED PRIVATE KEY", new EncryptedPrivateKeyParser()); + parsers.put("PRIVATE KEY", new PrivateKeyParser()); + } + + public Object readObject() + throws IOException + { + PemObject obj = readPemObject(); + + if (obj != null) + { + String type = obj.getType(); + if (parsers.containsKey(type)) + { + return ((PemObjectParser)parsers.get(type)).parseObject(obj); + } + else + { + throw new IOException("unrecognised object: " + type); + } + } + + return null; + } + + private class KeyPairParser + implements PemObjectParser + { + private final PEMKeyPairParser pemKeyPairParser; + + public KeyPairParser(PEMKeyPairParser pemKeyPairParser) + { + this.pemKeyPairParser = pemKeyPairParser; + } + + /** + * Read a Key Pair + */ + public Object parseObject( + PemObject obj) + throws IOException + { + boolean isEncrypted = false; + String dekInfo = null; + List headers = obj.getHeaders(); + + for (Iterator it = headers.iterator(); it.hasNext();) + { + PemHeader hdr = (PemHeader)it.next(); + + if (hdr.getName().equals("Proc-Type") && hdr.getValue().equals("4,ENCRYPTED")) + { + isEncrypted = true; + } + else if (hdr.getName().equals("DEK-Info")) + { + dekInfo = hdr.getValue(); + } + } + + // + // extract the key + // + byte[] keyBytes = obj.getContent(); + + try + { + if (isEncrypted) + { + StringTokenizer tknz = new StringTokenizer(dekInfo, ","); + String dekAlgName = tknz.nextToken(); + byte[] iv = Hex.decode(tknz.nextToken()); + + return new PEMEncryptedKeyPair(dekAlgName, iv, keyBytes, pemKeyPairParser); + } + + return pemKeyPairParser.parse(keyBytes); + } + catch (IOException e) + { + if (isEncrypted) + { + throw new PEMException("exception decoding - please check password and data.", e); + } + else + { + throw new PEMException(e.getMessage(), e); + } + } + catch (IllegalArgumentException e) + { + if (isEncrypted) + { + throw new PEMException("exception decoding - please check password and data.", e); + } + else + { + throw new PEMException(e.getMessage(), e); + } + } + } + } + + private class DSAKeyPairParser + implements PEMKeyPairParser + { + public PEMKeyPair parse(byte[] encoding) + throws IOException + { + try + { + ASN1Sequence seq = ASN1Sequence.getInstance(encoding); + + if (seq.size() != 6) + { + throw new PEMException("malformed sequence in DSA private key"); + } + + // ASN1Integer v = (ASN1Integer)seq.getObjectAt(0); + ASN1Integer p = ASN1Integer.getInstance(seq.getObjectAt(1)); + ASN1Integer q = ASN1Integer.getInstance(seq.getObjectAt(2)); + ASN1Integer g = ASN1Integer.getInstance(seq.getObjectAt(3)); + ASN1Integer y = ASN1Integer.getInstance(seq.getObjectAt(4)); + ASN1Integer x = ASN1Integer.getInstance(seq.getObjectAt(5)); + + return new PEMKeyPair( + new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(p.getValue(), q.getValue(), g.getValue())), y), + new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(p.getValue(), q.getValue(), g.getValue())), x)); + } + catch (IOException e) + { + throw e; + } + catch (Exception e) + { + throw new PEMException( + "problem creating DSA private key: " + e.toString(), e); + } + } + } + + private class ECDSAKeyPairParser + implements PEMKeyPairParser + { + public PEMKeyPair parse(byte[] encoding) + throws IOException + { + try + { + ASN1Sequence seq = ASN1Sequence.getInstance(encoding); + + org.spongycastle.asn1.sec.ECPrivateKey pKey = org.spongycastle.asn1.sec.ECPrivateKey.getInstance(seq); + AlgorithmIdentifier algId = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, pKey.getParameters()); + PrivateKeyInfo privInfo = new PrivateKeyInfo(algId, pKey); + SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(algId, pKey.getPublicKey().getBytes()); + + return new PEMKeyPair(pubInfo, privInfo); + } + catch (IOException e) + { + throw e; + } + catch (Exception e) + { + throw new PEMException( + "problem creating EC private key: " + e.toString(), e); + } + } + } + + private class RSAKeyPairParser + implements PEMKeyPairParser + { + public PEMKeyPair parse(byte[] encoding) + throws IOException + { + try + { + ASN1Sequence seq = ASN1Sequence.getInstance(encoding); + + if (seq.size() != 9) + { + throw new PEMException("malformed sequence in RSA private key"); + } + + org.spongycastle.asn1.pkcs.RSAPrivateKey keyStruct = org.spongycastle.asn1.pkcs.RSAPrivateKey.getInstance(seq); + + RSAPublicKey pubSpec = new RSAPublicKey( + keyStruct.getModulus(), keyStruct.getPublicExponent()); + + AlgorithmIdentifier algId = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE); + + return new PEMKeyPair(new SubjectPublicKeyInfo(algId, pubSpec), new PrivateKeyInfo(algId, keyStruct)); + } + catch (IOException e) + { + throw e; + } + catch (Exception e) + { + throw new PEMException( + "problem creating RSA private key: " + e.toString(), e); + } + } + } + + private class PublicKeyParser + implements PemObjectParser + { + public PublicKeyParser() + { + } + + public Object parseObject(PemObject obj) + throws IOException + { + return SubjectPublicKeyInfo.getInstance(obj.getContent()); + } + } + + private class RSAPublicKeyParser + implements PemObjectParser + { + public RSAPublicKeyParser() + { + } + + public Object parseObject(PemObject obj) + throws IOException + { + try + { + RSAPublicKey rsaPubStructure = RSAPublicKey.getInstance(obj.getContent()); + + return new SubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), rsaPubStructure); + } + catch (IOException e) + { + throw e; + } + catch (Exception e) + { + throw new PEMException("problem extracting key: " + e.toString(), e); + } + } + } + + private class X509CertificateParser + implements PemObjectParser + { + /** + * Reads in a X509Certificate. + * + * @return the X509Certificate + * @throws java.io.IOException if an I/O error occured + */ + public Object parseObject(PemObject obj) + throws IOException + { + try + { + return new X509CertificateHolder(obj.getContent()); + } + catch (Exception e) + { + throw new PEMException("problem parsing cert: " + e.toString(), e); + } + } + } + + private class X509CRLParser + implements PemObjectParser + { + /** + * Reads in a X509CRL. + * + * @return the X509Certificate + * @throws java.io.IOException if an I/O error occured + */ + public Object parseObject(PemObject obj) + throws IOException + { + try + { + return new X509CRLHolder(obj.getContent()); + } + catch (Exception e) + { + throw new PEMException("problem parsing cert: " + e.toString(), e); + } + } + } + + private class PKCS10CertificationRequestParser + implements PemObjectParser + { + /** + * Reads in a PKCS10 certification request. + * + * @return the certificate request. + * @throws java.io.IOException if an I/O error occured + */ + public Object parseObject(PemObject obj) + throws IOException + { + try + { + return new PKCS10CertificationRequest(obj.getContent()); + } + catch (Exception e) + { + throw new PEMException("problem parsing certrequest: " + e.toString(), e); + } + } + } + + private class PKCS7Parser + implements PemObjectParser + { + /** + * Reads in a PKCS7 object. This returns a ContentInfo object suitable for use with the CMS + * API. + * + * @return the X509Certificate + * @throws java.io.IOException if an I/O error occured + */ + public Object parseObject(PemObject obj) + throws IOException + { + try + { + ASN1InputStream aIn = new ASN1InputStream(obj.getContent()); + + return ContentInfo.getInstance(aIn.readObject()); + } + catch (Exception e) + { + throw new PEMException("problem parsing PKCS7 object: " + e.toString(), e); + } + } + } + + private class X509AttributeCertificateParser + implements PemObjectParser + { + public Object parseObject(PemObject obj) + throws IOException + { + return new X509AttributeCertificateHolder(obj.getContent()); + } + } + + private class ECCurveParamsParser + implements PemObjectParser + { + public Object parseObject(PemObject obj) + throws IOException + { + try + { + Object param = ASN1Primitive.fromByteArray(obj.getContent()); + + if (param instanceof ASN1ObjectIdentifier) + { + return ASN1Primitive.fromByteArray(obj.getContent()); + } + else if (param instanceof ASN1Sequence) + { + return X9ECParameters.getInstance(param); + } + else + { + return null; // implicitly CA + } + } + catch (IOException e) + { + throw e; + } + catch (Exception e) + { + throw new PEMException("exception extracting EC named curve: " + e.toString()); + } + } + } + + private class EncryptedPrivateKeyParser + implements PemObjectParser + { + public EncryptedPrivateKeyParser() + { + } + + /** + * Reads in an EncryptedPrivateKeyInfo + * + * @return the X509Certificate + * @throws java.io.IOException if an I/O error occured + */ + public Object parseObject(PemObject obj) + throws IOException + { + try + { + return new PKCS8EncryptedPrivateKeyInfo(EncryptedPrivateKeyInfo.getInstance(obj.getContent())); + } + catch (Exception e) + { + throw new PEMException("problem parsing ENCRYPTED PRIVATE KEY: " + e.toString(), e); + } + } + } + + private class PrivateKeyParser + implements PemObjectParser + { + public PrivateKeyParser() + { + } + + public Object parseObject(PemObject obj) + throws IOException + { + try + { + return PrivateKeyInfo.getInstance(obj.getContent()); + } + catch (Exception e) + { + throw new PEMException("problem parsing PRIVATE KEY: " + e.toString(), e); + } + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/PEMUtilities.java b/pkix/src/main/java/org/spongycastle/openssl/PEMUtilities.java new file mode 100644 index 00000000..e8fec527 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/PEMUtilities.java @@ -0,0 +1,64 @@ +package org.spongycastle.openssl; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.util.Integers; + +public final class PEMUtilities +{ + private static final Map KEYSIZES = new HashMap(); + private static final Set PKCS5_SCHEME_1 = new HashSet(); + private static final Set PKCS5_SCHEME_2 = new HashSet(); + + static + { + PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC); + PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC); + PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC); + PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC); + PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC); + PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC); + + PKCS5_SCHEME_2.add(PKCSObjectIdentifiers.id_PBES2); + PKCS5_SCHEME_2.add(PKCSObjectIdentifiers.des_EDE3_CBC); + PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes128_CBC); + PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes192_CBC); + PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes256_CBC); + + KEYSIZES.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), Integers.valueOf(192)); + KEYSIZES.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), Integers.valueOf(128)); + KEYSIZES.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), Integers.valueOf(192)); + KEYSIZES.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), Integers.valueOf(256)); + } + + static int getKeySize(String algorithm) + { + if (!KEYSIZES.containsKey(algorithm)) + { + throw new IllegalStateException("no key size for algorithm: " + algorithm); + } + + return ((Integer)KEYSIZES.get(algorithm)).intValue(); + } + + static boolean isPKCS5Scheme1(ASN1ObjectIdentifier algOid) + { + return PKCS5_SCHEME_1.contains(algOid); + } + + public static boolean isPKCS5Scheme2(ASN1ObjectIdentifier algOid) + { + return PKCS5_SCHEME_2.contains(algOid); + } + + public static boolean isPKCS12(ASN1ObjectIdentifier algOid) + { + return algOid.getId().startsWith(PKCSObjectIdentifiers.pkcs_12PbeIds.getId()); + } +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/PEMWriter.java b/pkix/src/main/java/org/spongycastle/openssl/PEMWriter.java new file mode 100644 index 00000000..379c014d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/PEMWriter.java @@ -0,0 +1,69 @@ +package org.spongycastle.openssl; + +import java.io.IOException; +import java.io.Writer; + +import org.spongycastle.openssl.jcajce.JcaMiscPEMGenerator; +import org.spongycastle.util.io.pem.PemGenerationException; +import org.spongycastle.util.io.pem.PemObjectGenerator; +import org.spongycastle.util.io.pem.PemWriter; + +/** + * General purpose writer for OpenSSL PEM objects. + * @deprecated use JcaPEMWriter + */ +public class PEMWriter + extends PemWriter +{ + /** + * Base constructor. + * + * @param out output stream to use. + */ + public PEMWriter(Writer out) + { + super(out); + } + + /** + * @throws IOException + */ + public void writeObject( + Object obj) + throws IOException + { + writeObject(obj, null); + } + + /** + * @param obj + * @param encryptor + * @throws IOException + */ + public void writeObject( + Object obj, + PEMEncryptor encryptor) + throws IOException + { + try + { + super.writeObject(new JcaMiscPEMGenerator(obj, encryptor)); + } + catch (PemGenerationException e) + { + if (e.getCause() instanceof IOException) + { + throw (IOException)e.getCause(); + } + + throw e; + } + } + + public void writeObject( + PemObjectGenerator obj) + throws IOException + { + super.writeObject(obj); + } +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/PKCS8Generator.java b/pkix/src/main/java/org/spongycastle/openssl/PKCS8Generator.java new file mode 100644 index 00000000..83130d36 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/PKCS8Generator.java @@ -0,0 +1,87 @@ +package org.spongycastle.openssl; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PrivateKeyInfo; +import org.spongycastle.operator.OutputEncryptor; +import org.spongycastle.util.io.pem.PemGenerationException; +import org.spongycastle.util.io.pem.PemObject; +import org.spongycastle.util.io.pem.PemObjectGenerator; + +public class PKCS8Generator + implements PemObjectGenerator +{ + public static final ASN1ObjectIdentifier AES_128_CBC = NISTObjectIdentifiers.id_aes128_CBC; + public static final ASN1ObjectIdentifier AES_192_CBC = NISTObjectIdentifiers.id_aes192_CBC; + public static final ASN1ObjectIdentifier AES_256_CBC = NISTObjectIdentifiers.id_aes256_CBC; + + public static final ASN1ObjectIdentifier DES3_CBC = PKCSObjectIdentifiers.des_EDE3_CBC; + + public static final ASN1ObjectIdentifier PBE_SHA1_RC4_128 = PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4; + public static final ASN1ObjectIdentifier PBE_SHA1_RC4_40 = PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4; + public static final ASN1ObjectIdentifier PBE_SHA1_3DES = PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC; + public static final ASN1ObjectIdentifier PBE_SHA1_2DES = PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC; + public static final ASN1ObjectIdentifier PBE_SHA1_RC2_128 = PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC; + public static final ASN1ObjectIdentifier PBE_SHA1_RC2_40 = PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC; + + private PrivateKeyInfo key; + private OutputEncryptor outputEncryptor; + + /** + * Base constructor. + */ + public PKCS8Generator(PrivateKeyInfo key, OutputEncryptor outputEncryptor) + { + this.key = key; + this.outputEncryptor = outputEncryptor; + } + + public PemObject generate() + throws PemGenerationException + { + if (outputEncryptor != null) + { + return generate(key, outputEncryptor); + } + else + { + return generate(key, null); + } + } + + private PemObject generate(PrivateKeyInfo key, OutputEncryptor encryptor) + throws PemGenerationException + { + try + { + byte[] keyData = key.getEncoded(); + + if (encryptor == null) + { + return new PemObject("PRIVATE KEY", keyData); + } + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + OutputStream cOut = encryptor.getOutputStream(bOut); + + cOut.write(key.getEncoded()); + + cOut.close(); + + EncryptedPrivateKeyInfo info = new EncryptedPrivateKeyInfo(encryptor.getAlgorithmIdentifier(), bOut.toByteArray()); + + return new PemObject("ENCRYPTED PRIVATE KEY", info.getEncoded()); + } + catch (IOException e) + { + throw new PemGenerationException("unable to process encoded key data: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/PasswordException.java b/pkix/src/main/java/org/spongycastle/openssl/PasswordException.java new file mode 100644 index 00000000..68de3213 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/PasswordException.java @@ -0,0 +1,10 @@ +package org.spongycastle.openssl; + +public class PasswordException + extends PEMException +{ + public PasswordException(String msg) + { + super(msg); + } +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/PasswordFinder.java b/pkix/src/main/java/org/spongycastle/openssl/PasswordFinder.java new file mode 100644 index 00000000..eb981fd5 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/PasswordFinder.java @@ -0,0 +1,9 @@ +package org.spongycastle.openssl; + +/** + * call back to allow a password to be fetched when one is requested. + */ +public interface PasswordFinder +{ + public char[] getPassword(); +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaMiscPEMGenerator.java b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaMiscPEMGenerator.java new file mode 100644 index 00000000..88f2a32e --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaMiscPEMGenerator.java @@ -0,0 +1,98 @@ +package org.spongycastle.openssl.jcajce; + +import java.io.IOException; +import java.security.Key; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.cert.CRLException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; + +import org.spongycastle.asn1.pkcs.PrivateKeyInfo; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.cert.jcajce.JcaX509AttributeCertificateHolder; +import org.spongycastle.cert.jcajce.JcaX509CRLHolder; +import org.spongycastle.cert.jcajce.JcaX509CertificateHolder; +import org.spongycastle.jce.PKCS10CertificationRequest; +import org.spongycastle.openssl.MiscPEMGenerator; +import org.spongycastle.openssl.PEMEncryptor; +import org.spongycastle.x509.X509AttributeCertificate; +import org.spongycastle.x509.X509V2AttributeCertificate; + +/** + * PEM generator for the original set of PEM objects used in Open SSL. + */ +public class JcaMiscPEMGenerator + extends MiscPEMGenerator +{ + private Object obj; + private String algorithm; + private char[] password; + private SecureRandom random; + private Provider provider; + + public JcaMiscPEMGenerator(Object o) + throws IOException + { + super(convertObject(o)); + } + + public JcaMiscPEMGenerator(Object o, PEMEncryptor encryptor) + throws IOException + { + super(convertObject(o), encryptor); + } + + private static Object convertObject(Object o) + throws IOException + { + if (o instanceof X509Certificate) + { + try + { + return new JcaX509CertificateHolder((X509Certificate)o); + } + catch (CertificateEncodingException e) + { + throw new IllegalArgumentException("Cannot encode object: " + e.toString()); + } + } + else if (o instanceof X509CRL) + { + try + { + return new JcaX509CRLHolder((X509CRL)o); + } + catch (CRLException e) + { + throw new IllegalArgumentException("Cannot encode object: " + e.toString()); + } + } + else if (o instanceof KeyPair) + { + return convertObject(((KeyPair)o).getPrivate()); + } + else if (o instanceof PrivateKey) + { + return PrivateKeyInfo.getInstance(((Key)o).getEncoded()); + } + else if (o instanceof PublicKey) + { + return SubjectPublicKeyInfo.getInstance(((PublicKey)o).getEncoded()); + } + else if (o instanceof X509AttributeCertificate) + { + return new JcaX509AttributeCertificateHolder((X509V2AttributeCertificate)o); + } + else if (o instanceof PKCS10CertificationRequest) + { + return new org.spongycastle.pkcs.PKCS10CertificationRequest(((PKCS10CertificationRequest)o).getEncoded()); + } + + return o; + } +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPEMKeyConverter.java b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPEMKeyConverter.java new file mode 100644 index 00000000..1b15639a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPEMKeyConverter.java @@ -0,0 +1,115 @@ +package org.spongycastle.openssl.jcajce; + +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.HashMap; +import java.util.Map; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PrivateKeyInfo; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.asn1.x9.X9ObjectIdentifiers; +import org.spongycastle.jcajce.util.DefaultJcaJceHelper; +import org.spongycastle.jcajce.util.JcaJceHelper; +import org.spongycastle.jcajce.util.NamedJcaJceHelper; +import org.spongycastle.jcajce.util.ProviderJcaJceHelper; +import org.spongycastle.openssl.PEMException; +import org.spongycastle.openssl.PEMKeyPair; + +public class JcaPEMKeyConverter +{ + private JcaJceHelper helper = new DefaultJcaJceHelper(); + + private static final Map algorithms = new HashMap(); + + static + { + algorithms.put(X9ObjectIdentifiers.id_ecPublicKey, "ECDSA"); + algorithms.put(PKCSObjectIdentifiers.rsaEncryption, "RSA"); + algorithms.put(X9ObjectIdentifiers.id_dsa, "DSA"); + } + + public JcaPEMKeyConverter setProvider(Provider provider) + { + this.helper = new ProviderJcaJceHelper(provider); + + return this; + } + + public JcaPEMKeyConverter setProvider(String providerName) + { + this.helper = new NamedJcaJceHelper(providerName); + + return this; + } + + public KeyPair getKeyPair(PEMKeyPair keyPair) + throws PEMException + { + try + { + KeyFactory keyFactory = getKeyFactory(keyPair.getPrivateKeyInfo().getPrivateKeyAlgorithm()); + + return new KeyPair(keyFactory.generatePublic(new X509EncodedKeySpec(keyPair.getPublicKeyInfo().getEncoded())), + keyFactory.generatePrivate(new PKCS8EncodedKeySpec(keyPair.getPrivateKeyInfo().getEncoded()))); + } + catch (Exception e) + { + throw new PEMException("unable to convert key pair: " + e.getMessage(), e); + } + } + + public PublicKey getPublicKey(SubjectPublicKeyInfo publicKeyInfo) + throws PEMException + { + try + { + KeyFactory keyFactory = getKeyFactory(publicKeyInfo.getAlgorithm()); + + return keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyInfo.getEncoded())); + } + catch (Exception e) + { + throw new PEMException("unable to convert key pair: " + e.getMessage(), e); + } + } + + public PrivateKey getPrivateKey(PrivateKeyInfo privateKeyInfo) + throws PEMException + { + try + { + KeyFactory keyFactory = getKeyFactory(privateKeyInfo.getPrivateKeyAlgorithm()); + + return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyInfo.getEncoded())); + } + catch (Exception e) + { + throw new PEMException("unable to convert key pair: " + e.getMessage(), e); + } + } + + private KeyFactory getKeyFactory(AlgorithmIdentifier algId) + throws NoSuchAlgorithmException, NoSuchProviderException + { + ASN1ObjectIdentifier algorithm = algId.getAlgorithm(); + + String algName = (String)algorithms.get(algorithm); + + if (algName == null) + { + algName = algorithm.getId(); + } + + return helper.createKeyFactory(algName); + } +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPEMWriter.java b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPEMWriter.java new file mode 100644 index 00000000..0224b89e --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPEMWriter.java @@ -0,0 +1,68 @@ +package org.spongycastle.openssl.jcajce; + +import java.io.IOException; +import java.io.Writer; + +import org.spongycastle.openssl.PEMEncryptor; +import org.spongycastle.util.io.pem.PemGenerationException; +import org.spongycastle.util.io.pem.PemObjectGenerator; +import org.spongycastle.util.io.pem.PemWriter; + +/** + * General purpose writer for OpenSSL PEM objects based on JCA/JCE classes. + */ +public class JcaPEMWriter + extends PemWriter +{ + /** + * Base constructor. + * + * @param out output stream to use. + */ + public JcaPEMWriter(Writer out) + { + super(out); + } + + /** + * @throws java.io.IOException + */ + public void writeObject( + Object obj) + throws IOException + { + writeObject(obj, null); + } + + /** + * @param obj + * @param encryptor + * @throws java.io.IOException + */ + public void writeObject( + Object obj, + PEMEncryptor encryptor) + throws IOException + { + try + { + super.writeObject(new JcaMiscPEMGenerator(obj, encryptor)); + } + catch (PemGenerationException e) + { + if (e.getCause() instanceof IOException) + { + throw (IOException)e.getCause(); + } + + throw e; + } + } + + public void writeObject( + PemObjectGenerator obj) + throws IOException + { + super.writeObject(obj); + } +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPKCS8Generator.java b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPKCS8Generator.java new file mode 100644 index 00000000..9c4e4f46 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPKCS8Generator.java @@ -0,0 +1,18 @@ +package org.spongycastle.openssl.jcajce; + +import java.security.PrivateKey; + +import org.spongycastle.asn1.pkcs.PrivateKeyInfo; +import org.spongycastle.openssl.PKCS8Generator; +import org.spongycastle.operator.OutputEncryptor; +import org.spongycastle.util.io.pem.PemGenerationException; + +public class JcaPKCS8Generator + extends PKCS8Generator +{ + public JcaPKCS8Generator(PrivateKey key, OutputEncryptor encryptor) + throws PemGenerationException + { + super(PrivateKeyInfo.getInstance(key.getEncoded()), encryptor); + } +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8DecryptorProviderBuilder.java b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8DecryptorProviderBuilder.java new file mode 100644 index 00000000..5050f4b2 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8DecryptorProviderBuilder.java @@ -0,0 +1,141 @@ +package org.spongycastle.openssl.jcajce; + +import java.io.IOException; +import java.io.InputStream; +import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; +import java.security.Provider; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.PBEParameterSpec; + +import org.spongycastle.asn1.pkcs.EncryptionScheme; +import org.spongycastle.asn1.pkcs.KeyDerivationFunc; +import org.spongycastle.asn1.pkcs.PBEParameter; +import org.spongycastle.asn1.pkcs.PBES2Parameters; +import org.spongycastle.asn1.pkcs.PBKDF2Params; +import org.spongycastle.asn1.pkcs.PKCS12PBEParams; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.jcajce.util.DefaultJcaJceHelper; +import org.spongycastle.jcajce.util.JcaJceHelper; +import org.spongycastle.jcajce.util.NamedJcaJceHelper; +import org.spongycastle.jcajce.util.ProviderJcaJceHelper; +import org.spongycastle.openssl.PEMException; +import org.spongycastle.operator.InputDecryptor; +import org.spongycastle.operator.InputDecryptorProvider; +import org.spongycastle.operator.OperatorCreationException; + +public class JceOpenSSLPKCS8DecryptorProviderBuilder +{ + private JcaJceHelper helper = new DefaultJcaJceHelper(); + + public JceOpenSSLPKCS8DecryptorProviderBuilder() + { + helper = new DefaultJcaJceHelper(); + } + + public JceOpenSSLPKCS8DecryptorProviderBuilder setProvider(String providerName) + { + helper = new NamedJcaJceHelper(providerName); + + return this; + } + + public JceOpenSSLPKCS8DecryptorProviderBuilder setProvider(Provider provider) + { + helper = new ProviderJcaJceHelper(provider); + + return this; + } + + public InputDecryptorProvider build(final char[] password) + throws OperatorCreationException + { + return new InputDecryptorProvider() + { + public InputDecryptor get(final AlgorithmIdentifier algorithm) + throws OperatorCreationException + { + final Cipher cipher; + + try + { + if (PEMUtilities.isPKCS5Scheme2(algorithm.getAlgorithm())) + { + PBES2Parameters params = PBES2Parameters.getInstance(algorithm.getParameters()); + KeyDerivationFunc func = params.getKeyDerivationFunc(); + EncryptionScheme scheme = params.getEncryptionScheme(); + PBKDF2Params defParams = (PBKDF2Params)func.getParameters(); + + int iterationCount = defParams.getIterationCount().intValue(); + byte[] salt = defParams.getSalt(); + + String oid = scheme.getAlgorithm().getId(); + + SecretKey key = PEMUtilities.generateSecretKeyForPKCS5Scheme2(oid, password, salt, iterationCount); + + cipher = helper.createCipher(oid); + AlgorithmParameters algParams = helper.createAlgorithmParameters(oid); + + algParams.init(scheme.getParameters().toASN1Primitive().getEncoded()); + + cipher.init(Cipher.DECRYPT_MODE, key, algParams); + } + else if (PEMUtilities.isPKCS12(algorithm.getAlgorithm())) + { + PKCS12PBEParams params = PKCS12PBEParams.getInstance(algorithm.getParameters()); + PBEKeySpec pbeSpec = new PBEKeySpec(password); + + SecretKeyFactory secKeyFact = helper.createSecretKeyFactory(algorithm.getAlgorithm().getId()); + PBEParameterSpec defParams = new PBEParameterSpec(params.getIV(), params.getIterations().intValue()); + + cipher = helper.createCipher(algorithm.getAlgorithm().getId()); + + cipher.init(Cipher.DECRYPT_MODE, secKeyFact.generateSecret(pbeSpec), defParams); + } + else if (PEMUtilities.isPKCS5Scheme1(algorithm.getAlgorithm())) + { + PBEParameter params = PBEParameter.getInstance(algorithm.getParameters()); + PBEKeySpec pbeSpec = new PBEKeySpec(password); + + SecretKeyFactory secKeyFact = helper.createSecretKeyFactory(algorithm.getAlgorithm().getId()); + PBEParameterSpec defParams = new PBEParameterSpec(params.getSalt(), params.getIterationCount().intValue()); + + cipher = helper.createCipher(algorithm.getAlgorithm().getId()); + + cipher.init(Cipher.DECRYPT_MODE, secKeyFact.generateSecret(pbeSpec), defParams); + } + else + { + throw new PEMException("Unknown algorithm: " + algorithm.getAlgorithm()); + } + + return new InputDecryptor() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return algorithm; + } + + public InputStream getInputStream(InputStream encIn) + { + return new CipherInputStream(encIn, cipher); + } + }; + } + catch (IOException e) + { + throw new OperatorCreationException(algorithm.getAlgorithm() + " not available: " + e.getMessage(), e); + } + catch (GeneralSecurityException e) + { + throw new OperatorCreationException(algorithm.getAlgorithm() + " not available: " + e.getMessage(), e); + } + }; + }; + } +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8EncryptorBuilder.java b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8EncryptorBuilder.java new file mode 100644 index 00000000..8404661f --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8EncryptorBuilder.java @@ -0,0 +1,221 @@ +package org.spongycastle.openssl.jcajce; + +import java.io.IOException; +import java.io.OutputStream; +import java.security.AlgorithmParameterGenerator; +import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; +import java.security.Provider; +import java.security.SecureRandom; + +import javax.crypto.Cipher; +import javax.crypto.CipherOutputStream; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.PBEParameterSpec; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.pkcs.KeyDerivationFunc; +import org.spongycastle.asn1.pkcs.PBES2Parameters; +import org.spongycastle.asn1.pkcs.PBKDF2Params; +import org.spongycastle.asn1.pkcs.PKCS12PBEParams; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.jcajce.util.DefaultJcaJceHelper; +import org.spongycastle.jcajce.util.JcaJceHelper; +import org.spongycastle.jcajce.util.NamedJcaJceHelper; +import org.spongycastle.jcajce.util.ProviderJcaJceHelper; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.operator.OutputEncryptor; +import org.spongycastle.operator.jcajce.JceGenericKey; + +public class JceOpenSSLPKCS8EncryptorBuilder +{ + public static final String AES_128_CBC = NISTObjectIdentifiers.id_aes128_CBC.getId(); + public static final String AES_192_CBC = NISTObjectIdentifiers.id_aes192_CBC.getId(); + public static final String AES_256_CBC = NISTObjectIdentifiers.id_aes256_CBC.getId(); + + public static final String DES3_CBC = PKCSObjectIdentifiers.des_EDE3_CBC.getId(); + + public static final String PBE_SHA1_RC4_128 = PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4.getId(); + public static final String PBE_SHA1_RC4_40 = PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4.getId(); + public static final String PBE_SHA1_3DES = PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC.getId(); + public static final String PBE_SHA1_2DES = PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC.getId(); + public static final String PBE_SHA1_RC2_128 = PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC.getId(); + public static final String PBE_SHA1_RC2_40 = PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC.getId(); + + private JcaJceHelper helper = new DefaultJcaJceHelper(); + + private AlgorithmParameters params; + private ASN1ObjectIdentifier algOID; + byte[] salt; + int iterationCount; + private Cipher cipher; + private SecureRandom random; + private AlgorithmParameterGenerator paramGen; + private SecretKeyFactory secKeyFact; + private char[] password; + + private SecretKey key; + + public JceOpenSSLPKCS8EncryptorBuilder(ASN1ObjectIdentifier algorithm) + { + algOID = algorithm; + + this.iterationCount = 2048; + } + + public JceOpenSSLPKCS8EncryptorBuilder setRandom(SecureRandom random) + { + this.random = random; + + return this; + } + + public JceOpenSSLPKCS8EncryptorBuilder setPasssword(char[] password) + { + this.password = password; + + return this; + } + + public JceOpenSSLPKCS8EncryptorBuilder setIterationCount(int iterationCount) + { + this.iterationCount = iterationCount; + + return this; + } + + public JceOpenSSLPKCS8EncryptorBuilder setProvider(String providerName) + { + helper = new NamedJcaJceHelper(providerName); + + return this; + } + + public JceOpenSSLPKCS8EncryptorBuilder setProvider(Provider provider) + { + helper = new ProviderJcaJceHelper(provider); + + return this; + } + + public OutputEncryptor build() + throws OperatorCreationException + { + final AlgorithmIdentifier algID; + + salt = new byte[20]; + + if (random == null) + { + random = new SecureRandom(); + } + + random.nextBytes(salt); + + try + { + this.cipher = helper.createCipher(algOID.getId()); + + if (PEMUtilities.isPKCS5Scheme2(algOID)) + { + this.paramGen = helper.createAlgorithmParameterGenerator(algOID.getId()); + } + else + { + this.secKeyFact = helper.createSecretKeyFactory(algOID.getId()); + } + } + catch (GeneralSecurityException e) + { + throw new OperatorCreationException(algOID + " not available: " + e.getMessage(), e); + } + + if (PEMUtilities.isPKCS5Scheme2(algOID)) + { + params = paramGen.generateParameters(); + + try + { + KeyDerivationFunc scheme = new KeyDerivationFunc(algOID, ASN1Primitive.fromByteArray(params.getEncoded())); + KeyDerivationFunc func = new KeyDerivationFunc(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(salt, iterationCount)); + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(func); + v.add(scheme); + + algID = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, PBES2Parameters.getInstance(new DERSequence(v))); + } + catch (IOException e) + { + throw new OperatorCreationException(e.getMessage(), e); + } + + key = PEMUtilities.generateSecretKeyForPKCS5Scheme2(algOID.getId(), password, salt, iterationCount); + + try + { + cipher.init(Cipher.ENCRYPT_MODE, key, params); + } + catch (GeneralSecurityException e) + { + throw new OperatorCreationException(e.getMessage(), e); + } + } + else if (PEMUtilities.isPKCS12(algOID)) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new DEROctetString(salt)); + v.add(new ASN1Integer(iterationCount)); + + algID = new AlgorithmIdentifier(algOID, PKCS12PBEParams.getInstance(new DERSequence(v))); + + try + { + PBEKeySpec pbeSpec = new PBEKeySpec(password); + PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount); + + key = secKeyFact.generateSecret(pbeSpec); + + cipher.init(Cipher.ENCRYPT_MODE, key, defParams); + } + catch (GeneralSecurityException e) + { + throw new OperatorCreationException(e.getMessage(), e); + } + } + else + { + throw new OperatorCreationException("unknown algorithm: " + algOID, null); + } + + return new OutputEncryptor() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return algID; + } + + public OutputStream getOutputStream(OutputStream encOut) + { + return new CipherOutputStream(encOut, cipher); + } + + public GenericKey getKey() + { + return new JceGenericKey(algID, key); + } + }; + } +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcePEMDecryptorProviderBuilder.java b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcePEMDecryptorProviderBuilder.java new file mode 100644 index 00000000..b54d7fd3 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcePEMDecryptorProviderBuilder.java @@ -0,0 +1,54 @@ +package org.spongycastle.openssl.jcajce; + +import java.security.Provider; + +import org.spongycastle.jcajce.util.DefaultJcaJceHelper; +import org.spongycastle.jcajce.util.JcaJceHelper; +import org.spongycastle.jcajce.util.NamedJcaJceHelper; +import org.spongycastle.jcajce.util.ProviderJcaJceHelper; +import org.spongycastle.openssl.PEMDecryptor; +import org.spongycastle.openssl.PEMDecryptorProvider; +import org.spongycastle.openssl.PEMException; +import org.spongycastle.openssl.PasswordException; + +public class JcePEMDecryptorProviderBuilder +{ + private JcaJceHelper helper = new DefaultJcaJceHelper(); + + public JcePEMDecryptorProviderBuilder setProvider(Provider provider) + { + this.helper = new ProviderJcaJceHelper(provider); + + return this; + } + + public JcePEMDecryptorProviderBuilder setProvider(String providerName) + { + this.helper = new NamedJcaJceHelper(providerName); + + return this; + } + + public PEMDecryptorProvider build(final char[] password) + { + return new PEMDecryptorProvider() + { + public PEMDecryptor get(final String dekAlgName) + { + return new PEMDecryptor() + { + public byte[] decrypt(byte[] keyBytes, byte[] iv) + throws PEMException + { + if (password == null) + { + throw new PasswordException("Password is null, but a password is required"); + } + + return PEMUtilities.crypt(false, helper, keyBytes, password, dekAlgName, iv); + } + }; + } + }; + } +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcePEMEncryptorBuilder.java b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcePEMEncryptorBuilder.java new file mode 100644 index 00000000..3360f8a8 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcePEMEncryptorBuilder.java @@ -0,0 +1,78 @@ +package org.spongycastle.openssl.jcajce; + +import java.security.Provider; +import java.security.SecureRandom; + +import org.spongycastle.jcajce.util.DefaultJcaJceHelper; +import org.spongycastle.jcajce.util.JcaJceHelper; +import org.spongycastle.jcajce.util.NamedJcaJceHelper; +import org.spongycastle.jcajce.util.ProviderJcaJceHelper; +import org.spongycastle.openssl.PEMEncryptor; +import org.spongycastle.openssl.PEMException; + +public class JcePEMEncryptorBuilder +{ + private final String algorithm; + + private JcaJceHelper helper = new DefaultJcaJceHelper(); + private SecureRandom random; + + public JcePEMEncryptorBuilder(String algorithm) + { + this.algorithm = algorithm; + } + + public JcePEMEncryptorBuilder setProvider(Provider provider) + { + this.helper = new ProviderJcaJceHelper(provider); + + return this; + } + + public JcePEMEncryptorBuilder setProvider(String providerName) + { + this.helper = new NamedJcaJceHelper(providerName); + + return this; + } + + public JcePEMEncryptorBuilder setSecureRandom(SecureRandom random) + { + this.random = random; + + return this; + } + + public PEMEncryptor build(final char[] password) + { + if (random == null) + { + random = new SecureRandom(); + } + + int ivLength = algorithm.startsWith("AES-") ? 16 : 8; + + final byte[] iv = new byte[ivLength]; + + random.nextBytes(iv); + + return new PEMEncryptor() + { + public String getAlgorithm() + { + return algorithm; + } + + public byte[] getIV() + { + return iv; + } + + public byte[] encrypt(byte[] encoding) + throws PEMException + { + return PEMUtilities.crypt(true, helper, encoding, password, algorithm, iv); + } + }; + } +} diff --git a/pkix/src/main/java/org/spongycastle/openssl/jcajce/PEMUtilities.java b/pkix/src/main/java/org/spongycastle/openssl/jcajce/PEMUtilities.java new file mode 100644 index 00000000..6bfa2a57 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/openssl/jcajce/PEMUtilities.java @@ -0,0 +1,257 @@ +package org.spongycastle.openssl.jcajce; + +import java.security.Key; +import java.security.spec.AlgorithmParameterSpec; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.RC2ParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.crypto.PBEParametersGenerator; +import org.spongycastle.crypto.generators.OpenSSLPBEParametersGenerator; +import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.jcajce.util.JcaJceHelper; +import org.spongycastle.openssl.EncryptionException; +import org.spongycastle.openssl.PEMException; +import org.spongycastle.util.Integers; + +class PEMUtilities +{ + private static final Map KEYSIZES = new HashMap(); + private static final Set PKCS5_SCHEME_1 = new HashSet(); + private static final Set PKCS5_SCHEME_2 = new HashSet(); + + static + { + PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC); + PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC); + PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC); + PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC); + PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC); + PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC); + + PKCS5_SCHEME_2.add(PKCSObjectIdentifiers.id_PBES2); + PKCS5_SCHEME_2.add(PKCSObjectIdentifiers.des_EDE3_CBC); + PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes128_CBC); + PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes192_CBC); + PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes256_CBC); + + KEYSIZES.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), Integers.valueOf(192)); + KEYSIZES.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), Integers.valueOf(128)); + KEYSIZES.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), Integers.valueOf(192)); + KEYSIZES.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), Integers.valueOf(256)); + } + + static int getKeySize(String algorithm) + { + if (!KEYSIZES.containsKey(algorithm)) + { + throw new IllegalStateException("no key size for algorithm: " + algorithm); + } + + return ((Integer)KEYSIZES.get(algorithm)).intValue(); + } + + static boolean isPKCS5Scheme1(ASN1ObjectIdentifier algOid) + { + return PKCS5_SCHEME_1.contains(algOid); + } + + static boolean isPKCS5Scheme2(ASN1ObjectIdentifier algOid) + { + return PKCS5_SCHEME_2.contains(algOid); + } + + public static boolean isPKCS12(ASN1ObjectIdentifier algOid) + { + return algOid.getId().startsWith(PKCSObjectIdentifiers.pkcs_12PbeIds.getId()); + } + + public static SecretKey generateSecretKeyForPKCS5Scheme2(String algorithm, char[] password, byte[] salt, int iterationCount) + { + PBEParametersGenerator generator = new PKCS5S2ParametersGenerator(); + + generator.init( + PBEParametersGenerator.PKCS5PasswordToBytes(password), + salt, + iterationCount); + + return new SecretKeySpec(((KeyParameter)generator.generateDerivedParameters(PEMUtilities.getKeySize(algorithm))).getKey(), algorithm); + } + + static byte[] crypt( + boolean encrypt, + JcaJceHelper helper, + byte[] bytes, + char[] password, + String dekAlgName, + byte[] iv) + throws PEMException + { + AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv); + String alg; + String blockMode = "CBC"; + String padding = "PKCS5Padding"; + Key sKey; + + // Figure out block mode and padding. + if (dekAlgName.endsWith("-CFB")) + { + blockMode = "CFB"; + padding = "NoPadding"; + } + if (dekAlgName.endsWith("-ECB") || + "DES-EDE".equals(dekAlgName) || + "DES-EDE3".equals(dekAlgName)) + { + // ECB is actually the default (though seldom used) when OpenSSL + // uses DES-EDE (des2) or DES-EDE3 (des3). + blockMode = "ECB"; + paramSpec = null; + } + if (dekAlgName.endsWith("-OFB")) + { + blockMode = "OFB"; + padding = "NoPadding"; + } + + + // Figure out algorithm and key size. + if (dekAlgName.startsWith("DES-EDE")) + { + alg = "DESede"; + // "DES-EDE" is actually des2 in OpenSSL-speak! + // "DES-EDE3" is des3. + boolean des2 = !dekAlgName.startsWith("DES-EDE3"); + sKey = getKey(password, alg, 24, iv, des2); + } + else if (dekAlgName.startsWith("DES-")) + { + alg = "DES"; + sKey = getKey(password, alg, 8, iv); + } + else if (dekAlgName.startsWith("BF-")) + { + alg = "Blowfish"; + sKey = getKey(password, alg, 16, iv); + } + else if (dekAlgName.startsWith("RC2-")) + { + alg = "RC2"; + int keyBits = 128; + if (dekAlgName.startsWith("RC2-40-")) + { + keyBits = 40; + } + else if (dekAlgName.startsWith("RC2-64-")) + { + keyBits = 64; + } + sKey = getKey(password, alg, keyBits / 8, iv); + if (paramSpec == null) // ECB block mode + { + paramSpec = new RC2ParameterSpec(keyBits); + } + else + { + paramSpec = new RC2ParameterSpec(keyBits, iv); + } + } + else if (dekAlgName.startsWith("AES-")) + { + alg = "AES"; + byte[] salt = iv; + if (salt.length > 8) + { + salt = new byte[8]; + System.arraycopy(iv, 0, salt, 0, 8); + } + + int keyBits; + if (dekAlgName.startsWith("AES-128-")) + { + keyBits = 128; + } + else if (dekAlgName.startsWith("AES-192-")) + { + keyBits = 192; + } + else if (dekAlgName.startsWith("AES-256-")) + { + keyBits = 256; + } + else + { + throw new EncryptionException("unknown AES encryption with private key"); + } + sKey = getKey(password, "AES", keyBits / 8, salt); + } + else + { + throw new EncryptionException("unknown encryption with private key"); + } + + String transformation = alg + "/" + blockMode + "/" + padding; + + try + { + Cipher c = helper.createCipher(transformation); + int mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE; + + if (paramSpec == null) // ECB block mode + { + c.init(mode, sKey); + } + else + { + c.init(mode, sKey, paramSpec); + } + return c.doFinal(bytes); + } + catch (Exception e) + { + throw new EncryptionException("exception using cipher - please check password and data.", e); + } + } + + private static SecretKey getKey( + char[] password, + String algorithm, + int keyLength, + byte[] salt) + { + return getKey(password, algorithm, keyLength, salt, false); + } + + private static SecretKey getKey( + char[] password, + String algorithm, + int keyLength, + byte[] salt, + boolean des2) + { + OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator(); + + pGen.init(PBEParametersGenerator.PKCS5PasswordToBytes(password), salt); + + KeyParameter keyParam; + keyParam = (KeyParameter) pGen.generateDerivedParameters(keyLength * 8); + byte[] key = keyParam.getKey(); + if (des2 && key.length >= 24) + { + // For DES2, we must copy first 8 bytes into the last 8 bytes. + System.arraycopy(key, 0, key, 16, 8); + } + return new SecretKeySpec(key, algorithm); + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/AsymmetricKeyUnwrapper.java b/pkix/src/main/java/org/spongycastle/operator/AsymmetricKeyUnwrapper.java new file mode 100644 index 00000000..2ed2f145 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/AsymmetricKeyUnwrapper.java @@ -0,0 +1,19 @@ +package org.spongycastle.operator; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +public abstract class AsymmetricKeyUnwrapper + implements KeyUnwrapper +{ + private AlgorithmIdentifier algorithmId; + + protected AsymmetricKeyUnwrapper(AlgorithmIdentifier algorithmId) + { + this.algorithmId = algorithmId; + } + + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return algorithmId; + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/AsymmetricKeyWrapper.java b/pkix/src/main/java/org/spongycastle/operator/AsymmetricKeyWrapper.java new file mode 100644 index 00000000..3de80226 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/AsymmetricKeyWrapper.java @@ -0,0 +1,19 @@ +package org.spongycastle.operator; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +public abstract class AsymmetricKeyWrapper + implements KeyWrapper +{ + private AlgorithmIdentifier algorithmId; + + protected AsymmetricKeyWrapper(AlgorithmIdentifier algorithmId) + { + this.algorithmId = algorithmId; + } + + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return algorithmId; + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/BufferingContentSigner.java b/pkix/src/main/java/org/spongycastle/operator/BufferingContentSigner.java new file mode 100644 index 00000000..e96a906c --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/BufferingContentSigner.java @@ -0,0 +1,70 @@ +package org.spongycastle.operator; + +import java.io.OutputStream; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.util.io.BufferingOutputStream; + +/** + * A class that explicitly buffers the data to be signed, sending it in one + * block when ready for signing. + */ +public class BufferingContentSigner + implements ContentSigner +{ + private final ContentSigner contentSigner; + private final OutputStream output; + + /** + * Base constructor. + * + * @param contentSigner the content signer to be wrapped. + */ + public BufferingContentSigner(ContentSigner contentSigner) + { + this.contentSigner = contentSigner; + this.output = new BufferingOutputStream(contentSigner.getOutputStream()); + } + + /** + * Base constructor. + * + * @param contentSigner the content signer to be wrapped. + * @param bufferSize the size of the internal buffer to use. + */ + public BufferingContentSigner(ContentSigner contentSigner, int bufferSize) + { + this.contentSigner = contentSigner; + this.output = new BufferingOutputStream(contentSigner.getOutputStream(), bufferSize); + } + + /** + * Return the algorithm identifier supported by this signer. + * + * @return algorithm identifier for the signature generated. + */ + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return contentSigner.getAlgorithmIdentifier(); + } + + /** + * Return the buffering stream. + * + * @return the output stream used to accumulate the data. + */ + public OutputStream getOutputStream() + { + return output; + } + + /** + * Generate signature from internally buffered data. + * + * @return the signature calculated from the bytes written to the buffering stream. + */ + public byte[] getSignature() + { + return contentSigner.getSignature(); + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/ContentSigner.java b/pkix/src/main/java/org/spongycastle/operator/ContentSigner.java new file mode 100644 index 00000000..fcdeefc4 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/ContentSigner.java @@ -0,0 +1,27 @@ +package org.spongycastle.operator; + +import java.io.OutputStream; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +public interface ContentSigner +{ + AlgorithmIdentifier getAlgorithmIdentifier(); + + /** + * Returns a stream that will accept data for the purpose of calculating + * a signature. Use org.spongycastle.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/pkix/src/main/java/org/spongycastle/operator/ContentVerifier.java b/pkix/src/main/java/org/spongycastle/operator/ContentVerifier.java new file mode 100644 index 00000000..a139ebb2 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/ContentVerifier.java @@ -0,0 +1,31 @@ +package org.spongycastle.operator; + +import java.io.OutputStream; + +import org.spongycastle.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.spongycastle.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/pkix/src/main/java/org/spongycastle/operator/ContentVerifierProvider.java b/pkix/src/main/java/org/spongycastle/operator/ContentVerifierProvider.java new file mode 100644 index 00000000..9d91304a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/ContentVerifierProvider.java @@ -0,0 +1,34 @@ +package org.spongycastle.operator; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java b/pkix/src/main/java/org/spongycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java new file mode 100644 index 00000000..42d6665e --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java @@ -0,0 +1,97 @@ +package org.spongycastle.operator; + +import java.util.HashMap; +import java.util.Map; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.pkcs.RSASSAPSSparams; +import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x9.X9ObjectIdentifiers; + +public class DefaultDigestAlgorithmIdentifierFinder + implements DigestAlgorithmIdentifierFinder +{ + private static Map digestOids = new HashMap(); + private static Map digestNameToOids = new HashMap(); + + static + { + // + // digests + // + digestOids.put(OIWObjectIdentifiers.md4WithRSAEncryption, PKCSObjectIdentifiers.md4); + digestOids.put(OIWObjectIdentifiers.md4WithRSA, PKCSObjectIdentifiers.md4); + 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); + digestOids.put(PKCSObjectIdentifiers.md2WithRSAEncryption, PKCSObjectIdentifiers.md2); + digestOids.put(PKCSObjectIdentifiers.md4WithRSAEncryption, PKCSObjectIdentifiers.md4); + 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); + + 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); + + 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); + + 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); + + digestNameToOids.put("GOST3411", CryptoProObjectIdentifiers.gostR3411); + + digestNameToOids.put("MD2", PKCSObjectIdentifiers.md2); + digestNameToOids.put("MD4", PKCSObjectIdentifiers.md4); + digestNameToOids.put("MD5", PKCSObjectIdentifiers.md5); + + digestNameToOids.put("RIPEMD128", TeleTrusTObjectIdentifiers.ripemd128); + digestNameToOids.put("RIPEMD160", TeleTrusTObjectIdentifiers.ripemd160); + digestNameToOids.put("RIPEMD256", TeleTrusTObjectIdentifiers.ripemd256); + } + + 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/pkix/src/main/java/org/spongycastle/operator/DefaultSecretKeySizeProvider.java b/pkix/src/main/java/org/spongycastle/operator/DefaultSecretKeySizeProvider.java new file mode 100644 index 00000000..d830e5cc --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/DefaultSecretKeySizeProvider.java @@ -0,0 +1,69 @@ +package org.spongycastle.operator; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.ntt.NTTObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.util.Integers; + +public class DefaultSecretKeySizeProvider + implements SecretKeySizeProvider +{ + public static final SecretKeySizeProvider INSTANCE = new DefaultSecretKeySizeProvider(); + + private static final Map KEY_SIZES; + + static + { + Map keySizes = new HashMap(); + + keySizes.put(new ASN1ObjectIdentifier("1.2.840.113533.7.66.10"), Integers.valueOf(128)); + + keySizes.put(PKCSObjectIdentifiers.des_EDE3_CBC, Integers.valueOf(192)); + + keySizes.put(NISTObjectIdentifiers.id_aes128_CBC, Integers.valueOf(128)); + keySizes.put(NISTObjectIdentifiers.id_aes192_CBC, Integers.valueOf(192)); + keySizes.put(NISTObjectIdentifiers.id_aes256_CBC, Integers.valueOf(256)); + + keySizes.put(NTTObjectIdentifiers.id_camellia128_cbc, Integers.valueOf(128)); + keySizes.put(NTTObjectIdentifiers.id_camellia192_cbc, Integers.valueOf(192)); + keySizes.put(NTTObjectIdentifiers.id_camellia256_cbc, Integers.valueOf(256)); + + keySizes.put(CryptoProObjectIdentifiers.gostR28147_gcfb, Integers.valueOf(256)); + + KEY_SIZES = Collections.unmodifiableMap(keySizes); + } + + public int getKeySize(AlgorithmIdentifier algorithmIdentifier) + { + int keySize = getKeySize(algorithmIdentifier.getAlgorithm()); + + // just need the OID + if (keySize > 0) + { + return keySize; + } + + // TODO: support OID/Parameter key sizes (e.g. RC2). + + return -1; + } + + public int getKeySize(ASN1ObjectIdentifier algorithm) + { + Integer keySize = (Integer)KEY_SIZES.get(algorithm); + + if (keySize != null) + { + return keySize.intValue(); + } + + return -1; + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java b/pkix/src/main/java/org/spongycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java new file mode 100644 index 00000000..58608c8b --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java @@ -0,0 +1,224 @@ +package org.spongycastle.operator; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.bsi.BSIObjectIdentifiers; +import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import org.spongycastle.asn1.eac.EACObjectIdentifiers; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.pkcs.RSASSAPSSparams; +import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x9.X9ObjectIdentifiers; +import org.spongycastle.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; + private static final ASN1ObjectIdentifier ENCRYPTION_GOST3410 = CryptoProObjectIdentifiers.gostR3410_94; + private static final ASN1ObjectIdentifier ENCRYPTION_ECGOST3410 = CryptoProObjectIdentifiers.gostR3410_2001; + + static + { + algorithms.put("MD2WITHRSAENCRYPTION", PKCSObjectIdentifiers.md2WithRSAEncryption); + algorithms.put("MD2WITHRSA", PKCSObjectIdentifiers.md2WithRSAEncryption); + 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); + 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); + 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); + 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("SHA224WITHPCVC-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); + // + // 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); + + // + // RFC 4491 + // + noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94); + noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001); + + // + // 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); + pkcs15RsaEncryption.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128); + pkcs15RsaEncryption.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160); + pkcs15RsaEncryption.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256); + + // + // 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); + digestOids.put(PKCSObjectIdentifiers.md2WithRSAEncryption, PKCSObjectIdentifiers.md2); + digestOids.put(PKCSObjectIdentifiers.md4WithRSAEncryption, PKCSObjectIdentifiers.md4); + digestOids.put(PKCSObjectIdentifiers.md5WithRSAEncryption, PKCSObjectIdentifiers.md5); + digestOids.put(PKCSObjectIdentifiers.sha1WithRSAEncryption, OIWObjectIdentifiers.idSHA1); + 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); + } + + 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/pkix/src/main/java/org/spongycastle/operator/DigestAlgorithmIdentifierFinder.java b/pkix/src/main/java/org/spongycastle/operator/DigestAlgorithmIdentifierFinder.java new file mode 100644 index 00000000..1254c38e --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/DigestAlgorithmIdentifierFinder.java @@ -0,0 +1,24 @@ +package org.spongycastle.operator; + +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/operator/DigestCalculator.java b/pkix/src/main/java/org/spongycastle/operator/DigestCalculator.java new file mode 100644 index 00000000..0bb4712f --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/DigestCalculator.java @@ -0,0 +1,36 @@ +package org.spongycastle.operator; + +import java.io.OutputStream; + +import org.spongycastle.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.spongycastle.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/pkix/src/main/java/org/spongycastle/operator/DigestCalculatorProvider.java b/pkix/src/main/java/org/spongycastle/operator/DigestCalculatorProvider.java new file mode 100644 index 00000000..55a7c143 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/DigestCalculatorProvider.java @@ -0,0 +1,9 @@ +package org.spongycastle.operator; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +public interface DigestCalculatorProvider +{ + DigestCalculator get(AlgorithmIdentifier digestAlgorithmIdentifier) + throws OperatorCreationException; +} diff --git a/pkix/src/main/java/org/spongycastle/operator/GenericKey.java b/pkix/src/main/java/org/spongycastle/operator/GenericKey.java new file mode 100644 index 00000000..5446ce7b --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/GenericKey.java @@ -0,0 +1,41 @@ +package org.spongycastle.operator; + +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/operator/InputDecryptor.java b/pkix/src/main/java/org/spongycastle/operator/InputDecryptor.java new file mode 100644 index 00000000..c55b3db0 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/InputDecryptor.java @@ -0,0 +1,29 @@ +package org.spongycastle.operator; + +import java.io.InputStream; + +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/operator/InputDecryptorProvider.java b/pkix/src/main/java/org/spongycastle/operator/InputDecryptorProvider.java new file mode 100644 index 00000000..4ef7e9c0 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/InputDecryptorProvider.java @@ -0,0 +1,9 @@ +package org.spongycastle.operator; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +public interface InputDecryptorProvider +{ + public InputDecryptor get(AlgorithmIdentifier algorithm) + throws OperatorCreationException; +} diff --git a/pkix/src/main/java/org/spongycastle/operator/InputExpander.java b/pkix/src/main/java/org/spongycastle/operator/InputExpander.java new file mode 100644 index 00000000..870e4807 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/InputExpander.java @@ -0,0 +1,29 @@ +package org.spongycastle.operator; + +import java.io.InputStream; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +/** + * General interface for an operator that is able to produce + * an InputStream that will produce uncompressed data. + */ +public interface InputExpander +{ + /** + * Return the algorithm identifier describing the compression + * algorithm and parameters this expander supports. + * + * @return algorithm oid and parameters. + */ + AlgorithmIdentifier getAlgorithmIdentifier(); + + /** + * Wrap the passed in input stream comIn, returning an input stream + * that expands anything read in from comIn. + * + * @param comIn the compressed input data stream.. + * @return an expanding InputStream. + */ + InputStream getInputStream(InputStream comIn); +} diff --git a/pkix/src/main/java/org/spongycastle/operator/InputExpanderProvider.java b/pkix/src/main/java/org/spongycastle/operator/InputExpanderProvider.java new file mode 100644 index 00000000..d38b813a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/InputExpanderProvider.java @@ -0,0 +1,8 @@ +package org.spongycastle.operator; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +public interface InputExpanderProvider +{ + InputExpander get(AlgorithmIdentifier algorithm); +} diff --git a/pkix/src/main/java/org/spongycastle/operator/KeyUnwrapper.java b/pkix/src/main/java/org/spongycastle/operator/KeyUnwrapper.java new file mode 100644 index 00000000..8e216230 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/KeyUnwrapper.java @@ -0,0 +1,11 @@ +package org.spongycastle.operator; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +public interface KeyUnwrapper +{ + AlgorithmIdentifier getAlgorithmIdentifier(); + + GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptionKeyAlgorithm, byte[] encryptedKey) + throws OperatorException; +} diff --git a/pkix/src/main/java/org/spongycastle/operator/KeyWrapper.java b/pkix/src/main/java/org/spongycastle/operator/KeyWrapper.java new file mode 100644 index 00000000..4b7986df --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/KeyWrapper.java @@ -0,0 +1,11 @@ +package org.spongycastle.operator; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +public interface KeyWrapper +{ + AlgorithmIdentifier getAlgorithmIdentifier(); + + byte[] generateWrappedKey(GenericKey encryptionKey) + throws OperatorException; +} diff --git a/pkix/src/main/java/org/spongycastle/operator/MacCalculator.java b/pkix/src/main/java/org/spongycastle/operator/MacCalculator.java new file mode 100644 index 00000000..df59ed65 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/MacCalculator.java @@ -0,0 +1,34 @@ +package org.spongycastle.operator; + +import java.io.OutputStream; + +import org.spongycastle.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.spongycastle.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/pkix/src/main/java/org/spongycastle/operator/MacCalculatorProvider.java b/pkix/src/main/java/org/spongycastle/operator/MacCalculatorProvider.java new file mode 100644 index 00000000..a30773f2 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/MacCalculatorProvider.java @@ -0,0 +1,8 @@ +package org.spongycastle.operator; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +public interface MacCalculatorProvider +{ + public MacCalculator get(AlgorithmIdentifier algorithm); +} diff --git a/pkix/src/main/java/org/spongycastle/operator/OperatorCreationException.java b/pkix/src/main/java/org/spongycastle/operator/OperatorCreationException.java new file mode 100644 index 00000000..4e7cadac --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/OperatorCreationException.java @@ -0,0 +1,15 @@ +package org.spongycastle.operator; + +public class OperatorCreationException + extends OperatorException +{ + public OperatorCreationException(String msg, Throwable cause) + { + super(msg, cause); + } + + public OperatorCreationException(String msg) + { + super(msg); + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/OperatorException.java b/pkix/src/main/java/org/spongycastle/operator/OperatorException.java new file mode 100644 index 00000000..32ce9e41 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/OperatorException.java @@ -0,0 +1,24 @@ +package org.spongycastle.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/pkix/src/main/java/org/spongycastle/operator/OperatorStreamException.java b/pkix/src/main/java/org/spongycastle/operator/OperatorStreamException.java new file mode 100644 index 00000000..960d292f --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/OperatorStreamException.java @@ -0,0 +1,21 @@ +package org.spongycastle.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/pkix/src/main/java/org/spongycastle/operator/OutputCompressor.java b/pkix/src/main/java/org/spongycastle/operator/OutputCompressor.java new file mode 100644 index 00000000..0e10df9a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/OutputCompressor.java @@ -0,0 +1,29 @@ +package org.spongycastle.operator; + +import java.io.OutputStream; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +/** + * General interface for an operator that is able to produce + * an OutputStream that will output compressed data. + */ +public interface OutputCompressor +{ + /** + * Return the algorithm identifier describing the compression + * algorithm and parameters this compressor uses. + * + * @return algorithm oid and parameters. + */ + AlgorithmIdentifier getAlgorithmIdentifier(); + + /** + * Wrap the passed in output stream comOut, returning an output stream + * that compresses anything passed in before sending on to comOut. + * + * @param comOut output stream for compressed output. + * @return a compressing OutputStream + */ + OutputStream getOutputStream(OutputStream comOut); +} diff --git a/pkix/src/main/java/org/spongycastle/operator/OutputEncryptor.java b/pkix/src/main/java/org/spongycastle/operator/OutputEncryptor.java new file mode 100644 index 00000000..595e3b75 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/OutputEncryptor.java @@ -0,0 +1,36 @@ +package org.spongycastle.operator; + +import java.io.OutputStream; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +/** + * General interface for an operator that is able to produce + * an OutputStream that will output encrypted data. + */ +public interface OutputEncryptor +{ + /** + * Return the algorithm identifier describing the encryption + * algorithm and parameters this encryptor uses. + * + * @return algorithm oid and parameters. + */ + AlgorithmIdentifier getAlgorithmIdentifier(); + + /** + * Wrap the passed in output stream encOut, returning an output stream + * that encrypts anything passed in before sending on to encOut. + * + * @param encOut output stream for encrypted output. + * @return an encrypting OutputStream + */ + OutputStream getOutputStream(OutputStream encOut); + + /** + * Return the key used for encrypting the output. + * + * @return the encryption key. + */ + GenericKey getKey(); +} diff --git a/pkix/src/main/java/org/spongycastle/operator/RawContentVerifier.java b/pkix/src/main/java/org/spongycastle/operator/RawContentVerifier.java new file mode 100644 index 00000000..56bfb47f --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/RawContentVerifier.java @@ -0,0 +1,17 @@ +package org.spongycastle.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/pkix/src/main/java/org/spongycastle/operator/RuntimeOperatorException.java b/pkix/src/main/java/org/spongycastle/operator/RuntimeOperatorException.java new file mode 100644 index 00000000..56cab04a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/RuntimeOperatorException.java @@ -0,0 +1,24 @@ +package org.spongycastle.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/pkix/src/main/java/org/spongycastle/operator/SecretKeySizeProvider.java b/pkix/src/main/java/org/spongycastle/operator/SecretKeySizeProvider.java new file mode 100644 index 00000000..cb2d6561 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/SecretKeySizeProvider.java @@ -0,0 +1,17 @@ +package org.spongycastle.operator; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +public interface SecretKeySizeProvider +{ + int getKeySize(AlgorithmIdentifier algorithmIdentifier); + + /** + * Return the key size implied by the OID, if one exists. + * + * @param algorithm the OID of the algorithm of interest. + * @return -1 if there is no fixed key size associated with the OID, or more information is required. + */ + int getKeySize(ASN1ObjectIdentifier algorithm); +} diff --git a/pkix/src/main/java/org/spongycastle/operator/SignatureAlgorithmIdentifierFinder.java b/pkix/src/main/java/org/spongycastle/operator/SignatureAlgorithmIdentifierFinder.java new file mode 100644 index 00000000..5c997bda --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/SignatureAlgorithmIdentifierFinder.java @@ -0,0 +1,15 @@ +package org.spongycastle.operator; + +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/operator/SymmetricKeyUnwrapper.java b/pkix/src/main/java/org/spongycastle/operator/SymmetricKeyUnwrapper.java new file mode 100644 index 00000000..705a7671 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/SymmetricKeyUnwrapper.java @@ -0,0 +1,19 @@ +package org.spongycastle.operator; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +public abstract class SymmetricKeyUnwrapper + implements KeyUnwrapper +{ + private AlgorithmIdentifier algorithmId; + + protected SymmetricKeyUnwrapper(AlgorithmIdentifier algorithmId) + { + this.algorithmId = algorithmId; + } + + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return algorithmId; + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/SymmetricKeyWrapper.java b/pkix/src/main/java/org/spongycastle/operator/SymmetricKeyWrapper.java new file mode 100644 index 00000000..56ac7ef1 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/SymmetricKeyWrapper.java @@ -0,0 +1,19 @@ +package org.spongycastle.operator; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +public abstract class SymmetricKeyWrapper + implements KeyWrapper +{ + private AlgorithmIdentifier algorithmId; + + protected SymmetricKeyWrapper(AlgorithmIdentifier algorithmId) + { + this.algorithmId = algorithmId; + } + + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return algorithmId; + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/AESUtil.java b/pkix/src/main/java/org/spongycastle/operator/bc/AESUtil.java new file mode 100644 index 00000000..7abd31be --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/bc/AESUtil.java @@ -0,0 +1,34 @@ +package org.spongycastle.operator.bc; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.crypto.params.KeyParameter; + +class AESUtil +{ + static AlgorithmIdentifier determineKeyEncAlg(KeyParameter key) + { + int length = key.getKey().length * 8; + ASN1ObjectIdentifier wrapOid; + + if (length == 128) + { + wrapOid = NISTObjectIdentifiers.id_aes128_wrap; + } + else if (length == 192) + { + wrapOid = NISTObjectIdentifiers.id_aes192_wrap; + } + else if (length == 256) + { + wrapOid = NISTObjectIdentifiers.id_aes256_wrap; + } + else + { + throw new IllegalArgumentException("illegal keysize in AES"); + } + + return new AlgorithmIdentifier(wrapOid); // parameters absent + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcAESSymmetricKeyUnwrapper.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcAESSymmetricKeyUnwrapper.java new file mode 100644 index 00000000..f9b8c09b --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcAESSymmetricKeyUnwrapper.java @@ -0,0 +1,13 @@ +package org.spongycastle.operator.bc; + +import org.spongycastle.crypto.engines.AESWrapEngine; +import org.spongycastle.crypto.params.KeyParameter; + +public class BcAESSymmetricKeyUnwrapper + extends BcSymmetricKeyUnwrapper +{ + public BcAESSymmetricKeyUnwrapper(KeyParameter wrappingKey) + { + super(AESUtil.determineKeyEncAlg(wrappingKey), new AESWrapEngine(), wrappingKey); + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcAESSymmetricKeyWrapper.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcAESSymmetricKeyWrapper.java new file mode 100644 index 00000000..62dc062f --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcAESSymmetricKeyWrapper.java @@ -0,0 +1,13 @@ +package org.spongycastle.operator.bc; + +import org.spongycastle.crypto.engines.AESWrapEngine; +import org.spongycastle.crypto.params.KeyParameter; + +public class BcAESSymmetricKeyWrapper + extends BcSymmetricKeyWrapper +{ + public BcAESSymmetricKeyWrapper(KeyParameter wrappingKey) + { + super(AESUtil.determineKeyEncAlg(wrappingKey), new AESWrapEngine(), wrappingKey); + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcAsymmetricKeyUnwrapper.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcAsymmetricKeyUnwrapper.java new file mode 100644 index 00000000..8fed9deb --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcAsymmetricKeyUnwrapper.java @@ -0,0 +1,51 @@ +package org.spongycastle.operator.bc; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.crypto.AsymmetricBlockCipher; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.params.AsymmetricKeyParameter; +import org.spongycastle.operator.AsymmetricKeyUnwrapper; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.OperatorException; + +public abstract class BcAsymmetricKeyUnwrapper + extends AsymmetricKeyUnwrapper +{ + private AsymmetricKeyParameter privateKey; + + public BcAsymmetricKeyUnwrapper(AlgorithmIdentifier encAlgId, AsymmetricKeyParameter privateKey) + { + super(encAlgId); + + this.privateKey = privateKey; + } + + public GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedKey) + throws OperatorException + { + AsymmetricBlockCipher keyCipher = createAsymmetricUnwrapper(this.getAlgorithmIdentifier().getAlgorithm()); + + keyCipher.init(false, privateKey); + try + { + byte[] key = keyCipher.processBlock(encryptedKey, 0, encryptedKey.length); + + if (encryptedKeyAlgorithm.getAlgorithm().equals(PKCSObjectIdentifiers.des_EDE3_CBC)) + { + return new GenericKey(encryptedKeyAlgorithm, key); + } + else + { + return new GenericKey(encryptedKeyAlgorithm, key); + } + } + catch (InvalidCipherTextException e) + { + throw new OperatorException("unable to recover secret key: " + e.getMessage(), e); + } + } + + protected abstract AsymmetricBlockCipher createAsymmetricUnwrapper(ASN1ObjectIdentifier algorithm); +} diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcAsymmetricKeyWrapper.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcAsymmetricKeyWrapper.java new file mode 100644 index 00000000..8b5bb3e8 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcAsymmetricKeyWrapper.java @@ -0,0 +1,60 @@ +package org.spongycastle.operator.bc; + +import java.security.SecureRandom; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.crypto.AsymmetricBlockCipher; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.params.AsymmetricKeyParameter; +import org.spongycastle.crypto.params.ParametersWithRandom; +import org.spongycastle.operator.AsymmetricKeyWrapper; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.OperatorException; + +public abstract class BcAsymmetricKeyWrapper + extends AsymmetricKeyWrapper +{ + private AsymmetricKeyParameter publicKey; + private SecureRandom random; + + public BcAsymmetricKeyWrapper(AlgorithmIdentifier encAlgId, AsymmetricKeyParameter publicKey) + { + super(encAlgId); + + this.publicKey = publicKey; + } + + public BcAsymmetricKeyWrapper setSecureRandom(SecureRandom random) + { + this.random = random; + + return this; + } + + public byte[] generateWrappedKey(GenericKey encryptionKey) + throws OperatorException + { + AsymmetricBlockCipher keyEncryptionCipher = createAsymmetricWrapper(getAlgorithmIdentifier().getAlgorithm()); + + CipherParameters params = publicKey; + if (random != null) + { + params = new ParametersWithRandom(params, random); + } + + try + { + byte[] keyEnc = OperatorUtils.getKeyBytes(encryptionKey); + keyEncryptionCipher.init(true, publicKey); + return keyEncryptionCipher.processBlock(keyEnc, 0, keyEnc.length); + } + catch (InvalidCipherTextException e) + { + throw new OperatorException("unable to encrypt contents key", e); + } + } + + protected abstract AsymmetricBlockCipher createAsymmetricWrapper(ASN1ObjectIdentifier algorithm); +} diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcContentSignerBuilder.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcContentSignerBuilder.java new file mode 100644 index 00000000..7160adff --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcContentSignerBuilder.java @@ -0,0 +1,82 @@ +package org.spongycastle.operator.bc; + +import java.io.OutputStream; +import java.security.SecureRandom; +import java.util.Map; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.crypto.CryptoException; +import org.spongycastle.crypto.Signer; +import org.spongycastle.crypto.params.AsymmetricKeyParameter; +import org.spongycastle.crypto.params.ParametersWithRandom; +import org.spongycastle.operator.ContentSigner; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.operator.RuntimeOperatorException; + +public abstract class BcContentSignerBuilder +{ + private SecureRandom random; + private AlgorithmIdentifier sigAlgId; + private AlgorithmIdentifier digAlgId; + + protected BcDigestProvider digestProvider; + + public BcContentSignerBuilder(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier digAlgId) + { + this.sigAlgId = sigAlgId; + this.digAlgId = digAlgId; + this.digestProvider = BcDefaultDigestProvider.INSTANCE; + } + + public BcContentSignerBuilder setSecureRandom(SecureRandom random) + { + this.random = random; + + return this; + } + + public ContentSigner build(AsymmetricKeyParameter privateKey) + throws OperatorCreationException + { + final Signer sig = createSigner(sigAlgId, digAlgId); + + if (random != null) + { + sig.init(true, new ParametersWithRandom(privateKey, random)); + } + else + { + sig.init(true, privateKey); + } + + return new ContentSigner() + { + private BcSignerOutputStream stream = new BcSignerOutputStream(sig); + + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return sigAlgId; + } + + public OutputStream getOutputStream() + { + return stream; + } + + public byte[] getSignature() + { + try + { + return stream.getSignature(); + } + catch (CryptoException e) + { + throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e); + } + } + }; + } + + protected abstract Signer createSigner(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier algorithmIdentifier) + throws OperatorCreationException; +} diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcContentVerifierProviderBuilder.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcContentVerifierProviderBuilder.java new file mode 100644 index 00000000..3b975e4f --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcContentVerifierProviderBuilder.java @@ -0,0 +1,144 @@ +package org.spongycastle.operator.bc; + +import java.io.IOException; +import java.io.OutputStream; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.crypto.Signer; +import org.spongycastle.crypto.params.AsymmetricKeyParameter; +import org.spongycastle.operator.ContentVerifier; +import org.spongycastle.operator.ContentVerifierProvider; +import org.spongycastle.operator.OperatorCreationException; + +public abstract class BcContentVerifierProviderBuilder +{ + protected BcDigestProvider digestProvider; + + public BcContentVerifierProviderBuilder() + { + this.digestProvider = BcDefaultDigestProvider.INSTANCE; + } + + public ContentVerifierProvider build(final X509CertificateHolder certHolder) + throws OperatorCreationException + { + return new ContentVerifierProvider() + { + public boolean hasAssociatedCertificate() + { + return true; + } + + public X509CertificateHolder getAssociatedCertificate() + { + return certHolder; + } + + public ContentVerifier get(AlgorithmIdentifier algorithm) + throws OperatorCreationException + { + try + { + AsymmetricKeyParameter publicKey = extractKeyParameters(certHolder.getSubjectPublicKeyInfo()); + BcSignerOutputStream stream = createSignatureStream(algorithm, publicKey); + + return new SigVerifier(algorithm, stream); + } + catch (IOException e) + { + throw new OperatorCreationException("exception on setup: " + e, e); + } + } + }; + } + + public ContentVerifierProvider build(final AsymmetricKeyParameter publicKey) + throws OperatorCreationException + { + return new ContentVerifierProvider() + { + public boolean hasAssociatedCertificate() + { + return false; + } + + public X509CertificateHolder getAssociatedCertificate() + { + return null; + } + + public ContentVerifier get(AlgorithmIdentifier algorithm) + throws OperatorCreationException + { + BcSignerOutputStream stream = createSignatureStream(algorithm, publicKey); + + return new SigVerifier(algorithm, stream); + } + }; + } + + private BcSignerOutputStream createSignatureStream(AlgorithmIdentifier algorithm, AsymmetricKeyParameter publicKey) + throws OperatorCreationException + { + Signer sig = createSigner(algorithm); + + sig.init(false, publicKey); + + return new BcSignerOutputStream(sig); + } + + /** + * Extract an AsymmetricKeyParameter from the passed in SubjectPublicKeyInfo structure. + * + * @param publicKeyInfo a publicKeyInfo structure describing the public key required. + * @return an AsymmetricKeyParameter object containing the appropriate public key. + * @throws IOException if the publicKeyInfo data cannot be parsed, + */ + protected abstract AsymmetricKeyParameter extractKeyParameters(SubjectPublicKeyInfo publicKeyInfo) + throws IOException; + + /** + * Create the correct signer for the algorithm identifier sigAlgId. + * + * @param sigAlgId the algorithm details for the signature we want to verify. + * @return a Signer object. + * @throws OperatorCreationException if the Signer cannot be constructed. + */ + protected abstract Signer createSigner(AlgorithmIdentifier sigAlgId) + throws OperatorCreationException; + + private class SigVerifier + implements ContentVerifier + { + private BcSignerOutputStream stream; + private AlgorithmIdentifier algorithm; + + SigVerifier(AlgorithmIdentifier algorithm, BcSignerOutputStream 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) + { + return stream.verify(expected); + } + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcDSAContentSignerBuilder.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcDSAContentSignerBuilder.java new file mode 100644 index 00000000..db7b608d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcDSAContentSignerBuilder.java @@ -0,0 +1,25 @@ +package org.spongycastle.operator.bc; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.Signer; +import org.spongycastle.crypto.signers.DSADigestSigner; +import org.spongycastle.crypto.signers.DSASigner; +import org.spongycastle.operator.OperatorCreationException; + +public class BcDSAContentSignerBuilder + extends BcContentSignerBuilder +{ + public BcDSAContentSignerBuilder(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier digAlgId) + { + super(sigAlgId, digAlgId); + } + + protected Signer createSigner(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier digAlgId) + throws OperatorCreationException + { + Digest dig = digestProvider.get(digAlgId); + + return new DSADigestSigner(new DSASigner(), dig); + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcDSAContentVerifierProviderBuilder.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcDSAContentVerifierProviderBuilder.java new file mode 100644 index 00000000..aaf25f4d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcDSAContentVerifierProviderBuilder.java @@ -0,0 +1,40 @@ +package org.spongycastle.operator.bc; + +import java.io.IOException; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.Signer; +import org.spongycastle.crypto.params.AsymmetricKeyParameter; +import org.spongycastle.crypto.signers.DSADigestSigner; +import org.spongycastle.crypto.signers.DSASigner; +import org.spongycastle.crypto.util.PublicKeyFactory; +import org.spongycastle.operator.DigestAlgorithmIdentifierFinder; +import org.spongycastle.operator.OperatorCreationException; + +public class BcDSAContentVerifierProviderBuilder + extends BcContentVerifierProviderBuilder +{ + private DigestAlgorithmIdentifierFinder digestAlgorithmFinder; + + public BcDSAContentVerifierProviderBuilder(DigestAlgorithmIdentifierFinder digestAlgorithmFinder) + { + this.digestAlgorithmFinder = digestAlgorithmFinder; + } + + protected Signer createSigner(AlgorithmIdentifier sigAlgId) + throws OperatorCreationException + { + AlgorithmIdentifier digAlg = digestAlgorithmFinder.find(sigAlgId); + Digest dig = digestProvider.get(digAlg); + + return new DSADigestSigner(new DSASigner(), dig); + } + + protected AsymmetricKeyParameter extractKeyParameters(SubjectPublicKeyInfo publicKeyInfo) + throws IOException + { + return PublicKeyFactory.createKey(publicKeyInfo); + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcDefaultDigestProvider.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcDefaultDigestProvider.java new file mode 100644 index 00000000..dce50a9e --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcDefaultDigestProvider.java @@ -0,0 +1,144 @@ +package org.spongycastle.operator.bc; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.crypto.ExtendedDigest; +import org.spongycastle.crypto.digests.GOST3411Digest; +import org.spongycastle.crypto.digests.MD2Digest; +import org.spongycastle.crypto.digests.MD4Digest; +import org.spongycastle.crypto.digests.MD5Digest; +import org.spongycastle.crypto.digests.RIPEMD128Digest; +import org.spongycastle.crypto.digests.RIPEMD160Digest; +import org.spongycastle.crypto.digests.RIPEMD256Digest; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.digests.SHA224Digest; +import org.spongycastle.crypto.digests.SHA256Digest; +import org.spongycastle.crypto.digests.SHA384Digest; +import org.spongycastle.crypto.digests.SHA512Digest; +import org.spongycastle.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(); + } + }); + 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(); + } + }); + + 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/pkix/src/main/java/org/spongycastle/operator/bc/BcDigestCalculatorProvider.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcDigestCalculatorProvider.java new file mode 100644 index 00000000..8e0a12f6 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcDigestCalculatorProvider.java @@ -0,0 +1,82 @@ +package org.spongycastle.operator.bc; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Map; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.ExtendedDigest; +import org.spongycastle.operator.DigestCalculator; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/operator/bc/BcDigestProvider.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcDigestProvider.java new file mode 100644 index 00000000..6eb930ee --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcDigestProvider.java @@ -0,0 +1,11 @@ +package org.spongycastle.operator.bc; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.crypto.ExtendedDigest; +import org.spongycastle.operator.OperatorCreationException; + +public interface BcDigestProvider +{ + ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) + throws OperatorCreationException; +} diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAAsymmetricKeyUnwrapper.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAAsymmetricKeyUnwrapper.java new file mode 100644 index 00000000..99762353 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAAsymmetricKeyUnwrapper.java @@ -0,0 +1,22 @@ +package org.spongycastle.operator.bc; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.crypto.AsymmetricBlockCipher; +import org.spongycastle.crypto.encodings.PKCS1Encoding; +import org.spongycastle.crypto.engines.RSAEngine; +import org.spongycastle.crypto.params.AsymmetricKeyParameter; + +public class BcRSAAsymmetricKeyUnwrapper + extends BcAsymmetricKeyUnwrapper +{ + public BcRSAAsymmetricKeyUnwrapper(AlgorithmIdentifier encAlgId, AsymmetricKeyParameter privateKey) + { + super(encAlgId, privateKey); + } + + protected AsymmetricBlockCipher createAsymmetricUnwrapper(ASN1ObjectIdentifier algorithm) + { + return new PKCS1Encoding(new RSAEngine()); + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAAsymmetricKeyWrapper.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAAsymmetricKeyWrapper.java new file mode 100644 index 00000000..c2153e6d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAAsymmetricKeyWrapper.java @@ -0,0 +1,32 @@ +package org.spongycastle.operator.bc; + +import java.io.IOException; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.crypto.AsymmetricBlockCipher; +import org.spongycastle.crypto.encodings.PKCS1Encoding; +import org.spongycastle.crypto.engines.RSAEngine; +import org.spongycastle.crypto.params.AsymmetricKeyParameter; +import org.spongycastle.crypto.util.PublicKeyFactory; + +public class BcRSAAsymmetricKeyWrapper + extends BcAsymmetricKeyWrapper +{ + public BcRSAAsymmetricKeyWrapper(AlgorithmIdentifier encAlgId, AsymmetricKeyParameter publicKey) + { + super(encAlgId, publicKey); + } + + public BcRSAAsymmetricKeyWrapper(AlgorithmIdentifier encAlgId, SubjectPublicKeyInfo publicKeyInfo) + throws IOException + { + super(encAlgId, PublicKeyFactory.createKey(publicKeyInfo)); + } + + protected AsymmetricBlockCipher createAsymmetricWrapper(ASN1ObjectIdentifier algorithm) + { + return new PKCS1Encoding(new RSAEngine()); + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAContentSignerBuilder.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAContentSignerBuilder.java new file mode 100644 index 00000000..d62543b0 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAContentSignerBuilder.java @@ -0,0 +1,24 @@ +package org.spongycastle.operator.bc; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.Signer; +import org.spongycastle.crypto.signers.RSADigestSigner; +import org.spongycastle.operator.OperatorCreationException; + +public class BcRSAContentSignerBuilder + extends BcContentSignerBuilder +{ + public BcRSAContentSignerBuilder(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier digAlgId) + { + super(sigAlgId, digAlgId); + } + + protected Signer createSigner(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier digAlgId) + throws OperatorCreationException + { + Digest dig = digestProvider.get(digAlgId); + + return new RSADigestSigner(dig); + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAContentVerifierProviderBuilder.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAContentVerifierProviderBuilder.java new file mode 100644 index 00000000..e1fd6736 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAContentVerifierProviderBuilder.java @@ -0,0 +1,39 @@ +package org.spongycastle.operator.bc; + +import java.io.IOException; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.Signer; +import org.spongycastle.crypto.params.AsymmetricKeyParameter; +import org.spongycastle.crypto.signers.RSADigestSigner; +import org.spongycastle.crypto.util.PublicKeyFactory; +import org.spongycastle.operator.DigestAlgorithmIdentifierFinder; +import org.spongycastle.operator.OperatorCreationException; + +public class BcRSAContentVerifierProviderBuilder + extends BcContentVerifierProviderBuilder +{ + private DigestAlgorithmIdentifierFinder digestAlgorithmFinder; + + public BcRSAContentVerifierProviderBuilder(DigestAlgorithmIdentifierFinder digestAlgorithmFinder) + { + this.digestAlgorithmFinder = digestAlgorithmFinder; + } + + protected Signer createSigner(AlgorithmIdentifier sigAlgId) + throws OperatorCreationException + { + AlgorithmIdentifier digAlg = digestAlgorithmFinder.find(sigAlgId); + Digest dig = digestProvider.get(digAlg); + + return new RSADigestSigner(dig); + } + + protected AsymmetricKeyParameter extractKeyParameters(SubjectPublicKeyInfo publicKeyInfo) + throws IOException + { + return PublicKeyFactory.createKey(publicKeyInfo); + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcSignerOutputStream.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcSignerOutputStream.java new file mode 100644 index 00000000..f4cdf62b --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcSignerOutputStream.java @@ -0,0 +1,47 @@ +package org.spongycastle.operator.bc; + +import java.io.IOException; +import java.io.OutputStream; + +import org.spongycastle.crypto.CryptoException; +import org.spongycastle.crypto.Signer; + +public class BcSignerOutputStream + extends OutputStream +{ + private Signer sig; + + BcSignerOutputStream(Signer sig) + { + this.sig = sig; + } + + public void write(byte[] bytes, int off, int len) + throws IOException + { + sig.update(bytes, off, len); + } + + public void write(byte[] bytes) + throws IOException + { + sig.update(bytes, 0, bytes.length); + } + + public void write(int b) + throws IOException + { + sig.update((byte)b); + } + + byte[] getSignature() + throws CryptoException + { + return sig.generateSignature(); + } + + boolean verify(byte[] expected) + { + return sig.verifySignature(expected); + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcSymmetricKeyUnwrapper.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcSymmetricKeyUnwrapper.java new file mode 100644 index 00000000..da37cf1a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcSymmetricKeyUnwrapper.java @@ -0,0 +1,49 @@ +package org.spongycastle.operator.bc; + +import java.security.SecureRandom; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.Wrapper; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.OperatorException; +import org.spongycastle.operator.SymmetricKeyUnwrapper; + +public class BcSymmetricKeyUnwrapper + extends SymmetricKeyUnwrapper +{ + private SecureRandom random; + private Wrapper wrapper; + private KeyParameter wrappingKey; + + public BcSymmetricKeyUnwrapper(AlgorithmIdentifier wrappingAlgorithm, Wrapper wrapper, KeyParameter wrappingKey) + { + super(wrappingAlgorithm); + + this.wrapper = wrapper; + this.wrappingKey = wrappingKey; + } + + public BcSymmetricKeyUnwrapper setSecureRandom(SecureRandom random) + { + this.random = random; + + return this; + } + + public GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedKey) + throws OperatorException + { + wrapper.init(false, wrappingKey); + + try + { + return new GenericKey(encryptedKeyAlgorithm, wrapper.unwrap(encryptedKey, 0, encryptedKey.length)); + } + catch (InvalidCipherTextException e) + { + throw new OperatorException("unable to unwrap key: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/BcSymmetricKeyWrapper.java b/pkix/src/main/java/org/spongycastle/operator/bc/BcSymmetricKeyWrapper.java new file mode 100644 index 00000000..a35de7d7 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/bc/BcSymmetricKeyWrapper.java @@ -0,0 +1,51 @@ +package org.spongycastle.operator.bc; + +import java.security.SecureRandom; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.crypto.Wrapper; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithRandom; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.OperatorException; +import org.spongycastle.operator.SymmetricKeyWrapper; + +public class BcSymmetricKeyWrapper + extends SymmetricKeyWrapper +{ + private SecureRandom random; + private Wrapper wrapper; + private KeyParameter wrappingKey; + + public BcSymmetricKeyWrapper(AlgorithmIdentifier wrappingAlgorithm, Wrapper wrapper, KeyParameter wrappingKey) + { + super(wrappingAlgorithm); + + this.wrapper = wrapper; + this.wrappingKey = wrappingKey; + } + + public BcSymmetricKeyWrapper setSecureRandom(SecureRandom random) + { + this.random = random; + + return this; + } + + public byte[] generateWrappedKey(GenericKey encryptionKey) + throws OperatorException + { + byte[] contentEncryptionKeySpec = OperatorUtils.getKeyBytes(encryptionKey); + + if (random == null) + { + wrapper.init(true, wrappingKey); + } + else + { + wrapper.init(true, new ParametersWithRandom(wrappingKey, random)); + } + + return wrapper.wrap(contentEncryptionKeySpec, 0, contentEncryptionKeySpec.length); + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/CamelliaUtil.java b/pkix/src/main/java/org/spongycastle/operator/bc/CamelliaUtil.java new file mode 100644 index 00000000..9b7c9836 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/bc/CamelliaUtil.java @@ -0,0 +1,36 @@ +package org.spongycastle.operator.bc; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ntt.NTTObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.crypto.params.KeyParameter; + +class CamelliaUtil +{ + static AlgorithmIdentifier determineKeyEncAlg(KeyParameter key) + { + int length = key.getKey().length * 8; + ASN1ObjectIdentifier wrapOid; + + if (length == 128) + { + wrapOid = NTTObjectIdentifiers.id_camellia128_wrap; + } + else if (length == 192) + { + wrapOid = NTTObjectIdentifiers.id_camellia192_wrap; + } + else if (length == 256) + { + wrapOid = NTTObjectIdentifiers.id_camellia256_wrap; + } + else + { + throw new IllegalArgumentException( + "illegal keysize in Camellia"); + } + + return new AlgorithmIdentifier(wrapOid); // parameters must be + // absent + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/OperatorUtils.java b/pkix/src/main/java/org/spongycastle/operator/bc/OperatorUtils.java new file mode 100644 index 00000000..a53c4692 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/bc/OperatorUtils.java @@ -0,0 +1,23 @@ +package org.spongycastle.operator.bc; + +import java.security.Key; + +import org.spongycastle.operator.GenericKey; + +class OperatorUtils +{ + static byte[] getKeyBytes(GenericKey key) + { + if (key.getRepresentation() instanceof Key) + { + return ((Key)key.getRepresentation()).getEncoded(); + } + + if (key.getRepresentation() instanceof byte[]) + { + return (byte[])key.getRepresentation(); + } + + throw new IllegalArgumentException("unknown generic key type"); + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/operator/bc/SEEDUtil.java b/pkix/src/main/java/org/spongycastle/operator/bc/SEEDUtil.java new file mode 100644 index 00000000..4d977310 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/bc/SEEDUtil.java @@ -0,0 +1,14 @@ +package org.spongycastle.operator.bc; + +import org.spongycastle.asn1.kisa.KISAObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +class SEEDUtil +{ + static AlgorithmIdentifier determineKeyEncAlg() + { + // parameters absent + return new AlgorithmIdentifier( + KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap); + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaAlgorithmParametersConverter.java b/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaAlgorithmParametersConverter.java new file mode 100644 index 00000000..98e2b929 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaAlgorithmParametersConverter.java @@ -0,0 +1,73 @@ +package org.spongycastle.operator.jcajce; + + +import java.io.IOException; +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.MGF1ParameterSpec; + +import javax.crypto.spec.OAEPParameterSpec; +import javax.crypto.spec.PSource; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.pkcs.RSAESOAEPparams; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder; + +public class JcaAlgorithmParametersConverter +{ + public JcaAlgorithmParametersConverter() + { + } + + public AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier algId, AlgorithmParameters parameters) + throws InvalidAlgorithmParameterException + { + try + { + ASN1Encodable params = ASN1Primitive.fromByteArray(parameters.getEncoded()); + + return new AlgorithmIdentifier(algId, params); + } + catch (IOException e) + { + throw new InvalidAlgorithmParameterException("unable to encode parameters object: " + e.getMessage()); + } + } + + public AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier algorithm, AlgorithmParameterSpec algorithmSpec) + throws InvalidAlgorithmParameterException + { + if (algorithmSpec instanceof OAEPParameterSpec) + { + if (algorithmSpec.equals(OAEPParameterSpec.DEFAULT)) + { + return new AlgorithmIdentifier(algorithm, + new RSAESOAEPparams(RSAESOAEPparams.DEFAULT_HASH_ALGORITHM, RSAESOAEPparams.DEFAULT_MASK_GEN_FUNCTION, RSAESOAEPparams.DEFAULT_P_SOURCE_ALGORITHM)); + } + else + { + OAEPParameterSpec oaepSpec = (OAEPParameterSpec)algorithmSpec; + PSource pSource = oaepSpec.getPSource(); + + if (!oaepSpec.getMGFAlgorithm().equals(OAEPParameterSpec.DEFAULT.getMGFAlgorithm())) + { + throw new InvalidAlgorithmParameterException("only " + OAEPParameterSpec.DEFAULT.getMGFAlgorithm() + " mask generator supported."); + } + + AlgorithmIdentifier hashAlgorithm = new DefaultDigestAlgorithmIdentifierFinder().find(oaepSpec.getDigestAlgorithm()); + AlgorithmIdentifier mgf1HashAlgorithm = new DefaultDigestAlgorithmIdentifierFinder().find((((MGF1ParameterSpec)oaepSpec.getMGFParameters()).getDigestAlgorithm())); + return new AlgorithmIdentifier(algorithm, + new RSAESOAEPparams(hashAlgorithm, new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, mgf1HashAlgorithm), + new AlgorithmIdentifier(PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(((PSource.PSpecified)pSource).getValue())))); + } + } + + throw new InvalidAlgorithmParameterException("unknown parameter spec passed."); + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaContentSignerBuilder.java b/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaContentSignerBuilder.java new file mode 100644 index 00000000..f3a008dd --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaContentSignerBuilder.java @@ -0,0 +1,160 @@ +package org.spongycastle.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 org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.jcajce.util.DefaultJcaJceHelper; +import org.spongycastle.jcajce.util.NamedJcaJceHelper; +import org.spongycastle.jcajce.util.ProviderJcaJceHelper; +import org.spongycastle.operator.ContentSigner; +import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.operator.OperatorStreamException; +import org.spongycastle.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); + + if (random != null) + { + sig.initSign(privateKey, random); + } + else + { + sig.initSign(privateKey); + } + + return new ContentSigner() + { + private SignatureOutputStream stream = new SignatureOutputStream(sig); + + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return sigAlgId; + } + + 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/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java b/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java new file mode 100644 index 00000000..7b5690e4 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java @@ -0,0 +1,312 @@ +package org.spongycastle.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 org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.cert.jcajce.JcaX509CertificateHolder; +import org.spongycastle.jcajce.util.DefaultJcaJceHelper; +import org.spongycastle.jcajce.util.NamedJcaJceHelper; +import org.spongycastle.jcajce.util.ProviderJcaJceHelper; +import org.spongycastle.operator.ContentVerifier; +import org.spongycastle.operator.ContentVerifierProvider; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.operator.OperatorStreamException; +import org.spongycastle.operator.RawContentVerifier; +import org.spongycastle.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 SignatureOutputStream stream; + private AlgorithmIdentifier algorithm; + + 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[] digest, byte[] expected) + { + try + { + rawSignature.update(digest); + + return rawSignature.verify(expected); + } + catch (SignatureException e) + { + throw new RuntimeOperatorException("exception obtaining raw signature: " + 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); + } + } + + boolean verify(byte[] expected) + throws SignatureException + { + return sig.verify(expected); + } + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaDigestCalculatorProviderBuilder.java b/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaDigestCalculatorProviderBuilder.java new file mode 100644 index 00000000..c734b866 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaDigestCalculatorProviderBuilder.java @@ -0,0 +1,114 @@ +package org.spongycastle.operator.jcajce; + +import java.io.IOException; +import java.io.OutputStream; +import java.security.GeneralSecurityException; +import java.security.MessageDigest; +import java.security.Provider; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.jcajce.util.DefaultJcaJceHelper; +import org.spongycastle.jcajce.util.NamedJcaJceHelper; +import org.spongycastle.jcajce.util.ProviderJcaJceHelper; +import org.spongycastle.operator.DigestCalculator; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.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/pkix/src/main/java/org/spongycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java b/pkix/src/main/java/org/spongycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java new file mode 100644 index 00000000..0b5cbf60 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java @@ -0,0 +1,133 @@ +package org.spongycastle.operator.jcajce; + +import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.ProviderException; +import java.util.HashMap; +import java.util.Map; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.spec.SecretKeySpec; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.jcajce.util.DefaultJcaJceHelper; +import org.spongycastle.jcajce.util.NamedJcaJceHelper; +import org.spongycastle.jcajce.util.ProviderJcaJceHelper; +import org.spongycastle.operator.AsymmetricKeyUnwrapper; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.OperatorException; + +public class JceAsymmetricKeyUnwrapper + extends AsymmetricKeyUnwrapper +{ + private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper()); + private Map extraMappings = new HashMap(); + private PrivateKey privKey; + + public JceAsymmetricKeyUnwrapper(AlgorithmIdentifier algorithmIdentifier, PrivateKey privKey) + { + super(algorithmIdentifier); + + this.privKey = privKey; + } + + public JceAsymmetricKeyUnwrapper setProvider(Provider provider) + { + this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider)); + + return this; + } + + public JceAsymmetricKeyUnwrapper setProvider(String providerName) + { + this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName)); + + return this; + } + + /** + * Internally algorithm ids are converted into cipher names using a lookup table. For some providers + * the standard lookup table won't work. Use this method to establish a specific mapping from an + * algorithm identifier to a specific algorithm. + * <p> + * For example: + * <pre> + * unwrapper.setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA"); + * </pre> + * </p> + * @param algorithm OID of algorithm in recipient. + * @param algorithmName JCE algorithm name to use. + * @return the current Unwrapper. + */ + public JceAsymmetricKeyUnwrapper setAlgorithmMapping(ASN1ObjectIdentifier algorithm, String algorithmName) + { + extraMappings.put(algorithm, algorithmName); + + return this; + } + + public GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedKey) + throws OperatorException + { + try + { + Key sKey = null; + + Cipher keyCipher = helper.createAsymmetricWrapper(this.getAlgorithmIdentifier().getAlgorithm(), extraMappings); + AlgorithmParameters algParams = helper.createAlgorithmParameters(this.getAlgorithmIdentifier()); + + try + { + if (algParams != null) + { + keyCipher.init(Cipher.UNWRAP_MODE, privKey, algParams); + } + else + { + keyCipher.init(Cipher.UNWRAP_MODE, privKey); + } + sKey = keyCipher.unwrap(encryptedKey, helper.getKeyAlgorithmName(encryptedKeyAlgorithm.getAlgorithm()), Cipher.SECRET_KEY); + } + catch (GeneralSecurityException e) + { + } + catch (IllegalStateException e) + { + } + catch (UnsupportedOperationException e) + { + } + catch (ProviderException e) + { + } + + // some providers do not support UNWRAP (this appears to be only for asymmetric algorithms) + if (sKey == null) + { + keyCipher.init(Cipher.DECRYPT_MODE, privKey); + sKey = new SecretKeySpec(keyCipher.doFinal(encryptedKey), encryptedKeyAlgorithm.getAlgorithm().getId()); + } + + return new JceGenericKey(encryptedKeyAlgorithm, sKey); + } + catch (InvalidKeyException e) + { + throw new OperatorException("key invalid: " + e.getMessage(), e); + } + catch (IllegalBlockSizeException e) + { + throw new OperatorException("illegal blocksize: " + e.getMessage(), e); + } + catch (BadPaddingException e) + { + throw new OperatorException("bad padding: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/jcajce/JceAsymmetricKeyWrapper.java b/pkix/src/main/java/org/spongycastle/operator/jcajce/JceAsymmetricKeyWrapper.java new file mode 100644 index 00000000..95eb3b9a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/jcajce/JceAsymmetricKeyWrapper.java @@ -0,0 +1,157 @@ +package org.spongycastle.operator.jcajce; + +import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; +import java.security.Provider; +import java.security.ProviderException; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.cert.X509Certificate; +import java.util.HashMap; +import java.util.Map; + +import javax.crypto.Cipher; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.jcajce.util.DefaultJcaJceHelper; +import org.spongycastle.jcajce.util.NamedJcaJceHelper; +import org.spongycastle.jcajce.util.ProviderJcaJceHelper; +import org.spongycastle.operator.AsymmetricKeyWrapper; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.OperatorException; + +public class JceAsymmetricKeyWrapper + extends AsymmetricKeyWrapper +{ + private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper()); + private Map extraMappings = new HashMap(); + private PublicKey publicKey; + private SecureRandom random; + + public JceAsymmetricKeyWrapper(PublicKey publicKey) + { + super(SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()).getAlgorithm()); + + this.publicKey = publicKey; + } + + public JceAsymmetricKeyWrapper(X509Certificate certificate) + { + this(certificate.getPublicKey()); + } + + /** + * Create a wrapper, overriding the algorithm type that is stored in the public key. + * + * @param algorithmIdentifier identifier for encryption algorithm to be used. + * @param publicKey the public key to be used. + */ + public JceAsymmetricKeyWrapper(AlgorithmIdentifier algorithmIdentifier, PublicKey publicKey) + { + super(algorithmIdentifier); + + this.publicKey = publicKey; + } + + public JceAsymmetricKeyWrapper setProvider(Provider provider) + { + this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider)); + + return this; + } + + public JceAsymmetricKeyWrapper setProvider(String providerName) + { + this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName)); + + return this; + } + + public JceAsymmetricKeyWrapper setSecureRandom(SecureRandom random) + { + this.random = random; + + return this; + } + + /** + * Internally algorithm ids are converted into cipher names using a lookup table. For some providers + * the standard lookup table won't work. Use this method to establish a specific mapping from an + * algorithm identifier to a specific algorithm. + * <p> + * For example: + * <pre> + * unwrapper.setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA"); + * </pre> + * </p> + * @param algorithm OID of algorithm in recipient. + * @param algorithmName JCE algorithm name to use. + * @return the current Wrapper. + */ + public JceAsymmetricKeyWrapper setAlgorithmMapping(ASN1ObjectIdentifier algorithm, String algorithmName) + { + extraMappings.put(algorithm, algorithmName); + + return this; + } + + public byte[] generateWrappedKey(GenericKey encryptionKey) + throws OperatorException + { + Cipher keyEncryptionCipher = helper.createAsymmetricWrapper(getAlgorithmIdentifier().getAlgorithm(), extraMappings); + AlgorithmParameters algParams = helper.createAlgorithmParameters(this.getAlgorithmIdentifier()); + + byte[] encryptedKeyBytes = null; + + try + { + if (algParams != null) + { + keyEncryptionCipher.init(Cipher.WRAP_MODE, publicKey, algParams, random); + } + else + { + keyEncryptionCipher.init(Cipher.WRAP_MODE, publicKey, random); + } + encryptedKeyBytes = keyEncryptionCipher.wrap(OperatorUtils.getJceKey(encryptionKey)); + } + catch (InvalidKeyException e) + { + } + catch (GeneralSecurityException e) + { + } + catch (IllegalStateException e) + { + } + catch (UnsupportedOperationException e) + { + } + catch (ProviderException e) + { + } + + // some providers do not support WRAP (this appears to be only for asymmetric algorithms) + if (encryptedKeyBytes == null) + { + try + { + keyEncryptionCipher.init(Cipher.ENCRYPT_MODE, publicKey, random); + encryptedKeyBytes = keyEncryptionCipher.doFinal(OperatorUtils.getJceKey(encryptionKey).getEncoded()); + } + catch (InvalidKeyException e) + { + throw new OperatorException("unable to encrypt contents key", e); + } + catch (GeneralSecurityException e) + { + throw new OperatorException("unable to encrypt contents key", e); + } + } + + return encryptedKeyBytes; + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/jcajce/JceGenericKey.java b/pkix/src/main/java/org/spongycastle/operator/jcajce/JceGenericKey.java new file mode 100644 index 00000000..a11a535e --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/jcajce/JceGenericKey.java @@ -0,0 +1,33 @@ +package org.spongycastle.operator.jcajce; + +import java.security.Key; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.operator.GenericKey; + +public class JceGenericKey + extends GenericKey +{ + /** + * Attempt to simplify the key representation if possible. + * + * @param key a provider based key + * @return the byte encoding if one exists, key object otherwise. + */ + private static Object getRepresentation(Key key) + { + byte[] keyBytes = key.getEncoded(); + + if (keyBytes != null) + { + return keyBytes; + } + + return key; + } + + public JceGenericKey(AlgorithmIdentifier algorithmIdentifier, Key representation) + { + super(algorithmIdentifier, getRepresentation(representation)); + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/jcajce/JceSymmetricKeyUnwrapper.java b/pkix/src/main/java/org/spongycastle/operator/jcajce/JceSymmetricKeyUnwrapper.java new file mode 100644 index 00000000..dd9e7e0a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/jcajce/JceSymmetricKeyUnwrapper.java @@ -0,0 +1,65 @@ +package org.spongycastle.operator.jcajce; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.jcajce.util.DefaultJcaJceHelper; +import org.spongycastle.jcajce.util.NamedJcaJceHelper; +import org.spongycastle.jcajce.util.ProviderJcaJceHelper; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.OperatorException; +import org.spongycastle.operator.SymmetricKeyUnwrapper; + +public class JceSymmetricKeyUnwrapper + extends SymmetricKeyUnwrapper +{ + private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper()); + private SecretKey secretKey; + + public JceSymmetricKeyUnwrapper(AlgorithmIdentifier algorithmIdentifier, SecretKey secretKey) + { + super(algorithmIdentifier); + + this.secretKey = secretKey; + } + + public JceSymmetricKeyUnwrapper setProvider(Provider provider) + { + this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider)); + + return this; + } + + public JceSymmetricKeyUnwrapper setProvider(String providerName) + { + this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName)); + + return this; + } + + public GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedKey) + throws OperatorException + { + try + { + Cipher keyCipher = helper.createSymmetricWrapper(this.getAlgorithmIdentifier().getAlgorithm()); + + keyCipher.init(Cipher.UNWRAP_MODE, secretKey); + + return new JceGenericKey(encryptedKeyAlgorithm, keyCipher.unwrap(encryptedKey, helper.getKeyAlgorithmName(encryptedKeyAlgorithm.getAlgorithm()), Cipher.SECRET_KEY)); + } + catch (InvalidKeyException e) + { + throw new OperatorException("key invalid in message.", e); + } + catch (NoSuchAlgorithmException e) + { + throw new OperatorException("can't find algorithm.", e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/jcajce/JceSymmetricKeyWrapper.java b/pkix/src/main/java/org/spongycastle/operator/jcajce/JceSymmetricKeyWrapper.java new file mode 100644 index 00000000..3689f6c2 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/jcajce/JceSymmetricKeyWrapper.java @@ -0,0 +1,154 @@ +package org.spongycastle.operator.jcajce; + +import java.security.GeneralSecurityException; +import java.security.Key; +import java.security.Provider; +import java.security.SecureRandom; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; + +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.kisa.KISAObjectIdentifiers; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.ntt.NTTObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.jcajce.util.DefaultJcaJceHelper; +import org.spongycastle.jcajce.util.NamedJcaJceHelper; +import org.spongycastle.jcajce.util.ProviderJcaJceHelper; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.OperatorException; +import org.spongycastle.operator.SymmetricKeyWrapper; + +public class JceSymmetricKeyWrapper + extends SymmetricKeyWrapper +{ + private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper()); + private SecureRandom random; + private SecretKey wrappingKey; + + public JceSymmetricKeyWrapper(SecretKey wrappingKey) + { + super(determineKeyEncAlg(wrappingKey)); + + this.wrappingKey = wrappingKey; + } + + public JceSymmetricKeyWrapper setProvider(Provider provider) + { + this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider)); + + return this; + } + + public JceSymmetricKeyWrapper setProvider(String providerName) + { + this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName)); + + return this; + } + + public JceSymmetricKeyWrapper setSecureRandom(SecureRandom random) + { + this.random = random; + + return this; + } + + public byte[] generateWrappedKey(GenericKey encryptionKey) + throws OperatorException + { + Key contentEncryptionKeySpec = OperatorUtils.getJceKey(encryptionKey); + + Cipher keyEncryptionCipher = helper.createSymmetricWrapper(this.getAlgorithmIdentifier().getAlgorithm()); + + try + { + keyEncryptionCipher.init(Cipher.WRAP_MODE, wrappingKey, random); + + return keyEncryptionCipher.wrap(contentEncryptionKeySpec); + } + catch (GeneralSecurityException e) + { + throw new OperatorException("cannot wrap key: " + e.getMessage(), e); + } + } + + private static AlgorithmIdentifier determineKeyEncAlg(SecretKey key) + { + String algorithm = key.getAlgorithm(); + + if (algorithm.startsWith("DES")) + { + return new AlgorithmIdentifier(new ASN1ObjectIdentifier( + "1.2.840.113549.1.9.16.3.6"), DERNull.INSTANCE); + } + else if (algorithm.startsWith("RC2")) + { + return new AlgorithmIdentifier(new ASN1ObjectIdentifier( + "1.2.840.113549.1.9.16.3.7"), new ASN1Integer(58)); + } + else if (algorithm.startsWith("AES")) + { + int length = key.getEncoded().length * 8; + ASN1ObjectIdentifier wrapOid; + + if (length == 128) + { + wrapOid = NISTObjectIdentifiers.id_aes128_wrap; + } + else if (length == 192) + { + wrapOid = NISTObjectIdentifiers.id_aes192_wrap; + } + else if (length == 256) + { + wrapOid = NISTObjectIdentifiers.id_aes256_wrap; + } + else + { + throw new IllegalArgumentException("illegal keysize in AES"); + } + + return new AlgorithmIdentifier(wrapOid); // parameters absent + } + else if (algorithm.startsWith("SEED")) + { + // parameters absent + return new AlgorithmIdentifier( + KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap); + } + else if (algorithm.startsWith("Camellia")) + { + int length = key.getEncoded().length * 8; + ASN1ObjectIdentifier wrapOid; + + if (length == 128) + { + wrapOid = NTTObjectIdentifiers.id_camellia128_wrap; + } + else if (length == 192) + { + wrapOid = NTTObjectIdentifiers.id_camellia192_wrap; + } + else if (length == 256) + { + wrapOid = NTTObjectIdentifiers.id_camellia256_wrap; + } + else + { + throw new IllegalArgumentException( + "illegal keysize in Camellia"); + } + + return new AlgorithmIdentifier(wrapOid); // parameters must be + // absent + } + else + { + throw new IllegalArgumentException("unknown algorithm"); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/jcajce/OperatorHelper.java b/pkix/src/main/java/org/spongycastle/operator/jcajce/OperatorHelper.java new file mode 100644 index 00000000..8f2776ae --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/jcajce/OperatorHelper.java @@ -0,0 +1,433 @@ +package org.spongycastle.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 org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.bsi.BSIObjectIdentifiers; +import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import org.spongycastle.asn1.eac.EACObjectIdentifiers; +import org.spongycastle.asn1.kisa.KISAObjectIdentifiers; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.ntt.NTTObjectIdentifiers; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.pkcs.RSASSAPSSparams; +import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.asn1.x9.X9ObjectIdentifiers; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.jcajce.util.JcaJceHelper; +import org.spongycastle.jcajce.util.JcaJceUtils; +import org.spongycastle.operator.OperatorCreationException; + +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(); + + 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"); + 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"); + + oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA"); + oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA"); + oids.put(new ASN1ObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA"); + oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WITHECDSA"); + oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA"); + oids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256WITHECDSA"); + oids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384WITHECDSA"); + oids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512WITHECDSA"); + oids.put(OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA"); + oids.put(OIWObjectIdentifiers.dsaWithSHA1, "SHA1WITHDSA"); + oids.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WITHDSA"); + oids.put(NISTObjectIdentifiers.dsa_with_sha256, "SHA256WITHDSA"); + + 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"); + + 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; + } + + 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(JcaJceUtils.getDigestAlgName(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; + } + } + + 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); + + JcaJceUtils.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 JcaJceUtils.getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "WITHRSAANDMGF1"; + } + } + + if (oids.containsKey(sigAlgId.getAlgorithm())) + { + return (String)oids.get(sigAlgId.getAlgorithm()); + } + + return sigAlgId.getAlgorithm().getId(); + } + + 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 (NoSuchAlgorithmException e) + { + throw new OpCertificateException("cannot create certificate factory: " + 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(); + } +} diff --git a/pkix/src/main/java/org/spongycastle/operator/jcajce/OperatorUtils.java b/pkix/src/main/java/org/spongycastle/operator/jcajce/OperatorUtils.java new file mode 100644 index 00000000..81cb4063 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/operator/jcajce/OperatorUtils.java @@ -0,0 +1,25 @@ +package org.spongycastle.operator.jcajce; + +import java.security.Key; + +import javax.crypto.spec.SecretKeySpec; + +import org.spongycastle.operator.GenericKey; + +class OperatorUtils +{ + static Key getJceKey(GenericKey key) + { + if (key.getRepresentation() instanceof Key) + { + return (Key)key.getRepresentation(); + } + + if (key.getRepresentation() instanceof byte[]) + { + return new SecretKeySpec((byte[])key.getRepresentation(), "ENC"); + } + + throw new IllegalArgumentException("unknown generic key type"); + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/pkcs/MacDataGenerator.java b/pkix/src/main/java/org/spongycastle/pkcs/MacDataGenerator.java new file mode 100644 index 00000000..c6667d8b --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/MacDataGenerator.java @@ -0,0 +1,49 @@ +package org.spongycastle.pkcs; + + +import java.io.IOException; +import java.io.OutputStream; + +import org.spongycastle.asn1.pkcs.MacData; +import org.spongycastle.asn1.pkcs.PKCS12PBEParams; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.DigestInfo; +import org.spongycastle.operator.MacCalculator; + +class MacDataGenerator +{ + private PKCS12MacCalculatorBuilder builder; + + MacDataGenerator(PKCS12MacCalculatorBuilder builder) + { + this.builder = builder; + } + + public MacData build(char[] password, byte[] data) + throws PKCSException + { + MacCalculator macCalculator; + + try + { + macCalculator = builder.build(password); + + OutputStream out = macCalculator.getOutputStream(); + + out.write(data); + + out.close(); + } + catch (Exception e) + { + throw new PKCSException("unable to process data: " + e.getMessage(), e); + } + + AlgorithmIdentifier algId = macCalculator.getAlgorithmIdentifier(); + + DigestInfo dInfo = new DigestInfo(builder.getDigestAlgorithmIdentifier(), macCalculator.getMac()); + PKCS12PBEParams params = PKCS12PBEParams.getInstance(algId.getParameters()); + + return new MacData(dInfo, params.getIV(), params.getIterations().intValue()); + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/PKCS10CertificationRequest.java b/pkix/src/main/java/org/spongycastle/pkcs/PKCS10CertificationRequest.java new file mode 100644 index 00000000..c4ee749a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/PKCS10CertificationRequest.java @@ -0,0 +1,236 @@ +package org.spongycastle.pkcs; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.pkcs.Attribute; +import org.spongycastle.asn1.pkcs.CertificationRequest; +import org.spongycastle.asn1.pkcs.CertificationRequestInfo; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.operator.ContentVerifier; +import org.spongycastle.operator.ContentVerifierProvider; + +/** + * Holding class for a PKCS#10 certification request. + */ +public class PKCS10CertificationRequest +{ + private static Attribute[] EMPTY_ARRAY = new Attribute[0]; + + private CertificationRequest certificationRequest; + + private static CertificationRequest parseBytes(byte[] encoding) + throws IOException + { + try + { + return CertificationRequest.getInstance(ASN1Primitive.fromByteArray(encoding)); + } + catch (ClassCastException e) + { + throw new PKCSIOException("malformed data: " + e.getMessage(), e); + } + catch (IllegalArgumentException e) + { + throw new PKCSIOException("malformed data: " + e.getMessage(), e); + } + } + + /** + * Create a PKCS10CertificationRequestHolder from an underlying ASN.1 structure. + * + * @param certificationRequest the underlying ASN.1 structure representing a request. + */ + public PKCS10CertificationRequest(CertificationRequest certificationRequest) + { + this.certificationRequest = certificationRequest; + } + + /** + * Create a PKCS10CertificationRequestHolder from the passed in bytes. + * + * @param encoded BER/DER encoding of the CertificationRequest structure. + * @throws IOException in the event of corrupted data, or an incorrect structure. + */ + public PKCS10CertificationRequest(byte[] encoded) + throws IOException + { + this(parseBytes(encoded)); + } + + /** + * Return the underlying ASN.1 structure for this request. + * + * @return a CertificateRequest object. + */ + public CertificationRequest toASN1Structure() + { + return certificationRequest; + } + + /** + * Return the subject on this request. + * + * @return the X500Name representing the request's subject. + */ + public X500Name getSubject() + { + return X500Name.getInstance(certificationRequest.getCertificationRequestInfo().getSubject()); + } + + /** + * Return the details of the signature algorithm used to create this request. + * + * @return the AlgorithmIdentifier describing the signature algorithm used to create this request. + */ + public AlgorithmIdentifier getSignatureAlgorithm() + { + return certificationRequest.getSignatureAlgorithm(); + } + + /** + * Return the bytes making up the signature associated with this request. + * + * @return the request signature bytes. + */ + public byte[] getSignature() + { + return certificationRequest.getSignature().getBytes(); + } + + /** + * Return the SubjectPublicKeyInfo describing the public key this request is carrying. + * + * @return the public key ASN.1 structure contained in the request. + */ + public SubjectPublicKeyInfo getSubjectPublicKeyInfo() + { + return certificationRequest.getCertificationRequestInfo().getSubjectPublicKeyInfo(); + } + + /** + * Return the attributes, if any associated with this request. + * + * @return an array of Attribute, zero length if none present. + */ + public Attribute[] getAttributes() + { + ASN1Set attrSet = certificationRequest.getCertificationRequestInfo().getAttributes(); + + if (attrSet == null) + { + return EMPTY_ARRAY; + } + + Attribute[] attrs = new Attribute[attrSet.size()]; + + for (int i = 0; i != attrSet.size(); i++) + { + attrs[i] = Attribute.getInstance(attrSet.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) + { + ASN1Set attrSet = certificationRequest.getCertificationRequestInfo().getAttributes(); + + if (attrSet == null) + { + return EMPTY_ARRAY; + } + + List list = new ArrayList(); + + for (int i = 0; i != attrSet.size(); i++) + { + Attribute attr = Attribute.getInstance(attrSet.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()]); + } + + public byte[] getEncoded() + throws IOException + { + return certificationRequest.getEncoded(); + } + + /** + * Validate the signature on the PKCS10 certification request 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 PKCSException if the signature cannot be processed or is inappropriate. + */ + public boolean isSignatureValid(ContentVerifierProvider verifierProvider) + throws PKCSException + { + CertificationRequestInfo requestInfo = certificationRequest.getCertificationRequestInfo(); + + ContentVerifier verifier; + + try + { + verifier = verifierProvider.get(certificationRequest.getSignatureAlgorithm()); + + OutputStream sOut = verifier.getOutputStream(); + + sOut.write(requestInfo.getEncoded(ASN1Encoding.DER)); + + sOut.close(); + } + catch (Exception e) + { + throw new PKCSException("unable to process signature: " + e.getMessage(), e); + } + + return verifier.verify(certificationRequest.getSignature().getBytes()); + } + + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + + if (!(o instanceof PKCS10CertificationRequest)) + { + return false; + } + + PKCS10CertificationRequest other = (PKCS10CertificationRequest)o; + + return this.toASN1Structure().equals(other.toASN1Structure()); + } + + public int hashCode() + { + return this.toASN1Structure().hashCode(); + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/PKCS10CertificationRequestBuilder.java b/pkix/src/main/java/org/spongycastle/pkcs/PKCS10CertificationRequestBuilder.java new file mode 100644 index 00000000..d10c6fdd --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/PKCS10CertificationRequestBuilder.java @@ -0,0 +1,156 @@ +package org.spongycastle.pkcs; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERBitString; +import org.spongycastle.asn1.DERSet; +import org.spongycastle.asn1.pkcs.Attribute; +import org.spongycastle.asn1.pkcs.CertificationRequest; +import org.spongycastle.asn1.pkcs.CertificationRequestInfo; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.operator.ContentSigner; + +/** + * A class for creating PKCS#10 Certification requests. + * <pre> + * CertificationRequest ::= SEQUENCE { + * certificationRequestInfo CertificationRequestInfo, + * signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }}, + * signature BIT STRING + * } + * + * CertificationRequestInfo ::= SEQUENCE { + * version INTEGER { v1(0) } (v1,...), + * subject Name, + * subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }}, + * attributes [0] Attributes{{ CRIAttributes }} + * } + * + * Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }} + * + * Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE { + * type ATTRIBUTE.&id({IOSet}), + * values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type}) + * } + * </pre> + */ +public class PKCS10CertificationRequestBuilder +{ + private SubjectPublicKeyInfo publicKeyInfo; + private X500Name subject; + private List attributes = new ArrayList(); + private boolean leaveOffEmpty = false; + + /** + * Basic constructor. + * + * @param subject the X.500 Name defining the certificate subject this request is for. + * @param publicKeyInfo the info structure for the public key to be associated with this subject. + */ + public PKCS10CertificationRequestBuilder(X500Name subject, SubjectPublicKeyInfo publicKeyInfo) + { + this.subject = subject; + this.publicKeyInfo = publicKeyInfo; + } + + /** + * Add an attribute to the certification request we are building. + * + * @param attrType the OID giving the type of the attribute. + * @param attrValue the ASN.1 structure that forms the value of the attribute. + * @return this builder object. + */ + public PKCS10CertificationRequestBuilder addAttribute(ASN1ObjectIdentifier attrType, ASN1Encodable attrValue) + { + attributes.add(new Attribute(attrType, new DERSet(attrValue))); + + return this; + } + + /** + * Add an attribute with multiple values to the certification request we are building. + * + * @param attrType the OID giving the type of the attribute. + * @param attrValues an array of ASN.1 structures that form the value of the attribute. + * @return this builder object. + */ + public PKCS10CertificationRequestBuilder addAttribute(ASN1ObjectIdentifier attrType, ASN1Encodable[] attrValues) + { + attributes.add(new Attribute(attrType, new DERSet(attrValues))); + + return this; + } + + /** + * The attributes field in PKCS10 should encoded to an empty tagged set if there are + * no attributes. Some CAs will reject requests with the attribute field present. + * + * @param leaveOffEmpty true if empty attributes should be left out of the encoding false otherwise. + * @return this builder object. + */ + public PKCS10CertificationRequestBuilder setLeaveOffEmptyAttributes(boolean leaveOffEmpty) + { + this.leaveOffEmpty = leaveOffEmpty; + + return this; + } + + /** + * Generate an PKCS#10 request based on the past in signer. + * + * @param signer the content signer to be used to generate the signature validating the certificate. + * @return a holder containing the resulting PKCS#10 certification request. + */ + public PKCS10CertificationRequest build( + ContentSigner signer) + { + CertificationRequestInfo info; + + if (attributes.isEmpty()) + { + if (leaveOffEmpty) + { + info = new CertificationRequestInfo(subject, publicKeyInfo, null); + } + else + { + info = new CertificationRequestInfo(subject, publicKeyInfo, new DERSet()); + } + } + else + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (Iterator it = attributes.iterator(); it.hasNext();) + { + v.add(Attribute.getInstance(it.next())); + } + + info = new CertificationRequestInfo(subject, publicKeyInfo, new DERSet(v)); + } + + try + { + OutputStream sOut = signer.getOutputStream(); + + sOut.write(info.getEncoded(ASN1Encoding.DER)); + + sOut.close(); + + return new PKCS10CertificationRequest(new CertificationRequest(info, signer.getAlgorithmIdentifier(), new DERBitString(signer.getSignature()))); + } + catch (IOException e) + { + throw new IllegalStateException("cannot produce certification request signature"); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/PKCS12MacCalculatorBuilder.java b/pkix/src/main/java/org/spongycastle/pkcs/PKCS12MacCalculatorBuilder.java new file mode 100644 index 00000000..be82e990 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/PKCS12MacCalculatorBuilder.java @@ -0,0 +1,13 @@ +package org.spongycastle.pkcs; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.operator.MacCalculator; +import org.spongycastle.operator.OperatorCreationException; + +public interface PKCS12MacCalculatorBuilder +{ + MacCalculator build(char[] password) + throws OperatorCreationException; + + AlgorithmIdentifier getDigestAlgorithmIdentifier(); +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/PKCS12MacCalculatorBuilderProvider.java b/pkix/src/main/java/org/spongycastle/pkcs/PKCS12MacCalculatorBuilderProvider.java new file mode 100644 index 00000000..52c9d1cd --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/PKCS12MacCalculatorBuilderProvider.java @@ -0,0 +1,8 @@ +package org.spongycastle.pkcs; + +import org.spongycastle.asn1.x509.AlgorithmIdentifier; + +public interface PKCS12MacCalculatorBuilderProvider +{ + PKCS12MacCalculatorBuilder get(AlgorithmIdentifier algorithmIdentifier); +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/PKCS12PfxPdu.java b/pkix/src/main/java/org/spongycastle/pkcs/PKCS12PfxPdu.java new file mode 100644 index 00000000..6a229e48 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/PKCS12PfxPdu.java @@ -0,0 +1,161 @@ +package org.spongycastle.pkcs; + +import java.io.IOException; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.pkcs.ContentInfo; +import org.spongycastle.asn1.pkcs.MacData; +import org.spongycastle.asn1.pkcs.PKCS12PBEParams; +import org.spongycastle.asn1.pkcs.Pfx; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cert.CertIOException; +import org.spongycastle.util.Arrays; + +/** + * A holding class for the PKCS12 Pfx structure. + */ +public class PKCS12PfxPdu +{ + private Pfx pfx; + + private static Pfx parseBytes(byte[] pfxEncoding) + throws IOException + { + try + { + return Pfx.getInstance(ASN1Primitive.fromByteArray(pfxEncoding)); + } + catch (ClassCastException e) + { + throw new CertIOException("malformed data: " + e.getMessage(), e); + } + catch (IllegalArgumentException e) + { + throw new CertIOException("malformed data: " + e.getMessage(), e); + } + } + + public PKCS12PfxPdu(Pfx pfx) + { + this.pfx = pfx; + } + + public PKCS12PfxPdu(byte[] pfx) + throws IOException + { + this(parseBytes(pfx)); + } + + /** + * Return the content infos in the AuthenticatedSafe contained in this Pfx. + * + * @return an array of ContentInfo. + */ + public ContentInfo[] getContentInfos() + { + ASN1Sequence seq = ASN1Sequence.getInstance(ASN1OctetString.getInstance(this.pfx.getAuthSafe().getContent()).getOctets()); + ContentInfo[] content = new ContentInfo[seq.size()]; + + for (int i = 0; i != seq.size(); i++) + { + content[i] = ContentInfo.getInstance(seq.getObjectAt(i)); + } + + return content; + } + + /** + * Return whether or not there is MAC attached to this file. + * + * @return true if there is, false otherwise. + */ + public boolean hasMac() + { + return pfx.getMacData() != null; + } + + /** + * Return the algorithm identifier describing the MAC algorithm + * + * @return the AlgorithmIdentifier representing the MAC algorithm, null if none present. + */ + public AlgorithmIdentifier getMacAlgorithmID() + { + MacData md = pfx.getMacData(); + + if (md != null) + { + return md.getMac().getAlgorithmId(); + } + + return null; + } + + /** + * Verify the MacData attached to the PFX is consistent with what is expected. + * + * @param macCalcProviderBuilder provider builder for the calculator for the MAC + * @param password password to use + * @return true if mac data is valid, false otherwise. + * @throws PKCSException if there is a problem evaluating the MAC. + * @throws IllegalStateException if no MAC is actually present + */ + public boolean isMacValid(PKCS12MacCalculatorBuilderProvider macCalcProviderBuilder, char[] password) + throws PKCSException + { + if (hasMac()) + { + MacData pfxmData = pfx.getMacData(); + MacDataGenerator mdGen = new MacDataGenerator(macCalcProviderBuilder.get(new AlgorithmIdentifier(pfxmData.getMac().getAlgorithmId().getAlgorithm(), new PKCS12PBEParams(pfxmData.getSalt(), pfxmData.getIterationCount().intValue())))); + + try + { + MacData mData = mdGen.build( + password, + ASN1OctetString.getInstance(pfx.getAuthSafe().getContent()).getOctets()); + + return Arrays.constantTimeAreEqual(mData.getEncoded(), pfx.getMacData().getEncoded()); + } + catch (IOException e) + { + throw new PKCSException("unable to process AuthSafe: " + e.getMessage()); + } + } + + throw new IllegalStateException("no MAC present on PFX"); + } + + /** + * Return the underlying ASN.1 object. + * + * @return a Pfx object. + */ + public Pfx toASN1Structure() + { + return pfx; + } + + public byte[] getEncoded() + throws IOException + { + return toASN1Structure().getEncoded(); + } + + /** + * Return a Pfx with the outer wrapper encoded as asked for. For example, Pfx is a usually + * a BER encoded object, to get one with DefiniteLength encoding use: + * <pre> + * getEncoded(ASN1Encoding.DL) + * </pre> + * @param encoding encoding style (ASN1Encoding.DER, ASN1Encoding.DL, ASN1Encoding.BER) + * @return a byte array containing the encoded object. + * @throws IOException + */ + public byte[] getEncoded(String encoding) + throws IOException + { + return toASN1Structure().getEncoded(encoding); + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/PKCS12PfxPduBuilder.java b/pkix/src/main/java/org/spongycastle/pkcs/PKCS12PfxPduBuilder.java new file mode 100644 index 00000000..a9cb0b5b --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/PKCS12PfxPduBuilder.java @@ -0,0 +1,179 @@ +package org.spongycastle.pkcs; + +import java.io.IOException; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.DLSequence; +import org.spongycastle.asn1.pkcs.AuthenticatedSafe; +import org.spongycastle.asn1.pkcs.ContentInfo; +import org.spongycastle.asn1.pkcs.MacData; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.pkcs.Pfx; +import org.spongycastle.cms.CMSEncryptedDataGenerator; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.CMSProcessableByteArray; +import org.spongycastle.operator.OutputEncryptor; + +/** + * A builder for the PKCS#12 Pfx key and certificate store. + * <p> + * For example: you can build a basic key store for the user owning privKey as follows: + * </p> + * <pre> + * X509Certificate[] chain = .... + * PublicKey pubKey = .... + * PrivateKey privKey = .... + * JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils(); + * + * PKCS12SafeBagBuilder taCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[2]); + * + * taCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Bouncy Primary Certificate")); + * + * PKCS12SafeBagBuilder caCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[1]); + * + * caCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Bouncy Intermediate Certificate")); + * + * PKCS12SafeBagBuilder eeCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[0]); + * + * eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Eric's Key")); + * eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, extUtils.createSubjectKeyIdentifier(pubKey)); + * + * PKCS12SafeBagBuilder keyBagBuilder = new JcaPKCS12SafeBagBuilder(privKey, new BcPKCS12PBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, new CBCBlockCipher(new DESedeEngine())).build(passwd)); + * + * keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Eric's Key")); + * keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, extUtils.createSubjectKeyIdentifier(pubKey)); + * + * // + * // construct the actual key store + * // + * PKCS12PfxPduBuilder pfxPduBuilder = new PKCS12PfxPduBuilder(); + * + * PKCS12SafeBag[] certs = new PKCS12SafeBag[3]; + * + * certs[0] = eeCertBagBuilder.build(); + * certs[1] = caCertBagBuilder.build(); + * certs[2] = taCertBagBuilder.build(); + * + * pfxPduBuilder.addEncryptedData(new BcPKCS12PBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC, new CBCBlockCipher(new RC2Engine())).build(passwd), certs); + * + * pfxPduBuilder.addData(keyBagBuilder.build()); + * + * PKCS12PfxPdu pfx = pfxPduBuilder.build(new BcPKCS12MacCalculatorBuilder(), passwd); + * </pre> + * + */ +public class PKCS12PfxPduBuilder +{ + private ASN1EncodableVector dataVector = new ASN1EncodableVector(); + + /** + * Add a SafeBag that is to be included as is. + * + * @param data the SafeBag to add. + * @return this builder. + * @throws IOException + */ + public PKCS12PfxPduBuilder addData(PKCS12SafeBag data) + throws IOException + { + dataVector.add(new ContentInfo(PKCSObjectIdentifiers.data, new DEROctetString(new DLSequence(data.toASN1Structure()).getEncoded()))); + + return this; + } + + /** + * Add a SafeBag that is to be wrapped in a EncryptedData object. + * + * @param dataEncryptor the encryptor to use for encoding the data. + * @param data the SafeBag to include. + * @return this builder. + * @throws IOException if a issue occurs processing the data. + */ + public PKCS12PfxPduBuilder addEncryptedData(OutputEncryptor dataEncryptor, PKCS12SafeBag data) + throws IOException + { + return addEncryptedData(dataEncryptor, new DERSequence(data.toASN1Structure())); + } + + /** + * Add a set of SafeBags that are to be wrapped in a EncryptedData object. + * + * @param dataEncryptor the encryptor to use for encoding the data. + * @param data the SafeBags to include. + * @return this builder. + * @throws IOException if a issue occurs processing the data. + */ + public PKCS12PfxPduBuilder addEncryptedData(OutputEncryptor dataEncryptor, PKCS12SafeBag[] data) + throws IOException + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (int i = 0; i != data.length; i++) + { + v.add(data[i].toASN1Structure()); + } + + return addEncryptedData(dataEncryptor, new DLSequence(v)); + } + + private PKCS12PfxPduBuilder addEncryptedData(OutputEncryptor dataEncryptor, ASN1Sequence data) + throws IOException + { + CMSEncryptedDataGenerator envGen = new CMSEncryptedDataGenerator(); + + try + { + dataVector.add(envGen.generate(new CMSProcessableByteArray(data.getEncoded()), dataEncryptor).toASN1Structure()); + } + catch (CMSException e) + { + throw new PKCSIOException(e.getMessage(), e.getCause()); + } + + return this; + } + + /** + * Build the Pfx structure, protecting it with a MAC calculated against the passed in password. + * + * @param macCalcBuilder a builder for a PKCS12 mac calculator. + * @param password the password to use. + * @return a Pfx object. + * @throws PKCSException on a encoding or processing error. + */ + public PKCS12PfxPdu build(PKCS12MacCalculatorBuilder macCalcBuilder, char[] password) + throws PKCSException + { + AuthenticatedSafe auth = AuthenticatedSafe.getInstance(new DLSequence(dataVector)); + byte[] encAuth; + + try + { + encAuth = auth.getEncoded(); + } + catch (IOException e) + { + throw new PKCSException("unable to encode AuthenticatedSafe: " + e.getMessage(), e); + } + + ContentInfo mainInfo = new ContentInfo(PKCSObjectIdentifiers.data, new DEROctetString(encAuth)); + MacData mData = null; + + if (macCalcBuilder != null) + { + MacDataGenerator mdGen = new MacDataGenerator(macCalcBuilder); + + mData = mdGen.build(password, encAuth); + } + + // + // output the Pfx + // + Pfx pfx = new Pfx(mainInfo, mData); + + return new PKCS12PfxPdu(pfx); + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/PKCS12SafeBag.java b/pkix/src/main/java/org/spongycastle/pkcs/PKCS12SafeBag.java new file mode 100644 index 00000000..0ce0887e --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/PKCS12SafeBag.java @@ -0,0 +1,93 @@ +package org.spongycastle.pkcs; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.pkcs.Attribute; +import org.spongycastle.asn1.pkcs.CRLBag; +import org.spongycastle.asn1.pkcs.CertBag; +import org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PrivateKeyInfo; +import org.spongycastle.asn1.pkcs.SafeBag; +import org.spongycastle.asn1.x509.Certificate; +import org.spongycastle.asn1.x509.CertificateList; +import org.spongycastle.cert.X509CRLHolder; +import org.spongycastle.cert.X509CertificateHolder; + +public class PKCS12SafeBag +{ + public static final ASN1ObjectIdentifier friendlyNameAttribute = PKCSObjectIdentifiers.pkcs_9_at_friendlyName; + public static final ASN1ObjectIdentifier localKeyIdAttribute = PKCSObjectIdentifiers.pkcs_9_at_localKeyId; + + private SafeBag safeBag; + + public PKCS12SafeBag(SafeBag safeBag) + { + this.safeBag = safeBag; + } + + /** + * Return the underlying ASN.1 structure for this safe bag. + * + * @return a SafeBag + */ + public SafeBag toASN1Structure() + { + return safeBag; + } + + /** + * Return the BagId giving the type of content in the bag. + * + * @return the bagId + */ + public ASN1ObjectIdentifier getType() + { + return safeBag.getBagId(); + } + + public Attribute[] getAttributes() + { + ASN1Set attrs = safeBag.getBagAttributes(); + + if (attrs == null) + { + return null; + } + + Attribute[] attributes = new Attribute[attrs.size()]; + for (int i = 0; i != attrs.size(); i++) + { + attributes[i] = Attribute.getInstance(attrs.getObjectAt(i)); + } + + return attributes; + } + + public Object getBagValue() + { + if (getType().equals(PKCSObjectIdentifiers.pkcs8ShroudedKeyBag)) + { + return new PKCS8EncryptedPrivateKeyInfo(EncryptedPrivateKeyInfo.getInstance(safeBag.getBagValue())); + } + if (getType().equals(PKCSObjectIdentifiers.certBag)) + { + CertBag certBag = CertBag.getInstance(safeBag.getBagValue()); + + return new X509CertificateHolder(Certificate.getInstance(ASN1OctetString.getInstance(certBag.getCertValue()).getOctets())); + } + if (getType().equals(PKCSObjectIdentifiers.keyBag)) + { + return PrivateKeyInfo.getInstance(safeBag.getBagValue()); + } + if (getType().equals(PKCSObjectIdentifiers.crlBag)) + { + CRLBag crlBag = CRLBag.getInstance(safeBag.getBagValue()); + + return new X509CRLHolder(CertificateList.getInstance(ASN1OctetString.getInstance(crlBag.getCRLValue()).getOctets())); + } + + return safeBag.getBagValue(); + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/PKCS12SafeBagBuilder.java b/pkix/src/main/java/org/spongycastle/pkcs/PKCS12SafeBagBuilder.java new file mode 100644 index 00000000..d60bd5a5 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/PKCS12SafeBagBuilder.java @@ -0,0 +1,76 @@ +package org.spongycastle.pkcs; + +import java.io.IOException; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.DERSet; +import org.spongycastle.asn1.pkcs.Attribute; +import org.spongycastle.asn1.pkcs.CertBag; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PrivateKeyInfo; +import org.spongycastle.asn1.pkcs.SafeBag; +import org.spongycastle.asn1.x509.Certificate; +import org.spongycastle.asn1.x509.CertificateList; +import org.spongycastle.cert.X509CRLHolder; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.operator.OutputEncryptor; + +public class PKCS12SafeBagBuilder +{ + private ASN1ObjectIdentifier bagType; + private ASN1Encodable bagValue; + private ASN1EncodableVector bagAttrs = new ASN1EncodableVector(); + + public PKCS12SafeBagBuilder(PrivateKeyInfo privateKeyInfo, OutputEncryptor encryptor) + { + this.bagType = PKCSObjectIdentifiers.pkcs8ShroudedKeyBag; + this.bagValue = new PKCS8EncryptedPrivateKeyInfoBuilder(privateKeyInfo).build(encryptor).toASN1Structure(); + } + + public PKCS12SafeBagBuilder(PrivateKeyInfo privateKeyInfo) + { + this.bagType = PKCSObjectIdentifiers.keyBag; + this.bagValue = privateKeyInfo; + } + + public PKCS12SafeBagBuilder(X509CertificateHolder certificate) + throws IOException + { + this(certificate.toASN1Structure()); + } + + public PKCS12SafeBagBuilder(X509CRLHolder crl) + throws IOException + { + this(crl.toASN1Structure()); + } + + public PKCS12SafeBagBuilder(Certificate certificate) + throws IOException + { + this.bagType = PKCSObjectIdentifiers.certBag; + this.bagValue = new CertBag(PKCSObjectIdentifiers.x509Certificate, new DEROctetString(certificate.getEncoded())); + } + + public PKCS12SafeBagBuilder(CertificateList crl) + throws IOException + { + this.bagType = PKCSObjectIdentifiers.crlBag; + this.bagValue = new CertBag(PKCSObjectIdentifiers.x509Crl, new DEROctetString(crl.getEncoded())); + } + + public PKCS12SafeBagBuilder addBagAttribute(ASN1ObjectIdentifier attrType, ASN1Encodable attrValue) + { + bagAttrs.add(new Attribute(attrType, new DERSet(attrValue))); + + return this; + } + + public PKCS12SafeBag build() + { + return new PKCS12SafeBag(new SafeBag(bagType, bagValue, new DERSet(bagAttrs))); + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/PKCS12SafeBagFactory.java b/pkix/src/main/java/org/spongycastle/pkcs/PKCS12SafeBagFactory.java new file mode 100644 index 00000000..36f53723 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/PKCS12SafeBagFactory.java @@ -0,0 +1,58 @@ +package org.spongycastle.pkcs; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.pkcs.ContentInfo; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.pkcs.SafeBag; +import org.spongycastle.cms.CMSEncryptedData; +import org.spongycastle.cms.CMSException; +import org.spongycastle.operator.InputDecryptorProvider; + +public class PKCS12SafeBagFactory +{ + private ASN1Sequence safeBagSeq; + + public PKCS12SafeBagFactory(ContentInfo info) + { + if (info.getContentType().equals(PKCSObjectIdentifiers.encryptedData)) + { + throw new IllegalArgumentException("encryptedData requires constructor with decryptor."); + } + + this.safeBagSeq = ASN1Sequence.getInstance(ASN1OctetString.getInstance(info.getContent()).getOctets()); + } + + public PKCS12SafeBagFactory(ContentInfo info, InputDecryptorProvider inputDecryptorProvider) + throws PKCSException + { + if (info.getContentType().equals(PKCSObjectIdentifiers.encryptedData)) + { + CMSEncryptedData encData = new CMSEncryptedData(org.spongycastle.asn1.cms.ContentInfo.getInstance(info)); + + try + { + this.safeBagSeq = ASN1Sequence.getInstance(encData.getContent(inputDecryptorProvider)); + } + catch (CMSException e) + { + throw new PKCSException("unable to extract data: " + e.getMessage(), e); + } + return; + } + + throw new IllegalArgumentException("encryptedData requires constructor with decryptor."); + } + + public PKCS12SafeBag[] getSafeBags() + { + PKCS12SafeBag[] safeBags = new PKCS12SafeBag[safeBagSeq.size()]; + + for (int i = 0; i != safeBagSeq.size(); i++) + { + safeBags[i] = new PKCS12SafeBag(SafeBag.getInstance(safeBagSeq.getObjectAt(i))); + } + + return safeBags; + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/PKCS8EncryptedPrivateKeyInfo.java b/pkix/src/main/java/org/spongycastle/pkcs/PKCS8EncryptedPrivateKeyInfo.java new file mode 100644 index 00000000..1f41fb67 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/PKCS8EncryptedPrivateKeyInfo.java @@ -0,0 +1,76 @@ +package org.spongycastle.pkcs; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo; +import org.spongycastle.asn1.pkcs.PrivateKeyInfo; +import org.spongycastle.cert.CertIOException; +import org.spongycastle.operator.InputDecryptor; +import org.spongycastle.operator.InputDecryptorProvider; +import org.spongycastle.util.io.Streams; + +/** + * Holding class for a PKCS#8 EncryptedPrivateKeyInfo structure. + */ +public class PKCS8EncryptedPrivateKeyInfo +{ + private EncryptedPrivateKeyInfo encryptedPrivateKeyInfo; + + private static EncryptedPrivateKeyInfo parseBytes(byte[] pkcs8Encoding) + throws IOException + { + try + { + return EncryptedPrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(pkcs8Encoding)); + } + catch (ClassCastException e) + { + throw new CertIOException("malformed data: " + e.getMessage(), e); + } + catch (IllegalArgumentException e) + { + throw new CertIOException("malformed data: " + e.getMessage(), e); + } + } + + public PKCS8EncryptedPrivateKeyInfo(EncryptedPrivateKeyInfo encryptedPrivateKeyInfo) + { + this.encryptedPrivateKeyInfo = encryptedPrivateKeyInfo; + } + + public PKCS8EncryptedPrivateKeyInfo(byte[] encryptedPrivateKeyInfo) + throws IOException + { + this(parseBytes(encryptedPrivateKeyInfo)); + } + + public EncryptedPrivateKeyInfo toASN1Structure() + { + return encryptedPrivateKeyInfo; + } + + public byte[] getEncoded() + throws IOException + { + return encryptedPrivateKeyInfo.getEncoded(); + } + + public PrivateKeyInfo decryptPrivateKeyInfo(InputDecryptorProvider inputDecryptorProvider) + throws PKCSException + { + try + { + InputDecryptor decrytor = inputDecryptorProvider.get(encryptedPrivateKeyInfo.getEncryptionAlgorithm()); + + ByteArrayInputStream encIn = new ByteArrayInputStream(encryptedPrivateKeyInfo.getEncryptedData()); + + return PrivateKeyInfo.getInstance(Streams.readAll(decrytor.getInputStream(encIn))); + } + catch (Exception e) + { + throw new PKCSException("unable to read encrypted data: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/PKCS8EncryptedPrivateKeyInfoBuilder.java b/pkix/src/main/java/org/spongycastle/pkcs/PKCS8EncryptedPrivateKeyInfoBuilder.java new file mode 100644 index 00000000..3897c40a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/PKCS8EncryptedPrivateKeyInfoBuilder.java @@ -0,0 +1,54 @@ +package org.spongycastle.pkcs; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo; +import org.spongycastle.asn1.pkcs.PrivateKeyInfo; +import org.spongycastle.operator.OutputEncryptor; + +/** + * A class for creating EncryptedPrivateKeyInfo structures. + * <pre> + * EncryptedPrivateKeyInfo ::= SEQUENCE { + * encryptionAlgorithm AlgorithmIdentifier {{KeyEncryptionAlgorithms}}, + * encryptedData EncryptedData + * } + * + * EncryptedData ::= OCTET STRING + * + * KeyEncryptionAlgorithms ALGORITHM-IDENTIFIER ::= { + * ... -- For local profiles + * } + * </pre> + */ +public class PKCS8EncryptedPrivateKeyInfoBuilder +{ + private PrivateKeyInfo privateKeyInfo; + + public PKCS8EncryptedPrivateKeyInfoBuilder(PrivateKeyInfo privateKeyInfo) + { + this.privateKeyInfo = privateKeyInfo; + } + + public PKCS8EncryptedPrivateKeyInfo build( + OutputEncryptor encryptor) + { + try + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OutputStream cOut = encryptor.getOutputStream(bOut); + + cOut.write(privateKeyInfo.getEncoded()); + + cOut.close(); + + return new PKCS8EncryptedPrivateKeyInfo(new EncryptedPrivateKeyInfo(encryptor.getAlgorithmIdentifier(), bOut.toByteArray())); + } + catch (IOException e) + { + throw new IllegalStateException("cannot encode privateKeyInfo"); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/PKCSException.java b/pkix/src/main/java/org/spongycastle/pkcs/PKCSException.java new file mode 100644 index 00000000..201dde93 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/PKCSException.java @@ -0,0 +1,27 @@ +package org.spongycastle.pkcs; + +/** + * General checked Exception thrown in the cert package and its sub-packages. + */ +public class PKCSException + extends Exception +{ + private Throwable cause; + + public PKCSException(String msg, Throwable cause) + { + super(msg); + + this.cause = cause; + } + + public PKCSException(String msg) + { + super(msg); + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/PKCSIOException.java b/pkix/src/main/java/org/spongycastle/pkcs/PKCSIOException.java new file mode 100644 index 00000000..0352829b --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/PKCSIOException.java @@ -0,0 +1,29 @@ +package org.spongycastle.pkcs; + +import java.io.IOException; + +/** + * General IOException thrown in the cert package and its sub-packages. + */ +public class PKCSIOException + extends IOException +{ + private Throwable cause; + + public PKCSIOException(String msg, Throwable cause) + { + super(msg); + + this.cause = cause; + } + + public PKCSIOException(String msg) + { + super(msg); + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS10CertificationRequest.java b/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS10CertificationRequest.java new file mode 100644 index 00000000..6ac22464 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS10CertificationRequest.java @@ -0,0 +1,42 @@ +package org.spongycastle.pkcs.bc; + +import java.io.IOException; + +import org.spongycastle.asn1.pkcs.CertificationRequest; +import org.spongycastle.crypto.params.AsymmetricKeyParameter; +import org.spongycastle.crypto.util.PublicKeyFactory; +import org.spongycastle.pkcs.PKCS10CertificationRequest; +import org.spongycastle.pkcs.PKCSException; + +public class BcPKCS10CertificationRequest + extends PKCS10CertificationRequest +{ + public BcPKCS10CertificationRequest(CertificationRequest certificationRequest) + { + super(certificationRequest); + } + + public BcPKCS10CertificationRequest(byte[] encoding) + throws IOException + { + super(encoding); + } + + public BcPKCS10CertificationRequest(PKCS10CertificationRequest requestHolder) + { + super(requestHolder.toASN1Structure()); + } + + public AsymmetricKeyParameter getPublicKey() + throws PKCSException + { + try + { + return PublicKeyFactory.createKey(this.getSubjectPublicKeyInfo()); + } + catch (IOException e) + { + throw new PKCSException("error extracting key encoding: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS10CertificationRequestBuilder.java b/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS10CertificationRequestBuilder.java new file mode 100644 index 00000000..1590a663 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS10CertificationRequestBuilder.java @@ -0,0 +1,28 @@ +package org.spongycastle.pkcs.bc; + +import java.io.IOException; + +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.crypto.params.AsymmetricKeyParameter; +import org.spongycastle.crypto.util.SubjectPublicKeyInfoFactory; +import org.spongycastle.pkcs.PKCS10CertificationRequestBuilder; + +/** + * Extension of the PKCS#10 builder to support AsymmetricKey objects. + */ +public class BcPKCS10CertificationRequestBuilder + extends PKCS10CertificationRequestBuilder +{ + /** + * Create a PKCS#10 builder for the passed in subject and JCA public key. + * + * @param subject an X500Name containing the subject associated with the request we are building. + * @param publicKey a JCA public key that is to be associated with the request we are building. + * @throws IOException if there is a problem encoding the public key. + */ + public BcPKCS10CertificationRequestBuilder(X500Name subject, AsymmetricKeyParameter publicKey) + throws IOException + { + super(subject, SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKey)); + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12MacCalculatorBuilder.java b/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12MacCalculatorBuilder.java new file mode 100644 index 00000000..456d5b08 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12MacCalculatorBuilder.java @@ -0,0 +1,54 @@ +package org.spongycastle.pkcs.bc; + +import java.security.SecureRandom; + +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCS12PBEParams; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.crypto.ExtendedDigest; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.operator.MacCalculator; +import org.spongycastle.pkcs.PKCS12MacCalculatorBuilder; + +public class BcPKCS12MacCalculatorBuilder + implements PKCS12MacCalculatorBuilder +{ + private ExtendedDigest digest; + private AlgorithmIdentifier algorithmIdentifier; + + private SecureRandom random; + private int saltLength; + private int iterationCount = 1024; + + public BcPKCS12MacCalculatorBuilder() + { + this(new SHA1Digest(), new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE)); + } + + public BcPKCS12MacCalculatorBuilder(ExtendedDigest digest, AlgorithmIdentifier algorithmIdentifier) + { + this.digest = digest; + this.algorithmIdentifier = algorithmIdentifier; + this.saltLength = digest.getDigestSize(); + } + + public AlgorithmIdentifier getDigestAlgorithmIdentifier() + { + return algorithmIdentifier; + } + + public MacCalculator build(final char[] password) + { + if (random == null) + { + random = new SecureRandom(); + } + + byte[] salt = new byte[saltLength]; + + random.nextBytes(salt); + + return PKCS12PBEUtils.createMacCalculator(algorithmIdentifier.getAlgorithm(), digest, new PKCS12PBEParams(salt, iterationCount), password); + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12MacCalculatorBuilderProvider.java b/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12MacCalculatorBuilderProvider.java new file mode 100644 index 00000000..d5533753 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12MacCalculatorBuilderProvider.java @@ -0,0 +1,40 @@ +package org.spongycastle.pkcs.bc; + +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.pkcs.PKCS12PBEParams; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.operator.MacCalculator; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.operator.bc.BcDigestProvider; +import org.spongycastle.pkcs.PKCS12MacCalculatorBuilder; +import org.spongycastle.pkcs.PKCS12MacCalculatorBuilderProvider; + +public class BcPKCS12MacCalculatorBuilderProvider + implements PKCS12MacCalculatorBuilderProvider +{ + private BcDigestProvider digestProvider; + + public BcPKCS12MacCalculatorBuilderProvider(BcDigestProvider digestProvider) + { + this.digestProvider = digestProvider; + } + + public PKCS12MacCalculatorBuilder get(final AlgorithmIdentifier algorithmIdentifier) + { + return new PKCS12MacCalculatorBuilder() + { + public MacCalculator build(final char[] password) + throws OperatorCreationException + { + PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algorithmIdentifier.getParameters()); + + return PKCS12PBEUtils.createMacCalculator(algorithmIdentifier.getAlgorithm(), digestProvider.get(algorithmIdentifier), pbeParams, password); + } + + public AlgorithmIdentifier getDigestAlgorithmIdentifier() + { + return new AlgorithmIdentifier(algorithmIdentifier.getAlgorithm(), DERNull.INSTANCE); + } + }; + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12PBEInputDecryptorProviderBuilder.java b/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12PBEInputDecryptorProviderBuilder.java new file mode 100644 index 00000000..a4618c04 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12PBEInputDecryptorProviderBuilder.java @@ -0,0 +1,66 @@ +package org.spongycastle.pkcs.bc; + +import java.io.InputStream; + +import org.spongycastle.asn1.pkcs.PKCS12PBEParams; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.ExtendedDigest; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.generators.PKCS12ParametersGenerator; +import org.spongycastle.crypto.io.CipherInputStream; +import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.InputDecryptor; +import org.spongycastle.operator.InputDecryptorProvider; + +public class BcPKCS12PBEInputDecryptorProviderBuilder +{ + private ExtendedDigest digest; + + public BcPKCS12PBEInputDecryptorProviderBuilder() + { + this(new SHA1Digest()); + } + + public BcPKCS12PBEInputDecryptorProviderBuilder(ExtendedDigest digest) + { + this.digest = digest; + } + + public InputDecryptorProvider build(final char[] password) + { + return new InputDecryptorProvider() + { + public InputDecryptor get(final AlgorithmIdentifier algorithmIdentifier) + { + final PaddedBufferedBlockCipher engine = PKCS12PBEUtils.getEngine(algorithmIdentifier.getAlgorithm()); + + PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algorithmIdentifier.getParameters()); + + CipherParameters params = PKCS12PBEUtils.createCipherParameters(algorithmIdentifier.getAlgorithm(), digest, engine.getBlockSize(), pbeParams, password); + + engine.init(false, params); + + return new InputDecryptor() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return algorithmIdentifier; + } + + public InputStream getInputStream(InputStream input) + { + return new CipherInputStream(input, engine); + } + + public GenericKey getKey() + { + return new GenericKey(PKCS12ParametersGenerator.PKCS12PasswordToBytes(password)); + } + }; + } + }; + + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12PBEOutputEncryptorBuilder.java b/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12PBEOutputEncryptorBuilder.java new file mode 100644 index 00000000..d8af97c3 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12PBEOutputEncryptorBuilder.java @@ -0,0 +1,77 @@ +package org.spongycastle.pkcs.bc; + +import java.io.OutputStream; +import java.security.SecureRandom; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.pkcs.PKCS12PBEParams; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.BufferedBlockCipher; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.ExtendedDigest; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.generators.PKCS12ParametersGenerator; +import org.spongycastle.crypto.io.CipherOutputStream; +import org.spongycastle.crypto.paddings.PKCS7Padding; +import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.OutputEncryptor; + +public class BcPKCS12PBEOutputEncryptorBuilder +{ + private ExtendedDigest digest; + + private BufferedBlockCipher engine; + private ASN1ObjectIdentifier algorithm; + private SecureRandom random; + + public BcPKCS12PBEOutputEncryptorBuilder(ASN1ObjectIdentifier algorithm, BlockCipher engine) + { + this(algorithm, engine, new SHA1Digest()); + } + + public BcPKCS12PBEOutputEncryptorBuilder(ASN1ObjectIdentifier algorithm, BlockCipher engine, ExtendedDigest pbeDigest) + { + this.algorithm = algorithm; + this.engine = new PaddedBufferedBlockCipher(engine, new PKCS7Padding()); + this.digest = pbeDigest; + } + + public OutputEncryptor build(final char[] password) + { + if (random == null) + { + random = new SecureRandom(); + } + + final byte[] salt = new byte[20]; + final int iterationCount = 1024; + + random.nextBytes(salt); + + final PKCS12PBEParams pbeParams = new PKCS12PBEParams(salt, iterationCount); + + CipherParameters params = PKCS12PBEUtils.createCipherParameters(algorithm, digest, engine.getBlockSize(), pbeParams, password); + + engine.init(true, params); + + return new OutputEncryptor() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return new AlgorithmIdentifier(algorithm, pbeParams); + } + + public OutputStream getOutputStream(OutputStream out) + { + return new CipherOutputStream(out, engine); + } + + public GenericKey getKey() + { + return new GenericKey(new AlgorithmIdentifier(algorithm, pbeParams), PKCS12ParametersGenerator.PKCS12PasswordToBytes(password)); + } + }; + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/bc/PKCS12PBEUtils.java b/pkix/src/main/java/org/spongycastle/pkcs/bc/PKCS12PBEUtils.java new file mode 100644 index 00000000..52f07a54 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/bc/PKCS12PBEUtils.java @@ -0,0 +1,153 @@ +package org.spongycastle.pkcs.bc; + +import java.io.OutputStream; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.pkcs.PKCS12PBEParams; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.ExtendedDigest; +import org.spongycastle.crypto.engines.DESedeEngine; +import org.spongycastle.crypto.engines.RC2Engine; +import org.spongycastle.crypto.generators.PKCS12ParametersGenerator; +import org.spongycastle.crypto.io.MacOutputStream; +import org.spongycastle.crypto.macs.HMac; +import org.spongycastle.crypto.modes.CBCBlockCipher; +import org.spongycastle.crypto.paddings.PKCS7Padding; +import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher; +import org.spongycastle.crypto.params.DESedeParameters; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.MacCalculator; +import org.spongycastle.util.Integers; + +class PKCS12PBEUtils +{ + private static Map keySizes = new HashMap(); + private static Set noIvAlgs = new HashSet(); + private static Set desAlgs = new HashSet(); + + static + { + keySizes.put(PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, Integers.valueOf(128)); + keySizes.put(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4, Integers.valueOf(40)); + keySizes.put(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, Integers.valueOf(192)); + keySizes.put(PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC, Integers.valueOf(128)); + keySizes.put(PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC, Integers.valueOf(128)); + keySizes.put(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC, Integers.valueOf(40)); + + noIvAlgs.add(PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4); + noIvAlgs.add(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4); + + desAlgs.add(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC); + desAlgs.add(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC); + } + + static int getKeySize(ASN1ObjectIdentifier algorithm) + { + return ((Integer)keySizes.get(algorithm)).intValue(); + } + + static boolean hasNoIv(ASN1ObjectIdentifier algorithm) + { + return noIvAlgs.contains(algorithm); + } + + static boolean isDesAlg(ASN1ObjectIdentifier algorithm) + { + return desAlgs.contains(algorithm); + } + + static PaddedBufferedBlockCipher getEngine(ASN1ObjectIdentifier algorithm) + { + BlockCipher engine; + + if (algorithm.equals(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC) + || algorithm.equals(PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC)) + { + engine = new DESedeEngine(); + } + else if (algorithm.equals(PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC) + || algorithm.equals(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC)) + { + engine = new RC2Engine(); + } + else + { + throw new IllegalStateException("unknown algorithm"); + } + + return new PaddedBufferedBlockCipher(new CBCBlockCipher(engine), new PKCS7Padding()); + } + + static MacCalculator createMacCalculator(final ASN1ObjectIdentifier digestAlgorithm, ExtendedDigest digest, final PKCS12PBEParams pbeParams, final char[] password) + { + PKCS12ParametersGenerator pGen = new PKCS12ParametersGenerator(digest); + + pGen.init(PKCS12ParametersGenerator.PKCS12PasswordToBytes(password), pbeParams.getIV(), pbeParams.getIterations().intValue()); + + final KeyParameter keyParam = (KeyParameter)pGen.generateDerivedMacParameters(digest.getDigestSize() * 8); + + final HMac hMac = new HMac(digest); + + hMac.init(keyParam); + + return new MacCalculator() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return new AlgorithmIdentifier(digestAlgorithm, pbeParams); + } + + public OutputStream getOutputStream() + { + return new MacOutputStream(hMac); + } + + public byte[] getMac() + { + byte[] res = new byte[hMac.getMacSize()]; + + hMac.doFinal(res, 0); + + return res; + } + + public GenericKey getKey() + { + return new GenericKey(getAlgorithmIdentifier(), PKCS12ParametersGenerator.PKCS12PasswordToBytes(password)); + } + }; + } + + static CipherParameters createCipherParameters(ASN1ObjectIdentifier algorithm, ExtendedDigest digest, int blockSize, PKCS12PBEParams pbeParams, char[] password) + { + PKCS12ParametersGenerator pGen = new PKCS12ParametersGenerator(digest); + + pGen.init(PKCS12ParametersGenerator.PKCS12PasswordToBytes(password), pbeParams.getIV(), pbeParams.getIterations().intValue()); + + CipherParameters params; + + if (PKCS12PBEUtils.hasNoIv(algorithm)) + { + params = pGen.generateDerivedParameters(PKCS12PBEUtils.getKeySize(algorithm)); + } + else + { + params = pGen.generateDerivedParameters(PKCS12PBEUtils.getKeySize(algorithm), blockSize * 8); + + if (PKCS12PBEUtils.isDesAlg(algorithm)) + { + DESedeParameters.setOddParity(((KeyParameter)((ParametersWithIV)params).getParameters()).getKey()); + } + } + return params; + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS10CertificationRequest.java b/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS10CertificationRequest.java new file mode 100644 index 00000000..8f0e20cf --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS10CertificationRequest.java @@ -0,0 +1,115 @@ +package org.spongycastle.pkcs.jcajce; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; +import java.util.Hashtable; + +import org.spongycastle.asn1.pkcs.CertificationRequest; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.asn1.x9.X9ObjectIdentifiers; +import org.spongycastle.jcajce.util.DefaultJcaJceHelper; +import org.spongycastle.jcajce.util.JcaJceHelper; +import org.spongycastle.jcajce.util.NamedJcaJceHelper; +import org.spongycastle.jcajce.util.ProviderJcaJceHelper; +import org.spongycastle.pkcs.PKCS10CertificationRequest; + +public class JcaPKCS10CertificationRequest + extends PKCS10CertificationRequest +{ + private static Hashtable keyAlgorithms = new Hashtable(); + + static + { + // + // key types + // + keyAlgorithms.put(PKCSObjectIdentifiers.rsaEncryption, "RSA"); + keyAlgorithms.put(X9ObjectIdentifiers.id_dsa, "DSA"); + } + + private JcaJceHelper helper = new DefaultJcaJceHelper(); + + public JcaPKCS10CertificationRequest(CertificationRequest certificationRequest) + { + super(certificationRequest); + } + + public JcaPKCS10CertificationRequest(byte[] encoding) + throws IOException + { + super(encoding); + } + + public JcaPKCS10CertificationRequest(PKCS10CertificationRequest requestHolder) + { + super(requestHolder.toASN1Structure()); + } + + public JcaPKCS10CertificationRequest setProvider(String providerName) + { + helper = new NamedJcaJceHelper(providerName); + + return this; + } + + public JcaPKCS10CertificationRequest setProvider(Provider provider) + { + helper = new ProviderJcaJceHelper(provider); + + return this; + } + + public PublicKey getPublicKey() + throws InvalidKeyException, NoSuchAlgorithmException + { + try + { + SubjectPublicKeyInfo keyInfo = this.getSubjectPublicKeyInfo(); + X509EncodedKeySpec xspec = new X509EncodedKeySpec(keyInfo.getEncoded()); + KeyFactory kFact; + + try + { + kFact = helper.createKeyFactory(keyInfo.getAlgorithm().getAlgorithm().getId()); + } + catch (NoSuchAlgorithmException e) + { + // + // try an alternate + // + if (keyAlgorithms.get(keyInfo.getAlgorithm().getAlgorithm()) != null) + { + String keyAlgorithm = (String)keyAlgorithms.get(keyInfo.getAlgorithm().getAlgorithm()); + + kFact = helper.createKeyFactory(keyAlgorithm); + } + else + { + throw e; + } + } + + return kFact.generatePublic(xspec); + } + catch (InvalidKeySpecException e) + { + throw new InvalidKeyException("error decoding public key"); + } + catch (IOException e) + { + throw new InvalidKeyException("error extracting key encoding"); + } + catch (NoSuchProviderException e) + { + throw new NoSuchAlgorithmException("cannot find provider: " + e.getMessage()); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS10CertificationRequestBuilder.java b/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS10CertificationRequestBuilder.java new file mode 100644 index 00000000..0efa5fa2 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS10CertificationRequestBuilder.java @@ -0,0 +1,38 @@ +package org.spongycastle.pkcs.jcajce; + +import java.security.PublicKey; + +import javax.security.auth.x500.X500Principal; + +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.pkcs.PKCS10CertificationRequestBuilder; + +/** + * Extension of the PKCS#10 builder to support PublicKey and X500Principal objects. + */ +public class JcaPKCS10CertificationRequestBuilder + extends PKCS10CertificationRequestBuilder +{ + /** + * Create a PKCS#10 builder for the passed in subject and JCA public key. + * + * @param subject an X500Name containing the subject associated with the request we are building. + * @param publicKey a JCA public key that is to be associated with the request we are building. + */ + public JcaPKCS10CertificationRequestBuilder(X500Name subject, PublicKey publicKey) + { + super(subject, SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); + } + + /** + * Create a PKCS#10 builder for the passed in subject and JCA public key. + * + * @param subject an X500Principal containing the subject associated with the request we are building. + * @param publicKey a JCA public key that is to be associated with the request we are building. + */ + public JcaPKCS10CertificationRequestBuilder(X500Principal subject, PublicKey publicKey) + { + super(X500Name.getInstance(subject.getEncoded()), SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS12SafeBagBuilder.java b/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS12SafeBagBuilder.java new file mode 100644 index 00000000..f8c06f7c --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS12SafeBagBuilder.java @@ -0,0 +1,45 @@ +package org.spongycastle.pkcs.jcajce; + +import java.io.IOException; +import java.security.PrivateKey; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; + +import org.spongycastle.asn1.pkcs.PrivateKeyInfo; +import org.spongycastle.asn1.x509.Certificate; +import org.spongycastle.operator.OutputEncryptor; +import org.spongycastle.pkcs.PKCS12SafeBagBuilder; +import org.spongycastle.pkcs.PKCSIOException; + +public class JcaPKCS12SafeBagBuilder + extends PKCS12SafeBagBuilder +{ + public JcaPKCS12SafeBagBuilder(X509Certificate certificate) + throws IOException + { + super(convertCert(certificate)); + } + + private static Certificate convertCert(X509Certificate certificate) + throws IOException + { + try + { + return Certificate.getInstance(certificate.getEncoded()); + } + catch (CertificateEncodingException e) + { + throw new PKCSIOException("cannot encode certificate: " + e.getMessage(), e); + } + } + + public JcaPKCS12SafeBagBuilder(PrivateKey privateKey, OutputEncryptor encryptor) + { + super(PrivateKeyInfo.getInstance(privateKey.getEncoded()), encryptor); + } + + public JcaPKCS12SafeBagBuilder(PrivateKey privateKey) + { + super(PrivateKeyInfo.getInstance(privateKey.getEncoded())); + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS8EncryptedPrivateKeyInfoBuilder.java b/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS8EncryptedPrivateKeyInfoBuilder.java new file mode 100644 index 00000000..f8a5856c --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS8EncryptedPrivateKeyInfoBuilder.java @@ -0,0 +1,15 @@ +package org.spongycastle.pkcs.jcajce; + +import java.security.PrivateKey; + +import org.spongycastle.asn1.pkcs.PrivateKeyInfo; +import org.spongycastle.pkcs.PKCS8EncryptedPrivateKeyInfoBuilder; + +public class JcaPKCS8EncryptedPrivateKeyInfoBuilder + extends PKCS8EncryptedPrivateKeyInfoBuilder +{ + public JcaPKCS8EncryptedPrivateKeyInfoBuilder(PrivateKey privateKey) + { + super(PrivateKeyInfo.getInstance(privateKey.getEncoded())); + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCS12MacCalculatorBuilder.java b/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCS12MacCalculatorBuilder.java new file mode 100644 index 00000000..25b8da06 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCS12MacCalculatorBuilder.java @@ -0,0 +1,122 @@ +package org.spongycastle.pkcs.jcajce; + +import java.io.OutputStream; +import java.security.Provider; +import java.security.SecureRandom; + +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.PBEParameterSpec; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCS12PBEParams; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.crypto.ExtendedDigest; +import org.spongycastle.crypto.generators.PKCS12ParametersGenerator; +import org.spongycastle.jcajce.io.MacOutputStream; +import org.spongycastle.jcajce.util.DefaultJcaJceHelper; +import org.spongycastle.jcajce.util.JcaJceHelper; +import org.spongycastle.jcajce.util.NamedJcaJceHelper; +import org.spongycastle.jcajce.util.ProviderJcaJceHelper; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.MacCalculator; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.pkcs.PKCS12MacCalculatorBuilder; + +public class JcePKCS12MacCalculatorBuilder + implements PKCS12MacCalculatorBuilder +{ + private JcaJceHelper helper = new DefaultJcaJceHelper(); + private ExtendedDigest digest; + private ASN1ObjectIdentifier algorithm; + + private SecureRandom random; + private int saltLength; + private int iterationCount = 1024; + + public JcePKCS12MacCalculatorBuilder() + { + this(OIWObjectIdentifiers.idSHA1); + } + + public JcePKCS12MacCalculatorBuilder(ASN1ObjectIdentifier hashAlgorithm) + { + this.algorithm = hashAlgorithm; + } + + public JcePKCS12MacCalculatorBuilder setProvider(Provider provider) + { + this.helper = new ProviderJcaJceHelper(provider); + + return this; + } + + public JcePKCS12MacCalculatorBuilder setProvider(String providerName) + { + this.helper = new NamedJcaJceHelper(providerName); + + return this; + } + + public AlgorithmIdentifier getDigestAlgorithmIdentifier() + { + return new AlgorithmIdentifier(algorithm, DERNull.INSTANCE); + } + + public MacCalculator build(final char[] password) + throws OperatorCreationException + { + if (random == null) + { + random = new SecureRandom(); + } + + try + { + final Mac mac = helper.createMac(algorithm.getId()); + + saltLength = mac.getMacLength(); + final byte[] salt = new byte[saltLength]; + + random.nextBytes(salt); + + SecretKeyFactory keyFact = helper.createSecretKeyFactory(algorithm.getId()); + PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount); + PBEKeySpec pbeSpec = new PBEKeySpec(password); + SecretKey key = keyFact.generateSecret(pbeSpec); + + mac.init(key, defParams); + + return new MacCalculator() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return new AlgorithmIdentifier(algorithm, new PKCS12PBEParams(salt, iterationCount)); + } + + public OutputStream getOutputStream() + { + return new MacOutputStream(mac); + } + + public byte[] getMac() + { + return mac.doFinal(); + } + + public GenericKey getKey() + { + return new GenericKey(getAlgorithmIdentifier(), PKCS12ParametersGenerator.PKCS12PasswordToBytes(password)); + } + }; + } + catch (Exception e) + { + throw new OperatorCreationException("unable to create MAC calculator: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCS12MacCalculatorBuilderProvider.java b/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCS12MacCalculatorBuilderProvider.java new file mode 100644 index 00000000..6c9c3023 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCS12MacCalculatorBuilderProvider.java @@ -0,0 +1,108 @@ +package org.spongycastle.pkcs.jcajce; + +import java.io.OutputStream; +import java.security.Provider; + +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.PBEParameterSpec; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.pkcs.PKCS12PBEParams; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.crypto.generators.PKCS12ParametersGenerator; +import org.spongycastle.jcajce.io.MacOutputStream; +import org.spongycastle.jcajce.util.DefaultJcaJceHelper; +import org.spongycastle.jcajce.util.JcaJceHelper; +import org.spongycastle.jcajce.util.NamedJcaJceHelper; +import org.spongycastle.jcajce.util.ProviderJcaJceHelper; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.MacCalculator; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.pkcs.PKCS12MacCalculatorBuilder; +import org.spongycastle.pkcs.PKCS12MacCalculatorBuilderProvider; + +public class JcePKCS12MacCalculatorBuilderProvider + implements PKCS12MacCalculatorBuilderProvider +{ + private JcaJceHelper helper = new DefaultJcaJceHelper(); + + public JcePKCS12MacCalculatorBuilderProvider() + { + } + + public JcePKCS12MacCalculatorBuilderProvider setProvider(Provider provider) + { + this.helper = new ProviderJcaJceHelper(provider); + + return this; + } + + public JcePKCS12MacCalculatorBuilderProvider setProvider(String providerName) + { + this.helper = new NamedJcaJceHelper(providerName); + + return this; + } + + public PKCS12MacCalculatorBuilder get(final AlgorithmIdentifier algorithmIdentifier) + { + return new PKCS12MacCalculatorBuilder() + { + public MacCalculator build(final char[] password) + throws OperatorCreationException + { + final PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algorithmIdentifier.getParameters()); + + try + { + final ASN1ObjectIdentifier algorithm = algorithmIdentifier.getAlgorithm(); + + final Mac mac = helper.createMac(algorithm.getId()); + + SecretKeyFactory keyFact = helper.createSecretKeyFactory(algorithm.getId()); + PBEParameterSpec defParams = new PBEParameterSpec(pbeParams.getIV(), pbeParams.getIterations().intValue()); + PBEKeySpec pbeSpec = new PBEKeySpec(password); + SecretKey key = keyFact.generateSecret(pbeSpec); + + mac.init(key, defParams); + + return new MacCalculator() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return new AlgorithmIdentifier(algorithm, pbeParams); + } + + public OutputStream getOutputStream() + { + return new MacOutputStream(mac); + } + + public byte[] getMac() + { + return mac.doFinal(); + } + + public GenericKey getKey() + { + return new GenericKey(getAlgorithmIdentifier(), PKCS12ParametersGenerator.PKCS12PasswordToBytes(password)); + } + }; + } + catch (Exception e) + { + throw new OperatorCreationException("unable to create MAC calculator: " + e.getMessage(), e); + } + } + + public AlgorithmIdentifier getDigestAlgorithmIdentifier() + { + return new AlgorithmIdentifier(algorithmIdentifier.getAlgorithm(), DERNull.INSTANCE); + } + }; + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCSPBEInputDecryptorProviderBuilder.java b/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCSPBEInputDecryptorProviderBuilder.java new file mode 100644 index 00000000..5f5413ca --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCSPBEInputDecryptorProviderBuilder.java @@ -0,0 +1,177 @@ +package org.spongycastle.pkcs.jcajce; + +import java.io.InputStream; +import java.security.Provider; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.PBEParameterSpec; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.cryptopro.GOST28147Parameters; +import org.spongycastle.asn1.pkcs.PBES2Parameters; +import org.spongycastle.asn1.pkcs.PBKDF2Params; +import org.spongycastle.asn1.pkcs.PKCS12PBEParams; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.jcajce.provider.symmetric.util.BCPBEKey; +import org.spongycastle.jcajce.spec.GOST28147ParameterSpec; +import org.spongycastle.jcajce.spec.PBKDF2KeySpec; +import org.spongycastle.jcajce.util.DefaultJcaJceHelper; +import org.spongycastle.jcajce.util.JcaJceHelper; +import org.spongycastle.jcajce.util.NamedJcaJceHelper; +import org.spongycastle.jcajce.util.ProviderJcaJceHelper; +import org.spongycastle.operator.DefaultSecretKeySizeProvider; +import org.spongycastle.operator.InputDecryptor; +import org.spongycastle.operator.InputDecryptorProvider; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.operator.SecretKeySizeProvider; + +public class JcePKCSPBEInputDecryptorProviderBuilder +{ + private JcaJceHelper helper = new DefaultJcaJceHelper(); + private boolean wrongPKCS12Zero = false; + private SecretKeySizeProvider keySizeProvider = DefaultSecretKeySizeProvider.INSTANCE; + + public JcePKCSPBEInputDecryptorProviderBuilder() + { + } + + public JcePKCSPBEInputDecryptorProviderBuilder setProvider(Provider provider) + { + this.helper = new ProviderJcaJceHelper(provider); + + return this; + } + + public JcePKCSPBEInputDecryptorProviderBuilder setProvider(String providerName) + { + this.helper = new NamedJcaJceHelper(providerName); + + return this; + } + + public JcePKCSPBEInputDecryptorProviderBuilder setTryWrongPKCS12Zero(boolean tryWrong) + { + this.wrongPKCS12Zero = tryWrong; + + return this; + } + + /** + * Set the lookup provider of AlgorithmIdentifier returning key_size_in_bits used to + * handle PKCS5 decryption. + * + * @param keySizeProvider a provider of integer secret key sizes. + * + * @return the current builder. + */ + public JcePKCSPBEInputDecryptorProviderBuilder setKeySizeProvider(SecretKeySizeProvider keySizeProvider) + { + this.keySizeProvider = keySizeProvider; + + return this; + } + + public InputDecryptorProvider build(final char[] password) + { + return new InputDecryptorProvider() + { + private Cipher cipher; + private SecretKey key; + private AlgorithmIdentifier encryptionAlg; + + public InputDecryptor get(final AlgorithmIdentifier algorithmIdentifier) + throws OperatorCreationException + { + ASN1ObjectIdentifier algorithm = algorithmIdentifier.getAlgorithm(); + + try + { + if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds)) + { + PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algorithmIdentifier.getParameters()); + + PBEKeySpec pbeSpec = new PBEKeySpec(password); + + SecretKeyFactory keyFact = helper.createSecretKeyFactory(algorithm.getId()); + + PBEParameterSpec defParams = new PBEParameterSpec( + pbeParams.getIV(), + pbeParams.getIterations().intValue()); + + key = keyFact.generateSecret(pbeSpec); + + if (key instanceof BCPBEKey) + { + ((BCPBEKey)key).setTryWrongPKCS12Zero(wrongPKCS12Zero); + } + + cipher = helper.createCipher(algorithm.getId()); + + cipher.init(Cipher.DECRYPT_MODE, key, defParams); + + encryptionAlg = algorithmIdentifier; + } + else if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2)) + { + PBES2Parameters alg = PBES2Parameters.getInstance(algorithmIdentifier.getParameters()); + PBKDF2Params func = PBKDF2Params.getInstance(alg.getKeyDerivationFunc().getParameters()); + AlgorithmIdentifier encScheme = AlgorithmIdentifier.getInstance(alg.getEncryptionScheme()); + + SecretKeyFactory keyFact = helper.createSecretKeyFactory(alg.getKeyDerivationFunc().getAlgorithm().getId()); + + if (func.isDefaultPrf()) + { + key = keyFact.generateSecret(new PBEKeySpec(password, func.getSalt(), func.getIterationCount().intValue(), keySizeProvider.getKeySize(encScheme))); + } + else + { + key = keyFact.generateSecret(new PBKDF2KeySpec(password, func.getSalt(), func.getIterationCount().intValue(), keySizeProvider.getKeySize(encScheme), func.getPrf())); + } + + cipher = helper.createCipher(alg.getEncryptionScheme().getAlgorithm().getId()); + + encryptionAlg = AlgorithmIdentifier.getInstance(alg.getEncryptionScheme()); + + ASN1Encodable encParams = alg.getEncryptionScheme().getParameters(); + if (encParams instanceof ASN1OctetString) + { + cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ASN1OctetString.getInstance(encParams).getOctets())); + } + else + { + // TODO: at the moment it's just GOST, but... + GOST28147Parameters gParams = GOST28147Parameters.getInstance(encParams); + + cipher.init(Cipher.DECRYPT_MODE, key, new GOST28147ParameterSpec(gParams.getEncryptionParamSet(), gParams.getIV())); + } + } + } + catch (Exception e) + { + throw new OperatorCreationException("unable to create InputDecryptor: " + e.getMessage(), e); + } + + return new InputDecryptor() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return encryptionAlg; + } + + public InputStream getInputStream(InputStream input) + { + return new CipherInputStream(input, cipher); + } + }; + } + }; + } +} diff --git a/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCSPBEOutputEncryptorBuilder.java b/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCSPBEOutputEncryptorBuilder.java new file mode 100644 index 00000000..9ab806ef --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCSPBEOutputEncryptorBuilder.java @@ -0,0 +1,179 @@ +package org.spongycastle.pkcs.jcajce; + +import java.io.OutputStream; +import java.security.Provider; +import java.security.SecureRandom; + +import javax.crypto.Cipher; +import javax.crypto.CipherOutputStream; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.PBEParameterSpec; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.bc.BCObjectIdentifiers; +import org.spongycastle.asn1.pkcs.EncryptionScheme; +import org.spongycastle.asn1.pkcs.KeyDerivationFunc; +import org.spongycastle.asn1.pkcs.PBES2Parameters; +import org.spongycastle.asn1.pkcs.PBKDF2Params; +import org.spongycastle.asn1.pkcs.PKCS12PBEParams; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.crypto.PBEParametersGenerator; +import org.spongycastle.jcajce.util.DefaultJcaJceHelper; +import org.spongycastle.jcajce.util.JcaJceHelper; +import org.spongycastle.jcajce.util.NamedJcaJceHelper; +import org.spongycastle.jcajce.util.ProviderJcaJceHelper; +import org.spongycastle.operator.DefaultSecretKeySizeProvider; +import org.spongycastle.operator.GenericKey; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.operator.OutputEncryptor; +import org.spongycastle.operator.SecretKeySizeProvider; + +public class JcePKCSPBEOutputEncryptorBuilder +{ + private JcaJceHelper helper = new DefaultJcaJceHelper(); + private ASN1ObjectIdentifier algorithm; + private ASN1ObjectIdentifier keyEncAlgorithm; + private SecureRandom random; + private SecretKeySizeProvider keySizeProvider = DefaultSecretKeySizeProvider.INSTANCE; + + public JcePKCSPBEOutputEncryptorBuilder(ASN1ObjectIdentifier algorithm) + { + if (isPKCS12(algorithm)) + { + this.algorithm = algorithm; + this.keyEncAlgorithm = algorithm; + } + else + { + this.algorithm = PKCSObjectIdentifiers.id_PBES2; + this.keyEncAlgorithm = algorithm; + } + } + + public JcePKCSPBEOutputEncryptorBuilder setProvider(Provider provider) + { + this.helper = new ProviderJcaJceHelper(provider); + + return this; + } + + public JcePKCSPBEOutputEncryptorBuilder setProvider(String providerName) + { + this.helper = new NamedJcaJceHelper(providerName); + + return this; + } + + /** + * Set the lookup provider of AlgorithmIdentifier returning key_size_in_bits used to + * handle PKCS5 decryption. + * + * @param keySizeProvider a provider of integer secret key sizes. + * + * @return the current builder. + */ + public JcePKCSPBEOutputEncryptorBuilder setKeySizeProvider(SecretKeySizeProvider keySizeProvider) + { + this.keySizeProvider = keySizeProvider; + + return this; + } + + public OutputEncryptor build(final char[] password) + throws OperatorCreationException + { + final Cipher cipher; + SecretKey key; + + if (random == null) + { + random = new SecureRandom(); + } + + final AlgorithmIdentifier encryptionAlg; + final byte[] salt = new byte[20]; + final int iterationCount = 1024; + + random.nextBytes(salt); + + try + { + if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds)) + { + PBEKeySpec pbeSpec = new PBEKeySpec(password); + + SecretKeyFactory keyFact = helper.createSecretKeyFactory(algorithm.getId()); + + PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount); + + key = keyFact.generateSecret(pbeSpec); + + cipher = helper.createCipher(algorithm.getId()); + + cipher.init(Cipher.ENCRYPT_MODE, key, defParams); + + encryptionAlg = new AlgorithmIdentifier(algorithm, new PKCS12PBEParams(salt, iterationCount)); + } + else if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2)) + { + SecretKeyFactory keyFact = helper.createSecretKeyFactory(PKCSObjectIdentifiers.id_PBKDF2.getId()); + + key = keyFact.generateSecret(new PBEKeySpec(password, salt, iterationCount, keySizeProvider.getKeySize(new AlgorithmIdentifier(keyEncAlgorithm)))); + + cipher = helper.createCipher(keyEncAlgorithm.getId()); + + cipher.init(Cipher.ENCRYPT_MODE, key, random); + + PBES2Parameters algParams = new PBES2Parameters( + new KeyDerivationFunc(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(salt, iterationCount)), + new EncryptionScheme(keyEncAlgorithm, ASN1Primitive.fromByteArray(cipher.getParameters().getEncoded()))); + + encryptionAlg = new AlgorithmIdentifier(algorithm, algParams); + } + else + { + throw new OperatorCreationException("unrecognised algorithm"); + } + + return new OutputEncryptor() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return encryptionAlg; + } + + public OutputStream getOutputStream(OutputStream out) + { + return new CipherOutputStream(out, cipher); + } + + public GenericKey getKey() + { + if (isPKCS12(encryptionAlg.getAlgorithm())) + { + return new GenericKey(encryptionAlg, PBEParametersGenerator.PKCS5PasswordToBytes(password)); + } + else + { + return new GenericKey(encryptionAlg, PBEParametersGenerator.PKCS12PasswordToBytes(password)); + } + } + }; + } + catch (Exception e) + { + throw new OperatorCreationException("unable to create OutputEncryptor: " + e.getMessage(), e); + } + } + + private boolean isPKCS12(ASN1ObjectIdentifier algorithm) + { + return algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds) + || algorithm.on(BCObjectIdentifiers.bc_pbe_sha1_pkcs12) + || algorithm.on(BCObjectIdentifiers.bc_pbe_sha256_pkcs12); + } +} diff --git a/pkix/src/main/java/org/spongycastle/tsp/GenTimeAccuracy.java b/pkix/src/main/java/org/spongycastle/tsp/GenTimeAccuracy.java new file mode 100644 index 00000000..bb042e90 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/tsp/GenTimeAccuracy.java @@ -0,0 +1,60 @@ +package org.spongycastle.tsp; + +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.tsp.Accuracy; + +public class GenTimeAccuracy +{ + private Accuracy accuracy; + + public GenTimeAccuracy(Accuracy accuracy) + { + this.accuracy = accuracy; + } + + public int getSeconds() + { + return getTimeComponent(accuracy.getSeconds()); + } + + public int getMillis() + { + return getTimeComponent(accuracy.getMillis()); + } + + public int getMicros() + { + return getTimeComponent(accuracy.getMicros()); + } + + private int getTimeComponent( + ASN1Integer time) + { + if (time != null) + { + return time.getValue().intValue(); + } + + return 0; + } + + public String toString() + { // digits + return getSeconds() + "." + format(getMillis()) + format(getMicros()); + } + + private String format(int v) + { + if (v < 10) + { + return "00" + v; + } + + if (v < 100) + { + return "0" + v; + } + + return Integer.toString(v); + } +} diff --git a/pkix/src/main/java/org/spongycastle/tsp/TSPAlgorithms.java b/pkix/src/main/java/org/spongycastle/tsp/TSPAlgorithms.java new file mode 100644 index 00000000..fa5c6f06 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/tsp/TSPAlgorithms.java @@ -0,0 +1,35 @@ +package org.spongycastle.tsp; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; + +/** + * Recognised hash algorithms for the time stamp protocol. + */ +public interface TSPAlgorithms +{ + public static final ASN1ObjectIdentifier MD5 = PKCSObjectIdentifiers.md5; + + public static final ASN1ObjectIdentifier SHA1 = OIWObjectIdentifiers.idSHA1; + + public static final ASN1ObjectIdentifier SHA224 = NISTObjectIdentifiers.id_sha224; + public static final ASN1ObjectIdentifier SHA256 = NISTObjectIdentifiers.id_sha256; + public static final ASN1ObjectIdentifier SHA384 = NISTObjectIdentifiers.id_sha384; + public static final ASN1ObjectIdentifier SHA512 = NISTObjectIdentifiers.id_sha512; + + public static final ASN1ObjectIdentifier RIPEMD128 = TeleTrusTObjectIdentifiers.ripemd128; + public static final ASN1ObjectIdentifier RIPEMD160 = TeleTrusTObjectIdentifiers.ripemd160; + public static final ASN1ObjectIdentifier RIPEMD256 = TeleTrusTObjectIdentifiers.ripemd256; + + public static final ASN1ObjectIdentifier GOST3411 = CryptoProObjectIdentifiers.gostR3411; + + public static final Set ALLOWED = new HashSet(Arrays.asList(new ASN1ObjectIdentifier[] { GOST3411, MD5, SHA1, SHA224, SHA256, SHA384, SHA512, RIPEMD128, RIPEMD160, RIPEMD256 })); +} diff --git a/pkix/src/main/java/org/spongycastle/tsp/TSPException.java b/pkix/src/main/java/org/spongycastle/tsp/TSPException.java new file mode 100644 index 00000000..6125ceff --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/tsp/TSPException.java @@ -0,0 +1,28 @@ +package org.spongycastle.tsp; + +public class TSPException + extends Exception +{ + Throwable underlyingException; + + public TSPException(String message) + { + super(message); + } + + public TSPException(String message, Throwable e) + { + super(message); + underlyingException = e; + } + + public Exception getUnderlyingException() + { + return (Exception)underlyingException; + } + + public Throwable getCause() + { + return underlyingException; + } +} diff --git a/pkix/src/main/java/org/spongycastle/tsp/TSPIOException.java b/pkix/src/main/java/org/spongycastle/tsp/TSPIOException.java new file mode 100644 index 00000000..418ff1b2 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/tsp/TSPIOException.java @@ -0,0 +1,30 @@ +package org.spongycastle.tsp; + +import java.io.IOException; + +public class TSPIOException + extends IOException +{ + Throwable underlyingException; + + public TSPIOException(String message) + { + super(message); + } + + public TSPIOException(String message, Throwable e) + { + super(message); + underlyingException = e; + } + + public Exception getUnderlyingException() + { + return (Exception)underlyingException; + } + + public Throwable getCause() + { + return underlyingException; + } +} diff --git a/pkix/src/main/java/org/spongycastle/tsp/TSPUtil.java b/pkix/src/main/java/org/spongycastle/tsp/TSPUtil.java new file mode 100644 index 00000000..23a0454c --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/tsp/TSPUtil.java @@ -0,0 +1,209 @@ +package org.spongycastle.tsp; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Set; +import org.spongycastle.asn1.cms.Attribute; +import org.spongycastle.asn1.cms.AttributeTable; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import org.spongycastle.asn1.x509.ExtendedKeyUsage; +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.asn1.x509.Extensions; +import org.spongycastle.asn1.x509.ExtensionsGenerator; +import org.spongycastle.asn1.x509.KeyPurposeId; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.cms.SignerInformation; +import org.spongycastle.operator.DigestCalculator; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.Integers; + +public class TSPUtil +{ + private static List EMPTY_LIST = Collections.unmodifiableList(new ArrayList()); + + private static final Map digestLengths = new HashMap(); + private static final Map digestNames = new HashMap(); + + static + { + digestLengths.put(PKCSObjectIdentifiers.md5.getId(), Integers.valueOf(16)); + digestLengths.put(OIWObjectIdentifiers.idSHA1.getId(), Integers.valueOf(20)); + digestLengths.put(NISTObjectIdentifiers.id_sha224.getId(), Integers.valueOf(28)); + digestLengths.put(NISTObjectIdentifiers.id_sha256.getId(), Integers.valueOf(32)); + digestLengths.put(NISTObjectIdentifiers.id_sha384.getId(), Integers.valueOf(48)); + digestLengths.put(NISTObjectIdentifiers.id_sha512.getId(), Integers.valueOf(64)); + digestLengths.put(TeleTrusTObjectIdentifiers.ripemd128.getId(), Integers.valueOf(16)); + digestLengths.put(TeleTrusTObjectIdentifiers.ripemd160.getId(), Integers.valueOf(20)); + digestLengths.put(TeleTrusTObjectIdentifiers.ripemd256.getId(), Integers.valueOf(32)); + digestLengths.put(CryptoProObjectIdentifiers.gostR3411.getId(), Integers.valueOf(32)); + + digestNames.put(PKCSObjectIdentifiers.md5.getId(), "MD5"); + digestNames.put(OIWObjectIdentifiers.idSHA1.getId(), "SHA1"); + digestNames.put(NISTObjectIdentifiers.id_sha224.getId(), "SHA224"); + digestNames.put(NISTObjectIdentifiers.id_sha256.getId(), "SHA256"); + digestNames.put(NISTObjectIdentifiers.id_sha384.getId(), "SHA384"); + digestNames.put(NISTObjectIdentifiers.id_sha512.getId(), "SHA512"); + digestNames.put(PKCSObjectIdentifiers.sha1WithRSAEncryption.getId(), "SHA1"); + digestNames.put(PKCSObjectIdentifiers.sha224WithRSAEncryption.getId(), "SHA224"); + digestNames.put(PKCSObjectIdentifiers.sha256WithRSAEncryption.getId(), "SHA256"); + digestNames.put(PKCSObjectIdentifiers.sha384WithRSAEncryption.getId(), "SHA384"); + digestNames.put(PKCSObjectIdentifiers.sha512WithRSAEncryption.getId(), "SHA512"); + digestNames.put(TeleTrusTObjectIdentifiers.ripemd128.getId(), "RIPEMD128"); + digestNames.put(TeleTrusTObjectIdentifiers.ripemd160.getId(), "RIPEMD160"); + digestNames.put(TeleTrusTObjectIdentifiers.ripemd256.getId(), "RIPEMD256"); + digestNames.put(CryptoProObjectIdentifiers.gostR3411.getId(), "GOST3411"); + } + + /** + * Fetches the signature time-stamp attributes from a SignerInformation object. + * Checks that the MessageImprint for each time-stamp matches the signature field. + * (see RFC 3161 Appendix A). + * + * @param signerInfo a SignerInformation to search for time-stamps + * @param digCalcProvider provider for digest calculators + * @return a collection of TimeStampToken objects + * @throws TSPValidationException + */ + public static Collection getSignatureTimestamps(SignerInformation signerInfo, DigestCalculatorProvider digCalcProvider) + throws TSPValidationException + { + List timestamps = new ArrayList(); + + AttributeTable unsignedAttrs = signerInfo.getUnsignedAttributes(); + if (unsignedAttrs != null) + { + ASN1EncodableVector allTSAttrs = unsignedAttrs.getAll( + PKCSObjectIdentifiers.id_aa_signatureTimeStampToken); + for (int i = 0; i < allTSAttrs.size(); ++i) + { + Attribute tsAttr = (Attribute)allTSAttrs.get(i); + ASN1Set tsAttrValues = tsAttr.getAttrValues(); + for (int j = 0; j < tsAttrValues.size(); ++j) + { + try + { + ContentInfo contentInfo = ContentInfo.getInstance(tsAttrValues.getObjectAt(j)); + TimeStampToken timeStampToken = new TimeStampToken(contentInfo); + TimeStampTokenInfo tstInfo = timeStampToken.getTimeStampInfo(); + + DigestCalculator digCalc = digCalcProvider.get(tstInfo.getHashAlgorithm()); + + OutputStream dOut = digCalc.getOutputStream(); + + dOut.write(signerInfo.getSignature()); + dOut.close(); + + byte[] expectedDigest = digCalc.getDigest(); + + if (!Arrays.constantTimeAreEqual(expectedDigest, tstInfo.getMessageImprintDigest())) + { + throw new TSPValidationException("Incorrect digest in message imprint"); + } + + timestamps.add(timeStampToken); + } + catch (OperatorCreationException e) + { + throw new TSPValidationException("Unknown hash algorithm specified in timestamp"); + } + catch (Exception e) + { + throw new TSPValidationException("Timestamp could not be parsed"); + } + } + } + } + + return timestamps; + } + + /** + * Validate the passed in certificate as being of the correct type to be used + * for time stamping. To be valid it must have an ExtendedKeyUsage extension + * which has a key purpose identifier of id-kp-timeStamping. + * + * @param cert the certificate of interest. + * @throws TSPValidationException if the certificate fails on one of the check points. + */ + public static void validateCertificate( + X509CertificateHolder cert) + throws TSPValidationException + { + if (cert.toASN1Structure().getVersionNumber() != 3) + { + throw new IllegalArgumentException("Certificate must have an ExtendedKeyUsage extension."); + } + + Extension ext = cert.getExtension(Extension.extendedKeyUsage); + if (ext == null) + { + throw new TSPValidationException("Certificate must have an ExtendedKeyUsage extension."); + } + + if (!ext.isCritical()) + { + throw new TSPValidationException("Certificate must have an ExtendedKeyUsage extension marked as critical."); + } + + ExtendedKeyUsage extKey = ExtendedKeyUsage.getInstance(ext.getParsedValue()); + + if (!extKey.hasKeyPurposeId(KeyPurposeId.id_kp_timeStamping) || extKey.size() != 1) + { + throw new TSPValidationException("ExtendedKeyUsage not solely time stamping."); + } + } + + static int getDigestLength( + String digestAlgOID) + throws TSPException + { + Integer length = (Integer)digestLengths.get(digestAlgOID); + + if (length != null) + { + return length.intValue(); + } + + throw new TSPException("digest algorithm cannot be found."); + } + + static List getExtensionOIDs(Extensions extensions) + { + if (extensions == null) + { + return EMPTY_LIST; + } + + return Collections.unmodifiableList(java.util.Arrays.asList(extensions.getExtensionOIDs())); + } + + static void addExtension(ExtensionsGenerator extGenerator, ASN1ObjectIdentifier oid, boolean isCritical, ASN1Encodable value) + throws TSPIOException + { + try + { + extGenerator.addExtension(oid, isCritical, value); + } + catch (IOException e) + { + throw new TSPIOException("cannot encode extension: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/tsp/TSPValidationException.java b/pkix/src/main/java/org/spongycastle/tsp/TSPValidationException.java new file mode 100644 index 00000000..f89ac6c1 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/tsp/TSPValidationException.java @@ -0,0 +1,34 @@ +package org.spongycastle.tsp; + +/** + * Exception thrown if a TSP request or response fails to validate. + * <p> + * If a failure code is associated with the exception it can be retrieved using + * the getFailureCode() method. + */ +public class TSPValidationException + extends TSPException +{ + private int failureCode = -1; + + public TSPValidationException(String message) + { + super(message); + } + + public TSPValidationException(String message, int failureCode) + { + super(message); + this.failureCode = failureCode; + } + + /** + * Return the failure code associated with this exception - if one is set. + * + * @return the failure code if set, -1 otherwise. + */ + public int getFailureCode() + { + return failureCode; + } +} diff --git a/pkix/src/main/java/org/spongycastle/tsp/TimeStampRequest.java b/pkix/src/main/java/org/spongycastle/tsp/TimeStampRequest.java new file mode 100644 index 00000000..54ed40ec --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/tsp/TimeStampRequest.java @@ -0,0 +1,267 @@ +package org.spongycastle.tsp; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.cmp.PKIFailureInfo; +import org.spongycastle.asn1.tsp.TimeStampReq; +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.asn1.x509.Extensions; + +/** + * Base class for an RFC 3161 Time Stamp Request. + */ +public class TimeStampRequest +{ + private static Set EMPTY_SET = Collections.unmodifiableSet(new HashSet()); + + private TimeStampReq req; + private Extensions extensions; + + public TimeStampRequest(TimeStampReq req) + { + this.req = req; + this.extensions = req.getExtensions(); + } + + /** + * Create a TimeStampRequest from the past in byte array. + * + * @param req byte array containing the request. + * @throws IOException if the request is malformed. + */ + public TimeStampRequest(byte[] req) + throws IOException + { + this(new ByteArrayInputStream(req)); + } + + /** + * Create a TimeStampRequest from the past in input stream. + * + * @param in input stream containing the request. + * @throws IOException if the request is malformed. + */ + public TimeStampRequest(InputStream in) + throws IOException + { + this(loadRequest(in)); + } + + private static TimeStampReq loadRequest(InputStream in) + throws IOException + { + try + { + return TimeStampReq.getInstance(new ASN1InputStream(in).readObject()); + } + catch (ClassCastException e) + { + throw new IOException("malformed request: " + e); + } + catch (IllegalArgumentException e) + { + throw new IOException("malformed request: " + e); + } + } + + public int getVersion() + { + return req.getVersion().getValue().intValue(); + } + + public ASN1ObjectIdentifier getMessageImprintAlgOID() + { + return req.getMessageImprint().getHashAlgorithm().getAlgorithm(); + } + + public byte[] getMessageImprintDigest() + { + return req.getMessageImprint().getHashedMessage(); + } + + public ASN1ObjectIdentifier getReqPolicy() + { + if (req.getReqPolicy() != null) + { + return req.getReqPolicy(); + } + else + { + return null; + } + } + + public BigInteger getNonce() + { + if (req.getNonce() != null) + { + return req.getNonce().getValue(); + } + else + { + return null; + } + } + + public boolean getCertReq() + { + if (req.getCertReq() != null) + { + return req.getCertReq().isTrue(); + } + else + { + return false; + } + } + + /** + * Validate the timestamp request, checking the digest to see if it is of an + * accepted type and whether it is of the correct length for the algorithm specified. + * + * @param algorithms a set of OIDs giving accepted algorithms. + * @param policies if non-null a set of policies OIDs we are willing to sign under. + * @param extensions if non-null a set of extensions OIDs we are willing to accept. + * @throws TSPException if the request is invalid, or processing fails. + */ + public void validate( + Set algorithms, + Set policies, + Set extensions) + throws TSPException + { + algorithms = convert(algorithms); + policies = convert(policies); + extensions = convert(extensions); + + if (!algorithms.contains(this.getMessageImprintAlgOID())) + { + throw new TSPValidationException("request contains unknown algorithm.", PKIFailureInfo.badAlg); + } + + if (policies != null && this.getReqPolicy() != null && !policies.contains(this.getReqPolicy())) + { + throw new TSPValidationException("request contains unknown policy.", PKIFailureInfo.unacceptedPolicy); + } + + if (this.getExtensions() != null && extensions != null) + { + Enumeration en = this.getExtensions().oids(); + while(en.hasMoreElements()) + { + String oid = ((ASN1ObjectIdentifier)en.nextElement()).getId(); + if (!extensions.contains(oid)) + { + throw new TSPValidationException("request contains unknown extension.", PKIFailureInfo.unacceptedExtension); + } + } + } + + int digestLength = TSPUtil.getDigestLength(this.getMessageImprintAlgOID().getId()); + + if (digestLength != this.getMessageImprintDigest().length) + { + throw new TSPValidationException("imprint digest the wrong length.", PKIFailureInfo.badDataFormat); + } + } + + /** + * return the ASN.1 encoded representation of this object. + * @return the default ASN,1 byte encoding for the object. + */ + public byte[] getEncoded() throws IOException + { + return req.getEncoded(); + } + + Extensions getExtensions() + { + return extensions; + } + + public boolean hasExtensions() + { + return extensions != null; + } + + public Extension getExtension(ASN1ObjectIdentifier oid) + { + if (extensions != null) + { + return extensions.getExtension(oid); + } + + return null; + } + + public List getExtensionOIDs() + { + return TSPUtil.getExtensionOIDs(extensions); + } + + /** + * Returns a set of ASN1ObjectIdentifiers giving the non-critical extensions. + * @return a set of ASN1ObjectIdentifiers. + */ + public Set getNonCriticalExtensionOIDs() + { + if (extensions == null) + { + return EMPTY_SET; + } + + return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getNonCriticalExtensionOIDs()))); + } + + /** + * Returns a set of ASN1ObjectIdentifiers giving the critical extensions. + * @return a set of ASN1ObjectIdentifiers. + */ + public Set getCriticalExtensionOIDs() + { + if (extensions == null) + { + return EMPTY_SET; + } + + return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getCriticalExtensionOIDs()))); + } + + private Set convert(Set orig) + { + if (orig == null) + { + return orig; + } + + Set con = new HashSet(orig.size()); + + for (Iterator it = orig.iterator(); it.hasNext();) + { + Object o = it.next(); + + if (o instanceof String) + { + con.add(new ASN1ObjectIdentifier((String)o)); + } + else + { + con.add(o); + } + } + + return con; + } +} diff --git a/pkix/src/main/java/org/spongycastle/tsp/TimeStampRequestGenerator.java b/pkix/src/main/java/org/spongycastle/tsp/TimeStampRequestGenerator.java new file mode 100644 index 00000000..382b366a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/tsp/TimeStampRequestGenerator.java @@ -0,0 +1,163 @@ +package org.spongycastle.tsp; + +import java.io.IOException; +import java.math.BigInteger; + +import org.spongycastle.asn1.ASN1Boolean; +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.tsp.MessageImprint; +import org.spongycastle.asn1.tsp.TimeStampReq; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.Extensions; +import org.spongycastle.asn1.x509.ExtensionsGenerator; + +/** + * Generator for RFC 3161 Time Stamp Request objects. + */ +public class TimeStampRequestGenerator +{ + private ASN1ObjectIdentifier reqPolicy; + + private ASN1Boolean certReq; + private ExtensionsGenerator extGenerator = new ExtensionsGenerator(); + + public TimeStampRequestGenerator() + { + } + + /** + * @deprecated use method taking ASN1ObjectIdentifier + * @param reqPolicy + */ + public void setReqPolicy( + String reqPolicy) + { + this.reqPolicy= new ASN1ObjectIdentifier(reqPolicy); + } + + public void setReqPolicy( + ASN1ObjectIdentifier reqPolicy) + { + this.reqPolicy= reqPolicy; + } + + public void setCertReq( + boolean certReq) + { + this.certReq = ASN1Boolean.getInstance(certReq); + } + + /** + * add a given extension field for the standard extensions tag (tag 3) + * @throws IOException + * @deprecated use method taking ASN1ObjectIdentifier + */ + public void addExtension( + String OID, + boolean critical, + ASN1Encodable value) + throws IOException + { + this.addExtension(OID, critical, value.toASN1Primitive().getEncoded()); + } + + /** + * add a given extension field for the standard extensions tag + * The value parameter becomes the contents of the octet string associated + * with the extension. + * @deprecated use method taking ASN1ObjectIdentifier + */ + public void addExtension( + String OID, + boolean critical, + byte[] value) + { + extGenerator.addExtension(new ASN1ObjectIdentifier(OID), critical, value); + } + + /** + * add a given extension field for the standard extensions tag (tag 3) + * @throws TSPIOException + */ + public void addExtension( + ASN1ObjectIdentifier oid, + boolean isCritical, + ASN1Encodable value) + throws TSPIOException + { + TSPUtil.addExtension(extGenerator, oid, isCritical, value); + } + + /** + * add a given extension field for the standard extensions tag + * The value parameter becomes the contents of the octet string associated + * with the extension. + */ + public void addExtension( + ASN1ObjectIdentifier oid, + boolean isCritical, + byte[] value) + { + extGenerator.addExtension(oid, isCritical, value); + } + + /** + * @deprecated use method taking ANS1ObjectIdentifier + */ + public TimeStampRequest generate( + String digestAlgorithm, + byte[] digest) + { + return this.generate(digestAlgorithm, digest, null); + } + + /** + * @deprecated use method taking ANS1ObjectIdentifier + */ + public TimeStampRequest generate( + String digestAlgorithmOID, + byte[] digest, + BigInteger nonce) + { + if (digestAlgorithmOID == null) + { + throw new IllegalArgumentException("No digest algorithm specified"); + } + + ASN1ObjectIdentifier digestAlgOID = new ASN1ObjectIdentifier(digestAlgorithmOID); + + AlgorithmIdentifier algID = new AlgorithmIdentifier(digestAlgOID, DERNull.INSTANCE); + MessageImprint messageImprint = new MessageImprint(algID, digest); + + Extensions ext = null; + + if (!extGenerator.isEmpty()) + { + ext = extGenerator.generate(); + } + + if (nonce != null) + { + return new TimeStampRequest(new TimeStampReq(messageImprint, + reqPolicy, new ASN1Integer(nonce), certReq, ext)); + } + else + { + return new TimeStampRequest(new TimeStampReq(messageImprint, + reqPolicy, null, certReq, ext)); + } + } + + public TimeStampRequest generate(ASN1ObjectIdentifier digestAlgorithm, byte[] digest) + { + return generate(digestAlgorithm.getId(), digest); + } + + public TimeStampRequest generate(ASN1ObjectIdentifier digestAlgorithm, byte[] digest, BigInteger nonce) + { + return generate(digestAlgorithm.getId(), digest, nonce); + } +} diff --git a/pkix/src/main/java/org/spongycastle/tsp/TimeStampResponse.java b/pkix/src/main/java/org/spongycastle/tsp/TimeStampResponse.java new file mode 100644 index 00000000..cc327f45 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/tsp/TimeStampResponse.java @@ -0,0 +1,189 @@ +package org.spongycastle.tsp; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.cmp.PKIFailureInfo; +import org.spongycastle.asn1.cmp.PKIFreeText; +import org.spongycastle.asn1.cmp.PKIStatus; +import org.spongycastle.asn1.cms.Attribute; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.tsp.TimeStampResp; +import org.spongycastle.util.Arrays; + +/** + * Base class for an RFC 3161 Time Stamp Response object. + */ +public class TimeStampResponse +{ + TimeStampResp resp; + TimeStampToken timeStampToken; + + public TimeStampResponse(TimeStampResp resp) + throws TSPException, IOException + { + this.resp = resp; + + if (resp.getTimeStampToken() != null) + { + timeStampToken = new TimeStampToken(resp.getTimeStampToken()); + } + } + + /** + * Create a TimeStampResponse from a byte array containing an ASN.1 encoding. + * + * @param resp the byte array containing the encoded response. + * @throws TSPException if the response is malformed. + * @throws IOException if the byte array doesn't represent an ASN.1 encoding. + */ + public TimeStampResponse(byte[] resp) + throws TSPException, IOException + { + this(new ByteArrayInputStream(resp)); + } + + /** + * Create a TimeStampResponse from an input stream containing an ASN.1 encoding. + * + * @param in the input stream containing the encoded response. + * @throws TSPException if the response is malformed. + * @throws IOException if the stream doesn't represent an ASN.1 encoding. + */ + public TimeStampResponse(InputStream in) + throws TSPException, IOException + { + this(readTimeStampResp(in)); + } + + private static TimeStampResp readTimeStampResp( + InputStream in) + throws IOException, TSPException + { + try + { + return TimeStampResp.getInstance(new ASN1InputStream(in).readObject()); + } + catch (IllegalArgumentException e) + { + throw new TSPException("malformed timestamp response: " + e, e); + } + catch (ClassCastException e) + { + throw new TSPException("malformed timestamp response: " + e, e); + } + } + + public int getStatus() + { + return resp.getStatus().getStatus().intValue(); + } + + public String getStatusString() + { + if (resp.getStatus().getStatusString() != null) + { + StringBuffer statusStringBuf = new StringBuffer(); + PKIFreeText text = resp.getStatus().getStatusString(); + for (int i = 0; i != text.size(); i++) + { + statusStringBuf.append(text.getStringAt(i).getString()); + } + return statusStringBuf.toString(); + } + else + { + return null; + } + } + + public PKIFailureInfo getFailInfo() + { + if (resp.getStatus().getFailInfo() != null) + { + return new PKIFailureInfo(resp.getStatus().getFailInfo()); + } + + return null; + } + + public TimeStampToken getTimeStampToken() + { + return timeStampToken; + } + + /** + * Check this response against to see if it a well formed response for + * the passed in request. Validation will include checking the time stamp + * token if the response status is GRANTED or GRANTED_WITH_MODS. + * + * @param request the request to be checked against + * @throws TSPException if the request can not match this response. + */ + public void validate( + TimeStampRequest request) + throws TSPException + { + TimeStampToken tok = this.getTimeStampToken(); + + if (tok != null) + { + TimeStampTokenInfo tstInfo = tok.getTimeStampInfo(); + + if (request.getNonce() != null && !request.getNonce().equals(tstInfo.getNonce())) + { + throw new TSPValidationException("response contains wrong nonce value."); + } + + if (this.getStatus() != PKIStatus.GRANTED && this.getStatus() != PKIStatus.GRANTED_WITH_MODS) + { + throw new TSPValidationException("time stamp token found in failed request."); + } + + if (!Arrays.constantTimeAreEqual(request.getMessageImprintDigest(), tstInfo.getMessageImprintDigest())) + { + throw new TSPValidationException("response for different message imprint digest."); + } + + if (!tstInfo.getMessageImprintAlgOID().equals(request.getMessageImprintAlgOID())) + { + throw new TSPValidationException("response for different message imprint algorithm."); + } + + Attribute scV1 = tok.getSignedAttributes().get(PKCSObjectIdentifiers.id_aa_signingCertificate); + Attribute scV2 = tok.getSignedAttributes().get(PKCSObjectIdentifiers.id_aa_signingCertificateV2); + + if (scV1 == null && scV2 == null) + { + throw new TSPValidationException("no signing certificate attribute present."); + } + + if (scV1 != null && scV2 != null) + { + /* + * RFC 5035 5.4. If both attributes exist in a single message, + * they are independently evaluated. + */ + } + + if (request.getReqPolicy() != null && !request.getReqPolicy().equals(tstInfo.getPolicy())) + { + throw new TSPValidationException("TSA policy wrong for request."); + } + } + else if (this.getStatus() == PKIStatus.GRANTED || this.getStatus() == PKIStatus.GRANTED_WITH_MODS) + { + throw new TSPValidationException("no time stamp token found and one expected."); + } + } + + /** + * return the ASN.1 encoded representation of this object. + */ + public byte[] getEncoded() throws IOException + { + return resp.getEncoded(); + } +}
\ No newline at end of file diff --git a/pkix/src/main/java/org/spongycastle/tsp/TimeStampResponseGenerator.java b/pkix/src/main/java/org/spongycastle/tsp/TimeStampResponseGenerator.java new file mode 100644 index 00000000..57e83aa2 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/tsp/TimeStampResponseGenerator.java @@ -0,0 +1,353 @@ +package org.spongycastle.tsp; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERBitString; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.DERUTF8String; +import org.spongycastle.asn1.cmp.PKIFailureInfo; +import org.spongycastle.asn1.cmp.PKIFreeText; +import org.spongycastle.asn1.cmp.PKIStatus; +import org.spongycastle.asn1.cmp.PKIStatusInfo; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.tsp.TimeStampResp; + +/** + * Generator for RFC 3161 Time Stamp Responses. + * <p> + * New generate methods have been introduced to give people more control over what ends up in the message. + * Unfortunately it turns out that in some cases fields like statusString must be left out otherwise a an + * otherwise valid timestamp will be rejected. + * </p> + * If you're after the most control with generating a response use: + * <pre> + * TimeStampResponse tsResp; + * + * try + * { + * tsResp = tsRespGen.generateGrantedResponse(request, new BigInteger("23"), new Date()); + * } + * catch (Exception e) + * { + * tsResp = tsRespGen.generateRejectedResponse(e); + * } + * </pre> + * The generate method does this, but provides a status string of "Operation Okay". + * <p> + * It should be pointed out that generateRejectedResponse() may also, on very rare occasions throw a TSPException. + * In the event that happens, there's a serious internal problem with your responder. + * </p> + */ +public class TimeStampResponseGenerator +{ + int status; + + ASN1EncodableVector statusStrings; + + int failInfo; + private TimeStampTokenGenerator tokenGenerator; + private Set acceptedAlgorithms; + private Set acceptedPolicies; + private Set acceptedExtensions; + + /** + * + * @param tokenGenerator + * @param acceptedAlgorithms a set of OIDs giving accepted algorithms. + */ + public TimeStampResponseGenerator( + TimeStampTokenGenerator tokenGenerator, + Set acceptedAlgorithms) + { + this(tokenGenerator, acceptedAlgorithms, null, null); + } + + /** + * + * @param tokenGenerator + * @param acceptedAlgorithms a set of OIDs giving accepted algorithms. + * @param acceptedPolicies if non-null a set of policies OIDs we are willing to sign under. + */ + public TimeStampResponseGenerator( + TimeStampTokenGenerator tokenGenerator, + Set acceptedAlgorithms, + Set acceptedPolicies) + { + this(tokenGenerator, acceptedAlgorithms, acceptedPolicies, null); + } + + /** + * + * @param tokenGenerator + * @param acceptedAlgorithms a set of OIDs giving accepted algorithms. + * @param acceptedPolicies if non-null a set of policies OIDs we are willing to sign under. + * @param acceptedExtensions if non-null a set of extensions OIDs we are willing to accept. + */ + public TimeStampResponseGenerator( + TimeStampTokenGenerator tokenGenerator, + Set acceptedAlgorithms, + Set acceptedPolicies, + Set acceptedExtensions) + { + this.tokenGenerator = tokenGenerator; + this.acceptedAlgorithms = convert(acceptedAlgorithms); + this.acceptedPolicies = convert(acceptedPolicies); + this.acceptedExtensions = convert(acceptedExtensions); + + statusStrings = new ASN1EncodableVector(); + } + + private void addStatusString(String statusString) + { + statusStrings.add(new DERUTF8String(statusString)); + } + + private void setFailInfoField(int field) + { + failInfo = failInfo | field; + } + + private PKIStatusInfo getPKIStatusInfo() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(status)); + + if (statusStrings.size() > 0) + { + v.add(PKIFreeText.getInstance(new DERSequence(statusStrings))); + } + + if (failInfo != 0) + { + DERBitString failInfoBitString = new FailInfo(failInfo); + v.add(failInfoBitString); + } + + return PKIStatusInfo.getInstance(new DERSequence(v)); + } + + /** + * Return an appropriate TimeStampResponse. + * <p> + * If genTime is null a timeNotAvailable error response will be returned. Calling generate() is the + * equivalent of: + * <pre> + * TimeStampResponse tsResp; + * + * try + * { + * tsResp = tsRespGen.generateGrantedResponse(request, serialNumber, genTime, "Operation Okay"); + * } + * catch (Exception e) + * { + * tsResp = tsRespGen.generateRejectedResponse(e); + * } + * </pre> + * @param request the request this response is for. + * @param serialNumber serial number for the response token. + * @param genTime generation time for the response token. + * @return a TimeStampResponse. + * @throws TSPException + */ + public TimeStampResponse generate( + TimeStampRequest request, + BigInteger serialNumber, + Date genTime) + throws TSPException + { + try + { + return this.generateGrantedResponse(request, serialNumber, genTime, "Operation Okay"); + } + catch (Exception e) + { + return this.generateRejectedResponse(e); + } + } + + /** + * Return a granted response, if the passed in request passes validation. + * <p> + * If genTime is null a timeNotAvailable or a validation exception occurs a TSPValidationException will + * be thrown. The parent TSPException will only occur on some sort of system failure. + * </p> + * @param request the request this response is for. + * @param serialNumber serial number for the response token. + * @param genTime generation time for the response token. + * @return the TimeStampResponse with a status of PKIStatus.GRANTED + * @throws TSPException on validation exception or internal error. + */ + public TimeStampResponse generateGrantedResponse( + TimeStampRequest request, + BigInteger serialNumber, + Date genTime) + throws TSPException + { + return generateGrantedResponse(request, serialNumber, genTime, null); + } + + /** + * Return a granted response, if the passed in request passes validation with the passed in status string. + * <p> + * If genTime is null a timeNotAvailable or a validation exception occurs a TSPValidationException will + * be thrown. The parent TSPException will only occur on some sort of system failure. + * </p> + * @param request the request this response is for. + * @param serialNumber serial number for the response token. + * @param genTime generation time for the response token. + * @return the TimeStampResponse with a status of PKIStatus.GRANTED + * @throws TSPException on validation exception or internal error. + */ + public TimeStampResponse generateGrantedResponse( + TimeStampRequest request, + BigInteger serialNumber, + Date genTime, + String statusString) + throws TSPException + { + if (genTime == null) + { + throw new TSPValidationException("The time source is not available.", PKIFailureInfo.timeNotAvailable); + } + + request.validate(acceptedAlgorithms, acceptedPolicies, acceptedExtensions); + + status = PKIStatus.GRANTED; + statusStrings = new ASN1EncodableVector(); + + if (statusString != null) + { + this.addStatusString(statusString); + } + + PKIStatusInfo pkiStatusInfo = getPKIStatusInfo(); + + ContentInfo tstTokenContentInfo; + try + { + tstTokenContentInfo = tokenGenerator.generate(request, serialNumber, genTime).toCMSSignedData().toASN1Structure(); + } + catch (TSPException e) + { + throw e; + } + catch (Exception e) + { + throw new TSPException( + "Timestamp token received cannot be converted to ContentInfo", e); + } + + TimeStampResp resp = new TimeStampResp(pkiStatusInfo, tstTokenContentInfo); + + try + { + return new TimeStampResponse(resp); + } + catch (IOException e) + { + throw new TSPException("created badly formatted response!"); + } + } + + /** + * Generate a generic rejection response based on a TSPValidationException or + * an Exception. Exceptions which are not an instance of TSPValidationException + * will be treated as systemFailure. The return value of exception.getMessage() will + * be used as the status string for the response. + * + * @param exception the exception thrown on validating the request. + * @return a TimeStampResponse. + * @throws TSPException if a failure response cannot be generated. + */ + public TimeStampResponse generateRejectedResponse(Exception exception) + throws TSPException + { + if (exception instanceof TSPValidationException) + { + return generateFailResponse(PKIStatus.REJECTION, ((TSPValidationException)exception).getFailureCode(), exception.getMessage()); + } + else + { + return generateFailResponse(PKIStatus.REJECTION, PKIFailureInfo.systemFailure, exception.getMessage()); + } + } + + /** + * Generate a non-granted TimeStampResponse with chosen status and FailInfoField. + * + * @param status the PKIStatus to set. + * @param failInfoField the FailInfoField to set. + * @param statusString an optional string describing the failure. + * @return a TimeStampResponse with a failInfoField and optional statusString + * @throws TSPException in case the response could not be created + */ + public TimeStampResponse generateFailResponse(int status, int failInfoField, String statusString) + throws TSPException + { + this.status = status; + this.statusStrings = new ASN1EncodableVector(); + + this.setFailInfoField(failInfoField); + + if (statusString != null) + { + this.addStatusString(statusString); + } + + PKIStatusInfo pkiStatusInfo = getPKIStatusInfo(); + + TimeStampResp resp = new TimeStampResp(pkiStatusInfo, null); + + try + { + return new TimeStampResponse(resp); + } + catch (IOException e) + { + throw new TSPException("created badly formatted response!"); + } + } + + private Set convert(Set orig) + { + if (orig == null) + { + return orig; + } + + Set con = new HashSet(orig.size()); + + for (Iterator it = orig.iterator(); it.hasNext();) + { + Object o = it.next(); + + if (o instanceof String) + { + con.add(new ASN1ObjectIdentifier((String)o)); + } + else + { + con.add(o); + } + } + + return con; + } + + class FailInfo extends DERBitString + { + FailInfo(int failInfoValue) + { + super(getBytes(failInfoValue), getPadBits(failInfoValue)); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/tsp/TimeStampToken.java b/pkix/src/main/java/org/spongycastle/tsp/TimeStampToken.java new file mode 100644 index 00000000..00d2a903 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/tsp/TimeStampToken.java @@ -0,0 +1,393 @@ +package org.spongycastle.tsp; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Collection; +import java.util.Date; + +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.cms.Attribute; +import org.spongycastle.asn1.cms.AttributeTable; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.cms.IssuerAndSerialNumber; +import org.spongycastle.asn1.ess.ESSCertID; +import org.spongycastle.asn1.ess.ESSCertIDv2; +import org.spongycastle.asn1.ess.SigningCertificate; +import org.spongycastle.asn1.ess.SigningCertificateV2; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.tsp.TSTInfo; +import org.spongycastle.asn1.x500.X500Name; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.asn1.x509.IssuerSerial; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.CMSProcessable; +import org.spongycastle.cms.CMSSignedData; +import org.spongycastle.cms.SignerId; +import org.spongycastle.cms.SignerInformation; +import org.spongycastle.cms.SignerInformationVerifier; +import org.spongycastle.operator.DigestCalculator; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.Store; + +/** + * Carrier class for a TimeStampToken. + */ +public class TimeStampToken +{ + CMSSignedData tsToken; + + SignerInformation tsaSignerInfo; + + Date genTime; + + TimeStampTokenInfo tstInfo; + + CertID certID; + + public TimeStampToken(ContentInfo contentInfo) + throws TSPException, IOException + { + this(getSignedData(contentInfo)); + } + + private static CMSSignedData getSignedData(ContentInfo contentInfo) + throws TSPException + { + try + { + return new CMSSignedData(contentInfo); + } + catch (CMSException e) + { + throw new TSPException("TSP parsing error: " + e.getMessage(), e.getCause()); + } + } + + public TimeStampToken(CMSSignedData signedData) + throws TSPException, IOException + { + this.tsToken = signedData; + + if (!this.tsToken.getSignedContentTypeOID().equals(PKCSObjectIdentifiers.id_ct_TSTInfo.getId())) + { + throw new TSPValidationException("ContentInfo object not for a time stamp."); + } + + Collection signers = tsToken.getSignerInfos().getSigners(); + + if (signers.size() != 1) + { + throw new IllegalArgumentException("Time-stamp token signed by " + + signers.size() + + " signers, but it must contain just the TSA signature."); + } + + tsaSignerInfo = (SignerInformation)signers.iterator().next(); + + try + { + CMSProcessable content = tsToken.getSignedContent(); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + content.write(bOut); + + ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(bOut.toByteArray())); + + this.tstInfo = new TimeStampTokenInfo(TSTInfo.getInstance(aIn.readObject())); + + Attribute attr = tsaSignerInfo.getSignedAttributes().get(PKCSObjectIdentifiers.id_aa_signingCertificate); + + if (attr != null) + { + SigningCertificate signCert = SigningCertificate.getInstance(attr.getAttrValues().getObjectAt(0)); + + this.certID = new CertID(ESSCertID.getInstance(signCert.getCerts()[0])); + } + else + { + attr = tsaSignerInfo.getSignedAttributes().get(PKCSObjectIdentifiers.id_aa_signingCertificateV2); + + if (attr == null) + { + throw new TSPValidationException("no signing certificate attribute found, time stamp invalid."); + } + + SigningCertificateV2 signCertV2 = SigningCertificateV2.getInstance(attr.getAttrValues().getObjectAt(0)); + + this.certID = new CertID(ESSCertIDv2.getInstance(signCertV2.getCerts()[0])); + } + } + catch (CMSException e) + { + throw new TSPException(e.getMessage(), e.getUnderlyingException()); + } + } + + public TimeStampTokenInfo getTimeStampInfo() + { + return tstInfo; + } + + public SignerId getSID() + { + return tsaSignerInfo.getSID(); + } + + public AttributeTable getSignedAttributes() + { + return tsaSignerInfo.getSignedAttributes(); + } + + public AttributeTable getUnsignedAttributes() + { + return tsaSignerInfo.getUnsignedAttributes(); + } + + public Store getCertificates() + { + return tsToken.getCertificates(); + } + + public Store getCRLs() + { + return tsToken.getCRLs(); + } + + public Store getAttributeCertificates() + { + return tsToken.getAttributeCertificates(); + } + + /** + * Validate the time stamp token. + * <p> + * To be valid the token must be signed by the passed in certificate and + * the certificate must be the one referred to by the SigningCertificate + * attribute included in the hashed attributes of the token. The + * certificate must also have the ExtendedKeyUsageExtension with only + * KeyPurposeId.id_kp_timeStamping and have been valid at the time the + * timestamp was created. + * </p> + * <p> + * A successful call to validate means all the above are true. + * </p> + * + * @param sigVerifier the content verifier create the objects required to verify the CMS object in the timestamp. + * @throws TSPException if an exception occurs in processing the token. + * @throws TSPValidationException if the certificate or signature fail to be valid. + * @throws IllegalArgumentException if the sigVerifierProvider has no associated certificate. + */ + public void validate( + SignerInformationVerifier sigVerifier) + throws TSPException, TSPValidationException + { + if (!sigVerifier.hasAssociatedCertificate()) + { + throw new IllegalArgumentException("verifier provider needs an associated certificate"); + } + + try + { + X509CertificateHolder certHolder = sigVerifier.getAssociatedCertificate(); + DigestCalculator calc = sigVerifier.getDigestCalculator(certID.getHashAlgorithm()); + + OutputStream cOut = calc.getOutputStream(); + + cOut.write(certHolder.getEncoded()); + cOut.close(); + + if (!Arrays.constantTimeAreEqual(certID.getCertHash(), calc.getDigest())) + { + throw new TSPValidationException("certificate hash does not match certID hash."); + } + + if (certID.getIssuerSerial() != null) + { + IssuerAndSerialNumber issuerSerial = new IssuerAndSerialNumber(certHolder.toASN1Structure()); + + if (!certID.getIssuerSerial().getSerial().equals(issuerSerial.getSerialNumber())) + { + throw new TSPValidationException("certificate serial number does not match certID for signature."); + } + + GeneralName[] names = certID.getIssuerSerial().getIssuer().getNames(); + boolean found = false; + + for (int i = 0; i != names.length; i++) + { + if (names[i].getTagNo() == 4 && X500Name.getInstance(names[i].getName()).equals(X500Name.getInstance(issuerSerial.getName()))) + { + found = true; + break; + } + } + + if (!found) + { + throw new TSPValidationException("certificate name does not match certID for signature. "); + } + } + + TSPUtil.validateCertificate(certHolder); + + if (!certHolder.isValidOn(tstInfo.getGenTime())) + { + throw new TSPValidationException("certificate not valid when time stamp created."); + } + + if (!tsaSignerInfo.verify(sigVerifier)) + { + throw new TSPValidationException("signature not created by certificate."); + } + } + catch (CMSException e) + { + if (e.getUnderlyingException() != null) + { + throw new TSPException(e.getMessage(), e.getUnderlyingException()); + } + else + { + throw new TSPException("CMS exception: " + e, e); + } + } + catch (IOException e) + { + throw new TSPException("problem processing certificate: " + e, e); + } + catch (OperatorCreationException e) + { + throw new TSPException("unable to create digest: " + e.getMessage(), e); + } + } + + /** + * Return true if the signature on time stamp token is valid. + * <p> + * Note: this is a much weaker proof of correctness than calling validate(). + * </p> + * + * @param sigVerifier the content verifier create the objects required to verify the CMS object in the timestamp. + * @return true if the signature matches, false otherwise. + * @throws TSPException if the signature cannot be processed or the provider cannot match the algorithm. + */ + public boolean isSignatureValid( + SignerInformationVerifier sigVerifier) + throws TSPException + { + try + { + return tsaSignerInfo.verify(sigVerifier); + } + catch (CMSException e) + { + if (e.getUnderlyingException() != null) + { + throw new TSPException(e.getMessage(), e.getUnderlyingException()); + } + else + { + throw new TSPException("CMS exception: " + e, e); + } + } + } + + /** + * Return the underlying CMSSignedData object. + * + * @return the underlying CMS structure. + */ + public CMSSignedData toCMSSignedData() + { + return tsToken; + } + + /** + * Return a ASN.1 encoded byte stream representing the encoded object. + * + * @throws IOException if encoding fails. + */ + public byte[] getEncoded() + throws IOException + { + return tsToken.getEncoded(); + } + + // perhaps this should be done using an interface on the ASN.1 classes... + private class CertID + { + private ESSCertID certID; + private ESSCertIDv2 certIDv2; + + CertID(ESSCertID certID) + { + this.certID = certID; + this.certIDv2 = null; + } + + CertID(ESSCertIDv2 certID) + { + this.certIDv2 = certID; + this.certID = null; + } + + public String getHashAlgorithmName() + { + if (certID != null) + { + return "SHA-1"; + } + else + { + if (NISTObjectIdentifiers.id_sha256.equals(certIDv2.getHashAlgorithm().getAlgorithm())) + { + return "SHA-256"; + } + return certIDv2.getHashAlgorithm().getAlgorithm().getId(); + } + } + + public AlgorithmIdentifier getHashAlgorithm() + { + if (certID != null) + { + return new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1); + } + else + { + return certIDv2.getHashAlgorithm(); + } + } + + public byte[] getCertHash() + { + if (certID != null) + { + return certID.getCertHash(); + } + else + { + return certIDv2.getCertHash(); + } + } + + public IssuerSerial getIssuerSerial() + { + if (certID != null) + { + return certID.getIssuerSerial(); + } + else + { + return certIDv2.getIssuerSerial(); + } + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/tsp/TimeStampTokenGenerator.java b/pkix/src/main/java/org/spongycastle/tsp/TimeStampTokenGenerator.java new file mode 100644 index 00000000..f3783f80 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/tsp/TimeStampTokenGenerator.java @@ -0,0 +1,380 @@ +package org.spongycastle.tsp; + +import java.io.IOException; +import java.io.OutputStream; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.spongycastle.asn1.ASN1Boolean; +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1GeneralizedTime; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.cms.AttributeTable; +import org.spongycastle.asn1.ess.ESSCertID; +import org.spongycastle.asn1.ess.ESSCertIDv2; +import org.spongycastle.asn1.ess.SigningCertificate; +import org.spongycastle.asn1.ess.SigningCertificateV2; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.tsp.Accuracy; +import org.spongycastle.asn1.tsp.MessageImprint; +import org.spongycastle.asn1.tsp.TSTInfo; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.asn1.x509.GeneralNames; +import org.spongycastle.asn1.x509.IssuerSerial; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.cms.CMSAttributeTableGenerationException; +import org.spongycastle.cms.CMSAttributeTableGenerator; +import org.spongycastle.cms.CMSException; +import org.spongycastle.cms.CMSProcessableByteArray; +import org.spongycastle.cms.CMSSignedData; +import org.spongycastle.cms.CMSSignedDataGenerator; +import org.spongycastle.cms.SignerInfoGenerator; +import org.spongycastle.operator.DigestCalculator; +import org.spongycastle.util.CollectionStore; +import org.spongycastle.util.Store; + +/** + * Currently the class supports ESSCertID by if a digest calculator based on SHA1 is passed in, otherwise it uses + * ESSCertIDv2. In the event you need to pass both types, you will need to override the SignedAttributeGenerator + * for the SignerInfoGeneratorBuilder you are using. For the default for ESSCertIDv2 the code will look something + * like the following: + * <pre> + * final ESSCertID essCertid = new ESSCertID(certHashSha1, issuerSerial); + * final ESSCertIDv2 essCertidV2 = new ESSCertIDv2(certHashSha256, issuerSerial); + * + * signerInfoGenBuilder.setSignedAttributeGenerator(new CMSAttributeTableGenerator() + * { + * public AttributeTable getAttributes(Map parameters) + * throws CMSAttributeTableGenerationException + * { + * CMSAttributeTableGenerator attrGen = new DefaultSignedAttributeTableGenerator(); + * + * AttributeTable table = attrGen.getAttributes(parameters); + * + * table = table.add(PKCSObjectIdentifiers.id_aa_signingCertificate, new SigningCertificate(essCertid)); + * table = table.add(PKCSObjectIdentifiers.id_aa_signingCertificateV2, new SigningCertificateV2(essCertidV2)); + * + * return table; + * } + * }); + * </pre> + */ +public class TimeStampTokenGenerator +{ + int accuracySeconds = -1; + + int accuracyMillis = -1; + + int accuracyMicros = -1; + + boolean ordering = false; + + GeneralName tsa = null; + + private ASN1ObjectIdentifier tsaPolicyOID; + + private List certs = new ArrayList(); + private List crls = new ArrayList(); + private List attrCerts = new ArrayList(); + private Map otherRevoc = new HashMap(); + private SignerInfoGenerator signerInfoGen; + + /** + * Basic Constructor - set up a calculator based on signerInfoGen with a ESSCertID calculated from + * the signer's associated certificate using the sha1DigestCalculator. If alternate values are required + * for id-aa-signingCertificate they should be added to the signerInfoGen object before it is passed in, + * otherwise a standard digest based value will be added. + * + * @param signerInfoGen the generator for the signer we are using. + * @param digestCalculator calculator for to use for digest of certificate. + * @param tsaPolicy tasPolicy to send. + * @throws IllegalArgumentException if calculator is not SHA-1 or there is no associated certificate for the signer, + * @throws TSPException if the signer certificate cannot be processed. + */ + public TimeStampTokenGenerator( + final SignerInfoGenerator signerInfoGen, + DigestCalculator digestCalculator, + ASN1ObjectIdentifier tsaPolicy) + throws IllegalArgumentException, TSPException + { + this(signerInfoGen, digestCalculator, tsaPolicy, false); + } + + /** + * Basic Constructor - set up a calculator based on signerInfoGen with a ESSCertID calculated from + * the signer's associated certificate using the sha1DigestCalculator. If alternate values are required + * for id-aa-signingCertificate they should be added to the signerInfoGen object before it is passed in, + * otherwise a standard digest based value will be added. + * + * @param signerInfoGen the generator for the signer we are using. + * @param digestCalculator calculator for to use for digest of certificate. + * @param tsaPolicy tasPolicy to send. + * @param isIssuerSerialIncluded should issuerSerial be included in the ESSCertIDs, true if yes, by default false. + * @throws IllegalArgumentException if calculator is not SHA-1 or there is no associated certificate for the signer, + * @throws TSPException if the signer certificate cannot be processed. + */ + public TimeStampTokenGenerator( + final SignerInfoGenerator signerInfoGen, + DigestCalculator digestCalculator, + ASN1ObjectIdentifier tsaPolicy, + boolean isIssuerSerialIncluded) + throws IllegalArgumentException, TSPException + { + this.signerInfoGen = signerInfoGen; + this.tsaPolicyOID = tsaPolicy; + + if (!signerInfoGen.hasAssociatedCertificate()) + { + throw new IllegalArgumentException("SignerInfoGenerator must have an associated certificate"); + } + + X509CertificateHolder assocCert = signerInfoGen.getAssociatedCertificate(); + TSPUtil.validateCertificate(assocCert); + + try + { + OutputStream dOut = digestCalculator.getOutputStream(); + + dOut.write(assocCert.getEncoded()); + + dOut.close(); + + if (digestCalculator.getAlgorithmIdentifier().getAlgorithm().equals(OIWObjectIdentifiers.idSHA1)) + { + final ESSCertID essCertid = new ESSCertID(digestCalculator.getDigest(), + isIssuerSerialIncluded ? new IssuerSerial(new GeneralNames(new GeneralName(assocCert.getIssuer())), assocCert.getSerialNumber()) + : null); + + this.signerInfoGen = new SignerInfoGenerator(signerInfoGen, new CMSAttributeTableGenerator() + { + public AttributeTable getAttributes(Map parameters) + throws CMSAttributeTableGenerationException + { + AttributeTable table = signerInfoGen.getSignedAttributeTableGenerator().getAttributes(parameters); + + if (table.get(PKCSObjectIdentifiers.id_aa_signingCertificate) == null) + { + return table.add(PKCSObjectIdentifiers.id_aa_signingCertificate, new SigningCertificate(essCertid)); + } + + return table; + } + }, signerInfoGen.getUnsignedAttributeTableGenerator()); + } + else + { + AlgorithmIdentifier digAlgID = new AlgorithmIdentifier(digestCalculator.getAlgorithmIdentifier().getAlgorithm()); + final ESSCertIDv2 essCertid = new ESSCertIDv2(digAlgID, digestCalculator.getDigest(), + isIssuerSerialIncluded ? new IssuerSerial(new GeneralNames(new GeneralName(assocCert.getIssuer())), new ASN1Integer(assocCert.getSerialNumber())) + : null); + + this.signerInfoGen = new SignerInfoGenerator(signerInfoGen, new CMSAttributeTableGenerator() + { + public AttributeTable getAttributes(Map parameters) + throws CMSAttributeTableGenerationException + { + AttributeTable table = signerInfoGen.getSignedAttributeTableGenerator().getAttributes(parameters); + + if (table.get(PKCSObjectIdentifiers.id_aa_signingCertificateV2) == null) + { + return table.add(PKCSObjectIdentifiers.id_aa_signingCertificateV2, new SigningCertificateV2(essCertid)); + } + + return table; + } + }, signerInfoGen.getUnsignedAttributeTableGenerator()); + } + } + catch (IOException e) + { + throw new TSPException("Exception processing certificate.", e); + } + } + + /** + * Add the store of X509 Certificates to the generator. + * + * @param certStore a Store containing X509CertificateHolder objects + */ + public void addCertificates( + Store certStore) + { + certs.addAll(certStore.getMatches(null)); + } + + /** + * + * @param crlStore a Store containing X509CRLHolder objects. + */ + public void addCRLs( + Store crlStore) + { + crls.addAll(crlStore.getMatches(null)); + } + + /** + * + * @param attrStore a Store containing X509AttributeCertificate objects. + */ + public void addAttributeCertificates( + Store attrStore) + { + attrCerts.addAll(attrStore.getMatches(null)); + } + + /** + * Add a Store of otherRevocationData to the CRL set to be included with the generated TimeStampToken. + * + * @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) + { + otherRevoc.put(otherRevocationInfoFormat, otherRevocationInfos.getMatches(null)); + } + + public void setAccuracySeconds(int accuracySeconds) + { + this.accuracySeconds = accuracySeconds; + } + + public void setAccuracyMillis(int accuracyMillis) + { + this.accuracyMillis = accuracyMillis; + } + + public void setAccuracyMicros(int accuracyMicros) + { + this.accuracyMicros = accuracyMicros; + } + + public void setOrdering(boolean ordering) + { + this.ordering = ordering; + } + + public void setTSA(GeneralName tsa) + { + this.tsa = tsa; + } + + /** + * Generate a TimeStampToken for the passed in request and serialNumber marking it with the passed in genTime. + * + * @param request the originating request. + * @param serialNumber serial number for the TimeStampToken + * @param genTime token generation time. + * @return a TimeStampToken + * @throws TSPException + */ + public TimeStampToken generate( + TimeStampRequest request, + BigInteger serialNumber, + Date genTime) + throws TSPException + { + ASN1ObjectIdentifier digestAlgOID = request.getMessageImprintAlgOID(); + + AlgorithmIdentifier algID = new AlgorithmIdentifier(digestAlgOID, DERNull.INSTANCE); + MessageImprint messageImprint = new MessageImprint(algID, request.getMessageImprintDigest()); + + Accuracy accuracy = null; + if (accuracySeconds > 0 || accuracyMillis > 0 || accuracyMicros > 0) + { + ASN1Integer seconds = null; + if (accuracySeconds > 0) + { + seconds = new ASN1Integer(accuracySeconds); + } + + ASN1Integer millis = null; + if (accuracyMillis > 0) + { + millis = new ASN1Integer(accuracyMillis); + } + + ASN1Integer micros = null; + if (accuracyMicros > 0) + { + micros = new ASN1Integer(accuracyMicros); + } + + accuracy = new Accuracy(seconds, millis, micros); + } + + ASN1Boolean derOrdering = null; + if (ordering) + { + derOrdering = new ASN1Boolean(ordering); + } + + ASN1Integer nonce = null; + if (request.getNonce() != null) + { + nonce = new ASN1Integer(request.getNonce()); + } + + ASN1ObjectIdentifier tsaPolicy = tsaPolicyOID; + if (request.getReqPolicy() != null) + { + tsaPolicy = request.getReqPolicy(); + } + + TSTInfo tstInfo = new TSTInfo(tsaPolicy, + messageImprint, new ASN1Integer(serialNumber), + new ASN1GeneralizedTime(genTime), accuracy, derOrdering, + nonce, tsa, request.getExtensions()); + + try + { + CMSSignedDataGenerator signedDataGenerator = new CMSSignedDataGenerator(); + + if (request.getCertReq()) + { + // TODO: do we need to check certs non-empty? + signedDataGenerator.addCertificates(new CollectionStore(certs)); + signedDataGenerator.addAttributeCertificates(new CollectionStore(attrCerts)); + } + + signedDataGenerator.addCRLs(new CollectionStore(crls)); + + if (!otherRevoc.isEmpty()) + { + for (Iterator it = otherRevoc.keySet().iterator(); it.hasNext();) + { + ASN1ObjectIdentifier format = (ASN1ObjectIdentifier)it.next(); + + signedDataGenerator.addOtherRevocationInfo(format, new CollectionStore((Collection)otherRevoc.get(format))); + } + } + + signedDataGenerator.addSignerInfoGenerator(signerInfoGen); + + byte[] derEncodedTSTInfo = tstInfo.getEncoded(ASN1Encoding.DER); + + CMSSignedData signedData = signedDataGenerator.generate(new CMSProcessableByteArray(PKCSObjectIdentifiers.id_ct_TSTInfo, derEncodedTSTInfo), true); + + return new TimeStampToken(signedData); + } + catch (CMSException cmsEx) + { + throw new TSPException("Error generating time-stamp token", cmsEx); + } + catch (IOException e) + { + throw new TSPException("Exception encoding info", e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/tsp/TimeStampTokenInfo.java b/pkix/src/main/java/org/spongycastle/tsp/TimeStampTokenInfo.java new file mode 100644 index 00000000..e9f70650 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/tsp/TimeStampTokenInfo.java @@ -0,0 +1,121 @@ +package org.spongycastle.tsp; + +import java.io.IOException; +import java.math.BigInteger; +import java.text.ParseException; +import java.util.Date; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.tsp.Accuracy; +import org.spongycastle.asn1.tsp.TSTInfo; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.GeneralName; + +public class TimeStampTokenInfo +{ + TSTInfo tstInfo; + Date genTime; + + TimeStampTokenInfo(TSTInfo tstInfo) + throws TSPException, IOException + { + this.tstInfo = tstInfo; + + try + { + this.genTime = tstInfo.getGenTime().getDate(); + } + catch (ParseException e) + { + throw new TSPException("unable to parse genTime field"); + } + } + + public boolean isOrdered() + { + return tstInfo.getOrdering().isTrue(); + } + + public Accuracy getAccuracy() + { + return tstInfo.getAccuracy(); + } + + public Date getGenTime() + { + return genTime; + } + + public GenTimeAccuracy getGenTimeAccuracy() + { + if (this.getAccuracy() != null) + { + return new GenTimeAccuracy(this.getAccuracy()); + } + + return null; + } + + public ASN1ObjectIdentifier getPolicy() + { + return tstInfo.getPolicy(); + } + + public BigInteger getSerialNumber() + { + return tstInfo.getSerialNumber().getValue(); + } + + public GeneralName getTsa() + { + return tstInfo.getTsa(); + } + + /** + * @return the nonce value, null if there isn't one. + */ + public BigInteger getNonce() + { + if (tstInfo.getNonce() != null) + { + return tstInfo.getNonce().getValue(); + } + + return null; + } + + public AlgorithmIdentifier getHashAlgorithm() + { + return tstInfo.getMessageImprint().getHashAlgorithm(); + } + + public ASN1ObjectIdentifier getMessageImprintAlgOID() + { + return tstInfo.getMessageImprint().getHashAlgorithm().getAlgorithm(); + } + + public byte[] getMessageImprintDigest() + { + return tstInfo.getMessageImprint().getHashedMessage(); + } + + public byte[] getEncoded() + throws IOException + { + return tstInfo.getEncoded(); + } + + /** + * @deprecated use toASN1Structure + * @return + */ + public TSTInfo toTSTInfo() + { + return tstInfo; + } + + public TSTInfo toASN1Structure() + { + return tstInfo; + } +} diff --git a/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedData.java b/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedData.java new file mode 100644 index 00000000..844f123a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedData.java @@ -0,0 +1,204 @@ +package org.spongycastle.tsp.cms; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; + +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.DERIA5String; +import org.spongycastle.asn1.cms.AttributeTable; +import org.spongycastle.asn1.cms.CMSObjectIdentifiers; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.cms.Evidence; +import org.spongycastle.asn1.cms.TimeStampAndCRL; +import org.spongycastle.asn1.cms.TimeStampTokenEvidence; +import org.spongycastle.asn1.cms.TimeStampedData; +import org.spongycastle.cms.CMSException; +import org.spongycastle.operator.DigestCalculator; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.tsp.TimeStampToken; + +public class CMSTimeStampedData +{ + private TimeStampedData timeStampedData; + private ContentInfo contentInfo; + private TimeStampDataUtil util; + + public CMSTimeStampedData(ContentInfo contentInfo) + { + this.initialize(contentInfo); + } + + public CMSTimeStampedData(InputStream in) + throws IOException + { + try + { + initialize(ContentInfo.getInstance(new ASN1InputStream(in).readObject())); + } + catch (ClassCastException e) + { + throw new IOException("Malformed content: " + e); + } + catch (IllegalArgumentException e) + { + throw new IOException("Malformed content: " + e); + } + } + + public CMSTimeStampedData(byte[] baseData) + throws IOException + { + this(new ByteArrayInputStream(baseData)); + } + + private void initialize(ContentInfo contentInfo) + { + this.contentInfo = contentInfo; + + if (CMSObjectIdentifiers.timestampedData.equals(contentInfo.getContentType())) + { + this.timeStampedData = TimeStampedData.getInstance(contentInfo.getContent()); + } + else + { + throw new IllegalArgumentException("Malformed content - type must be " + CMSObjectIdentifiers.timestampedData.getId()); + } + + util = new TimeStampDataUtil(this.timeStampedData); + } + + public byte[] calculateNextHash(DigestCalculator calculator) + throws CMSException + { + return util.calculateNextHash(calculator); + } + + /** + * Return a new timeStampedData object with the additional token attached. + * + * @throws CMSException + */ + public CMSTimeStampedData addTimeStamp(TimeStampToken token) + throws CMSException + { + TimeStampAndCRL[] timeStamps = util.getTimeStamps(); + TimeStampAndCRL[] newTimeStamps = new TimeStampAndCRL[timeStamps.length + 1]; + + System.arraycopy(timeStamps, 0, newTimeStamps, 0, timeStamps.length); + + newTimeStamps[timeStamps.length] = new TimeStampAndCRL(token.toCMSSignedData().toASN1Structure()); + + return new CMSTimeStampedData(new ContentInfo(CMSObjectIdentifiers.timestampedData, new TimeStampedData(timeStampedData.getDataUri(), timeStampedData.getMetaData(), timeStampedData.getContent(), new Evidence(new TimeStampTokenEvidence(newTimeStamps))))); + } + + public byte[] getContent() + { + if (timeStampedData.getContent() != null) + { + return timeStampedData.getContent().getOctets(); + } + + return null; + } + + public URI getDataUri() + throws URISyntaxException + { + DERIA5String dataURI = this.timeStampedData.getDataUri(); + + if (dataURI != null) + { + return new URI(dataURI.getString()); + } + + return null; + } + + public String getFileName() + { + return util.getFileName(); + } + + public String getMediaType() + { + return util.getMediaType(); + } + + public AttributeTable getOtherMetaData() + { + return util.getOtherMetaData(); + } + + public TimeStampToken[] getTimeStampTokens() + throws CMSException + { + return util.getTimeStampTokens(); + } + + /** + * Initialise the passed in calculator with the MetaData for this message, if it is + * required as part of the initial message imprint calculation. + * + * @param calculator the digest calculator to be initialised. + * @throws CMSException if the MetaData is required and cannot be processed + */ + public void initialiseMessageImprintDigestCalculator(DigestCalculator calculator) + throws CMSException + { + util.initialiseMessageImprintDigestCalculator(calculator); + } + + /** + * Returns an appropriately initialised digest calculator based on the message imprint algorithm + * described in the first time stamp in the TemporalData for this message. If the metadata is required + * to be included in the digest calculation, the returned calculator will be pre-initialised. + * + * @param calculatorProvider a provider of DigestCalculator objects. + * @return an initialised digest calculator. + * @throws OperatorCreationException if the provider is unable to create the calculator. + */ + public DigestCalculator getMessageImprintDigestCalculator(DigestCalculatorProvider calculatorProvider) + throws OperatorCreationException + { + return util.getMessageImprintDigestCalculator(calculatorProvider); + } + + /** + * Validate the digests present in the TimeStampTokens contained in the CMSTimeStampedData. + * + * @param calculatorProvider provider for digest calculators + * @param dataDigest the calculated data digest for the message + * @throws ImprintDigestInvalidException if an imprint digest fails to compare + * @throws CMSException if an exception occurs processing the message. + */ + public void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest) + throws ImprintDigestInvalidException, CMSException + { + util.validate(calculatorProvider, dataDigest); + } + + /** + * Validate the passed in timestamp token against the tokens and data present in the message. + * + * @param calculatorProvider provider for digest calculators + * @param dataDigest the calculated data digest for the message. + * @param timeStampToken the timestamp token of interest. + * @throws ImprintDigestInvalidException if the token is not present in the message, or an imprint digest fails to compare. + * @throws CMSException if an exception occurs processing the message. + */ + public void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest, TimeStampToken timeStampToken) + throws ImprintDigestInvalidException, CMSException + { + util.validate(calculatorProvider, dataDigest, timeStampToken); + } + + public byte[] getEncoded() + throws IOException + { + return contentInfo.getEncoded(); + } +} diff --git a/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedDataGenerator.java b/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedDataGenerator.java new file mode 100644 index 00000000..a1ad0c0f --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedDataGenerator.java @@ -0,0 +1,70 @@ +package org.spongycastle.tsp.cms; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.BEROctetString; +import org.spongycastle.asn1.DERIA5String; +import org.spongycastle.asn1.cms.CMSObjectIdentifiers; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.cms.Evidence; +import org.spongycastle.asn1.cms.TimeStampAndCRL; +import org.spongycastle.asn1.cms.TimeStampTokenEvidence; +import org.spongycastle.asn1.cms.TimeStampedData; +import org.spongycastle.cms.CMSException; +import org.spongycastle.tsp.TimeStampToken; +import org.spongycastle.util.io.Streams; + +public class CMSTimeStampedDataGenerator + extends CMSTimeStampedGenerator +{ + public CMSTimeStampedData generate(TimeStampToken timeStamp) throws CMSException + { + return generate(timeStamp, (InputStream)null); + } + + public CMSTimeStampedData generate(TimeStampToken timeStamp, byte[] content) throws CMSException + { + return generate(timeStamp, new ByteArrayInputStream(content)); + } + + public CMSTimeStampedData generate(TimeStampToken timeStamp, InputStream content) + throws CMSException + { + ByteArrayOutputStream contentOut = new ByteArrayOutputStream(); + + if (content != null) + { + try + { + Streams.pipeAll(content, contentOut); + } + catch (IOException e) + { + throw new CMSException("exception encapsulating content: " + e.getMessage(), e); + } + } + + ASN1OctetString encContent = null; + + if (contentOut.size() != 0) + { + encContent = new BEROctetString(contentOut.toByteArray()); + } + + TimeStampAndCRL stamp = new TimeStampAndCRL(timeStamp.toCMSSignedData().toASN1Structure()); + + DERIA5String asn1DataUri = null; + + if (dataUri != null) + { + asn1DataUri = new DERIA5String(dataUri.toString()); + } + + return new CMSTimeStampedData(new ContentInfo(CMSObjectIdentifiers.timestampedData, new TimeStampedData(asn1DataUri, metaData, encContent, new Evidence(new TimeStampTokenEvidence(stamp))))); + } +} + diff --git a/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedDataParser.java b/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedDataParser.java new file mode 100644 index 00000000..c3518b77 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedDataParser.java @@ -0,0 +1,207 @@ +package org.spongycastle.tsp.cms; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; + +import org.spongycastle.asn1.BERTags; +import org.spongycastle.asn1.DERIA5String; +import org.spongycastle.asn1.cms.AttributeTable; +import org.spongycastle.asn1.cms.CMSObjectIdentifiers; +import org.spongycastle.asn1.cms.ContentInfoParser; +import org.spongycastle.asn1.cms.TimeStampedDataParser; +import org.spongycastle.cms.CMSContentInfoParser; +import org.spongycastle.cms.CMSException; +import org.spongycastle.operator.DigestCalculator; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.tsp.TimeStampToken; +import org.spongycastle.util.io.Streams; + +public class CMSTimeStampedDataParser + extends CMSContentInfoParser +{ + private TimeStampedDataParser timeStampedData; + private TimeStampDataUtil util; + + public CMSTimeStampedDataParser(InputStream in) + throws CMSException + { + super(in); + + initialize(_contentInfo); + } + + public CMSTimeStampedDataParser(byte[] baseData) + throws CMSException + { + this(new ByteArrayInputStream(baseData)); + } + + private void initialize(ContentInfoParser contentInfo) + throws CMSException + { + try + { + if (CMSObjectIdentifiers.timestampedData.equals(contentInfo.getContentType())) + { + this.timeStampedData = TimeStampedDataParser.getInstance(contentInfo.getContent(BERTags.SEQUENCE)); + } + else + { + throw new IllegalArgumentException("Malformed content - type must be " + CMSObjectIdentifiers.timestampedData.getId()); + } + } + catch (IOException e) + { + throw new CMSException("parsing exception: " + e.getMessage(), e); + } + } + + public byte[] calculateNextHash(DigestCalculator calculator) + throws CMSException + { + return util.calculateNextHash(calculator); + } + + public InputStream getContent() + { + if (timeStampedData.getContent() != null) + { + return timeStampedData.getContent().getOctetStream(); + } + + return null; + } + + public URI getDataUri() + throws URISyntaxException + { + DERIA5String dataURI = this.timeStampedData.getDataUri(); + + if (dataURI != null) + { + return new URI(dataURI.getString()); + } + + return null; + } + + public String getFileName() + { + return util.getFileName(); + } + + public String getMediaType() + { + return util.getMediaType(); + } + + public AttributeTable getOtherMetaData() + { + return util.getOtherMetaData(); + } + + /** + * Initialise the passed in calculator with the MetaData for this message, if it is + * required as part of the initial message imprint calculation. + * + * @param calculator the digest calculator to be initialised. + * @throws CMSException if the MetaData is required and cannot be processed + */ + public void initialiseMessageImprintDigestCalculator(DigestCalculator calculator) + throws CMSException + { + util.initialiseMessageImprintDigestCalculator(calculator); + } + + /** + * Returns an appropriately initialised digest calculator based on the message imprint algorithm + * described in the first time stamp in the TemporalData for this message. If the metadata is required + * to be included in the digest calculation, the returned calculator will be pre-initialised. + * + * @param calculatorProvider a provider of DigestCalculator objects. + * @return an initialised digest calculator. + * @throws OperatorCreationException if the provider is unable to create the calculator. + */ + public DigestCalculator getMessageImprintDigestCalculator(DigestCalculatorProvider calculatorProvider) + throws OperatorCreationException + { + try + { + parseTimeStamps(); + } + catch (CMSException e) + { + throw new OperatorCreationException("unable to extract algorithm ID: " + e.getMessage(), e); + } + + return util.getMessageImprintDigestCalculator(calculatorProvider); + } + + public TimeStampToken[] getTimeStampTokens() + throws CMSException + { + parseTimeStamps(); + + return util.getTimeStampTokens(); + } + + /** + * Validate the digests present in the TimeStampTokens contained in the CMSTimeStampedData. + * + * @param calculatorProvider provider for digest calculators + * @param dataDigest the calculated data digest for the message + * @throws ImprintDigestInvalidException if an imprint digest fails to compare + * @throws CMSException if an exception occurs processing the message. + */ + public void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest) + throws ImprintDigestInvalidException, CMSException + { + parseTimeStamps(); + + util.validate(calculatorProvider, dataDigest); + } + + /** + * Validate the passed in timestamp token against the tokens and data present in the message. + * + * @param calculatorProvider provider for digest calculators + * @param dataDigest the calculated data digest for the message. + * @param timeStampToken the timestamp token of interest. + * @throws ImprintDigestInvalidException if the token is not present in the message, or an imprint digest fails to compare. + * @throws CMSException if an exception occurs processing the message. + */ + public void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest, TimeStampToken timeStampToken) + throws ImprintDigestInvalidException, CMSException + { + parseTimeStamps(); + + util.validate(calculatorProvider, dataDigest, timeStampToken); + } + + private void parseTimeStamps() + throws CMSException + { + try + { + if (util == null) + { + InputStream cont = this.getContent(); + + if (cont != null) + { + Streams.drain(cont); + } + + util = new TimeStampDataUtil(timeStampedData); + } + } + catch (IOException e) + { + throw new CMSException("unable to parse evidence block: " + e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedGenerator.java b/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedGenerator.java new file mode 100644 index 00000000..9dbeb97f --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedGenerator.java @@ -0,0 +1,88 @@ +package org.spongycastle.tsp.cms; + +import java.net.URI; + +import org.spongycastle.asn1.ASN1Boolean; +import org.spongycastle.asn1.DERIA5String; +import org.spongycastle.asn1.DERUTF8String; +import org.spongycastle.asn1.cms.Attributes; +import org.spongycastle.asn1.cms.MetaData; +import org.spongycastle.cms.CMSException; +import org.spongycastle.operator.DigestCalculator; + +public class CMSTimeStampedGenerator +{ + protected MetaData metaData; + protected URI dataUri; + + /** + * Set the dataURI to be included in message. + * + * @param dataUri URI for the data the initial message imprint digest is based on. + */ + public void setDataUri(URI dataUri) + { + this.dataUri = dataUri; + } + + /** + * Set the MetaData for the generated message. + * + * @param hashProtected true if the MetaData should be included in first imprint calculation, false otherwise. + * @param fileName optional file name, may be null. + * @param mediaType optional media type, may be null. + */ + public void setMetaData(boolean hashProtected, String fileName, String mediaType) + { + setMetaData(hashProtected, fileName, mediaType, null); + } + + /** + * Set the MetaData for the generated message. + * + * @param hashProtected true if the MetaData should be included in first imprint calculation, false otherwise. + * @param fileName optional file name, may be null. + * @param mediaType optional media type, may be null. + * @param attributes optional attributes, may be null. + */ + public void setMetaData(boolean hashProtected, String fileName, String mediaType, Attributes attributes) + { + DERUTF8String asn1FileName = null; + + if (fileName != null) + { + asn1FileName = new DERUTF8String(fileName); + } + + DERIA5String asn1MediaType = null; + + if (mediaType != null) + { + asn1MediaType = new DERIA5String(mediaType); + } + + setMetaData(hashProtected, asn1FileName, asn1MediaType, attributes); + } + + private void setMetaData(boolean hashProtected, DERUTF8String fileName, DERIA5String mediaType, Attributes attributes) + { + this.metaData = new MetaData(ASN1Boolean.getInstance(hashProtected), fileName, mediaType, attributes); + } + + /** + * Initialise the passed in calculator with the MetaData for this message, if it is + * required as part of the initial message imprint calculation. After initialisation the + * calculator can then be used to calculate the initial message imprint digest for the first + * timestamp. + * + * @param calculator the digest calculator to be initialised. + * @throws CMSException if the MetaData is required and cannot be processed + */ + public void initialiseMessageImprintDigestCalculator(DigestCalculator calculator) + throws CMSException + { + MetaDataUtil util = new MetaDataUtil(metaData); + + util.initialiseMessageImprintDigestCalculator(calculator); + } +} diff --git a/pkix/src/main/java/org/spongycastle/tsp/cms/ImprintDigestInvalidException.java b/pkix/src/main/java/org/spongycastle/tsp/cms/ImprintDigestInvalidException.java new file mode 100644 index 00000000..1dfc2bb3 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/tsp/cms/ImprintDigestInvalidException.java @@ -0,0 +1,21 @@ +package org.spongycastle.tsp.cms; + +import org.spongycastle.tsp.TimeStampToken; + +public class ImprintDigestInvalidException + extends Exception +{ + private TimeStampToken token; + + public ImprintDigestInvalidException(String message, TimeStampToken token) + { + super(message); + + this.token = token; + } + + public TimeStampToken getTimeStampToken() + { + return token; + } +} diff --git a/pkix/src/main/java/org/spongycastle/tsp/cms/MetaDataUtil.java b/pkix/src/main/java/org/spongycastle/tsp/cms/MetaDataUtil.java new file mode 100644 index 00000000..f4ad579a --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/tsp/cms/MetaDataUtil.java @@ -0,0 +1,76 @@ +package org.spongycastle.tsp.cms; + +import java.io.IOException; + +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1String; +import org.spongycastle.asn1.cms.Attributes; +import org.spongycastle.asn1.cms.MetaData; +import org.spongycastle.cms.CMSException; +import org.spongycastle.operator.DigestCalculator; + +class MetaDataUtil +{ + private final MetaData metaData; + + MetaDataUtil(MetaData metaData) + { + this.metaData = metaData; + } + + void initialiseMessageImprintDigestCalculator(DigestCalculator calculator) + throws CMSException + { + if (metaData != null && metaData.isHashProtected()) + { + try + { + calculator.getOutputStream().write(metaData.getEncoded(ASN1Encoding.DER)); + } + catch (IOException e) + { + throw new CMSException("unable to initialise calculator from metaData: " + e.getMessage(), e); + } + } + } + + String getFileName() + { + if (metaData != null) + { + return convertString(metaData.getFileName()); + } + + return null; + } + + String getMediaType() + { + if (metaData != null) + { + return convertString(metaData.getMediaType()); + } + + return null; + } + + Attributes getOtherMetaData() + { + if (metaData != null) + { + return metaData.getOtherMetaData(); + } + + return null; + } + + private String convertString(ASN1String s) + { + if (s != null) + { + return s.toString(); + } + + return null; + } +} diff --git a/pkix/src/main/java/org/spongycastle/tsp/cms/TimeStampDataUtil.java b/pkix/src/main/java/org/spongycastle/tsp/cms/TimeStampDataUtil.java new file mode 100644 index 00000000..fd1bcc8d --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/tsp/cms/TimeStampDataUtil.java @@ -0,0 +1,256 @@ +package org.spongycastle.tsp.cms; + +import java.io.IOException; +import java.io.OutputStream; + +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.cms.AttributeTable; +import org.spongycastle.asn1.cms.ContentInfo; +import org.spongycastle.asn1.cms.Evidence; +import org.spongycastle.asn1.cms.TimeStampAndCRL; +import org.spongycastle.asn1.cms.TimeStampedData; +import org.spongycastle.asn1.cms.TimeStampedDataParser; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.cms.CMSException; +import org.spongycastle.operator.DigestCalculator; +import org.spongycastle.operator.DigestCalculatorProvider; +import org.spongycastle.operator.OperatorCreationException; +import org.spongycastle.tsp.TSPException; +import org.spongycastle.tsp.TimeStampToken; +import org.spongycastle.tsp.TimeStampTokenInfo; +import org.spongycastle.util.Arrays; + +class TimeStampDataUtil +{ + private final TimeStampAndCRL[] timeStamps; + + private final MetaDataUtil metaDataUtil; + + TimeStampDataUtil(TimeStampedData timeStampedData) + { + this.metaDataUtil = new MetaDataUtil(timeStampedData.getMetaData()); + + Evidence evidence = timeStampedData.getTemporalEvidence(); + this.timeStamps = evidence.getTstEvidence().toTimeStampAndCRLArray(); + } + + TimeStampDataUtil(TimeStampedDataParser timeStampedData) + throws IOException + { + this.metaDataUtil = new MetaDataUtil(timeStampedData.getMetaData()); + + Evidence evidence = timeStampedData.getTemporalEvidence(); + this.timeStamps = evidence.getTstEvidence().toTimeStampAndCRLArray(); + } + + TimeStampToken getTimeStampToken(TimeStampAndCRL timeStampAndCRL) + throws CMSException + { + ContentInfo timeStampToken = timeStampAndCRL.getTimeStampToken(); + + try + { + TimeStampToken token = new TimeStampToken(timeStampToken); + return token; + } + catch (IOException e) + { + throw new CMSException("unable to parse token data: " + e.getMessage(), e); + } + catch (TSPException e) + { + if (e.getCause() instanceof CMSException) + { + throw (CMSException)e.getCause(); + } + + throw new CMSException("token data invalid: " + e.getMessage(), e); + } + catch (IllegalArgumentException e) + { + throw new CMSException("token data invalid: " + e.getMessage(), e); + } + } + + void initialiseMessageImprintDigestCalculator(DigestCalculator calculator) + throws CMSException + { + metaDataUtil.initialiseMessageImprintDigestCalculator(calculator); + } + + DigestCalculator getMessageImprintDigestCalculator(DigestCalculatorProvider calculatorProvider) + throws OperatorCreationException + { + TimeStampToken token; + + try + { + token = this.getTimeStampToken(timeStamps[0]); + + TimeStampTokenInfo info = token.getTimeStampInfo(); + ASN1ObjectIdentifier algOID = info.getMessageImprintAlgOID(); + + DigestCalculator calc = calculatorProvider.get(new AlgorithmIdentifier(algOID)); + + initialiseMessageImprintDigestCalculator(calc); + + return calc; + } + catch (CMSException e) + { + throw new OperatorCreationException("unable to extract algorithm ID: " + e.getMessage(), e); + } + } + + TimeStampToken[] getTimeStampTokens() + throws CMSException + { + TimeStampToken[] tokens = new TimeStampToken[timeStamps.length]; + for (int i = 0; i < timeStamps.length; i++) + { + tokens[i] = this.getTimeStampToken(timeStamps[i]); + } + + return tokens; + } + + TimeStampAndCRL[] getTimeStamps() + { + return timeStamps; + } + + byte[] calculateNextHash(DigestCalculator calculator) + throws CMSException + { + TimeStampAndCRL tspToken = timeStamps[timeStamps.length - 1]; + + OutputStream out = calculator.getOutputStream(); + + try + { + out.write(tspToken.getEncoded(ASN1Encoding.DER)); + + out.close(); + + return calculator.getDigest(); + } + catch (IOException e) + { + throw new CMSException("exception calculating hash: " + e.getMessage(), e); + } + } + + /** + * Validate the digests present in the TimeStampTokens contained in the CMSTimeStampedData. + */ + void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest) + throws ImprintDigestInvalidException, CMSException + { + byte[] currentDigest = dataDigest; + + for (int i = 0; i < timeStamps.length; i++) + { + try + { + TimeStampToken token = this.getTimeStampToken(timeStamps[i]); + if (i > 0) + { + TimeStampTokenInfo info = token.getTimeStampInfo(); + DigestCalculator calculator = calculatorProvider.get(info.getHashAlgorithm()); + + calculator.getOutputStream().write(timeStamps[i - 1].getEncoded(ASN1Encoding.DER)); + + currentDigest = calculator.getDigest(); + } + + this.compareDigest(token, currentDigest); + } + catch (IOException e) + { + throw new CMSException("exception calculating hash: " + e.getMessage(), e); + } + catch (OperatorCreationException e) + { + throw new CMSException("cannot create digest: " + e.getMessage(), e); + } + } + } + + void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest, TimeStampToken timeStampToken) + throws ImprintDigestInvalidException, CMSException + { + byte[] currentDigest = dataDigest; + byte[] encToken; + + try + { + encToken = timeStampToken.getEncoded(); + } + catch (IOException e) + { + throw new CMSException("exception encoding timeStampToken: " + e.getMessage(), e); + } + + for (int i = 0; i < timeStamps.length; i++) + { + try + { + TimeStampToken token = this.getTimeStampToken(timeStamps[i]); + if (i > 0) + { + TimeStampTokenInfo info = token.getTimeStampInfo(); + DigestCalculator calculator = calculatorProvider.get(info.getHashAlgorithm()); + + calculator.getOutputStream().write(timeStamps[i - 1].getEncoded(ASN1Encoding.DER)); + + currentDigest = calculator.getDigest(); + } + + this.compareDigest(token, currentDigest); + + if (Arrays.areEqual(token.getEncoded(), encToken)) + { + return; + } + } + catch (IOException e) + { + throw new CMSException("exception calculating hash: " + e.getMessage(), e); + } + catch (OperatorCreationException e) + { + throw new CMSException("cannot create digest: " + e.getMessage(), e); + } + } + + throw new ImprintDigestInvalidException("passed in token not associated with timestamps present", timeStampToken); + } + + private void compareDigest(TimeStampToken timeStampToken, byte[] digest) + throws ImprintDigestInvalidException + { + TimeStampTokenInfo info = timeStampToken.getTimeStampInfo(); + byte[] tsrMessageDigest = info.getMessageImprintDigest(); + + if (!Arrays.areEqual(digest, tsrMessageDigest)) + { + throw new ImprintDigestInvalidException("hash calculated is different from MessageImprintDigest found in TimeStampToken", timeStampToken); + } + } + + String getFileName() + { + return metaDataUtil.getFileName(); + } + + String getMediaType() + { + return metaDataUtil.getMediaType(); + } + + AttributeTable getOtherMetaData() + { + return new AttributeTable(metaDataUtil.getOtherMetaData()); + } +} diff --git a/pkix/src/main/java/org/spongycastle/voms/VOMSAttribute.java b/pkix/src/main/java/org/spongycastle/voms/VOMSAttribute.java new file mode 100644 index 00000000..4e7aac73 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/voms/VOMSAttribute.java @@ -0,0 +1,242 @@ +package org.spongycastle.voms; + +import java.util.List; +import java.util.ArrayList; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.DERIA5String; +import org.spongycastle.asn1.x509.IetfAttrSyntax; +import org.spongycastle.x509.X509Attribute; +import org.spongycastle.x509.X509AttributeCertificate; + + +/** + * Representation of the authorization information (VO, server address + * and list of Fully Qualified Attribute Names, or FQANs) contained in + * a VOMS attribute certificate. + */ +public class VOMSAttribute +{ + + /** + * The ASN.1 object identifier for VOMS attributes + */ + public static final String VOMS_ATTR_OID = "1.3.6.1.4.1.8005.100.100.4"; + private X509AttributeCertificate myAC; + private String myHostPort; + private String myVo; + private List myStringList = new ArrayList(); + private List myFQANs = new ArrayList(); + + /** + * Parses the contents of an attribute certificate.<br> + * <b>NOTE:</b> Cryptographic signatures, time stamps etc. will <b>not</b> be checked. + * + * @param ac the attribute certificate to parse for VOMS attributes + */ + public VOMSAttribute(X509AttributeCertificate ac) + { + if (ac == null) + { + throw new IllegalArgumentException("VOMSAttribute: AttributeCertificate is NULL"); + } + + myAC = ac; + + X509Attribute[] l = ac.getAttributes(VOMS_ATTR_OID); + + if (l == null) + { + return; + } + + try + { + for (int i = 0; i != l.length; i++) + { + IetfAttrSyntax attr = IetfAttrSyntax.getInstance(l[i].getValues()[0]); + + // policyAuthority is on the format <vo>/<host>:<port> + String url = ((DERIA5String)attr.getPolicyAuthority().getNames()[0].getName()).getString(); + int idx = url.indexOf("://"); + + if ((idx < 0) || (idx == (url.length() - 1))) + { + throw new IllegalArgumentException("Bad encoding of VOMS policyAuthority : [" + url + "]"); + } + + myVo = url.substring(0, idx); + myHostPort = url.substring(idx + 3); + + if (attr.getValueType() != IetfAttrSyntax.VALUE_OCTETS) + { + throw new IllegalArgumentException( + "VOMS attribute values are not encoded as octet strings, policyAuthority = " + url); + } + + ASN1OctetString[] values = (ASN1OctetString[])attr.getValues(); + for (int j = 0; j != values.length; j++) + { + String fqan = new String(values[j].getOctets()); + FQAN f = new FQAN(fqan); + + if (!myStringList.contains(fqan) && fqan.startsWith("/" + myVo + "/")) + { + myStringList.add(fqan); + myFQANs.add(f); + } + } + } + } + catch (IllegalArgumentException ie) + { + throw ie; + } + catch (Exception e) + { + throw new IllegalArgumentException("Badly encoded VOMS extension in AC issued by " + + ac.getIssuer()); + } + } + + /** + * @return The AttributeCertificate containing the VOMS information + */ + public X509AttributeCertificate getAC() + { + return myAC; + } + + /** + * @return List of String of the VOMS fully qualified + * attributes names (FQANs):<br> + * <code>/vo[/group[/group2...]][/Role=[role]][/Capability=capability]</code> + */ + public List getFullyQualifiedAttributes() + { + return myStringList; + } + + /** + * @return List of FQAN of the VOMS fully qualified + * attributes names (FQANs) + */ + public List getListOfFQAN() + { + return myFQANs; + } + + /** + * Returns the address of the issuing VOMS server, on the form <code><host>:<port></code> + * @return String + */ + public String getHostPort() + { + return myHostPort; + } + + /** + * Returns the VO name + * @return + */ + public String getVO() + { + return myVo; + } + + public String toString() + { + return "VO :" + myVo + "\n" + "HostPort:" + myHostPort + "\n" + "FQANs :" + myFQANs; + } + + /** + * Inner class providing a container of the group,role,capability + * information triplet in an FQAN. + */ + public class FQAN + { + String fqan; + String group; + String role; + String capability; + + public FQAN(String fqan) + { + this.fqan = fqan; + } + + public FQAN(String group, String role, String capability) + { + this.group = group; + this.role = role; + this.capability = capability; + } + + public String getFQAN() + { + if (fqan != null) + { + return fqan; + } + + fqan = group + "/Role=" + ((role != null) ? role : "") + + ((capability != null) ? ("/Capability=" + capability) : ""); + + return fqan; + } + + protected void split() + { + int len = fqan.length(); + int i = fqan.indexOf("/Role="); + + if (i < 0) + { + return; + } + + group = fqan.substring(0, i); + + int j = fqan.indexOf("/Capability=", i + 6); + String s = (j < 0) ? fqan.substring(i + 6) : fqan.substring(i + 6, j); + role = (s.length() == 0) ? null : s; + s = (j < 0) ? null : fqan.substring(j + 12); + capability = ((s == null) || (s.length() == 0)) ? null : s; + } + + public String getGroup() + { + if ((group == null) && (fqan != null)) + { + split(); + } + + return group; + } + + public String getRole() + { + if ((group == null) && (fqan != null)) + { + split(); + } + + return role; + } + + public String getCapability() + { + if ((group == null) && (fqan != null)) + { + split(); + } + + return capability; + } + + public String toString() + { + return getFQAN(); + } + } +} |