# HG changeset patch # User juh # Date 1420833514 28800 # Node ID 5fdc6e6c0b972d4acd38304c18f0a726320b038e # Parent ddfb652c749628bd09e92b033030e4f7556b139a 8046724: XML Signature ECKeyValue elements cannot be marshalled or unmarshalled Reviewed-by: mullan diff -r ddfb652c7496 -r 5fdc6e6c0b97 jdk/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyValue.java --- a/jdk/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyValue.java Fri Jan 09 16:54:17 2015 +0100 +++ b/jdk/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyValue.java Fri Jan 09 11:58:34 2015 -0800 @@ -21,7 +21,7 @@ * under the License. */ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. */ /* * $Id: DOMKeyValue.java 1333415 2012-05-03 12:03:51Z coheigea $ @@ -33,20 +33,19 @@ import javax.xml.crypto.dsig.*; import javax.xml.crypto.dsig.keyinfo.KeyValue; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.security.AccessController; +import java.io.IOException; +import java.math.BigInteger; import java.security.KeyException; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; import java.security.PublicKey; import java.security.interfaces.DSAParams; import java.security.interfaces.DSAPublicKey; import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.DSAPublicKeySpec; +import java.security.spec.ECField; +import java.security.spec.ECFieldFp; import java.security.spec.ECParameterSpec; import java.security.spec.ECPoint; import java.security.spec.ECPublicKeySpec; @@ -54,6 +53,7 @@ import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; import java.security.spec.RSAPublicKeySpec; +import java.util.Arrays; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -325,55 +325,112 @@ private byte[] ecPublicKey; private KeyFactory eckf; private ECParameterSpec ecParams; - private Method encodePoint, decodePoint, getCurveName, - getECParameterSpec; + + // The supported curve, secp256r1 + private static final Curve SECP256R1; + static { + final String name, oid, sfield, a, b, x, y, n; + name = "secp256r1 [NIST P-256, X9.62 prime256v1]"; + oid = "1.2.840.10045.3.1.7"; + sfield = + "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"; + a = + "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC"; + b = + "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"; + x = + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"; + y = + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"; + n = + "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"; + final int h = 1; + + BigInteger p = bigInt(sfield); + ECField field = new ECFieldFp(p); + EllipticCurve curve = new EllipticCurve(field, bigInt(a), + bigInt(b)); + ECPoint g = new ECPoint(bigInt(x), bigInt(y)); + SECP256R1 = new Curve(name, oid, curve, g, bigInt(n), h); + } EC(PublicKey key) throws KeyException { super(key); ECPublicKey ecKey = (ECPublicKey)key; ECPoint ecPoint = ecKey.getW(); ecParams = ecKey.getParams(); - try { - AccessController.doPrivileged( - new PrivilegedExceptionAction() { - public Void run() throws - ClassNotFoundException, NoSuchMethodException - { - getMethods(); - return null; - } - } - ); - } catch (PrivilegedActionException pae) { - throw new KeyException("ECKeyValue not supported", - pae.getException()); - } - Object[] args = new Object[] { ecPoint, ecParams.getCurve() }; - try { - ecPublicKey = (byte[])encodePoint.invoke(null, args); - } catch (IllegalAccessException iae) { - throw new KeyException(iae); - } catch (InvocationTargetException ite) { - throw new KeyException(ite); - } + ecPublicKey = encodePoint(ecPoint, ecParams.getCurve()); } EC(Element dmElem) throws MarshalException { super(dmElem); } - void getMethods() throws ClassNotFoundException, NoSuchMethodException { - Class c = Class.forName("sun.security.util.ECParameters"); - Class[] params = new Class[] { ECPoint.class, - EllipticCurve.class }; - encodePoint = c.getMethod("encodePoint", params); - params = new Class[] { ECParameterSpec.class }; - getCurveName = c.getMethod("getCurveName", params); - params = new Class[] { byte[].class, EllipticCurve.class }; - decodePoint = c.getMethod("decodePoint", params); - c = Class.forName("sun.security.util.NamedCurve"); - params = new Class[] { String.class }; - getECParameterSpec = c.getMethod("getECParameterSpec", params); + private static ECPoint decodePoint(byte[] data, EllipticCurve curve) + throws IOException { + if ((data.length == 0) || (data[0] != 4)) { + throw new IOException("Only uncompressed point format " + + "supported"); + } + // Per ANSI X9.62, an encoded point is a 1 byte type followed by + // ceiling(log base 2 field-size / 8) bytes of x and the same of y. + int n = (data.length - 1) / 2; + if (n != ((curve.getField().getFieldSize() + 7) >> 3)) { + throw new IOException("Point does not match field size"); + } + + byte[] xb = Arrays.copyOfRange(data, 1, 1 + n); + byte[] yb = Arrays.copyOfRange(data, n + 1, n + 1 + n); + + return new ECPoint(new BigInteger(1, xb), new BigInteger(1, yb)); + } + + private static byte[] encodePoint(ECPoint point, EllipticCurve curve) { + // get field size in bytes (rounding up) + int n = (curve.getField().getFieldSize() + 7) >> 3; + byte[] xb = trimZeroes(point.getAffineX().toByteArray()); + byte[] yb = trimZeroes(point.getAffineY().toByteArray()); + if ((xb.length > n) || (yb.length > n)) { + throw new RuntimeException("Point coordinates do not " + + "match field size"); + } + byte[] b = new byte[1 + (n << 1)]; + b[0] = 4; // uncompressed + System.arraycopy(xb, 0, b, n - xb.length + 1, xb.length); + System.arraycopy(yb, 0, b, b.length - yb.length, yb.length); + return b; + } + + private static byte[] trimZeroes(byte[] b) { + int i = 0; + while ((i < b.length - 1) && (b[i] == 0)) { + i++; + } + if (i == 0) { + return b; + } + return Arrays.copyOfRange(b, i, b.length); + } + + private static String getCurveOid(ECParameterSpec params) { + // Check that the params represent the secp256r1 curve + // If so, return the object identifier of the curve + int fieldSize = params.getCurve().getField().getFieldSize(); + if (SECP256R1.getCurve().getField().getFieldSize() == fieldSize + && SECP256R1.getCurve().equals(params.getCurve()) + && SECP256R1.getGenerator().equals(params.getGenerator()) + && SECP256R1.getOrder().equals(params.getOrder()) + && SECP256R1.getCofactor() == params.getCofactor()) { + return SECP256R1.getObjectId(); + } + return null; + } + + private static ECParameterSpec getECParameterSpec(String oid) { + if (oid.equals(SECP256R1.getObjectId())) { + return SECP256R1; + } + return null; } void marshalPublicKey(Node parent, Document doc, String dsPrefix, @@ -391,14 +448,11 @@ XMLDSIG_11_XMLNS, prefix); Object[] args = new Object[] { ecParams }; - try { - String oid = (String) getCurveName.invoke(null, args); - DOMUtils.setAttribute(namedCurveElem, "URI", "urn:oid:" + oid); - } catch (IllegalAccessException iae) { - throw new MarshalException(iae); - } catch (InvocationTargetException ite) { - throw new MarshalException(ite); + String oid = getCurveOid(ecParams); + if (oid == null) { + throw new MarshalException("Invalid ECParameterSpec"); } + DOMUtils.setAttribute(namedCurveElem, "URI", "urn:oid:" + oid); String qname = (prefix == null || prefix.length() == 0) ? "xmlns" : "xmlns:" + prefix; namedCurveElem.setAttributeNS("http://www.w3.org/2000/xmlns/", @@ -422,21 +476,6 @@ ("unable to create EC KeyFactory: " + e.getMessage()); } } - try { - AccessController.doPrivileged( - new PrivilegedExceptionAction() { - public Void run() throws - ClassNotFoundException, NoSuchMethodException - { - getMethods(); - return null; - } - } - ); - } catch (PrivilegedActionException pae) { - throw new MarshalException("ECKeyValue not supported", - pae.getException()); - } ECParameterSpec ecParams = null; Element curElem = DOMUtils.getFirstChildElement(kvtElem); if (curElem.getLocalName().equals("ECParameters")) { @@ -447,14 +486,9 @@ // strip off "urn:oid" if (uri.startsWith("urn:oid:")) { String oid = uri.substring(8); - try { - Object[] args = new Object[] { oid }; - ecParams = (ECParameterSpec) - getECParameterSpec.invoke(null, args); - } catch (IllegalAccessException iae) { - throw new MarshalException(iae); - } catch (InvocationTargetException ite) { - throw new MarshalException(ite); + ecParams = getECParameterSpec(oid); + if (ecParams == null) { + throw new MarshalException("Invalid curve OID"); } } else { throw new MarshalException("Invalid NamedCurve URI"); @@ -464,24 +498,43 @@ } curElem = DOMUtils.getNextSiblingElement(curElem, "PublicKey"); ECPoint ecPoint = null; + try { - Object[] args = new Object[] { Base64.decode(curElem), - ecParams.getCurve() }; - ecPoint = (ECPoint)decodePoint.invoke(null, args); + ecPoint = decodePoint(Base64.decode(curElem), + ecParams.getCurve()); } catch (Base64DecodingException bde) { throw new MarshalException("Invalid EC PublicKey", bde); - } catch (IllegalAccessException iae) { - throw new MarshalException(iae); - } catch (InvocationTargetException ite) { - throw new MarshalException(ite); + } catch (IOException ioe) { + throw new MarshalException("Invalid EC Point", ioe); } -/* - ecPoint = sun.security.util.ECParameters.decodePoint( - Base64.decode(curElem), ecParams.getCurve()); -*/ + ECPublicKeySpec spec = new ECPublicKeySpec(ecPoint, ecParams); return generatePublicKey(eckf, spec); } + + static final class Curve extends ECParameterSpec { + private final String name; + private final String oid; + + Curve(String name, String oid, EllipticCurve curve, + ECPoint g, BigInteger n, int h) { + super(curve, g, n, h); + this.name = name; + this.oid = oid; + } + + private String getName() { + return name; + } + + private String getObjectId() { + return oid; + } + } + } + + private static BigInteger bigInt(String s) { + return new BigInteger(s, 16); } static final class Unknown extends DOMKeyValue { diff -r ddfb652c7496 -r 5fdc6e6c0b97 jdk/test/javax/xml/crypto/dsig/GenerationTests.java --- a/jdk/test/javax/xml/crypto/dsig/GenerationTests.java Fri Jan 09 16:54:17 2015 +0100 +++ b/jdk/test/javax/xml/crypto/dsig/GenerationTests.java Fri Jan 09 11:58:34 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ /** * @test * @bug 4635230 6283345 6303830 6824440 6867348 7094155 8038184 8038349 8046949 + * 8046724 * @summary Basic unit tests for generating XML Signatures with JSR 105 * @compile -XDignore.symbol.file KeySelectors.java SignatureValidator.java * X509KeySelector.java GenerationTests.java @@ -45,6 +46,13 @@ import java.security.spec.KeySpec; import java.security.spec.DSAPrivateKeySpec; import java.security.spec.DSAPublicKeySpec; +import java.security.spec.ECField; +import java.security.spec.ECFieldFp; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPrivateKeySpec; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.EllipticCurve; import java.security.spec.RSAPrivateKeySpec; import java.security.spec.RSAPublicKeySpec; import java.util.*; @@ -81,9 +89,10 @@ private static DocumentBuilder db; private static CanonicalizationMethod withoutComments; private static SignatureMethod dsaSha1, dsaSha256, rsaSha1, - rsaSha256, rsaSha384, rsaSha512; + rsaSha256, rsaSha384, rsaSha512, + ecdsaSha1; private static DigestMethod sha1, sha256, sha384, sha512; - private static KeyInfo dsa1024, dsa2048, rsa, rsa1024; + private static KeyInfo dsa1024, dsa2048, rsa, rsa1024, p256ki; private static KeySelector kvks = new KeySelectors.KeyValueKeySelector(); private static KeySelector sks; private static Key signingKey; @@ -121,6 +130,7 @@ test_create_signature_enveloping_hmac_sha384(); test_create_signature_enveloping_hmac_sha512(); test_create_signature_enveloping_rsa(); + test_create_signature_enveloping_p256_sha1(); test_create_signature_external_b64_dsa(); test_create_signature_external_dsa(); test_create_signature_keyname(); @@ -175,6 +185,8 @@ (kifac.newKeyValue(getPublicKey("RSA", 512)))); rsa1024 = kifac.newKeyInfo(Collections.singletonList (kifac.newKeyValue(getPublicKey("RSA", 1024)))); + p256ki = kifac.newKeyInfo(Collections.singletonList + (kifac.newKeyValue(getECPublicKey()))); rsaSha1 = fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null); rsaSha256 = fac.newSignatureMethod ("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", null); @@ -182,6 +194,8 @@ ("http://www.w3.org/2001/04/xmldsig-more#rsa-sha384", null); rsaSha512 = fac.newSignatureMethod ("http://www.w3.org/2001/04/xmldsig-more#rsa-sha512", null); + ecdsaSha1 = fac.newSignatureMethod + ("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1", null); sks = new KeySelectors.SecretKeySelector("secret".getBytes("ASCII")); httpUd = new HttpURIDereferencer(); @@ -342,6 +356,13 @@ System.out.println(); } + static void test_create_signature_enveloping_p256_sha1() throws Exception { + System.out.println("* Generating signature-enveloping-p256-sha1.xml"); + test_create_signature_enveloping(sha1, ecdsaSha1, p256ki, + getECPrivateKey(), kvks, false); + System.out.println(); + } + static void test_create_signature_external_b64_dsa() throws Exception { System.out.println("* Generating signature-external-b64-dsa.xml"); test_create_signature_external(dsaSha1, dsa1024, signingKey, kvks, true); @@ -1168,7 +1189,42 @@ "237008997971129772408397621801631622129297063463868593083106979716" + "204903524890556839550490384015324575598723478554854070823335021842" + "210112348400928769"; + private static final String EC_X = + "335863644451761614592446380116804721648611739647823420286081723541" + + "6166183710"; + private static final String EC_Y = + "951559601159729477487064127150143688502130342917782252098602422796" + + "95457910701"; + private static final String EC_S = + "425976209773168452211813225517384419928639977904006759709292218082" + + "7440083936"; + private static final ECParameterSpec EC_PARAMS; + static { + final String ec_sfield, ec_a, ec_b, ec_gx, ec_gy, ec_n; + ec_sfield = + "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"; + ec_a = + "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC"; + ec_b = + "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"; + ec_gx = + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"; + ec_gy = + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"; + ec_n = + "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"; + final int ec_h = 1; + final ECField ec_field = new ECFieldFp(bigInt(ec_sfield)); + final EllipticCurve ec_curve = new EllipticCurve(ec_field, + bigInt(ec_a), bigInt(ec_b)); + final ECPoint ec_g = new ECPoint(bigInt(ec_gx), bigInt(ec_gy)); + EC_PARAMS = new ECParameterSpec(ec_curve, ec_g, bigInt(ec_n), ec_h); + } + + private static BigInteger bigInt(String s) { + return new BigInteger(s, 16); + } private static PublicKey getPublicKey(String algo, int keysize) throws Exception { KeyFactory kf = KeyFactory.getInstance(algo); @@ -1197,6 +1253,14 @@ return kf.generatePublic(kspec); } + private static PublicKey getECPublicKey() throws Exception { + KeyFactory kf = KeyFactory.getInstance("EC"); + KeySpec kspec = new ECPublicKeySpec(new ECPoint(new BigInteger(EC_X), + new BigInteger(EC_Y)), + EC_PARAMS); + return kf.generatePublic(kspec); + } + private static PrivateKey getPrivateKey(String algo, int keysize) throws Exception { KeyFactory kf = KeyFactory.getInstance(algo); @@ -1223,6 +1287,12 @@ return kf.generatePrivate(kspec); } + private static PrivateKey getECPrivateKey() throws Exception { + KeyFactory kf = KeyFactory.getInstance("EC"); + KeySpec kspec = new ECPrivateKeySpec(new BigInteger(EC_S), EC_PARAMS); + return kf.generatePrivate(kspec); + } + private static SecretKey getSecretKey(final byte[] secret) { return new SecretKey() { public String getFormat() { return "RAW"; } diff -r ddfb652c7496 -r 5fdc6e6c0b97 jdk/test/javax/xml/crypto/dsig/KeySelectors.java --- a/jdk/test/javax/xml/crypto/dsig/KeySelectors.java Fri Jan 09 16:54:17 2015 +0100 +++ b/jdk/test/javax/xml/crypto/dsig/KeySelectors.java Fri Jan 09 11:58:34 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -166,7 +166,6 @@ throw new KeySelectorException("No KeyValue element found!"); } - //@@@FIXME: this should also work for key types other than DSA/RSA static boolean algEquals(String algURI, String algName) { if (algName.equalsIgnoreCase("DSA") && algURI.equals(SignatureMethod.DSA_SHA1) || @@ -181,6 +180,10 @@ algURI.equals ("http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"))) { return true; + } else if (algName.equalsIgnoreCase("EC") && + (algURI.equals + ("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1"))) { + return true; } else { return false; } diff -r ddfb652c7496 -r 5fdc6e6c0b97 jdk/test/javax/xml/crypto/dsig/ValidationTests.java --- a/jdk/test/javax/xml/crypto/dsig/ValidationTests.java Fri Jan 09 16:54:17 2015 +0100 +++ b/jdk/test/javax/xml/crypto/dsig/ValidationTests.java Fri Jan 09 11:58:34 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /** * @test - * @bug 4635230 6365103 6366054 6824440 7131084 + * @bug 4635230 6365103 6366054 6824440 7131084 8046724 * @summary Basic unit tests for validating XML Signatures with JSR 105 * @compile -XDignore.symbol.file KeySelectors.java SignatureValidator.java * X509KeySelector.java ValidationTests.java @@ -90,6 +90,7 @@ new Test("signature-enveloping-b64-dsa.xml", KVKS), new Test("signature-enveloping-dsa.xml", KVKS), new Test("signature-enveloping-rsa.xml", KVKS), + new Test("signature-enveloping-p256-sha1.xml", KVKS), new Test("signature-enveloping-hmac-sha1.xml", SKKS), new Test("signature-external-dsa.xml", KVKS), new Test("signature-external-b64-dsa.xml", KVKS), diff -r ddfb652c7496 -r 5fdc6e6c0b97 jdk/test/javax/xml/crypto/dsig/data/signature-enveloping-p256-sha1.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/xml/crypto/dsig/data/signature-enveloping-p256-sha1.xml Fri Jan 09 11:58:34 2015 -0800 @@ -0,0 +1,3 @@ +7/XTsHaBSOnJ/jXD5v0zL6VKYsk=WiF/Hd0s7BiH36Ds/1iJcbKiXOUVBSGFteuTjXwBbezR43NAwpMmMX5c1su0A9hG9rVVzE/1DOlO +vuDVLBBblg==BAds672US3sCYunM2k2bEQLbuRxdQlNTvq+5fitOpDMe0mBdZV4J3yZaG0taziYIuAT9GJGfds+q +xtXOCNWe/60=some text \ No newline at end of file