From dff006b341fa1d94c0a1e8e315f019721aeabe5f Mon Sep 17 00:00:00 2001 From: David Hook Date: Fri, 24 May 2013 16:23:40 +1000 Subject: BJA-453 added parsing of explicit parameters --- .../bouncycastle/asn1/x9/ECNamedCurveTable.java | 97 ++++++++++++++++++++++ .../java/org/bouncycastle/openssl/PEMParser.java | 26 +++--- .../org/bouncycastle/openssl/test/ParserTest.java | 49 ++++++++++- 3 files changed, 157 insertions(+), 15 deletions(-) create mode 100644 src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java diff --git a/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java b/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java new file mode 100644 index 00000000..fb545c2b --- /dev/null +++ b/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java @@ -0,0 +1,97 @@ +package org.bouncycastle.asn1.x9; + +import java.util.Enumeration; +import java.util.Vector; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.nist.NISTNamedCurves; +import org.bouncycastle.asn1.sec.SECNamedCurves; +import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves; + +/** + * A general class that reads all X9.62 style EC curve tables. + */ +public class ECNamedCurveTable +{ + /** + * return a X9ECParameters object representing the passed in named + * curve. The routine returns null if the curve is not present. + * + * @param name the name of the curve requested + * @return an X9ECParameters object or null if the curve is not available. + */ + public static X9ECParameters getByName( + String name) + { + X9ECParameters ecP = X962NamedCurves.getByName(name); + + if (ecP == null) + { + ecP = SECNamedCurves.getByName(name); + } + + if (ecP == null) + { + ecP = TeleTrusTNamedCurves.getByName(name); + } + + if (ecP == null) + { + ecP = NISTNamedCurves.getByName(name); + } + + return ecP; + } + + /** + * return a X9ECParameters object representing the passed in named + * curve. + * + * @param oid the object id of the curve requested + * @return an X9ECParameters object or null if the curve is not available. + */ + public static X9ECParameters getByOID( + ASN1ObjectIdentifier oid) + { + X9ECParameters ecP = X962NamedCurves.getByOID(oid); + + if (ecP == null) + { + ecP = SECNamedCurves.getByOID(oid); + } + + if (ecP == null) + { + ecP = TeleTrusTNamedCurves.getByOID(oid); + } + + return ecP; + } + + /** + * return an enumeration of the names of the available curves. + * + * @return an enumeration of the names of the available curves. + */ + public static Enumeration getNames() + { + Vector v = new Vector(); + + addEnumeration(v, X962NamedCurves.getNames()); + addEnumeration(v, SECNamedCurves.getNames()); + addEnumeration(v, NISTNamedCurves.getNames()); + addEnumeration(v, TeleTrusTNamedCurves.getNames()); + + return v.elements(); + } + + private static void addEnumeration( + Vector v, + Enumeration e) + { + while (e.hasMoreElements()) + { + v.addElement(e.nextElement()); + } + } +} diff --git a/src/main/java/org/bouncycastle/openssl/PEMParser.java b/src/main/java/org/bouncycastle/openssl/PEMParser.java index ed0caf6f..672f3da5 100644 --- a/src/main/java/org/bouncycastle/openssl/PEMParser.java +++ b/src/main/java/org/bouncycastle/openssl/PEMParser.java @@ -10,10 +10,10 @@ import java.util.StringTokenizer; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.cms.ContentInfo; import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; @@ -22,11 +22,11 @@ import org.bouncycastle.asn1.pkcs.RSAPublicKey; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.DSAParameter; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.cert.X509AttributeCertificateHolder; import org.bouncycastle.cert.X509CRLHolder; import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.jce.ECNamedCurveTable; import org.bouncycastle.pkcs.PKCS10CertificationRequest; import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo; import org.bouncycastle.util.encoders.Hex; @@ -67,7 +67,7 @@ public class PEMParser parsers.put("X509 CRL", new X509CRLParser()); parsers.put("PKCS7", new PKCS7Parser()); parsers.put("ATTRIBUTE CERTIFICATE", new X509AttributeCertificateParser()); - parsers.put("EC PARAMETERS", new ECNamedCurveSpecParser()); + parsers.put("EC PARAMETERS", new ECCurveParamsParser()); parsers.put("PUBLIC KEY", new PublicKeyParser()); parsers.put("RSA PUBLIC KEY", new RSAPublicKeyParser()); parsers.put("RSA PRIVATE KEY", new KeyPairParser(new RSAKeyPairParser())); @@ -425,7 +425,7 @@ public class PEMParser } } - private class ECNamedCurveSpecParser + private class ECCurveParamsParser implements PemObjectParser { public Object parseObject(PemObject obj) @@ -433,16 +433,20 @@ public class PEMParser { try { - DERObjectIdentifier oid = (DERObjectIdentifier)ASN1Primitive.fromByteArray(obj.getContent()); + Object param = ASN1Primitive.fromByteArray(obj.getContent()); - Object params = ECNamedCurveTable.getParameterSpec(oid.getId()); - - if (params == null) + if (param instanceof ASN1ObjectIdentifier) { - throw new IOException("object ID not found in EC curve table"); + return ASN1Primitive.fromByteArray(obj.getContent()); + } + else if (param instanceof ASN1Sequence) + { + return X9ECParameters.getInstance(param); + } + else + { + return null; // implicitly CA } - - return params; } catch (IOException e) { diff --git a/src/test/java/org/bouncycastle/openssl/test/ParserTest.java b/src/test/java/org/bouncycastle/openssl/test/ParserTest.java index 507b60a6..188b536b 100644 --- a/src/test/java/org/bouncycastle/openssl/test/ParserTest.java +++ b/src/test/java/org/bouncycastle/openssl/test/ParserTest.java @@ -20,18 +20,20 @@ import java.security.interfaces.DSAPrivateKey; import java.security.interfaces.RSAPrivateCrtKey; import java.security.interfaces.RSAPrivateKey; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; import org.bouncycastle.asn1.cms.ContentInfo; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.asn1.x9.ECNamedCurveTable; +import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; import org.bouncycastle.openssl.PEMDecryptorProvider; import org.bouncycastle.openssl.PEMEncryptedKeyPair; +import org.bouncycastle.openssl.PEMKeyPair; import org.bouncycastle.openssl.PEMParser; import org.bouncycastle.openssl.PEMWriter; -import org.bouncycastle.openssl.PEMKeyPair; import org.bouncycastle.openssl.PasswordFinder; import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder; @@ -79,7 +81,6 @@ public class ParserTest public void performTest() throws Exception { - PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build("secret".toCharArray()); PEMParser pemRd = openPEMResource("test.pem"); Object o; PEMKeyPair pemPair; @@ -126,7 +127,8 @@ public class ParserTest // ECKey // pemRd = openPEMResource("eckey.pem"); - ECNamedCurveParameterSpec spec = (ECNamedCurveParameterSpec)pemRd.readObject(); + ASN1ObjectIdentifier ecOID = (ASN1ObjectIdentifier)pemRd.readObject(); + X9ECParameters ecSpec = ECNamedCurveTable.getByOID(ecOID); pemPair = (PEMKeyPair)pemRd.readObject(); @@ -161,6 +163,45 @@ public class ParserTest fail("wrong algorithm name on private"); } + // + // ECKey -- explicit parameters + // + pemRd = openPEMResource("ecexpparam.pem"); + ecSpec = (X9ECParameters)pemRd.readObject(); + + pemPair = (PEMKeyPair)pemRd.readObject(); + + pair = new JcaPEMKeyConverter().setProvider("BC").getKeyPair(pemPair); + + sgr = Signature.getInstance("ECDSA", "BC"); + + sgr.initSign(pair.getPrivate()); + + message = new byte[] { (byte)'a', (byte)'b', (byte)'c' }; + + sgr.update(message); + + sigBytes = sgr.sign(); + + sgr.initVerify(pair.getPublic()); + + sgr.update(message); + + if (!sgr.verify(sigBytes)) + { + fail("EC verification failed"); + } + + if (!pair.getPublic().getAlgorithm().equals("ECDSA")) + { + fail("wrong algorithm name on public got: " + pair.getPublic().getAlgorithm()); + } + + if (!pair.getPrivate().getAlgorithm().equals("ECDSA")) + { + fail("wrong algorithm name on private"); + } + // // writer/parser test // -- cgit v1.2.3