--- a/src/java.base/share/classes/sun/security/tools/keytool/Main.java Mon May 13 13:32:38 2019 -0700
+++ b/src/java.base/share/classes/sun/security/tools/keytool/Main.java Tue May 14 08:47:13 2019 +0800
@@ -3578,6 +3578,11 @@
{
Key key = null;
+ if (KeyStoreUtil.isWindowsKeyStore(storetype)) {
+ key = keyStore.getKey(alias, null);
+ return Pair.of(key, null);
+ }
+
if (keyStore.containsAlias(alias) == false) {
MessageFormat form = new MessageFormat
(rb.getString("Alias.alias.does.not.exist"));
--- a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPrivateKey.java Mon May 13 13:32:38 2019 -0700
+++ b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPrivateKey.java Tue May 14 08:47:13 2019 +0800
@@ -62,9 +62,13 @@
}
public String toString() {
- return algorithm + "PrivateKey [size=" + keyLength + " bits, type=" +
- getKeyType(handles.hCryptKey) + ", container=" +
- getContainerName(handles.hCryptProv) + "]";
+ if (handles.hCryptKey != 0) {
+ return algorithm + "PrivateKey [size=" + keyLength + " bits, type=" +
+ getKeyType(handles.hCryptKey) + ", container=" +
+ getContainerName(handles.hCryptProv) + "]";
+ } else {
+ return algorithm + "PrivateKey [size=" + keyLength + " bits, type=CNG]";
+ }
}
// This class is not serializable
--- a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPublicKey.java Mon May 13 13:32:38 2019 -0700
+++ b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPublicKey.java Tue May 14 08:47:13 2019 +0800
@@ -128,9 +128,14 @@
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(algorithm + "PublicKey [size=").append(keyLength)
- .append(" bits, type=").append(getKeyType(handles.hCryptKey))
- .append(", container=").append(getContainerName(handles.hCryptProv))
- .append("]\n modulus: ").append(getModulus())
+ .append(" bits, type=");
+ if (handles.hCryptKey != 0) {
+ sb.append(getKeyType(handles.hCryptKey))
+ .append(", container=").append(getContainerName(handles.hCryptProv));
+ } else {
+ sb.append("CNG");
+ }
+ sb.append("]\n modulus: ").append(getModulus())
.append("\n public exponent: ").append(getPublicExponent());
return sb.toString();
}
--- a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CSignature.java Mon May 13 13:32:38 2019 -0700
+++ b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CSignature.java Tue May 14 08:47:13 2019 +0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2019, 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
@@ -121,7 +121,8 @@
if ((key instanceof CPrivateKey) == false
|| !key.getAlgorithm().equalsIgnoreCase("RSA")) {
- throw new InvalidKeyException("Key type not supported");
+ throw new InvalidKeyException("Key type not supported: "
+ + key.getClass() + " " + key.getAlgorithm());
}
privateKey = (CPrivateKey) key;
@@ -201,16 +202,22 @@
byte[] hash = getDigestValue();
- // Omit the hash OID when generating a NONEwithRSA signature
- boolean noHashOID = this instanceof NONEwithRSA;
-
- // Sign hash using MS Crypto APIs
- byte[] result = signHash(noHashOID, hash, hash.length,
+ if (privateKey.getHCryptKey() == 0) {
+ return signCngHash(1, hash, hash.length,
+ 0,
+ this instanceof NONEwithRSA ? null : messageDigestAlgorithm,
+ privateKey.getHCryptProvider(), 0);
+ } else {
+ // Omit the hash OID when generating a NONEwithRSA signature
+ boolean noHashOID = this instanceof NONEwithRSA;
+ // Sign hash using MS Crypto APIs
+ byte[] result = signHash(noHashOID, hash, hash.length,
messageDigestAlgorithm, privateKey.getHCryptProvider(),
privateKey.getHCryptKey());
- // Convert signature array from little endian to big endian
- return convertEndianArray(result);
+ // Convert signature array from little endian to big endian
+ return convertEndianArray(result);
+ }
}
/**
@@ -230,10 +237,20 @@
throws SignatureException {
byte[] hash = getDigestValue();
- return verifySignedHash(hash, hash.length,
- messageDigestAlgorithm, convertEndianArray(sigBytes),
- sigBytes.length, publicKey.getHCryptProvider(),
- publicKey.getHCryptKey());
+ if (publicKey.getHCryptKey() == 0) {
+ return verifyCngSignedHash(
+ 1, hash, hash.length,
+ sigBytes, sigBytes.length,
+ 0,
+ messageDigestAlgorithm,
+ publicKey.getHCryptProvider(),
+ 0);
+ } else {
+ return verifySignedHash(hash, hash.length,
+ messageDigestAlgorithm, convertEndianArray(sigBytes),
+ sigBytes.length, publicKey.getHCryptProvider(),
+ publicKey.getHCryptKey());
+ }
}
/**
--- a/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp Mon May 13 13:32:38 2019 -0700
+++ b/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp Tue May 14 08:47:13 2019 +0800
@@ -649,19 +649,28 @@
if (::NCryptGetProperty(
hCryptProv, NCRYPT_ALGORITHM_PROPERTY,
(PBYTE)buffer, 32, &len, NCRYPT_SILENT_FLAG) == ERROR_SUCCESS) {
+ jstring name = env->NewStringUTF(pszNameString);
+ if (name == NULL) {
+ __leave;
+ }
if (buffer[0] == 'E' && buffer[2] == 'C'
&& (dwPublicKeyLength == 256
|| dwPublicKeyLength == 384
|| dwPublicKeyLength == 521)) {
- jstring name = env->NewStringUTF(pszNameString);
- if (name == NULL) {
- __leave;
- }
env->CallVoidMethod(obj, mGenKeyAndCertChain,
0,
name,
(jlong) hCryptProv, 0,
dwPublicKeyLength, jArrayList);
+ } else if (buffer[0] == 'R' && buffer[2] == 'S'
+ && buffer[4] == 'A') {
+ env->CallVoidMethod(obj, mGenKeyAndCertChain,
+ 1,
+ name,
+ (jlong) hCryptProv, 0,
+ dwPublicKeyLength, jArrayList);
+ } else {
+ dump("Unknown NCRYPT_ALGORITHM_PROPERTY", buffer, len);
}
}
}
@@ -890,11 +899,15 @@
break;
case 1:
BCRYPT_PKCS1_PADDING_INFO pkcs1Info;
- pkcs1Info.pszAlgId = MapHashIdentifier(env, jHashAlgorithm);
- if (pkcs1Info.pszAlgId == NULL) {
- ThrowExceptionWithMessage(env, SIGNATURE_EXCEPTION,
- "Unrecognised hash algorithm");
- __leave;
+ if (jHashAlgorithm) {
+ pkcs1Info.pszAlgId = MapHashIdentifier(env, jHashAlgorithm);
+ if (pkcs1Info.pszAlgId == NULL) {
+ ThrowExceptionWithMessage(env, SIGNATURE_EXCEPTION,
+ "Unrecognised hash algorithm");
+ __leave;
+ }
+ } else {
+ pkcs1Info.pszAlgId = NULL;
}
param = &pkcs1Info;
dwFlags = BCRYPT_PAD_PKCS1;
@@ -1121,11 +1134,15 @@
break;
case 1:
BCRYPT_PKCS1_PADDING_INFO pkcs1Info;
- pkcs1Info.pszAlgId = MapHashIdentifier(env, jHashAlgorithm);
- if (pkcs1Info.pszAlgId == NULL) {
- ThrowExceptionWithMessage(env, SIGNATURE_EXCEPTION,
- "Unrecognised hash algorithm");
- __leave;
+ if (jHashAlgorithm) {
+ pkcs1Info.pszAlgId = MapHashIdentifier(env, jHashAlgorithm);
+ if (pkcs1Info.pszAlgId == NULL) {
+ ThrowExceptionWithMessage(env, SIGNATURE_EXCEPTION,
+ "Unrecognised hash algorithm");
+ __leave;
+ }
+ } else {
+ pkcs1Info.pszAlgId = NULL;
}
param = &pkcs1Info;
dwFlags = NCRYPT_PAD_PKCS1_FLAG;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/sun/security/mscapi/VeryLongAlias.java Tue May 14 08:47:13 2019 +0800
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8223063
+ * @requires os.family == "windows"
+ * @library /test/lib
+ * @summary Support CNG RSA keys
+ */
+
+import jdk.test.lib.SecurityTools;
+import jdk.test.lib.process.ProcessTools;
+
+import java.io.File;
+import java.security.KeyStore;
+import java.security.MessageDigest;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.cert.X509Certificate;
+import java.util.List;
+import java.util.Random;
+
+public class VeryLongAlias {
+
+ static String alias = String.format("%0512d", new Random().nextInt(100000));
+
+ public static void main(String[] args) throws Throwable {
+
+ SecurityTools.keytool("-genkeypair -storetype pkcs12 -keystore ks"
+ + " -storepass changeit -keyalg RSA -dname CN=A -alias "
+ + alias);
+ String id = ((X509Certificate)KeyStore.getInstance(
+ new File("ks"), "changeit".toCharArray())
+ .getCertificate(alias)).getSerialNumber().toString(16);
+ try {
+ // Importing pkcs12 file. Long alias is only supported by CNG.
+ ProcessTools.executeCommand("certutil", "-v", "-p", "changeit",
+ "-csp", "Microsoft Software Key Storage Provider",
+ "-user", "-importpfx", "MY", "ks", "NoRoot,NoExport")
+ .shouldHaveExitValue(0);
+ test();
+ } finally {
+ ProcessTools.executeCommand("certutil", "-user", "-delstore", "MY",
+ id);
+ }
+ }
+
+ static void test() throws Exception {
+
+ char[] pass = "changeit".toCharArray();
+
+ KeyStore k1 = KeyStore.getInstance("Windows-MY");
+ k1.load(null, null);
+
+ KeyStore k2 = KeyStore.getInstance(new File("ks"), pass);
+
+ PrivateKey p1 = (PrivateKey)k1.getKey(alias, null);
+ PublicKey u1 = k1.getCertificate(alias).getPublicKey();
+
+ PrivateKey p2 = (PrivateKey)k2.getKey(alias, pass);
+ PublicKey u2 = k2.getCertificate(alias).getPublicKey();
+
+ System.out.println(p1.toString());
+ System.out.println(u1.toString());
+ if (!p1.toString().contains("type=CNG")) {
+ throw new Exception("Not a CNG key");
+ }
+
+ testSignature(p1, u1);
+ testSignature(p1, u2);
+ testSignature(p2, u1);
+ testSignature(p2, u2);
+ }
+
+ static void testSignature(PrivateKey p, PublicKey u) throws Exception {
+ byte[] data = "hello".getBytes();
+ for (String alg : List.of(
+ "NONEwithRSA", "SHA1withRSA",
+ "SHA256withRSA", "SHA512withRSA")) {
+ if (alg.contains("NONE")) {
+ data = MessageDigest.getInstance("SHA-256").digest(data);
+ }
+ Signature s1 = Signature.getInstance(alg);
+ Signature s2 = Signature.getInstance(alg);
+ s1.initSign(p);
+ s2.initVerify(u);
+ s1.update(data);
+ s2.update(data);
+ if (!s2.verify(s1.sign())) {
+ throw new Exception("Error");
+ }
+ }
+ }
+}