8205445: Add RSASSA-PSS Signature support to SunMSCAPI
Reviewed-by: xuelei
This commit is contained in:
parent
5f55147841
commit
578576f523
@ -35,7 +35,7 @@ ifeq ($(OPENJDK_TARGET_OS), windows)
|
||||
CFLAGS := $(CFLAGS_JDKLIB), \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) $(LDFLAGS_CXX_JDK) \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN), \
|
||||
LIBS := crypt32.lib advapi32.lib, \
|
||||
LIBS := crypt32.lib advapi32.lib ncrypt.lib, \
|
||||
))
|
||||
|
||||
TARGETS += $(BUILD_LIBSUNMSCAPI)
|
||||
|
@ -132,7 +132,7 @@ public class RSAPSSSignature extends SignatureSpi {
|
||||
}
|
||||
this.pubKey = (RSAPublicKey) isValid((RSAKey)publicKey);
|
||||
this.privKey = null;
|
||||
|
||||
resetDigest();
|
||||
}
|
||||
|
||||
// initialize for signing. See JCA doc
|
||||
@ -153,6 +153,7 @@ public class RSAPSSSignature extends SignatureSpi {
|
||||
this.pubKey = null;
|
||||
this.random =
|
||||
(random == null? JCAUtil.getSecureRandom() : random);
|
||||
resetDigest();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -29,6 +29,9 @@ import java.nio.ByteBuffer;
|
||||
import java.security.*;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.math.BigInteger;
|
||||
import java.security.spec.MGF1ParameterSpec;
|
||||
import java.security.spec.PSSParameterSpec;
|
||||
import java.util.Locale;
|
||||
|
||||
import sun.security.rsa.RSAKeyFactory;
|
||||
|
||||
@ -45,6 +48,7 @@ import sun.security.rsa.RSAKeyFactory;
|
||||
* . "SHA512withRSA"
|
||||
* . "MD5withRSA"
|
||||
* . "MD2withRSA"
|
||||
* . "RSASSA-PSS"
|
||||
*
|
||||
* NOTE: RSA keys must be at least 512 bits long.
|
||||
*
|
||||
@ -59,19 +63,19 @@ import sun.security.rsa.RSAKeyFactory;
|
||||
abstract class RSASignature extends java.security.SignatureSpi
|
||||
{
|
||||
// message digest implementation we use
|
||||
private final MessageDigest messageDigest;
|
||||
protected MessageDigest messageDigest;
|
||||
|
||||
// message digest name
|
||||
private String messageDigestAlgorithm;
|
||||
|
||||
// flag indicating whether the digest has been reset
|
||||
private boolean needsReset;
|
||||
protected boolean needsReset;
|
||||
|
||||
// the signing key
|
||||
private Key privateKey = null;
|
||||
protected Key privateKey = null;
|
||||
|
||||
// the verification key
|
||||
private Key publicKey = null;
|
||||
protected Key publicKey = null;
|
||||
|
||||
/**
|
||||
* Constructs a new RSASignature. Used by Raw subclass.
|
||||
@ -222,6 +226,254 @@ abstract class RSASignature extends java.security.SignatureSpi
|
||||
}
|
||||
}
|
||||
|
||||
public static final class PSS extends RSASignature {
|
||||
|
||||
private PSSParameterSpec pssParams = null;
|
||||
|
||||
// Workaround: Cannot import raw public key to CNG. This signature
|
||||
// will be used for verification if key is not from MSCAPI.
|
||||
private Signature fallbackSignature;
|
||||
|
||||
@Override
|
||||
protected void engineInitSign(PrivateKey key) throws InvalidKeyException {
|
||||
super.engineInitSign(key);
|
||||
fallbackSignature = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineInitVerify(PublicKey key) throws InvalidKeyException {
|
||||
// This signature accepts only RSAPublicKey
|
||||
if ((key instanceof java.security.interfaces.RSAPublicKey) == false) {
|
||||
throw new InvalidKeyException("Key type not supported");
|
||||
}
|
||||
|
||||
this.privateKey = null;
|
||||
|
||||
if (key instanceof sun.security.mscapi.RSAPublicKey) {
|
||||
fallbackSignature = null;
|
||||
publicKey = (sun.security.mscapi.RSAPublicKey) key;
|
||||
} else {
|
||||
if (fallbackSignature == null) {
|
||||
try {
|
||||
fallbackSignature = Signature.getInstance(
|
||||
"RSASSA-PSS", "SunRsaSign");
|
||||
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
|
||||
throw new InvalidKeyException("Invalid key", e);
|
||||
}
|
||||
}
|
||||
fallbackSignature.initVerify(key);
|
||||
if (pssParams != null) {
|
||||
try {
|
||||
fallbackSignature.setParameter(pssParams);
|
||||
} catch (InvalidAlgorithmParameterException e) {
|
||||
throw new InvalidKeyException("Invalid params", e);
|
||||
}
|
||||
}
|
||||
publicKey = null;
|
||||
}
|
||||
resetDigest();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineUpdate(byte b) throws SignatureException {
|
||||
ensureInit();
|
||||
if (fallbackSignature != null) {
|
||||
fallbackSignature.update(b);
|
||||
} else {
|
||||
messageDigest.update(b);
|
||||
}
|
||||
needsReset = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineUpdate(byte[] b, int off, int len) throws SignatureException {
|
||||
ensureInit();
|
||||
if (fallbackSignature != null) {
|
||||
fallbackSignature.update(b, off, len);
|
||||
} else {
|
||||
messageDigest.update(b, off, len);
|
||||
}
|
||||
needsReset = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineUpdate(ByteBuffer input) {
|
||||
try {
|
||||
ensureInit();
|
||||
} catch (SignatureException se) {
|
||||
// hack for working around API bug
|
||||
throw new RuntimeException(se.getMessage());
|
||||
}
|
||||
if (fallbackSignature != null) {
|
||||
try {
|
||||
fallbackSignature.update(input);
|
||||
} catch (SignatureException se) {
|
||||
// hack for working around API bug
|
||||
throw new RuntimeException(se.getMessage());
|
||||
}
|
||||
} else {
|
||||
messageDigest.update(input);
|
||||
}
|
||||
needsReset = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] engineSign() throws SignatureException {
|
||||
ensureInit();
|
||||
byte[] hash = getDigestValue();
|
||||
return signPssHash(hash, hash.length,
|
||||
pssParams.getSaltLength(),
|
||||
((MGF1ParameterSpec)
|
||||
pssParams.getMGFParameters()).getDigestAlgorithm(),
|
||||
privateKey.getHCryptProvider(), privateKey.getHCryptKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
|
||||
ensureInit();
|
||||
if (fallbackSignature != null) {
|
||||
needsReset = false;
|
||||
return fallbackSignature.verify(sigBytes);
|
||||
} else {
|
||||
byte[] hash = getDigestValue();
|
||||
return verifyPssSignedHash(
|
||||
hash, hash.length,
|
||||
sigBytes, sigBytes.length,
|
||||
pssParams.getSaltLength(),
|
||||
((MGF1ParameterSpec)
|
||||
pssParams.getMGFParameters()).getDigestAlgorithm(),
|
||||
publicKey.getHCryptProvider(),
|
||||
publicKey.getHCryptKey()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineSetParameter(AlgorithmParameterSpec params)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
if (needsReset) {
|
||||
throw new ProviderException
|
||||
("Cannot set parameters during operations");
|
||||
}
|
||||
this.pssParams = validateSigParams(params);
|
||||
if (fallbackSignature != null) {
|
||||
fallbackSignature.setParameter(params);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AlgorithmParameters engineGetParameters() {
|
||||
if (this.pssParams == null) {
|
||||
throw new ProviderException("Missing required PSS parameters");
|
||||
}
|
||||
try {
|
||||
AlgorithmParameters ap =
|
||||
AlgorithmParameters.getInstance("RSASSA-PSS");
|
||||
ap.init(this.pssParams);
|
||||
return ap;
|
||||
} catch (GeneralSecurityException gse) {
|
||||
throw new ProviderException(gse.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureInit() throws SignatureException {
|
||||
if (this.privateKey == null && this.publicKey == null
|
||||
&& fallbackSignature == null) {
|
||||
throw new SignatureException("Missing key");
|
||||
}
|
||||
if (this.pssParams == null) {
|
||||
// Parameters are required for signature verification
|
||||
throw new SignatureException
|
||||
("Parameters required for RSASSA-PSS signatures");
|
||||
}
|
||||
if (fallbackSignature == null && messageDigest == null) {
|
||||
// This could happen if initVerify(softKey), setParameter(),
|
||||
// and initSign() were called. No messageDigest. Create it.
|
||||
try {
|
||||
messageDigest = MessageDigest
|
||||
.getInstance(pssParams.getDigestAlgorithm());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new SignatureException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the specified Signature PSS parameters.
|
||||
*/
|
||||
private PSSParameterSpec validateSigParams(AlgorithmParameterSpec p)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
|
||||
if (p == null) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Parameters cannot be null");
|
||||
}
|
||||
|
||||
if (!(p instanceof PSSParameterSpec)) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("parameters must be type PSSParameterSpec");
|
||||
}
|
||||
|
||||
// no need to validate again if same as current signature parameters
|
||||
PSSParameterSpec params = (PSSParameterSpec) p;
|
||||
if (params == this.pssParams) return params;
|
||||
|
||||
// now sanity check the parameter values
|
||||
if (!(params.getMGFAlgorithm().equalsIgnoreCase("MGF1"))) {
|
||||
throw new InvalidAlgorithmParameterException("Only supports MGF1");
|
||||
|
||||
}
|
||||
|
||||
if (params.getTrailerField() != PSSParameterSpec.TRAILER_FIELD_BC) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Only supports TrailerFieldBC(1)");
|
||||
}
|
||||
|
||||
AlgorithmParameterSpec algSpec = params.getMGFParameters();
|
||||
if (!(algSpec instanceof MGF1ParameterSpec)) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Only support MGF1ParameterSpec");
|
||||
}
|
||||
|
||||
MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec)algSpec;
|
||||
|
||||
String msgHashAlg = params.getDigestAlgorithm()
|
||||
.toLowerCase(Locale.ROOT).replaceAll("-", "");
|
||||
if (msgHashAlg.equals("sha")) {
|
||||
msgHashAlg = "sha1";
|
||||
}
|
||||
String mgf1HashAlg = mgfSpec.getDigestAlgorithm()
|
||||
.toLowerCase(Locale.ROOT).replaceAll("-", "");
|
||||
if (mgf1HashAlg.equals("sha")) {
|
||||
mgf1HashAlg = "sha1";
|
||||
}
|
||||
|
||||
if (!mgf1HashAlg.equals(msgHashAlg)) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("MGF1 hash must be the same as message hash");
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign hash using CNG API with HCRYPTKEY. Used by RSASSA-PSS.
|
||||
*/
|
||||
private native static byte[] signPssHash(byte[] hash,
|
||||
int hashSize, int saltLength, String hashAlgorithm,
|
||||
long hCryptProv, long nCryptKey)
|
||||
throws SignatureException;
|
||||
|
||||
/**
|
||||
* Verify a signed hash using CNG API with HCRYPTKEY. Used by RSASSA-PSS.
|
||||
* This method is not used now. See {@link #fallbackSignature}.
|
||||
*/
|
||||
private native static boolean verifyPssSignedHash(byte[] hash, int hashSize,
|
||||
byte[] signature, int signatureSize,
|
||||
int saltLength, String hashAlgorithm,
|
||||
long hCryptProv, long hKey) throws SignatureException;
|
||||
}
|
||||
|
||||
// initialize for signing. See JCA doc
|
||||
@Override
|
||||
protected void engineInitVerify(PublicKey key)
|
||||
@ -298,7 +550,9 @@ abstract class RSASignature extends java.security.SignatureSpi
|
||||
*/
|
||||
protected void resetDigest() {
|
||||
if (needsReset) {
|
||||
messageDigest.reset();
|
||||
if (messageDigest != null) {
|
||||
messageDigest.reset();
|
||||
}
|
||||
needsReset = false;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2018, 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
|
||||
@ -105,6 +105,8 @@ public final class SunMSCAPI extends Provider {
|
||||
return new RSASignature.MD5();
|
||||
} else if (algo.equals("MD2withRSA")) {
|
||||
return new RSASignature.MD2();
|
||||
} else if (algo.equals("RSASSA-PSS")) {
|
||||
return new RSASignature.PSS();
|
||||
}
|
||||
} else if (type.equals("KeyPairGenerator")) {
|
||||
if (algo.equals("RSA")) {
|
||||
@ -177,6 +179,10 @@ public final class SunMSCAPI extends Provider {
|
||||
"SHA512withRSA", "sun.security.mscapi.RSASignature$SHA512",
|
||||
new String[] { "1.2.840.113549.1.1.13", "OID.1.2.840.113549.1.1.13" },
|
||||
attrs));
|
||||
putService(new ProviderService(p, "Signature",
|
||||
"RSASSA-PSS", "sun.security.mscapi.RSASignature$PSS",
|
||||
new String[] { "1.2.840.113549.1.1.10", "OID.1.2.840.113549.1.1.10" },
|
||||
attrs));
|
||||
putService(new ProviderService(p, "Signature",
|
||||
"MD5withRSA", "sun.security.mscapi.RSASignature$MD5",
|
||||
null, attrs));
|
||||
|
@ -57,6 +57,18 @@
|
||||
#define SIGNATURE_EXCEPTION "java/security/SignatureException"
|
||||
#define OUT_OF_MEMORY_ERROR "java/lang/OutOfMemoryError"
|
||||
|
||||
#define SS_CHECK(Status) \
|
||||
if (Status != ERROR_SUCCESS) { \
|
||||
ThrowException(env, SIGNATURE_EXCEPTION, Status); \
|
||||
__leave; \
|
||||
}
|
||||
|
||||
//#define PP(fmt, ...) \
|
||||
// fprintf(stdout, "SSPI (%ld): ", __LINE__); \
|
||||
// fprintf(stdout, fmt, ##__VA_ARGS__); \
|
||||
// fprintf(stdout, "\n"); \
|
||||
// fflush(stdout)
|
||||
|
||||
extern "C" {
|
||||
|
||||
/*
|
||||
@ -64,6 +76,18 @@ extern "C" {
|
||||
*/
|
||||
DEF_STATIC_JNI_OnLoad
|
||||
|
||||
//void dump(LPSTR title, PBYTE data, DWORD len)
|
||||
//{
|
||||
// printf("==== %s ====\n", title);
|
||||
// for (DWORD i = 0; i < len; i++) {
|
||||
// if (i != 0 && i % 16 == 0) {
|
||||
// printf("\n");
|
||||
// }
|
||||
// printf("%02X ", *(data + i) & 0xff);
|
||||
// }
|
||||
// printf("\n");
|
||||
//}
|
||||
|
||||
/*
|
||||
* Throws an arbitrary Java exception with the given message.
|
||||
*/
|
||||
@ -146,6 +170,37 @@ ALG_ID MapHashAlgorithm(JNIEnv *env, jstring jHashAlgorithm) {
|
||||
return algId;
|
||||
}
|
||||
|
||||
/*
|
||||
* Maps the name of a hash algorithm to a CNG Algorithm Identifier.
|
||||
*/
|
||||
LPCWSTR MapHashIdentifier(JNIEnv *env, jstring jHashAlgorithm) {
|
||||
|
||||
const char* pszHashAlgorithm = NULL;
|
||||
LPCWSTR id = NULL;
|
||||
|
||||
if ((pszHashAlgorithm = env->GetStringUTFChars(jHashAlgorithm, NULL))
|
||||
== NULL) {
|
||||
return id;
|
||||
}
|
||||
|
||||
if ((strcmp("SHA", pszHashAlgorithm) == 0) ||
|
||||
(strcmp("SHA1", pszHashAlgorithm) == 0) ||
|
||||
(strcmp("SHA-1", pszHashAlgorithm) == 0)) {
|
||||
|
||||
id = BCRYPT_SHA1_ALGORITHM;
|
||||
} else if (strcmp("SHA-256", pszHashAlgorithm) == 0) {
|
||||
id = BCRYPT_SHA256_ALGORITHM;
|
||||
} else if (strcmp("SHA-384", pszHashAlgorithm) == 0) {
|
||||
id = BCRYPT_SHA384_ALGORITHM;
|
||||
} else if (strcmp("SHA-512", pszHashAlgorithm) == 0) {
|
||||
id = BCRYPT_SHA512_ALGORITHM;
|
||||
}
|
||||
|
||||
if (pszHashAlgorithm)
|
||||
env->ReleaseStringUTFChars(jHashAlgorithm, pszHashAlgorithm);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a certificate chain context given a certificate context and key
|
||||
@ -561,7 +616,6 @@ JNIEXPORT void JNICALL Java_sun_security_mscapi_Key_cleanUp
|
||||
::CryptReleaseContext((HCRYPTPROV) hCryptProv, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Class: sun_security_mscapi_RSASignature
|
||||
* Method: signHash
|
||||
@ -692,6 +746,94 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_RSASignature_signHash
|
||||
return jSignedHash;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_security_mscapi_RSASignature_PSS
|
||||
* Method: signPssHash
|
||||
* Signature: ([BIILjava/lang/String;JJ)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_RSASignature_00024PSS_signPssHash
|
||||
(JNIEnv *env, jclass clazz, jbyteArray jHash,
|
||||
jint jHashSize, jint saltLen, jstring jHashAlgorithm, jlong hCryptProv,
|
||||
jlong hCryptKey)
|
||||
{
|
||||
jbyteArray jSignedHash = NULL;
|
||||
|
||||
jbyte* pHashBuffer = NULL;
|
||||
jbyte* pSignedHashBuffer = NULL;
|
||||
NCRYPT_KEY_HANDLE hk = NULL;
|
||||
|
||||
__try
|
||||
{
|
||||
SS_CHECK(::NCryptTranslateHandle(
|
||||
NULL,
|
||||
&hk,
|
||||
hCryptProv,
|
||||
hCryptKey,
|
||||
NULL,
|
||||
0));
|
||||
|
||||
// Copy hash from Java to native buffer
|
||||
pHashBuffer = new (env) jbyte[jHashSize];
|
||||
if (pHashBuffer == NULL) {
|
||||
__leave;
|
||||
}
|
||||
env->GetByteArrayRegion(jHash, 0, jHashSize, pHashBuffer);
|
||||
|
||||
BCRYPT_PSS_PADDING_INFO pssInfo;
|
||||
pssInfo.pszAlgId = MapHashIdentifier(env, jHashAlgorithm);
|
||||
pssInfo.cbSalt = saltLen;
|
||||
|
||||
if (pssInfo.pszAlgId == NULL) {
|
||||
ThrowExceptionWithMessage(env, SIGNATURE_EXCEPTION,
|
||||
"Unrecognised hash algorithm");
|
||||
__leave;
|
||||
}
|
||||
|
||||
DWORD dwBufLen = 0;
|
||||
SS_CHECK(::NCryptSignHash(
|
||||
hk,
|
||||
&pssInfo,
|
||||
(BYTE*)pHashBuffer, jHashSize,
|
||||
NULL, 0, &dwBufLen,
|
||||
BCRYPT_PAD_PSS
|
||||
));
|
||||
|
||||
pSignedHashBuffer = new (env) jbyte[dwBufLen];
|
||||
if (pSignedHashBuffer == NULL) {
|
||||
__leave;
|
||||
}
|
||||
|
||||
SS_CHECK(::NCryptSignHash(
|
||||
hk,
|
||||
&pssInfo,
|
||||
(BYTE*)pHashBuffer, jHashSize,
|
||||
(BYTE*)pSignedHashBuffer, dwBufLen, &dwBufLen,
|
||||
BCRYPT_PAD_PSS
|
||||
));
|
||||
|
||||
// Create new byte array
|
||||
jbyteArray temp = env->NewByteArray(dwBufLen);
|
||||
|
||||
// Copy data from native buffer
|
||||
env->SetByteArrayRegion(temp, 0, dwBufLen, pSignedHashBuffer);
|
||||
|
||||
jSignedHash = temp;
|
||||
}
|
||||
__finally
|
||||
{
|
||||
if (pSignedHashBuffer)
|
||||
delete [] pSignedHashBuffer;
|
||||
|
||||
if (pHashBuffer)
|
||||
delete [] pHashBuffer;
|
||||
|
||||
if (hk != NULL)
|
||||
::NCryptFreeObject(hk);
|
||||
}
|
||||
|
||||
return jSignedHash;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_security_mscapi_RSASignature
|
||||
* Method: verifySignedHash
|
||||
@ -797,6 +939,85 @@ JNIEXPORT jboolean JNICALL Java_sun_security_mscapi_RSASignature_verifySignedHas
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_security_mscapi_RSASignature_PSS
|
||||
* Method: verifyPssSignedHash
|
||||
* Signature: ([BI[BIILjava/lang/String;JJ)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_sun_security_mscapi_RSASignature_00024PSS_verifyPssSignedHash
|
||||
(JNIEnv *env, jclass clazz,
|
||||
jbyteArray jHash, jint jHashSize,
|
||||
jbyteArray jSignedHash, jint jSignedHashSize,
|
||||
jint saltLen, jstring jHashAlgorithm,
|
||||
jlong hCryptProv, jlong hKey)
|
||||
{
|
||||
jbyte* pHashBuffer = NULL;
|
||||
jbyte* pSignedHashBuffer = NULL;
|
||||
jboolean result = JNI_FALSE;
|
||||
NCRYPT_KEY_HANDLE hk = NULL;
|
||||
|
||||
__try
|
||||
{
|
||||
SS_CHECK(::NCryptTranslateHandle(
|
||||
NULL,
|
||||
&hk,
|
||||
hCryptProv,
|
||||
hKey,
|
||||
NULL,
|
||||
0));
|
||||
|
||||
// Copy hash and signedHash from Java to native buffer
|
||||
pHashBuffer = new (env) jbyte[jHashSize];
|
||||
if (pHashBuffer == NULL) {
|
||||
__leave;
|
||||
}
|
||||
env->GetByteArrayRegion(jHash, 0, jHashSize, pHashBuffer);
|
||||
|
||||
pSignedHashBuffer = new (env) jbyte[jSignedHashSize];
|
||||
if (pSignedHashBuffer == NULL) {
|
||||
__leave;
|
||||
}
|
||||
env->GetByteArrayRegion(jSignedHash, 0, jSignedHashSize,
|
||||
pSignedHashBuffer);
|
||||
|
||||
BCRYPT_PSS_PADDING_INFO pssInfo;
|
||||
pssInfo.pszAlgId = MapHashIdentifier(env, jHashAlgorithm);
|
||||
pssInfo.cbSalt = saltLen;
|
||||
|
||||
if (pssInfo.pszAlgId == NULL) {
|
||||
ThrowExceptionWithMessage(env, SIGNATURE_EXCEPTION,
|
||||
"Unrecognised hash algorithm");
|
||||
__leave;
|
||||
}
|
||||
|
||||
// For RSA, the hash encryption algorithm is normally the same as the
|
||||
// public key algorithm, so AT_SIGNATURE is used.
|
||||
|
||||
// Verify the signature
|
||||
if (::NCryptVerifySignature(hk, &pssInfo,
|
||||
(BYTE *) pHashBuffer, jHashSize,
|
||||
(BYTE *) pSignedHashBuffer, jSignedHashSize,
|
||||
NCRYPT_PAD_PSS_FLAG) == ERROR_SUCCESS)
|
||||
{
|
||||
result = JNI_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
__finally
|
||||
{
|
||||
if (pSignedHashBuffer)
|
||||
delete [] pSignedHashBuffer;
|
||||
|
||||
if (pHashBuffer)
|
||||
delete [] pHashBuffer;
|
||||
|
||||
if (hk != NULL)
|
||||
::NCryptFreeObject(hk);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_security_mscapi_RSAKeyPairGenerator
|
||||
* Method: generateRSAKeyPair
|
||||
|
171
test/jdk/sun/security/mscapi/InteropWithSunRsaSign.java
Normal file
171
test/jdk/sun/security/mscapi/InteropWithSunRsaSign.java
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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 8205445
|
||||
* @summary Interop test between SunMSCAPI and SunRsaSign on RSASSA-PSS
|
||||
* @requires os.family == "windows"
|
||||
*/
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.Signature;
|
||||
import java.security.spec.MGF1ParameterSpec;
|
||||
import java.security.spec.PSSParameterSpec;
|
||||
import java.util.Random;
|
||||
|
||||
public class InteropWithSunRsaSign {
|
||||
|
||||
private static final SecureRandom NOT_SECURE_RANDOM = new SecureRandom() {
|
||||
Random r = new Random();
|
||||
@Override
|
||||
public void nextBytes(byte[] bytes) {
|
||||
r.nextBytes(bytes);
|
||||
}
|
||||
};
|
||||
|
||||
private static boolean allResult = true;
|
||||
private static byte[] msg = "hello".getBytes();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
matrix(new PSSParameterSpec(
|
||||
"SHA-1",
|
||||
"MGF1",
|
||||
MGF1ParameterSpec.SHA1,
|
||||
20,
|
||||
PSSParameterSpec.TRAILER_FIELD_BC));
|
||||
|
||||
matrix(new PSSParameterSpec(
|
||||
"SHA-256",
|
||||
"MGF1",
|
||||
MGF1ParameterSpec.SHA256,
|
||||
32,
|
||||
PSSParameterSpec.TRAILER_FIELD_BC));
|
||||
|
||||
matrix(new PSSParameterSpec(
|
||||
"SHA-384",
|
||||
"MGF1",
|
||||
MGF1ParameterSpec.SHA384,
|
||||
48,
|
||||
PSSParameterSpec.TRAILER_FIELD_BC));
|
||||
|
||||
matrix(new PSSParameterSpec(
|
||||
"SHA-512",
|
||||
"MGF1",
|
||||
MGF1ParameterSpec.SHA512,
|
||||
64,
|
||||
PSSParameterSpec.TRAILER_FIELD_BC));
|
||||
|
||||
// non-typical salt length
|
||||
matrix(new PSSParameterSpec(
|
||||
"SHA-1",
|
||||
"MGF1",
|
||||
MGF1ParameterSpec.SHA1,
|
||||
17,
|
||||
PSSParameterSpec.TRAILER_FIELD_BC));
|
||||
|
||||
if (!allResult) {
|
||||
throw new Exception("Failed");
|
||||
}
|
||||
}
|
||||
|
||||
static void matrix(PSSParameterSpec pss) throws Exception {
|
||||
|
||||
System.out.printf("\n%10s%20s%20s%20s %s\n", pss.getDigestAlgorithm(),
|
||||
"KeyPairGenerator", "signer", "verifier", "result");
|
||||
System.out.printf("%10s%20s%20s%20s %s\n",
|
||||
"-------", "----------------", "------", "--------", "------");
|
||||
|
||||
// KeyPairGenerator chooses SPI when getInstance() is called.
|
||||
String[] provsForKPG = {"SunRsaSign", "SunMSCAPI"};
|
||||
|
||||
// "-" means no preferred provider. In this case, SPI is chosen
|
||||
// when initSign/initVerify is called. Worth testing.
|
||||
String[] provsForSignature = {"SunRsaSign", "SunMSCAPI", "-"};
|
||||
|
||||
int pos = 0;
|
||||
for (String pg : provsForKPG) {
|
||||
for (String ps : provsForSignature) {
|
||||
for (String pv : provsForSignature) {
|
||||
System.out.printf("%10d%20s%20s%20s ", ++pos, pg, ps, pv);
|
||||
try {
|
||||
boolean result = test(pg, ps, pv, pss);
|
||||
System.out.println(result);
|
||||
if (!result) {
|
||||
allResult = false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (pg.equals("-") || pg.equals(ps)) {
|
||||
// When Signature provider is automatically
|
||||
// chosen or the same with KeyPairGenerator,
|
||||
// this is an error.
|
||||
allResult = false;
|
||||
System.out.println("X " + e.getMessage());
|
||||
} else {
|
||||
// Known restriction: SunRsaSign and SunMSCAPI can't
|
||||
// use each other's private key for signing.
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static boolean test(String pg, String ps, String pv, PSSParameterSpec pss)
|
||||
throws Exception {
|
||||
|
||||
KeyPairGenerator kpg = pg.length() == 1
|
||||
? KeyPairGenerator.getInstance("RSA")
|
||||
:KeyPairGenerator.getInstance("RSA", pg);
|
||||
kpg.initialize(
|
||||
pss.getDigestAlgorithm().equals("SHA-512") ? 2048: 1024,
|
||||
NOT_SECURE_RANDOM);
|
||||
KeyPair kp = kpg.generateKeyPair();
|
||||
PrivateKey pr = kp.getPrivate();
|
||||
PublicKey pu = kp.getPublic();
|
||||
|
||||
Signature s = ps.length() == 1
|
||||
? Signature.getInstance("RSASSA-PSS")
|
||||
: Signature.getInstance("RSASSA-PSS", ps);
|
||||
s.initSign(pr);
|
||||
s.setParameter(pss);
|
||||
s.update(msg);
|
||||
byte[] sig = s.sign();
|
||||
|
||||
Signature s2 = pv.length() == 1
|
||||
? Signature.getInstance("RSASSA-PSS")
|
||||
: Signature.getInstance("RSASSA-PSS", pv);
|
||||
s2.initVerify(pu);
|
||||
s2.setParameter(pss);
|
||||
s2.update(msg);
|
||||
|
||||
return s2.verify(sig);
|
||||
}
|
||||
}
|
69
test/jdk/sun/security/rsa/pss/InitAgain.java
Normal file
69
test/jdk/sun/security/rsa/pss/InitAgain.java
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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.
|
||||
*/
|
||||
import java.security.*;
|
||||
import java.security.spec.*;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8205445
|
||||
* @summary Make sure old state is cleared when init is called again
|
||||
*/
|
||||
public class InitAgain {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
byte[] msg = "hello".getBytes();
|
||||
|
||||
Signature s1 = Signature.getInstance("RSASSA-PSS");
|
||||
Signature s2 = Signature.getInstance("RSASSA-PSS");
|
||||
|
||||
s1.setParameter(PSSParameterSpec.DEFAULT);
|
||||
s2.setParameter(PSSParameterSpec.DEFAULT);
|
||||
|
||||
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
|
||||
kpg.initialize(1024);
|
||||
KeyPair kp = kpg.generateKeyPair();
|
||||
|
||||
s1.initSign(kp.getPrivate());
|
||||
s1.update(msg);
|
||||
s1.initSign(kp.getPrivate());
|
||||
s1.update(msg);
|
||||
// Data digested in s1:
|
||||
// Before this fix, msg | msg
|
||||
// After this fix, msg
|
||||
|
||||
s2.initVerify(kp.getPublic());
|
||||
s2.update(msg);
|
||||
s2.initVerify(kp.getPublic());
|
||||
s2.update(msg);
|
||||
s2.initVerify(kp.getPublic());
|
||||
s2.update(msg);
|
||||
// Data digested in s2:
|
||||
// Before this fix, msg | msg | msg
|
||||
// After this fix, msg
|
||||
|
||||
if (!s2.verify(s1.sign())) {
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user