diff options
author | Andreas Tobler <andreast@gcc.gnu.org> | 2004-11-15 21:02:08 +0100 |
---|---|---|
committer | Andreas Tobler <andreast@gcc.gnu.org> | 2004-11-15 21:02:08 +0100 |
commit | 507148866c2116c2d15dadc4b1609eb21ce88a45 (patch) | |
tree | 397eb5fe893a7d4cba478362f2a48f749834452d /libjava/gnu | |
parent | fcb94d103b1e287f95bb7de1c582a25223529654 (diff) | |
download | gcc-507148866c2116c2d15dadc4b1609eb21ce88a45.zip gcc-507148866c2116c2d15dadc4b1609eb21ce88a45.tar.gz gcc-507148866c2116c2d15dadc4b1609eb21ce88a45.tar.bz2 |
004-11-15 Andreas Tobler <a.tobler@schweiz.ch>
Import/Merge the X.509 certificate code from Classpath.
* Makefile.am: Add imported files.
* Makefile.in: Regenerate.
2004-11-07 Casey Marshall <csm@gnu.org>
* gnu/java/security/provider/Gnu.java(<init>): Add entries in a
priviliged action. Add new algorithms.
* gnu/java/security/provider/X509CertificateFactory.java
(engineGenerateCertificate): Chain exceptions.
(engineGenerateCertificates): Likewise.
(engineGenerateCRL): Likewise.
(engineGenerateCRLs): Likewise.
(engineGenerateCertPath): New methods.
(generateCert): Throw exception if 'inStream' is null.
(generateCRL): Likewise.
* gnu/java/security/x509/X500DistinguishedName.java: Replaced with
version from GNU Crypto CVS.
* gnu/java/security/x509/X509CRL.java: Likewise.
* gnu/java/security/x509/X509CRLEntry.java: Likewise.
* gnu/java/security/x509/X509Certificate.java: Likewise.
* java/security/cert/TrustAnchor.java: Call 'toString' and not
toRFC2253.
* gnu/java/security/provider/CollectionCertStoreImpl.java,
* gnu/java/security/provider/EncodedKeyFactory.java,
* gnu/java/security/provider/GnuDHPublicKey.java,
* gnu/java/security/provider/GnuRSAPrivateKey.java,
* gnu/java/security/provider/GnuRSAPublicKey.java,
* gnu/java/security/provider/MD2withRSA.java,
* gnu/java/security/provider/MD4withRSA.java,
* gnu/java/security/provider/MD5withRSA.java,
* gnu/java/security/provider/PKIXCertPathValidatorImpl.java,
* gnu/java/security/provider/RSA.java,
* gnu/java/security/provider/RSAKeyFactory.java,
* gnu/java/security/provider/SHA1withRSA.java,
* gnu/java/security/x509/GnuPKIExtension.java,
* gnu/java/security/x509/PolicyNodeImpl.java,
* gnu/java/security/x509/Util.java,
* gnu/java/security/x509/X509CRLSelectorImpl.java,
* gnu/java/security/x509/X509CertPath.java,
* gnu/java/security/x509/X509CertSelectorImpl.java,
* gnu/java/security/x509/ext/AuthorityKeyIdentifier.java,
* gnu/java/security/x509/ext/BasicConstraints.java,
* gnu/java/security/x509/ext/CRLNumber.java,
* gnu/java/security/x509/ext/CertificatePolicies.java,
* gnu/java/security/x509/ext/ExtendedKeyUsage.java,
* gnu/java/security/x509/ext/Extension.java,
* gnu/java/security/x509/ext/GeneralNames.java,
* gnu/java/security/x509/ext/IssuerAlternativeNames.java,
* gnu/java/security/x509/ext/KeyUsage.java,
* gnu/java/security/x509/ext/PolicyConstraint.java,
* gnu/java/security/x509/ext/PolicyMappings.java,
* gnu/java/security/x509/ext/PrivateKeyUsagePeriod.java,
* gnu/java/security/x509/ext/ReasonCode.java,
* gnu/java/security/x509/ext/SubjectAlternativeNames.java,
* gnu/java/security/x509/ext/SubjectKeyIdentifier.java: New files.
2004-11-07 Casey Marshall <csm@gnu.org>
* gnu/java/security/x509/X509CRL.java:
Missed import statements in previous checkin.
2004-11-07 Casey Marshall <csm@gnu.org>
* gnu/java/security/x509/X509CertPath.java (parse): Fixed reference
to 'X509CertificateImpl' from previous checkin.
From-SVN: r90682
Diffstat (limited to 'libjava/gnu')
39 files changed, 6249 insertions, 1098 deletions
diff --git a/libjava/gnu/java/security/provider/CollectionCertStoreImpl.java b/libjava/gnu/java/security/provider/CollectionCertStoreImpl.java new file mode 100644 index 0000000..1b22cc8 --- /dev/null +++ b/libjava/gnu/java/security/provider/CollectionCertStoreImpl.java @@ -0,0 +1,103 @@ +/* CollectionCertStore.java -- Collection-based cert store. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.provider; + +import java.security.InvalidAlgorithmParameterException; +import java.security.cert.Certificate; +import java.security.cert.CertSelector; +import java.security.cert.CRL; +import java.security.cert.CRLSelector; +import java.security.cert.CertStoreException; +import java.security.cert.CertStoreParameters; +import java.security.cert.CertStoreSpi; +import java.security.cert.CollectionCertStoreParameters; + +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; + +public final class CollectionCertStoreImpl extends CertStoreSpi +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final Collection store; + + // Constructors. + // ------------------------------------------------------------------------- + + public CollectionCertStoreImpl(CertStoreParameters params) + throws InvalidAlgorithmParameterException + { + super(params); + if (! (params instanceof CollectionCertStoreParameters)) + throw new InvalidAlgorithmParameterException("not a CollectionCertStoreParameters object"); + store = ((CollectionCertStoreParameters) params).getCollection(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public Collection engineGetCertificates(CertSelector selector) + throws CertStoreException + { + LinkedList result = new LinkedList(); + for (Iterator it = store.iterator(); it.hasNext(); ) + { + Object o = it.next(); + if ((o instanceof Certificate) && selector.match((Certificate) o)) + result.add(o); + } + return result; + } + + public Collection engineGetCRLs(CRLSelector selector) + throws CertStoreException + { + LinkedList result = new LinkedList(); + for (Iterator it = store.iterator(); it.hasNext(); ) + { + Object o = it.next(); + if ((o instanceof CRL) && selector.match((CRL) o)) + result.add(o); + } + return result; + } +} diff --git a/libjava/gnu/java/security/provider/EncodedKeyFactory.java b/libjava/gnu/java/security/provider/EncodedKeyFactory.java new file mode 100644 index 0000000..e308d44 --- /dev/null +++ b/libjava/gnu/java/security/provider/EncodedKeyFactory.java @@ -0,0 +1,310 @@ +/* EncodedKeyFactory.java -- encoded key factory. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.provider; + +import java.io.IOException; + +import java.math.BigInteger; + +import java.security.AlgorithmParameters; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.KeyFactorySpi; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; + +import java.security.spec.DSAParameterSpec; +import java.security.spec.DSAPrivateKeySpec; +import java.security.spec.DSAPublicKeySpec; +import java.security.spec.InvalidParameterSpecException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.RSAPrivateCrtKeySpec; +import java.security.spec.RSAPublicKeySpec; +import java.security.spec.X509EncodedKeySpec; + +import javax.crypto.spec.DHParameterSpec; + +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; + +/** + * A factory for keys encoded in either the X.509 format (for public + * keys) or the PKCS#8 format (for private keys). + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public class EncodedKeyFactory extends KeyFactorySpi +{ + + // Constants. + // ------------------------------------------------------------------------ + + private static final OID ID_DSA = new OID("1.2.840.10040.4.1"); + private static final OID ID_RSA = new OID("1.2.840.113549.1.1.1"); + private static final OID ID_DH = new OID("1.2.840.10046.2.1"); + + // Instance methods. + // ------------------------------------------------------------------------ + + public PublicKey engineGeneratePublic(KeySpec spec) + throws InvalidKeySpecException + { + if (!(spec instanceof X509EncodedKeySpec)) + throw new InvalidKeySpecException("only supports X.509 key specs"); + DERReader der = new DERReader(((X509EncodedKeySpec) spec).getEncoded()); + try + { + DERValue spki = der.read(); + if (!spki.isConstructed()) + { + throw new InvalidKeySpecException("malformed encoded key"); + } + DERValue alg = der.read(); + if (!alg.isConstructed()) + { + throw new InvalidKeySpecException("malformed encoded key"); + } + DERValue val = der.read(); + if (!(val.getValue() instanceof OID)) + { + throw new InvalidKeySpecException("malformed encoded key"); + } + OID algId = (OID) val.getValue(); + byte[] algParams = null; + if (alg.getLength() > val.getEncodedLength()) + { + val = der.read(); + algParams = val.getEncoded(); + if (val.isConstructed()) + der.skip(val.getLength()); + } + val = der.read(); + if (!(val.getValue() instanceof BitString)) + { + throw new InvalidKeySpecException("malformed encoded key"); + } + byte[] publicKey = ((BitString) val.getValue()).toByteArray(); + if (algId.equals(ID_DSA)) + { + BigInteger p = null, g = null, q = null, Y; + if (algParams != null) + { + DERReader dsaParams = new DERReader(algParams); + val = dsaParams.read(); + if (!val.isConstructed()) + throw new InvalidKeySpecException("malformed DSA parameters"); + val = dsaParams.read(); + if (!(val.getValue() instanceof BigInteger)) + throw new InvalidKeySpecException("malformed DSA parameters"); + p = (BigInteger) val.getValue(); + val = dsaParams.read(); + if (!(val.getValue() instanceof BigInteger)) + throw new InvalidKeySpecException("malformed DSA parameters"); + q = (BigInteger) val.getValue(); + val = dsaParams.read(); + if (!(val.getValue() instanceof BigInteger)) + throw new InvalidKeySpecException("malformed DSA parameters"); + g = (BigInteger) val.getValue(); + } + DERReader dsaPub = new DERReader(publicKey); + val = dsaPub.read(); + if (!(val.getValue() instanceof BigInteger)) + throw new InvalidKeySpecException("malformed DSA parameters"); + Y = (BigInteger) val.getValue(); + return new GnuDSAPublicKey(Y, p, q, g); + } + else if (algId.equals(ID_RSA)) + { + DERReader rsaParams = new DERReader(publicKey); + if (!rsaParams.read().isConstructed()) + { + throw new InvalidKeySpecException("malformed encoded key"); + } + return new GnuRSAPublicKey(new RSAPublicKeySpec( + (BigInteger) rsaParams.read().getValue(), + (BigInteger) rsaParams.read().getValue())); + } + else if (algId.equals(ID_DH)) + { + if (algParams == null) + throw new InvalidKeySpecException("missing DH parameters"); + DERReader dhParams = new DERReader(algParams); + val = dhParams.read(); + BigInteger p, g, q, Y; + if (!val.isConstructed()) + throw new InvalidKeySpecException("malformed DH parameters"); + val = dhParams.read(); + if (!(val.getValue() instanceof BigInteger)) + throw new InvalidKeySpecException("malformed DH parameters"); + p = (BigInteger) val.getValue(); + val = dhParams.read(); + if (!(val.getValue() instanceof BigInteger)) + throw new InvalidKeySpecException("malformed DH parameters"); + g = (BigInteger) val.getValue(); + val = dhParams.read(); + if (!(val.getValue() instanceof BigInteger)) + throw new InvalidKeySpecException("malformed DH parameters"); + q = (BigInteger) val.getValue(); + DERReader dhPub = new DERReader(publicKey); + val = dhPub.read(); + if (!(val.getValue() instanceof BigInteger)) + throw new InvalidKeySpecException("malformed DH parameters"); + Y = (BigInteger) val.getValue(); + return (PublicKey) new GnuDHPublicKey(new DHParameterSpec(p, g), Y, q); + } + else + throw new InvalidKeySpecException("unknown algorithm: " + algId); + } + catch (IOException ioe) + { + throw new InvalidKeySpecException(ioe.getMessage()); + } + } + + public PrivateKey engineGeneratePrivate(KeySpec spec) + throws InvalidKeySpecException + { + if (!(spec instanceof PKCS8EncodedKeySpec)) + { + throw new InvalidKeySpecException("only supports PKCS8 key specs"); + } + DERReader der = new DERReader(((PKCS8EncodedKeySpec) spec).getEncoded()); + try + { + DERValue pki = der.read(); + if (!pki.isConstructed()) + { + throw new InvalidKeySpecException("malformed encoded key"); + } + DERValue val = der.read(); + if (!(val.getValue() instanceof BigInteger)) + { + throw new InvalidKeySpecException("malformed encoded key"); + } + DERValue alg = der.read(); + if (!alg.isConstructed()) + { + throw new InvalidKeySpecException("malformed encoded key"); + } + val = der.read(); + if (!(val.getValue() instanceof OID)) + { + throw new InvalidKeySpecException("malformed encoded key"); + } + OID algId = (OID) val.getValue(); + byte[] algParams = null; + if (alg.getLength() > val.getEncodedLength()) + { + val = der.read(); + algParams = val.getEncoded(); + if (val.isConstructed()) + der.skip(val.getLength()); + } + byte[] privateKey = (byte[]) der.read().getValue(); + if (algId.equals(ID_DSA)) + { + if (algParams == null) + { + throw new InvalidKeySpecException("missing DSA parameters"); + } + AlgorithmParameters params = AlgorithmParameters.getInstance("DSA"); + params.init(algParams); + DSAParameterSpec dsaSpec = (DSAParameterSpec) + params.getParameterSpec(DSAParameterSpec.class); + DERReader dsaPriv = new DERReader(privateKey); + return new GnuDSAPrivateKey((BigInteger) dsaPriv.read().getValue(), + dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG()); + } + else if (algId.equals(ID_RSA)) + { + DERReader rsaParams = new DERReader(privateKey); + if (!rsaParams.read().isConstructed()) + throw new InvalidKeySpecException("malformed encoded key"); + return new GnuRSAPrivateKey(new RSAPrivateCrtKeySpec( + (BigInteger) rsaParams.read().getValue(), // n + (BigInteger) rsaParams.read().getValue(), // e + (BigInteger) rsaParams.read().getValue(), // d + (BigInteger) rsaParams.read().getValue(), // p + (BigInteger) rsaParams.read().getValue(), // q + (BigInteger) rsaParams.read().getValue(), // d mod (p - 1) + (BigInteger) rsaParams.read().getValue(), // d mod (q - 1) + (BigInteger) rsaParams.read().getValue())); // (inv q) mod p + } + else + throw new InvalidKeySpecException("unknown algorithm: " + algId); + } + catch (InvalidParameterSpecException iapse) + { + throw new InvalidKeySpecException(iapse.getMessage()); + } + catch (NoSuchAlgorithmException nsae) + { + throw new InvalidKeySpecException(nsae.getMessage()); + } + catch (IOException ioe) + { + throw new InvalidKeySpecException(ioe.getMessage()); + } + } + + public KeySpec engineGetKeySpec(Key key, Class speClass) + throws InvalidKeySpecException + { + if ((key instanceof PrivateKey) && key.getFormat().equals("PKCS#8") + && speClass.isAssignableFrom(PKCS8EncodedKeySpec.class)) + return new PKCS8EncodedKeySpec(key.getEncoded()); + else if ((key instanceof PublicKey) && key.getFormat().equals("X.509") + && speClass.isAssignableFrom(X509EncodedKeySpec.class)) + return new X509EncodedKeySpec(key.getEncoded()); + else + throw new InvalidKeySpecException(); + } + + public Key engineTranslateKey(Key key) throws InvalidKeyException + { + throw new InvalidKeyException("translating keys not supported"); + } +} diff --git a/libjava/gnu/java/security/provider/Gnu.java b/libjava/gnu/java/security/provider/Gnu.java index 70a7d1d..02f509d 100644 --- a/libjava/gnu/java/security/provider/Gnu.java +++ b/libjava/gnu/java/security/provider/Gnu.java @@ -7,7 +7,7 @@ GNU Classpath is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. - + GNU Classpath is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -37,75 +37,131 @@ exception statement from your version. */ 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"); - - // 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. - - // Signature - put("Signature.SHA1withDSA", - gnu.java.security.provider.DSASignature.class.getName()); - - put("Alg.Alias.Signature.DSS", "SHA1withDSA"); - put("Alg.Alias.Signature.DSA", "SHA1withDSA"); - put("Alg.Alias.Signature.SHAwithDSA", "SHA1withDSA"); - put("Alg.Alias.Signature.DSAwithSHA", "SHA1withDSA"); - put("Alg.Alias.Signature.DSAwithSHA1", "SHA1withDSA"); - put("Alg.Alias.Signature.SHA/DSA", "SHA1withDSA"); - put("Alg.Alias.Signature.SHA-1/DSA", "SHA1withDSA"); - put("Alg.Alias.Signature.SHA1/DSA", "SHA1withDSA"); - put("Alg.Alias.Signature.OID.1.2.840.10040.4.3", "SHA1withDSA"); - put("Alg.Alias.Signature.1.2.840.10040.4.3", "SHA1withDSA"); - put("Alg.Alias.Signature.1.3.14.3.2.13", "SHA1withDSA"); - put("Alg.Alias.Signature.1.3.14.3.2.27", "SHA1withDSA"); - - // Key Pair Generator - put("KeyPairGenerator.DSA", - gnu.java.security.provider.DSAKeyPairGenerator.class.getName()); - - put("Alg.Alias.KeyPairGenerator.OID.1.2.840.10040.4.1", "DSA"); - put("Alg.Alias.KeyPairGenerator.1.2.840.10040.4.1", "DSA"); - put("Alg.Alias.KeyPairGenerator.1.3.14.3.2.12", "DSA"); - - // Key Factory - put("KeyFactory.DSA", - gnu.java.security.provider.DSAKeyFactory.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"); - - // Message Digests - put("MessageDigest.SHA", gnu.java.security.provider.SHA.class.getName()); - put("MessageDigest.MD5", gnu.java.security.provider.MD5.class.getName()); - - // Format "Alias", "Actual Name" - put("Alg.Alias.MessageDigest.SHA1", "SHA"); - put("Alg.Alias.MessageDigest.SHA-1", "SHA"); - - // Algorithm Parameters - put("AlgorithmParameters.DSA", - gnu.java.security.provider.DSAParameters.class.getName()); - - // Algorithm Parameter Generator - put("AlgorithmParameterGenerator.DSA", - gnu.java.security.provider.DSAParameterGenerator.class.getName()); - - // SecureRandom - put("SecureRandom.SHA1PRNG", - gnu.java.security.provider.SHA1PRNG.class.getName()); - - // CertificateFactory - put("CertificateFactory.X.509", - gnu.java.security.provider.X509CertificateFactory.class.getName()); - - put("Alg.Alias.CertificateFactory.X509", "X.509"); + 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. + + // Signature + put("Signature.SHA1withDSA", + gnu.java.security.provider.DSASignature.class.getName()); + + put("Alg.Alias.Signature.DSS", "SHA1withDSA"); + put("Alg.Alias.Signature.DSA", "SHA1withDSA"); + put("Alg.Alias.Signature.SHAwithDSA", "SHA1withDSA"); + put("Alg.Alias.Signature.DSAwithSHA", "SHA1withDSA"); + put("Alg.Alias.Signature.DSAwithSHA1", "SHA1withDSA"); + put("Alg.Alias.Signature.SHA/DSA", "SHA1withDSA"); + put("Alg.Alias.Signature.SHA-1/DSA", "SHA1withDSA"); + put("Alg.Alias.Signature.SHA1/DSA", "SHA1withDSA"); + put("Alg.Alias.Signature.OID.1.2.840.10040.4.3", "SHA1withDSA"); + put("Alg.Alias.Signature.1.2.840.10040.4.3", "SHA1withDSA"); + 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()); + + put("Alg.Alias.KeyPairGenerator.OID.1.2.840.10040.4.1", "DSA"); + put("Alg.Alias.KeyPairGenerator.1.2.840.10040.4.1", "DSA"); + put("Alg.Alias.KeyPairGenerator.1.3.14.3.2.12", "DSA"); + + // Key Factory + 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"); + + // Message Digests + put("MessageDigest.SHA", gnu.java.security.provider.SHA.class.getName()); + put("MessageDigest.MD5", gnu.java.security.provider.MD5.class.getName()); + + // Format "Alias", "Actual Name" + put("Alg.Alias.MessageDigest.SHA1", "SHA"); + put("Alg.Alias.MessageDigest.SHA-1", "SHA"); + + // Algorithm Parameters + 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()); + + // SecureRandom + put("SecureRandom.SHA1PRNG", + gnu.java.security.provider.SHA1PRNG.class.getName()); + + // CertificateFactory + 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"); + + // CertStore + put("CertStore.Collection", CollectionCertStoreImpl.class.getName()); + + return null; + } + }); } } diff --git a/libjava/gnu/java/security/provider/GnuDHPublicKey.java b/libjava/gnu/java/security/provider/GnuDHPublicKey.java new file mode 100644 index 0000000..a650761 --- /dev/null +++ b/libjava/gnu/java/security/provider/GnuDHPublicKey.java @@ -0,0 +1,117 @@ +/* GnuDHPublicKey.java -- A Diffie-Hellman public key. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.provider; + +import java.math.BigInteger; + +import java.util.ArrayList; + +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHParameterSpec; + +import gnu.java.security.OID; +import gnu.java.security.der.BitString; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; + +public class GnuDHPublicKey implements DHPublicKey +{ + + // Fields. + // ------------------------------------------------------------------------- + + private byte[] encoded; + private final DHParameterSpec params; + private final BigInteger Y; + private final BigInteger q; + + // Constructor. + // ------------------------------------------------------------------------- + + public GnuDHPublicKey(DHParameterSpec params, BigInteger Y, BigInteger q) + { + this.params = params; + this.Y = Y; + this.q = q; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public BigInteger getY() + { + return Y; + } + + public DHParameterSpec getParams() + { + return params; + } + + public String getAlgorithm() + { + return "DH"; + } + + public String getFormat() + { + return "X.509"; + } + + public byte[] getEncoded() + { + if (encoded != null) + return (byte[]) encoded.clone(); + ArrayList spki = new ArrayList(2); + ArrayList alg = new ArrayList(2); + alg.add(new DERValue(DER.OBJECT_IDENTIFIER, new OID("1.2.840.10046.2.1"))); + ArrayList param = new ArrayList(3); + param.add(new DERValue(DER.INTEGER, params.getP())); + param.add(new DERValue(DER.INTEGER, params.getG())); + param.add(new DERValue(DER.INTEGER, q)); + alg.add(new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, param)); + spki.add(new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, alg)); + spki.add(new DERValue(DER.BIT_STRING, new BitString(Y.toByteArray()))); + encoded = new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, spki).getEncoded(); + if (encoded != null) + return (byte[]) encoded.clone(); + return null; + } +} diff --git a/libjava/gnu/java/security/provider/GnuRSAPrivateKey.java b/libjava/gnu/java/security/provider/GnuRSAPrivateKey.java new file mode 100644 index 0000000..455326d --- /dev/null +++ b/libjava/gnu/java/security/provider/GnuRSAPrivateKey.java @@ -0,0 +1,166 @@ +/* GnuRSAPrivateKey.java -- GNU RSA private key. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.provider; + +import java.math.BigInteger; + +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.spec.RSAPrivateCrtKeySpec; + +import java.util.ArrayList; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERValue; + +class GnuRSAPrivateKey implements RSAPrivateCrtKey +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final RSAPrivateCrtKeySpec spec; + private byte[] encodedKey; + + // Constructor. + // ------------------------------------------------------------------------- + + public GnuRSAPrivateKey(RSAPrivateCrtKeySpec spec) + { + this.spec = spec; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public BigInteger getModulus() + { + return spec.getModulus(); + } + + public BigInteger getPrivateExponent() + { + return spec.getPrivateExponent(); + } + + public BigInteger getCrtCoefficient() + { + return spec.getCrtCoefficient(); + } + + public BigInteger getPrimeExponentP() + { + return spec.getPrimeExponentP(); + } + + public BigInteger getPrimeExponentQ() + { + return spec.getPrimeExponentQ(); + } + + public BigInteger getPrimeP() + { + return spec.getPrimeP(); + } + + public BigInteger getPrimeQ() + { + return spec.getPrimeQ(); + } + + public BigInteger getPublicExponent() + { + return spec.getPublicExponent(); + } + + public String getAlgorithm() + { + return "RSA"; + } + + public String getFormat() + { + return "PKCS#8"; + } + + /** + * The encoded form is: + * + * <pre> + * RSAPrivateKey ::= SEQUENCE { + * version Version, + * modulus INTEGER, -- n + * publicExponent INTEGER, -- e + * privateExponent INTEGER, -- d + * prime1 INTEGER, -- p + * prime2 INTEGER, -- q + * exponent1 INTEGER, -- d mod (p-1) + * exponent2 INTEGER, -- d mod (q-1) + * coefficient INTEGER -- (inverse of q) mod p } + * </pre> + * + * <p>Which is in turn encoded in a PrivateKeyInfo structure from PKCS#8. + */ + public byte[] getEncoded() + { + if (encodedKey != null) + return (byte[]) encodedKey.clone(); + ArrayList key = new ArrayList(9); + key.add(new DERValue(DER.INTEGER, BigInteger.ZERO)); + key.add(new DERValue(DER.INTEGER, getModulus())); + key.add(new DERValue(DER.INTEGER, getPublicExponent())); + key.add(new DERValue(DER.INTEGER, getPrivateExponent())); + key.add(new DERValue(DER.INTEGER, getPrimeP())); + key.add(new DERValue(DER.INTEGER, getPrimeQ())); + key.add(new DERValue(DER.INTEGER, getPrimeExponentP())); + key.add(new DERValue(DER.INTEGER, getPrimeExponentQ())); + key.add(new DERValue(DER.INTEGER, getCrtCoefficient())); + DERValue pk = new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, key); + ArrayList pki = new ArrayList(3); + pki.add(new DERValue(DER.INTEGER, BigInteger.ZERO)); + ArrayList alg = new ArrayList(2); + alg.add(new DERValue(DER.OBJECT_IDENTIFIER, + new OID("1.2.840.113549.1.1.1"))); + alg.add(new DERValue(DER.NULL, null)); + pki.add(new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, alg)); + pki.add(new DERValue(DER.OCTET_STRING, pk.getEncoded())); + encodedKey = new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, pki).getEncoded(); + return (byte[]) encodedKey.clone(); + } +} diff --git a/libjava/gnu/java/security/provider/GnuRSAPublicKey.java b/libjava/gnu/java/security/provider/GnuRSAPublicKey.java new file mode 100644 index 0000000..502fccc --- /dev/null +++ b/libjava/gnu/java/security/provider/GnuRSAPublicKey.java @@ -0,0 +1,109 @@ +/* GnuRSAPublicKey.java -- GNU RSA public key. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.provider; + +import java.math.BigInteger; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.RSAPublicKeySpec; +import java.util.ArrayList; + +import gnu.java.security.OID; +import gnu.java.security.der.BitString; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERValue; + +class GnuRSAPublicKey implements RSAPublicKey +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final RSAPublicKeySpec spec; + private byte[] encodedKey; + + // Constructor. + // ------------------------------------------------------------------------- + + public GnuRSAPublicKey(RSAPublicKeySpec spec) + { + this.spec = spec; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public BigInteger getModulus() + { + return spec.getModulus(); + } + + public BigInteger getPublicExponent() + { + return spec.getPublicExponent(); + } + + public String getAlgorithm() + { + return "RSA"; + } + + public String getFormat() + { + return "X.509"; + } + + public byte[] getEncoded() + { + if (encodedKey != null) + return (byte[]) encodedKey.clone(); + ArrayList key = new ArrayList(2); + key.add(new DERValue(DER.INTEGER, getModulus())); + key.add(new DERValue(DER.INTEGER, getPublicExponent())); + DERValue rsapk = new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, key); + ArrayList alg = new ArrayList(2); + alg.add(new DERValue(DER.OBJECT_IDENTIFIER, + new OID("1.2.840.113549.1.1.1"))); + alg.add(new DERValue(DER.NULL, null)); + ArrayList spki = new ArrayList(2); + spki.add(new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, alg)); + spki.add(new DERValue(DER.BIT_STRING, new BitString(rsapk.getEncoded()))); + encodedKey = new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, spki).getEncoded(); + return (byte[]) encodedKey.clone(); + } +} diff --git a/libjava/gnu/java/security/provider/MD2withRSA.java b/libjava/gnu/java/security/provider/MD2withRSA.java new file mode 100644 index 0000000..c43d07a --- /dev/null +++ b/libjava/gnu/java/security/provider/MD2withRSA.java @@ -0,0 +1,54 @@ +/* MD2withRSA.java -- MD2 with RSA encryption signatures. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.provider; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class MD2withRSA extends RSA +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public MD2withRSA() throws NoSuchAlgorithmException + { + super(MessageDigest.getInstance("MD2"), DIGEST_ALGORITHM.getChild(2)); + } +} diff --git a/libjava/gnu/java/security/provider/MD4withRSA.java b/libjava/gnu/java/security/provider/MD4withRSA.java new file mode 100644 index 0000000..86cd2be --- /dev/null +++ b/libjava/gnu/java/security/provider/MD4withRSA.java @@ -0,0 +1,54 @@ +/* MD4withRSA.java -- MD4 with RSA encryption signatures. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.provider; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class MD4withRSA extends RSA +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public MD4withRSA() throws NoSuchAlgorithmException + { + super(MessageDigest.getInstance("MD4"), DIGEST_ALGORITHM.getChild(4)); + } +} diff --git a/libjava/gnu/java/security/provider/MD5withRSA.java b/libjava/gnu/java/security/provider/MD5withRSA.java new file mode 100644 index 0000000..ec8370d --- /dev/null +++ b/libjava/gnu/java/security/provider/MD5withRSA.java @@ -0,0 +1,54 @@ +/* MD5withRSA.java -- MD5 with RSA encryption signatures. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.provider; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class MD5withRSA extends RSA +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public MD5withRSA() throws NoSuchAlgorithmException + { + super(MessageDigest.getInstance("MD5"), DIGEST_ALGORITHM.getChild(5)); + } +} diff --git a/libjava/gnu/java/security/provider/PKIXCertPathValidatorImpl.java b/libjava/gnu/java/security/provider/PKIXCertPathValidatorImpl.java new file mode 100644 index 0000000..7d1d857 --- /dev/null +++ b/libjava/gnu/java/security/provider/PKIXCertPathValidatorImpl.java @@ -0,0 +1,689 @@ +/* PKIXCertPathValidatorImpl.java -- PKIX certificate path validator. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.provider; + +import java.io.IOException; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Principal; +import java.security.PublicKey; + +import java.security.cert.*; + +import java.security.interfaces.DSAParams; +import java.security.interfaces.DSAPublicKey; +import java.security.spec.DSAParameterSpec; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import gnu.java.security.x509.GnuPKIExtension; +import gnu.java.security.x509.PolicyNodeImpl; +import gnu.java.security.x509.X509CertSelectorImpl; +import gnu.java.security.x509.X509CRLSelectorImpl; +import gnu.java.security.x509.ext.*; +import gnu.java.security.OID; + +/** + * An implementation of the Public Key Infrastructure's X.509 + * certificate path validation algorithm. + * + * <p>See <a href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280: + * Internet X.509 Public Key Infrastructure Certificate and + * Certificate Revocation List (CRL) Profile</a>. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public class PKIXCertPathValidatorImpl extends CertPathValidatorSpi +{ + + // Constants. + // ------------------------------------------------------------------------- + + private static final boolean DEBUG = false; + private static void debug (String msg) + { + System.err.print (">> PKIXCertPathValidatorImpl: "); + System.err.println (msg); + } + + public static final String ANY_POLICY = "2.5.29.32.0"; + + // Constructor. + // ------------------------------------------------------------------------- + + public PKIXCertPathValidatorImpl() + { + super(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public CertPathValidatorResult engineValidate(CertPath path, + CertPathParameters params) + throws CertPathValidatorException, InvalidAlgorithmParameterException + { + if (!(params instanceof PKIXParameters)) + throw new InvalidAlgorithmParameterException("not a PKIXParameters object"); + + // First check if the certificate path is valid. + // + // This means that: + // + // (a) for all x in {1, ..., n-1}, the subject of certificate x is + // the issuer of certificate x+1; + // + // (b) for all x in {1, ..., n}, the certificate was valid at the + // time in question. + // + // Because this is the X.509 algorithm, we also check if all + // cerificates are of type X509Certificate. + + PolicyNodeImpl rootNode = new PolicyNodeImpl(); + Set initPolicies = ((PKIXParameters) params).getInitialPolicies(); + rootNode.setValidPolicy(ANY_POLICY); + rootNode.setCritical(false); + rootNode.setDepth(0); + if (initPolicies != null) + rootNode.addAllExpectedPolicies(initPolicies); + else + rootNode.addExpectedPolicy(ANY_POLICY); + List checks = ((PKIXParameters) params).getCertPathCheckers(); + List l = path.getCertificates(); + if (l == null || l.size() == 0) + throw new CertPathValidatorException(); + X509Certificate[] p = null; + try + { + p = (X509Certificate[]) l.toArray(new X509Certificate[l.size()]); + } + catch (ClassCastException cce) + { + throw new CertPathValidatorException("invalid certificate path"); + } + + String sigProvider = ((PKIXParameters) params).getSigProvider(); + PublicKey prevKey = null; + Date now = ((PKIXParameters) params).getDate(); + if (now == null) + now = new Date(); + LinkedList policyConstraints = new LinkedList(); + for (int i = p.length - 1; i >= 0; i--) + { + try + { + p[i].checkValidity(now); + } + catch (CertificateException ce) + { + throw new CertPathValidatorException(ce.toString()); + } + Set uce = getCritExts(p[i]); + for (Iterator check = checks.iterator(); check.hasNext(); ) + { + try + { + ((PKIXCertPathChecker) check.next()).check(p[i], uce); + } + catch (Exception x) + { + } + } + + PolicyConstraint constr = null; + if (p[i] instanceof GnuPKIExtension) + { + Extension pcx = + ((GnuPKIExtension) p[i]).getExtension (PolicyConstraint.ID); + if (pcx != null) + constr = (PolicyConstraint) pcx.getValue(); + } + else + { + byte[] pcx = p[i].getExtensionValue (PolicyConstraint.ID.toString()); + if (pcx != null) + { + try + { + constr = new PolicyConstraint (pcx); + } + catch (Exception x) + { + } + } + } + if (constr != null && constr.getRequireExplicitPolicy() >= 0) + { + policyConstraints.add (new int[] + { p.length-i, constr.getRequireExplicitPolicy() }); + } + + updatePolicyTree(p[i], rootNode, p.length-i, (PKIXParameters) params, + checkExplicitPolicy (p.length-i, policyConstraints)); + + // The rest of the tests involve this cert's relationship with the + // next in the path. If this cert is the end entity, we can stop. + if (i == 0) + break; + + basicSanity(p, i); + PublicKey pubKey = null; + try + { + pubKey = p[i].getPublicKey(); + if (pubKey instanceof DSAPublicKey) + { + DSAParams dsa = ((DSAPublicKey) pubKey).getParams(); + // If the DSA public key is missing its parameters, use those + // from the previous cert's key. + if (dsa == null || dsa.getP() == null || dsa.getG() == null + || dsa.getQ() == null) + { + if (prevKey == null) + throw new InvalidKeyException("DSA keys not chainable"); + if (!(prevKey instanceof DSAPublicKey)) + throw new InvalidKeyException("DSA keys not chainable"); + dsa = ((DSAPublicKey) prevKey).getParams(); + pubKey = new GnuDSAPublicKey(((DSAPublicKey) pubKey).getY(), + dsa.getP(), dsa.getQ(), dsa.getG()); + } + } + if (sigProvider == null) + p[i-1].verify(pubKey); + else + p[i-1].verify(pubKey, sigProvider); + prevKey = pubKey; + } + catch (Exception e) + { + throw new CertPathValidatorException(e.toString()); + } + if (!p[i].getSubjectDN().equals(p[i-1].getIssuerDN())) + throw new CertPathValidatorException("issuer DN mismatch"); + boolean[] issuerUid = p[i-1].getIssuerUniqueID(); + boolean[] subjectUid = p[i].getSubjectUniqueID(); + if (issuerUid != null && subjectUid != null) + if (!Arrays.equals(issuerUid, subjectUid)) + throw new CertPathValidatorException("UID mismatch"); + + // Check the certificate against the revocation lists. + if (((PKIXParameters) params).isRevocationEnabled()) + { + X509CRLSelectorImpl selector = new X509CRLSelectorImpl(); + try + { + selector.addIssuerName(p[i].getSubjectDN()); + } + catch (IOException ioe) + { + throw new CertPathValidatorException("error selecting CRLs"); + } + List certStores = ((PKIXParameters) params).getCertStores(); + List crls = new LinkedList(); + for (Iterator it = certStores.iterator(); it.hasNext(); ) + { + CertStore cs = (CertStore) it.next(); + try + { + Collection c = cs.getCRLs(selector); + crls.addAll(c); + } + catch (CertStoreException cse) + { + } + } + if (crls.isEmpty()) + throw new CertPathValidatorException("no CRLs for issuer"); + boolean certOk = false; + for (Iterator it = crls.iterator(); it.hasNext(); ) + { + CRL crl = (CRL) it.next(); + if (!(crl instanceof X509CRL)) + continue; + X509CRL xcrl = (X509CRL) crl; + if (!checkCRL(xcrl, p, now, p[i], pubKey, certStores)) + continue; + if (xcrl.isRevoked(p[i-1])) + throw new CertPathValidatorException("certificate is revoked"); + else + certOk = true; + } + if (!certOk) + throw new CertPathValidatorException("certificate's validity could not be determined"); + } + } + rootNode.setReadOnly(); + + // Now ensure that the first certificate in the chain was issued + // by a trust anchor. + Exception cause = null; + Set anchors = ((PKIXParameters) params).getTrustAnchors(); + for (Iterator i = anchors.iterator(); i.hasNext(); ) + { + TrustAnchor anchor = (TrustAnchor) i.next(); + X509Certificate anchorCert = null; + PublicKey anchorKey = null; + if (anchor.getTrustedCert() != null) + { + anchorCert = anchor.getTrustedCert(); + anchorKey = anchorCert.getPublicKey(); + } + else + anchorKey = anchor.getCAPublicKey(); + if (anchorKey == null) + continue; + try + { + if (anchorCert == null) + anchorCert.checkValidity(now); + p[p.length-1].verify(anchorKey); + if (anchorCert != null && anchorCert.getBasicConstraints() >= 0 + && anchorCert.getBasicConstraints() < p.length) + continue; + + if (((PKIXParameters) params).isRevocationEnabled()) + { + X509CRLSelectorImpl selector = new X509CRLSelectorImpl(); + if (anchorCert != null) + try + { + selector.addIssuerName(anchorCert.getSubjectDN()); + } + catch (IOException ioe) + { + } + else + selector.addIssuerName(anchor.getCAName()); + List certStores = ((PKIXParameters) params).getCertStores(); + List crls = new LinkedList(); + for (Iterator it = certStores.iterator(); it.hasNext(); ) + { + CertStore cs = (CertStore) it.next(); + try + { + Collection c = cs.getCRLs(selector); + crls.addAll(c); + } + catch (CertStoreException cse) + { + } + } + if (crls.isEmpty()) + continue; + for (Iterator it = crls.iterator(); it.hasNext(); ) + { + CRL crl = (CRL) it.next(); + if (!(crl instanceof X509CRL)) + continue; + X509CRL xcrl = (X509CRL) crl; + try + { + xcrl.verify(anchorKey); + } + catch (Exception x) + { + continue; + } + Date nextUpdate = xcrl.getNextUpdate(); + if (nextUpdate != null && nextUpdate.compareTo(now) < 0) + continue; + if (xcrl.isRevoked(p[p.length-1])) + throw new CertPathValidatorException("certificate is revoked"); + } + } + + // The chain is valid; return the result. + return new PKIXCertPathValidatorResult(anchor, rootNode, + p[0].getPublicKey()); + } + catch (Exception ignored) + { + cause = ignored; + continue; + } + } + + // The path is not valid. + CertPathValidatorException cpve = + new CertPathValidatorException("path validation failed"); + if (cause != null) + cpve.initCause (cause); + throw cpve; + } + + // Own methods. + // ------------------------------------------------------------------------- + + /** + * Check if a given CRL is acceptable for checking the revocation status + * of certificates in the path being checked. + * + * <p>The CRL is accepted iff:</p> + * + * <ol> + * <li>The <i>nextUpdate</i> field (if present) is in the future.</li> + * <li>The CRL does not contain any unsupported critical extensions.</li> + * <li>The CRL is signed by one of the certificates in the path, or,</li> + * <li>The CRL is signed by the given public key and was issued by the + * public key's subject, or,</li> + * <li>The CRL is signed by a certificate in the given cert stores, and + * that cert is signed by one of the certificates in the path.</li> + * </ol> + * + * @param crl The CRL being checked. + * @param path The path this CRL is being checked against. + * @param now The value to use as 'now'. + * @param pubKeySubject The subject of the public key. + * @param pubKey The public key to check. + * @return True if the CRL is acceptable. + */ + private static boolean checkCRL(X509CRL crl, X509Certificate[] path, Date now, + X509Certificate pubKeyCert, PublicKey pubKey, + List certStores) + { + Date nextUpdate = crl.getNextUpdate(); + if (nextUpdate != null && nextUpdate.compareTo(now) < 0) + return false; + if (crl.hasUnsupportedCriticalExtension()) + return false; + for (int i = 0; i < path.length; i++) + { + if (!path[i].getSubjectDN().equals(crl.getIssuerDN())) + continue; + boolean[] keyUsage = path[i].getKeyUsage(); + if (keyUsage != null) + { + if (!keyUsage[KeyUsage.CRL_SIGN]) + continue; + } + try + { + crl.verify(path[i].getPublicKey()); + return true; + } + catch (Exception x) + { + } + } + if (crl.getIssuerDN().equals(pubKeyCert.getSubjectDN())) + { + try + { + boolean[] keyUsage = pubKeyCert.getKeyUsage(); + if (keyUsage != null) + { + if (!keyUsage[KeyUsage.CRL_SIGN]) + throw new Exception(); + } + crl.verify(pubKey); + return true; + } + catch (Exception x) + { + } + } + try + { + X509CertSelectorImpl select = new X509CertSelectorImpl(); + select.addSubjectName(crl.getIssuerDN()); + List certs = new LinkedList(); + for (Iterator it = certStores.iterator(); it.hasNext(); ) + { + CertStore cs = (CertStore) it.next(); + try + { + certs.addAll(cs.getCertificates(select)); + } + catch (CertStoreException cse) + { + } + } + for (Iterator it = certs.iterator(); it.hasNext(); ) + { + X509Certificate c = (X509Certificate) it.next(); + for (int i = 0; i < path.length; i++) + { + if (!c.getIssuerDN().equals(path[i].getSubjectDN())) + continue; + boolean[] keyUsage = c.getKeyUsage(); + if (keyUsage != null) + { + if (!keyUsage[KeyUsage.CRL_SIGN]) + continue; + } + try + { + c.verify(path[i].getPublicKey()); + crl.verify(c.getPublicKey()); + return true; + } + catch (Exception x) + { + } + } + if (c.getIssuerDN().equals(pubKeyCert.getSubjectDN())) + { + c.verify(pubKey); + crl.verify(c.getPublicKey()); + } + } + } + catch (Exception x) + { + } + return false; + } + + private static Set getCritExts(X509Certificate cert) + { + HashSet s = new HashSet(); + if (cert instanceof GnuPKIExtension) + { + Collection exts = ((GnuPKIExtension) cert).getExtensions(); + for (Iterator it = exts.iterator(); it.hasNext(); ) + { + Extension ext = (Extension) it.next(); + if (ext.isCritical() && !ext.isSupported()) + s.add(ext.getOid().toString()); + } + } + else + s.addAll(cert.getCriticalExtensionOIDs()); + return s; + } + + /** + * Perform a basic sanity check on the CA certificate at <code>index</code>. + */ + private static void basicSanity(X509Certificate[] path, int index) + throws CertPathValidatorException + { + X509Certificate cert = path[index]; + int pathLen = 0; + for (int i = index - 1; i > 0; i--) + { + if (!path[i].getIssuerDN().equals(path[i].getSubjectDN())) + pathLen++; + } + Extension e = null; + if (cert instanceof GnuPKIExtension) + { + e = ((GnuPKIExtension) cert).getExtension(BasicConstraints.ID); + } + else + { + try + { + e = new Extension(cert.getExtensionValue(BasicConstraints.ID.toString())); + } + catch (Exception x) + { + } + } + if (e == null) + throw new CertPathValidatorException("no basicConstraints"); + BasicConstraints bc = (BasicConstraints) e.getValue(); + if (!bc.isCA()) + throw new CertPathValidatorException("certificate cannot be used to verify signatures"); + if (bc.getPathLengthConstraint() >= 0 && bc.getPathLengthConstraint() < pathLen) + throw new CertPathValidatorException("path is too long"); + + boolean[] keyUsage = cert.getKeyUsage(); + if (keyUsage != null) + { + if (!keyUsage[KeyUsage.KEY_CERT_SIGN]) + throw new CertPathValidatorException("certificate cannot be used to sign certificates"); + } + } + + private static void updatePolicyTree(X509Certificate cert, PolicyNodeImpl root, + int depth, PKIXParameters params, + boolean explicitPolicy) + throws CertPathValidatorException + { + if (DEBUG) debug("updatePolicyTree depth == " + depth); + Set nodes = new HashSet(); + LinkedList stack = new LinkedList(); + Iterator current = null; + stack.addLast(Collections.singleton(root).iterator()); + do + { + current = (Iterator) stack.removeLast(); + while (current.hasNext()) + { + PolicyNodeImpl p = (PolicyNodeImpl) current.next(); + if (DEBUG) debug("visiting node == " + p); + if (p.getDepth() == depth - 1) + { + if (DEBUG) debug("added node"); + nodes.add(p); + } + else + { + if (DEBUG) debug("skipped node"); + stack.addLast(current); + current = p.getChildren(); + } + } + } + while (!stack.isEmpty()); + + Extension e = null; + CertificatePolicies policies = null; + List qualifierInfos = null; + if (cert instanceof GnuPKIExtension) + { + e = ((GnuPKIExtension) cert).getExtension(CertificatePolicies.ID); + if (e != null) + policies = (CertificatePolicies) e.getValue(); + } + + List cp = null; + if (policies != null) + cp = policies.getPolicies(); + else + cp = Collections.EMPTY_LIST; + boolean match = false; + if (DEBUG) debug("nodes are == " + nodes); + if (DEBUG) debug("cert policies are == " + cp); + for (Iterator it = nodes.iterator(); it.hasNext(); ) + { + PolicyNodeImpl parent = (PolicyNodeImpl) it.next(); + if (DEBUG) debug("adding policies to " + parent); + for (Iterator it2 = cp.iterator(); it2.hasNext(); ) + { + OID policy = (OID) it2.next(); + if (DEBUG) debug("trying to add policy == " + policy); + if (policy.toString().equals(ANY_POLICY) && + params.isAnyPolicyInhibited()) + continue; + PolicyNodeImpl child = new PolicyNodeImpl(); + child.setValidPolicy(policy.toString()); + child.addExpectedPolicy(policy.toString()); + if (parent.getExpectedPolicies().contains(policy.toString())) + { + parent.addChild(child); + match = true; + } + else if (parent.getExpectedPolicies().contains(ANY_POLICY)) + { + parent.addChild(child); + match = true; + } + else if (ANY_POLICY.equals (policy.toString())) + { + parent.addChild (child); + match = true; + } + if (match && policies != null) + { + List qualifiers = policies.getPolicyQualifierInfos (policy); + if (qualifiers != null) + child.addAllPolicyQualifiers (qualifiers); + } + } + } + if (!match && (params.isExplicitPolicyRequired() || explicitPolicy)) + throw new CertPathValidatorException("policy tree building failed"); + } + + private boolean checkExplicitPolicy (int depth, List explicitPolicies) + { + if (DEBUG) debug ("checkExplicitPolicy depth=" + depth); + for (Iterator it = explicitPolicies.iterator(); it.hasNext(); ) + { + int[] i = (int[]) it.next(); + int caDepth = i[0]; + int limit = i[1]; + if (DEBUG) debug (" caDepth=" + caDepth + " limit=" + limit); + if (depth - caDepth >= limit) + return true; + } + return false; + } +} diff --git a/libjava/gnu/java/security/provider/RSA.java b/libjava/gnu/java/security/provider/RSA.java new file mode 100644 index 0000000..5afa8b7 --- /dev/null +++ b/libjava/gnu/java/security/provider/RSA.java @@ -0,0 +1,314 @@ +/* RSA.java -- RSA PKCS#1 signatures. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.provider; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import java.math.BigInteger; + +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.SignatureException; +import java.security.SignatureSpi; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +import java.util.ArrayList; + +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; + +public abstract class RSA extends SignatureSpi implements Cloneable +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + /** + * digestAlgorithm OBJECT IDENTIFIER ::= + * { iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) } + */ + protected static final OID DIGEST_ALGORITHM = new OID("1.2.840.113549.2"); + + protected final OID digestAlgorithm; + protected final MessageDigest md; + protected RSAPrivateKey signerKey; + protected RSAPublicKey verifierKey; + + // Constructor. + // ------------------------------------------------------------------------- + + protected RSA(MessageDigest md, OID digestAlgorithm) + { + super(); + this.md = md; + this.digestAlgorithm = digestAlgorithm; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public Object clone() throws CloneNotSupportedException + { + return super.clone(); + } + + protected Object engineGetParameter(String param) + { + throw new UnsupportedOperationException("deprecated"); + } + + protected void engineSetParameter(String param, Object value) + { + throw new UnsupportedOperationException("deprecated"); + } + + protected void engineInitSign(PrivateKey privateKey) + throws InvalidKeyException + { + if (!(privateKey instanceof RSAPrivateKey)) + throw new InvalidKeyException(); + verifierKey = null; + signerKey = (RSAPrivateKey) privateKey; + } + + protected void engineInitSign(PrivateKey privateKey, SecureRandom random) + throws InvalidKeyException + { + // This class does not need random bytes. + engineInitSign(privateKey); + } + + protected void engineInitVerify(PublicKey publicKey) + throws InvalidKeyException + { + if (!(publicKey instanceof RSAPublicKey)) + throw new InvalidKeyException(); + signerKey = null; + verifierKey = (RSAPublicKey) publicKey; + } + + protected void engineUpdate(byte b) throws SignatureException + { + if (signerKey == null && verifierKey == null) + throw new SignatureException("not initialized"); + md.update(b); + } + + protected void engineUpdate(byte[] buf, int off, int len) + throws SignatureException + { + if (signerKey == null && verifierKey == null) + throw new SignatureException("not initialized"); + md.update(buf, off, len); + } + + protected byte[] engineSign() throws SignatureException + { + if (signerKey == null) + throw new SignatureException("not initialized for signing"); + // + // The signature will be the RSA encrypted BER representation of + // the following: + // + // DigestInfo ::= SEQUENCE { + // digestAlgorithm DigestAlgorithmIdentifier, + // digest Digest } + // + // DigestAlgorithmIdentifier ::= AlgorithmIdentifier + // + // Digest ::= OCTET STRING + // + ArrayList digestAlg = new ArrayList(2); + digestAlg.add(new DERValue(DER.OBJECT_IDENTIFIER, digestAlgorithm)); + digestAlg.add(new DERValue(DER.NULL, null)); + ArrayList digestInfo = new ArrayList(2); + digestInfo.add(new DERValue(DER.SEQUENCE, digestAlg)); + digestInfo.add(new DERValue(DER.OCTET_STRING, md.digest())); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try + { + DERWriter.write(out, new DERValue(DER.SEQUENCE, digestInfo)); + } + catch (IOException ioe) + { + throw new SignatureException(ioe.toString()); + } + byte[] buf = out.toByteArray(); + md.reset(); + + // k = octect length of the modulus. + int k = signerKey.getModulus().bitLength(); + k = (k >>> 3) + ((k & 7) == 0 ? 0 : 1); + if (buf.length < k - 3) + { + throw new SignatureException("RSA modulus too small"); + } + byte[] d = new byte[k]; + + // Padding type 1: + // 00 | 01 | FF | ... | FF | 00 | D + d[1] = 0x01; + for (int i = 2; i < k - buf.length - 1; i++) + d[i] = (byte) 0xFF; + System.arraycopy(buf, 0, d, k - buf.length, buf.length); + + BigInteger eb = new BigInteger(d); + + byte[] ed = eb.modPow(signerKey.getPrivateExponent(), + signerKey.getModulus()).toByteArray(); + + // Ensure output is k octets long. + if (ed.length < k) + { + byte[] b = new byte[k]; + System.arraycopy(eb, 0, b, k - ed.length, ed.length); + ed = b; + } + else if (ed.length > k) + { + if (ed.length != k + 1) + { + throw new SignatureException("modPow result is larger than the modulus"); + } + // Maybe an extra 00 octect. + byte[] b = new byte[k]; + System.arraycopy(ed, 1, b, 0, k); + ed = b; + } + + return ed; + } + + protected int engineSign(byte[] out, int off, int len) + throws SignatureException + { + if (out == null || off < 0 || len < 0 || off+len > out.length) + throw new SignatureException("illegal output argument"); + byte[] result = engineSign(); + if (result.length > len) + throw new SignatureException("not enough space for signature"); + System.arraycopy(result, 0, out, off, result.length); + return result.length; + } + + protected boolean engineVerify(byte[] sig) throws SignatureException + { + if (verifierKey == null) + throw new SignatureException("not initialized for verifying"); + if (sig == null) + throw new SignatureException("no signature specified"); + int k = verifierKey.getModulus().bitLength(); + k = (k >>> 3) + ((k & 7) == 0 ? 0 : 1); + if (sig.length != k) + throw new SignatureException("signature is the wrong size (expecting " + + k + " bytes, got " + sig.length + ")"); + BigInteger ed = new BigInteger(1, sig); + byte[] eb = ed.modPow(verifierKey.getPublicExponent(), + verifierKey.getModulus()).toByteArray(); + + int i = 0; + if (eb[0] == 0x00) + { + for (i = 1; i < eb.length && eb[i] == 0x00; i++); + if (i == 1) + throw new SignatureException("wrong RSA padding"); + i--; + } + else if (eb[0] == 0x01) + { + for (i = 1; i < eb.length && eb[i] != 0x00; i++) + if (eb[i] != (byte) 0xFF) + throw new IllegalArgumentException("wrong RSA padding"); + } + else + throw new SignatureException("wrong RSA padding type"); + + byte[] d = new byte[eb.length-i-1]; + System.arraycopy(eb, i+1, d, 0, eb.length-i-1); + + DERReader der = new DERReader(d); + try + { + DERValue val = der.read(); + if (val.getTag() != DER.SEQUENCE) + throw new SignatureException("failed to parse DigestInfo"); + val = der.read(); + if (val.getTag() != DER.SEQUENCE) + throw new SignatureException("failed to parse DigestAlgorithmIdentifier"); + boolean sequenceIsBer = val.getLength() == 0; + val = der.read(); + if (val.getTag() != DER.OBJECT_IDENTIFIER) + throw new SignatureException("failed to parse object identifier"); + if (!val.getValue().equals(digestAlgorithm)) + throw new SignatureException("digest algorithms do not match"); + val = der.read(); + // We should never see parameters here, since they are never used. + if (val.getTag() != DER.NULL) + throw new SignatureException("cannot handle digest parameters"); + if (sequenceIsBer) + der.skip(1); // end-of-sequence byte. + val = der.read(); + if (val.getTag() != DER.OCTET_STRING) + throw new SignatureException("failed to parse Digest"); + return MessageDigest.isEqual(md.digest(), (byte[]) val.getValue()); + } + catch (IOException ioe) + { + throw new SignatureException(ioe.toString()); + } + } + + protected boolean engineVerify(byte[] sig, int off, int len) + throws SignatureException + { + if (sig == null || off < 0 || len < 0 || off+len > sig.length) + throw new SignatureException("illegal parameter"); + byte[] buf = new byte[len]; + System.arraycopy(sig, off, buf, 0, len); + return engineVerify(buf); + } +} diff --git a/libjava/gnu/java/security/provider/RSAKeyFactory.java b/libjava/gnu/java/security/provider/RSAKeyFactory.java new file mode 100644 index 0000000..33c8c22 --- /dev/null +++ b/libjava/gnu/java/security/provider/RSAKeyFactory.java @@ -0,0 +1,181 @@ +/* RSAKeyFactory.java -- RSA key factory. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.provider; + +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactorySpi; +import java.security.PrivateKey; +import java.security.PublicKey; + +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.RSAPrivateCrtKeySpec; +import java.security.spec.RSAPrivateKeySpec; +import java.security.spec.RSAPublicKeySpec; +import java.security.spec.X509EncodedKeySpec; + +public class RSAKeyFactory extends KeyFactorySpi +{ + + // Default constructor. + // ------------------------------------------------------------------------- + + // Instance methods. + // ------------------------------------------------------------------------- + + protected PrivateKey engineGeneratePrivate(KeySpec spec) + throws InvalidKeySpecException + { + if (spec instanceof RSAPrivateCrtKeySpec) + { + return new GnuRSAPrivateKey((RSAPrivateCrtKeySpec) spec); + } + if (spec instanceof RSAPrivateKeySpec) + { + return new GnuRSAPrivateKey(new RSAPrivateCrtKeySpec( + ((RSAPrivateKeySpec) spec).getModulus(), null, + ((RSAPrivateKeySpec) spec).getPrivateExponent(), null, + null, null, null, null)); + } + if (spec instanceof PKCS8EncodedKeySpec) + { + EncodedKeyFactory ekf = new EncodedKeyFactory(); + PrivateKey pk = ekf.engineGeneratePrivate(spec); + if (pk instanceof RSAPrivateKey) + return pk; + } + throw new InvalidKeySpecException(); + } + + protected PublicKey engineGeneratePublic(KeySpec spec) + throws InvalidKeySpecException + { + if (spec instanceof RSAPublicKeySpec) + { + return new GnuRSAPublicKey((RSAPublicKeySpec) spec); + } + if (spec instanceof X509EncodedKeySpec) + { + EncodedKeyFactory ekf = new EncodedKeyFactory(); + PublicKey pk = ekf.engineGeneratePublic(spec); + if (pk instanceof RSAPublicKey) + return pk; + } + throw new InvalidKeySpecException(); + } + + protected KeySpec engineGetKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException + { + if (keySpec.isAssignableFrom(RSAPrivateCrtKeySpec.class) + && (key instanceof RSAPrivateCrtKey)) + { + return new RSAPrivateCrtKeySpec( + ((RSAPrivateCrtKey) key).getModulus(), + ((RSAPrivateCrtKey) key).getPublicExponent(), + ((RSAPrivateCrtKey) key).getPrivateExponent(), + ((RSAPrivateCrtKey) key).getPrimeP(), + ((RSAPrivateCrtKey) key).getPrimeQ(), + ((RSAPrivateCrtKey) key).getPrimeExponentP(), + ((RSAPrivateCrtKey) key).getPrimeExponentQ(), + ((RSAPrivateCrtKey) key).getCrtCoefficient()); + } + if (keySpec.isAssignableFrom(RSAPrivateKeySpec.class) + && (key instanceof RSAPrivateKey)) + { + return new RSAPrivateKeySpec( + ((RSAPrivateCrtKey) key).getModulus(), + ((RSAPrivateCrtKey) key).getPrivateExponent()); + } + if (keySpec.isAssignableFrom(RSAPublicKeySpec.class) + && (key instanceof RSAPublicKey)) + { + return new RSAPublicKeySpec( + ((RSAPrivateCrtKey) key).getModulus(), + ((RSAPrivateCrtKey) key).getPublicExponent()); + } + if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class) + && key.getFormat().equalsIgnoreCase("PKCS#8")) + { + return new PKCS8EncodedKeySpec(key.getEncoded()); + } + if (keySpec.isAssignableFrom(X509EncodedKeySpec.class) + && key.getFormat().equalsIgnoreCase("X.509")) + { + return new X509EncodedKeySpec(key.getEncoded()); + } + throw new InvalidKeySpecException(); + } + + protected Key engineTranslateKey(Key key) throws InvalidKeyException + { + if (key instanceof RSAPrivateCrtKey) + { + return new GnuRSAPrivateKey(new RSAPrivateCrtKeySpec( + ((RSAPrivateCrtKey) key).getModulus(), + ((RSAPrivateCrtKey) key).getPublicExponent(), + ((RSAPrivateCrtKey) key).getPrivateExponent(), + ((RSAPrivateCrtKey) key).getPrimeP(), + ((RSAPrivateCrtKey) key).getPrimeQ(), + ((RSAPrivateCrtKey) key).getPrimeExponentP(), + ((RSAPrivateCrtKey) key).getPrimeExponentQ(), + ((RSAPrivateCrtKey) key).getCrtCoefficient())); + } + if (key instanceof RSAPrivateKey) + { + return new GnuRSAPrivateKey(new RSAPrivateCrtKeySpec( + ((RSAPrivateKey) key).getModulus(), null, + ((RSAPrivateKey) key).getPrivateExponent(), null, + null, null, null, null)); + } + if (key instanceof RSAPublicKey) + { + return new GnuRSAPublicKey(new RSAPublicKeySpec( + ((RSAPrivateCrtKey) key).getModulus(), + ((RSAPrivateCrtKey) key).getPublicExponent())); + } + throw new InvalidKeyException(); + } +} diff --git a/libjava/gnu/java/security/provider/SHA1withRSA.java b/libjava/gnu/java/security/provider/SHA1withRSA.java new file mode 100644 index 0000000..64e93f9 --- /dev/null +++ b/libjava/gnu/java/security/provider/SHA1withRSA.java @@ -0,0 +1,61 @@ +/* SHA1withRSA.java -- SHA-1 with RSA encryption signatures. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.provider; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import gnu.java.security.OID; + +public class SHA1withRSA extends RSA +{ + + // Constant. + // ------------------------------------------------------------------------- + + private static final OID SHA1 = new OID("1.3.14.3.2.26"); + + // Constructor. + // ------------------------------------------------------------------------- + + public SHA1withRSA() throws NoSuchAlgorithmException + { + super(MessageDigest.getInstance("SHA-160"), SHA1); + } +} diff --git a/libjava/gnu/java/security/provider/X509CertificateFactory.java b/libjava/gnu/java/security/provider/X509CertificateFactory.java index 62d3d38..7533006 100644 --- a/libjava/gnu/java/security/provider/X509CertificateFactory.java +++ b/libjava/gnu/java/security/provider/X509CertificateFactory.java @@ -7,7 +7,7 @@ GNU Classpath is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. - + GNU Classpath is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -44,16 +44,21 @@ import java.io.InputStream; 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 @@ public class X509CertificateFactory extends CertificateFactorySpi } catch (IOException ioe) { - throw new CertificateException(ioe.toString()); + CertificateException ce = new CertificateException(ioe.getMessage()); + ce.initCause (ioe); + throw ce; } } @@ -107,7 +114,9 @@ public class X509CertificateFactory extends CertificateFactorySpi } 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 @@ public class X509CertificateFactory extends CertificateFactorySpi } catch (IOException ioe) { - throw new CRLException(ioe.toString()); + CRLException crle = new CRLException(ioe.getMessage()); + crle.initCause (ioe); + throw crle; } } @@ -141,18 +152,44 @@ public class X509CertificateFactory extends CertificateFactorySpi } 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 @@ public class X509CertificateFactory extends CertificateFactorySpi 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); @@ -265,5 +304,4 @@ public class X509CertificateFactory extends CertificateFactorySpi return new X509CRL(inStream); } } - } diff --git a/libjava/gnu/java/security/x509/GnuPKIExtension.java b/libjava/gnu/java/security/x509/GnuPKIExtension.java new file mode 100644 index 0000000..8294e65 --- /dev/null +++ b/libjava/gnu/java/security/x509/GnuPKIExtension.java @@ -0,0 +1,59 @@ +/* GnuPKIExtension.java -- interface for GNU PKI extensions. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509; + +import java.security.cert.X509Extension; +import java.util.Collection; + +import gnu.java.security.OID; +import gnu.java.security.x509.ext.Extension; + +public interface GnuPKIExtension extends X509Extension +{ + + /** + * Returns the extension object for the given object identifier. + * + * @param oid The OID of the extension to get. + * @return The extension, or null if there is no such extension. + */ + Extension getExtension(OID oid); + + Collection getExtensions(); +} diff --git a/libjava/gnu/java/security/x509/PolicyNodeImpl.java b/libjava/gnu/java/security/x509/PolicyNodeImpl.java new file mode 100644 index 0000000..d3d4bd9 --- /dev/null +++ b/libjava/gnu/java/security/x509/PolicyNodeImpl.java @@ -0,0 +1,214 @@ +/* PolicyNodeImpl.java -- An implementation of a policy tree node. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509; + +import java.security.cert.PolicyNode; +import java.security.cert.PolicyQualifierInfo; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +public final class PolicyNodeImpl implements PolicyNode +{ + + // Fields. + // ------------------------------------------------------------------------- + + private String policy; + private final Set expectedPolicies; + private final Set qualifiers; + private final Set children; + private PolicyNodeImpl parent; + private int depth; + private boolean critical; + private boolean readOnly; + + // Constructors. + // ------------------------------------------------------------------------- + + public PolicyNodeImpl() + { + expectedPolicies = new HashSet(); + qualifiers = new HashSet(); + children = new HashSet(); + readOnly = false; + critical = false; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void addChild(PolicyNodeImpl node) + { + if (readOnly) + throw new IllegalStateException("read only"); + if (node.getParent() != null) + throw new IllegalStateException("already a child node"); + node.parent = this; + node.setDepth(depth + 1); + children.add(node); + } + + public Iterator getChildren() + { + return Collections.unmodifiableSet(children).iterator(); + } + + public int getDepth() + { + return depth; + } + + public void setDepth(int depth) + { + if (readOnly) + throw new IllegalStateException("read only"); + this.depth = depth; + } + + public void addAllExpectedPolicies(Set policies) + { + if (readOnly) + throw new IllegalStateException("read only"); + expectedPolicies.addAll(policies); + } + + public void addExpectedPolicy(String policy) + { + if (readOnly) + throw new IllegalStateException("read only"); + expectedPolicies.add(policy); + } + + public Set getExpectedPolicies() + { + return Collections.unmodifiableSet(expectedPolicies); + } + + public PolicyNode getParent() + { + return parent; + } + + public void addAllPolicyQualifiers (Collection qualifiers) + { + for (Iterator it = qualifiers.iterator(); it.hasNext(); ) + { + if (!(it.next() instanceof PolicyQualifierInfo)) + throw new IllegalArgumentException ("can only add PolicyQualifierInfos"); + } + qualifiers.addAll (qualifiers); + } + + public void addPolicyQualifier (PolicyQualifierInfo qualifier) + { + if (readOnly) + throw new IllegalStateException("read only"); + qualifiers.add(qualifier); + } + + public Set getPolicyQualifiers() + { + return Collections.unmodifiableSet(qualifiers); + } + + public String getValidPolicy() + { + return policy; + } + + public void setValidPolicy(String policy) + { + if (readOnly) + throw new IllegalStateException("read only"); + this.policy = policy; + } + + public boolean isCritical() + { + return critical; + } + + public void setCritical(boolean critical) + { + if (readOnly) + throw new IllegalStateException("read only"); + this.critical = critical; + } + + public void setReadOnly() + { + if (readOnly) + return; + readOnly = true; + for (Iterator it = getChildren(); it.hasNext(); ) + ((PolicyNodeImpl) it.next()).setReadOnly(); + } + + public String toString() + { + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < depth; i++) + buf.append(" "); + buf.append("("); + buf.append(PolicyNodeImpl.class.getName()); + buf.append(" (oid "); + buf.append(policy); + buf.append(") (depth "); + buf.append(depth); + buf.append(") (qualifiers "); + buf.append(qualifiers); + buf.append(") (critical "); + buf.append(critical); + buf.append(") (expectedPolicies "); + buf.append(expectedPolicies); + buf.append(") (children ("); + final String nl = System.getProperty("line.separator"); + for (Iterator it = getChildren(); it.hasNext(); ) + { + buf.append(nl); + buf.append(it.next().toString()); + } + buf.append(")))"); + return buf.toString(); + } +} diff --git a/libjava/gnu/java/security/x509/Util.java b/libjava/gnu/java/security/x509/Util.java new file mode 100644 index 0000000..3bbbff2 --- /dev/null +++ b/libjava/gnu/java/security/x509/Util.java @@ -0,0 +1,202 @@ +/* Util.java -- Miscellaneous utility methods. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509; + +/** + * A collection of useful class methods. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public final class Util +{ + + // Constants. + // ------------------------------------------------------------------------- + + public static final String HEX = "0123456789abcdef"; + + // Class methods. + // ------------------------------------------------------------------------- + + /** + * Convert a byte array to a hexadecimal string, as though it were a + * big-endian arbitrarily-sized integer. + * + * @param buf The bytes to format. + * @param off The offset to start at. + * @param len The number of bytes to format. + * @return A hexadecimal representation of the specified bytes. + */ + public static String toHexString(byte[] buf, int off, int len) + { + StringBuffer str = new StringBuffer(); + for (int i = 0; i < len; i++) + { + str.append(HEX.charAt(buf[i+off] >>> 4 & 0x0F)); + str.append(HEX.charAt(buf[i+off] & 0x0F)); + } + return str.toString(); + } + + /** + * See {@link #toHexString(byte[],int,int)}. + */ + public static String toHexString(byte[] buf) + { + return Util.toHexString(buf, 0, buf.length); + } + + /** + * Convert a byte array to a hexadecimal string, separating octets + * with the given character. + * + * @param buf The bytes to format. + * @param off The offset to start at. + * @param len The number of bytes to format. + * @param sep The character to insert between octets. + * @return A hexadecimal representation of the specified bytes. + */ + public static String toHexString(byte[] buf, int off, int len, char sep) + { + StringBuffer str = new StringBuffer(); + for (int i = 0; i < len; i++) + { + str.append(HEX.charAt(buf[i+off] >>> 4 & 0x0F)); + str.append(HEX.charAt(buf[i+off] & 0x0F)); + if (i < len - 1) + str.append(sep); + } + return str.toString(); + } + + /** + * See {@link #toHexString(byte[],int,int,char)}. + */ + public static String toHexString(byte[] buf, char sep) + { + return Util.toHexString(buf, 0, buf.length, sep); + } + + /** + * Create a representation of the given byte array similar to the + * output of `hexdump -C', which is + * + * <p><pre>OFFSET SIXTEEN-BYTES-IN-HEX PRINTABLE-BYTES</pre> + * + * <p>The printable bytes show up as-is if they are printable and + * not a newline character, otherwise showing as '.'. + * + * @param buf The bytes to format. + * @param off The offset to start at. + * @param len The number of bytes to encode. + * @return The formatted string. + */ + public static String hexDump(byte[] buf, int off, int len, String prefix) + { + String nl = System.getProperty("line.separator"); + StringBuffer str = new StringBuffer(); + int i = 0; + while (i < len) + { + str.append(prefix); + str.append(Util.formatInt(i+off, 16, 8)); + str.append(" "); + String s = Util.toHexString(buf, i+off, Math.min(16, len-i), ' '); + str.append(s); + for (int j = 56 - (56 - s.length()); j < 56; j++) + str.append(" "); + for (int j = 0; j < Math.min(16, len - i); j++) + { + if ((buf[i+off+j] & 0xFF) < 0x20 || (buf[i+off+j] & 0xFF) > 0x7E) + str.append('.'); + else + str.append((char) (buf[i+off+j] & 0xFF)); + } + str.append(nl); + i += 16; + } + return str.toString(); + } + + /** + * See {@link #hexDump(byte[],int,int)}. + */ + public static String hexDump(byte[] buf, String prefix) + { + return hexDump(buf, 0, buf.length, prefix); + } + + /** + * Format an integer into the specified radix, zero-filled. + * + * @param i The integer to format. + * @param radix The radix to encode to. + * @param len The target length of the string. The string is + * zero-padded to this length, but may be longer. + * @return The formatted integer. + */ + public static String formatInt(int i, int radix, int len) + { + String s = Integer.toString(i, radix); + StringBuffer buf = new StringBuffer(); + for (int j = 0; j < len - s.length(); j++) + buf.append("0"); + buf.append(s); + return buf.toString(); + } + + /** + * Convert a hexadecimal string into its byte representation. + * + * @param hex The hexadecimal string. + * @return The converted bytes. + */ + public static byte[] toByteArray(String hex) + { + hex = hex.toLowerCase(); + byte[] buf = new byte[hex.length() / 2]; + int j = 0; + for (int i = 0; i < buf.length; i++) + { + buf[i] = (byte) ((Character.digit(hex.charAt(j++), 16) << 4) | + Character.digit(hex.charAt(j++), 16)); + } + return buf; + } +} diff --git a/libjava/gnu/java/security/x509/X500DistinguishedName.java b/libjava/gnu/java/security/x509/X500DistinguishedName.java index 8a71567..64e320b 100644 --- a/libjava/gnu/java/security/x509/X500DistinguishedName.java +++ b/libjava/gnu/java/security/x509/X500DistinguishedName.java @@ -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. @@ -7,7 +7,7 @@ GNU Classpath is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. - + GNU Classpath is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -38,121 +38,35 @@ exception statement from your version. */ 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: - * - * <table cellpadding="0" cellspacing="0" border="0"> - * <tr> - * <th bgcolor="#CCCCFF" align="left">Name</th> - * <th bgcolor="#CCCCFF" align="left">X.500 AttributeType</th> - * <th bgcolor="#CCCCFF" align="left">ObjectIdentifier</th> - * </tr> - * <tr> - * <td align="left">CN</td> - * <td align="left">commonName</td> - * <td align="left">2.5.4.3</td> - * </tr> - * <tr> - * <td align="left">C</td> - * <td align="left">countryName</td> - * <td align="left">2.5.4.6</td> - * </tr> - * <tr> - * <td align="left">L</td> - * <td align="left">localityName</td> - * <td align="left">2.5.4.7</td> - * </tr> - * <tr> - * <td align="left">ST</td> - * <td align="left">stateOrProvinceName</td> - * <td align="left">2.5.4.8</td> - * </tr> - * <tr> - * <td align="left">STREET</td> - * <td align="left">streetAddress</td> - * <td align="left">2.5.4.9</td> - * </tr> - * <tr> - * <td align="left">O</td> - * <td align="left">organizationName</td> - * <td align="left">2.5.4.10</td> - * </tr> - * <tr> - * <td align="left">OU</td> - * <td align="left">organizationUnitName</td> - * <td align="left">2.5.4.11</td> - * </tr> - * <tr> - * <td align="left">DC</td> - * <td align="left">domainComponent</td> - * <td align="left">0.9.2342.19200300.100.1.25</td> - * </tr> - * <tr> - * <td align="left">UID</td> - * <td align="left">userid</td> - * <td align="left"0.9.2342.19200300.100.1.1></td> - * </tr> - * <tr> - * <td align="left">DNQ or DNQUALIFIER(*)</td> - * <td align="left">domainNameQualifier</td> - * <td align="left">2.5.4.46</td> - * </tr> - * <tr> - * <td align="left">SURNAME(*)</td> - * <td align="left">name</td> - * <td align="left">2.5.4.41</td> - * </tr> - * <tr> - * <td align="left">GIVENNAME(*)</td> - * <td align="left">givenName</td> - * <td align="left">2.5.4.42</td> - * </tr> - * <tr> - * <td align="left">INITIALS(*)</td> - * <td align="left">initials</td> - * <td align="left">2.5.4.43</td> - * </tr> - * <tr> - * <td align="left">EMAILADDRESS(*)</td> - * <td align="left">emailAddress</td> - * <td align="left">2.5.4.44</td> - * </tr> - * </table> - * - * <p><i>(*) = attributes not specified in RFC1779 or RFC2253, but - * recognized anyway.</i> - * - * <p>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 (rsdio@metastatic.org) - * @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 class X500DistinguishedName 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. - // ------------------------------------------------------------------------ - - /** - * 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() + { + components = new LinkedList(); + currentRdn = new LinkedHashMap(); + components.add(currentRdn); + } + 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) - { - 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)); - } - - public byte[] getEncoded() - { - if (encoded == null) - encoded = encodeDER(); - return (byte[]) encoded.clone(); - } - - private static String quote(String str) - { - 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; - } - - public String toRFC1779() - { - 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() - { - 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)); - } + // ------------------------------------------------------------------------- - public String toCanonical() + public String getName() { - if (nameCanonical != null) - return nameCanonical; - nameCanonical = toRFC2253(); - return nameCanonical; // XXX canonicalize + return toString(); } - public String getCommonName() + public void newRelativeDistinguishedName() { - return commonName; + if (fixed || currentRdn.isEmpty()) return; + currentRdn = new LinkedHashMap(); + components.add(currentRdn); } - public String getCountry() + public int size() { - return country; + return components.size(); } - public String getLocality() + public int countComponents() { - return locality; + int count = 0; + for (Iterator it = components.iterator(); it.hasNext(); ) + { + count += ((Map) it.next()).size(); + } + return count; } - public String getOrganizationalUnit() + public boolean containsComponent(OID oid, String value) { - return orgUnit; + for (Iterator it = components.iterator(); it.hasNext(); ) + { + Map rdn = (Map) it.next(); + String s = (String) rdn.get(oid); + if (s == null) + continue; + if (compressWS(value).equalsIgnoreCase(compressWS(s))) + return true; + } + return false; } - public String getOrganization() + public String getComponent(OID oid) { - return organization; + for (Iterator it = components.iterator(); it.hasNext(); ) + { + Map rdn = (Map) it.next(); + if (rdn.containsKey(oid)) + return (String) rdn.get(oid); + } + return null; } - public String getStreet() + public String getComponent(OID oid, int rdn) { - return street; + if (rdn >= size()) + return null; + return (String) ((Map) components.get(rdn)).get(oid); } - public String getState() + public void putComponent(OID oid, String value) { - return state; + currentRdn.put(oid, value); } - public String getTitle() + public void putComponent(String name, String value) { - return title; + 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 getDNQualifier() + public void setUnmodifiable() { - return dnQualifier; + 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 getSurname() + public int hashCode() { - return surname; + int sum = 0; + for (Iterator it = components.iterator(); it.hasNext(); ) + { + 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 getGivenName() + public boolean equals(Object o) { - return givenName; + 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 getInitials() + public String toString() { - return initials; + 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(); } - public String getEmail() - { - return email; - } + // Own methods. + // ------------------------------------------------------------------------- - public String getDomain() - { - return domainComponent; - } + private int sep; - public String getUserID() + private void parseString(String str) throws IOException { - return userid; + Reader in = new StringReader(str); + while (true) + { + String key = readAttributeType(in); + if (key == null) + break; + String value = readAttributeValue(in); + putComponent(key, value); + if (sep == ',') + newRelativeDistinguishedName(); + } + setUnmodifiable(); } - // Own methods. - // ------------------------------------------------------------------------ - - private static String unquote(String str) + private String readAttributeType(Reader in) throws IOException { - if (str.startsWith("\"") && str.endsWith("\"")) - str = str.substring(1, str.length()-1); - // XXX needs regex - //return str.replaceAll("\\([,+\"\\<>;])", "\1"); - return str; + StringBuffer buf = new StringBuffer(); + int ch; + while ((ch = in.read()) != '=') + { + 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(); } - private void parseDN(String name, boolean rfc2253) + private String readAttributeValue(Reader in) throws IOException { - 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) + StringBuffer buf = new StringBuffer(); + int ch = in.read(); + if (ch == '#') { - try + while (true) { - token = parse.nextToken(); + 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)); + } + else + throw new IOException("illegal character: " + (char) ch); } - catch (IOException ioe) + } + else if (ch == '"') + { + while (true) { - throw new IllegalArgumentException(); + ch = in.read(); + if (ch == '"') + break; + else if (ch == '\\') + { + 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); + } + else + buf.append((char) ch); + } + else + buf.append((char) ch); } - switch (token) + sep = in.read(); + if (sep != '+' || sep != ',') + throw new IOException("illegal character: " + (char) ch); + return buf.toString(); + } + else + { + while (true) { - 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; - 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) - { - setAttribute(attrib, value); - } - attrib = null; - value = null; - break; - case '=': - break; - case StreamTokenizer.TT_EOF: - return; - default: - throw new IllegalArgumentException("unknown token " + (char)token - + " (" + token + ")"); + 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); + } + else + buf.append((char) ch); + break; + case '=': + case '<': + case '>': + case '#': + case ';': + throw new IOException("illegal character: " + (char) ch); + case -1: + throw new EOFException(); + default: + 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()); + 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 += len2 + 1 + DERWriter.definiteEncodingSize(name.getLength()); + len += rdn.getEncodedLength(); + if (len < name.getLength()) + newRelativeDistinguishedName(); } + setUnmodifiable(); } - private byte[] encodeDER() + private static String compressWS(String str) { - try + StringBuffer buf = new StringBuffer(); + char lastChar = 0; + for (int i = 0; i < str.length(); i++) { - LinkedList name = new LinkedList(); - if (commonName != null) - { - 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) + char c = str.charAt(i); + if (Character.isWhitespace(c)) { - 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 (!Character.isWhitespace(lastChar)) + buf.append(' '); } - 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) - { - throw new Error(ioe); + else + buf.append(c); + lastChar = c; } - } - - 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); - } - - 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(); } } diff --git a/libjava/gnu/java/security/x509/X509CRL.java b/libjava/gnu/java/security/x509/X509CRL.java index e31a85d..adaa003 100644 --- a/libjava/gnu/java/security/x509/X509CRL.java +++ b/libjava/gnu/java/security/x509/X509CRL.java @@ -7,7 +7,7 @@ GNU Classpath is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. - + GNU Classpath is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -44,6 +44,7 @@ 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.x509.ext.Extension; import java.io.InputStream; import java.io.IOException; @@ -57,11 +58,12 @@ import java.security.Signature; import java.security.SignatureException; import java.security.cert.Certificate; import java.security.cert.CRLException; -import java.security.cert.X509CRLEntry; +import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.HashMap; +import java.util.Iterator; import java.util.Set; import javax.security.auth.x500.X500Principal; @@ -72,11 +74,22 @@ import javax.security.auth.x500.X500Principal; * @author Casey Marshall (rsdio@metastatic.org) */ 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,12 +105,10 @@ public class X509CRL extends java.security.cert.X509CRL 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; private byte[] rawSig; @@ -118,8 +129,6 @@ public class X509CRL extends java.security.cert.X509CRL super(); revokedCerts = new HashMap(); extensions = new HashMap(); - critOids = new HashSet(); - nonCritOids = new HashSet(); try { parse(encoded); @@ -141,7 +150,9 @@ public class X509CRL extends java.security.cert.X509CRL 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 +193,7 @@ public class X509CRL extends java.security.cert.X509CRL public X500Principal getIssuerX500Principal() { - return issuerDN; + return new X500Principal(issuerDN.getDer()); } public Date getThisUpdate() @@ -197,9 +208,9 @@ public class X509CRL extends java.security.cert.X509CRL 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 +258,68 @@ public class X509CRL extends java.security.cert.X509CRL 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 +348,23 @@ public class X509CRL extends java.security.cert.X509CRL 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 +373,104 @@ public class X509CRL extends java.security.cert.X509CRL } 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; } + val = der.read(); } - if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 0) + + // crlExtensions [0] EXPLICIT Extensions OPTIONAL + // -- if present MUST be v2 + if (val.getTagClass() != DER.UNIVERSAL && val.getTag() == 0) { - val = der.read(); + 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(); } diff --git a/libjava/gnu/java/security/x509/X509CRLEntry.java b/libjava/gnu/java/security/x509/X509CRLEntry.java index 4057c60..252737c 100644 --- a/libjava/gnu/java/security/x509/X509CRLEntry.java +++ b/libjava/gnu/java/security/x509/X509CRLEntry.java @@ -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. @@ -7,7 +7,7 @@ GNU Classpath is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. - + GNU Classpath is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -45,17 +45,17 @@ import java.math.BigInteger; 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 @@ import gnu.java.security.der.DERWriter; * @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 @@ class X509CRLEntry extends java.security.cert.X509CRLEntry /** 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 @@ class X509CRLEntry extends java.security.cert.X509CRLEntry * @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 @@ class X509CRLEntry extends java.security.cert.X509CRLEntry 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 @@ class X509CRLEntry extends java.security.cert.X509CRLEntry 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); } } } diff --git a/libjava/gnu/java/security/x509/X509CRLSelectorImpl.java b/libjava/gnu/java/security/x509/X509CRLSelectorImpl.java new file mode 100644 index 0000000..c409779 --- /dev/null +++ b/libjava/gnu/java/security/x509/X509CRLSelectorImpl.java @@ -0,0 +1,138 @@ +/* X509CRLSelectorImpl.java -- implementation of an X509CRLSelector. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509; + +import java.io.IOException; + +import java.security.Principal; +import java.security.cert.CRL; +import java.security.cert.CRLSelector; +import java.security.cert.X509CRL; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import javax.security.auth.x500.X500Principal; + +/** + * Sun's implementation of X509CRLSelector sucks. This one tries to work + * better. + */ +public class X509CRLSelectorImpl implements CRLSelector +{ + + // Fields. + // ------------------------------------------------------------------------- + + private Set issuerNames; + + // Constructor. + // ------------------------------------------------------------------------- + + public X509CRLSelectorImpl() + { + issuerNames = new HashSet(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void addIssuerName(byte[] issuerName) throws IOException + { + issuerNames.add(new X500DistinguishedName(issuerName)); + } + + public void addIssuerName(String issuerName) + { + issuerNames.add(new X500DistinguishedName(issuerName)); + } + + public void addIssuerName(Principal issuerName) throws IOException + { + if (issuerName instanceof X500DistinguishedName) + issuerNames.add(issuerName); + else if (issuerName instanceof X500Principal) + issuerNames.add(new X500DistinguishedName(((X500Principal) issuerName).getEncoded())); + else + issuerNames.add(new X500DistinguishedName(issuerName.getName())); + } + + public Collection getIssuerNames() + { + return Collections.unmodifiableSet(issuerNames); + } + + public Object clone() + { + X509CRLSelectorImpl copy = new X509CRLSelectorImpl(); + copy.issuerNames.addAll(issuerNames); + return copy; + } + + public boolean match(CRL crl) + { + if (!(crl instanceof X509CRL)) + return false; + try + { + Principal p = ((X509CRL) crl).getIssuerDN(); + X500DistinguishedName thisName = null; + if (p instanceof X500DistinguishedName) + thisName = (X500DistinguishedName) p; + else if (p instanceof X500Principal) + thisName = new X500DistinguishedName(((X500Principal) p).getEncoded()); + else + thisName = new X500DistinguishedName(p.getName()); + for (Iterator it = issuerNames.iterator(); it.hasNext(); ) + { + X500DistinguishedName name = (X500DistinguishedName) it.next(); + if (thisName.equals(name)) + return true; + } + } + catch (Exception x) + { + } + return false; + } +} + diff --git a/libjava/gnu/java/security/x509/X509CertPath.java b/libjava/gnu/java/security/x509/X509CertPath.java new file mode 100644 index 0000000..0990abd --- /dev/null +++ b/libjava/gnu/java/security/x509/X509CertPath.java @@ -0,0 +1,306 @@ +/* X509CertPath.java -- an X.509 certificate path. + Copyright (C) 2004 Free Software Fonudation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; + +import java.math.BigInteger; + +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertPath; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DEREncodingException; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +/** + * A certificate path (or certificate chain) of X509Certificates. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public class X509CertPath extends CertPath +{ + + // Fields. + // ------------------------------------------------------------------------- + + public static final List ENCODINGS = Collections.unmodifiableList( + Arrays.asList(new String[] { "PkiPath", "PKCS7" })); + + private static final OID PKCS7_SIGNED_DATA = new OID("1.2.840.113549.1.7.2"); + private static final OID PKCS7_DATA = new OID("1.2.840.113549.1.7.1"); + + /** The certificate path. */ + private List path; + + /** The cached PKCS #7 encoded bytes. */ + private byte[] pkcs_encoded; + + /** The cached PkiPath encoded bytes. */ + private byte[] pki_encoded; + + // Constructor. + // ------------------------------------------------------------------------- + + public X509CertPath(List path) + { + super("X.509"); + this.path = Collections.unmodifiableList(path); + } + + public X509CertPath(InputStream in) throws CertificateEncodingException + { + this(in, (String) ENCODINGS.get(0)); + } + + public X509CertPath(InputStream in, String encoding) + throws CertificateEncodingException + { + super("X.509"); + try + { + parse(in, encoding); + } + catch (IOException ioe) + { + throw new CertificateEncodingException(); + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public List getCertificates() + { + return path; // already unmodifiable + } + + public byte[] getEncoded() throws CertificateEncodingException + { + return getEncoded((String) ENCODINGS.get(0)); + } + + public byte[] getEncoded(String encoding) throws CertificateEncodingException + { + if (encoding.equalsIgnoreCase("PkiPath")) + { + if (pki_encoded == null) + { + try + { + pki_encoded = encodePki(); + } + catch (IOException ioe) + { + throw new CertificateEncodingException(); + } + } + return (byte[]) pki_encoded.clone(); + } + else if (encoding.equalsIgnoreCase("PKCS7")) + { + if (pkcs_encoded == null) + { + try + { + pkcs_encoded = encodePKCS(); + } + catch (IOException ioe) + { + throw new CertificateEncodingException(); + } + } + return (byte[]) pkcs_encoded.clone(); + } + else + throw new CertificateEncodingException("unknown encoding: " + encoding); + } + + public Iterator getEncodings() + { + return ENCODINGS.iterator(); // already unmodifiable + } + + // Own methods. + // ------------------------------------------------------------------------- + + private void parse(InputStream in, String encoding) + throws CertificateEncodingException, IOException + { + DERReader der = new DERReader(in); + DERValue path = null; + if (encoding.equalsIgnoreCase("PkiPath")) + { + // PKI encoding is just a SEQUENCE of X.509 certificates. + path = der.read(); + if (!path.isConstructed()) + throw new DEREncodingException("malformed PkiPath"); + } + else if (encoding.equalsIgnoreCase("PKCS7")) + { + // PKCS #7 encoding means that the certificates are contained in a + // SignedData PKCS #7 type. + // + // ContentInfo ::= SEQUENCE { + // contentType ::= ContentType, + // content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL } + // + // ContentType ::= OBJECT IDENTIFIER + // + // SignedData ::= SEQUENCE { + // version Version, + // digestAlgorithms DigestAlgorithmIdentifiers, + // contentInfo ContentInfo, + // certificates [0] IMPLICIT ExtendedCertificatesAndCertificates + // OPTIONAL, + // crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, + // signerInfos SignerInfos } + // + // Version ::= INTEGER + // + DERValue value = der.read(); + if (!value.isConstructed()) + throw new DEREncodingException("malformed ContentInfo"); + value = der.read(); + if (!(value.getValue() instanceof OID) || + ((OID) value.getValue()).equals(PKCS7_SIGNED_DATA)) + throw new DEREncodingException("not a SignedData"); + value = der.read(); + if (!value.isConstructed() || value.getTag() != 0) + throw new DEREncodingException("malformed content"); + value = der.read(); + if (value.getTag() != DER.INTEGER) + throw new DEREncodingException("malformed Version"); + value = der.read(); + if (!value.isConstructed() || value.getTag() != DER.SET) + throw new DEREncodingException("malformed DigestAlgorithmIdentifiers"); + der.skip(value.getLength()); + value = der.read(); + if (!value.isConstructed()) + throw new DEREncodingException("malformed ContentInfo"); + der.skip(value.getLength()); + path = der.read(); + if (!path.isConstructed() || path.getTag() != 0) + throw new DEREncodingException("no certificates"); + } + else + throw new CertificateEncodingException("unknown encoding: " + encoding); + + LinkedList certs = new LinkedList(); + int len = 0; + while (len < path.getLength()) + { + DERValue cert = der.read(); + try + { + certs.add(new X509Certificate(new ByteArrayInputStream(cert.getEncoded()))); + } + catch (CertificateException ce) + { + throw new CertificateEncodingException(ce.getMessage()); + } + len += cert.getEncodedLength(); + der.skip(cert.getLength()); + } + + this.path = Collections.unmodifiableList(certs); + } + + private byte[] encodePki() + throws CertificateEncodingException, IOException + { + synchronized (path) + { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + for (Iterator i = path.iterator(); i.hasNext(); ) + { + out.write(((Certificate) i.next()).getEncoded()); + } + byte[] b = out.toByteArray(); + DERValue val = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + b.length, b, null); + return val.getEncoded(); + } + } + + private byte[] encodePKCS() + throws CertificateEncodingException, IOException + { + synchronized (path) + { + ArrayList signedData = new ArrayList(5); + signedData.add(new DERValue(DER.INTEGER, BigInteger.ONE)); + signedData.add(new DERValue(DER.CONSTRUCTED | DER.SET, + Collections.EMPTY_SET)); + signedData.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + Collections.singletonList( + new DERValue(DER.OBJECT_IDENTIFIER, PKCS7_DATA)))); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + for (Iterator i = path.iterator(); i.hasNext(); ) + { + out.write(((Certificate) i.next()).getEncoded()); + } + byte[] b = out.toByteArray(); + signedData.add(new DERValue(DER.CONSTRUCTED | DER.CONTEXT, + b.length, b, null)); + DERValue sdValue = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + signedData); + + ArrayList contentInfo = new ArrayList(2); + contentInfo.add(new DERValue(DER.OBJECT_IDENTIFIER, PKCS7_SIGNED_DATA)); + contentInfo.add(new DERValue(DER.CONSTRUCTED | DER.CONTEXT, sdValue)); + return new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + contentInfo).getEncoded(); + } + } +} diff --git a/libjava/gnu/java/security/x509/X509CertSelectorImpl.java b/libjava/gnu/java/security/x509/X509CertSelectorImpl.java new file mode 100644 index 0000000..4535cce --- /dev/null +++ b/libjava/gnu/java/security/x509/X509CertSelectorImpl.java @@ -0,0 +1,199 @@ +/* X509CertSelectorImpl.java -- implementation of an X509CertSelector. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509; + +import java.io.IOException; + +import java.security.Principal; +import java.security.cert.Certificate; +import java.security.cert.CertSelector; +import java.security.cert.X509Certificate; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import javax.security.auth.x500.X500Principal; + +/** + * Sun's implementation of X509CertSelector sucks. This one tries to work + * better. + */ +public class X509CertSelectorImpl implements CertSelector +{ + + // Fields. + // ------------------------------------------------------------------------- + + private Set issuerNames; + private Set subjectNames; + + // Constructor. + // ------------------------------------------------------------------------- + + public X509CertSelectorImpl() + { + issuerNames = new HashSet(); + subjectNames = new HashSet(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void addIssuerName(byte[] issuerName) throws IOException + { + issuerNames.add(new X500DistinguishedName(issuerName)); + } + + public void addIssuerName(String issuerName) + { + issuerNames.add(new X500DistinguishedName(issuerName)); + } + + public void addIssuerName(Principal issuerName) throws IOException + { + if (issuerName instanceof X500DistinguishedName) + issuerNames.add(issuerName); + else if (issuerName instanceof X500Principal) + issuerNames.add(new X500DistinguishedName(((X500Principal) issuerName).getEncoded())); + else + issuerNames.add(new X500DistinguishedName(issuerName.getName())); + } + + public Collection getIssuerNames() + { + return Collections.unmodifiableSet(issuerNames); + } + + public void addSubjectName(byte[] subjectName) throws IOException + { + subjectNames.add(new X500DistinguishedName(subjectName)); + } + + public void addSubjectName(String subjectName) throws IOException + { + subjectNames.add(new X500DistinguishedName(subjectName)); + } + + public void addSubjectName(Principal subjectName) throws IOException + { + if (subjectName instanceof X500DistinguishedName) + subjectNames.add(subjectName); + else if (subjectName instanceof X500Principal) + subjectNames.add(new X500DistinguishedName(((X500Principal) subjectName).getEncoded())); + else + subjectNames.add(new X500DistinguishedName(subjectName.getName())); + } + + public Collection getSubjectNames() + { + return Collections.unmodifiableSet(subjectNames); + } + + public Object clone() + { + X509CertSelectorImpl copy = new X509CertSelectorImpl(); + copy.issuerNames.addAll(issuerNames); + copy.subjectNames.addAll(subjectNames); + return copy; + } + + public boolean match(Certificate cert) + { + if (!(cert instanceof X509Certificate)) + return false; + boolean matchIssuer = false; + boolean matchSubject = false; + try + { + Principal p = ((X509Certificate) cert).getIssuerDN(); + X500DistinguishedName thisName = null; + if (p instanceof X500DistinguishedName) + thisName = (X500DistinguishedName) p; + else if (p instanceof X500Principal) + thisName = new X500DistinguishedName(((X500Principal) p).getEncoded()); + else + thisName = new X500DistinguishedName(p.getName()); + if (issuerNames.isEmpty()) + matchIssuer = true; + else + { + for (Iterator it = issuerNames.iterator(); it.hasNext(); ) + { + X500DistinguishedName name = (X500DistinguishedName) it.next(); + if (thisName.equals(name)) + { + matchIssuer = true; + break; + } + } + } + + p = ((X509Certificate) cert).getSubjectDN(); + thisName = null; + if (p instanceof X500DistinguishedName) + thisName = (X500DistinguishedName) p; + else if (p instanceof X500Principal) + thisName = new X500DistinguishedName(((X500Principal) p).getEncoded()); + else + thisName = new X500DistinguishedName(p.getName()); + if (subjectNames.isEmpty()) + matchSubject = true; + else + { + for (Iterator it = subjectNames.iterator(); it.hasNext(); ) + { + X500DistinguishedName name = (X500DistinguishedName) it.next(); + if (thisName.equals(name)) + { + matchSubject = true; + break; + } + } + } + } + catch (Exception x) + { + } + return matchIssuer && matchSubject; + } +} + diff --git a/libjava/gnu/java/security/x509/X509Certificate.java b/libjava/gnu/java/security/x509/X509Certificate.java index 1ec2e87..25a56d4 100644 --- a/libjava/gnu/java/security/x509/X509Certificate.java +++ b/libjava/gnu/java/security/x509/X509Certificate.java @@ -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. @@ -7,7 +7,7 @@ GNU Classpath is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. - + GNU Classpath is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -42,7 +42,9 @@ import java.io.ByteArrayInputStream; 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.CertificateExpiredException; 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.HashSet; 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 @@ import gnu.java.security.der.DERWriter; * @author Casey Marshall (rsdio@metastatic.org) */ 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 @@ public class X509Certificate extends java.security.cert.X509Certificate { 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,9 +209,13 @@ public class X509Certificate extends java.security.cert.X509Certificate throws CertificateExpiredException, CertificateNotYetValidException { if (date.compareTo(notBefore) < 0) - throw new CertificateNotYetValidException(); + { + throw new CertificateNotYetValidException(); + } if (date.compareTo(notAfter) > 0) - throw new CertificateExpiredException(); + { + throw new CertificateExpiredException(); + } } public int getVersion() @@ -219,22 +230,22 @@ public class X509Certificate extends java.security.cert.X509Certificate 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 class X509Certificate extends java.security.cert.X509Certificate public String getSigAlgName() { if (sigAlgId.equals(ID_DSA_WITH_SHA1)) - return "SHA1withDSA"; - if (sigAlgId.equals(ID_RSA_WITH_MD2 )) - return "MD2withRSA"; - if (sigAlgId.equals(ID_RSA_WITH_MD5 )) - return "MD5withRSA"; - if (sigAlgId.equals(ID_RSA_WITH_SHA1 )) - return "SHA1withRSA"; + { + return "SHA1withDSA"; + } + if (sigAlgId.equals(ID_RSA_WITH_MD2)) + { + return "MD2withRSA"; + } + if (sigAlgId.equals(ID_RSA_WITH_MD5)) + { + return "MD5withRSA"; + } + if (sigAlgId.equals(ID_RSA_WITH_SHA1)) + { + return "SHA1withRSA"; + } return "unknown"; - // return sigAlgId.getShortName(); } public String getSigAlgOID() @@ -284,75 +302,81 @@ public class X509Certificate extends java.security.cert.X509Certificate public boolean[] getIssuerUniqueID() { if (issuerUniqueId != null) - return issuerUniqueId.toBooleanArray(); + { + return issuerUniqueId.toBooleanArray(); + } return null; } public boolean[] getSubjectUniqueID() { if (subjectUniqueId != null) - return subjectUniqueId.toBooleanArray(); + { + 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()); } + return Collections.unmodifiableList(b); } - catch (IOException ioe) - { - throw new CertificateParsingException(); - } - 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) - return null; - return getAltNames(ext); + Extension e = getExtension(SubjectAlternativeNames.ID); + if (e != null) + { + return ((SubjectAlternativeNames) e.getValue()).getNames(); + } + return null; } public Collection getIssuerAlternativeNames() throws CertificateParsingException { - byte[] ext = getExtensionValue("2.5.29.18"); - if (ext == null) - return null; - return getAltNames(ext); + Extension e = getExtension(IssuerAlternativeNames.ID); + if (e != null) + { + return ((IssuerAlternativeNames) e.getValue()).getNames(); + } + return null; } // X509Extension methods. @@ -360,12 +384,10 @@ public class X509Certificate extends java.security.cert.X509Certificate 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 class X509Certificate extends java.security.cert.X509Certificate 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 { @@ -398,7 +449,7 @@ public class X509Certificate extends java.security.cert.X509Certificate } public void verify(PublicKey key) - throws CertificateException, NoSuchAlgorithmException, + throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException { Signature sig = Signature.getInstance(sigAlgId.toString()); @@ -415,8 +466,50 @@ public class X509Certificate extends java.security.cert.X509Certificate 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,11 +517,25 @@ public class X509Certificate extends java.security.cert.X509Certificate 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 @@ public class X509Certificate extends java.security.cert.X509Certificate 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 @@ public class X509Certificate extends java.security.cert.X509Certificate // 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 @@ public class X509Certificate extends java.security.cert.X509Certificate { 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; + { + algVal = null; + } else - algVal = val.getEncoded(); + { + algVal = val.getEncoded(); + } if (val.isConstructed()) - encoded.skip(val.getLength()); + { + 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(); + // subject Name, val = der.read(); - OID keyID = (OID) val.getValue(); - byte[] keyParams = null; - if (keyAlgLen > val.getEncodedLength()) + 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()) { - val = der.read(); - keyParams = val.getEncoded(); - if (algVal == null) - algVal = keyParams; - if (val.isConstructed()) - encoded.skip(val.getLength()); + throw new IOException("malformed SubjectPublicKeyInfo"); } - val = der.read(); - byte[] keyVal = ((BitString) val.getValue()).toByteArray(); + KeyFactory spkFac = KeyFactory.getInstance("X.509"); + subjectKey = spkFac.generatePublic(new X509EncodedKeySpec(spki.getEncoded())); + der.skip(spki.getLength()); + debug("read subjectPublicKey == " + subjectKey); - 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)) + if (version > 1) { - 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())); + val = der.read(); } - else - throw new ASN1ParsingException("unknown key algorithm " + keyID); - - 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(); + { + sigAlgVal = (byte[]) val.getEncoded(); + } if (val.isConstructed()) - encoded.skip(val.getLength()); + { + encoded.skip(val.getLength()); + } + debug("read parameters == " + sigAlgVal); } signature = ((BitString) der.read().getValue()).toByteArray(); + debug("read signature ==\n" + Util.hexDump(signature, ">>>> ")); } } diff --git a/libjava/gnu/java/security/x509/ext/AuthorityKeyIdentifier.java b/libjava/gnu/java/security/x509/ext/AuthorityKeyIdentifier.java new file mode 100644 index 0000000..6f4e00b --- /dev/null +++ b/libjava/gnu/java/security/x509/ext/AuthorityKeyIdentifier.java @@ -0,0 +1,134 @@ +/* AuthorityKeyIdentifier.java -- Authority key identifier extension. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509.ext; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.List; + +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.x509.Util; + +public class AuthorityKeyIdentifier extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.35"); + + private final byte[] keyIdentifier; + private final GeneralNames authorityCertIssuer; + private final BigInteger authorityCertSerialNumber; + + // Contstructor. + // ------------------------------------------------------------------------- + + public AuthorityKeyIdentifier(final byte[] encoded) throws IOException + { + super(encoded); + DERReader der = new DERReader(encoded); + + // AuthorityKeyIdentifier ::= SEQUENCE { + DERValue val = der.read(); + if (!val.isConstructed()) + throw new IOException("malformed AuthorityKeyIdentifier"); + if (val.getLength() > 0) + val = der.read(); + + // keyIdentifier [0] KeyIdentifier OPTIONAL, + // KeyIdentifier ::= OCTET STRING + if (val.getTagClass() == DER.APPLICATION && val.getTag() == 0) + { + keyIdentifier = (byte[]) val.getValue(); + val = der.read(); + } + else + keyIdentifier = null; + + // authorityCertIssuer [1] GeneralNames OPTIONAL, + if (val.getTagClass() == DER.APPLICATION && val.getTag() == 1) + { + byte[] b = val.getEncoded(); + b[0] = (byte) (DER.CONSTRUCTED|DER.SEQUENCE); + authorityCertIssuer = new GeneralNames(b); + der.skip(val.getLength()); + val = der.read(); + } + else + authorityCertIssuer = null; + + // authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL } + if (val.getTagClass() == DER.APPLICATION && val.getTag() == 2) + { + authorityCertSerialNumber = new BigInteger((byte[]) val.getValue()); + } + else + authorityCertSerialNumber = null; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public byte[] getKeyIdentifier() + { + return keyIdentifier != null ? (byte[]) keyIdentifier.clone() : null; + } + + public GeneralNames getAuthorityCertIssuer() + { + return authorityCertIssuer; + } + + public BigInteger getAuthorityCertSerialNumber() + { + return authorityCertSerialNumber; + } + + public String toString() + { + return AuthorityKeyIdentifier.class.getName() + " [ keyId=" + + (keyIdentifier != null ? Util.toHexString (keyIdentifier, ':') : "nil") + + " authorityCertIssuer=" + authorityCertIssuer + + " authorityCertSerialNumbe=" + authorityCertSerialNumber + " ]"; + } +} diff --git a/libjava/gnu/java/security/x509/ext/BasicConstraints.java b/libjava/gnu/java/security/x509/ext/BasicConstraints.java new file mode 100644 index 0000000..f720d22 --- /dev/null +++ b/libjava/gnu/java/security/x509/ext/BasicConstraints.java @@ -0,0 +1,129 @@ +/* BasicConstraints.java -- the basic constraints extension. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509.ext; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +public class BasicConstraints extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.19"); + + private final boolean ca; + private final int pathLenConstraint; + + // Constructor. + // ------------------------------------------------------------------------- + + public BasicConstraints(final byte[] encoded) throws IOException + { + super(encoded); + DERReader der = new DERReader(encoded); + DERValue bc = der.read(); + if (!bc.isConstructed()) + throw new IOException("malformed BasicConstraints"); + DERValue val = bc; + if (bc.getLength() > 0) + val = der.read(); + if (val.getTag() == DER.BOOLEAN) + { + ca = ((Boolean) val.getValue()).booleanValue(); + if (val.getEncodedLength() < bc.getLength()) + val = der.read(); + } + else + ca = false; + if (val.getTag() == DER.INTEGER) + { + pathLenConstraint = ((BigInteger) val.getValue()).intValue(); + } + else + pathLenConstraint = -1; + } + + public BasicConstraints (final boolean ca, final int pathLenConstraint) + { + this.ca = ca; + this.pathLenConstraint = pathLenConstraint; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public boolean isCA() + { + return ca; + } + + public int getPathLengthConstraint() + { + return pathLenConstraint; + } + + public byte[] getEncoded() + { + if (encoded == null) + { + List bc = new ArrayList (2); + bc.add (new DERValue (DER.BOOLEAN, new Boolean (ca))); + if (pathLenConstraint >= 0) + bc.add (new DERValue (DER.INTEGER, + BigInteger.valueOf ((long) pathLenConstraint))); + encoded = new DERValue (DER.CONSTRUCTED|DER.SEQUENCE, bc).getEncoded(); + } + return (byte[]) encoded.clone(); + } + + public String toString() + { + return BasicConstraints.class.getName() + " [ isCA=" + ca + + " pathLen=" + pathLenConstraint + " ]"; + } +} diff --git a/libjava/gnu/java/security/x509/ext/CRLNumber.java b/libjava/gnu/java/security/x509/ext/CRLNumber.java new file mode 100644 index 0000000..556aa30 --- /dev/null +++ b/libjava/gnu/java/security/x509/ext/CRLNumber.java @@ -0,0 +1,97 @@ +/* CRLNumber.java -- CRL number extension. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509.ext; + +import java.io.IOException; +import java.math.BigInteger; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +public class CRLNumber extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.20"); + + private final BigInteger number; + + // Constructor. + // ------------------------------------------------------------------------- + + public CRLNumber(final byte[] encoded) throws IOException + { + super(encoded); + DERValue val = DERReader.read(encoded); + if (val.getTag() != DER.INTEGER) + throw new IOException("malformed CRLNumber"); + number = (BigInteger) val.getValue(); + } + + public CRLNumber (final BigInteger number) + { + this.number = number; + } + + // Instance method. + // ------------------------------------------------------------------------- + + public BigInteger getNumber() + { + return number; + } + + public byte[] getEncoded() + { + if (encoded == null) + { + encoded = new DERValue (DER.INTEGER, number).getEncoded(); + } + return (byte[]) encoded.clone(); + } + + public String toString() + { + return CRLNumber.class.getName() + " [ " + number + " ]"; + } +} diff --git a/libjava/gnu/java/security/x509/ext/CertificatePolicies.java b/libjava/gnu/java/security/x509/ext/CertificatePolicies.java new file mode 100644 index 0000000..206fa7e --- /dev/null +++ b/libjava/gnu/java/security/x509/ext/CertificatePolicies.java @@ -0,0 +1,191 @@ +/* CertificatePolicies.java -- certificate policy extension. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509.ext; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.cert.PolicyQualifierInfo; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +public class CertificatePolicies extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.32"); + + private final List policies; + private final Map policyQualifierInfos; + + // Constructor. + // ------------------------------------------------------------------------- + + public CertificatePolicies(final byte[] encoded) throws IOException + { + super(encoded); + DERReader der = new DERReader(encoded); + DERValue pol = der.read(); + if (!pol.isConstructed()) + throw new IOException("malformed CertificatePolicies"); + + int len = 0; + LinkedList policyList = new LinkedList(); + HashMap qualifierMap = new HashMap(); + while (len < pol.getLength()) + { + DERValue policyInfo = der.read(); + if (!policyInfo.isConstructed()) + throw new IOException("malformed PolicyInformation"); + DERValue val = der.read(); + if (val.getTag() != DER.OBJECT_IDENTIFIER) + throw new IOException("malformed CertPolicyId"); + OID policyId = (OID) val.getValue(); + policyList.add(policyId); + if (val.getEncodedLength() < policyInfo.getLength()) + { + DERValue qual = der.read(); + int len2 = 0; + LinkedList quals = new LinkedList(); + while (len2 < qual.getLength()) + { + val = der.read(); + quals.add(new PolicyQualifierInfo(val.getEncoded())); + der.skip(val.getLength()); + len2 += val.getEncodedLength(); + } + qualifierMap.put(policyId, quals); + } + len += policyInfo.getEncodedLength(); + } + + policies = Collections.unmodifiableList(policyList); + policyQualifierInfos = Collections.unmodifiableMap(qualifierMap); + } + + public CertificatePolicies (final List policies, + final Map policyQualifierInfos) + { + for (Iterator it = policies.iterator(); it.hasNext(); ) + if (!(it.next() instanceof OID)) + throw new IllegalArgumentException ("policies must be OIDs"); + for (Iterator it = policyQualifierInfos.entrySet().iterator(); it.hasNext();) + { + Map.Entry e = (Map.Entry) it.next(); + if (!(e.getKey() instanceof OID) || !policies.contains (e.getKey())) + throw new IllegalArgumentException + ("policyQualifierInfos keys must be OIDs"); + if (!(e.getValue() instanceof List)) + throw new IllegalArgumentException + ("policyQualifierInfos values must be Lists of PolicyQualifierInfos"); + for (Iterator it2 = ((List) e.getValue()).iterator(); it.hasNext(); ) + if (!(it2.next() instanceof PolicyQualifierInfo)) + throw new IllegalArgumentException + ("policyQualifierInfos values must be Lists of PolicyQualifierInfos"); + } + this.policies = Collections.unmodifiableList (new ArrayList (policies)); + this.policyQualifierInfos = Collections.unmodifiableMap + (new HashMap (policyQualifierInfos)); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public List getPolicies() + { + return policies; + } + + public List getPolicyQualifierInfos(OID oid) + { + return (List) policyQualifierInfos.get(oid); + } + + public byte[] getEncoded() + { + if (encoded == null) + { + List pol = new ArrayList (policies.size()); + for (Iterator it = policies.iterator(); it.hasNext(); ) + { + OID policy = (OID) it.next(); + List qualifiers = getPolicyQualifierInfos (policy); + List l = new ArrayList (qualifiers == null ? 1 : 2); + l.add (new DERValue (DER.OBJECT_IDENTIFIER, policy)); + if (qualifiers != null) + { + List ll = new ArrayList (qualifiers.size()); + for (Iterator it2 = qualifiers.iterator(); it.hasNext(); ) + { + PolicyQualifierInfo info = (PolicyQualifierInfo) it2.next(); + try + { + ll.add (DERReader.read (info.getEncoded())); + } + catch (IOException ioe) + { + } + } + l.add (new DERValue (DER.CONSTRUCTED|DER.SEQUENCE, ll)); + } + pol.add (new DERValue (DER.CONSTRUCTED|DER.SEQUENCE, l)); + } + encoded = new DERValue (DER.CONSTRUCTED|DER.SEQUENCE, pol).getEncoded(); + } + return (byte[]) encoded.clone(); + } + + public String toString() + { + return CertificatePolicies.class.getName() + " [ policies=" + policies + + " policyQualifierInfos=" + policyQualifierInfos + " ]"; + } +} diff --git a/libjava/gnu/java/security/x509/ext/ExtendedKeyUsage.java b/libjava/gnu/java/security/x509/ext/ExtendedKeyUsage.java new file mode 100644 index 0000000..e2a98e0 --- /dev/null +++ b/libjava/gnu/java/security/x509/ext/ExtendedKeyUsage.java @@ -0,0 +1,95 @@ +/* ExtendedKeyUsage.java -- the extended key usage extension. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509.ext; + +import java.io.IOException; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +public class ExtendedKeyUsage extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.37"); + + private final List purposeIds; + + // Constructor. + // ------------------------------------------------------------------------- + + public ExtendedKeyUsage(final byte[] encoded) throws IOException + { + super(encoded); + DERReader der = new DERReader(encoded); + DERValue usageList = der.read(); + if (!usageList.isConstructed()) + throw new IOException("malformed ExtKeyUsageSyntax"); + int len = 0; + purposeIds = new LinkedList(); + while (len < usageList.getLength()) + { + DERValue val = der.read(); + if (val.getTag() != DER.OBJECT_IDENTIFIER) + throw new IOException("malformed KeyPurposeId"); + purposeIds.add(val.getValue()); + len += val.getEncodedLength(); + } + } + + // Instance method. + // ------------------------------------------------------------------------- + + public List getPurposeIds() + { + return Collections.unmodifiableList(purposeIds); + } + + public String toString() + { + return ExtendedKeyUsage.class.getName() + " [ " + purposeIds + " ]"; + } +} diff --git a/libjava/gnu/java/security/x509/ext/Extension.java b/libjava/gnu/java/security/x509/ext/Extension.java new file mode 100644 index 0000000..ccbd60c --- /dev/null +++ b/libjava/gnu/java/security/x509/ext/Extension.java @@ -0,0 +1,289 @@ +/* Extension.java -- an X.509 certificate or CRL extension. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509.ext; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +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.x509.Util; + +public class Extension +{ + + // Fields. + // ------------------------------------------------------------------------- + + private static final boolean DEBUG = false; + private static void debug(String msg) + { + System.err.print(">> Extension: "); + System.err.println(msg); + } + + /** + * This extension's object identifier. + */ + protected final OID oid; + + /** + * The criticality flag. + */ + protected final boolean critical; + + /** + * Whether or not this extension is locally supported. + */ + protected boolean isSupported; + + /** + * The extension value. + */ + protected final Value value; + + /** + * The DER encoded form. + */ + protected byte[] encoded; + + // Constructors. + // ------------------------------------------------------------------------- + + public Extension(byte[] encoded) throws IOException + { + this.encoded = (byte[]) encoded.clone(); + DERReader der = new DERReader(encoded); + + // Extension ::= SEQUENCE { + DERValue val = der.read(); + if (DEBUG) debug("read val tag == " + val.getTag() + " len == " + val.getLength()); + if (!val.isConstructed()) + throw new IOException("malformed Extension"); + + // extnID OBJECT IDENTIFIER, + val = der.read(); + if (val.getTag() != DER.OBJECT_IDENTIFIER) + throw new IOException("expecting OBJECT IDENTIFIER"); + oid = (OID) val.getValue(); + if (DEBUG) debug("read oid == " + oid); + + // critical BOOLEAN DEFAULT FALSE, + val = der.read(); + if (val.getTag() == DER.BOOLEAN) + { + critical = ((Boolean) val.getValue()).booleanValue(); + val = der.read(); + } + else + critical = false; + if (DEBUG) debug("is critical == " + critical); + + // extnValue OCTET STRING } + if (val.getTag() != DER.OCTET_STRING) + throw new IOException("expecting OCTET STRING"); + byte[] encval = (byte[]) val.getValue(); + isSupported = true; + if (oid.equals(AuthorityKeyIdentifier.ID)) + { + value = new AuthorityKeyIdentifier(encval); + } + else if (oid.equals(SubjectKeyIdentifier.ID)) + { + value = new SubjectKeyIdentifier(encval); + } + else if (oid.equals(KeyUsage.ID)) + { + value = new KeyUsage(encval); + } + else if (oid.equals(PrivateKeyUsagePeriod.ID)) + { + value = new PrivateKeyUsagePeriod(encval); + } + else if (oid.equals(CertificatePolicies.ID)) + { + value = new CertificatePolicies(encval); + } + else if (oid.equals (PolicyConstraint.ID)) + { + value = new PolicyConstraint (encval); + } + else if (oid.equals(PolicyMappings.ID)) + { + value = new PolicyMappings(encval); + } + else if (oid.equals(SubjectAlternativeNames.ID)) + { + value = new SubjectAlternativeNames(encval); + } + else if (oid.equals(IssuerAlternativeNames.ID)) + { + value = new IssuerAlternativeNames(encval); + } + else if (oid.equals(BasicConstraints.ID)) + { + value = new BasicConstraints(encval); + } + else if (oid.equals(ExtendedKeyUsage.ID)) + { + value = new ExtendedKeyUsage(encval); + } + else if (oid.equals(CRLNumber.ID)) + { + value = new CRLNumber(encval); + } + else if (oid.equals(ReasonCode.ID)) + { + value = new ReasonCode(encval); + } + else + { + value = new Value(encval); + isSupported = false; + } + if (DEBUG) debug("read value == " + value); + } + + public Extension (final OID oid, final Value value, final boolean critical) + { + this.oid = oid; + this.value = value; + this.critical = critical; + isSupported = true; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public OID getOid() + { + return oid; + } + + public boolean isCritical() + { + return critical; + } + + public boolean isSupported() + { + return isSupported; + } + + public Value getValue() + { + return value; + } + + public byte[] getEncoded() + { + if (encoded == null) + encode(); + return (byte[]) encoded.clone(); + } + + public String toString() + { + return Extension.class.getName() + " [ id=" + oid + " critical=" + + critical + " value=" + value + " ]"; + } + + public DERValue getDerValue() + { + List ext = new ArrayList (3); + ext.add (new DERValue (DER.OBJECT_IDENTIFIER, oid)); + ext.add (new DERValue (DER.BOOLEAN, new Boolean (critical))); + ext.add (new DERValue (DER.OCTET_STRING, value.getEncoded())); + return new DERValue (DER.CONSTRUCTED|DER.SEQUENCE, ext); + } + + // Own methods. + // ------------------------------------------------------------------------- + + private void encode() + { + encoded = getDerValue().getEncoded(); + } + + // Inner class. + // ------------------------------------------------------------------------- + + public static class Value + { + + // Fields. + // ----------------------------------------------------------------------- + + protected byte[] encoded; + + // Constructor. + // ----------------------------------------------------------------------- + + public Value(byte[] encoded) + { + this.encoded = (byte[]) encoded.clone(); + } + + protected Value() { } + + // Instance methods. + // ----------------------------------------------------------------------- + + public byte[] getEncoded() + { + return (byte[]) encoded; + } + + public boolean equals(Object o) + { + if (!(o instanceof Value)) + return false; + return Arrays.equals(encoded, ((Value) o).encoded); + } + + public String toString() + { + return Util.toHexString(encoded, ':'); + } + } +} diff --git a/libjava/gnu/java/security/x509/ext/GeneralNames.java b/libjava/gnu/java/security/x509/ext/GeneralNames.java new file mode 100644 index 0000000..fc9a73b --- /dev/null +++ b/libjava/gnu/java/security/x509/ext/GeneralNames.java @@ -0,0 +1,157 @@ +/* GeneralNames.java -- the GeneralNames object. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509.ext; + +import java.io.IOException; + +import java.net.InetAddress; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import gnu.java.security.OID; +import gnu.java.security.x509.X500DistinguishedName; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +public class GeneralNames +{ + + // Instance methods. + // ------------------------------------------------------------------------- + + public static final int OTHER_NAME = 0; + public static final int RFC822_NAME = 1; + public static final int DNS_NAME = 2; + public static final int X400_ADDRESS = 3; + public static final int DIRECTORY_NAME = 4; + public static final int EDI_PARTY_NAME = 5; + public static final int URI = 6; + public static final int IP_ADDRESS = 7; + public static final int REGISTERED_ID = 8; + + private List names; + + // Constructor. + // ------------------------------------------------------------------------- + + public GeneralNames(final byte[] encoded) throws IOException + { + names = new LinkedList(); + DERReader der = new DERReader(encoded); + DERValue nameList = der.read(); + if (!nameList.isConstructed()) + throw new IOException("malformed GeneralNames"); + int len = 0; + while (len < nameList.getLength()) + { + DERValue name = der.read(); + List namePair = new ArrayList(2); + if (name.getTagClass() != DER.APPLICATION) + throw new IOException("malformed GeneralName"); + namePair.add(new Integer(name.getTag())); + DERValue val = null; + switch (name.getTag()) + { + case RFC822_NAME: + case DNS_NAME: + case X400_ADDRESS: + case URI: + namePair.add(new String((byte[]) name.getValue())); + break; + + case OTHER_NAME: + case EDI_PARTY_NAME: + namePair.add(name.getValue()); + break; + + case DIRECTORY_NAME: + byte[] b = name.getEncoded(); + b[0] = (byte) (DER.CONSTRUCTED|DER.SEQUENCE); + namePair.add(new X500DistinguishedName(b).toString()); + break; + + case IP_ADDRESS: + namePair.add(InetAddress.getByAddress((byte[]) name.getValue()) + .getHostAddress()); + break; + + case REGISTERED_ID: + byte[] bb = name.getEncoded(); + bb[0] = (byte) DER.OBJECT_IDENTIFIER; + namePair.add(new OID(bb).toString()); + break; + + default: + throw new IOException("unknown tag " + name.getTag()); + } + names.add(namePair); + len += name.getEncodedLength(); + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public List getNames() + { + List l = new ArrayList(names.size()); + for (Iterator it = names.iterator(); it.hasNext(); ) + { + List ll = (List) it.next(); + List pair = new ArrayList(2); + pair.add(ll.get(0)); + if (ll.get(1) instanceof byte[]) + pair.add(((byte[]) ll.get(1)).clone()); + else + pair.add(ll.get(1)); + l.add(Collections.unmodifiableList(pair)); + } + return Collections.unmodifiableList(l); + } + + public String toString() + { + return GeneralNames.class.getName() + " [ " + names + " ]"; + } +} diff --git a/libjava/gnu/java/security/x509/ext/IssuerAlternativeNames.java b/libjava/gnu/java/security/x509/ext/IssuerAlternativeNames.java new file mode 100644 index 0000000..0d0beb0 --- /dev/null +++ b/libjava/gnu/java/security/x509/ext/IssuerAlternativeNames.java @@ -0,0 +1,76 @@ +/* IssuerAlternatuveNames.java -- issuer alternative names extension. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509.ext; + +import java.io.IOException; +import java.util.List; +import gnu.java.security.OID; + +public class IssuerAlternativeNames extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.18"); + + private final GeneralNames names; + + // Constructor. + // ------------------------------------------------------------------------- + + public IssuerAlternativeNames(final byte[] encoded) throws IOException + { + super(encoded); + names = new GeneralNames(encoded); + } + + // Instance method. + // ------------------------------------------------------------------------- + + public List getNames() + { + return names.getNames(); + } + + public String toString() + { + return IssuerAlternativeNames.class.getName() + " [ " + names + " ]"; + } +} diff --git a/libjava/gnu/java/security/x509/ext/KeyUsage.java b/libjava/gnu/java/security/x509/ext/KeyUsage.java new file mode 100644 index 0000000..7d5d7c6 --- /dev/null +++ b/libjava/gnu/java/security/x509/ext/KeyUsage.java @@ -0,0 +1,92 @@ +/* KeyUsage.java -- the key usage extension. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509.ext; + +import java.io.IOException; + +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; + +public class KeyUsage extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.15"); + public static final int DIGITAL_SIGNATURE = 0; + public static final int NON_REPUDIATION = 1; + public static final int KEY_ENCIPHERMENT = 2; + public static final int DATA_ENCIPHERMENT = 3; + public static final int KEY_AGREEMENT = 4; + public static final int KEY_CERT_SIGN = 5; + public static final int CRL_SIGN = 6; + public static final int ENCIPHER_ONLY = 7; + public static final int DECIPHER_ONLY = 8; + + private final BitString keyUsage; + + // Constructor. + // ------------------------------------------------------------------------- + + public KeyUsage(final byte[] encoded) throws IOException + { + super(encoded); + DERValue val = DERReader.read(encoded); + if (val.getTag() != DER.BIT_STRING) + throw new IOException("malformed KeyUsage"); + keyUsage = (BitString) val.getValue(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public BitString getKeyUsage() + { + return keyUsage; + } + + public String toString() + { + return KeyUsage.class.getName() + " [ " + keyUsage + " ]"; + } +} diff --git a/libjava/gnu/java/security/x509/ext/PolicyConstraint.java b/libjava/gnu/java/security/x509/ext/PolicyConstraint.java new file mode 100644 index 0000000..0949b50 --- /dev/null +++ b/libjava/gnu/java/security/x509/ext/PolicyConstraint.java @@ -0,0 +1,109 @@ +/* PolicyConstraint.java -- policyConstraint extension + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509.ext; + +import java.io.IOException; +import java.math.BigInteger; + +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.x509.Util; + +public class PolicyConstraint extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID ("2.5.29.36"); + + private final int requireExplicitPolicy; + private final int inhibitPolicyMapping; + + // Constructors. + // ------------------------------------------------------------------------- + + public PolicyConstraint (final byte[] encoded) throws IOException + { + super (encoded); + int rpc = -1, ipm = -1; + DERReader der = new DERReader(encoded); + DERValue pc = der.read(); + if (!pc.isConstructed()) + throw new IOException("malformed PolicyConstraints"); + DERValue val; + int len = pc.getLength(); + while (len > 0) + { + val = der.read(); + if (val.getTag() == 0) + rpc = new BigInteger ((byte[]) val.getValue()).intValue(); + else if (val.getTag() == 1) + ipm = new BigInteger ((byte[]) val.getValue()).intValue(); + else + throw new IOException ("invalid policy constraint"); + len -= val.getEncodedLength(); + } + + requireExplicitPolicy = rpc; + inhibitPolicyMapping = ipm; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int getRequireExplicitPolicy() + { + return requireExplicitPolicy; + } + + public int getInhibitPolicyMapping() + { + return inhibitPolicyMapping; + } + + public String toString() + { + return PolicyConstraint.class.getName() + " [ requireExplicitPolicy=" + + requireExplicitPolicy + " inhibitPolicyMapping=" + inhibitPolicyMapping + + " ]"; + } +} diff --git a/libjava/gnu/java/security/x509/ext/PolicyMappings.java b/libjava/gnu/java/security/x509/ext/PolicyMappings.java new file mode 100644 index 0000000..827e83f --- /dev/null +++ b/libjava/gnu/java/security/x509/ext/PolicyMappings.java @@ -0,0 +1,104 @@ +/* PolicyMappings.java -- policy mappings extension. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509.ext; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +public class PolicyMappings extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.33"); + + private final Map mappings; + + // Constructor. + // ------------------------------------------------------------------------- + + public PolicyMappings(final byte[] encoded) throws IOException + { + super(encoded); + DERReader der = new DERReader(encoded); + DERValue maps = der.read(); + if (!maps.isConstructed()) + throw new IOException("malformed PolicyMappings"); + int len = 0; + HashMap _mappings = new HashMap(); + while (len < maps.getLength()) + { + DERValue map = der.read(); + if (!map.isConstructed()) + throw new IOException("malformed PolicyMapping"); + DERValue val = der.read(); + if (val.getTag() != DER.OBJECT_IDENTIFIER) + throw new IOException("malformed PolicyMapping"); + OID issuerPolicy = (OID) val.getValue(); + val = der.read(); + if (val.getTag() != DER.OBJECT_IDENTIFIER) + throw new IOException("malformed PolicyMapping"); + OID subjectPolicy = (OID) val.getValue(); + _mappings.put(issuerPolicy, subjectPolicy); + len += map.getEncodedLength(); + } + mappings = Collections.unmodifiableMap(_mappings); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public OID getSubjectDomainPolicy(OID issuerDomainPolicy) + { + return (OID) mappings.get(issuerDomainPolicy); + } + + public String toString() + { + return PolicyMappings.class.getName() + " [ " + mappings + " ]"; + } +} diff --git a/libjava/gnu/java/security/x509/ext/PrivateKeyUsagePeriod.java b/libjava/gnu/java/security/x509/ext/PrivateKeyUsagePeriod.java new file mode 100644 index 0000000..108af4b --- /dev/null +++ b/libjava/gnu/java/security/x509/ext/PrivateKeyUsagePeriod.java @@ -0,0 +1,105 @@ +/* PrivateKeyUsagePeriod.java -- private key usage period extension. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509.ext; + +import java.io.IOException; +import java.util.Date; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +public class PrivateKeyUsagePeriod extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.16"); + + private final Date notBefore; + private final Date notAfter; + + // Constructor. + // ------------------------------------------------------------------------- + + public PrivateKeyUsagePeriod(final byte[] encoded) throws IOException + { + super(encoded); + DERReader der = new DERReader(encoded); + DERValue val = der.read(); + if (!val.isConstructed()) + throw new IOException("malformed PrivateKeyUsagePeriod"); + if (val.getLength() > 0) + val = der.read(); + if (val.getTagClass() == DER.APPLICATION || val.getTag() == 0) + { + notBefore = (Date) val.getValue(); + val = der.read(); + } + else + notBefore = null; + if (val.getTagClass() == DER.APPLICATION || val.getTag() == 1) + { + notAfter = (Date) val.getValue(); + } + else + notAfter = null; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public Date getNotBefore() + { + return notBefore != null ? (Date) notBefore.clone() : null; + } + + public Date getNotAfter() + { + return notAfter != null ? (Date) notAfter.clone() : null; + } + + public String toString() + { + return PrivateKeyUsagePeriod.class.getName() + " [ notBefore=" + notBefore + + " notAfter=" + notAfter + " ]"; + } +} diff --git a/libjava/gnu/java/security/x509/ext/ReasonCode.java b/libjava/gnu/java/security/x509/ext/ReasonCode.java new file mode 100644 index 0000000..779611d --- /dev/null +++ b/libjava/gnu/java/security/x509/ext/ReasonCode.java @@ -0,0 +1,85 @@ +/* ReasonCode.java -- a reason code for a certificate revocation. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509.ext; + +import java.io.IOException; +import java.math.BigInteger; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +public class ReasonCode extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.21"); + + public final int reason; + + // Constructor. + // ------------------------------------------------------------------------- + + public ReasonCode(final byte[] encoded) throws IOException + { + super(encoded); + DERValue val = DERReader.read(encoded); + if (val.getTag() != DER.ENUMERATED) + throw new IOException("malformed CRLReason"); + reason = ((BigInteger) val.getValue()).intValue(); + if (reason < 0 || reason == 7 || reason > 10) + throw new IOException("illegal reason: " + reason); + } + + // Instance method. + // ------------------------------------------------------------------------- + + public int getReasonCode() + { + return reason; + } + + public String toString() + { + return ReasonCode.class.getName() + " [ " + reason + " ]"; + } +} diff --git a/libjava/gnu/java/security/x509/ext/SubjectAlternativeNames.java b/libjava/gnu/java/security/x509/ext/SubjectAlternativeNames.java new file mode 100644 index 0000000..19c0bde --- /dev/null +++ b/libjava/gnu/java/security/x509/ext/SubjectAlternativeNames.java @@ -0,0 +1,77 @@ +/* SubjectAlternatuveNames.java -- subject alternative names extension. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509.ext; + +import java.io.IOException; +import java.util.List; + +import gnu.java.security.OID; + +public class SubjectAlternativeNames extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.17"); + + private final GeneralNames names; + + // Constructor. + // ------------------------------------------------------------------------- + + public SubjectAlternativeNames(final byte[] encoded) throws IOException + { + super(encoded); + names = new GeneralNames(encoded); + } + + // Instance method. + // ------------------------------------------------------------------------- + + public List getNames() + { + return names.getNames(); + } + + public String toString() + { + return SubjectAlternativeNames.class.getName() + " [ " + names + " ]"; + } +} diff --git a/libjava/gnu/java/security/x509/ext/SubjectKeyIdentifier.java b/libjava/gnu/java/security/x509/ext/SubjectKeyIdentifier.java new file mode 100644 index 0000000..2d48f7c --- /dev/null +++ b/libjava/gnu/java/security/x509/ext/SubjectKeyIdentifier.java @@ -0,0 +1,84 @@ +/* SubjectKeyIdentifier.java -- subject key identifier extension. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509.ext; + +import java.io.IOException; + +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.x509.Util; + +public class SubjectKeyIdentifier extends Extension.Value +{ + + // Constant. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.14"); + + private final byte[] keyIdentifier; + + // Constructor. + // ------------------------------------------------------------------------- + + public SubjectKeyIdentifier(final byte[] encoded) throws IOException + { + super(encoded); + DERValue val = DERReader.read(encoded); + if (val.getTag() != DER.OCTET_STRING) + throw new IOException("malformed SubjectKeyIdentifier"); + keyIdentifier = (byte[]) val.getValue(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public byte[] getKeyIdentifier() + { + return (byte[]) keyIdentifier.clone(); + } + + public String toString() + { + return SubjectKeyIdentifier.class.getName() + " [ " + + Util.toHexString (keyIdentifier, ':') + " ]"; + } +} |