8153438: Avoid repeated "Please insert a smart card" popup windows
authorigerasim
Fri, 19 Aug 2016 01:41:54 +0300
changeset 40414 1f4a9da41c1f
parent 40413 14b3d338ebe0
child 40415 256109602af0
8153438: Avoid repeated "Please insert a smart card" popup windows Reviewed-by: vinnie, valeriep
jdk/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp
--- a/jdk/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp	Thu Aug 18 17:51:40 2016 -0400
+++ b/jdk/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp	Fri Aug 19 01:41:54 2016 +0300
@@ -358,38 +358,50 @@
             BOOL bHasNoPrivateKey = FALSE;
             DWORD dwPublicKeyLength = 0;
 
-            if (::CryptAcquireCertificatePrivateKey(pCertContext, NULL, NULL,
-                                                    &hCryptProv, &dwKeySpec, &bCallerFreeProv) == FALSE)
+            // First, probe it silently
+            if (::CryptAcquireCertificatePrivateKey(pCertContext, CRYPT_ACQUIRE_SILENT_FLAG, NULL,
+                    &hCryptProv, &dwKeySpec, &bCallerFreeProv) == FALSE
+                && GetLastError() != NTE_SILENT_CONTEXT)
             {
                 bHasNoPrivateKey = TRUE;
-
-            } else {
-                // Private key is available
-
-                BOOL bGetUserKey = ::CryptGetUserKey(hCryptProv, dwKeySpec, &hUserKey);
-
-                // Skip certificate if cannot find private key
-                if (bGetUserKey == FALSE)
-                {
-                    if (bCallerFreeProv)
-                        ::CryptReleaseContext(hCryptProv, NULL);
-
-                    continue;
+            }
+            else
+            {
+                if (bCallerFreeProv == TRUE) {
+                    ::CryptReleaseContext(hCryptProv, NULL);
+                    bCallerFreeProv = FALSE;
                 }
 
-                // Set cipher mode to ECB
-                DWORD dwCipherMode = CRYPT_MODE_ECB;
-                ::CryptSetKeyParam(hUserKey, KP_MODE, (BYTE*)&dwCipherMode, NULL);
-
+                // Second, acquire the key normally (not silently)
+                if (::CryptAcquireCertificatePrivateKey(pCertContext, 0, NULL,
+                        &hCryptProv, &dwKeySpec, &bCallerFreeProv) == FALSE)
+                {
+                    bHasNoPrivateKey = TRUE;
+                }
+                else
+                {
+                    // Private key is available
+                    BOOL bGetUserKey = ::CryptGetUserKey(hCryptProv, dwKeySpec, &hUserKey);
 
-                // If the private key is present in smart card, we may not be able to
-                // determine the key length by using the private key handle. However,
-                // since public/private key pairs must have the same length, we could
-                // determine the key length of the private key by using the public key
-                // in the certificate.
-                dwPublicKeyLength = ::CertGetPublicKeyLength(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
-                        &(pCertContext->pCertInfo->SubjectPublicKeyInfo));
+                    // Skip certificate if cannot find private key
+                    if (bGetUserKey == FALSE) {
+                        if (bCallerFreeProv)
+                            ::CryptReleaseContext(hCryptProv, NULL);
+                        continue;
+                    }
 
+                    // Set cipher mode to ECB
+                    DWORD dwCipherMode = CRYPT_MODE_ECB;
+                    ::CryptSetKeyParam(hUserKey, KP_MODE, (BYTE*)&dwCipherMode, NULL);
+
+                    // If the private key is present in smart card, we may not be able to
+                    // determine the key length by using the private key handle. However,
+                    // since public/private key pairs must have the same length, we could
+                    // determine the key length of the private key by using the public key
+                    // in the certificate.
+                    dwPublicKeyLength = ::CertGetPublicKeyLength(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+                            &(pCertContext->pCertInfo->SubjectPublicKeyInfo));
+                }
             }
             PCCERT_CHAIN_CONTEXT pCertChainContext = NULL;
 
@@ -398,8 +410,7 @@
             //
             if (GetCertificateChain(OID_EKU_ANY, pCertContext, &pCertChainContext))
             {
-
-                for (unsigned int i=0; i < pCertChainContext->cChain; i++)
+                for (DWORD i = 0; i < pCertChainContext->cChain; i++)
                 {
                     // Found cert chain
                     PCERT_SIMPLE_CHAIN rgpChain =
@@ -449,6 +460,7 @@
                         // cert collection
                         env->CallVoidMethod(obj, mGenCert, byteArray, jArrayList);
                     }
+
                     if (bHasNoPrivateKey)
                     {
                         // Generate certificate chain and store into cert chain
@@ -1367,43 +1379,57 @@
     HCRYPTPROV hCryptProv = NULL;
     HCRYPTKEY hKey = NULL;
     DWORD dwKeySpec;
+    BOOL bCallerFreeProv = FALSE;
+    BOOL bRes;
 
     __try
     {
         if (usePrivateKey == JNI_TRUE) {
             // Locate the key container for the certificate's private key
-            if (!(::CryptAcquireCertificatePrivateKey(
-                (PCCERT_CONTEXT) pCertContext, 0, NULL, &hCryptProv,
-                &dwKeySpec, NULL))) {
+
+            // First, probe it silently
+            bRes = ::CryptAcquireCertificatePrivateKey(
+                    (PCCERT_CONTEXT) pCertContext, CRYPT_ACQUIRE_SILENT_FLAG,
+                    NULL, &hCryptProv, &dwKeySpec, &bCallerFreeProv);
 
+            if (bRes == FALSE && GetLastError() != NTE_SILENT_CONTEXT)
+            {
+                ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
+                __leave;
+            }
+
+            if (bCallerFreeProv == TRUE) {
+                ::CryptReleaseContext(hCryptProv, NULL);
+                bCallerFreeProv = FALSE;
+            }
+
+            // Now, do it normally (not silently)
+            if (::CryptAcquireCertificatePrivateKey(
+                    (PCCERT_CONTEXT) pCertContext, 0, NULL, &hCryptProv,
+                    &dwKeySpec, &bCallerFreeProv) == FALSE)
+            {
                 ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
                 __leave;
             }
 
             // Get a handle to the private key
-            if (!(::CryptGetUserKey(hCryptProv, dwKeySpec, &hKey))) {
+            if (::CryptGetUserKey(hCryptProv, dwKeySpec, &hKey) == FALSE) {
                 ThrowException(env, KEY_EXCEPTION, GetLastError());
                 __leave;
             }
-
-        } else { // use public key
+        }
+        else // use public key
+        {
+            bCallerFreeProv = TRUE;
 
             //  Acquire a CSP context.
-            if(::CryptAcquireContext(
-               &hCryptProv,
-               "J2SE",
-               NULL,
-               PROV_RSA_FULL,
-               0) == FALSE)
+            if (::CryptAcquireContext(&hCryptProv, "J2SE", NULL,
+                    PROV_RSA_FULL, 0) == FALSE)
             {
                 // If CSP context hasn't been created, create one.
                 //
-                if (::CryptAcquireContext(
-                    &hCryptProv,
-                    "J2SE",
-                    NULL,
-                    PROV_RSA_FULL,
-                    CRYPT_NEWKEYSET) == FALSE)
+                if (::CryptAcquireContext(&hCryptProv, "J2SE", NULL,
+                        PROV_RSA_FULL, CRYPT_NEWKEYSET) == FALSE)
                 {
                     ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
                     __leave;
@@ -1411,10 +1437,10 @@
             }
 
             // Import the certificate's public key into the key container
-            if (!(::CryptImportPublicKeyInfo(hCryptProv, X509_ASN_ENCODING,
-                &(((PCCERT_CONTEXT) pCertContext)->pCertInfo->SubjectPublicKeyInfo),
-                &hKey))) {
-
+            if (::CryptImportPublicKeyInfo(hCryptProv, X509_ASN_ENCODING,
+                    &(((PCCERT_CONTEXT) pCertContext)->pCertInfo->SubjectPublicKeyInfo),
+                    &hKey) == FALSE)
+            {
                 ThrowException(env, KEY_EXCEPTION, GetLastError());
                 __leave;
             }
@@ -1425,7 +1451,7 @@
         //--------------------------------------------------------------------
         // Clean up.
 
-        if (hCryptProv)
+        if (bCallerFreeProv == TRUE && hCryptProv != NULL)
             ::CryptReleaseContext(hCryptProv, 0);
     }