Index: gnu/java/security/provider/Gnu.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/security/provider/Gnu.java,v retrieving revision 1.5 diff -u -b -B -r1.5 Gnu.java --- gnu/java/security/provider/Gnu.java 23 Apr 2003 22:59:42 -0000 1.5 +++ gnu/java/security/provider/Gnu.java 7 Nov 2004 19:25:52 -0000 @@ -37,14 +37,21 @@ package gnu.java.security.provider; + +import java.security.AccessController; +import java.security.PrivilegedAction; import java.security.Provider; public final class Gnu extends Provider { public Gnu() { - super("GNU", 1.0, "GNU provider v1.0 implementing SHA-1, MD5, DSA, X.509 Certificates"); + super("GNU", 1.0, "GNU provider v1.0 implementing SHA-1, MD5, DSA, RSA, X.509 Certificates and CRLs, PKIX certificate path validators, Collection cert stores"); + AccessController.doPrivileged (new PrivilegedAction() + { + public Object run() + { // Note that all implementation class names are referenced by using // Class.getName(). That way when we staticly link the Gnu provider // we automatically get all the implementation classes. @@ -66,6 +73,30 @@ put("Alg.Alias.Signature.1.3.14.3.2.13", "SHA1withDSA"); put("Alg.Alias.Signature.1.3.14.3.2.27", "SHA1withDSA"); + put("Signature.MD2withRSA", MD2withRSA.class.getName()); + put("Signature.MD2withRSA ImplementedIn", "Software"); + put("Alg.Alias.Signature.md2WithRSAEncryption", "MD2withRSA"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.2", "MD2withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.2", "MD2withRSA"); + + put("Signature.MD4withRSA", MD4withRSA.class.getName()); + put("Signature.MD4withRSA ImplementedIn", "Software"); + put("Alg.Alias.Signature.md4WithRSAEncryption", "MD4withRSA"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.3", "MD4withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.3", "MD4withRSA"); + + put("Signature.MD5withRSA", MD5withRSA.class.getName()); + put("Signature.MD5withRSA ImplementedIn", "Software"); + put("Alg.Alias.Signature.md5WithRSAEncryption", "MD5withRSA"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.4", "MD5withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5withRSA"); + + put("Signature.SHA1withRSA", SHA1withRSA.class.getName()); + put("Signature.SHA1withRSA ImplementedIn", "Software"); + put("Alg.Alias.Signature.sha-1WithRSAEncryption", "SHA1withRSA"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.5", "SHA1withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1withRSA"); + // Key Pair Generator put("KeyPairGenerator.DSA", gnu.java.security.provider.DSAKeyPairGenerator.class.getName()); @@ -78,6 +109,15 @@ put("KeyFactory.DSA", gnu.java.security.provider.DSAKeyFactory.class.getName()); + put("KeyFactory.Encoded", EncodedKeyFactory.class.getName()); + put("KeyFactory.Encoded ImplementedIn", "Software"); + put("Alg.Alias.KeyFactory.X.509", "Encoded"); + put("Alg.Alias.KeyFactory.X509", "Encoded"); + put("Alg.Alias.KeyFactory.PKCS#8", "Encoded"); + put("Alg.Alias.KeyFactory.PKCS8", "Encoded"); + + put("KeyFactory.RSA", RSAKeyFactory.class.getName()); + put("Alg.Alias.KeyFactory.OID.1.2.840.10040.4.1", "DSA"); put("Alg.Alias.KeyFactory.1.2.840.10040.4.1", "DSA"); put("Alg.Alias.KeyFactory.1.3.14.3.2.12", "DSA"); @@ -94,6 +134,11 @@ put("AlgorithmParameters.DSA", gnu.java.security.provider.DSAParameters.class.getName()); + put("Alg.Alias.AlgorithmParameters.DSS", "DSA"); + put("Alg.Alias.AlgorithmParameters.SHAwithDSA", "DSA"); + put("Alg.Alias.AlgorithmParameters.OID.1.2.840.10040.4.3", "DSA"); + put("Alg.Alias.AlgorithmParameters.1.2.840.10040.4.3", "DSA"); + // Algorithm Parameter Generator put("AlgorithmParameterGenerator.DSA", gnu.java.security.provider.DSAParameterGenerator.class.getName()); @@ -103,9 +148,20 @@ gnu.java.security.provider.SHA1PRNG.class.getName()); // CertificateFactory - put("CertificateFactory.X.509", - gnu.java.security.provider.X509CertificateFactory.class.getName()); + put("CertificateFactory.X509", X509CertificateFactory.class.getName()); + + put("CertificateFactory.X509 ImplementedIn", "Software"); + put("Alg.Alias.CertificateFactory.X.509", "X509"); + + // CertPathValidator + put("CertPathValidator.PKIX", PKIXCertPathValidatorImpl.class.getName()); + put("CertPathValidator.PKIX ImplementedIn", "Software"); - put("Alg.Alias.CertificateFactory.X509", "X.509"); + // CertStore + put("CertStore.Collection", CollectionCertStoreImpl.class.getName()); + + return null; + } + }); } } Index: gnu/java/security/provider/X509CertificateFactory.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/security/provider/X509CertificateFactory.java,v retrieving revision 1.1 diff -u -b -B -r1.1 X509CertificateFactory.java --- gnu/java/security/provider/X509CertificateFactory.java 23 Apr 2003 22:59:42 -0000 1.1 +++ gnu/java/security/provider/X509CertificateFactory.java 7 Nov 2004 19:25:52 -0000 @@ -44,16 +44,21 @@ import java.io.IOException; import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactorySpi; +import java.security.cert.CertPath; import java.security.cert.CRL; import java.security.cert.CRLException; import java.util.Collection; +import java.util.Iterator; import java.util.LinkedList; +import java.util.List; import gnu.java.io.Base64InputStream; import gnu.java.security.x509.X509Certificate; +import gnu.java.security.x509.X509CertPath; import gnu.java.security.x509.X509CRL; public class X509CertificateFactory extends CertificateFactorySpi @@ -87,7 +92,9 @@ } catch (IOException ioe) { - throw new CertificateException(ioe.toString()); + CertificateException ce = new CertificateException(ioe.getMessage()); + ce.initCause (ioe); + throw ce; } } @@ -107,7 +114,9 @@ } catch (IOException ioe) { - throw new CertificateException(ioe.toString()); + CertificateException ce = new CertificateException(ioe.getMessage()); + ce.initCause (ioe); + throw ce; } } return certs; @@ -121,7 +130,9 @@ } catch (IOException ioe) { - throw new CRLException(ioe.toString()); + CRLException crle = new CRLException(ioe.getMessage()); + crle.initCause (ioe); + throw crle; } } @@ -141,18 +152,44 @@ } catch (IOException ioe) { - throw new CRLException(ioe.toString()); + CRLException crle = new CRLException(ioe.getMessage()); + crle.initCause (ioe); + throw crle; } } return crls; } + public CertPath engineGenerateCertPath(List certs) + { + return new X509CertPath(certs); + } + + public CertPath engineGenerateCertPath(InputStream in) + throws CertificateEncodingException + { + return new X509CertPath(in); + } + + public CertPath engineGenerateCertPath(InputStream in, String encoding) + throws CertificateEncodingException + { + return new X509CertPath(in, encoding); + } + + public Iterator engineGetCertPathEncodings() + { + return X509CertPath.ENCODINGS.iterator(); + } + // Own methods. // ------------------------------------------------------------------------ private X509Certificate generateCert(InputStream inStream) throws IOException, CertificateException { + if (inStream == null) + throw new CertificateException("missing input stream"); if (!inStream.markSupported()) inStream = new BufferedInputStream(inStream, 8192); inStream.mark(20); @@ -211,6 +248,8 @@ private X509CRL generateCRL(InputStream inStream) throws IOException, CRLException { + if (inStream == null) + throw new CRLException("missing input stream"); if (!inStream.markSupported()) inStream = new BufferedInputStream(inStream, 8192); inStream.mark(20); Index: gnu/java/security/x509/X500DistinguishedName.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/security/x509/X500DistinguishedName.java,v retrieving revision 1.2 diff -u -b -B -r1.2 X500DistinguishedName.java --- gnu/java/security/x509/X500DistinguishedName.java 13 Oct 2004 14:32:34 -0000 1.2 +++ gnu/java/security/x509/X500DistinguishedName.java 7 Nov 2004 19:25:52 -0000 @@ -1,5 +1,5 @@ -/* X500DistinguishedName.java -- X.500 name. - Copyright (C) 2003, 2004 Free Software Foundation, Inc. +/* X500DistinguishedName.java -- X.500 distinguished name. + Copyright (C) 2004 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,121 +38,35 @@ package gnu.java.security.x509; -import gnu.java.io.ASN1ParsingException; -import gnu.java.security.OID; -import gnu.java.security.der.DER; -import gnu.java.security.der.DERReader; -import gnu.java.security.der.DERValue; -import gnu.java.security.der.DERWriter; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; +import java.io.EOFException; import java.io.InputStream; import java.io.IOException; -import java.io.StreamTokenizer; +import java.io.Reader; import java.io.StringReader; + +import java.security.Principal; + +import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; -/** - * A X.500 distinguished name. Distinguished names are sequences of - * ATTRIB=VALUE pairs, where ATTRIB is one of the following: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
NameX.500 AttributeTypeObjectIdentifier
CNcommonName2.5.4.3
CcountryName2.5.4.6
LlocalityName2.5.4.7
STstateOrProvinceName2.5.4.8
STREETstreetAddress2.5.4.9
OorganizationName2.5.4.10
OUorganizationUnitName2.5.4.11
DCdomainComponent0.9.2342.19200300.100.1.25
UIDuserid
DNQ or DNQUALIFIER(*)domainNameQualifier2.5.4.46
SURNAME(*)name2.5.4.41
GIVENNAME(*)givenName2.5.4.42
INITIALS(*)initials2.5.4.43
EMAILADDRESS(*)emailAddress2.5.4.44
- * - *

(*) = attributes not specified in RFC1779 or RFC2253, but - * recognized anyway. - * - *

Distinguished names of this form are used in the lightweight - * directory access protocol (LDAP) and in the issuer and subject fields - * of X.509 certificates. - * - * @author Casey Marshall (address@hidden) - * @see javax.security.auth.x500.X500Principal - * @status DER decoding/encoding works, RFC1779 and RFC2253 need to be - * made more robust. - */ -public class X500DistinguishedName +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.OID; + +public class X500DistinguishedName implements Principal { // Constants and fields. - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- public static final OID CN = new OID("2.5.4.3"); public static final OID C = new OID("2.5.4.6"); @@ -171,651 +85,467 @@ public static final OID DC = new OID("0.9.2342.19200300.100.1.25"); public static final OID UID = new OID("0.9.2342.19200300.100.1.1"); - private String commonName; - private String country; - private String locality; - private String orgUnit; - private String organization; - private String street; - private String state; - private String title; - private String dnQualifier; - private String surname; - private String givenName; - private String initials; - private String generation; - private String email; - private String domainComponent; - private String userid; - - private String nameRFC1779; - private String nameRFC2253; - private String nameCanonical; - - private transient byte[] encoded; + private List components; + private Map currentRdn; + private boolean fixed; + private String stringRep; + private byte[] encoded; // Constructors. - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- + + public X500DistinguishedName() + { + components = new LinkedList(); + currentRdn = new LinkedHashMap(); + components.add(currentRdn); + } - /** - * Create a new X500DistinguishedName from the RFC1779 or RFC2253 - * encoded form. - * - * @param name The encoded name. - * @throws IllegalArgumentException If the name cannot be parsed. - */ public X500DistinguishedName(String name) { - if (name == null) - throw new NullPointerException(); + this(); try { - parseDN(name, true); + parseString(name); } - catch (Exception e) + catch (IOException ioe) { - parseDN(name, false); + throw new IllegalArgumentException(ioe.toString()); } } - /** - * Create a new X500DistinguishedName from the DER encoded bytes. - * - * @param encoded The encoded form. - * @throws IOException If the bytes are not a valid DER construct. - */ public X500DistinguishedName(byte[] encoded) throws IOException { - this(new ByteArrayInputStream(encoded)); + this(); + parseDer(new DERReader(encoded)); } - /** - * Create a new X500DistinguishedName from the DER encoded bytes. - * - * @param encoded The encoded form. - * @throws IOException If the bytes are not a valid DER construct. - */ public X500DistinguishedName(InputStream encoded) throws IOException { - parseDER(encoded); + this(); + parseDer(new DERReader(encoded)); } // Instance methods. - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- - public boolean equals(Object o) + public String getName() { - return - (commonName != null && - commonName.equals(((X500DistinguishedName) o).commonName)) && - (country != null && - country.equals(((X500DistinguishedName) o).country)) && - (locality != null && - locality.equals(((X500DistinguishedName) o).locality)) && - (orgUnit != null && - orgUnit.equals(((X500DistinguishedName) o).orgUnit)) && - (organization != null && - organization.equals(((X500DistinguishedName) o).organization)) && - (street != null && - street.equals(((X500DistinguishedName) o).street)) && - (state != null && - state.equals(((X500DistinguishedName) o).state)) && - (domainComponent != null && - domainComponent.equals(((X500DistinguishedName) o).domainComponent)) && - (title != null && - title.equals(((X500DistinguishedName) o).title)) && - (dnQualifier != null && - dnQualifier.equals(((X500DistinguishedName) o).dnQualifier)) && - (surname != null && - surname.equals(((X500DistinguishedName) o).surname)) && - (givenName != null && - givenName.equals(((X500DistinguishedName) o).givenName)) && - (initials != null && - initials.equals(((X500DistinguishedName) o).initials)) && - (generation != null && - generation.equals(((X500DistinguishedName) o).generation)) && - (email != null && - email.equals(((X500DistinguishedName) o).email)) && - (userid != null && - userid.equals(((X500DistinguishedName) o).userid)); + return toString(); } - public byte[] getEncoded() + public void newRelativeDistinguishedName() { - if (encoded == null) - encoded = encodeDER(); - return (byte[]) encoded.clone(); + if (fixed || currentRdn.isEmpty()) return; + currentRdn = new LinkedHashMap(); + components.add(currentRdn); } - private static String quote(String str) + public int size() { - if (str.indexOf(" ") > 0 || str.indexOf("\f") > 0 || - str.indexOf("\n") > 0 || str.indexOf("\r") > 0 || - str.indexOf("\t") > 0) - str = '"' + str + '"'; - // XXX needs regex - //return str.replaceAll("([,+\"\\<>;])", "\\\1"); - return str; + return components.size(); } - public String toRFC1779() + public int countComponents() { - if (nameRFC1779 != null) - return nameRFC1779; - StringBuffer buf = new StringBuffer(); - if (commonName != null) - buf.append("CN=").append(quote(commonName)).append(", "); - if (country != null) - buf.append("C=").append(quote(country)).append(", "); - if (locality != null) - buf.append("L=").append(quote(locality)).append(", "); - if (orgUnit != null) - buf.append("OU=").append(quote(orgUnit)).append(", "); - if (organization != null) - buf.append("O=").append(quote(organization)).append(", "); - if (street != null) - buf.append("STREET=").append(quote(street)).append(", "); - if (state != null) - buf.append("ST=").append(quote(state)).append(", "); - if (title != null) - buf.append(T).append("=").append(quote(title)).append(", "); - if (dnQualifier != null) - buf.append(DNQ).append("=").append(quote(dnQualifier)).append(", "); - if (surname != null) - buf.append(NAME).append("=").append(quote(surname)).append(", "); - if (givenName != null) - buf.append(GIVENNAME).append("=").append(quote(givenName)).append(", "); - if (initials != null) - buf.append(INITIALS).append("=").append(quote(initials)).append(", "); - if (generation != null) - buf.append(GENERATION).append("=").append(quote(generation)).append(", "); - if (email != null) - buf.append(EMAIL).append("=").append(quote(email)).append(", "); - if (domainComponent != null) - buf.append(DC).append("=").append(quote(domainComponent)).append(", "); - if (userid != null) - buf.append(UID).append("=").append(quote(userid)).append(", "); - // XXX escapes - return (nameRFC1779 = buf.substring(0, buf.length()-2)); - } - - public String toRFC2253() + int count = 0; + for (Iterator it = components.iterator(); it.hasNext(); ) { - if (nameRFC2253 != null) - return nameRFC2253; - StringBuffer buf = new StringBuffer(); - if (commonName != null) - buf.append("CN=").append(quote(commonName)).append(","); - if (country != null) - buf.append("C=").append(quote(country)).append(","); - if (locality != null) - buf.append("L=").append(quote(locality)).append(","); - if (orgUnit != null) - buf.append("OU=").append(quote(orgUnit)).append(","); - if (organization != null) - buf.append("O=").append(quote(organization)).append(","); - if (street != null) - buf.append("STREET=").append(quote(street)).append(","); - if (state != null) - buf.append("ST=").append(quote(state)).append(","); - if (title != null) - buf.append(T).append("=").append(quote(title)).append(","); - if (dnQualifier != null) - buf.append(DNQ).append("=").append(quote(dnQualifier)).append(","); - if (surname != null) - buf.append(NAME).append("=").append(quote(surname)).append(","); - if (givenName != null) - buf.append(GIVENNAME).append("=").append(quote(givenName)).append(","); - if (initials != null) - buf.append(INITIALS).append("=").append(quote(initials)).append(","); - if (generation != null) - buf.append(GENERATION).append("=").append(quote(generation)).append(","); - if (email != null) - buf.append(EMAIL).append("=").append(quote(email)).append(","); - if (domainComponent != null) - buf.append(DC).append("=").append(quote(domainComponent)).append(","); - if (userid != null) - buf.append(UID).append("=").append(quote(userid)).append(","); - // XXX escapes. - return (nameRFC2253 = buf.substring(0, buf.length()-1)); + count += ((Map) it.next()).size(); } - - public String toCanonical() - { - if (nameCanonical != null) - return nameCanonical; - nameCanonical = toRFC2253(); - return nameCanonical; // XXX canonicalize + return count; } - public String getCommonName() + public boolean containsComponent(OID oid, String value) { - return commonName; - } - - public String getCountry() + for (Iterator it = components.iterator(); it.hasNext(); ) { - return country; + Map rdn = (Map) it.next(); + String s = (String) rdn.get(oid); + if (s == null) + continue; + if (compressWS(value).equalsIgnoreCase(compressWS(s))) + return true; } - - public String getLocality() - { - return locality; + return false; } - public String getOrganizationalUnit() + public String getComponent(OID oid) { - return orgUnit; - } - - public String getOrganization() + for (Iterator it = components.iterator(); it.hasNext(); ) { - return organization; + Map rdn = (Map) it.next(); + if (rdn.containsKey(oid)) + return (String) rdn.get(oid); } - - public String getStreet() - { - return street; + return null; } - public String getState() + public String getComponent(OID oid, int rdn) { - return state; + if (rdn >= size()) + return null; + return (String) ((Map) components.get(rdn)).get(oid); } - public String getTitle() + public void putComponent(OID oid, String value) { - return title; + currentRdn.put(oid, value); } - public String getDNQualifier() + public void putComponent(String name, String value) { - return dnQualifier; + name = name.trim().toLowerCase(); + if (name.equals("cn")) + putComponent(CN, value); + else if (name.equals("c")) + putComponent(C, value); + else if (name.equals("l")) + putComponent(L, value); + else if (name.equals("street")) + putComponent(STREET, value); + else if (name.equals("st")) + putComponent(ST, value); + else if (name.equals("t")) + putComponent(T, value); + else if (name.equals("dnq")) + putComponent(DNQ, value); + else if (name.equals("name")) + putComponent(NAME, value); + else if (name.equals("givenname")) + putComponent(GIVENNAME, value); + else if (name.equals("initials")) + putComponent(INITIALS, value); + else if (name.equals("generation")) + putComponent(GENERATION, value); + else if (name.equals("email")) + putComponent(EMAIL, value); + else if (name.equals("dc")) + putComponent(DC, value); + else if (name.equals("uid")) + putComponent(UID, value); + else + putComponent(new OID(name), value); } - public String getSurname() + public void setUnmodifiable() { - return surname; + if (fixed) return; + fixed = true; + List newComps = new ArrayList(components.size()); + for (Iterator it = components.iterator(); it.hasNext(); ) + { + Map rdn = (Map) it.next(); + rdn = Collections.unmodifiableMap(rdn); + newComps.add(rdn); + } + components = Collections.unmodifiableList(newComps); + currentRdn = Collections.EMPTY_MAP; } - public String getGivenName() + public int hashCode() + { + int sum = 0; + for (Iterator it = components.iterator(); it.hasNext(); ) { - return givenName; + Map m = (Map) it.next(); + for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); ) + { + Map.Entry e = (Map.Entry) it2.next(); + sum += e.getKey().hashCode(); + sum += e.getValue().hashCode(); + } + } + return sum; } - public String getInitials() + public boolean equals(Object o) { - return initials; + if (!(o instanceof X500DistinguishedName)) + return false; + if (size() != ((X500DistinguishedName) o).size()) + return false; + for (int i = 0; i < size(); i++) + { + Map m = (Map) components.get(i); + for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); ) + { + Map.Entry e = (Map.Entry) it2.next(); + OID oid = (OID) e.getKey(); + String v1 = (String) e.getValue(); + String v2 = ((X500DistinguishedName) o).getComponent(oid, i); + if (!compressWS(v1).equalsIgnoreCase(compressWS(v2))) + return false; + } + } + return true; + } + + public String toString() + { + if (fixed && stringRep != null) + return stringRep; + StringBuffer str = new StringBuffer(); + for (Iterator it = components.iterator(); it.hasNext(); ) + { + Map m = (Map) it.next(); + for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); ) + { + Map.Entry entry = (Map.Entry) it2.next(); + OID oid = (OID) entry.getKey(); + String value = (String) entry.getValue(); + if (oid.equals(CN)) + str.append("CN"); + else if (oid.equals(C)) + str.append("C"); + else if (oid.equals(L)) + str.append("L"); + else if (oid.equals(ST)) + str.append("ST"); + else if (oid.equals(STREET)) + str.append("STREET"); + else if (oid.equals(O)) + str.append("O"); + else if (oid.equals(OU)) + str.append("OU"); + else if (oid.equals(T)) + str.append("T"); + else if (oid.equals(DNQ)) + str.append("DNQ"); + else if (oid.equals(NAME)) + str.append("NAME"); + else + str.append(oid.toString()); + str.append('='); + str.append(value); + if (it2.hasNext()) + str.append("+"); + } + if (it.hasNext()) + str.append(','); + } + return (stringRep = str.toString()); } - public String getGeneration() + public byte[] getDer() { - return generation; + if (fixed && encoded != null) + return (byte[]) encoded.clone(); + ArrayList name = new ArrayList(components.size()); + for (Iterator it = components.iterator(); it.hasNext(); ) + { + Map m = (Map) it.next(); + if (m.isEmpty()) + continue; + Set rdn = new HashSet(); + for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); ) + { + Map.Entry e = (Map.Entry) it.next(); + ArrayList atav = new ArrayList(2); + atav.add(new DERValue(DER.OBJECT_IDENTIFIER, e.getKey())); + atav.add(new DERValue(DER.UTF8_STRING, e.getValue())); + rdn.add(new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, atav)); + } + name.add(new DERValue(DER.SET|DER.CONSTRUCTED, rdn)); } + DERValue val = new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, name); + return (byte[]) (encoded = val.getEncoded()).clone(); + } + + // Own methods. + // ------------------------------------------------------------------------- - public String getEmail() + private int sep; + + private void parseString(String str) throws IOException + { + Reader in = new StringReader(str); + while (true) { - return email; + String key = readAttributeType(in); + if (key == null) + break; + String value = readAttributeValue(in); + putComponent(key, value); + if (sep == ',') + newRelativeDistinguishedName(); + } + setUnmodifiable(); } - public String getDomain() + private String readAttributeType(Reader in) throws IOException + { + StringBuffer buf = new StringBuffer(); + int ch; + while ((ch = in.read()) != '=') { - return domainComponent; + if (ch == -1) + { + if (buf.length() > 0) + throw new EOFException(); + return null; + } + if (ch > 127) + throw new IOException("Invalid char: " + (char) ch); + if (Character.isLetterOrDigit((char) ch) || ch == '-' || ch == '.') + buf.append((char) ch); + else + throw new IOException("Invalid char: " + (char) ch); + } + return buf.toString(); } - public String getUserID() + private String readAttributeValue(Reader in) throws IOException { - return userid; + StringBuffer buf = new StringBuffer(); + int ch = in.read(); + if (ch == '#') + { + while (true) + { + ch = in.read(); + if (('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F') + || Character.isDigit((char) ch)) + buf.append((char) ch); + else if (ch == '+' || ch == ',') + { + sep = ch; + String hex = buf.toString(); + return new String(Util.toByteArray(hex)); } - - // Own methods. - // ------------------------------------------------------------------------ - - private static String unquote(String str) + else + throw new IOException("illegal character: " + (char) ch); + } + } + else if (ch == '"') { - if (str.startsWith("\"") && str.endsWith("\"")) - str = str.substring(1, str.length()-1); - // XXX needs regex - //return str.replaceAll("\\([,+\"\\<>;])", "\1"); - return str; - } - - private void parseDN(String name, boolean rfc2253) - { - if (name.length() == 0) - throw new IllegalArgumentException("zero-length distinguished name"); - StreamTokenizer parse = new StreamTokenizer(new StringReader(name)); - parse.resetSyntax(); - parse.wordChars('\000', '~'); - parse.ordinaryChar('#'); - parse.ordinaryChar(','); - parse.ordinaryChar('='); - parse.ordinaryChar('<'); - parse.ordinaryChar('>'); - parse.ordinaryChar(';'); - parse.ordinaryChar('\\'); - parse.quoteChar('"'); - String attrib = null; - String value = null; - int token, lastToken = ','; while (true) { - try + ch = in.read(); + if (ch == '"') + break; + else if (ch == '\\') { - token = parse.nextToken(); + ch = in.read(); + if (ch == -1) + throw new EOFException(); + if (('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F') + || Character.isDigit((char) ch)) + { + int i = Character.digit((char) ch, 16) << 4; + ch = in.read(); + if (!(('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F') + || Character.isDigit((char) ch))) + throw new IOException("illegal hex char"); + i |= Character.digit((char) ch, 16); + buf.append((char) i); } - catch (IOException ioe) - { - throw new IllegalArgumentException(); + else + buf.append((char) ch); } - switch (token) - { - case StreamTokenizer.TT_WORD: - if (lastToken == ',' || lastToken == '+' || - (!rfc2253 && lastToken == ';')) - attrib = parse.sval.trim(); - else if (lastToken == '=') - value = unquote(parse.sval.trim()); else - throw new IllegalArgumentException(); - break; - case '"': - if (lastToken == '=') - value = parse.sval; + buf.append((char) ch); + } + sep = in.read(); + if (sep != '+' || sep != ',') + throw new IOException("illegal character: " + (char) ch); + return buf.toString(); + } else - throw new IllegalArgumentException(); - break; - case ';': - if (rfc2253) - throw new IllegalArgumentException(); - case ',': - case '+': - if (attrib == null || value == null) - throw new IllegalArgumentException("extraneous separator"); - try { - setAttribute(new OID(attrib), value); - } - catch (Exception x) + while (true) { - setAttribute(attrib, value); + switch (ch) + { + case '+': + case ',': + sep = ch; + return buf.toString(); + case '\\': + ch = in.read(); + if (ch == -1) + throw new EOFException(); + if (('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F') + || Character.isDigit((char) ch)) + { + int i = Character.digit((char) ch, 16) << 4; + ch = in.read(); + if (!(('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F') + || Character.isDigit((char) ch))) + throw new IOException("illegal hex char"); + i |= Character.digit((char) ch, 16); + buf.append((char) i); } - attrib = null; - value = null; + else + buf.append((char) ch); break; case '=': - break; - case StreamTokenizer.TT_EOF: - return; + case '<': + case '>': + case '#': + case ';': + throw new IOException("illegal character: " + (char) ch); + case -1: + throw new EOFException(); default: - throw new IllegalArgumentException("unknown token " + (char)token - + " (" + token + ")"); + buf.append((char) ch); + } } - lastToken = token; } } - private void parseDER(InputStream in) throws IOException + private void parseDer(DERReader der) throws IOException { - DERReader der = new DERReader(in); DERValue name = der.read(); if (!name.isConstructed()) - throw new ASN1ParsingException("badly formed Name"); + throw new IOException("malformed Name"); + encoded = name.getEncoded(); int len = 0; while (len < name.getLength()) { DERValue rdn = der.read(); - if (rdn.getValue() != DER.CONSTRUCTED_VALUE) - throw new ASN1ParsingException("badly formed RDNSequence"); + if (!rdn.isConstructed()) + throw new IOException("badly formed RDNSequence"); int len2 = 0; while (len2 < rdn.getLength()) { DERValue atav = der.read(); - if (atav.getValue() != DER.CONSTRUCTED_VALUE) - throw new ASN1ParsingException( - "badly formed AttributeTypeAndValue"); - OID atype = (OID) der.read().getValue(); - String aval = (String) der.read().getValue(); - setAttribute(atype, aval); - len2 += 1 + atav.getLength() - + DERWriter.definiteEncodingSize(atav.getLength()); - } - len += len2 + 1 + DERWriter.definiteEncodingSize(name.getLength()); + if (!atav.isConstructed()) + throw new IOException("badly formed AttributeTypeAndValue"); + DERValue val = der.read(); + if (val.getTag() != DER.OBJECT_IDENTIFIER) + throw new IOException("badly formed AttributeTypeAndValue"); + OID oid = (OID) val.getValue(); + val = der.read(); + if (!(val.getValue() instanceof String)) + throw new IOException("badly formed AttributeTypeAndValue"); + String value = (String) val.getValue(); + putComponent(oid, value); + len2 += atav.getEncodedLength(); + } + len += rdn.getEncodedLength(); + if (len < name.getLength()) + newRelativeDistinguishedName(); } + setUnmodifiable(); } - private byte[] encodeDER() - { - try + private static String compressWS(String str) { - LinkedList name = new LinkedList(); - if (commonName != null) + StringBuffer buf = new StringBuffer(); + char lastChar = 0; + for (int i = 0; i < str.length(); i++) { - HashSet rdn = new HashSet(); - LinkedList atav = new LinkedList(); - atav.add(new DERValue(DER.OBJECT_IDENTIFIER, CN)); - atav.add(new DERValue(DER.PRINTABLE_STRING, commonName)); - rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav)); - name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn)); - } - if (country != null) - { - HashSet rdn = new HashSet(); - LinkedList atav = new LinkedList(); - atav.add(new DERValue(DER.OBJECT_IDENTIFIER, C)); - atav.add(new DERValue(DER.PRINTABLE_STRING, country)); - rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav)); - name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn)); - } - if (locality != null) - { - HashSet rdn = new HashSet(); - LinkedList atav = new LinkedList(); - atav.add(new DERValue(DER.OBJECT_IDENTIFIER, L)); - atav.add(new DERValue(DER.PRINTABLE_STRING, locality)); - rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav)); - name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn)); - } - if (orgUnit != null) - { - HashSet rdn = new HashSet(); - LinkedList atav = new LinkedList(); - atav.add(new DERValue(DER.OBJECT_IDENTIFIER, OU)); - atav.add(new DERValue(DER.PRINTABLE_STRING, orgUnit)); - rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav)); - name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn)); - } - if (organization != null) - { - HashSet rdn = new HashSet(); - LinkedList atav = new LinkedList(); - atav.add(new DERValue(DER.OBJECT_IDENTIFIER, O)); - atav.add(new DERValue(DER.PRINTABLE_STRING, organization)); - rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav)); - name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn)); - } - if (street != null) - { - HashSet rdn = new HashSet(); - LinkedList atav = new LinkedList(); - atav.add(new DERValue(DER.OBJECT_IDENTIFIER, STREET)); - atav.add(new DERValue(DER.PRINTABLE_STRING, street)); - rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav)); - name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn)); - } - if (state != null) - { - HashSet rdn = new HashSet(); - LinkedList atav = new LinkedList(); - atav.add(new DERValue(DER.OBJECT_IDENTIFIER, ST)); - atav.add(new DERValue(DER.PRINTABLE_STRING, state)); - rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav)); - name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn)); - } - if (title != null) - { - HashSet rdn = new HashSet(); - LinkedList atav = new LinkedList(); - atav.add(new DERValue(DER.OBJECT_IDENTIFIER, T)); - atav.add(new DERValue(DER.PRINTABLE_STRING, title)); - rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav)); - name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn)); - } - if (dnQualifier != null) - { - HashSet rdn = new HashSet(); - LinkedList atav = new LinkedList(); - atav.add(new DERValue(DER.OBJECT_IDENTIFIER, DNQ)); - atav.add(new DERValue(DER.PRINTABLE_STRING, dnQualifier)); - rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav)); - name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn)); - } - if (surname != null) - { - HashSet rdn = new HashSet(); - LinkedList atav = new LinkedList(); - atav.add(new DERValue(DER.OBJECT_IDENTIFIER, NAME)); - atav.add(new DERValue(DER.PRINTABLE_STRING, surname)); - rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav)); - name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn)); - } - if (givenName != null) - { - HashSet rdn = new HashSet(); - LinkedList atav = new LinkedList(); - atav.add(new DERValue(DER.OBJECT_IDENTIFIER, GIVENNAME)); - atav.add(new DERValue(DER.PRINTABLE_STRING, givenName)); - rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav)); - name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn)); - } - if (initials != null) - { - HashSet rdn = new HashSet(); - LinkedList atav = new LinkedList(); - atav.add(new DERValue(DER.OBJECT_IDENTIFIER, INITIALS)); - atav.add(new DERValue(DER.PRINTABLE_STRING, initials)); - rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav)); - name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn)); - } - if (generation != null) - { - HashSet rdn = new HashSet(); - LinkedList atav = new LinkedList(); - atav.add(new DERValue(DER.OBJECT_IDENTIFIER, GENERATION)); - atav.add(new DERValue(DER.PRINTABLE_STRING, generation)); - rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav)); - name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn)); - } - if (email != null) - { - HashSet rdn = new HashSet(); - LinkedList atav = new LinkedList(); - atav.add(new DERValue(DER.OBJECT_IDENTIFIER, EMAIL)); - atav.add(new DERValue(DER.PRINTABLE_STRING, email)); - rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav)); - name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn)); - } - if (domainComponent != null) - { - HashSet rdn = new HashSet(); - LinkedList atav = new LinkedList(); - atav.add(new DERValue(DER.OBJECT_IDENTIFIER, DC)); - atav.add(new DERValue(DER.PRINTABLE_STRING, domainComponent)); - rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav)); - name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn)); - } - if (userid != null) - { - HashSet rdn = new HashSet(); - LinkedList atav = new LinkedList(); - atav.add(new DERValue(DER.OBJECT_IDENTIFIER, UID)); - atav.add(new DERValue(DER.PRINTABLE_STRING, userid)); - rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav)); - name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn)); - } - ByteArrayOutputStream out = new ByteArrayOutputStream(); - DERWriter.write(out, new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, name)); - return out.toByteArray(); - } - catch (IOException ioe) + char c = str.charAt(i); + if (Character.isWhitespace(c)) { - throw new Error(ioe); + if (!Character.isWhitespace(lastChar)) + buf.append(' '); } - } - - private void setAttribute(String atype, String aval) - { - if (atype.equals("CN")) - commonName = aval; - else if (atype.equals("C")) - country = aval; - else if (atype.equals("L")) - locality = aval; - else if (atype.equals("ST")) - state = aval; - else if (atype.equals("STREET")) - street = aval; - else if (atype.equals("O")) - organization = aval; - else if (atype.equals("OU")) - orgUnit = aval; - else if (atype.equals("T")) - title = aval; - else if (atype.equals("DNQ") || atype.equals("DNQUALIFIER")) - dnQualifier = aval; - else if (atype.equals("SURNAME")) - surname = aval; - else if (atype.equals("GIVENNAME")) - givenName = aval; - else if (atype.equals("INITIALS")) - initials = aval; - else if (atype.equals("GENERATION")) - generation = aval; - else if (atype.equals("EMAILADDRESS")) - email = aval; - else if (atype.equals("DC")) - domainComponent = aval; - else if (atype.equals("UID")) - userid = aval; else - throw new IllegalArgumentException("unknown attribute " + atype); + buf.append(c); + lastChar = c; } - - private void setAttribute(OID atype, String aval) - { - if (atype.equals(CN)) - commonName = aval; - else if (atype.equals(C)) - country = aval; - else if (atype.equals(L)) - locality = aval; - else if (atype.equals(ST)) - state = aval; - else if (atype.equals(STREET)) - street = aval; - else if (atype.equals(O)) - organization = aval; - else if (atype.equals(OU)) - orgUnit = aval; - else if (atype.equals(T)) - title = aval; - else if (atype.equals(DNQ)) - dnQualifier = aval; - else if (atype.equals(NAME)) - surname = aval; - else if (atype.equals(GIVENNAME)) - givenName = aval; - else if (atype.equals(INITIALS)) - initials = aval; - else if (atype.equals(GENERATION)) - generation = aval; - else if (atype.equals(EMAIL)) - email = aval; - else if (atype.equals(DC)) - domainComponent = aval; - else if (atype.equals(UID)) - userid = aval; - else - throw new IllegalArgumentException("unknown attribute " + atype); + return buf.toString().trim(); } } Index: gnu/java/security/x509/X509CRL.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/security/x509/X509CRL.java,v retrieving revision 1.2 diff -u -b -B -r1.2 X509CRL.java --- gnu/java/security/x509/X509CRL.java 13 Oct 2004 14:32:34 -0000 1.2 +++ gnu/java/security/x509/X509CRL.java 7 Nov 2004 19:25:52 -0000 @@ -44,6 +44,7 @@ import gnu.java.security.der.DER; import gnu.java.security.der.DERReader; import gnu.java.security.der.DERValue; +import gnu.java.security.x509.ext.Extension; import java.io.InputStream; import java.io.IOException; @@ -57,7 +58,6 @@ import java.security.SignatureException; import java.security.cert.Certificate; import java.security.cert.CRLException; -import java.security.cert.X509CRLEntry; import java.util.Collections; import java.util.Date; import java.util.HashSet; @@ -72,11 +72,22 @@ * @author Casey Marshall (address@hidden) */ public class X509CRL extends java.security.cert.X509CRL + implements GnuPKIExtension { // Constants and fields. // ------------------------------------------------------------------------ + private static final boolean DEBUG = false; + private static void debug(String msg) + { + if (DEBUG) + { + System.err.print(">> X509CRL: "); + System.err.println(msg); + } + } + private static final OID ID_DSA = new OID("1.2.840.10040.4.1"); private static final OID ID_DSA_WITH_SHA1 = new OID("1.2.840.10040.4.3"); private static final OID ID_RSA = new OID("1.2.840.113549.1.1.1"); @@ -92,11 +103,9 @@ private byte[] algParams; private Date thisUpdate; private Date nextUpdate; - private X500Principal issuerDN; + private X500DistinguishedName issuerDN; private HashMap revokedCerts; private HashMap extensions; - private HashSet critOids; - private HashSet nonCritOids; private OID sigAlg; private byte[] sigAlgParams; @@ -118,8 +127,6 @@ super(); revokedCerts = new HashMap(); extensions = new HashMap(); - critOids = new HashSet(); - nonCritOids = new HashSet(); try { parse(encoded); @@ -141,7 +148,9 @@ public boolean equals(Object o) { - return ((X509CRL) o).revokedCerts.equals(revokedCerts); + if (!(o instanceof X509CRL)) + return false; + return ((X509CRL) o).getRevokedCertificates().equals(revokedCerts.values()); } public int hashCode() @@ -182,7 +191,7 @@ public X500Principal getIssuerX500Principal() { - return issuerDN; + return new X500Principal(issuerDN.getDer()); } public Date getThisUpdate() @@ -197,9 +206,9 @@ return null; } - public X509CRLEntry getRevokedCertificate(BigInteger serialNo) + public java.security.cert.X509CRLEntry getRevokedCertificate(BigInteger serialNo) { - return (X509CRLEntry) revokedCerts.get(serialNo); + return (java.security.cert.X509CRLEntry) revokedCerts.get(serialNo); } public Set getRevokedCertificates() @@ -247,33 +256,68 @@ public boolean hasUnsupportedCriticalExtension() { - return false; // XXX + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (e.isCritical() && !e.isSupported()) + return true; + } + return false; } public Set getCriticalExtensionOIDs() { - return Collections.unmodifiableSet(critOids); + HashSet s = new HashSet(); + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (e.isCritical()) + s.add(e.getOid().toString()); + } + return Collections.unmodifiableSet(s); } public Set getNonCriticalExtensionOIDs() { - return Collections.unmodifiableSet(nonCritOids); + HashSet s = new HashSet(); + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (!e.isCritical()) + s.add(e.getOid().toString()); + } + return Collections.unmodifiableSet(s); } public byte[] getExtensionValue(String oid) { - byte[] ext = (byte[]) extensions.get(oid); - if (ext != null) - return (byte[]) ext.clone(); + Extension e = getExtension(new OID(oid)); + if (e != null) + { + return e.getValue().getEncoded(); + } return null; } + // GnuPKIExtension method. + // ------------------------------------------------------------------------- + + public Extension getExtension(OID oid) + { + return (Extension) extensions.get(oid); + } + + public Collection getExtensions() + { + return extensions.values(); + } + // CRL methods. - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- public String toString() { - return gnu.java.security.x509.X509CRL.class.getName(); + return X509CRL.class.getName(); } public boolean isRevoked(Certificate cert) @@ -302,17 +346,23 @@ private void parse(InputStream in) throws Exception { + // CertificateList ::= SEQUENCE { DERReader der = new DERReader(in); DERValue val = der.read(); + debug("start CertificateList len == " + val.getLength()); if (!val.isConstructed()) - throw new ASN1ParsingException("malformed CertificateList"); + throw new IOException("malformed CertificateList"); encoded = val.getEncoded(); + // tbsCertList ::= SEQUENCE { -- TBSCertList val = der.read(); if (!val.isConstructed()) - throw new ASN1ParsingException("malformed TBSCertList"); + throw new IOException("malformed TBSCertList"); + debug("start tbsCertList len == " + val.getLength()); tbsCRLBytes = val.getEncoded(); + // version Version OPTIONAL, + // -- If present must be v2 val = der.read(); if (val.getValue() instanceof BigInteger) { @@ -321,78 +371,104 @@ } else version = 1; + debug("read version == " + version); + // signature AlgorithmIdentifier, + debug("start AlgorithmIdentifier len == " + val.getLength()); if (!val.isConstructed()) - throw new ASN1ParsingException("malformed AlgorithmIdentifier"); + throw new IOException("malformed AlgorithmIdentifier"); DERValue algIdVal = der.read(); algId = (OID) algIdVal.getValue(); + debug("read object identifier == " + algId); if (val.getLength() > algIdVal.getEncodedLength()) { val = der.read(); + debug("read parameters len == " + val.getEncodedLength()); algParams = val.getEncoded(); if (val.isConstructed()) in.skip(val.getLength()); } - issuerDN = new X500Principal(in); + // issuer Name, + val = der.read(); + issuerDN = new X500DistinguishedName(val.getEncoded()); + der.skip(val.getLength()); + debug("read issuer == " + issuerDN); + // thisUpdate Time, thisUpdate = (Date) der.read().getValue(); + debug("read thisUpdate == " + thisUpdate); + // nextUpdate Time OPTIONAL, val = der.read(); if (val.getValue() instanceof Date) { nextUpdate = (Date) val.getValue(); + debug("read nextUpdate == " + nextUpdate); val = der.read(); } + + // revokedCertificates SEQUENCE OF SEQUENCE { + // -- X509CRLEntry objects... + // } OPTIONAL, if (val.getTag() != 0) { int len = 0; while (len < val.getLength()) { - X509CRLEntry entry = - new gnu.java.security.x509.X509CRLEntry(version, in); + X509CRLEntry entry = new X509CRLEntry(version, der); revokedCerts.put(entry.getSerialNumber(), entry); len += entry.getEncoded().length; } - } - if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 0) - { val = der.read(); + } + + // crlExtensions [0] EXPLICIT Extensions OPTIONAL + // -- if present MUST be v2 + if (val.getTagClass() != DER.UNIVERSAL && val.getTag() == 0) + { + if (version < 2) + throw new IOException("extra data in CRL"); + DERValue exts = der.read(); + if (!exts.isConstructed()) + throw new IOException("malformed Extensions"); + debug("start Extensions len == " + exts.getLength()); int len = 0; - while (len < val.getLength()) + while (len < exts.getLength()) { DERValue ext = der.read(); - OID extId = (OID) der.read().getValue(); - DERValue val2 = der.read(); - Boolean crit = Boolean.valueOf(false); - if (val2.getValue() instanceof Boolean) - { - crit = (Boolean) val2.getValue(); - val2 = der.read(); - } - byte[] extVal = (byte[]) val2.getValue(); - extensions.put(extId.toString(), extVal); - if (crit.booleanValue()) - critOids.add(extId.toString()); - else - nonCritOids.add(extId.toString()); + if (!ext.isConstructed()) + throw new IOException("malformed Extension"); + Extension e = new Extension(ext.getEncoded()); + extensions.put(e.getOid(), e); + der.skip(ext.getLength()); len += ext.getEncodedLength(); + debug("current count == " + len); } + val = der.read(); } - val = der.read(); + debug("read tag == " + val.getTag()); if (!val.isConstructed()) - throw new ASN1ParsingException("malformed AlgorithmIdentifier"); + throw new IOException("malformed AlgorithmIdentifier"); + debug("start AlgorithmIdentifier len == " + val.getLength()); DERValue sigAlgVal = der.read(); + debug("read tag == " + sigAlgVal.getTag()); + if (sigAlgVal.getTag() != DER.OBJECT_IDENTIFIER) + throw new IOException("malformed AlgorithmIdentifier"); sigAlg = (OID) sigAlgVal.getValue(); + debug("signature id == " + sigAlg); + debug("sigAlgVal length == " + sigAlgVal.getEncodedLength()); if (val.getLength() > sigAlgVal.getEncodedLength()) { val = der.read(); + debug("sig params tag = " + val.getTag() + " len == " + val.getEncodedLength()); sigAlgParams = (byte[]) val.getEncoded(); if (val.isConstructed()) in.skip(val.getLength()); } val = der.read(); + debug("read tag = " + val.getTag()); rawSig = val.getEncoded(); signature = ((BitString) val.getValue()).toByteArray(); } Index: gnu/java/security/x509/X509CRLEntry.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/security/x509/X509CRLEntry.java,v retrieving revision 1.1 diff -u -b -B -r1.1 X509CRLEntry.java --- gnu/java/security/x509/X509CRLEntry.java 23 Apr 2003 23:01:24 -0000 1.1 +++ gnu/java/security/x509/X509CRLEntry.java 7 Nov 2004 19:25:52 -0000 @@ -1,5 +1,5 @@ -/* X509CRLEntry.java -- entry in a X.509 CRL. - Copyright (C) 2003 Free Software Foundation, Inc. +/* X509CRLEntry.java -- an entry in a X.509 CRL. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -45,17 +45,17 @@ import java.security.cert.CRLException; +import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.Set; -import gnu.java.io.ASN1ParsingException; import gnu.java.security.OID; -import gnu.java.security.der.DERReader; -import gnu.java.security.der.DERValue; -import gnu.java.security.der.DERWriter; +import gnu.java.security.der.*; +import gnu.java.security.x509.ext.*; /** * A single entry in a X.509 certificate revocation list. @@ -64,11 +64,22 @@ * @author Casey Marshall */ class X509CRLEntry extends java.security.cert.X509CRLEntry + implements GnuPKIExtension { // Constants and fields. // ------------------------------------------------------------------------ + private static final boolean DEBUG = false; + private static void debug(String msg) + { + if (DEBUG) + { + System.err.print(">> X509CRLEntry: "); + System.err.println(msg); + } + } + /** The DER encoded form of this CRL entry. */ private byte[] encoded; @@ -78,15 +89,9 @@ /** The date the certificate was revoked. */ private Date revocationDate; - /** The encoded extensions. */ + /** The CRL entry extensions. */ private HashMap extensions; - /** The set of critical extension OIDs. */ - private HashSet critOids; - - /** the set of non-critical extension OIDs. */ - private HashSet nonCritOids; - // Constructor. // ------------------------------------------------------------------------ @@ -99,13 +104,11 @@ * @throws CRLException If the ASN.1 structure is invalid. * @throws IOException If the bytes cannot be read. */ - X509CRLEntry(int version, InputStream encoded) + X509CRLEntry(int version, DERReader encoded) throws CRLException, IOException { super(); extensions = new HashMap(); - critOids = new HashSet(); - nonCritOids = new HashSet(); try { parse(version, encoded); @@ -125,8 +128,10 @@ public boolean equals(Object o) { - return ((X509CRLEntry) o).serialNo.equals(serialNo) && - ((X509CRLEntry) o).revocationDate.equals(revocationDate); + if (!(o instanceof X509CRLEntry)) + return false; + return ((X509CRLEntry) o).getSerialNumber().equals(serialNo) && + ((X509CRLEntry) o).getRevocationDate().equals(revocationDate); } public int hashCode() @@ -157,79 +162,119 @@ public String toString() { return "X509CRLEntry serial=" + serialNo + " revocation date=" - + revocationDate + " critExt=" + critOids + " ext=" + nonCritOids; + + revocationDate + " ext=" + extensions; } // X509Extension methods. - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- public boolean hasUnsupportedCriticalExtension() { - return false; // XXX + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (e.isCritical() && !e.isSupported()) + return true; + } + return false; } public Set getCriticalExtensionOIDs() { - return Collections.unmodifiableSet(critOids); + HashSet s = new HashSet(); + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (e.isCritical()) + s.add(e.getOid().toString()); + } + return Collections.unmodifiableSet(s); } public Set getNonCriticalExtensionOIDs() { - return Collections.unmodifiableSet(nonCritOids); + HashSet s = new HashSet(); + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (!e.isCritical()) + s.add(e.getOid().toString()); + } + return Collections.unmodifiableSet(s); } public byte[] getExtensionValue(String oid) { - byte[] ext = (byte[]) extensions.get(oid); - if (ext != null) - return (byte[]) ext.clone(); + Extension e = getExtension(new OID(oid)); + if (e != null) + { + return e.getValue().getEncoded(); + } return null; } + // GnuPKIExtension method. + // ------------------------------------------------------------------------- + + public Extension getExtension(OID oid) + { + return (Extension) extensions.get(oid); + } + + public Collection getExtensions() + { + return extensions.values(); + } + // Own methods. - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- - private void parse(int version, InputStream in) throws Exception + private void parse(int version, DERReader der) throws Exception { - DERReader der = new DERReader(in); + // RevokedCertificate ::= SEQUENCE { DERValue entry = der.read(); + debug("start CRL entry len == " + entry.getLength()); if (!entry.isConstructed()) - throw new ASN1ParsingException("malformed revokedCertificate"); + throw new IOException("malformed revokedCertificate"); encoded = entry.getEncoded(); int len = 0; + + debug("encoded entry:\n" + Util.hexDump(encoded, ">>>> ")); + + // userCertificate CertificateSerialNumber, DERValue val = der.read(); serialNo = (BigInteger) val.getValue(); - len += DERWriter.definiteEncodingSize(val.getLength()) - + val.getLength() + 1; + len += val.getEncodedLength(); + debug("userCertificate == " + serialNo + " current count == " + len); + + // revocationDate Time, val = der.read(); revocationDate = (Date) val.getValue(); - len += DERWriter.definiteEncodingSize(val.getLength()) - + val.getLength() + 1; + len += val.getEncodedLength(); + debug("revocationDate == " + revocationDate + " current count == " + len); + // crlEntryExtensions Extensions OPTIONAL + // -- if present MUST be v2 if (len < entry.getLength()) { if (version < 2) - throw new ASN1ParsingException("extra data in CRL entry"); - while (len < entry.getLength()) + throw new IOException("extra data in CRL entry"); + DERValue exts = der.read(); + if (!exts.isConstructed()) + throw new IOException("malformed Extensions"); + debug("start Extensions len == " + exts.getLength()); + len = 0; + while (len < exts.getLength()) { val = der.read(); if (!val.isConstructed()) - throw new ASN1ParsingException("malformed Extension"); - OID extOid = (OID) der.read().getValue(); - Boolean critical = Boolean.valueOf(false); - DERValue val2 = der.read(); - if (val2.getValue() instanceof Boolean) - { - critical = (Boolean) val2.getValue(); - val2 = der.read(); - } - byte[] ext = (byte[]) val2.getValue(); - extensions.put(extOid.toString(), ext); - if (critical.booleanValue()) - critOids.add(extOid.toString()); - else - nonCritOids.add(extOid.toString()); + throw new IOException("malformed Extension"); + debug("start Extension len == " + val.getLength()); + Extension e = new Extension(val.getEncoded()); + extensions.put(e.getOid(), e); + der.skip(val.getLength()); len += val.getEncodedLength(); + debug("current count == " + len); } } } Index: gnu/java/security/x509/X509Certificate.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/security/x509/X509Certificate.java,v retrieving revision 1.3 diff -u -b -B -r1.3 X509Certificate.java --- gnu/java/security/x509/X509Certificate.java 18 Jun 2003 10:01:34 -0000 1.3 +++ gnu/java/security/x509/X509Certificate.java 7 Nov 2004 19:25:52 -0000 @@ -1,5 +1,5 @@ /* X509Certificate.java -- X.509 certificate. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,7 +42,9 @@ import java.io.InputStream; import java.io.IOException; import java.io.ObjectStreamException; +import java.io.PrintWriter; import java.io.Serializable; +import java.io.StringWriter; import java.math.BigInteger; @@ -64,10 +66,12 @@ import java.security.cert.CertificateNotYetValidException; import java.security.cert.CertificateParsingException; +import java.security.interfaces.DSAParams; +import java.security.interfaces.DSAPublicKey; import java.security.spec.DSAParameterSpec; -import java.security.spec.DSAPublicKeySpec; -import java.security.spec.RSAPublicKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Arrays; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -77,17 +81,14 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Set; import javax.security.auth.x500.X500Principal; -import gnu.java.io.ASN1ParsingException; import gnu.java.security.OID; -import gnu.java.security.der.BitString; -import gnu.java.security.der.DER; -import gnu.java.security.der.DERReader; -import gnu.java.security.der.DERValue; -import gnu.java.security.der.DERWriter; +import gnu.java.security.der.*; +import gnu.java.security.x509.ext.*; /** * An implementation of X.509 certificates. @@ -95,65 +96,64 @@ * @author Casey Marshall (address@hidden) */ public class X509Certificate extends java.security.cert.X509Certificate - implements Serializable + implements Serializable, GnuPKIExtension { // Constants and fields. // ------------------------------------------------------------------------ - private static final OID ID_DSA = new OID("1.2.840.10040.4.1"); - private static final OID ID_DSA_WITH_SHA1 = new OID("1.2.840.10040.4.3"); - private static final OID ID_RSA = new OID("1.2.840.113549.1.1.1"); - private static final OID ID_RSA_WITH_MD2 = new OID("1.2.840.113549.1.1.2"); - private static final OID ID_RSA_WITH_MD5 = new OID("1.2.840.113549.1.1.4"); - private static final OID ID_RSA_WITH_SHA1 = new OID("1.2.840.113549.1.1.5"); - - private static final OID ID_EXTENSION = new OID("2.5.29"); - private static final OID ID_KEY_USAGE = ID_EXTENSION.getChild(15); - private static final OID ID_BASIC_CONSTRAINTS = ID_EXTENSION.getChild(19); - private static final OID ID_EXT_KEY_USAGE = ID_EXTENSION.getChild(37); - - private static final int OTHER_NAME = 0; - private static final int RFC882_NAME = 1; - private static final int DNS_NAME = 2; - private static final int X400_ADDRESS = 3; - private static final int DIRECTORY_NAME = 4; - private static final int EDI_PARTY_NAME = 5; - private static final int URI = 6; - private static final int IP_ADDRESS = 7; - private static final int REGISTERED_ID = 8; + private static final boolean DEBUG = false; + private static void debug(String msg) + { + if (DEBUG) + { + System.err.print(">> X509Certificate: "); + System.err.println(msg); + } + } + private static void debug(Throwable t) + { + if (DEBUG) + { + System.err.print(">> X509Certificate: "); + t.printStackTrace(); + } + } + + protected static final OID ID_DSA = new OID ("1.2.840.10040.4.1"); + protected static final OID ID_DSA_WITH_SHA1 = new OID ("1.2.840.10040.4.3"); + protected static final OID ID_RSA = new OID ("1.2.840.113549.1.1.1"); + protected static final OID ID_RSA_WITH_MD2 = new OID ("1.2.840.113549.1.1.2"); + protected static final OID ID_RSA_WITH_MD5 = new OID ("1.2.840.113549.1.1.4"); + protected static final OID ID_RSA_WITH_SHA1 = new OID ("1.2.840.113549.1.1.5"); + protected static final OID ID_ECDSA_WITH_SHA1 = new OID ("1.2.840.10045.4.1"); // This object SHOULD be serialized with an instance of // java.security.cert.Certificate.CertificateRep, thus all fields are // transient. // The encoded certificate. - private transient byte[] encoded; + protected transient byte[] encoded; // TBSCertificate part. - private transient byte[] tbsCertBytes; - private transient int version; - private transient BigInteger serialNo; - private transient OID algId; - private transient byte[] algVal; - private transient X500Principal issuer; - private transient Date notBefore; - private transient Date notAfter; - private transient X500Principal subject; - private transient PublicKey subjectKey; - private transient BitString issuerUniqueId; - private transient BitString subjectUniqueId; - private transient HashMap extensions; - private transient HashSet critOids; - private transient HashSet nonCritOids; - - private transient BitString keyUsage; - private transient int basicConstraints = -1; + protected transient byte[] tbsCertBytes; + protected transient int version; + protected transient BigInteger serialNo; + protected transient OID algId; + protected transient byte[] algVal; + protected transient X500DistinguishedName issuer; + protected transient Date notBefore; + protected transient Date notAfter; + protected transient X500DistinguishedName subject; + protected transient PublicKey subjectKey; + protected transient BitString issuerUniqueId; + protected transient BitString subjectUniqueId; + protected transient Map extensions; // Signature. - private transient OID sigAlgId; - private transient byte[] sigAlgVal; - private transient byte[] signature; + protected transient OID sigAlgId; + protected transient byte[] sigAlgVal; + protected transient byte[] signature; // Constructors. // ------------------------------------------------------------------------ @@ -173,22 +173,29 @@ { super(); extensions = new HashMap(); - critOids = new HashSet(); - nonCritOids = new HashSet(); try { parse(encoded); } catch (IOException ioe) { + debug(ioe); throw ioe; } catch (Exception e) { - throw new CertificateException(e.toString()); + debug(e); + CertificateException ce = new CertificateException(e.getMessage()); + ce.initCause (e); + throw ce; } } + protected X509Certificate() + { + extensions = new HashMap(); + } + // X509Certificate methods. // ------------------------------------------------------------------------ @@ -202,10 +209,14 @@ throws CertificateExpiredException, CertificateNotYetValidException { if (date.compareTo(notBefore) < 0) + { throw new CertificateNotYetValidException(); + } if (date.compareTo(notAfter) > 0) + { throw new CertificateExpiredException(); } + } public int getVersion() { @@ -219,22 +230,22 @@ public Principal getIssuerDN() { - return getIssuerX500Principal(); + return issuer; } public X500Principal getIssuerX500Principal() { - return issuer; + return new X500Principal(issuer.getDer()); } public Principal getSubjectDN() { - return getSubjectX500Principal(); + return subject; } public X500Principal getSubjectX500Principal() { - return subject; + return new X500Principal(subject.getDer()); } public Date getNotBefore() @@ -260,15 +271,22 @@ public String getSigAlgName() { if (sigAlgId.equals(ID_DSA_WITH_SHA1)) + { return "SHA1withDSA"; - if (sigAlgId.equals(ID_RSA_WITH_MD2 )) + } + if (sigAlgId.equals(ID_RSA_WITH_MD2)) + { return "MD2withRSA"; - if (sigAlgId.equals(ID_RSA_WITH_MD5 )) + } + if (sigAlgId.equals(ID_RSA_WITH_MD5)) + { return "MD5withRSA"; - if (sigAlgId.equals(ID_RSA_WITH_SHA1 )) + } + if (sigAlgId.equals(ID_RSA_WITH_SHA1)) + { return "SHA1withRSA"; + } return "unknown"; - // return sigAlgId.getShortName(); } public String getSigAlgOID() @@ -284,75 +302,81 @@ public boolean[] getIssuerUniqueID() { if (issuerUniqueId != null) + { return issuerUniqueId.toBooleanArray(); + } return null; } public boolean[] getSubjectUniqueID() { if (subjectUniqueId != null) + { return subjectUniqueId.toBooleanArray(); + } return null; } public boolean[] getKeyUsage() { - if (keyUsage != null) - return keyUsage.toBooleanArray(); + Extension e = getExtension(KeyUsage.ID); + if (e != null) + { + KeyUsage ku = (KeyUsage) e.getValue(); + boolean[] result = new boolean[9]; + boolean[] b = ku.getKeyUsage().toBooleanArray(); + System.arraycopy(b, 0, result, 0, b.length); + return result; + } return null; } public List getExtendedKeyUsage() throws CertificateParsingException { - byte[] ext = (byte[]) extensions.get("2.5.29.37"); - if (ext == null) - return null; - LinkedList usages = new LinkedList(); - try + Extension e = getExtension(ExtendedKeyUsage.ID); + if (e != null) { - DERReader der = new DERReader(new ByteArrayInputStream(ext)); - DERValue seq = der.read(); - if (!seq.isConstructed()) - throw new CertificateParsingException(); - int len = 0; - while (len < seq.getLength()) + List a = ((ExtendedKeyUsage) e.getValue()).getPurposeIds(); + List b = new ArrayList(a.size()); + for (Iterator it = a.iterator(); it.hasNext(); ) { - DERValue oid = der.read(); - if (!(oid.getValue() instanceof OID)) - throw new CertificateParsingException(); - usages.add(oid.getValue().toString()); - len += DERWriter.definiteEncodingSize(oid.getLength()) - + oid.getLength() + 1; - } + b.add(it.next().toString()); } - catch (IOException ioe) - { - throw new CertificateParsingException(); + return Collections.unmodifiableList(b); } - return usages; + return null; } public int getBasicConstraints() { - return basicConstraints; + Extension e = getExtension(BasicConstraints.ID); + if (e != null) + { + return ((BasicConstraints) e.getValue()).getPathLengthConstraint(); + } + return -1; } public Collection getSubjectAlternativeNames() throws CertificateParsingException { - byte[] ext = getExtensionValue("2.5.29.17"); - if (ext == null) + Extension e = getExtension(SubjectAlternativeNames.ID); + if (e != null) + { + return ((SubjectAlternativeNames) e.getValue()).getNames(); + } return null; - return getAltNames(ext); } public Collection getIssuerAlternativeNames() throws CertificateParsingException { - byte[] ext = getExtensionValue("2.5.29.18"); - if (ext == null) + Extension e = getExtension(IssuerAlternativeNames.ID); + if (e != null) + { + return ((IssuerAlternativeNames) e.getValue()).getNames(); + } return null; - return getAltNames(ext); } // X509Extension methods. @@ -360,12 +384,10 @@ public boolean hasUnsupportedCriticalExtension() { - for (Iterator it = critOids.iterator(); it.hasNext(); ) + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) { - String oid = (String) it.next(); - if (!oid.equals("2.5.29.15") && !oid.equals("2.5.29.17") && - !oid.equals("2.5.29.18") && !oid.equals("2.5.29.19") && - !oid.equals("2.5.29.37")) + Extension e = (Extension) it.next(); + if (e.isCritical() && !e.isSupported()) return true; } return false; @@ -373,24 +395,53 @@ public Set getCriticalExtensionOIDs() { - return Collections.unmodifiableSet(critOids); + HashSet s = new HashSet(); + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (e.isCritical()) + s.add(e.getOid().toString()); + } + return Collections.unmodifiableSet(s); } public Set getNonCriticalExtensionOIDs() { - return Collections.unmodifiableSet(nonCritOids); + HashSet s = new HashSet(); + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (!e.isCritical()) + s.add(e.getOid().toString()); + } + return Collections.unmodifiableSet(s); } public byte[] getExtensionValue(String oid) { - byte[] ext = (byte[]) extensions.get(oid); - if (ext != null) - return (byte[]) ext.clone(); + Extension e = getExtension(new OID(oid)); + if (e != null) + { + return e.getValue().getEncoded(); + } return null; } + // GnuPKIExtension method. + // ------------------------------------------------------------------------- + + public Extension getExtension(OID oid) + { + return (Extension) extensions.get(oid); + } + + public Collection getExtensions() + { + return extensions.values(); + } + // Certificate methods. - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- public byte[] getEncoded() throws CertificateEncodingException { @@ -415,8 +466,50 @@ public String toString() { - // XXX say more than this. - return gnu.java.security.x509.X509Certificate.class.getName(); + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println(X509Certificate.class.getName() + " {"); + out.println(" TBSCertificate {"); + out.println(" version = " + version + ";"); + out.println(" serialNo = " + serialNo + ";"); + out.println(" signature = {"); + out.println(" algorithm = " + getSigAlgName() + ";"); + out.print(" parameters ="); + if (sigAlgVal != null) + { + out.println(); + out.print(Util.hexDump(sigAlgVal, " ")); + } + else + { + out.println(" null;"); + } + out.println(" }"); + out.println(" issuer = " + issuer.getName() + ";"); + out.println(" validity = {"); + out.println(" notBefore = " + notBefore + ";"); + out.println(" notAfter = " + notAfter + ";"); + out.println(" }"); + out.println(" subject = " + subject.getName() + ";"); + out.println(" subjectPublicKeyInfo = {"); + out.println(" algorithm = " + subjectKey.getAlgorithm()); + out.println(" key ="); + out.print(Util.hexDump(subjectKey.getEncoded(), " ")); + out.println(" };"); + out.println(" issuerUniqueId = " + issuerUniqueId + ";"); + out.println(" subjectUniqueId = " + subjectUniqueId + ";"); + out.println(" extensions = {"); + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + out.println(" " + it.next()); + } + out.println(" }"); + out.println(" }"); + out.println(" signatureAlgorithm = " + getSigAlgName() + ";"); + out.println(" signatureValue ="); + out.print(Util.hexDump(signature, " ")); + out.println("}"); + return str.toString(); } public PublicKey getPublicKey() @@ -424,9 +517,23 @@ return subjectKey; } - protected Object writeReplace() throws ObjectStreamException + public boolean equals(Object other) { - return super.writeReplace(); + if (!(other instanceof X509Certificate)) + return false; + try + { + if (other instanceof X509Certificate) + return Arrays.equals(encoded, ((X509Certificate) other).encoded); + byte[] enc = ((X509Certificate) other).getEncoded(); + if (enc == null) + return false; + return Arrays.equals(encoded, enc); + } + catch (CertificateEncodingException cee) + { + return false; + } } // Own methods. @@ -438,68 +545,13 @@ private void doVerify(Signature sig, PublicKey key) throws CertificateException, InvalidKeyException, SignatureException { + debug("verifying sig=" + sig + " key=" + key); sig.initVerify(key); sig.update(tbsCertBytes); if (!sig.verify(signature)) - throw new CertificateException("signature not validated"); - } - - /** - * Read a GeneralNames structure. - */ - private List getAltNames(byte[] encoded) - throws CertificateParsingException { - LinkedList names = new LinkedList(); - try - { - ByteArrayInputStream in = new ByteArrayInputStream(encoded); - DERReader der = new DERReader(in); - DERValue seq = der.read(); - if (!seq.isConstructed()) - throw new CertificateParsingException(); - int len = 0; - while (len < seq.getLength()) - { - DERValue name = der.read(); - ArrayList pair = new ArrayList(2); - Object nameVal = null; - switch (name.getTag()) - { - case RFC882_NAME: - case DNS_NAME: - case URI: - nameVal = new String((byte[]) name.getValue()); - break; - case IP_ADDRESS: - nameVal = InetAddress.getByAddress( - (byte[]) name.getValue()).getHostAddress(); - break; - case REGISTERED_ID: - nameVal = new OID((byte[]) name.getValue()); - break; - case OTHER_NAME: - case X400_ADDRESS: - case DIRECTORY_NAME: - case EDI_PARTY_NAME: - nameVal = name.getEncoded(); - break; - default: - throw new CertificateParsingException(); - } - pair.add(new Integer(name.getTag())); - pair.add(nameVal); - names.add(pair); - if (name.isConstructed()) - in.skip(name.getLength()); - len += name.getEncodedLength(); - } - } - catch (IOException ioe) - { - throw new CertificateParsingException(ioe.toString()); + throw new CertificateException("signature not validated"); } - return Collections.unmodifiableList(names); } /** @@ -513,20 +565,27 @@ // Certificate ::= SEQUENCE { DERValue cert = der.read(); + debug("start Certificate len == " + cert.getLength()); + this.encoded = cert.getEncoded(); if (!cert.isConstructed()) - throw new ASN1ParsingException("malformed Certificate"); + { + throw new IOException("malformed Certificate"); + } // TBSCertificate ::= SEQUENCE { DERValue tbsCert = der.read(); if (tbsCert.getValue() != DER.CONSTRUCTED_VALUE) - throw new ASN1ParsingException("malformed TBSCertificate"); + { + throw new IOException("malformed TBSCertificate"); + } tbsCertBytes = tbsCert.getEncoded(); + debug("start TBSCertificate len == " + tbsCert.getLength()); + // Version ::= INTEGER [0] { v1(0), v2(1), v3(2) } DERValue val = der.read(); if (val.getTagClass() == DER.CONTEXT && val.getTag() == 0) { - // Version ::= INTEGER [0] { v1(0), v2(1), v3(2) } version = ((BigInteger) der.read().getValue()).intValue() + 1; val = der.read(); } @@ -534,163 +593,154 @@ { version = 1; } + debug("read version == " + version); + // SerialNumber ::= INTEGER serialNo = (BigInteger) val.getValue(); + debug("read serial number == " + serialNo); // AlgorithmIdentifier ::= SEQUENCE { val = der.read(); if (!val.isConstructed()) - throw new ASN1ParsingException("malformed AlgorithmIdentifier"); + { + throw new IOException("malformed AlgorithmIdentifier"); + } int certAlgLen = val.getLength(); + debug("start AlgorithmIdentifier len == " + certAlgLen); val = der.read(); + + // algorithm OBJECT IDENTIFIER, algId = (OID) val.getValue(); + debug("read algorithm ID == " + algId); + + // parameters ANY DEFINED BY algorithm OPTIONAL } if (certAlgLen > val.getEncodedLength()) { val = der.read(); if (val == null) + { algVal = null; + } else + { algVal = val.getEncoded(); + } if (val.isConstructed()) + { encoded.skip(val.getLength()); } + debug("read algorithm parameters == " + algVal); + } - issuer = new X500Principal(encoded); + // issuer Name, + val = der.read(); + issuer = new X500DistinguishedName(val.getEncoded()); + der.skip(val.getLength()); + debug("read issuer == " + issuer); + // Validity ::= SEQUENCE { + // notBefore Time, + // notAfter Time } if (!der.read().isConstructed()) - throw new ASN1ParsingException("malformed Validity"); + { + throw new IOException("malformed Validity"); + } notBefore = (Date) der.read().getValue(); notAfter = (Date) der.read().getValue(); + debug("read notBefore == " + notBefore); + debug("read notAfter == " + notAfter); - subject = new X500Principal(encoded); - - if (!der.read().isConstructed()) - throw new ASN1ParsingException("malformed SubjectPublicKeyInfo"); - - val = der.read(); - if (!val.isConstructed()) - throw new ASN1ParsingException("malformed AlgorithmIdentifier"); - int keyAlgLen = val.getLength(); - val = der.read(); - OID keyID = (OID) val.getValue(); - byte[] keyParams = null; - if (keyAlgLen > val.getEncodedLength()) - { - val = der.read(); - keyParams = val.getEncoded(); - if (algVal == null) - algVal = keyParams; - if (val.isConstructed()) - encoded.skip(val.getLength()); - } + // subject Name, val = der.read(); - byte[] keyVal = ((BitString) val.getValue()).toByteArray(); - - if (keyID.equals(ID_DSA)) - { - AlgorithmParameters params = AlgorithmParameters.getInstance("DSA"); - params.init(keyParams, "ASN.1"); - KeyFactory keyFac = KeyFactory.getInstance("DSA"); - DSAParameterSpec spec = (DSAParameterSpec) - params.getParameterSpec(DSAParameterSpec.class); - subjectKey = keyFac.generatePublic(new DSAPublicKeySpec( - (BigInteger) new DERReader(keyVal).read().getValue(), - spec.getP(), spec.getQ(), spec.getG())); - } - else if (keyID.equals(ID_RSA)) - { - KeyFactory keyFac = KeyFactory.getInstance("RSA"); - DERReader rsaKey = new DERReader(keyVal); - if (!rsaKey.read().isConstructed()) - throw new ASN1ParsingException("malformed RSAPublicKey"); - subjectKey = keyFac.generatePublic(new RSAPublicKeySpec( - (BigInteger) rsaKey.read().getValue(), - (BigInteger) rsaKey.read().getValue())); - } - else - throw new ASN1ParsingException("unknown key algorithm " + keyID); + subject = new X500DistinguishedName(val.getEncoded()); + der.skip(val.getLength()); + debug("read subject == " + subject); + + // SubjectPublicKeyInfo ::= SEQUENCE { + // algorithm AlgorithmIdentifier, + // subjectPublicKey BIT STRING } + DERValue spki = der.read(); + if (!spki.isConstructed()) + { + throw new IOException("malformed SubjectPublicKeyInfo"); + } + KeyFactory spkFac = KeyFactory.getInstance("X.509"); + subjectKey = spkFac.generatePublic(new X509EncodedKeySpec(spki.getEncoded())); + der.skip(spki.getLength()); + debug("read subjectPublicKey == " + subjectKey); if (version > 1) + { val = der.read(); + } if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 1) { byte[] b = (byte[]) val.getValue(); issuerUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF); + debug("read issuerUniqueId == " + issuerUniqueId); val = der.read(); } if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 2) { byte[] b = (byte[]) val.getValue(); subjectUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF); + debug("read subjectUniqueId == " + subjectUniqueId); val = der.read(); } if (version >= 3 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 3) { val = der.read(); + debug("start Extensions len == " + val.getLength()); int len = 0; while (len < val.getLength()) { DERValue ext = der.read(); - OID extId = (OID) der.read().getValue(); - DERValue val2 = der.read(); - Boolean crit = Boolean.valueOf(false); - if (val2.getValue() instanceof Boolean) - { - crit = (Boolean) val2.getValue(); - val2 = der.read(); - } - byte[] extVal = (byte[]) val2.getValue(); - extensions.put(extId.toString(), extVal); - if (crit.booleanValue()) - critOids.add(extId.toString()); - else - nonCritOids.add(extId.toString()); - if (extId.equals(ID_KEY_USAGE)) - { - keyUsage = (BitString) DERReader.read(extVal).getValue(); - } - else if (extId.equals(ID_BASIC_CONSTRAINTS)) - { - DERReader bc = new DERReader(extVal); - DERValue constraints = bc.read(); - if (!constraints.isConstructed()) - throw new ASN1ParsingException("malformed BasicConstraints"); - if (constraints.getLength() > 0) - { - boolean ca = false; - int constr = -1; - val2 = bc.read(); - if (val2.getValue() instanceof Boolean) - { - ca = ((Boolean) val2.getValue()).booleanValue(); - if (constraints.getLength() > val2.getEncodedLength()) - val2 = bc.read(); - } - if (val2.getValue() instanceof BigInteger) - constr = ((BigInteger) val2.getValue()).intValue(); - basicConstraints = constr; - } - } + debug("start extension len == " + ext.getLength()); + Extension e = new Extension(ext.getEncoded()); + extensions.put(e.getOid(), e); + der.skip(ext.getLength()); len += ext.getEncodedLength(); + debug("count == " + len); } } val = der.read(); if (!val.isConstructed()) - throw new ASN1ParsingException("malformed AlgorithmIdentifier"); + { + throw new IOException("malformed AlgorithmIdentifier"); + } int sigAlgLen = val.getLength(); + debug("start AlgorithmIdentifier len == " + sigAlgLen); val = der.read(); sigAlgId = (OID) val.getValue(); + debug("read algorithm id == " + sigAlgId); if (sigAlgLen > val.getEncodedLength()) { val = der.read(); if (val.getValue() == null) - sigAlgVal = keyParams; + { + if (subjectKey instanceof DSAPublicKey) + { + AlgorithmParameters params = + AlgorithmParameters.getInstance("DSA"); + DSAParams dsap = ((DSAPublicKey) subjectKey).getParams(); + DSAParameterSpec spec = + new DSAParameterSpec(dsap.getP(), dsap.getQ(), dsap.getG()); + params.init(spec); + sigAlgVal = params.getEncoded(); + } + } else + { sigAlgVal = (byte[]) val.getEncoded(); + } if (val.isConstructed()) + { encoded.skip(val.getLength()); } + debug("read parameters == " + sigAlgVal); + } signature = ((BitString) der.read().getValue()).toByteArray(); + debug("read signature ==\n" + Util.hexDump(signature, ">>>> ")); } } Index: java/security/cert/TrustAnchor.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/security/cert/TrustAnchor.java,v retrieving revision 1.3 diff -u -b -B -r1.3 TrustAnchor.java --- java/security/cert/TrustAnchor.java 21 Oct 2004 20:22:12 -0000 1.3 +++ java/security/cert/TrustAnchor.java 7 Nov 2004 19:25:52 -0000 @@ -140,7 +140,7 @@ public final String getCAName() { if (caName != null) - return caName.toRFC2253(); + return caName.toString(); return null; } @@ -179,7 +179,7 @@ { if (trustedCert == null) return "[ Trusted CA Public Key=" + caKey + ", Trusted CA Issuer Name=" - + caName.toRFC2253() + " ]"; + + caName.toString() + " ]"; return "[ Trusted CA Certificate=" + trustedCert + " ]"; } }