diff options
Diffstat (limited to 'prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java')
-rw-r--r-- | prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java | 379 |
1 files changed, 379 insertions, 0 deletions
diff --git a/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java b/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java new file mode 100644 index 00000000..a2462a9a --- /dev/null +++ b/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java @@ -0,0 +1,379 @@ +package org.spongycastle.jcajce.provider.asymmetric.x509; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.security.NoSuchProviderException; +import java.security.cert.CertPath; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +import org.spongycastle.jce.X509Principal; +import org.spongycastle.jce.PrincipalUtil; +import org.spongycastle.asn1.ASN1Encodable; +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1Integer; +import org.spongycastle.asn1.ASN1Primitive; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.DERSet; +import org.spongycastle.asn1.pkcs.ContentInfo; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.pkcs.SignedData; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.util.io.pem.PemObject; +import org.spongycastle.util.io.pem.PemWriter; + +/** + * CertPath implementation for X.509 certificates. + * <br /> + **/ +public class PKIXCertPath + extends CertPath +{ + static final List certPathEncodings; + + static + { + List encodings = new ArrayList(); + encodings.add("PkiPath"); + encodings.add("PEM"); + encodings.add("PKCS7"); + certPathEncodings = Collections.unmodifiableList(encodings); + } + + private List certificates; + + /** + * @param certs + */ + private List sortCerts( + List certs) + { + try + { + if (certs.size() < 2) + { + return certs; + } + + X509Principal issuer = PrincipalUtil.getIssuerX509Principal(((X509Certificate)certs.get(0))); + boolean okay = true; + + for (int i = 1; i != certs.size(); i++) + { + X509Certificate cert = (X509Certificate)certs.get(i); + + if (issuer.equals(PrincipalUtil.getSubjectX509Principal(cert))) + { + issuer = PrincipalUtil.getIssuerX509Principal(((X509Certificate)certs.get(i))); + } + else + { + okay = false; + break; + } + } + + if (okay) + { + return certs; + } + + // find end-entity cert + List retList = new ArrayList(certs.size()); + List orig = new ArrayList(certs); + + for (int i = 0; i < certs.size(); i++) + { + X509Certificate cert = (X509Certificate)certs.get(i); + boolean found = false; + + X509Principal subject = PrincipalUtil.getSubjectX509Principal(cert); + + for (int j = 0; j != certs.size(); j++) + { + X509Certificate c = (X509Certificate)certs.get(j); + if (PrincipalUtil.getIssuerX509Principal(c).equals(subject)) + { + found = true; + break; + } + } + + if (!found) + { + retList.add(cert); + certs.remove(i); + } + } + + // can only have one end entity cert - something's wrong, give up. + if (retList.size() > 1) + { + return orig; + } + + for (int i = 0; i != retList.size(); i++) + { + issuer = PrincipalUtil.getIssuerX509Principal(((X509Certificate)retList.get(i))); + + for (int j = 0; j < certs.size(); j++) + { + X509Certificate c = (X509Certificate)certs.get(j); + if (issuer.equals(PrincipalUtil.getSubjectX509Principal(c))) + { + retList.add(c); + certs.remove(j); + break; + } + } + } + + // make sure all certificates are accounted for. + if (certs.size() > 0) + { + return orig; + } + + return retList; + } + catch (Exception e) + { + return certs; + } + } + + PKIXCertPath(List certificates) + { + super("X.509"); + this.certificates = sortCerts(new ArrayList(certificates)); + } + + /** + * Creates a CertPath of the specified type. + * This constructor is protected because most users should use + * a CertificateFactory to create CertPaths. + **/ + PKIXCertPath( + InputStream inStream, + String encoding) + throws CertificateException + { + super("X.509"); + try + { + if (encoding.equalsIgnoreCase("PkiPath")) + { + ASN1InputStream derInStream = new ASN1InputStream(inStream); + ASN1Primitive derObject = derInStream.readObject(); + if (!(derObject instanceof ASN1Sequence)) + { + throw new CertificateException("input stream does not contain a ASN1 SEQUENCE while reading PkiPath encoded data to load CertPath"); + } + Enumeration e = ((ASN1Sequence)derObject).getObjects(); + certificates = new ArrayList(); + CertificateFactory certFactory = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME); + while (e.hasMoreElements()) + { + ASN1Encodable element = (ASN1Encodable)e.nextElement(); + byte[] encoded = element.toASN1Primitive().getEncoded(ASN1Encoding.DER); + certificates.add(0, certFactory.generateCertificate( + new ByteArrayInputStream(encoded))); + } + } + else if (encoding.equalsIgnoreCase("PKCS7") || encoding.equalsIgnoreCase("PEM")) + { + inStream = new BufferedInputStream(inStream); + certificates = new ArrayList(); + CertificateFactory certFactory= CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME); + Certificate cert; + while ((cert = certFactory.generateCertificate(inStream)) != null) + { + certificates.add(cert); + } + } + else + { + throw new CertificateException("unsupported encoding: " + encoding); + } + } + catch (IOException ex) + { + throw new CertificateException("IOException throw while decoding CertPath:\n" + ex.toString()); + } + catch (NoSuchProviderException ex) + { + throw new CertificateException("BouncyCastle provider not found while trying to get a CertificateFactory:\n" + ex.toString()); + } + + this.certificates = sortCerts(certificates); + } + + /** + * Returns an iteration of the encodings supported by this + * certification path, with the default encoding + * first. Attempts to modify the returned Iterator via its + * remove method result in an UnsupportedOperationException. + * + * @return an Iterator over the names of the supported encodings (as Strings) + **/ + public Iterator getEncodings() + { + return certPathEncodings.iterator(); + } + + /** + * Returns the encoded form of this certification path, using + * the default encoding. + * + * @return the encoded bytes + * @exception java.security.cert.CertificateEncodingException if an encoding error occurs + **/ + public byte[] getEncoded() + throws CertificateEncodingException + { + Iterator iter = getEncodings(); + if (iter.hasNext()) + { + Object enc = iter.next(); + if (enc instanceof String) + { + return getEncoded((String)enc); + } + } + return null; + } + + /** + * Returns the encoded form of this certification path, using + * the specified encoding. + * + * @param encoding the name of the encoding to use + * @return the encoded bytes + * @exception java.security.cert.CertificateEncodingException if an encoding error + * occurs or the encoding requested is not supported + * + **/ + public byte[] getEncoded(String encoding) + throws CertificateEncodingException + { + if (encoding.equalsIgnoreCase("PkiPath")) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + ListIterator iter = certificates.listIterator(certificates.size()); + while (iter.hasPrevious()) + { + v.add(toASN1Object((X509Certificate)iter.previous())); + } + + return toDEREncoded(new DERSequence(v)); + } + else if (encoding.equalsIgnoreCase("PKCS7")) + { + ContentInfo encInfo = new ContentInfo(PKCSObjectIdentifiers.data, null); + + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i = 0; i != certificates.size(); i++) + { + v.add(toASN1Object((X509Certificate)certificates.get(i))); + } + + SignedData sd = new SignedData( + new ASN1Integer(1), + new DERSet(), + encInfo, + new DERSet(v), + null, + new DERSet()); + + return toDEREncoded(new ContentInfo( + PKCSObjectIdentifiers.signedData, sd)); + } + else if (encoding.equalsIgnoreCase("PEM")) + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + PemWriter pWrt = new PemWriter(new OutputStreamWriter(bOut)); + + try + { + for (int i = 0; i != certificates.size(); i++) + { + pWrt.writeObject(new PemObject("CERTIFICATE", ((X509Certificate)certificates.get(i)).getEncoded())); + } + + pWrt.close(); + } + catch (Exception e) + { + throw new CertificateEncodingException("can't encode certificate for PEM encoded path"); + } + + return bOut.toByteArray(); + } + else + { + throw new CertificateEncodingException("unsupported encoding: " + encoding); + } + } + + /** + * Returns the list of certificates in this certification + * path. The List returned must be immutable and thread-safe. + * + * @return an immutable List of Certificates (may be empty, but not null) + **/ + public List getCertificates() + { + return Collections.unmodifiableList(new ArrayList(certificates)); + } + + /** + * Return a DERObject containing the encoded certificate. + * + * @param cert the X509Certificate object to be encoded + * + * @return the DERObject + **/ + private ASN1Primitive toASN1Object( + X509Certificate cert) + throws CertificateEncodingException + { + try + { + return new ASN1InputStream(cert.getEncoded()).readObject(); + } + catch (Exception e) + { + throw new CertificateEncodingException("Exception while encoding certificate: " + e.toString()); + } + } + + private byte[] toDEREncoded(ASN1Encodable obj) + throws CertificateEncodingException + { + try + { + return obj.toASN1Primitive().getEncoded(ASN1Encoding.DER); + } + catch (IOException e) + { + throw new CertificateEncodingException("Exception thrown: " + e); + } + } +} |