diff options
Diffstat (limited to 'prov/src/main/jdk1.1/org/spongycastle/x509')
10 files changed, 3110 insertions, 0 deletions
diff --git a/prov/src/main/jdk1.1/org/spongycastle/x509/AttributeCertificateHolder.java b/prov/src/main/jdk1.1/org/spongycastle/x509/AttributeCertificateHolder.java new file mode 100644 index 00000000..644883d4 --- /dev/null +++ b/prov/src/main/jdk1.1/org/spongycastle/x509/AttributeCertificateHolder.java @@ -0,0 +1,406 @@ +package org.spongycastle.x509; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.Principal; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +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.jce.PrincipalUtil; +import org.spongycastle.jce.X509Principal; +import java.security.cert.CertSelector; +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> + * @deprecated use org.spongycastle.cert.AttributeCertificateHolder + */ +public class AttributeCertificateHolder + implements CertSelector, Selector +{ + final Holder holder; + + AttributeCertificateHolder(ASN1Sequence seq) + { + holder = Holder.getInstance(seq); + } + + public AttributeCertificateHolder(X509Principal issuerName, + BigInteger serialNumber) + { + holder = new org.spongycastle.asn1.x509.Holder(new IssuerSerial( + new GeneralNames(new GeneralName(issuerName)), + new ASN1Integer(serialNumber))); + } + + public AttributeCertificateHolder(X509Certificate cert) + throws CertificateParsingException + { + X509Principal name; + + try + { + name = PrincipalUtil.getIssuerX509Principal(cert); + } + catch (Exception e) + { + throw new CertificateParsingException(e.getMessage()); + } + + holder = new Holder(new IssuerSerial(generateGeneralNames(name), + new ASN1Integer(cert.getSerialNumber()))); + } + + public AttributeCertificateHolder(X509Principal 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, + String digestAlgorithm, String otherObjectTypeID, byte[] objectDigest) + { + holder = new Holder(new ObjectDigestInfo(digestedObjectType, + new ASN1ObjectIdentifier(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 the other object type ID if an object digest info is used. + * + * @return The other object type ID or <code>null</code> if no object + * digest info is set. + */ + public String getDigestAlgorithm() + { + if (holder.getObjectDigestInfo() != null) + { + return holder.getObjectDigestInfo().getDigestAlgorithm().getObjectId() + .getId(); + } + return null; + } + + /** + * Returns the hash if an object digest info is used. + * + * @return The hash or <code>null</code> if no object digest info is set. + */ + 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 String getOtherObjectTypeID() + { + if (holder.getObjectDigestInfo() != null) + { + holder.getObjectDigestInfo().getOtherObjectTypeID().getId(); + } + return null; + } + + private GeneralNames generateGeneralNames(X509Principal principal) + { + return new GeneralNames(new GeneralName(principal)); + } + + private boolean matchesDN(X509Principal subject, GeneralNames targets) + { + GeneralName[] names = targets.getNames(); + + for (int i = 0; i != names.length; i++) + { + GeneralName gn = names[i]; + + if (gn.getTagNo() == GeneralName.directoryName) + { + try + { + if (new X509Principal(((ASN1Encodable)gn.getName()).toASN1Primitive() + .getEncoded()).equals(subject)) + { + return true; + } + } + catch (IOException e) + { + } + } + } + + return false; + } + + private Object[] getNames(GeneralName[] names) + { + List l = new ArrayList(names.length); + + for (int i = 0; i != names.length; i++) + { + if (names[i].getTagNo() == GeneralName.directoryName) + { + try + { + l.add(new X509Principal( + ((ASN1Encodable)names[i].getName()).toASN1Primitive().getEncoded())); + } + catch (IOException e) + { + throw new RuntimeException("badly formed Name object"); + } + } + } + + return l.toArray(new Object[l.size()]); + } + + private Principal[] getPrincipals(GeneralNames names) + { + Object[] p = this.getNames(names.getNames()); + List l = new ArrayList(); + + for (int i = 0; i != p.length; i++) + { + if (p[i] instanceof Principal) + { + l.add(p[i]); + } + } + + return (Principal[])l.toArray(new Principal[l.size()]); + } + + /** + * Return any principal objects inside the attribute certificate holder + * entity names field. + * + * @return an array of Principal objects (usually X509Principal), null if no + * entity names field is set. + */ + public Principal[] getEntityNames() + { + if (holder.getEntityName() != null) + { + return getPrincipals(holder.getEntityName()); + } + + 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 Principal[] getIssuer() + { + if (holder.getBaseCertificateID() != null) + { + return getPrincipals(holder.getBaseCertificateID().getIssuer()); + } + + 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 + .toASN1Object()); + } + + public boolean match(Certificate cert) + { + if (!(cert instanceof X509Certificate)) + { + return false; + } + + X509Certificate x509Cert = (X509Certificate)cert; + + try + { + if (holder.getBaseCertificateID() != null) + { + return holder.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber()) + && matchesDN(PrincipalUtil.getIssuerX509Principal(x509Cert), holder.getBaseCertificateID().getIssuer()); + } + + if (holder.getEntityName() != null) + { + if (matchesDN(PrincipalUtil.getSubjectX509Principal(x509Cert), + holder.getEntityName())) + { + return true; + } + } + if (holder.getObjectDigestInfo() != null) + { + MessageDigest md = null; + try + { + md = MessageDigest.getInstance(getDigestAlgorithm(), "SC"); + + } + catch (Exception e) + { + return false; + } + switch (getDigestedObjectType()) + { + case ObjectDigestInfo.publicKey: + // TODO: DSA Dss-parms + md.update(cert.getPublicKey().getEncoded()); + break; + case ObjectDigestInfo.publicKeyCert: + md.update(cert.getEncoded()); + break; + } + if (!Arrays.areEqual(md.digest(), getObjectDigest())) + { + return false; + } + } + } + catch (CertificateEncodingException 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(); + } + + public boolean match(Object obj) + { + if (!(obj instanceof X509Certificate)) + { + return false; + } + + return match((Certificate)obj); + } +} diff --git a/prov/src/main/jdk1.1/org/spongycastle/x509/AttributeCertificateIssuer.java b/prov/src/main/jdk1.1/org/spongycastle/x509/AttributeCertificateIssuer.java new file mode 100644 index 00000000..383292d7 --- /dev/null +++ b/prov/src/main/jdk1.1/org/spongycastle/x509/AttributeCertificateIssuer.java @@ -0,0 +1,212 @@ +package org.spongycastle.x509; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.DERSequence; +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.jce.PrincipalUtil; +import org.spongycastle.jce.X509Principal; +import org.spongycastle.util.Selector; + +import java.io.IOException; +import java.security.Principal; +import java.security.cert.CertSelector; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; + +/** + * Carrying class for an attribute certificate issuer. + */ +public class AttributeCertificateIssuer + implements CertSelector, Selector +{ + final ASN1Encodable form; + + /** + * @param issuer + */ + AttributeCertificateIssuer( + AttCertIssuer issuer) + { + form = issuer.getIssuer(); + } + + public AttributeCertificateIssuer( + X509Principal principal) + { + form = new V2Form(new GeneralNames(new GeneralName(principal))); + } + + private Object[] 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) + { + try + { + l.add(new X509Principal(((ASN1Encodable)names[i].getName()).toASN1Primitive().getEncoded())); + } + catch (IOException e) + { + throw new RuntimeException("badly formed Name object"); + } + } + } + + return l.toArray(new Object[l.size()]); + } + + /** + * Return any principal objects inside the attribute certificate issuer object. + * + * @return an array of Principal objects (usually X509Principal) + */ + public Principal[] getPrincipals() + { + Object[] p = this.getNames(); + List l = new ArrayList(); + + for (int i = 0; i != p.length; i++) + { + if (p[i] instanceof Principal) + { + l.add(p[i]); + } + } + + return (Principal[])l.toArray(new Principal[l.size()]); + } + + private boolean matchesDN(X509Principal subject, GeneralNames targets) + { + GeneralName[] names = targets.getNames(); + + for (int i = 0; i != names.length; i++) + { + GeneralName gn = names[i]; + + if (gn.getTagNo() == GeneralName.directoryName) + { + try + { + if (new X509Principal(((ASN1Encodable)gn.getName()).toASN1Primitive().getEncoded()).equals(subject)) + { + return true; + } + } + catch (IOException e) + { + } + } + } + + return false; + } + + /* (non-Javadoc) + * @see java.security.cert.CertSelector#clone() + */ + public Object clone() + { + return new AttributeCertificateIssuer(AttCertIssuer.getInstance(form)); + } + + /* (non-Javadoc) + * @see java.security.cert.CertSelector#match(java.security.cert.Certificate) + */ + public boolean match(Certificate cert) + { + if (!(cert instanceof X509Certificate)) + { + return false; + } + + X509Certificate x509Cert = (X509Certificate)cert; + + try + { + if (form instanceof V2Form) + { + V2Form issuer = (V2Form)form; + if (issuer.getBaseCertificateID() != null) + { + return issuer.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber()) + && matchesDN(PrincipalUtil.getIssuerX509Principal(x509Cert), issuer.getBaseCertificateID().getIssuer()); + } + + GeneralNames name = issuer.getIssuerName(); + if (matchesDN(PrincipalUtil.getSubjectX509Principal(x509Cert), name)) + { + return true; + } + } + else + { + GeneralNames name = (GeneralNames)form; + if (matchesDN(PrincipalUtil.getSubjectX509Principal(x509Cert), name)) + { + return true; + } + } + } + catch (CertificateEncodingException e) + { + return false; + } + + return false; + } + + 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 X509Certificate)) + { + return false; + } + + return match((Certificate)obj); + } +} diff --git a/prov/src/main/jdk1.1/org/spongycastle/x509/X509AttributeCertStoreSelector.java b/prov/src/main/jdk1.1/org/spongycastle/x509/X509AttributeCertStoreSelector.java new file mode 100644 index 00000000..eafa21d0 --- /dev/null +++ b/prov/src/main/jdk1.1/org/spongycastle/x509/X509AttributeCertStoreSelector.java @@ -0,0 +1,488 @@ +package org.spongycastle.x509; + +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1Object; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.DEROctetString; +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.asn1.x509.X509Extensions; +import org.spongycastle.util.Selector; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.X509CertSelector; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * This class is an <code>Selector</code> like implementation to select + * attribute certificates from a given set of criteria. + * + * @see org.spongycastle.x509.X509AttributeCertificate + * @see org.spongycastle.x509.X509Store + */ +public class X509AttributeCertStoreSelector + implements Selector +{ + + // TODO: name constraints??? + + private AttributeCertificateHolder holder; + + private AttributeCertificateIssuer issuer; + + private BigInteger serialNumber; + + private Date attributeCertificateValid; + + private X509AttributeCertificate attributeCert; + + private Collection targetNames = new HashSet(); + + private Collection targetGroups = new HashSet(); + + public X509AttributeCertStoreSelector() + { + super(); + } + + /** + * Decides if the given attribute certificate should be selected. + * + * @param obj The attribute certificate which should be checked. + * @return <code>true</code> if the attribute certificate can be selected, + * <code>false</code> otherwise. + */ + public boolean match(Object obj) + { + if (!(obj instanceof X509AttributeCertificate)) + { + return false; + } + + X509AttributeCertificate attrCert = (X509AttributeCertificate) 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) + { + try + { + attrCert.checkValidity(attributeCertificateValid); + } + catch (CertificateExpiredException e) + { + return false; + } + catch (CertificateNotYetValidException e) + { + return false; + } + } + if (!targetNames.isEmpty() || !targetGroups.isEmpty()) + { + + byte[] targetInfoExt = attrCert + .getExtensionValue(X509Extensions.TargetInformation.getId()); + if (targetInfoExt != null) + { + TargetInformation targetinfo; + try + { + targetinfo = TargetInformation + .getInstance(new ASN1InputStream( + ((DEROctetString) DEROctetString + .fromByteArray(targetInfoExt)).getOctets()) + .readObject()); + } + catch (IOException e) + { + return false; + } + 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(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(targets[j] + .getTargetGroup())) + { + found = true; + break; + } + } + } + if (!found) + { + return false; + } + } + } + } + return true; + } + + /** + * Returns a clone of this object. + * + * @return the clone. + */ + public Object clone() + { + X509AttributeCertStoreSelector sel = new X509AttributeCertStoreSelector(); + sel.attributeCert = attributeCert; + sel.attributeCertificateValid = getAttributeCertificateValid(); + sel.holder = holder; + sel.issuer = issuer; + sel.serialNumber = serialNumber; + sel.targetGroups = getTargetGroups(); + sel.targetNames = getTargetNames(); + return sel; + } + + /** + * Returns the attribute certificate which must be matched. + * + * @return Returns the attribute certificate. + */ + public X509AttributeCertificate getAttributeCert() + { + return attributeCert; + } + + /** + * Set the attribute certificate to be matched. If <code>null</code> is + * given any will do. + * + * @param attributeCert The attribute certificate to set. + */ + public void setAttributeCert(X509AttributeCertificate attributeCert) + { + this.attributeCert = attributeCert; + } + + /** + * Get the criteria for the validity. + * + * @return Returns the attributeCertificateValid. + */ + public Date getAttributeCertificateValid() + { + if (attributeCertificateValid != null) + { + return new Date(attributeCertificateValid.getTime()); + } + + return null; + } + + /** + * 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; + } + } + + /** + * Gets the holder. + * + * @return Returns the holder. + */ + public AttributeCertificateHolder getHolder() + { + return holder; + } + + /** + * 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; + } + + /** + * Returns the issuer criterion. + * + * @return Returns the issuer. + */ + public AttributeCertificateIssuer getIssuer() + { + return issuer; + } + + /** + * 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; + } + + /** + * Gets the serial number the attribute certificate must have. + * + * @return Returns the serialNumber. + */ + public BigInteger getSerialNumber() + { + return serialNumber; + } + + /** + * 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>X509AttributeCertificate</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 target name criterion for the attribute certificate to the target + * information extension criteria. The <code>X509AttributeCertificate</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 a byte array containing the name in ASN.1 DER encoded form of a GeneralName + * @throws IOException if a parsing error occurs. + */ + public void addTargetName(byte[] name) throws IOException + { + addTargetName(GeneralName.getInstance(ASN1Primitive.fromByteArray(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 IOException if a parsing error occurs. + * @see #addTargetName(byte[]) + * @see #addTargetName(GeneralName) + */ + public void setTargetNames(Collection names) throws IOException + { + targetNames = extractGeneralNames(names); + } + + /** + * Gets the target names. The collection consists of <code>List</code>s + * made up of an <code>Integer</code> in the first entry and a DER encoded + * byte array or a <code>String</code> in the second entry. + * <p> + * The returned collection is immutable. + * + * @return The collection of target names + * @see #setTargetNames(Collection) + */ + public Collection getTargetNames() + { + return Collections.unmodifiableCollection(targetNames); + } + + /** + * Adds a target group criterion for the attribute certificate to the target + * information extension criteria. The <code>X509AttributeCertificate</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 target group criterion for the attribute certificate to the target + * information extension criteria. The <code>X509AttributeCertificate</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 name a byte array containing the group in ASN.1 DER encoded form of a GeneralName + * @throws IOException if a parsing error occurs. + */ + public void addTargetGroup(byte[] name) throws IOException + { + addTargetGroup(GeneralName.getInstance(ASN1Primitive.fromByteArray(name))); + } + + /** + * 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 IOException if a parsing error occurs. + * @see #addTargetGroup(byte[]) + * @see #addTargetGroup(GeneralName) + */ + public void setTargetGroups(Collection names) throws IOException + { + targetGroups = extractGeneralNames(names); + } + + + + /** + * Gets the target groups. The collection consists of <code>List</code>s + * made up of an <code>Integer</code> in the first entry and a DER encoded + * byte array or a <code>String</code> in the second entry. + * <p> + * The returned collection is immutable. + * + * @return The collection of target groups. + * @see #setTargetGroups(Collection) + */ + public Collection getTargetGroups() + { + return Collections.unmodifiableCollection(targetGroups); + } + + 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();) + { + Object o = it.next(); + if (o instanceof GeneralName) + { + temp.add(o); + } + else + { + temp.add(GeneralName.getInstance(ASN1Primitive.fromByteArray((byte[])o))); + } + } + return temp; + } +} diff --git a/prov/src/main/jdk1.1/org/spongycastle/x509/X509CRLStoreSelector.java b/prov/src/main/jdk1.1/org/spongycastle/x509/X509CRLStoreSelector.java new file mode 100644 index 00000000..a6c8cc31 --- /dev/null +++ b/prov/src/main/jdk1.1/org/spongycastle/x509/X509CRLStoreSelector.java @@ -0,0 +1,26 @@ +package org.spongycastle.x509; + +import org.spongycastle.util.Selector; + +import java.security.cert.X509CRLSelector; +import java.security.cert.CRL; + +public class X509CRLStoreSelector + extends X509CRLSelector + implements Selector +{ + public boolean match(Object obj) + { + if (!(obj instanceof CRL)) + { + return false; + } + + return super.match((CRL)obj); + } + + public boolean match(CRL obj) + { + return this.match((Object)obj); + } +} diff --git a/prov/src/main/jdk1.1/org/spongycastle/x509/X509CertStoreSelector.java b/prov/src/main/jdk1.1/org/spongycastle/x509/X509CertStoreSelector.java new file mode 100644 index 00000000..2c0e6cc3 --- /dev/null +++ b/prov/src/main/jdk1.1/org/spongycastle/x509/X509CertStoreSelector.java @@ -0,0 +1,26 @@ +package org.spongycastle.x509; + +import org.spongycastle.util.Selector; + +import java.security.cert.X509CertSelector; +import java.security.cert.Certificate; + +public class X509CertStoreSelector + extends X509CertSelector + implements Selector +{ + public boolean match(Object obj) + { + if (!(obj instanceof Certificate)) + { + return false; + } + + return super.match((Certificate)obj); + } + + public boolean match(Certificate obj) + { + return this.match((Object)obj); + } +} diff --git a/prov/src/main/jdk1.1/org/spongycastle/x509/X509Util.java b/prov/src/main/jdk1.1/org/spongycastle/x509/X509Util.java new file mode 100644 index 00000000..74aa897b --- /dev/null +++ b/prov/src/main/jdk1.1/org/spongycastle/x509/X509Util.java @@ -0,0 +1,397 @@ +package org.spongycastle.x509; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.Security; +import java.security.Signature; +import java.security.SignatureException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.oiw.OIWObjectIdentifiers; +import org.spongycastle.asn1.pkcs.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.jce.X509Principal; +import org.spongycastle.util.Strings; + +class X509Util +{ + private static Hashtable algorithms = new Hashtable(); + private static Hashtable params = new Hashtable(); + private static Set noParams = new HashSet(); + + 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); + + // + // 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); + + // + // explicit params + // + AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, new DERNull()); + params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20)); + + AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, new DERNull()); + params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28)); + + AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, new DERNull()); + params.put("SHA256WITHRSAANDMGF1", creatPSSParams(sha256AlgId, 32)); + + AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, new DERNull()); + params.put("SHA384WITHRSAANDMGF1", creatPSSParams(sha384AlgId, 48)); + + AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512, new DERNull()); + params.put("SHA512WITHRSAANDMGF1", creatPSSParams(sha512AlgId, 64)); + } + + private static RSASSAPSSparams creatPSSParams(AlgorithmIdentifier hashAlgId, int saltSize) + { + return new RSASSAPSSparams( + hashAlgId, + new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId), + new ASN1Integer(saltSize), + new ASN1Integer(1)); + } + + static ASN1ObjectIdentifier getAlgorithmOID( + String algorithmName) + { + algorithmName = Strings.toUpperCase(algorithmName); + + if (algorithms.containsKey(algorithmName)) + { + return (ASN1ObjectIdentifier)algorithms.get(algorithmName); + } + + return new ASN1ObjectIdentifier(algorithmName); + } + + static AlgorithmIdentifier getSigAlgID( + ASN1ObjectIdentifier sigOid, + String algorithmName) + { + if (noParams.contains(sigOid)) + { + return new AlgorithmIdentifier(sigOid); + } + + algorithmName = Strings.toUpperCase(algorithmName); + + if (params.containsKey(algorithmName)) + { + return new AlgorithmIdentifier(sigOid, (ASN1Encodable)params.get(algorithmName)); + } + else + { + return new AlgorithmIdentifier(sigOid, new DERNull()); + } + } + + static Iterator getAlgNames() + { + Enumeration e = algorithms.keys(); + List l = new ArrayList(); + + while (e.hasMoreElements()) + { + l.add(e.nextElement()); + } + + return l.iterator(); + } + + static Signature getSignatureInstance( + String algorithm) + throws NoSuchAlgorithmException + { + return Signature.getInstance(algorithm); + } + + static Signature getSignatureInstance( + String algorithm, + String provider) + throws NoSuchProviderException, NoSuchAlgorithmException + { + if (provider != null) + { + return Signature.getInstance(algorithm, provider); + } + else + { + return Signature.getInstance(algorithm); + } + } + + static byte[] calculateSignature( + ASN1ObjectIdentifier sigOid, + String sigName, + PrivateKey key, + SecureRandom random, + ASN1Encodable object) + throws IOException, NoSuchAlgorithmException, InvalidKeyException, SignatureException + { + Signature sig; + + if (sigOid == null) + { + throw new IllegalStateException("no signature algorithm specified"); + } + + sig = X509Util.getSignatureInstance(sigName); + + if (random != null) + { + sig.initSign(key); + } + else + { + sig.initSign(key); + } + + sig.update(object.toASN1Primitive().getEncoded(ASN1Encoding.DER)); + + return sig.sign(); + } + + static byte[] calculateSignature( + ASN1ObjectIdentifier sigOid, + String sigName, + String provider, + PrivateKey key, + SecureRandom random, + ASN1Encodable object) + throws IOException, NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException, SignatureException + { + Signature sig; + + if (sigOid == null) + { + throw new IllegalStateException("no signature algorithm specified"); + } + + sig = X509Util.getSignatureInstance(sigName, provider); + + if (random != null) + { + sig.initSign(key); + } + else + { + sig.initSign(key); + } + + sig.update(object.toASN1Primitive().getEncoded(ASN1Encoding.DER)); + + return sig.sign(); + } + + static class Implementation + { + Object engine; + Provider provider; + + Implementation( + Object engine, + Provider provider) + { + this.engine = engine; + this.provider = provider; + } + + Object getEngine() + { + return engine; + } + + Provider getProvider() + { + return provider; + } + } + + /** + * see if we can find an algorithm (or its alias and what it represents) in + * the property table for the given provider. + */ + static Implementation getImplementation( + String baseName, + String algorithm, + Provider prov) + throws NoSuchAlgorithmException + { + algorithm = Strings.toUpperCase(algorithm); + + String alias; + + while ((alias = prov.getProperty("Alg.Alias." + baseName + "." + algorithm)) != null) + { + algorithm = alias; + } + + String className = prov.getProperty(baseName + "." + algorithm); + + if (className != null) + { + try + { + Class cls; + ClassLoader clsLoader = prov.getClass().getClassLoader(); + + if (clsLoader != null) + { + cls = clsLoader.loadClass(className); + } + else + { + cls = Class.forName(className); + } + + return new Implementation(cls.newInstance(), prov); + } + catch (ClassNotFoundException e) + { + throw new IllegalStateException( + "algorithm " + algorithm + " in provider " + prov.getName() + " but no class \"" + className + "\" found!"); + } + catch (Exception e) + { + throw new IllegalStateException( + "algorithm " + algorithm + " in provider " + prov.getName() + " but class \"" + className + "\" inaccessible!"); + } + } + + throw new NoSuchAlgorithmException("cannot find implementation " + algorithm + " for provider " + prov.getName()); + } + + /** + * return an implementation for a given algorithm/provider. + * If the provider is null, we grab the first avalaible who has the required algorithm. + */ + static Implementation getImplementation( + String baseName, + String algorithm) + throws NoSuchAlgorithmException + { + Provider[] prov = Security.getProviders(); + + // + // search every provider looking for the algorithm we want. + // + for (int i = 0; i != prov.length; i++) + { + // + // try case insensitive + // + Implementation imp = getImplementation(baseName, Strings.toUpperCase(algorithm), prov[i]); + if (imp != null) + { + return imp; + } + + try + { + imp = getImplementation(baseName, algorithm, prov[i]); + } + catch (NoSuchAlgorithmException e) + { + // continue + } + } + + throw new NoSuchAlgorithmException("cannot find implementation " + algorithm); + } + + static Provider getProvider(String provider) + throws NoSuchProviderException + { + Provider prov = Security.getProvider(provider); + + if (prov == null) + { + throw new NoSuchProviderException("Provider " + provider + " not found"); + } + + return prov; + } +} diff --git a/prov/src/main/jdk1.1/org/spongycastle/x509/X509V1CertificateGenerator.java b/prov/src/main/jdk1.1/org/spongycastle/x509/X509V1CertificateGenerator.java new file mode 100644 index 00000000..95cf7d6a --- /dev/null +++ b/prov/src/main/jdk1.1/org/spongycastle/x509/X509V1CertificateGenerator.java @@ -0,0 +1,345 @@ +package org.spongycastle.x509; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.SignatureException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.Date; +import java.util.Iterator; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.DERBitString; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.asn1.x509.TBSCertificate; +import org.spongycastle.asn1.x509.Time; +import org.spongycastle.asn1.x509.V1TBSCertificateGenerator; +import org.spongycastle.asn1.x509.Certificate; +import org.spongycastle.asn1.x509.X509Name; +import org.spongycastle.jce.provider.X509CertificateObject; + +/** + * class to produce an X.509 Version 1 certificate. + * @deprecated use org.spongycastle.cert.X509v1CertificateBuilder. + */ +public class X509V1CertificateGenerator +{ + private V1TBSCertificateGenerator tbsGen; + private ASN1ObjectIdentifier sigOID; + private AlgorithmIdentifier sigAlgId; + private String signatureAlgorithm; + + public X509V1CertificateGenerator() + { + tbsGen = new V1TBSCertificateGenerator(); + } + + /** + * reset the generator + */ + public void reset() + { + tbsGen = new V1TBSCertificateGenerator(); + } + + /** + * set the serial number for the certificate. + */ + public void setSerialNumber( + BigInteger serialNumber) + { + if (serialNumber.compareTo(BigInteger.valueOf(0)) <= 0) + { + throw new IllegalArgumentException("serial number must be a positive integer"); + } + + tbsGen.setSerialNumber(new ASN1Integer(serialNumber)); + } + + /** + * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the + * certificate. + */ + public void setIssuerDN( + X509Name issuer) + { + tbsGen.setIssuer(issuer); + } + + public void setNotBefore( + Date date) + { + tbsGen.setStartDate(new Time(date)); + } + + public void setNotAfter( + Date date) + { + tbsGen.setEndDate(new Time(date)); + } + + /** + * Set the subject distinguished name. The subject describes the entity associated with the public key. + */ + public void setSubjectDN( + X509Name subject) + { + tbsGen.setSubject(subject); + } + + public void setPublicKey( + PublicKey key) + { + try + { + tbsGen.setSubjectPublicKeyInfo(new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream( + new ByteArrayInputStream(key.getEncoded())).readObject())); + } + catch (Exception e) + { + throw new IllegalArgumentException("unable to process key - " + e.toString()); + } + } + + /** + * Set the signature algorithm. This can be either a name or an OID, names + * are treated as case insensitive. + * + * @param signatureAlgorithm string representation of the algorithm name. + */ + public void setSignatureAlgorithm( + String signatureAlgorithm) + { + this.signatureAlgorithm = signatureAlgorithm; + + try + { + sigOID = X509Util.getAlgorithmOID(signatureAlgorithm); + } + catch (Exception e) + { + throw new IllegalArgumentException("Unknown signature type requested"); + } + + sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm); + + tbsGen.setSignature(sigAlgId); + } + + /** + * generate an X509 certificate, based on the current issuer and subject + * using the default provider "SC". + * @deprecated use generate(key, "SC") + */ + public X509Certificate generateX509Certificate( + PrivateKey key) + throws SecurityException, SignatureException, InvalidKeyException + { + try + { + return generateX509Certificate(key, "SC", null); + } + catch (NoSuchProviderException e) + { + throw new SecurityException("BC provider not installed!"); + } + } + + /** + * generate an X509 certificate, based on the current issuer and subject + * using the default provider "SC" and the passed in source of randomness + * @deprecated use generate(key, random, "SC") + */ + public X509Certificate generateX509Certificate( + PrivateKey key, + SecureRandom random) + throws SecurityException, SignatureException, InvalidKeyException + { + try + { + return generateX509Certificate(key, "SC", random); + } + catch (NoSuchProviderException e) + { + throw new SecurityException("BC provider not installed!"); + } + } + + /** + * generate an X509 certificate, based on the current issuer and subject, + * using the passed in provider for the signing, and the passed in source + * of randomness (if required). + * @deprecated use generate() + */ + public X509Certificate generateX509Certificate( + PrivateKey key, + String provider) + throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException + { + return generateX509Certificate(key, provider, null); + } + + /** + * generate an X509 certificate, based on the current issuer and subject, + * using the passed in provider for the signing, and the passed in source + * of randomness (if required). + * @deprecated use generate() + */ + public X509Certificate generateX509Certificate( + PrivateKey key, + String provider, + SecureRandom random) + throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException + { + try + { + return generate(key, provider, random); + } + catch (NoSuchProviderException e) + { + throw e; + } + catch (SignatureException e) + { + throw e; + } + catch (InvalidKeyException e) + { + throw e; + } + catch (NoSuchAlgorithmException e) + { + throw new SecurityException("exception: " + e); + } + catch (GeneralSecurityException e) + { + throw new SecurityException("exception: " + e); + } + } + + /** + * generate an X509 certificate, based on the current issuer and subject + * using the default provider. + * <p> + * <b>Note:</b> this differs from the deprecated method in that the default provider is + * used - not "SC". + * </p> + */ + public X509Certificate generate( + PrivateKey key) + throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException + { + return generate(key, (SecureRandom)null); + } + + /** + * generate an X509 certificate, based on the current issuer and subject + * using the default provider and the passed in source of randomness + * <p> + * <b>Note:</b> this differs from the deprecated method in that the default provider is + * used - not "SC". + * </p> + */ + public X509Certificate generate( + PrivateKey key, + SecureRandom random) + throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException + { + TBSCertificate tbsCert = tbsGen.generateTBSCertificate(); + byte[] signature; + + try + { + signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, key, random, tbsCert); + } + catch (IOException e) + { + throw new ExtCertificateEncodingException("exception encoding TBS cert", e); + } + + return generateJcaObject(tbsCert, signature); + } + + /** + * generate an X509 certificate, based on the current issuer and subject, + * using the passed in provider for the signing, and the passed in source + * of randomness (if required). + */ + public X509Certificate generate( + PrivateKey key, + String provider) + throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException + { + return generate(key, provider, null); + } + + /** + * generate an X509 certificate, based on the current issuer and subject, + * using the passed in provider for the signing, and the passed in source + * of randomness (if required). + */ + public X509Certificate generate( + PrivateKey key, + String provider, + SecureRandom random) + throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException + { + TBSCertificate tbsCert = tbsGen.generateTBSCertificate(); + byte[] signature; + + try + { + signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, tbsCert); + } + catch (IOException e) + { + throw new ExtCertificateEncodingException("exception encoding TBS cert", e); + } + + return generateJcaObject(tbsCert, signature); + } + + private X509Certificate generateJcaObject(TBSCertificate tbsCert, byte[] signature) + throws CertificateEncodingException + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(tbsCert); + v.add(sigAlgId); + v.add(new DERBitString(signature)); + + try + { + return new X509CertificateObject(Certificate.getInstance((new DERSequence(v)))); + } + catch (CertificateParsingException e) + { + throw new ExtCertificateEncodingException("exception producing certificate object", e); + } + } + + /** + * Return an iterator of the signature names supported by the generator. + * + * @return an iterator containing recognised names. + */ + public Iterator getSignatureAlgNames() + { + return X509Util.getAlgNames(); + } +} diff --git a/prov/src/main/jdk1.1/org/spongycastle/x509/X509V2AttributeCertificateGenerator.java b/prov/src/main/jdk1.1/org/spongycastle/x509/X509V2AttributeCertificateGenerator.java new file mode 100644 index 00000000..9aae6e85 --- /dev/null +++ b/prov/src/main/jdk1.1/org/spongycastle/x509/X509V2AttributeCertificateGenerator.java @@ -0,0 +1,281 @@ +package org.spongycastle.x509; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.SecureRandom; +import java.security.Signature; +import java.security.SignatureException; +import java.util.Date; +import java.util.Hashtable; +import java.util.Vector; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.DERBitString; +import org.spongycastle.asn1.ASN1GeneralizedTime; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.DERNull; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DEROctetString; +import org.spongycastle.asn1.DEROutputStream; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.AttCertIssuer; +import org.spongycastle.asn1.x509.Attribute; +import org.spongycastle.asn1.x509.AttributeCertificate; +import org.spongycastle.asn1.x509.V2AttributeCertificateInfoGenerator; +import org.spongycastle.asn1.x509.AttributeCertificateInfo; +import org.spongycastle.asn1.x509.X509Extension; +import org.spongycastle.asn1.x509.X509Extensions; +import org.spongycastle.util.Strings; + +/** + * class to produce an X.509 Version 2 AttributeCertificate. + */ +public class X509V2AttributeCertificateGenerator +{ + private V2AttributeCertificateInfoGenerator acInfoGen; + private ASN1ObjectIdentifier sigOID; + private AlgorithmIdentifier sigAlgId; + private String signatureAlgorithm; + private Hashtable extensions = null; + private Vector extOrdering = null; + private static Hashtable algorithms = new Hashtable(); + + static + { + algorithms.put("MD2WITHRSAENCRYPTION", new ASN1ObjectIdentifier("1.2.840.113549.1.1.2")); + algorithms.put("MD2WITHRSA", new ASN1ObjectIdentifier("1.2.840.113549.1.1.2")); + algorithms.put("MD5WITHRSAENCRYPTION", new ASN1ObjectIdentifier("1.2.840.113549.1.1.4")); + algorithms.put("MD5WITHRSA", new ASN1ObjectIdentifier("1.2.840.113549.1.1.4")); + algorithms.put("SHA1WITHRSAENCRYPTION", new ASN1ObjectIdentifier("1.2.840.113549.1.1.5")); + algorithms.put("SHA1WITHRSA", new ASN1ObjectIdentifier("1.2.840.113549.1.1.5")); + algorithms.put("RIPEMD160WITHRSAENCRYPTION", new ASN1ObjectIdentifier("1.3.36.3.3.1.2")); + algorithms.put("RIPEMD160WITHRSA", new ASN1ObjectIdentifier("1.3.36.3.3.1.2")); + algorithms.put("SHA1WITHDSA", new ASN1ObjectIdentifier("1.2.840.10040.4.3")); + algorithms.put("DSAWITHSHA1", new ASN1ObjectIdentifier("1.2.840.10040.4.3")); + algorithms.put("SHA1WITHECDSA", new ASN1ObjectIdentifier("1.2.840.10045.4.1")); + algorithms.put("ECDSAWITHSHA1", new ASN1ObjectIdentifier("1.2.840.10045.4.1")); + } + + public X509V2AttributeCertificateGenerator() + { + acInfoGen = new V2AttributeCertificateInfoGenerator(); + } + + /** + * reset the generator + */ + public void reset() + { + acInfoGen = new V2AttributeCertificateInfoGenerator(); + extensions = null; + extOrdering = null; + } + + /** + * Set the Holder of this Attribute Certificate + */ + public void setHolder( + AttributeCertificateHolder holder) + { + acInfoGen.setHolder(holder.holder); + } + + /** + * Set the issuer + */ + public void setIssuer( + AttributeCertificateIssuer issuer) + { + acInfoGen.setIssuer(AttCertIssuer.getInstance(issuer.form)); + } + + /** + * Set the Signature inside the AttributeCertificateInfo + */ + public void setSignature( + AlgorithmIdentifier sig) + { + acInfoGen.setSignature(sig); + } + + /** + * set the serial number for the certificate. + */ + public void setSerialNumber( + BigInteger serialNumber) + { + acInfoGen.setSerialNumber(new ASN1Integer(serialNumber)); + } + + public void setNotBefore( + Date date) + { + acInfoGen.setStartDate(new ASN1GeneralizedTime(date)); + } + + public void setNotAfter( + Date date) + { + acInfoGen.setEndDate(new ASN1GeneralizedTime(date)); + } + + public void setSignatureAlgorithm( + String signatureAlgorithm) + { + this.signatureAlgorithm = signatureAlgorithm; + + sigOID = (ASN1ObjectIdentifier)algorithms.get(Strings.toUpperCase(signatureAlgorithm)); + + if (sigOID == null) + { + throw new IllegalArgumentException("Unknown signature type requested"); + } + + sigAlgId = new AlgorithmIdentifier(this.sigOID, new DERNull()); + + acInfoGen.setSignature(sigAlgId); + } + + /** + * add an attribute + */ + public void addAttribute( + X509Attribute attribute) + { + acInfoGen.addAttribute(Attribute.getInstance(attribute.toASN1Object())); + } + + public void setIssuerUniqueId( + boolean[] iui) + { + // [TODO] convert boolean array to bit string + //acInfoGen.setIssuerUniqueID(iui); + } + + /** + * add a given extension field for the standard extensions tag (tag 3) + * @throws IOException + */ + 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 (tag 3) + * The value parameter becomes the contents of the octet string associated + * with the extension. + */ + public void addExtension( + String OID, + boolean critical, + byte[] value) + { + if (extensions == null) + { + extensions = new Hashtable(); + extOrdering = new Vector(); + } + + ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier(OID); + + extensions.put(oid, new X509Extension(critical, new DEROctetString(value))); + extOrdering.addElement(oid); + } + + /** + * generate an X509 certificate, based on the current issuer and subject, + * using the passed in provider for the signing. + */ + public X509AttributeCertificate generateCertificate( + PrivateKey key, + String provider) + throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException + { + return generateCertificate(key, provider, null); + } + + /** + * generate an X509 certificate, based on the current issuer and subject, + * using the passed in provider for the signing and the supplied source + * of randomness, if required. + */ + public X509AttributeCertificate generateCertificate( + PrivateKey key, + String provider, + SecureRandom random) + throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException + { + Signature sig = null; + + if (sigOID == null) + { + throw new IllegalStateException("no signature algorithm specified"); + } + + try + { + sig = Signature.getInstance(sigOID.getId(), provider); + } + catch (NoSuchAlgorithmException ex) + { + try + { + sig = Signature.getInstance(signatureAlgorithm, provider); + } + catch (NoSuchAlgorithmException e) + { + throw new SecurityException("exception creating signature: " + e.toString()); + } + } + + sig.initSign(key); + + if (extensions != null) + { + acInfoGen.setExtensions(new X509Extensions(extOrdering, extensions)); + } + + AttributeCertificateInfo acInfo = acInfoGen.generateAttributeCertificateInfo(); + + try + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + DEROutputStream dOut = new DEROutputStream(bOut); + + dOut.writeObject(acInfo); + + sig.update(bOut.toByteArray()); + } + catch (Exception e) + { + throw new SecurityException("exception encoding Attribute cert - " + e); + } + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(acInfo); + v.add(sigAlgId); + v.add(new DERBitString(sig.sign())); + + try + { + return new X509V2AttributeCertificate(new AttributeCertificate(new DERSequence(v))); + } + catch (IOException e) + { + throw new RuntimeException("constructed invalid certificate!"); + } + } +} diff --git a/prov/src/main/jdk1.1/org/spongycastle/x509/X509V2CRLGenerator.java b/prov/src/main/jdk1.1/org/spongycastle/x509/X509V2CRLGenerator.java new file mode 100644 index 00000000..ac9ad6dd --- /dev/null +++ b/prov/src/main/jdk1.1/org/spongycastle/x509/X509V2CRLGenerator.java @@ -0,0 +1,434 @@ +package org.spongycastle.x509; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.SecureRandom; +import java.security.SignatureException; +import java.security.cert.CRLException; +import java.security.cert.X509CRL; +import java.security.cert.X509CRLEntry; +import java.util.Date; +import java.util.Iterator; +import java.util.Set; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.DERBitString; +import org.spongycastle.asn1.ASN1GeneralizedTime; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.CertificateList; +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.asn1.x509.Extensions; +import org.spongycastle.asn1.x509.X509ExtensionsGenerator; +import org.spongycastle.asn1.x509.X509Name; +import org.spongycastle.jce.provider.X509CRLObject; + +/** + * class to produce an X.509 Version 2 CRL. + * @deprecated use org.spongycastle.cert.X509v2CRLBuilder. + */ +public class X509V2CRLGenerator +{ + private V2TBSCertListGenerator tbsGen; + private ASN1ObjectIdentifier sigOID; + private AlgorithmIdentifier sigAlgId; + private String signatureAlgorithm; + private X509ExtensionsGenerator extGenerator; + + public X509V2CRLGenerator() + { + tbsGen = new V2TBSCertListGenerator(); + extGenerator = new X509ExtensionsGenerator(); + } + + /** + * reset the generator + */ + public void reset() + { + tbsGen = new V2TBSCertListGenerator(); + extGenerator.reset(); + } + + /** + * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the + * certificate. + */ + public void setIssuerDN( + X509Name issuer) + { + tbsGen.setIssuer(issuer); + } + + public void setThisUpdate( + Date date) + { + tbsGen.setThisUpdate(new Time(date)); + } + + public void setNextUpdate( + Date date) + { + tbsGen.setNextUpdate(new Time(date)); + } + + /** + * Reason being as indicated by CRLReason, i.e. CRLReason.keyCompromise + * or 0 if CRLReason is not to be used + **/ + public void addCRLEntry(BigInteger userCertificate, Date revocationDate, int reason) + { + tbsGen.addCRLEntry(new ASN1Integer(userCertificate), new Time(revocationDate), reason); + } + + /** + * Add a CRL entry with an Invalidity Date extension as well as a CRLReason extension. + * Reason being as indicated by CRLReason, i.e. CRLReason.keyCompromise + * or 0 if CRLReason is not to be used + **/ + public void addCRLEntry(BigInteger userCertificate, Date revocationDate, int reason, Date invalidityDate) + { + tbsGen.addCRLEntry(new ASN1Integer(userCertificate), new Time(revocationDate), reason, new ASN1GeneralizedTime(invalidityDate)); + } + + /** + * Add a CRL entry with extensions. + **/ + public void addCRLEntry(BigInteger userCertificate, Date revocationDate, X509Extensions extensions) + { + tbsGen.addCRLEntry(new ASN1Integer(userCertificate), new Time(revocationDate), Extensions.getInstance(extensions)); + } + + /** + * Add the CRLEntry objects contained in a previous CRL. + * + * @param other the X509CRL to source the other entries from. + */ + public void addCRL(X509CRL other) + throws CRLException + { + Set revocations = other.getRevokedCertificates(); + + if (revocations != null) + { + Iterator it = revocations.iterator(); + while (it.hasNext()) + { + X509CRLEntry entry = (X509CRLEntry)it.next(); + + ASN1InputStream aIn = new ASN1InputStream(entry.getEncoded()); + + try + { + tbsGen.addCRLEntry(ASN1Sequence.getInstance(aIn.readObject())); + } + catch (IOException e) + { + throw new CRLException("exception processing encoding of CRL: " + e.toString()); + } + } + } + } + + /** + * Set the signature algorithm. This can be either a name or an OID, names + * are treated as case insensitive. + * + * @param signatureAlgorithm string representation of the algorithm name. + */ + public void setSignatureAlgorithm( + String signatureAlgorithm) + { + this.signatureAlgorithm = signatureAlgorithm; + + try + { + sigOID = X509Util.getAlgorithmOID(signatureAlgorithm); + } + catch (Exception e) + { + throw new IllegalArgumentException("Unknown signature type requested"); + } + + sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm); + + tbsGen.setSignature(sigAlgId); + } + + /** + * add a given extension field for the standard extensions tag (tag 0) + */ + public void addExtension( + String oid, + boolean critical, + ASN1Encodable value) + { + this.addExtension(new ASN1ObjectIdentifier(oid), critical, value); + } + + /** + * add a given extension field for the standard extensions tag (tag 0) + */ + public void addExtension( + ASN1ObjectIdentifier oid, + boolean critical, + ASN1Encodable value) + { + extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value); + } + + /** + * add a given extension field for the standard extensions tag (tag 0) + */ + public void addExtension( + String oid, + boolean critical, + byte[] value) + { + this.addExtension(new ASN1ObjectIdentifier(oid), critical, value); + } + + /** + * add a given extension field for the standard extensions tag (tag 0) + */ + public void addExtension( + ASN1ObjectIdentifier oid, + boolean critical, + byte[] value) + { + extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value); + } + + /** + * generate an X509 CRL, based on the current issuer and subject + * using the default provider "SC". + * @deprecated use generate(key, "SC") + */ + public X509CRL generateX509CRL( + PrivateKey key) + throws SecurityException, SignatureException, InvalidKeyException + { + try + { + return generateX509CRL(key, "SC", null); + } + catch (NoSuchProviderException e) + { + throw new SecurityException("BC provider not installed!"); + } + } + + /** + * generate an X509 CRL, based on the current issuer and subject + * using the default provider "SC" and an user defined SecureRandom object as + * source of randomness. + * @deprecated use generate(key, random, "SC") + */ + public X509CRL generateX509CRL( + PrivateKey key, + SecureRandom random) + throws SecurityException, SignatureException, InvalidKeyException + { + try + { + return generateX509CRL(key, "SC", random); + } + catch (NoSuchProviderException e) + { + throw new SecurityException("BC provider not installed!"); + } + } + + /** + * generate an X509 certificate, based on the current issuer and subject + * using the passed in provider for the signing. + * @deprecated use generate() + */ + public X509CRL generateX509CRL( + PrivateKey key, + String provider) + throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException + { + return generateX509CRL(key, provider, null); + } + + /** + * generate an X509 CRL, based on the current issuer and subject, + * using the passed in provider for the signing. + * @deprecated use generate() + */ + public X509CRL generateX509CRL( + PrivateKey key, + String provider, + SecureRandom random) + throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException + { + try + { + return generate(key, provider, random); + } + catch (NoSuchProviderException e) + { + throw e; + } + catch (SignatureException e) + { + throw e; + } + catch (InvalidKeyException e) + { + throw e; + } + catch (NoSuchAlgorithmException e) + { + throw new SecurityException("exception: " + e); + } + catch (GeneralSecurityException e) + { + throw new SecurityException("exception: " + e); + } + } + + /** + * generate an X509 CRL, based on the current issuer and subject + * using the default provider. + * <p> + * <b>Note:</b> this differs from the deprecated method in that the default provider is + * used - not "SC". + * </p> + */ + public X509CRL generate( + PrivateKey key) + throws CRLException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException + { + return generate(key, (SecureRandom)null); + } + + /** + * generate an X509 CRL, based on the current issuer and subject + * using the default provider and an user defined SecureRandom object as + * source of randomness. + * <p> + * <b>Note:</b> this differs from the deprecated method in that the default provider is + * used - not "SC". + * </p> + */ + public X509CRL generate( + PrivateKey key, + SecureRandom random) + throws CRLException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException + { + TBSCertList tbsCrl = generateCertList(); + byte[] signature; + + try + { + signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, key, random, tbsCrl); + } + catch (IOException e) + { + throw new ExtCRLException("cannot generate CRL encoding", e); + } + + return generateJcaObject(tbsCrl, signature); + } + + /** + * generate an X509 certificate, based on the current issuer and subject + * using the passed in provider for the signing. + */ + public X509CRL generate( + PrivateKey key, + String provider) + throws CRLException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException + { + return generate(key, provider, null); + } + + /** + * generate an X509 CRL, based on the current issuer and subject, + * using the passed in provider for the signing. + */ + public X509CRL generate( + PrivateKey key, + String provider, + SecureRandom random) + throws CRLException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException + { + TBSCertList tbsCrl = generateCertList(); + byte[] signature; + + try + { + signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, tbsCrl); + } + catch (IOException e) + { + throw new ExtCRLException("cannot generate CRL encoding", e); + } + + return generateJcaObject(tbsCrl, signature); + } + + private TBSCertList generateCertList() + { + if (!extGenerator.isEmpty()) + { + tbsGen.setExtensions(extGenerator.generate()); + } + + return tbsGen.generateTBSCertList(); + } + + private X509CRL generateJcaObject(TBSCertList tbsCrl, byte[] signature) + throws CRLException + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(tbsCrl); + v.add(sigAlgId); + v.add(new DERBitString(signature)); + + return new X509CRLObject(new CertificateList(new DERSequence(v))); + } + + /** + * Return an iterator of the signature names supported by the generator. + * + * @return an iterator containing recognised names. + */ + public Iterator getSignatureAlgNames() + { + return X509Util.getAlgNames(); + } + + private static class ExtCRLException + extends CRLException + { + Throwable cause; + + ExtCRLException(String message, Throwable cause) + { + super(message); + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } + } +} diff --git a/prov/src/main/jdk1.1/org/spongycastle/x509/X509V3CertificateGenerator.java b/prov/src/main/jdk1.1/org/spongycastle/x509/X509V3CertificateGenerator.java new file mode 100644 index 00000000..1a0dc95b --- /dev/null +++ b/prov/src/main/jdk1.1/org/spongycastle/x509/X509V3CertificateGenerator.java @@ -0,0 +1,495 @@ +package org.spongycastle.x509; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.SignatureException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.Date; +import java.util.Iterator; + +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERBitString; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.x509.AlgorithmIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.asn1.x509.TBSCertificate; +import org.spongycastle.asn1.x509.Time; +import org.spongycastle.asn1.x509.V3TBSCertificateGenerator; +import org.spongycastle.asn1.x509.Certificate; +import org.spongycastle.asn1.x509.X509ExtensionsGenerator; +import org.spongycastle.asn1.x509.X509Name; +import org.spongycastle.jce.provider.X509CertificateObject; +import org.spongycastle.x509.extension.X509ExtensionUtil; + +/** + * class to produce an X.509 Version 3 certificate. + * @deprecated use org.spongycastle.cert.X509v3CertificateBuilder. + */ +public class X509V3CertificateGenerator +{ + private V3TBSCertificateGenerator tbsGen; + private ASN1ObjectIdentifier sigOID; + private AlgorithmIdentifier sigAlgId; + private String signatureAlgorithm; + private X509ExtensionsGenerator extGenerator; + + public X509V3CertificateGenerator() + { + tbsGen = new V3TBSCertificateGenerator(); + extGenerator = new X509ExtensionsGenerator(); + } + + /** + * reset the generator + */ + public void reset() + { + tbsGen = new V3TBSCertificateGenerator(); + extGenerator.reset(); + } + + /** + * set the serial number for the certificate. + */ + public void setSerialNumber( + BigInteger serialNumber) + { + if (serialNumber.compareTo(BigInteger.valueOf(0)) <= 0) + { + throw new IllegalArgumentException("serial number must be a positive integer"); + } + + tbsGen.setSerialNumber(new ASN1Integer(serialNumber)); + } + + /** + * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the + * certificate. + */ + public void setIssuerDN( + X509Name issuer) + { + tbsGen.setIssuer(issuer); + } + + public void setNotBefore( + Date date) + { + tbsGen.setStartDate(new Time(date)); + } + + public void setNotAfter( + Date date) + { + tbsGen.setEndDate(new Time(date)); + } + + /** + * Set the subject distinguished name. The subject describes the entity associated with the public key. + */ + public void setSubjectDN( + X509Name subject) + { + tbsGen.setSubject(subject); + } + + public void setPublicKey( + PublicKey key) + throws IllegalArgumentException + { + try + { + tbsGen.setSubjectPublicKeyInfo( + SubjectPublicKeyInfo.getInstance(new ASN1InputStream(key.getEncoded()).readObject())); + } + catch (Exception e) + { + throw new IllegalArgumentException("unable to process key - " + e.toString()); + } + } + + /** + * Set the signature algorithm. This can be either a name or an OID, names + * are treated as case insensitive. + * + * @param signatureAlgorithm string representation of the algorithm name. + */ + public void setSignatureAlgorithm( + String signatureAlgorithm) + { + this.signatureAlgorithm = signatureAlgorithm; + + try + { + sigOID = X509Util.getAlgorithmOID(signatureAlgorithm); + } + catch (Exception e) + { + throw new IllegalArgumentException("Unknown signature type requested: " + signatureAlgorithm); + } + + sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm); + + tbsGen.setSignature(sigAlgId); + } + + /** + * Set the subject unique ID - note: it is very rare that it is correct to do this. + */ + public void setSubjectUniqueID(boolean[] uniqueID) + { + tbsGen.setSubjectUniqueID(booleanToBitString(uniqueID)); + } + + /** + * Set the issuer unique ID - note: it is very rare that it is correct to do this. + */ + public void setIssuerUniqueID(boolean[] uniqueID) + { + tbsGen.setIssuerUniqueID(booleanToBitString(uniqueID)); + } + + private 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); + } + } + + /** + * add a given extension field for the standard extensions tag (tag 3) + */ + public void addExtension( + String oid, + boolean critical, + ASN1Encodable value) + { + this.addExtension(new ASN1ObjectIdentifier(oid), critical, value); + } + + /** + * add a given extension field for the standard extensions tag (tag 3) + */ + public void addExtension( + ASN1ObjectIdentifier oid, + boolean critical, + ASN1Encodable value) + { + extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value); + } + + /** + * add a given extension field for the standard extensions tag (tag 3) + * The value parameter becomes the contents of the octet string associated + * with the extension. + */ + public void addExtension( + String oid, + boolean critical, + byte[] value) + { + this.addExtension(new ASN1ObjectIdentifier(oid), critical, value); + } + + /** + * add a given extension field for the standard extensions tag (tag 3) + */ + public void addExtension( + ASN1ObjectIdentifier oid, + boolean critical, + byte[] value) + { + extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value); + } + + /** + * add a given extension field for the standard extensions tag (tag 3) + * copying the extension value from another certificate. + * @throws CertificateParsingException if the extension cannot be extracted. + */ + public void copyAndAddExtension( + String oid, + boolean critical, + X509Certificate cert) + throws CertificateParsingException + { + byte[] extValue = cert.getExtensionValue(oid); + + if (extValue == null) + { + throw new CertificateParsingException("extension " + oid + " not present"); + } + + try + { + ASN1Encodable value = X509ExtensionUtil.fromExtensionValue(extValue); + + this.addExtension(oid, critical, value); + } + catch (IOException e) + { + throw new CertificateParsingException(e.toString()); + } + } + + /** + * add a given extension field for the standard extensions tag (tag 3) + * copying the extension value from another certificate. + * @throws CertificateParsingException if the extension cannot be extracted. + */ + public void copyAndAddExtension( + ASN1ObjectIdentifier oid, + boolean critical, + X509Certificate cert) + throws CertificateParsingException + { + this.copyAndAddExtension(oid.getId(), critical, cert); + } + + /** + * generate an X509 certificate, based on the current issuer and subject + * using the default provider "SC". + * @deprecated use generate(key, "SC") + */ + public X509Certificate generateX509Certificate( + PrivateKey key) + throws SecurityException, SignatureException, InvalidKeyException + { + try + { + return generateX509Certificate(key, "SC", null); + } + catch (NoSuchProviderException e) + { + throw new SecurityException("BC provider not installed!"); + } + } + + /** + * generate an X509 certificate, based on the current issuer and subject + * using the default provider "SC", and the passed in source of randomness + * (if required). + * @deprecated use generate(key, random, "SC") + */ + public X509Certificate generateX509Certificate( + PrivateKey key, + SecureRandom random) + throws SecurityException, SignatureException, InvalidKeyException + { + try + { + return generateX509Certificate(key, "SC", random); + } + catch (NoSuchProviderException e) + { + throw new SecurityException("BC provider not installed!"); + } + } + + /** + * generate an X509 certificate, based on the current issuer and subject, + * using the passed in provider for the signing. + * @deprecated use generate() + */ + public X509Certificate generateX509Certificate( + PrivateKey key, + String provider) + throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException + { + return generateX509Certificate(key, provider, null); + } + + /** + * generate an X509 certificate, based on the current issuer and subject, + * using the passed in provider for the signing and the supplied source + * of randomness, if required. + * @deprecated use generate() + */ + public X509Certificate generateX509Certificate( + PrivateKey key, + String provider, + SecureRandom random) + throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException + { + try + { + return generate(key, provider, random); + } + catch (NoSuchProviderException e) + { + throw e; + } + catch (SignatureException e) + { + throw e; + } + catch (InvalidKeyException e) + { + throw e; + } + catch (NoSuchAlgorithmException e) + { + throw new SecurityException("exception: " + e); + } + catch (GeneralSecurityException e) + { + throw new SecurityException("exception: " + e); + } + } + + /** + * generate an X509 certificate, based on the current issuer and subject + * using the default provider. + * <p> + * <b>Note:</b> this differs from the deprecated method in that the default provider is + * used - not "SC". + * </p> + */ + public X509Certificate generate( + PrivateKey key) + throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException + { + return generate(key, (SecureRandom)null); + } + + /** + * generate an X509 certificate, based on the current issuer and subject + * using the default provider, and the passed in source of randomness + * (if required). + * <p> + * <b>Note:</b> this differs from the deprecated method in that the default provider is + * used - not "SC". + * </p> + */ + public X509Certificate generate( + PrivateKey key, + SecureRandom random) + throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException + { + TBSCertificate tbsCert = generateTbsCert(); + byte[] signature; + + try + { + signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, key, random, tbsCert); + } + catch (IOException e) + { + throw new ExtCertificateEncodingException("exception encoding TBS cert", e); + } + + try + { + return generateJcaObject(tbsCert, signature); + } + catch (CertificateParsingException e) + { + throw new ExtCertificateEncodingException("exception producing certificate object", e); + } + } + + /** + * generate an X509 certificate, based on the current issuer and subject, + * using the passed in provider for the signing. + */ + public X509Certificate generate( + PrivateKey key, + String provider) + throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException + { + return generate(key, provider, null); + } + + /** + * generate an X509 certificate, based on the current issuer and subject, + * using the passed in provider for the signing and the supplied source + * of randomness, if required. + */ + public X509Certificate generate( + PrivateKey key, + String provider, + SecureRandom random) + throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException + { + TBSCertificate tbsCert = generateTbsCert(); + byte[] signature; + + try + { + signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, tbsCert); + } + catch (IOException e) + { + throw new ExtCertificateEncodingException("exception encoding TBS cert", e); + } + + try + { + return generateJcaObject(tbsCert, signature); + } + catch (CertificateParsingException e) + { + throw new ExtCertificateEncodingException("exception producing certificate object", e); + } + } + + private TBSCertificate generateTbsCert() + { + if (!extGenerator.isEmpty()) + { + tbsGen.setExtensions(extGenerator.generate()); + } + + return tbsGen.generateTBSCertificate(); + } + + private X509Certificate generateJcaObject(TBSCertificate tbsCert, byte[] signature) + throws CertificateParsingException + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(tbsCert); + v.add(sigAlgId); + v.add(new DERBitString(signature)); + + return new X509CertificateObject(Certificate.getInstance(new DERSequence(v))); + } + + /** + * Return an iterator of the signature names supported by the generator. + * + * @return an iterator containing recognised names. + */ + public Iterator getSignatureAlgNames() + { + return X509Util.getAlgNames(); + } +} |