--- a/jdk/src/windows/classes/sun/security/mscapi/RSASignature.java Fri Apr 22 17:03:51 2011 +0100
+++ b/jdk/src/windows/classes/sun/security/mscapi/RSASignature.java Wed Apr 27 20:21:32 2011 +0100
@@ -50,6 +50,9 @@
* following algorithm names:
*
* . "SHA1withRSA"
+ * . "SHA256withRSA"
+ * . "SHA384withRSA"
+ * . "SHA512withRSA"
* . "MD5withRSA"
* . "MD2withRSA"
*
@@ -63,7 +66,10 @@
// message digest implementation we use
private final MessageDigest messageDigest;
- // flag indicating whether the digest is reset
+ // message digest name
+ private final String messageDigestAlgorithm;
+
+ // flag indicating whether the digest has been reset
private boolean needsReset;
// the signing key
@@ -73,10 +79,15 @@
private Key publicKey = null;
+ /**
+ * Constructs a new RSASignature. Used by subclasses.
+ */
RSASignature(String digestName) {
try {
messageDigest = MessageDigest.getInstance(digestName);
+ // Get the digest's canonical name
+ messageDigestAlgorithm = messageDigest.getAlgorithm();
} catch (NoSuchAlgorithmException e) {
throw new ProviderException(e);
@@ -91,6 +102,24 @@
}
}
+ public static final class SHA256 extends RSASignature {
+ public SHA256() {
+ super("SHA-256");
+ }
+ }
+
+ public static final class SHA384 extends RSASignature {
+ public SHA384() {
+ super("SHA-384");
+ }
+ }
+
+ public static final class SHA512 extends RSASignature {
+ public SHA512() {
+ super("SHA-512");
+ }
+ }
+
public static final class MD5 extends RSASignature {
public MD5() {
super("MD5");
@@ -103,16 +132,7 @@
}
}
- /**
- * Initializes this signature object with the specified
- * public key for verification operations.
- *
- * @param publicKey the public key of the identity whose signature is
- * going to be verified.
- *
- * @exception InvalidKeyException if the key is improperly
- * encoded, parameters are missing, and so on.
- */
+ // initialize for signing. See JCA doc
protected void engineInitVerify(PublicKey key)
throws InvalidKeyException
{
@@ -158,24 +178,12 @@
publicKey = (sun.security.mscapi.RSAPublicKey) key;
}
- if (needsReset) {
- messageDigest.reset();
- needsReset = false;
- }
+ this.privateKey = null;
+ resetDigest();
}
- /**
- * Initializes this signature object with the specified
- * private key for signing operations.
- *
- * @param privateKey the private key of the identity whose signature
- * will be generated.
- *
- * @exception InvalidKeyException if the key is improperly
- * encoded, parameters are missing, and so on.
- */
- protected void engineInitSign(PrivateKey key)
- throws InvalidKeyException
+ // initialize for signing. See JCA doc
+ protected void engineInitSign(PrivateKey key) throws InvalidKeyException
{
// This signature accepts only RSAPrivateKey
if ((key instanceof sun.security.mscapi.RSAPrivateKey) == false) {
@@ -189,12 +197,25 @@
null, RSAKeyPairGenerator.KEY_SIZE_MIN,
RSAKeyPairGenerator.KEY_SIZE_MAX);
+ this.publicKey = null;
+ resetDigest();
+ }
+
+ /**
+ * Resets the message digest if needed.
+ */
+ private void resetDigest() {
if (needsReset) {
messageDigest.reset();
needsReset = false;
}
}
+ private byte[] getDigestValue() {
+ needsReset = false;
+ return messageDigest.digest();
+ }
+
/**
* Updates the data to be signed or verified
* using the specified byte.
@@ -254,13 +275,12 @@
*/
protected byte[] engineSign() throws SignatureException {
- byte[] hash = messageDigest.digest();
- needsReset = false;
+ byte[] hash = getDigestValue();
// Sign hash using MS Crypto APIs
byte[] result = signHash(hash, hash.length,
- messageDigest.getAlgorithm(), privateKey.getHCryptProvider(),
+ messageDigestAlgorithm, privateKey.getHCryptProvider(),
privateKey.getHCryptKey());
// Convert signature array from little endian to big endian
@@ -314,11 +334,10 @@
protected boolean engineVerify(byte[] sigBytes)
throws SignatureException
{
- byte[] hash = messageDigest.digest();
- needsReset = false;
+ byte[] hash = getDigestValue();
return verifySignedHash(hash, hash.length,
- messageDigest.getAlgorithm(), convertEndianArray(sigBytes),
+ messageDigestAlgorithm, convertEndianArray(sigBytes),
sigBytes.length, publicKey.getHCryptProvider(),
publicKey.getHCryptKey());
}
--- a/jdk/src/windows/classes/sun/security/mscapi/SunMSCAPI.java Fri Apr 22 17:03:51 2011 +0100
+++ b/jdk/src/windows/classes/sun/security/mscapi/SunMSCAPI.java Wed Apr 27 20:21:32 2011 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2011, 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
@@ -81,6 +81,12 @@
*/
map.put("Signature.SHA1withRSA",
"sun.security.mscapi.RSASignature$SHA1");
+ map.put("Signature.SHA256withRSA",
+ "sun.security.mscapi.RSASignature$SHA256");
+ map.put("Signature.SHA384withRSA",
+ "sun.security.mscapi.RSASignature$SHA384");
+ map.put("Signature.SHA512withRSA",
+ "sun.security.mscapi.RSASignature$SHA512");
map.put("Signature.MD5withRSA",
"sun.security.mscapi.RSASignature$MD5");
map.put("Signature.MD2withRSA",
@@ -89,12 +95,16 @@
// supported key classes
map.put("Signature.SHA1withRSA SupportedKeyClasses",
"sun.security.mscapi.Key");
+ map.put("Signature.SHA256withRSA SupportedKeyClasses",
+ "sun.security.mscapi.Key");
+ map.put("Signature.SHA384withRSA SupportedKeyClasses",
+ "sun.security.mscapi.Key");
+ map.put("Signature.SHA512withRSA SupportedKeyClasses",
+ "sun.security.mscapi.Key");
map.put("Signature.MD5withRSA SupportedKeyClasses",
"sun.security.mscapi.Key");
map.put("Signature.MD2withRSA SupportedKeyClasses",
"sun.security.mscapi.Key");
- map.put("Signature.NONEwithRSA SupportedKeyClasses",
- "sun.security.mscapi.Key");
/*
* Key Pair Generator engines
--- a/jdk/src/windows/native/sun/security/mscapi/security.cpp Fri Apr 22 17:03:51 2011 +0100
+++ b/jdk/src/windows/native/sun/security/mscapi/security.cpp Wed Apr 27 20:21:32 2011 +0100
@@ -483,6 +483,7 @@
jbyte* pHashBuffer = NULL;
jbyte* pSignedHashBuffer = NULL;
jbyteArray jSignedHash = NULL;
+ HCRYPTPROV hCryptProvAlt = NULL;
__try
{
@@ -492,8 +493,32 @@
// Acquire a hash object handle.
if (::CryptCreateHash(HCRYPTPROV(hCryptProv), algId, 0, 0, &hHash) == FALSE)
{
- ThrowException(env, SIGNATURE_EXCEPTION, GetLastError());
- __leave;
+ // Failover to using the PROV_RSA_AES CSP
+
+ DWORD cbData = 256;
+ BYTE pbData[256];
+ pbData[0] = '\0';
+
+ // Get name of the key container
+ ::CryptGetProvParam((HCRYPTPROV)hCryptProv, PP_CONTAINER,
+ (BYTE *)pbData, &cbData, 0);
+
+ // Acquire an alternative CSP handle
+ if (::CryptAcquireContext(&hCryptProvAlt, LPCSTR(pbData), NULL,
+ PROV_RSA_AES, 0) == FALSE)
+ {
+
+ ThrowException(env, SIGNATURE_EXCEPTION, GetLastError());
+ __leave;
+ }
+
+ // Acquire a hash object handle.
+ if (::CryptCreateHash(HCRYPTPROV(hCryptProvAlt), algId, 0, 0,
+ &hHash) == FALSE)
+ {
+ ThrowException(env, SIGNATURE_EXCEPTION, GetLastError());
+ __leave;
+ }
}
// Copy hash from Java to native buffer
@@ -546,6 +571,9 @@
}
__finally
{
+ if (hCryptProvAlt)
+ ::CryptReleaseContext(hCryptProvAlt, 0);
+
if (pSignedHashBuffer)
delete [] pSignedHashBuffer;
@@ -574,6 +602,7 @@
jbyte* pSignedHashBuffer = NULL;
DWORD dwSignedHashBufferLen = jSignedHashSize;
jboolean result = JNI_FALSE;
+ HCRYPTPROV hCryptProvAlt = NULL;
__try
{
@@ -584,8 +613,32 @@
if (::CryptCreateHash(HCRYPTPROV(hCryptProv), algId, 0, 0, &hHash)
== FALSE)
{
- ThrowException(env, SIGNATURE_EXCEPTION, GetLastError());
- __leave;
+ // Failover to using the PROV_RSA_AES CSP
+
+ DWORD cbData = 256;
+ BYTE pbData[256];
+ pbData[0] = '\0';
+
+ // Get name of the key container
+ ::CryptGetProvParam((HCRYPTPROV)hCryptProv, PP_CONTAINER,
+ (BYTE *)pbData, &cbData, 0);
+
+ // Acquire an alternative CSP handle
+ if (::CryptAcquireContext(&hCryptProvAlt, LPCSTR(pbData), NULL,
+ PROV_RSA_AES, 0) == FALSE)
+ {
+
+ ThrowException(env, SIGNATURE_EXCEPTION, GetLastError());
+ __leave;
+ }
+
+ // Acquire a hash object handle.
+ if (::CryptCreateHash(HCRYPTPROV(hCryptProvAlt), algId, 0, 0,
+ &hHash) == FALSE)
+ {
+ ThrowException(env, SIGNATURE_EXCEPTION, GetLastError());
+ __leave;
+ }
}
// Copy hash and signedHash from Java to native buffer
@@ -616,6 +669,9 @@
__finally
{
+ if (hCryptProvAlt)
+ ::CryptReleaseContext(hCryptProvAlt, 0);
+
if (pSignedHashBuffer)
delete [] pSignedHashBuffer;
@@ -648,15 +704,27 @@
pszKeyContainerName = env->GetStringUTFChars(keyContainerName, NULL);
// Acquire a CSP context (create a new key container).
+ // Prefer a PROV_RSA_AES CSP, when available, due to its support
+ // for SHA-2-based signatures.
if (::CryptAcquireContext(
&hCryptProv,
pszKeyContainerName,
NULL,
- PROV_RSA_FULL,
+ PROV_RSA_AES,
CRYPT_NEWKEYSET) == FALSE)
{
- ThrowException(env, KEY_EXCEPTION, GetLastError());
- __leave;
+ // Failover to using the default CSP (PROV_RSA_FULL)
+
+ if (::CryptAcquireContext(
+ &hCryptProv,
+ pszKeyContainerName,
+ NULL,
+ PROV_RSA_FULL,
+ CRYPT_NEWKEYSET) == FALSE)
+ {
+ ThrowException(env, KEY_EXCEPTION, GetLastError());
+ __leave;
+ }
}
// Generate an RSA keypair
@@ -1849,15 +1917,27 @@
pbKeyBlob = (BYTE *) env->GetByteArrayElements(keyBlob, 0);
// Acquire a CSP context (create a new key container).
+ // Prefer a PROV_RSA_AES CSP, when available, due to its support
+ // for SHA-2-based signatures.
if (::CryptAcquireContext(
&hCryptProv,
NULL,
NULL,
- PROV_RSA_FULL,
+ PROV_RSA_AES,
CRYPT_VERIFYCONTEXT) == FALSE)
{
- ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
- __leave;
+ // Failover to using the default CSP (PROV_RSA_FULL)
+
+ if (::CryptAcquireContext(
+ &hCryptProv,
+ NULL,
+ NULL,
+ PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT) == FALSE)
+ {
+ ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
+ __leave;
+ }
}
// Import the public key
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/mscapi/SignUsingSHA2withRSA.java Wed Apr 27 20:21:32 2011 +0100
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2011, 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.
+ */
+
+/**
+ * @see SignUsingSHA2withRSA.sh
+ */
+
+import java.security.*;
+import java.util.*;
+
+public class SignUsingSHA2withRSA {
+
+ private static final byte[] toBeSigned = new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10
+ };
+
+ private static List<byte[]> generatedSignatures = new ArrayList<>();
+
+ public static void main(String[] args) throws Exception {
+
+ Provider[] providers = Security.getProviders("Signature.SHA256withRSA");
+ if (providers == null) {
+ System.out.println("No JCE providers support the " +
+ "'Signature.SHA256withRSA' algorithm");
+ System.out.println("Skipping this test...");
+ return;
+
+ } else {
+ System.out.println("The following JCE providers support the " +
+ "'Signature.SHA256withRSA' algorithm: ");
+ for (Provider provider : providers) {
+ System.out.println(" " + provider.getName());
+ }
+ }
+ System.out.println("-------------------------------------------------");
+
+ KeyStore ks = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
+ ks.load(null, null);
+ System.out.println("Loaded keystore: Windows-MY");
+
+ Enumeration e = ks.aliases();
+ PrivateKey privateKey = null;
+ PublicKey publicKey = null;
+
+ while (e.hasMoreElements()) {
+ String alias = (String) e.nextElement();
+ if (alias.equals("6753664")) {
+ System.out.println("Loaded entry: " + alias);
+ privateKey = (PrivateKey) ks.getKey(alias, null);
+ publicKey = (PublicKey) ks.getCertificate(alias).getPublicKey();
+ }
+ }
+ if (privateKey == null || publicKey == null) {
+ throw new Exception("Cannot load the keys need to run this test");
+ }
+ System.out.println("-------------------------------------------------");
+
+ generatedSignatures.add(signUsing("SHA256withRSA", privateKey));
+ generatedSignatures.add(signUsing("SHA384withRSA", privateKey));
+ generatedSignatures.add(signUsing("SHA512withRSA", privateKey));
+
+ System.out.println("-------------------------------------------------");
+
+ verifyUsing("SHA256withRSA", publicKey, generatedSignatures.get(0));
+ verifyUsing("SHA384withRSA", publicKey, generatedSignatures.get(1));
+ verifyUsing("SHA512withRSA", publicKey, generatedSignatures.get(2));
+
+ System.out.println("-------------------------------------------------");
+ }
+
+ private static byte[] signUsing(String signAlgorithm,
+ PrivateKey privateKey) throws Exception {
+
+ // Must explicitly specify the SunMSCAPI JCE provider
+ // (otherwise SunJCE is chosen because it appears earlier in the list)
+ Signature sig1 = Signature.getInstance(signAlgorithm, "SunMSCAPI");
+ if (sig1 == null) {
+ throw new Exception("'" + signAlgorithm + "' is not supported");
+ }
+ System.out.println("Using " + signAlgorithm + " signer from the " +
+ sig1.getProvider().getName() + " JCE provider");
+
+ System.out.println("Using key: " + privateKey);
+ sig1.initSign(privateKey);
+ sig1.update(toBeSigned);
+ byte [] sigBytes = null;
+
+ try {
+ sigBytes = sig1.sign();
+ System.out.println("Generated RSA signature over a " +
+ toBeSigned.length + "-byte data (signature length: " +
+ sigBytes.length * 8 + " bits)");
+ System.out.println(String.format("0x%0" +
+ (sigBytes.length * 2) + "x",
+ new java.math.BigInteger(1, sigBytes)));
+
+ } catch (SignatureException se) {
+ System.out.println("Error generating RSA signature: " + se);
+ }
+
+ return sigBytes;
+ }
+
+ private static void verifyUsing(String signAlgorithm, PublicKey publicKey,
+ byte[] signature) throws Exception {
+
+ // Must explicitly specify the SunMSCAPI JCE provider
+ // (otherwise SunJCE is chosen because it appears earlier in the list)
+ Signature sig1 = Signature.getInstance(signAlgorithm, "SunMSCAPI");
+ if (sig1 == null) {
+ throw new Exception("'" + signAlgorithm + "' is not supported");
+ }
+ System.out.println("Using " + signAlgorithm + " verifier from the "
+ + sig1.getProvider().getName() + " JCE provider");
+
+ System.out.println("Using key: " + publicKey);
+
+ System.out.println("\nVerifying RSA Signature over a " +
+ toBeSigned.length + "-byte data (signature length: " +
+ signature.length * 8 + " bits)");
+ System.out.println(String.format("0x%0" + (signature.length * 2) +
+ "x", new java.math.BigInteger(1, signature)));
+
+ sig1.initVerify(publicKey);
+ sig1.update(toBeSigned);
+
+ if (sig1.verify(signature)) {
+ System.out.println("Verify PASSED\n");
+ } else {
+ throw new Exception("Verify FAILED");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/mscapi/SignUsingSHA2withRSA.sh Wed Apr 27 20:21:32 2011 +0100
@@ -0,0 +1,83 @@
+#!/bin/sh
+
+#
+# Copyright (c) 2011, 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 6753664
+# @run shell SignUsingSHA2withRSA.sh
+# @summary Support SHA256 (and higher) in SunMSCAPI
+
+# set a few environment variables so that the shell-script can run stand-alone
+# in the source directory
+if [ "${TESTSRC}" = "" ] ; then
+ TESTSRC="."
+fi
+
+if [ "${TESTCLASSES}" = "" ] ; then
+ TESTCLASSES="."
+fi
+
+if [ "${TESTJAVA}" = "" ] ; then
+ echo "TESTJAVA not set. Test cannot execute."
+ echo "FAILED!!!"
+ exit 1
+fi
+
+OS=`uname -s`
+case "$OS" in
+ Windows* | CYGWIN* )
+
+ echo "Creating a temporary RSA keypair in the Windows-My store..."
+ ${TESTJAVA}/bin/keytool \
+ -genkeypair \
+ -storetype Windows-My \
+ -keyalg RSA \
+ -alias 6753664 \
+ -dname "cn=6753664,c=US" \
+ -noprompt
+
+ echo
+ echo "Running the test..."
+ ${TESTJAVA}/bin/javac -d . ${TESTSRC}\\SignUsingSHA2withRSA.java
+ ${TESTJAVA}/bin/java SignUsingSHA2withRSA
+
+ rc=$?
+
+ echo
+ echo "Removing the temporary RSA keypair from the Windows-My store..."
+ ${TESTJAVA}/bin/keytool \
+ -delete \
+ -storetype Windows-My \
+ -alias 6753664
+
+ echo done.
+ exit $rc
+ ;;
+
+ * )
+ echo "This test is not intended for '$OS' - passing test"
+ exit 0
+ ;;
+esac