diff src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp @ 51349:46492a773912

8205445: Add RSASSA-PSS Signature support to SunMSCAPI Reviewed-by: xuelei
author weijun
date Fri, 22 Jun 2018 21:42:00 +0800
parents f0aeede1b855
children c31b6e1c4383
line wrap: on
line diff
--- a/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp	Fri Jun 22 13:20:55 2018 +0200
+++ b/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp	Fri Jun 22 21:42:00 2018 +0800
@@ -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 @@
  */
 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 @@
    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 @@
         ::CryptReleaseContext((HCRYPTPROV) hCryptProv, NULL);
 }
 
-
 /*
  * Class:     sun_security_mscapi_RSASignature
  * Method:    signHash
@@ -693,6 +747,94 @@
 }
 
 /*
+ * 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
  * Signature: ([BIL/java/lang/String;[BIJJ)Z
@@ -798,6 +940,85 @@
 }
 
 /*
+ * 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
  * Signature: (ILjava/lang/String;)Lsun/security/mscapi/RSAKeyPair;