Skip to content

Commit

Permalink
8237219: Disable native SunEC implementation by default
Browse files Browse the repository at this point in the history
Reviewed-by: weijun, mullan
  • Loading branch information
Anthony Scarpino committed Mar 25, 2020
1 parent b8f2b32 commit b0245c2
Show file tree
Hide file tree
Showing 16 changed files with 160 additions and 62 deletions.
1 change: 1 addition & 0 deletions src/java.base/share/classes/module-info.java
Expand Up @@ -284,6 +284,7 @@
exports sun.security.action to
java.desktop,
java.security.jgss,
jdk.crypto.ec,
jdk.incubator.foreign;
exports sun.security.internal.interfaces to
jdk.crypto.cryptoki;
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2020, 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
Expand Down Expand Up @@ -35,7 +35,9 @@
import javax.crypto.spec.*;

import sun.security.util.ArrayUtil;
import sun.security.util.CurveDB;
import sun.security.util.ECUtil;
import sun.security.util.NamedCurve;
import sun.security.util.math.*;
import sun.security.ec.point.*;

Expand Down Expand Up @@ -165,11 +167,24 @@ protected byte[] engineGenerateSecret() throws IllegalStateException {
if ((privateKey == null) || (publicKey == null)) {
throw new IllegalStateException("Not initialized correctly");
}

byte[] result;
Optional<byte[]> resultOpt = deriveKeyImpl(privateKey, publicKey);
byte[] result = resultOpt.orElseGet(
() -> deriveKeyNative(privateKey, publicKey)
);
if (resultOpt.isPresent()) {
result = resultOpt.get();
} else {
if (SunEC.isNativeDisabled()) {
NamedCurve privNC = CurveDB.lookup(privateKey.getParams());
NamedCurve pubNC = CurveDB.lookup(publicKey.getParams());
throw new IllegalStateException(
new InvalidAlgorithmParameterException("Legacy SunEC " +
"curve disabled, one or both keys: " +
"Private: " + ((privNC != null) ?
privNC.toString() : " unknown") +
", PublicKey:" + ((pubNC != null) ?
pubNC.toString() : " unknown")));
}
result = deriveKeyNative(privateKey, publicKey);
}
publicKey = null;
return result;
}
Expand Down
Expand Up @@ -463,6 +463,14 @@ protected byte[] engineSign() throws SignatureException {
if (sigOpt.isPresent()) {
sig = sigOpt.get();
} else {
if (SunEC.isNativeDisabled()) {
NamedCurve nc = CurveDB.lookup(privateKey.getParams());
throw new SignatureException(
new InvalidAlgorithmParameterException(
"Legacy SunEC curve disabled: " +
(nc != null ? nc.toString()
: "unknown")));
}
sig = signDigestNative(privateKey, digest, random);
}

Expand Down Expand Up @@ -491,6 +499,15 @@ protected boolean engineVerify(byte[] signature) throws SignatureException {
if (verifyOpt.isPresent()) {
return verifyOpt.get();
} else {
if (SunEC.isNativeDisabled()) {
NamedCurve nc = CurveDB.lookup(publicKey.getParams());
throw new SignatureException(
new InvalidAlgorithmParameterException(
"Legacy SunEC curve disabled: " +
(nc != null ? nc.toString()
: "unknown")));
}

byte[] w;
ECParameterSpec params = publicKey.getParams();
// DER OID
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2020, 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
Expand Down Expand Up @@ -33,7 +33,6 @@
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.InvalidParameterSpecException;
import java.security.spec.*;
import java.util.Optional;

import sun.security.jca.JCAUtil;
Expand Down Expand Up @@ -121,14 +120,29 @@ public void initialize(AlgorithmParameterSpec params, SecureRandom random)
private static void ensureCurveIsSupported(ECParameterSpec ecSpec)
throws InvalidAlgorithmParameterException {

// Check if ecSpec is a valid curve
AlgorithmParameters ecParams = ECUtil.getECParameters(null);
byte[] encodedParams;
try {
ecParams.init(ecSpec);
encodedParams = ecParams.getEncoded();
} catch (InvalidParameterSpecException ex) {
throw new InvalidAlgorithmParameterException(
"Unsupported curve: " + ecSpec.toString());
}

// Check if the java implementation supports this curve
if (ECOperations.forParameters(ecSpec).isPresent()) {
return;
}

// Check if the native library supported this curve, if available
if (SunEC.isNativeDisabled()) {
throw new InvalidAlgorithmParameterException(
"Unsupported curve: " + ecSpec.toString());
}

byte[] encodedParams;
try {
encodedParams = ecParams.getEncoded();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
Expand All @@ -151,6 +165,14 @@ public KeyPair generateKeyPair() {
if (kp.isPresent()) {
return kp.get();
}
} catch (Exception ex) {
throw new ProviderException(ex);
}
if (SunEC.isNativeDisabled()) {
throw new ProviderException("Legacy SunEC curve disabled: " +
params.toString());
}
try {
return generateKeyPairNative(random);
} catch (Exception ex) {
throw new ProviderException(ex);
Expand Down
77 changes: 50 additions & 27 deletions src/jdk.crypto.ec/share/classes/sun/security/ec/SunEC.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2020, 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
Expand All @@ -25,8 +25,17 @@

package sun.security.ec;

import java.util.*;
import java.security.*;
import java.security.AccessController;
import java.security.InvalidParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivilegedAction;
import java.security.Provider;
import java.security.ProviderException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Pattern;
import sun.security.util.CurveDB;
import sun.security.util.NamedCurve;
Expand All @@ -53,22 +62,36 @@ public final class SunEC extends Provider {

private static final long serialVersionUID = -2279741672933606418L;

// flag indicating whether the full EC implementation is present
// (when native library is absent then fewer EC algorithms are available)
private static boolean useFullImplementation = true;
// This flag is true if the native library is disabled or not loaded.
private static boolean disableNative = true;

static {
try {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
System.loadLibrary("sunec"); // check for native library
return null;
}
});
} catch (UnsatisfiedLinkError e) {
useFullImplementation = false;
String s = sun.security.action.GetPropertyAction.privilegedGetProperty(
"jdk.sunec.disableNative");
if (s != null && s.equalsIgnoreCase("false")) {
disableNative = false;
}

// If native is enabled, verify the library is available.
if (!disableNative) {
try {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
System.loadLibrary("sunec"); // check for native library
return null;
}
});
} catch (UnsatisfiedLinkError e) {
disableNative = true;
}
}
}

// Check if native library support is disabled.
static boolean isNativeDisabled() {
return SunEC.disableNative;
}

private static class ProviderService extends Provider.Service {

ProviderService(Provider p, String type, String algo, String cn) {
Expand Down Expand Up @@ -165,13 +188,13 @@ public SunEC() {
"Sun Elliptic Curve provider (EC, ECDSA, ECDH)");
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
putEntries(useFullImplementation);
putEntries();
return null;
}
});
}

void putEntries(boolean useFullImplementation) {
void putEntries() {
HashMap<String, String> ATTRS = new HashMap<>(3);
ATTRS.put("ImplementedIn", "Software");
String ecKeyClasses = "java.security.interfaces.ECPublicKey" +
Expand All @@ -194,8 +217,16 @@ void putEntries(boolean useFullImplementation) {
StringBuilder names = new StringBuilder();
Pattern nameSplitPattern = Pattern.compile(CurveDB.SPLIT_PATTERN);

Collection<? extends NamedCurve> supportedCurves =
CurveDB.getSupportedCurves();
Collection<? extends NamedCurve> supportedCurves;
if (SunEC.isNativeDisabled()) {
supportedCurves = Collections.unmodifiableList(List.of(
CurveDB.lookup("secp256r1"),
CurveDB.lookup("secp384r1"),
CurveDB.lookup("secp521r1")));
} else {
supportedCurves = CurveDB.getSupportedCurves();
}

for (NamedCurve namedCurve : supportedCurves) {
if (!firstCurve) {
names.append("|");
Expand Down Expand Up @@ -225,14 +256,6 @@ void putEntries(boolean useFullImplementation) {

putXDHEntries();

/*
* Register the algorithms below only when the full ECC implementation
* is available
*/
if (!useFullImplementation) {
return;
}

/*
* Signature engines
*/
Expand Down
20 changes: 18 additions & 2 deletions test/jdk/java/security/KeyAgreement/KeyAgreementTest.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020 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
Expand Down Expand Up @@ -31,6 +31,8 @@
* this test file was covered before with JDK-4936763.
* @run main/othervm -Djdk.crypto.KeyAgreement.legacyKDF=true KeyAgreementTest
* DiffieHellman DH SunJCE
* @run main/othervm -Djdk.sunec.disableNative=false KeyAgreementTest
* ECDHNative EC SunEC
* @run main KeyAgreementTest ECDH EC SunEC
* @run main KeyAgreementTest XDH XDH SunEC
*/
Expand All @@ -52,7 +54,12 @@ public static void main(String[] args) throws Exception {
String kaAlgo = args[0];
String kpgAlgo = args[1];
String provider = args[2];
System.out.println("Testing " + kaAlgo);
AlgoSpec aSpec = AlgoSpec.valueOf(AlgoSpec.class, kaAlgo);
// Switch kaAlgo to ECDH as it is used for algorithm names
if (kaAlgo.equals("ECDHNative")) {
kaAlgo = "ECDH";
}
List<AlgorithmParameterSpec> specs = aSpec.getAlgorithmParameterSpecs();
for (AlgorithmParameterSpec spec : specs) {
testKeyAgreement(provider, kaAlgo, kpgAlgo, spec);
Expand All @@ -69,7 +76,7 @@ private enum AlgoSpec {
// "java.base/share/classes/sun/security/util/CurveDB.java"
// and
// "jdk.crypto.ec/share/native/libsunec/impl/ecdecode.c"
ECDH(
ECDHNative(
// SEC2 prime curves
"secp112r1", "secp112r2", "secp128r1", "secp128r2", "secp160k1",
"secp160r1", "secp192k1", "secp192r1", "secp224k1", "secp224r1",
Expand All @@ -87,6 +94,7 @@ private enum AlgoSpec {
"X9.62 c2tnb239v1", "X9.62 c2tnb239v2", "X9.62 c2tnb239v3",
"X9.62 c2tnb359v1", "X9.62 c2tnb431r1"
),
ECDH("secp256r1", "secp384r1", "secp521r1"),
XDH("X25519", "X448", "x25519"),
// There is no curve for DiffieHellman
DiffieHellman(new String[]{});
Expand All @@ -97,6 +105,7 @@ private AlgoSpec(String... curves) {
// Generate AlgorithmParameterSpec for each KeyExchangeAlgorithm
for (String crv : curves) {
switch (this.name()) {
case "ECDHNative":
case "ECDH":
specs.add(new ECGenParameterSpec(crv));
break;
Expand Down Expand Up @@ -126,6 +135,13 @@ private static void testKeyAgreement(String provider, String kaAlgo,

KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgo, provider);
kpg.initialize(spec);
if (spec instanceof ECGenParameterSpec) {
System.out.println("Testing curve: " +
((ECGenParameterSpec)spec).getName());
} else if (spec instanceof NamedParameterSpec) {
System.out.println("Testing curve: " +
((NamedParameterSpec)spec).getName());
}
KeyPair kp1 = kpg.generateKeyPair();
KeyPair kp2 = kpg.generateKeyPair();

Expand Down
8 changes: 4 additions & 4 deletions test/jdk/java/security/KeyAgreement/KeySizeTest.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020, 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
Expand Down Expand Up @@ -37,9 +37,9 @@
* @run main KeySizeTest DiffieHellman SunJCE DiffieHellman 4096
* @run main KeySizeTest DiffieHellman SunJCE DiffieHellman 6144
* @run main KeySizeTest DiffieHellman SunJCE DiffieHellman 8192
* @run main KeySizeTest ECDH SunEC EC 128
* @run main KeySizeTest ECDH SunEC EC 192
* @run main KeySizeTest ECDH SunEC EC 256
* @run main/othervm -Djdk.sunec.disableNative=false KeySizeTest ECDH SunEC EC 128
* @run main/othervm -Djdk.sunec.disableNative=false KeySizeTest ECDH SunEC EC 192
* @run main/othervm KeySizeTest ECDH SunEC EC 256
* @run main KeySizeTest XDH SunEC XDH 255
* @run main KeySizeTest XDH SunEC XDH 448
*/
Expand Down
4 changes: 2 additions & 2 deletions test/jdk/jdk/security/jarsigner/Spec.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2020, 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
Expand Down Expand Up @@ -31,7 +31,7 @@
* jdk.jartool
* jdk.crypto.ec
* @build jdk.test.lib.util.JarUtils
* @run main Spec
* @run main/othervm -Djdk.sunec.disableNative=false Spec
*/

import com.sun.jarsigner.ContentSigner;
Expand Down
3 changes: 2 additions & 1 deletion test/jdk/sun/security/ec/ECDSAJavaVerify.java
Expand Up @@ -100,7 +100,8 @@ static void debug() throws Exception {
= launchingConnector.defaultArguments();
arguments.get("main").setValue(ECDSAJavaVerify.class.getName());
arguments.get("options").setValue(
"-cp " + System.getProperty("test.classes"));
"-cp " + System.getProperty("test.classes") +
" -Djdk.sunec.disableNative=false");
VirtualMachine vm = launchingConnector.launch(arguments);

MethodEntryRequest req = vm.eventRequestManager()
Expand Down

0 comments on commit b0245c2

Please sign in to comment.