8046724: XML Signature ECKeyValue elements cannot be marshalled or unmarshalled

Reviewed-by: mullan
This commit is contained in:
Jason Uh 2015-01-09 11:58:34 -08:00
parent 6d1426d546
commit dfb7eea15e
5 changed files with 221 additions and 91 deletions
jdk
src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom
test/javax/xml/crypto/dsig

@ -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.dom.DOMCryptoContext;
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.EllipticCurve;
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 @@ public abstract class DOMKeyValue extends DOMStructure implements KeyValue {
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<Void>() {
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 @@ public abstract class DOMKeyValue extends DOMStructure implements KeyValue {
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 @@ public abstract class DOMKeyValue extends DOMStructure implements KeyValue {
("unable to create EC KeyFactory: " + e.getMessage());
}
}
try {
AccessController.doPrivileged(
new PrivilegedExceptionAction<Void>() {
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 @@ public abstract class DOMKeyValue extends DOMStructure implements KeyValue {
// 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 @@ public abstract class DOMKeyValue extends DOMStructure implements KeyValue {
}
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 {

@ -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.cert.X509CRL;
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 @@ public class GenerationTests {
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 @@ public class GenerationTests {
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 @@ public class GenerationTests {
(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 @@ public class GenerationTests {
("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 @@ public class GenerationTests {
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 @@ public class GenerationTests {
"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 @@ public class GenerationTests {
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 @@ public class GenerationTests {
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"; }

@ -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 @@ class KeySelectors {
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 @@ class KeySelectors {
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;
}

@ -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 @@ public class ValidationTests {
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),

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1"/><Reference URI="#object"><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>7/XTsHaBSOnJ/jXD5v0zL6VKYsk=</DigestValue></Reference></SignedInfo><SignatureValue>WiF/Hd0s7BiH36Ds/1iJcbKiXOUVBSGFteuTjXwBbezR43NAwpMmMX5c1su0A9hG9rVVzE/1DOlO
vuDVLBBblg==</SignatureValue><KeyInfo><KeyValue><ECKeyValue xmlns="http://www.w3.org/2009/xmldsig11#"><NamedCurve URI="urn:oid:1.2.840.10045.3.1.7"/><PublicKey>BAds672US3sCYunM2k2bEQLbuRxdQlNTvq+5fitOpDMe0mBdZV4J3yZaG0taziYIuAT9GJGfds+q
xtXOCNWe/60=</PublicKey></ECKeyValue></KeyValue></KeyInfo><Object Id="object">some text</Object></Signature>