You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@santuario.apache.org by mu...@apache.org on 2015/12/22 21:21:34 UTC

svn commit: r1721459 - in /santuario/xml-security-java/trunk/src: main/java/org/apache/jcp/xml/dsig/internal/dom/DOMKeyValue.java test/java/javax/xml/crypto/test/dsig/PKSignatureAlgorithmTest.java

Author: mullan
Date: Tue Dec 22 20:21:34 2015
New Revision: 1721459

URL: http://svn.apache.org/viewvc?rev=1721459&view=rev
Log:
Remove dependencies on internal JDK APIs for parsing EC KeyValue elements. Restrict support to standard 256, 384, and 512 bit curves.

Modified:
    santuario/xml-security-java/trunk/src/main/java/org/apache/jcp/xml/dsig/internal/dom/DOMKeyValue.java
    santuario/xml-security-java/trunk/src/test/java/javax/xml/crypto/test/dsig/PKSignatureAlgorithmTest.java

Modified: santuario/xml-security-java/trunk/src/main/java/org/apache/jcp/xml/dsig/internal/dom/DOMKeyValue.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/jcp/xml/dsig/internal/dom/DOMKeyValue.java?rev=1721459&r1=1721458&r2=1721459&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/jcp/xml/dsig/internal/dom/DOMKeyValue.java (original)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/jcp/xml/dsig/internal/dom/DOMKeyValue.java Tue Dec 22 20:21:34 2015
@@ -28,36 +28,31 @@ import javax.xml.crypto.*;
 import javax.xml.crypto.dsig.*;
 import javax.xml.crypto.dsig.keyinfo.KeyValue;
 
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
+import java.io.IOException;
 import java.math.BigInteger;
-import java.security.AccessController;
-import java.security.AlgorithmParameters;
 import java.security.KeyException;
 import java.security.KeyFactory;
-import java.security.GeneralSecurityException;
 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.ECGenParameterSpec;
 import java.security.spec.ECPoint;
 import java.security.spec.ECPublicKeySpec;
 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.Element;
 import org.apache.xml.security.exceptions.Base64DecodingException;
 import org.apache.xml.security.utils.Base64;
-import org.apache.xml.security.utils.ClassLoaderUtils;
 
 /**
  * DOM-based implementation of KeyValue.
@@ -317,59 +312,146 @@ public abstract class DOMKeyValue<K exte
 
     static final class EC extends DOMKeyValue<ECPublicKey> {
 
-        private static final String VER = System.getProperty("java.version");
-        private static final boolean AT_LEAST_18 = !VER.startsWith("1.5") &&
-            !VER.startsWith("1.6") && !VER.startsWith("1.7");
         // ECKeyValue CryptoBinaries
         private byte[] ecPublicKey;
         private KeyFactory eckf;
         private ECParameterSpec ecParams;
-        private Method encodePoint, decodePoint;
+
+        /* Supported curve, secp256r1 */
+        private static final Curve SECP256R1 = initializeCurve(
+            "secp256r1 [NIST P-256, X9.62 prime256v1]",
+            "1.2.840.10045.3.1.7",
+            "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
+            "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
+            "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
+            "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
+            "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
+            "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
+            1
+        );
+
+        /* Supported curve secp384r1 */
+        private static final Curve SECP384R1 = initializeCurve(
+            "secp384r1 [NIST P-384]",
+            "1.3.132.0.34",
+            "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
+            "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC",
+            "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
+            "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
+            "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F",
+            "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
+            1
+        );
+
+        /* Supported curve secp521r1 */
+        private static final Curve SECP521R1 = initializeCurve(
+            "secp521r1 [NIST P-521]",
+            "1.3.132.0.35",
+            "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
+            "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC",
+            "0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
+            "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66",
+            "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650",
+            "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
+            1
+        );
+
+        private static Curve initializeCurve(String name, String oid,
+                String sfield, String a, String b,
+                String x, String y, String n, int h) {
+            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));
+            return new Curve(name, oid, curve, g, bigInt(n), h);
+        }
 
         EC(ECPublicKey ecKey) throws KeyException {
             super(ecKey);
             ECPoint ecPoint = ecKey.getW();
             ecParams = ecKey.getParams();
-            try {
-                AccessController.doPrivileged(
-                    new PrivilegedExceptionAction<Void>() {
-                        @Override
-                        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 {
-            String className = AT_LEAST_18
-                ? "sun.security.util.ECUtil"
-                : "sun.security.ec.ECParameters";
-            Class<?> c = ClassLoaderUtils.loadClass(className, DOMKeyValue.class);
-            Class<?>[] params = new Class<?>[] { ECPoint.class, EllipticCurve.class };
-            encodePoint = c.getMethod("encodePoint", params);
-            params = new Class[] { ECParameterSpec.class };
-            params = new Class[] { byte[].class, EllipticCurve.class };
-            decodePoint = c.getMethod("decodePoint", 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 one of the supported
+            // curves. If there is a match, return the object identifier
+            // of the curve.
+            Curve match;
+            if (matchCurve(params, SECP256R1)) {
+                match = SECP256R1;
+            } else if (matchCurve(params, SECP384R1)) {
+                match = SECP384R1;
+            } else if (matchCurve(params, SECP521R1)) {
+                match = SECP521R1;
+            } else {
+                return null;
+            }
+            return match.getObjectId();
+        }
+
+        private static boolean matchCurve(ECParameterSpec params, Curve curve) {
+            int fieldSize = params.getCurve().getField().getFieldSize();
+            if (curve.getCurve().getField().getFieldSize() == fieldSize
+                && curve.getCurve().equals(params.getCurve())
+                && curve.getGenerator().equals(params.getGenerator())
+                && curve.getOrder().equals(params.getOrder())
+                && curve.getCofactor() == params.getCofactor()) {
+                return true;
+            } else {
+                return false;
+            }
         }
 
         @Override
@@ -382,12 +464,11 @@ public abstract class DOMKeyValue<K exte
 
             xwriter.writeStartElement(prefix, "NamedCurve", XMLDSIG_11_XMLNS);
             xwriter.writeNamespace(prefix, XMLDSIG_11_XMLNS);
-            try {
-                String oid = getCurveName(ecParams);
-                xwriter.writeAttribute("", "", "URI", "urn:oid:" + oid);
-            } catch (GeneralSecurityException gse) {
-                throw new MarshalException(gse);
+            String oid = getCurveOid(ecParams);
+            if (oid == null) {
+                throw new MarshalException("Invalid ECParameterSpec");
             }
+            xwriter.writeAttribute("", "", "URI", "urn:oid:" + oid);
             xwriter.writeEndElement();
 
             xwriter.writeStartElement(prefix, "PublicKey", XMLDSIG_11_XMLNS);
@@ -397,19 +478,6 @@ public abstract class DOMKeyValue<K exte
             xwriter.writeEndElement(); // "ECKeyValue"
         }
 
-        private static String getCurveName(ECParameterSpec spec)
-            throws GeneralSecurityException
-        {
-            AlgorithmParameters ap = AlgorithmParameters.getInstance("EC");
-            ap.init(spec);
-            ECGenParameterSpec nameSpec =
-                ap.getParameterSpec(ECGenParameterSpec.class);
-            if (nameSpec == null) {
-                return null;
-            }
-            return nameSpec.getName();
-        }
-
         @Override
         ECPublicKey unmarshalKeyValue(Element kvtElem)
             throws MarshalException
@@ -422,23 +490,7 @@ public abstract class DOMKeyValue<K exte
                         ("unable to create EC KeyFactory: " + e.getMessage());
                 }
             }
-            try {
-                AccessController.doPrivileged(
-                    new PrivilegedExceptionAction<Void>() {
-                        @Override
-                        public Void run() throws
-                            ClassNotFoundException, NoSuchMethodException
-                        {
-                            getMethods();
-                            return null;
-                        }
-                    }
-                );
-            } catch (PrivilegedActionException pae) {
-                throw new MarshalException("ECKeyValue not supported",
-                                           pae.getException());
-            }
-            ECParameterSpec ellipticParams = null;
+            ECParameterSpec ecParams = null;
             Element curElem = DOMUtils.getFirstChildElement(kvtElem);
             if (curElem == null) {
                 throw new MarshalException("KeyValue must contain at least one type");
@@ -454,10 +506,9 @@ public abstract class DOMKeyValue<K exte
                 // strip off "urn:oid"
                 if (uri.startsWith("urn:oid:")) {
                     String oid = uri.substring("urn:oid:".length());
-                    try {
-                        ellipticParams = getECParameterSpec(oid);
-                    } catch (GeneralSecurityException gse) {
-                        throw new MarshalException(gse);
+                    ecParams = getECParameterSpec(oid);
+                    if (ecParams == null) {
+                        throw new MarshalException("Invalid curve OID");
                     }
                 } else {
                     throw new MarshalException("Invalid NamedCurve URI");
@@ -467,32 +518,55 @@ public abstract class DOMKeyValue<K exte
             }
             curElem = DOMUtils.getNextSiblingElement(curElem, "PublicKey", XMLDSIG_11_XMLNS);
             ECPoint ecPoint = null;
+
             try {
-                Object[] args = new Object[] { Base64.decode(curElem),
-                                               ellipticParams.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);
-            }
-/*
-                ecPoint = sun.security.ec.ECParameters.decodePoint(
-                    Base64.decode(curElem), ellipticParams.getCurve());
-*/
-            ECPublicKeySpec spec = new ECPublicKeySpec(ecPoint, ellipticParams);
+            } catch (IOException ioe) {
+                throw new MarshalException("Invalid EC Point", ioe);
+            }
+
+            ECPublicKeySpec spec = new ECPublicKeySpec(ecPoint, ecParams);
             return (ECPublicKey) generatePublicKey(eckf, spec);
         }
 
-        private static ECParameterSpec getECParameterSpec(String name)
-            throws GeneralSecurityException
-        {
-            AlgorithmParameters ap = AlgorithmParameters.getInstance("EC");
-            ap.init(new ECGenParameterSpec(name));
-            return ap.getParameterSpec(ECParameterSpec.class);
+        private static ECParameterSpec getECParameterSpec(String oid) {
+            if (oid.equals(SECP256R1.getObjectId())) {
+                return SECP256R1;
+            } else if (oid.equals(SECP384R1.getObjectId())) {
+                return SECP384R1;
+            } else if (oid.equals(SECP521R1.getObjectId())) {
+                return SECP521R1;
+            } else {
+                return null;
+            }
         }
+
+        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<PublicKey> {

Modified: santuario/xml-security-java/trunk/src/test/java/javax/xml/crypto/test/dsig/PKSignatureAlgorithmTest.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/test/java/javax/xml/crypto/test/dsig/PKSignatureAlgorithmTest.java?rev=1721459&r1=1721458&r2=1721459&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/test/java/javax/xml/crypto/test/dsig/PKSignatureAlgorithmTest.java (original)
+++ santuario/xml-security-java/trunk/src/test/java/javax/xml/crypto/test/dsig/PKSignatureAlgorithmTest.java Tue Dec 22 20:21:34 2015
@@ -137,7 +137,9 @@ public class PKSignatureAlgorithmTest ex
         rsaKpg.initialize(2048);
         rsaKeyPair = rsaKpg.genKeyPair();
 
-        ecKeyPair = KeyPairGenerator.getInstance("EC").genKeyPair();
+        KeyPairGenerator ecKpg = KeyPairGenerator.getInstance("EC");
+        ecKpg.initialize(256);
+        ecKeyPair = ecKpg.genKeyPair();
 
         KeyInfoFactory kifac = fac.getKeyInfoFactory();
         rsaki = kifac.newKeyInfo(Collections.singletonList