1 /*
   2  * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 //=--------------------------------------------------------------------------=
  27 // security.cpp    by Stanley Man-Kit Ho
  28 //=--------------------------------------------------------------------------=
  29 //
  30 
  31 #include <jni.h>
  32 #include "jni_util.h"
  33 #include <stdlib.h>
  34 #include <string.h>
  35 #include <windows.h>
  36 #include <BaseTsd.h>
  37 #include <wincrypt.h>
  38 #include <stdio.h>
  39 
  40 
  41 #define OID_EKU_ANY         "2.5.29.37.0"
  42 
  43 #define CERTIFICATE_PARSING_EXCEPTION \
  44                             "java/security/cert/CertificateParsingException"
  45 #define INVALID_KEY_EXCEPTION \
  46                             "java/security/InvalidKeyException"
  47 #define KEY_EXCEPTION       "java/security/KeyException"
  48 #define KEYSTORE_EXCEPTION  "java/security/KeyStoreException"
  49 #define PROVIDER_EXCEPTION  "java/security/ProviderException"
  50 #define SIGNATURE_EXCEPTION "java/security/SignatureException"
  51 
  52 extern "C" {
  53 
  54 /*
  55  * Declare library specific JNI_Onload entry if static build
  56  */
  57 DEF_STATIC_JNI_OnLoad
  58 
  59 /*
  60  * Throws an arbitrary Java exception.
  61  * The exception message is a Windows system error message.
  62  */
  63 void ThrowException(JNIEnv *env, char *exceptionName, DWORD dwError)
  64 {
  65     char szMessage[1024];
  66     szMessage[0] = '\0';
  67 
  68     DWORD res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
  69         NULL, szMessage, sizeof(szMessage), NULL);
  70     if (res == 0) {
  71         strcpy(szMessage, "Unknown error");
  72     }
  73 
  74     jclass exceptionClazz = env->FindClass(exceptionName);
  75     if (exceptionClazz != NULL) {
  76         env->ThrowNew(exceptionClazz, szMessage);
  77     }
  78 }
  79 
  80 
  81 /*
  82  * Maps the name of a hash algorithm to an algorithm identifier.
  83  */
  84 ALG_ID MapHashAlgorithm(JNIEnv *env, jstring jHashAlgorithm) {
  85 
  86     const char* pszHashAlgorithm = NULL;
  87     ALG_ID algId = 0;
  88 
  89     if ((pszHashAlgorithm = env->GetStringUTFChars(jHashAlgorithm, NULL))
  90         == NULL) {
  91         return algId;
  92     }
  93 
  94     if ((strcmp("SHA", pszHashAlgorithm) == 0) ||
  95         (strcmp("SHA1", pszHashAlgorithm) == 0) ||
  96         (strcmp("SHA-1", pszHashAlgorithm) == 0)) {
  97 
  98         algId = CALG_SHA1;
  99     } else if (strcmp("SHA1+MD5", pszHashAlgorithm) == 0) {
 100         algId = CALG_SSL3_SHAMD5; // a 36-byte concatenation of SHA-1 and MD5
 101     } else if (strcmp("SHA-256", pszHashAlgorithm) == 0) {
 102         algId = CALG_SHA_256;
 103     } else if (strcmp("SHA-384", pszHashAlgorithm) == 0) {
 104         algId = CALG_SHA_384;
 105     } else if (strcmp("SHA-512", pszHashAlgorithm) == 0) {
 106         algId = CALG_SHA_512;
 107     } else if (strcmp("MD5", pszHashAlgorithm) == 0) {
 108         algId = CALG_MD5;
 109     } else if (strcmp("MD2", pszHashAlgorithm) == 0) {
 110         algId = CALG_MD2;
 111     }
 112 
 113     if (pszHashAlgorithm)
 114         env->ReleaseStringUTFChars(jHashAlgorithm, pszHashAlgorithm);
 115 
 116    return algId;
 117 }
 118 
 119 
 120 /*
 121  * Returns a certificate chain context given a certificate context and key
 122  * usage identifier.
 123  */
 124 bool GetCertificateChain(LPSTR lpszKeyUsageIdentifier, PCCERT_CONTEXT pCertContext, PCCERT_CHAIN_CONTEXT* ppChainContext)
 125 {
 126     CERT_ENHKEY_USAGE        EnhkeyUsage;
 127     CERT_USAGE_MATCH         CertUsage;
 128     CERT_CHAIN_PARA          ChainPara;
 129     DWORD                    dwFlags = 0;
 130     LPSTR                    szUsageIdentifierArray[1];
 131 
 132     szUsageIdentifierArray[0] = lpszKeyUsageIdentifier;
 133     EnhkeyUsage.cUsageIdentifier = 1;
 134     EnhkeyUsage.rgpszUsageIdentifier = szUsageIdentifierArray;
 135     CertUsage.dwType = USAGE_MATCH_TYPE_AND;
 136     CertUsage.Usage  = EnhkeyUsage;
 137     ChainPara.cbSize = sizeof(CERT_CHAIN_PARA);
 138     ChainPara.RequestedUsage=CertUsage;
 139 
 140     // Build a chain using CertGetCertificateChain
 141     // and the certificate retrieved.
 142     return (::CertGetCertificateChain(NULL,     // use the default chain engine
 143                 pCertContext,   // pointer to the end certificate
 144                 NULL,           // use the default time
 145                 NULL,           // search no additional stores
 146                 &ChainPara,     // use AND logic and enhanced key usage
 147                                 //  as indicated in the ChainPara
 148                                 //  data structure
 149                 dwFlags,
 150                 NULL,           // currently reserved
 151                 ppChainContext) == TRUE);       // return a pointer to the chain created
 152 }
 153 
 154 
 155 /////////////////////////////////////////////////////////////////////////////
 156 //
 157 
 158 /*
 159  * Class:     sun_security_mscapi_PRNG
 160  * Method:    generateSeed
 161  * Signature: (I[B)[B
 162  */
 163 JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_PRNG_generateSeed
 164   (JNIEnv *env, jclass clazz, jint length, jbyteArray seed)
 165 {
 166 
 167     HCRYPTPROV hCryptProv = NULL;
 168     BYTE*      pbData = NULL;
 169     jbyte*     reseedBytes = NULL;
 170     jbyte*     seedBytes = NULL;
 171     jbyteArray result = NULL;
 172 
 173     __try
 174     {
 175         //  Acquire a CSP context.
 176         if(::CryptAcquireContext(
 177            &hCryptProv,
 178            NULL,
 179            NULL,
 180            PROV_RSA_FULL,
 181            CRYPT_VERIFYCONTEXT) == FALSE)
 182         {
 183             ThrowException(env, PROVIDER_EXCEPTION, GetLastError());
 184             __leave;
 185         }
 186 
 187         /*
 188          * If length is negative then use the supplied seed to re-seed the
 189          * generator and return null.
 190          * If length is non-zero then generate a new seed according to the
 191          * requested length and return the new seed.
 192          * If length is zero then overwrite the supplied seed with a new
 193          * seed of the same length and return the seed.
 194          */
 195         if (length < 0) {
 196             length = env->GetArrayLength(seed);
 197             if ((reseedBytes = env->GetByteArrayElements(seed, 0)) == NULL) {
 198                 __leave;
 199             }
 200 
 201             if (::CryptGenRandom(
 202                 hCryptProv,
 203                 length,
 204                 (BYTE *) reseedBytes) == FALSE) {
 205 
 206                 ThrowException(env, PROVIDER_EXCEPTION, GetLastError());
 207                 __leave;
 208             }
 209 
 210             result = NULL;
 211 
 212         } else if (length > 0) {
 213 
 214             pbData = new BYTE[length];
 215 
 216             if (::CryptGenRandom(
 217                 hCryptProv,
 218                 length,
 219                 pbData) == FALSE) {
 220 
 221                 ThrowException(env, PROVIDER_EXCEPTION, GetLastError());
 222                 __leave;
 223             }
 224 
 225             result = env->NewByteArray(length);
 226             env->SetByteArrayRegion(result, 0, length, (jbyte*) pbData);
 227 
 228         } else { // length == 0
 229 
 230             length = env->GetArrayLength(seed);
 231             if ((seedBytes = env->GetByteArrayElements(seed, 0)) == NULL) {
 232                 __leave;
 233             }
 234 
 235             if (::CryptGenRandom(
 236                 hCryptProv,
 237                 length,
 238                 (BYTE *) seedBytes) == FALSE) {
 239 
 240                 ThrowException(env, PROVIDER_EXCEPTION, GetLastError());
 241                 __leave;
 242             }
 243 
 244             result = seed; // seed will be updated when seedBytes gets released
 245         }
 246     }
 247     __finally
 248     {
 249         //--------------------------------------------------------------------
 250         // Clean up.
 251 
 252         if (reseedBytes)
 253             env->ReleaseByteArrayElements(seed, reseedBytes, JNI_ABORT);
 254 
 255         if (pbData)
 256             delete [] pbData;
 257 
 258         if (seedBytes)
 259             env->ReleaseByteArrayElements(seed, seedBytes, 0); // update orig
 260 
 261         if (hCryptProv)
 262             ::CryptReleaseContext(hCryptProv, 0);
 263     }
 264 
 265     return result;
 266 }
 267 
 268 
 269 /*
 270  * Class:     sun_security_mscapi_KeyStore
 271  * Method:    loadKeysOrCertificateChains
 272  * Signature: (Ljava/lang/String;Ljava/util/Collection;)V
 273  */
 274 JNIEXPORT void JNICALL Java_sun_security_mscapi_KeyStore_loadKeysOrCertificateChains
 275   (JNIEnv *env, jobject obj, jstring jCertStoreName)
 276 {
 277     /**
 278      * Certificate in cert store has enhanced key usage extension
 279      * property (or EKU property) that is not part of the certificate itself. To determine
 280      * if the certificate should be returned, both the enhanced key usage in certificate
 281      * extension block and the extension property stored along with the certificate in
 282      * certificate store should be examined. Otherwise, we won't be able to determine
 283      * the proper key usage from the Java side because the information is not stored as
 284      * part of the encoded certificate.
 285      */
 286 
 287     const char* pszCertStoreName = NULL;
 288     HCERTSTORE hCertStore = NULL;
 289     PCCERT_CONTEXT pCertContext = NULL;
 290     char* pszNameString = NULL; // certificate's friendly name
 291     DWORD cchNameString = 0;
 292 
 293 
 294     __try
 295     {
 296         // Open a system certificate store.
 297         if ((pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL))
 298             == NULL) {
 299             __leave;
 300         }
 301         if ((hCertStore = ::CertOpenSystemStore(NULL, pszCertStoreName))
 302             == NULL) {
 303 
 304             ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
 305             __leave;
 306         }
 307 
 308         // Determine clazz and method ID to generate certificate
 309         jclass clazzArrayList = env->FindClass("java/util/ArrayList");
 310         if (clazzArrayList == NULL) {
 311             __leave;
 312         }
 313 
 314         jmethodID mNewArrayList = env->GetMethodID(clazzArrayList, "<init>", "()V");
 315         if (mNewArrayList == NULL) {
 316             __leave;
 317         }
 318 
 319         jclass clazzOfThis = env->GetObjectClass(obj);
 320         if (clazzOfThis == NULL) {
 321             __leave;
 322         }
 323 
 324         jmethodID mGenCert = env->GetMethodID(clazzOfThis,
 325                                               "generateCertificate",
 326                                               "([BLjava/util/Collection;)V");
 327         if (mGenCert == NULL) {
 328             __leave;
 329         }
 330 
 331         // Determine method ID to generate certificate chain
 332         jmethodID mGenCertChain = env->GetMethodID(clazzOfThis,
 333                                                    "generateCertificateChain",
 334                                                    "(Ljava/lang/String;Ljava/util/Collection;)V");
 335         if (mGenCertChain == NULL) {
 336             __leave;
 337         }
 338 
 339         // Determine method ID to generate RSA certificate chain
 340         jmethodID mGenRSAKeyAndCertChain = env->GetMethodID(clazzOfThis,
 341                                                    "generateRSAKeyAndCertificateChain",
 342                                                    "(Ljava/lang/String;JJILjava/util/Collection;)V");
 343         if (mGenRSAKeyAndCertChain == NULL) {
 344             __leave;
 345         }
 346 
 347         // Use CertEnumCertificatesInStore to get the certificates
 348         // from the open store. pCertContext must be reset to
 349         // NULL to retrieve the first certificate in the store.
 350         while (pCertContext = ::CertEnumCertificatesInStore(hCertStore, pCertContext))
 351         {
 352             // Check if private key available - client authentication certificate
 353             // must have private key available.
 354             HCRYPTPROV hCryptProv = NULL;
 355             DWORD dwKeySpec = 0;
 356             HCRYPTKEY hUserKey = NULL;
 357             BOOL bCallerFreeProv = FALSE;
 358             BOOL bHasNoPrivateKey = FALSE;
 359             DWORD dwPublicKeyLength = 0;
 360 
 361             // First, probe it silently
 362             if (::CryptAcquireCertificatePrivateKey(pCertContext, CRYPT_ACQUIRE_SILENT_FLAG, NULL,
 363                     &hCryptProv, &dwKeySpec, &bCallerFreeProv) == FALSE
 364                 && GetLastError() != NTE_SILENT_CONTEXT)
 365             {
 366                 bHasNoPrivateKey = TRUE;
 367             }
 368             else
 369             {
 370                 if (bCallerFreeProv == TRUE) {
 371                     ::CryptReleaseContext(hCryptProv, NULL);
 372                     bCallerFreeProv = FALSE;
 373                 }
 374 
 375                 // Second, acquire the key normally (not silently)
 376                 if (::CryptAcquireCertificatePrivateKey(pCertContext, 0, NULL,
 377                         &hCryptProv, &dwKeySpec, &bCallerFreeProv) == FALSE)
 378                 {
 379                     bHasNoPrivateKey = TRUE;
 380                 }
 381                 else
 382                 {
 383                     // Private key is available
 384                     BOOL bGetUserKey = ::CryptGetUserKey(hCryptProv, dwKeySpec, &hUserKey);
 385 
 386                     // Skip certificate if cannot find private key
 387                     if (bGetUserKey == FALSE) {
 388                         if (bCallerFreeProv)
 389                             ::CryptReleaseContext(hCryptProv, NULL);
 390                         continue;
 391                     }
 392 
 393                     // Set cipher mode to ECB
 394                     DWORD dwCipherMode = CRYPT_MODE_ECB;
 395                     ::CryptSetKeyParam(hUserKey, KP_MODE, (BYTE*)&dwCipherMode, NULL);
 396 
 397                     // If the private key is present in smart card, we may not be able to
 398                     // determine the key length by using the private key handle. However,
 399                     // since public/private key pairs must have the same length, we could
 400                     // determine the key length of the private key by using the public key
 401                     // in the certificate.
 402                     dwPublicKeyLength = ::CertGetPublicKeyLength(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
 403                             &(pCertContext->pCertInfo->SubjectPublicKeyInfo));
 404                 }
 405             }
 406             PCCERT_CHAIN_CONTEXT pCertChainContext = NULL;
 407 
 408             // Build certificate chain by using system certificate store.
 409             // Add cert chain into collection for any key usage.
 410             //
 411             if (GetCertificateChain(OID_EKU_ANY, pCertContext, &pCertChainContext))
 412             {
 413                 for (DWORD i = 0; i < pCertChainContext->cChain; i++)
 414                 {
 415                     // Found cert chain
 416                     PCERT_SIMPLE_CHAIN rgpChain =
 417                         pCertChainContext->rgpChain[i];
 418 
 419                     // Create ArrayList to store certs in each chain
 420                     jobject jArrayList =
 421                         env->NewObject(clazzArrayList, mNewArrayList);
 422 
 423                     for (unsigned int j=0; j < rgpChain->cElement; j++)
 424                     {
 425                         PCERT_CHAIN_ELEMENT rgpElement =
 426                             rgpChain->rgpElement[j];
 427                         PCCERT_CONTEXT pc = rgpElement->pCertContext;
 428 
 429                         // Retrieve the friendly name of the first certificate
 430                         // in the chain
 431                         if (j == 0) {
 432 
 433                             // If the cert's name cannot be retrieved then
 434                             // pszNameString remains set to NULL.
 435                             // (An alias name will be generated automatically
 436                             // when storing this cert in the keystore.)
 437 
 438                             // Get length of friendly name
 439                             if ((cchNameString = CertGetNameString(pc,
 440                                 CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL,
 441                                 NULL, 0)) > 1) {
 442 
 443                                 // Found friendly name
 444                                 pszNameString = new char[cchNameString];
 445                                 CertGetNameString(pc,
 446                                     CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL,
 447                                     pszNameString, cchNameString);
 448                             }
 449                         }
 450 
 451                         BYTE* pbCertEncoded = pc->pbCertEncoded;
 452                         DWORD cbCertEncoded = pc->cbCertEncoded;
 453 
 454                         // Allocate and populate byte array
 455                         jbyteArray byteArray = env->NewByteArray(cbCertEncoded);
 456                         env->SetByteArrayRegion(byteArray, 0, cbCertEncoded,
 457                             (jbyte*) pbCertEncoded);
 458 
 459                         // Generate certificate from byte array and store into
 460                         // cert collection
 461                         env->CallVoidMethod(obj, mGenCert, byteArray, jArrayList);
 462                     }
 463 
 464                     if (bHasNoPrivateKey)
 465                     {
 466                         // Generate certificate chain and store into cert chain
 467                         // collection
 468                         env->CallVoidMethod(obj, mGenCertChain,
 469                             env->NewStringUTF(pszNameString),
 470                             jArrayList);
 471                     }
 472                     else
 473                     {
 474                         // Determine key type: RSA or DSA
 475                         DWORD dwData = CALG_RSA_KEYX;
 476                         DWORD dwSize = sizeof(DWORD);
 477                         ::CryptGetKeyParam(hUserKey, KP_ALGID, (BYTE*)&dwData,
 478                                 &dwSize, NULL);
 479 
 480                         if ((dwData & ALG_TYPE_RSA) == ALG_TYPE_RSA)
 481                         {
 482                             // Generate RSA certificate chain and store into cert
 483                             // chain collection
 484                             env->CallVoidMethod(obj, mGenRSAKeyAndCertChain,
 485                                     env->NewStringUTF(pszNameString),
 486                                     (jlong) hCryptProv, (jlong) hUserKey,
 487                                     dwPublicKeyLength, jArrayList);
 488                         }
 489                     }
 490                 }
 491 
 492                 // Free cert chain
 493                 if (pCertChainContext)
 494                     ::CertFreeCertificateChain(pCertChainContext);
 495             }
 496         }
 497     }
 498     __finally
 499     {
 500         if (hCertStore)
 501             ::CertCloseStore(hCertStore, 0);
 502 
 503         if (pszCertStoreName)
 504             env->ReleaseStringUTFChars(jCertStoreName, pszCertStoreName);
 505 
 506         if (pszNameString)
 507             delete [] pszNameString;
 508     }
 509 }
 510 
 511 
 512 /*
 513  * Class:     sun_security_mscapi_Key
 514  * Method:    cleanUp
 515  * Signature: (JJ)V
 516  */
 517 JNIEXPORT void JNICALL Java_sun_security_mscapi_Key_cleanUp
 518   (JNIEnv *env, jclass clazz, jlong hCryptProv, jlong hCryptKey)
 519 {
 520     if (hCryptKey != NULL)
 521         ::CryptDestroyKey((HCRYPTKEY) hCryptKey);
 522 
 523     if (hCryptProv != NULL)
 524         ::CryptReleaseContext((HCRYPTPROV) hCryptProv, NULL);
 525 }
 526 
 527 
 528 /*
 529  * Class:     sun_security_mscapi_RSASignature
 530  * Method:    signHash
 531  * Signature: (Z[BILjava/lang/String;JJ)[B
 532  */
 533 JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_RSASignature_signHash
 534   (JNIEnv *env, jclass clazz, jboolean noHashOID, jbyteArray jHash,
 535         jint jHashSize, jstring jHashAlgorithm, jlong hCryptProv,
 536         jlong hCryptKey)
 537 {
 538     HCRYPTHASH hHash = NULL;
 539     jbyte* pHashBuffer = NULL;
 540     jbyte* pSignedHashBuffer = NULL;
 541     jbyteArray jSignedHash = NULL;
 542     HCRYPTPROV hCryptProvAlt = NULL;
 543 
 544     __try
 545     {
 546         // Map hash algorithm
 547         ALG_ID algId = MapHashAlgorithm(env, jHashAlgorithm);
 548 
 549         // Acquire a hash object handle.
 550         if (::CryptCreateHash(HCRYPTPROV(hCryptProv), algId, 0, 0, &hHash) == FALSE)
 551         {
 552             // Failover to using the PROV_RSA_AES CSP
 553 
 554             DWORD cbData = 256;
 555             BYTE pbData[256];
 556             pbData[0] = '\0';
 557 
 558             // Get name of the key container
 559             ::CryptGetProvParam((HCRYPTPROV)hCryptProv, PP_CONTAINER,
 560                 (BYTE *)pbData, &cbData, 0);
 561 
 562             // Acquire an alternative CSP handle
 563             if (::CryptAcquireContext(&hCryptProvAlt, LPCSTR(pbData), NULL,
 564                 PROV_RSA_AES, 0) == FALSE)
 565             {
 566 
 567                 ThrowException(env, SIGNATURE_EXCEPTION, GetLastError());
 568                 __leave;
 569             }
 570 
 571             // Acquire a hash object handle.
 572             if (::CryptCreateHash(HCRYPTPROV(hCryptProvAlt), algId, 0, 0,
 573                 &hHash) == FALSE)
 574             {
 575                 ThrowException(env, SIGNATURE_EXCEPTION, GetLastError());
 576                 __leave;
 577             }
 578         }
 579 
 580         // Copy hash from Java to native buffer
 581         pHashBuffer = new jbyte[jHashSize];
 582         env->GetByteArrayRegion(jHash, 0, jHashSize, pHashBuffer);
 583 
 584         // Set hash value in the hash object
 585         if (::CryptSetHashParam(hHash, HP_HASHVAL, (BYTE*)pHashBuffer, NULL) == FALSE)
 586         {
 587             ThrowException(env, SIGNATURE_EXCEPTION, GetLastError());
 588             __leave;
 589         }
 590 
 591         // Determine key spec.
 592         DWORD dwKeySpec = AT_SIGNATURE;
 593         ALG_ID dwAlgId;
 594         DWORD dwAlgIdLen = sizeof(ALG_ID);
 595 
 596         if (! ::CryptGetKeyParam((HCRYPTKEY) hCryptKey, KP_ALGID, (BYTE*)&dwAlgId, &dwAlgIdLen, 0)) {
 597             ThrowException(env, SIGNATURE_EXCEPTION, GetLastError());
 598             __leave;
 599 
 600         }
 601         if (CALG_RSA_KEYX == dwAlgId) {
 602             dwKeySpec = AT_KEYEXCHANGE;
 603         }
 604 
 605         // Determine size of buffer
 606         DWORD dwBufLen = 0;
 607         DWORD dwFlags = 0;
 608 
 609         if (noHashOID == JNI_TRUE) {
 610             dwFlags = CRYPT_NOHASHOID; // omit hash OID in NONEwithRSA signature
 611         }
 612 
 613         if (::CryptSignHash(hHash, dwKeySpec, NULL, dwFlags, NULL, &dwBufLen) == FALSE)
 614         {
 615             ThrowException(env, SIGNATURE_EXCEPTION, GetLastError());
 616             __leave;
 617         }
 618 
 619         pSignedHashBuffer = new jbyte[dwBufLen];
 620         if (::CryptSignHash(hHash, dwKeySpec, NULL, dwFlags, (BYTE*)pSignedHashBuffer, &dwBufLen) == FALSE)
 621         {
 622             ThrowException(env, SIGNATURE_EXCEPTION, GetLastError());
 623             __leave;
 624         }
 625 
 626         // Create new byte array
 627         jbyteArray temp = env->NewByteArray(dwBufLen);
 628 
 629         // Copy data from native buffer
 630         env->SetByteArrayRegion(temp, 0, dwBufLen, pSignedHashBuffer);
 631 
 632         jSignedHash = temp;
 633     }
 634     __finally
 635     {
 636         if (pSignedHashBuffer)
 637             delete [] pSignedHashBuffer;
 638 
 639         if (pHashBuffer)
 640             delete [] pHashBuffer;
 641 
 642         if (hHash)
 643             ::CryptDestroyHash(hHash);
 644 
 645         if (hCryptProvAlt)
 646             ::CryptReleaseContext(hCryptProvAlt, 0);
 647     }
 648 
 649     return jSignedHash;
 650 }
 651 
 652 /*
 653  * Class:     sun_security_mscapi_RSASignature
 654  * Method:    verifySignedHash
 655  * Signature: ([BIL/java/lang/String;[BIJJ)Z
 656  */
 657 JNIEXPORT jboolean JNICALL Java_sun_security_mscapi_RSASignature_verifySignedHash
 658   (JNIEnv *env, jclass clazz, jbyteArray jHash, jint jHashSize,
 659         jstring jHashAlgorithm, jbyteArray jSignedHash, jint jSignedHashSize,
 660         jlong hCryptProv, jlong hCryptKey)
 661 {
 662     HCRYPTHASH hHash = NULL;
 663     jbyte* pHashBuffer = NULL;
 664     jbyte* pSignedHashBuffer = NULL;
 665     DWORD dwSignedHashBufferLen = jSignedHashSize;
 666     jboolean result = JNI_FALSE;
 667     HCRYPTPROV hCryptProvAlt = NULL;
 668 
 669     __try
 670     {
 671         // Map hash algorithm
 672         ALG_ID algId = MapHashAlgorithm(env, jHashAlgorithm);
 673 
 674         // Acquire a hash object handle.
 675         if (::CryptCreateHash(HCRYPTPROV(hCryptProv), algId, 0, 0, &hHash)
 676             == FALSE)
 677         {
 678             // Failover to using the PROV_RSA_AES CSP
 679 
 680             DWORD cbData = 256;
 681             BYTE pbData[256];
 682             pbData[0] = '\0';
 683 
 684             // Get name of the key container
 685             ::CryptGetProvParam((HCRYPTPROV)hCryptProv, PP_CONTAINER,
 686                 (BYTE *)pbData, &cbData, 0);
 687 
 688             // Acquire an alternative CSP handle
 689             if (::CryptAcquireContext(&hCryptProvAlt, LPCSTR(pbData), NULL,
 690                 PROV_RSA_AES, 0) == FALSE)
 691             {
 692 
 693                 ThrowException(env, SIGNATURE_EXCEPTION, GetLastError());
 694                 __leave;
 695             }
 696 
 697             // Acquire a hash object handle.
 698             if (::CryptCreateHash(HCRYPTPROV(hCryptProvAlt), algId, 0, 0,
 699                 &hHash) == FALSE)
 700             {
 701                 ThrowException(env, SIGNATURE_EXCEPTION, GetLastError());
 702                 __leave;
 703             }
 704         }
 705 
 706         // Copy hash and signedHash from Java to native buffer
 707         pHashBuffer = new jbyte[jHashSize];
 708         env->GetByteArrayRegion(jHash, 0, jHashSize, pHashBuffer);
 709         pSignedHashBuffer = new jbyte[jSignedHashSize];
 710         env->GetByteArrayRegion(jSignedHash, 0, jSignedHashSize,
 711             pSignedHashBuffer);
 712 
 713         // Set hash value in the hash object
 714         if (::CryptSetHashParam(hHash, HP_HASHVAL, (BYTE*) pHashBuffer, NULL)
 715             == FALSE)
 716         {
 717             ThrowException(env, SIGNATURE_EXCEPTION, GetLastError());
 718             __leave;
 719         }
 720 
 721         // For RSA, the hash encryption algorithm is normally the same as the
 722         // public key algorithm, so AT_SIGNATURE is used.
 723 
 724         // Verify the signature
 725         if (::CryptVerifySignatureA(hHash, (BYTE *) pSignedHashBuffer,
 726             dwSignedHashBufferLen, (HCRYPTKEY) hCryptKey, NULL, 0) == TRUE)
 727         {
 728             result = JNI_TRUE;
 729         }
 730     }
 731 
 732     __finally
 733     {
 734         if (pSignedHashBuffer)
 735             delete [] pSignedHashBuffer;
 736 
 737         if (pHashBuffer)
 738             delete [] pHashBuffer;
 739 
 740         if (hHash)
 741             ::CryptDestroyHash(hHash);
 742 
 743         if (hCryptProvAlt)
 744             ::CryptReleaseContext(hCryptProvAlt, 0);
 745     }
 746 
 747     return result;
 748 }
 749 
 750 /*
 751  * Class:     sun_security_mscapi_RSAKeyPairGenerator
 752  * Method:    generateRSAKeyPair
 753  * Signature: (ILjava/lang/String;)Lsun/security/mscapi/RSAKeyPair;
 754  */
 755 JNIEXPORT jobject JNICALL Java_sun_security_mscapi_RSAKeyPairGenerator_generateRSAKeyPair
 756   (JNIEnv *env, jclass clazz, jint keySize, jstring keyContainerName)
 757 {
 758     HCRYPTPROV hCryptProv = NULL;
 759     HCRYPTKEY hKeyPair;
 760     DWORD dwFlags = (keySize << 16) | CRYPT_EXPORTABLE;
 761     jobject keypair = NULL;
 762     const char* pszKeyContainerName = NULL; // UUID
 763 
 764     __try
 765     {
 766         if ((pszKeyContainerName =
 767             env->GetStringUTFChars(keyContainerName, NULL)) == NULL) {
 768             __leave;
 769         }
 770 
 771         // Acquire a CSP context (create a new key container).
 772         // Prefer a PROV_RSA_AES CSP, when available, due to its support
 773         // for SHA-2-based signatures.
 774         if (::CryptAcquireContext(
 775             &hCryptProv,
 776             pszKeyContainerName,
 777             NULL,
 778             PROV_RSA_AES,
 779             CRYPT_NEWKEYSET) == FALSE)
 780         {
 781             // Failover to using the default CSP (PROV_RSA_FULL)
 782 
 783             if (::CryptAcquireContext(
 784                 &hCryptProv,
 785                 pszKeyContainerName,
 786                 NULL,
 787                 PROV_RSA_FULL,
 788                 CRYPT_NEWKEYSET) == FALSE)
 789             {
 790                 ThrowException(env, KEY_EXCEPTION, GetLastError());
 791                 __leave;
 792             }
 793         }
 794 
 795         // Generate an RSA keypair
 796         if(::CryptGenKey(
 797            hCryptProv,
 798            AT_KEYEXCHANGE,
 799            dwFlags,
 800            &hKeyPair) == FALSE)
 801         {
 802             ThrowException(env, KEY_EXCEPTION, GetLastError());
 803             __leave;
 804         }
 805 
 806         // Get the method ID for the RSAKeyPair constructor
 807         jclass clazzRSAKeyPair =
 808             env->FindClass("sun/security/mscapi/RSAKeyPair");
 809         if (clazzRSAKeyPair == NULL) {
 810             __leave;
 811         }
 812 
 813         jmethodID mNewRSAKeyPair =
 814             env->GetMethodID(clazzRSAKeyPair, "<init>", "(JJI)V");
 815         if (mNewRSAKeyPair == NULL) {
 816             __leave;
 817         }
 818 
 819         // Create a new RSA keypair
 820         keypair = env->NewObject(clazzRSAKeyPair, mNewRSAKeyPair,
 821             (jlong) hCryptProv, (jlong) hKeyPair, keySize);
 822 
 823     }
 824     __finally
 825     {
 826         //--------------------------------------------------------------------
 827         // Clean up.
 828 
 829         if (pszKeyContainerName)
 830             env->ReleaseStringUTFChars(keyContainerName, pszKeyContainerName);
 831     }
 832 
 833     return keypair;
 834 }
 835 
 836 /*
 837  * Class:     sun_security_mscapi_Key
 838  * Method:    getContainerName
 839  * Signature: (J)Ljava/lang/String;
 840  */
 841 JNIEXPORT jstring JNICALL Java_sun_security_mscapi_Key_getContainerName
 842   (JNIEnv *env, jclass jclazz, jlong hCryptProv)
 843 {
 844     DWORD cbData = 256;
 845     BYTE pbData[256];
 846     pbData[0] = '\0';
 847 
 848     ::CryptGetProvParam(
 849         (HCRYPTPROV)hCryptProv,
 850         PP_CONTAINER,
 851         (BYTE *)pbData,
 852         &cbData,
 853         0);
 854 
 855     return env->NewStringUTF((const char*)pbData);
 856 }
 857 
 858 /*
 859  * Class:     sun_security_mscapi_Key
 860  * Method:    getKeyType
 861  * Signature: (J)Ljava/lang/String;
 862  */
 863 JNIEXPORT jstring JNICALL Java_sun_security_mscapi_Key_getKeyType
 864   (JNIEnv *env, jclass jclazz, jlong hCryptKey)
 865 {
 866     ALG_ID dwAlgId;
 867     DWORD dwAlgIdLen = sizeof(ALG_ID);
 868 
 869     if (::CryptGetKeyParam((HCRYPTKEY) hCryptKey, KP_ALGID, (BYTE*)&dwAlgId, &dwAlgIdLen, 0)) {
 870 
 871         if (CALG_RSA_SIGN == dwAlgId) {
 872             return env->NewStringUTF("Signature");
 873 
 874         } else if (CALG_RSA_KEYX == dwAlgId) {
 875             return env->NewStringUTF("Exchange");
 876 
 877         } else {
 878             char buffer[64];
 879             if (sprintf(buffer, "%lu", dwAlgId)) {
 880                 return env->NewStringUTF(buffer);
 881             }
 882         }
 883     }
 884 
 885     return env->NewStringUTF("<Unknown>");
 886 }
 887 
 888 /*
 889  * Class:     sun_security_mscapi_KeyStore
 890  * Method:    storeCertificate
 891  * Signature: (Ljava/lang/String;Ljava/lang/String;[BIJJ)V
 892  */
 893 JNIEXPORT void JNICALL Java_sun_security_mscapi_KeyStore_storeCertificate
 894   (JNIEnv *env, jobject obj, jstring jCertStoreName, jstring jCertAliasName,
 895         jbyteArray jCertEncoding, jint jCertEncodingSize, jlong hCryptProv,
 896         jlong hCryptKey)
 897 {
 898     const char* pszCertStoreName = NULL;
 899     HCERTSTORE hCertStore = NULL;
 900     PCCERT_CONTEXT pCertContext = NULL;
 901     PWCHAR pszCertAliasName = NULL;
 902     jbyte* pbCertEncoding = NULL;
 903     const jchar* jCertAliasChars = NULL;
 904     const char* pszContainerName = NULL;
 905     const char* pszProviderName = NULL;
 906     WCHAR * pwszContainerName = NULL;
 907     WCHAR * pwszProviderName = NULL;
 908 
 909     __try
 910     {
 911         // Open a system certificate store.
 912         if ((pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL))
 913             == NULL) {
 914             __leave;
 915         }
 916         if ((hCertStore = ::CertOpenSystemStore(NULL, pszCertStoreName)) == NULL) {
 917             ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
 918             __leave;
 919         }
 920 
 921         // Copy encoding from Java to native buffer
 922         pbCertEncoding = new jbyte[jCertEncodingSize];
 923         env->GetByteArrayRegion(jCertEncoding, 0, jCertEncodingSize, pbCertEncoding);
 924 
 925         // Create a certificate context from the encoded cert
 926         if (!(pCertContext = ::CertCreateCertificateContext(X509_ASN_ENCODING,
 927             (BYTE*) pbCertEncoding, jCertEncodingSize))) {
 928 
 929             ThrowException(env, CERTIFICATE_PARSING_EXCEPTION, GetLastError());
 930             __leave;
 931         }
 932 
 933         // Set the certificate's friendly name
 934         int size = env->GetStringLength(jCertAliasName);
 935         pszCertAliasName = new WCHAR[size + 1];
 936 
 937         jCertAliasChars = env->GetStringChars(jCertAliasName, NULL);
 938         memcpy(pszCertAliasName, jCertAliasChars, size * sizeof(WCHAR));
 939         pszCertAliasName[size] = 0; // append the string terminator
 940 
 941         CRYPT_DATA_BLOB friendlyName = {
 942             sizeof(WCHAR) * (size + 1),
 943             (BYTE *) pszCertAliasName
 944         };
 945 
 946         env->ReleaseStringChars(jCertAliasName, jCertAliasChars);
 947 
 948         if (! ::CertSetCertificateContextProperty(pCertContext,
 949             CERT_FRIENDLY_NAME_PROP_ID, 0, &friendlyName)) {
 950 
 951             ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
 952             __leave;
 953         }
 954 
 955         // Attach the certificate's private key (if supplied)
 956         if (hCryptProv != 0 && hCryptKey != 0) {
 957 
 958             CRYPT_KEY_PROV_INFO keyProviderInfo;
 959             DWORD dwDataLen;
 960 
 961             // Get the name of the key container
 962             if (! ::CryptGetProvParam(
 963                 (HCRYPTPROV) hCryptProv,
 964                 PP_CONTAINER,
 965                 NULL,
 966                 &dwDataLen,
 967                 0)) {
 968 
 969                 ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
 970                 __leave;
 971             }
 972 
 973             pszContainerName = new char[dwDataLen];
 974 
 975             if (! ::CryptGetProvParam(
 976                 (HCRYPTPROV) hCryptProv,
 977                 PP_CONTAINER,
 978                 (BYTE *) pszContainerName,
 979                 &dwDataLen,
 980                 0)) {
 981 
 982                 ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
 983                 __leave;
 984             }
 985 
 986             // Convert to a wide char string
 987             pwszContainerName = new WCHAR[dwDataLen];
 988 
 989             if (mbstowcs(pwszContainerName, pszContainerName, dwDataLen) == 0) {
 990                 ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
 991                 __leave;
 992             }
 993 
 994             // Set the name of the key container
 995             keyProviderInfo.pwszContainerName = pwszContainerName;
 996 
 997 
 998             // Get the name of the provider
 999             if (! ::CryptGetProvParam(
1000                 (HCRYPTPROV) hCryptProv,
1001                 PP_NAME,
1002                 NULL,
1003                 &dwDataLen,
1004                 0)) {
1005 
1006                 ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
1007                 __leave;
1008             }
1009 
1010             pszProviderName = new char[dwDataLen];
1011 
1012             if (! ::CryptGetProvParam(
1013                 (HCRYPTPROV) hCryptProv,
1014                 PP_NAME,
1015                 (BYTE *) pszProviderName,
1016                 &dwDataLen,
1017                 0)) {
1018 
1019                 ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
1020                 __leave;
1021             }
1022 
1023             // Convert to a wide char string
1024             pwszProviderName = new WCHAR[dwDataLen];
1025 
1026             if (mbstowcs(pwszProviderName, pszProviderName, dwDataLen) == 0) {
1027                 ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
1028                 __leave;
1029             }
1030 
1031             // Set the name of the provider
1032             keyProviderInfo.pwszProvName = pwszProviderName;
1033 
1034             // Get and set the type of the provider
1035             if (! ::CryptGetProvParam(
1036                 (HCRYPTPROV) hCryptProv,
1037                 PP_PROVTYPE,
1038                 (LPBYTE) &keyProviderInfo.dwProvType,
1039                 &dwDataLen,
1040                 0)) {
1041 
1042                 ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
1043                 __leave;
1044             }
1045 
1046             // Set no provider flags
1047             keyProviderInfo.dwFlags = 0;
1048 
1049             // Set no provider parameters
1050             keyProviderInfo.cProvParam = 0;
1051             keyProviderInfo.rgProvParam = NULL;
1052 
1053             // Get the key's algorithm ID
1054             if (! ::CryptGetKeyParam(
1055                 (HCRYPTKEY) hCryptKey,
1056                 KP_ALGID,
1057                 (LPBYTE) &keyProviderInfo.dwKeySpec,
1058                 &dwDataLen,
1059                 0)) {
1060 
1061                 ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
1062                 __leave;
1063             }
1064             // Set the key spec (using the algorithm ID).
1065             switch (keyProviderInfo.dwKeySpec) {
1066             case CALG_RSA_KEYX:
1067             case CALG_DH_SF:
1068                 keyProviderInfo.dwKeySpec = AT_KEYEXCHANGE;
1069                 break;
1070 
1071             case CALG_RSA_SIGN:
1072             case CALG_DSS_SIGN:
1073                 keyProviderInfo.dwKeySpec = AT_SIGNATURE;
1074                 break;
1075 
1076             default:
1077                 ThrowException(env, KEYSTORE_EXCEPTION, NTE_BAD_ALGID);
1078                 __leave;
1079             }
1080 
1081             if (! ::CertSetCertificateContextProperty(pCertContext,
1082                 CERT_KEY_PROV_INFO_PROP_ID, 0, &keyProviderInfo)) {
1083 
1084                 ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
1085                 __leave;
1086             }
1087         }
1088 
1089         // Import encoded certificate
1090         if (!::CertAddCertificateContextToStore(hCertStore, pCertContext,
1091             CERT_STORE_ADD_REPLACE_EXISTING, NULL))
1092         {
1093             ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
1094             __leave;
1095         }
1096 
1097     }
1098     __finally
1099     {
1100         //--------------------------------------------------------------------
1101         // Clean up.
1102 
1103         if (hCertStore)
1104             ::CertCloseStore(hCertStore, 0);
1105 
1106         if (pszCertStoreName)
1107             env->ReleaseStringUTFChars(jCertStoreName, pszCertStoreName);
1108 
1109         if (pbCertEncoding)
1110             delete [] pbCertEncoding;
1111 
1112         if (pszCertAliasName)
1113             delete [] pszCertAliasName;
1114 
1115         if (pszContainerName)
1116             delete [] pszContainerName;
1117 
1118         if (pwszContainerName)
1119             delete [] pwszContainerName;
1120 
1121         if (pszProviderName)
1122             delete [] pszProviderName;
1123 
1124         if (pwszProviderName)
1125             delete [] pwszProviderName;
1126 
1127         if (pCertContext)
1128             ::CertFreeCertificateContext(pCertContext);
1129     }
1130 }
1131 
1132 /*
1133  * Class:     sun_security_mscapi_KeyStore
1134  * Method:    removeCertificate
1135  * Signature: (Ljava/lang/String;Ljava/lang/String;[BI)V
1136  */
1137 JNIEXPORT void JNICALL Java_sun_security_mscapi_KeyStore_removeCertificate
1138   (JNIEnv *env, jobject obj, jstring jCertStoreName, jstring jCertAliasName,
1139   jbyteArray jCertEncoding, jint jCertEncodingSize) {
1140 
1141     const char* pszCertStoreName = NULL;
1142     const char* pszCertAliasName = NULL;
1143     HCERTSTORE hCertStore = NULL;
1144     PCCERT_CONTEXT pCertContext = NULL;
1145     PCCERT_CONTEXT pTBDCertContext = NULL;
1146     jbyte* pbCertEncoding = NULL;
1147     DWORD cchNameString = 0;
1148     char* pszNameString = NULL; // certificate's friendly name
1149     BOOL bDeleteAttempted = FALSE;
1150 
1151     __try
1152     {
1153         // Open a system certificate store.
1154         if ((pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL))
1155             == NULL) {
1156             __leave;
1157         }
1158         if ((hCertStore = ::CertOpenSystemStore(NULL, pszCertStoreName)) == NULL) {
1159             ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
1160             __leave;
1161         }
1162 
1163         // Copy encoding from Java to native buffer
1164         pbCertEncoding = new jbyte[jCertEncodingSize];
1165         env->GetByteArrayRegion(jCertEncoding, 0, jCertEncodingSize, pbCertEncoding);
1166 
1167         // Create a certificate context from the encoded cert
1168         if (!(pCertContext = ::CertCreateCertificateContext(X509_ASN_ENCODING,
1169             (BYTE*) pbCertEncoding, jCertEncodingSize))) {
1170 
1171             ThrowException(env, CERTIFICATE_PARSING_EXCEPTION, GetLastError());
1172             __leave;
1173         }
1174 
1175         // Find the certificate to be deleted
1176         if (!(pTBDCertContext = ::CertFindCertificateInStore(hCertStore,
1177             X509_ASN_ENCODING, 0, CERT_FIND_EXISTING, pCertContext, NULL))) {
1178 
1179             ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
1180             __leave;
1181         }
1182 
1183         // Check that its friendly name matches the supplied alias
1184         if ((cchNameString = ::CertGetNameString(pTBDCertContext,
1185                 CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, NULL, 0)) > 1) {
1186 
1187             pszNameString = new char[cchNameString];
1188 
1189             ::CertGetNameString(pTBDCertContext,
1190                 CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, pszNameString,
1191                 cchNameString);
1192 
1193             // Compare the certificate's friendly name with supplied alias name
1194             if ((pszCertAliasName = env->GetStringUTFChars(jCertAliasName, NULL))
1195                 == NULL) {
1196                 __leave;
1197             }
1198             if (strcmp(pszCertAliasName, pszNameString) == 0) {
1199 
1200                 // Only delete the certificate if the alias names matches
1201                 if (! ::CertDeleteCertificateFromStore(pTBDCertContext)) {
1202 
1203                     // pTBDCertContext is always freed by the
1204                     //  CertDeleteCertificateFromStore method
1205                     bDeleteAttempted = TRUE;
1206 
1207                     ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
1208                     __leave;
1209                 }
1210             }
1211         }
1212 
1213     }
1214     __finally
1215     {
1216         //--------------------------------------------------------------------
1217         // Clean up.
1218 
1219         if (hCertStore)
1220             ::CertCloseStore(hCertStore, 0);
1221 
1222         if (pszCertStoreName)
1223             env->ReleaseStringUTFChars(jCertStoreName, pszCertStoreName);
1224 
1225         if (pszCertAliasName)
1226             env->ReleaseStringUTFChars(jCertAliasName, pszCertAliasName);
1227 
1228         if (pbCertEncoding)
1229             delete [] pbCertEncoding;
1230 
1231         if (pszNameString)
1232             delete [] pszNameString;
1233 
1234         if (pCertContext)
1235             ::CertFreeCertificateContext(pCertContext);
1236 
1237         if (bDeleteAttempted && pTBDCertContext)
1238             ::CertFreeCertificateContext(pTBDCertContext);
1239     }
1240 }
1241 
1242 /*
1243  * Class:     sun_security_mscapi_KeyStore
1244  * Method:    destroyKeyContainer
1245  * Signature: (Ljava/lang/String;)V
1246  */
1247 JNIEXPORT void JNICALL Java_sun_security_mscapi_KeyStore_destroyKeyContainer
1248   (JNIEnv *env, jclass clazz, jstring keyContainerName)
1249 {
1250     HCRYPTPROV hCryptProv = NULL;
1251     const char* pszKeyContainerName = NULL;
1252 
1253     __try
1254     {
1255         if ((pszKeyContainerName =
1256             env->GetStringUTFChars(keyContainerName, NULL)) == NULL) {
1257             __leave;
1258         }
1259 
1260         // Destroying the default key container is not permitted
1261         // (because it may contain more one keypair).
1262         if (pszKeyContainerName == NULL) {
1263 
1264             ThrowException(env, KEYSTORE_EXCEPTION, NTE_BAD_KEYSET_PARAM);
1265             __leave;
1266         }
1267 
1268         // Acquire a CSP context (to the key container).
1269         if (::CryptAcquireContext(
1270             &hCryptProv,
1271             pszKeyContainerName,
1272             NULL,
1273             PROV_RSA_FULL,
1274             CRYPT_DELETEKEYSET) == FALSE)
1275         {
1276             ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
1277             __leave;
1278         }
1279 
1280     }
1281     __finally
1282     {
1283         //--------------------------------------------------------------------
1284         // Clean up.
1285 
1286         if (pszKeyContainerName)
1287             env->ReleaseStringUTFChars(keyContainerName, pszKeyContainerName);
1288     }
1289 }
1290 
1291 
1292 
1293 
1294 /*
1295  * Class:     sun_security_mscapi_RSACipher
1296  * Method:    findCertificateUsingAlias
1297  * Signature: (Ljava/lang/String;Ljava/lang/String;)J
1298  */
1299 JNIEXPORT jlong JNICALL Java_sun_security_mscapi_RSACipher_findCertificateUsingAlias
1300   (JNIEnv *env, jobject obj, jstring jCertStoreName, jstring jCertAliasName)
1301 {
1302     const char* pszCertStoreName = NULL;
1303     const char* pszCertAliasName = NULL;
1304     HCERTSTORE hCertStore = NULL;
1305     PCCERT_CONTEXT pCertContext = NULL;
1306     char* pszNameString = NULL; // certificate's friendly name
1307     DWORD cchNameString = 0;
1308 
1309     __try
1310     {
1311         if ((pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL))
1312             == NULL) {
1313             __leave;
1314         }
1315         if ((pszCertAliasName = env->GetStringUTFChars(jCertAliasName, NULL))
1316             == NULL) {
1317             __leave;
1318         }
1319 
1320         // Open a system certificate store.
1321         if ((hCertStore = ::CertOpenSystemStore(NULL, pszCertStoreName)) == NULL) {
1322             ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
1323             __leave;
1324         }
1325 
1326         // Use CertEnumCertificatesInStore to get the certificates
1327         // from the open store. pCertContext must be reset to
1328         // NULL to retrieve the first certificate in the store.
1329         while (pCertContext = ::CertEnumCertificatesInStore(hCertStore, pCertContext))
1330         {
1331             if ((cchNameString = ::CertGetNameString(pCertContext,
1332                 CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, NULL, 0)) == 1) {
1333 
1334                 continue; // not found
1335             }
1336 
1337             pszNameString = new char[cchNameString];
1338 
1339             if (::CertGetNameString(pCertContext,
1340                 CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, pszNameString,
1341                 cchNameString) == 1) {
1342 
1343                 continue; // not found
1344             }
1345 
1346             // Compare the certificate's friendly name with supplied alias name
1347             if (strcmp(pszCertAliasName, pszNameString) == 0) {
1348                 delete [] pszNameString;
1349                 break;
1350 
1351             } else {
1352                 delete [] pszNameString;
1353             }
1354         }
1355     }
1356     __finally
1357     {
1358         if (hCertStore)
1359             ::CertCloseStore(hCertStore, 0);
1360 
1361         if (pszCertStoreName)
1362             env->ReleaseStringUTFChars(jCertStoreName, pszCertStoreName);
1363 
1364         if (pszCertAliasName)
1365             env->ReleaseStringUTFChars(jCertAliasName, pszCertAliasName);
1366     }
1367 
1368     return (jlong) pCertContext;
1369 }
1370 
1371 /*
1372  * Class:     sun_security_mscapi_RSACipher
1373  * Method:    getKeyFromCert
1374  * Signature: (JZ)J
1375  */
1376 JNIEXPORT jlong JNICALL Java_sun_security_mscapi_RSACipher_getKeyFromCert
1377   (JNIEnv *env, jobject obj, jlong pCertContext, jboolean usePrivateKey)
1378 {
1379     HCRYPTPROV hCryptProv = NULL;
1380     HCRYPTKEY hKey = NULL;
1381     DWORD dwKeySpec;
1382     BOOL bCallerFreeProv = FALSE;
1383     BOOL bRes;
1384 
1385     __try
1386     {
1387         if (usePrivateKey == JNI_TRUE) {
1388             // Locate the key container for the certificate's private key
1389 
1390             // First, probe it silently
1391             bRes = ::CryptAcquireCertificatePrivateKey(
1392                     (PCCERT_CONTEXT) pCertContext, CRYPT_ACQUIRE_SILENT_FLAG,
1393                     NULL, &hCryptProv, &dwKeySpec, &bCallerFreeProv);
1394 
1395             if (bRes == FALSE && GetLastError() != NTE_SILENT_CONTEXT)
1396             {
1397                 ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
1398                 __leave;
1399             }
1400 
1401             if (bCallerFreeProv == TRUE) {
1402                 ::CryptReleaseContext(hCryptProv, NULL);
1403                 bCallerFreeProv = FALSE;
1404             }
1405 
1406             // Now, do it normally (not silently)
1407             if (::CryptAcquireCertificatePrivateKey(
1408                     (PCCERT_CONTEXT) pCertContext, 0, NULL, &hCryptProv,
1409                     &dwKeySpec, &bCallerFreeProv) == FALSE)
1410             {
1411                 ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
1412                 __leave;
1413             }
1414 
1415             // Get a handle to the private key
1416             if (::CryptGetUserKey(hCryptProv, dwKeySpec, &hKey) == FALSE) {
1417                 ThrowException(env, KEY_EXCEPTION, GetLastError());
1418                 __leave;
1419             }
1420         }
1421         else // use public key
1422         {
1423             bCallerFreeProv = TRUE;
1424 
1425             //  Acquire a CSP context.
1426             if (::CryptAcquireContext(&hCryptProv, "J2SE", NULL,
1427                     PROV_RSA_FULL, 0) == FALSE)
1428             {
1429                 // If CSP context hasn't been created, create one.
1430                 //
1431                 if (::CryptAcquireContext(&hCryptProv, "J2SE", NULL,
1432                         PROV_RSA_FULL, CRYPT_NEWKEYSET) == FALSE)
1433                 {
1434                     ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
1435                     __leave;
1436                 }
1437             }
1438 
1439             // Import the certificate's public key into the key container
1440             if (::CryptImportPublicKeyInfo(hCryptProv, X509_ASN_ENCODING,
1441                     &(((PCCERT_CONTEXT) pCertContext)->pCertInfo->SubjectPublicKeyInfo),
1442                     &hKey) == FALSE)
1443             {
1444                 ThrowException(env, KEY_EXCEPTION, GetLastError());
1445                 __leave;
1446             }
1447         }
1448     }
1449     __finally
1450     {
1451         //--------------------------------------------------------------------
1452         // Clean up.
1453 
1454         if (bCallerFreeProv == TRUE && hCryptProv != NULL)
1455             ::CryptReleaseContext(hCryptProv, 0);
1456     }
1457 
1458     return hKey;        // TODO - when finished with this key, call
1459                         //              CryptDestroyKey(hKey)
1460 }
1461 
1462 /*
1463  * Class:     sun_security_mscapi_KeyStore
1464  * Method:    getKeyLength
1465  * Signature: (J)I
1466  */
1467 JNIEXPORT jint JNICALL Java_sun_security_mscapi_KeyStore_getKeyLength
1468   (JNIEnv *env, jobject obj, jlong hKey)
1469 {
1470     DWORD dwDataLen = sizeof(DWORD);
1471     BYTE pbData[sizeof(DWORD)];
1472     DWORD length = 0;
1473 
1474     __try
1475     {
1476         // Get key length (in bits)
1477         //TODO - may need to use KP_BLOCKLEN instead?
1478         if (!(::CryptGetKeyParam((HCRYPTKEY) hKey, KP_KEYLEN, (BYTE *)pbData, &dwDataLen,
1479             0))) {
1480 
1481             ThrowException(env, KEY_EXCEPTION, GetLastError());
1482             __leave;
1483         }
1484         length = (DWORD) pbData;
1485     }
1486     __finally
1487     {
1488         // no cleanup required
1489     }
1490 
1491     return (jint) length;
1492 }
1493 
1494 /*
1495  * Class:     sun_security_mscapi_RSACipher
1496  * Method:    encryptDecrypt
1497  * Signature: ([BIJZ)[B
1498  */
1499 JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_RSACipher_encryptDecrypt
1500   (JNIEnv *env, jclass clazz, jbyteArray jData, jint jDataSize, jlong hKey,
1501    jboolean doEncrypt)
1502 {
1503     jbyteArray result = NULL;
1504     jbyte* pData = NULL;
1505     DWORD dwDataLen = jDataSize;
1506     DWORD dwBufLen = env->GetArrayLength(jData);
1507     DWORD i;
1508     BYTE tmp;
1509 
1510     __try
1511     {
1512         // Copy data from Java buffer to native buffer
1513         pData = new jbyte[dwBufLen];
1514         env->GetByteArrayRegion(jData, 0, dwBufLen, pData);
1515 
1516         if (doEncrypt == JNI_TRUE) {
1517             // encrypt
1518             if (! ::CryptEncrypt((HCRYPTKEY) hKey, 0, TRUE, 0, (BYTE *)pData,
1519                 &dwDataLen, dwBufLen)) {
1520 
1521                 ThrowException(env, KEY_EXCEPTION, GetLastError());
1522                 __leave;
1523             }
1524             dwBufLen = dwDataLen;
1525 
1526             // convert from little-endian
1527             for (i = 0; i < dwBufLen / 2; i++) {
1528                 tmp = pData[i];
1529                 pData[i] = pData[dwBufLen - i -1];
1530                 pData[dwBufLen - i - 1] = tmp;
1531             }
1532         } else {
1533             // convert to little-endian
1534             for (i = 0; i < dwBufLen / 2; i++) {
1535                 tmp = pData[i];
1536                 pData[i] = pData[dwBufLen - i -1];
1537                 pData[dwBufLen - i - 1] = tmp;
1538             }
1539 
1540             // decrypt
1541             if (! ::CryptDecrypt((HCRYPTKEY) hKey, 0, TRUE, 0, (BYTE *)pData,
1542                 &dwBufLen)) {
1543 
1544                 ThrowException(env, KEY_EXCEPTION, GetLastError());
1545                 __leave;
1546             }
1547         }
1548 
1549         // Create new byte array
1550         result = env->NewByteArray(dwBufLen);
1551 
1552         // Copy data from native buffer to Java buffer
1553         env->SetByteArrayRegion(result, 0, dwBufLen, (jbyte*) pData);
1554     }
1555     __finally
1556     {
1557         if (pData)
1558             delete [] pData;
1559     }
1560 
1561     return result;
1562 }
1563 
1564 /*
1565  * Class:     sun_security_mscapi_RSAPublicKey
1566  * Method:    getPublicKeyBlob
1567  * Signature: (J)[B
1568  */
1569 JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_RSAPublicKey_getPublicKeyBlob
1570     (JNIEnv *env, jclass clazz, jlong hCryptKey) {
1571 
1572     jbyteArray blob = NULL;
1573     DWORD dwBlobLen;
1574     BYTE* pbKeyBlob = NULL;
1575 
1576     __try
1577     {
1578 
1579         // Determine the size of the blob
1580         if (! ::CryptExportKey((HCRYPTKEY) hCryptKey, 0, PUBLICKEYBLOB, 0, NULL,
1581             &dwBlobLen)) {
1582 
1583             ThrowException(env, KEY_EXCEPTION, GetLastError());
1584             __leave;
1585         }
1586 
1587         pbKeyBlob = new BYTE[dwBlobLen];
1588 
1589         // Generate key blob
1590         if (! ::CryptExportKey((HCRYPTKEY) hCryptKey, 0, PUBLICKEYBLOB, 0,
1591             pbKeyBlob, &dwBlobLen)) {
1592 
1593             ThrowException(env, KEY_EXCEPTION, GetLastError());
1594             __leave;
1595         }
1596 
1597         // Create new byte array
1598         blob = env->NewByteArray(dwBlobLen);
1599 
1600         // Copy data from native buffer to Java buffer
1601         env->SetByteArrayRegion(blob, 0, dwBlobLen, (jbyte*) pbKeyBlob);
1602     }
1603     __finally
1604     {
1605         if (pbKeyBlob)
1606             delete [] pbKeyBlob;
1607     }
1608 
1609     return blob;
1610 }
1611 
1612 /*
1613  * Class:     sun_security_mscapi_RSAPublicKey
1614  * Method:    getExponent
1615  * Signature: ([B)[B
1616  */
1617 JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_RSAPublicKey_getExponent
1618     (JNIEnv *env, jclass clazz, jbyteArray jKeyBlob) {
1619 
1620     jbyteArray exponent = NULL;
1621     jbyte*     exponentBytes = NULL;
1622     jbyte*     keyBlob = NULL;
1623 
1624     __try {
1625 
1626         jsize length = env->GetArrayLength(jKeyBlob);
1627         if ((keyBlob = env->GetByteArrayElements(jKeyBlob, 0)) == NULL) {
1628             __leave;
1629         }
1630 
1631         PUBLICKEYSTRUC* pPublicKeyStruc = (PUBLICKEYSTRUC *) keyBlob;
1632 
1633         // Check BLOB type
1634         if (pPublicKeyStruc->bType != PUBLICKEYBLOB) {
1635             ThrowException(env, KEY_EXCEPTION, NTE_BAD_TYPE);
1636             __leave;
1637         }
1638 
1639         RSAPUBKEY* pRsaPubKey =
1640             (RSAPUBKEY *) (keyBlob + sizeof(PUBLICKEYSTRUC));
1641         int len = sizeof(pRsaPubKey->pubexp);
1642         exponentBytes = new jbyte[len];
1643 
1644         // convert from little-endian while copying from blob
1645         for (int i = 0, j = len - 1; i < len; i++, j--) {
1646             exponentBytes[i] = ((BYTE*) &pRsaPubKey->pubexp)[j];
1647         }
1648 
1649         exponent = env->NewByteArray(len);
1650         env->SetByteArrayRegion(exponent, 0, len, exponentBytes);
1651     }
1652     __finally
1653     {
1654         if (keyBlob)
1655             env->ReleaseByteArrayElements(jKeyBlob, keyBlob, JNI_ABORT);
1656 
1657         if (exponentBytes)
1658             delete [] exponentBytes;
1659     }
1660 
1661     return exponent;
1662 }
1663 
1664 /*
1665  * Class:     sun_security_mscapi_RSAPublicKey
1666  * Method:    getModulus
1667  * Signature: ([B)[B
1668  */
1669 JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_RSAPublicKey_getModulus
1670     (JNIEnv *env, jclass clazz, jbyteArray jKeyBlob) {
1671 
1672     jbyteArray modulus = NULL;
1673     jbyte*     modulusBytes = NULL;
1674     jbyte*     keyBlob = NULL;
1675 
1676     __try {
1677 
1678         jsize length = env->GetArrayLength(jKeyBlob);
1679         if ((keyBlob = env->GetByteArrayElements(jKeyBlob, 0)) == NULL) {
1680             __leave;
1681         }
1682 
1683         PUBLICKEYSTRUC* pPublicKeyStruc = (PUBLICKEYSTRUC *) keyBlob;
1684 
1685         // Check BLOB type
1686         if (pPublicKeyStruc->bType != PUBLICKEYBLOB) {
1687             ThrowException(env, KEY_EXCEPTION, NTE_BAD_TYPE);
1688             __leave;
1689         }
1690 
1691         RSAPUBKEY* pRsaPubKey =
1692             (RSAPUBKEY *) (keyBlob + sizeof(PUBLICKEYSTRUC));
1693         int len = pRsaPubKey->bitlen / 8;
1694 
1695         modulusBytes = new jbyte[len];
1696         BYTE * pbModulus =
1697             (BYTE *) (keyBlob + sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY));
1698 
1699         // convert from little-endian while copying from blob
1700         for (int i = 0, j = len - 1; i < len; i++, j--) {
1701             modulusBytes[i] = pbModulus[j];
1702         }
1703 
1704         modulus = env->NewByteArray(len);
1705         env->SetByteArrayRegion(modulus, 0, len, modulusBytes);
1706     }
1707     __finally
1708     {
1709         if (keyBlob)
1710             env->ReleaseByteArrayElements(jKeyBlob, keyBlob, JNI_ABORT);
1711 
1712         if (modulusBytes)
1713             delete [] modulusBytes;
1714     }
1715 
1716     return modulus;
1717 }
1718 
1719 /*
1720  * Convert an array in big-endian byte order into little-endian byte order.
1721  */
1722 int convertToLittleEndian(JNIEnv *env, jbyteArray source, jbyte* destination,
1723     int destinationLength) {
1724 
1725     int sourceLength = env->GetArrayLength(source);
1726 
1727     jbyte* sourceBytes = env->GetByteArrayElements(source, 0);
1728     if (sourceBytes == NULL) {
1729         return -1;
1730     }
1731 
1732     int copyLen = sourceLength;
1733     if (sourceLength > destinationLength) {
1734         // source might include an extra sign byte
1735         if (sourceLength == destinationLength + 1 && sourceBytes[0] == 0) {
1736             copyLen--;
1737         } else {
1738             return -1;
1739         }
1740     }
1741 
1742     // Copy bytes from the end of the source array to the beginning of the
1743     // destination array (until the destination array is full).
1744     // This ensures that the sign byte from the source array will be excluded.
1745     for (int i = 0; i < copyLen; i++) {
1746         destination[i] = sourceBytes[sourceLength - 1 - i];
1747     }
1748     if (copyLen < destinationLength) {
1749         memset(destination + copyLen, 0, destinationLength - copyLen);
1750     }
1751 
1752     env->ReleaseByteArrayElements(source, sourceBytes, JNI_ABORT);
1753 
1754     return destinationLength;
1755 }
1756 
1757 /*
1758  * The Microsoft Base Cryptographic Provider supports public-key BLOBs
1759  * that have the following format:
1760  *
1761  *     PUBLICKEYSTRUC publickeystruc;
1762  *     RSAPUBKEY rsapubkey;
1763  *     BYTE modulus[rsapubkey.bitlen/8];
1764  *
1765  * and private-key BLOBs that have the following format:
1766  *
1767  *     PUBLICKEYSTRUC publickeystruc;
1768  *     RSAPUBKEY rsapubkey;
1769  *     BYTE modulus[rsapubkey.bitlen/8];
1770  *     BYTE prime1[rsapubkey.bitlen/16];
1771  *     BYTE prime2[rsapubkey.bitlen/16];
1772  *     BYTE exponent1[rsapubkey.bitlen/16];
1773  *     BYTE exponent2[rsapubkey.bitlen/16];
1774  *     BYTE coefficient[rsapubkey.bitlen/16];
1775  *     BYTE privateExponent[rsapubkey.bitlen/8];
1776  *
1777  * This method generates such BLOBs from the key elements supplied.
1778  */
1779 jbyteArray generateKeyBlob(
1780         JNIEnv *env,
1781         jint jKeyBitLength,
1782         jbyteArray jModulus,
1783         jbyteArray jPublicExponent,
1784         jbyteArray jPrivateExponent,
1785         jbyteArray jPrimeP,
1786         jbyteArray jPrimeQ,
1787         jbyteArray jExponentP,
1788         jbyteArray jExponentQ,
1789         jbyteArray jCrtCoefficient)
1790 {
1791     jsize jKeyByteLength = jKeyBitLength / 8;
1792     jsize jBlobLength;
1793     BOOL bGeneratePrivateKeyBlob;
1794 
1795     // Determine whether to generate a public-key or a private-key BLOB
1796     if (jPrivateExponent != NULL &&
1797         jPrimeP != NULL &&
1798         jPrimeQ != NULL &&
1799         jExponentP != NULL &&
1800         jExponentQ != NULL &&
1801         jCrtCoefficient != NULL) {
1802 
1803         bGeneratePrivateKeyBlob = TRUE;
1804         jBlobLength = sizeof(BLOBHEADER) +
1805                         sizeof(RSAPUBKEY) +
1806                         ((jKeyBitLength / 8) * 4) +
1807                         (jKeyBitLength / 16);
1808 
1809     } else {
1810         bGeneratePrivateKeyBlob = FALSE;
1811         jBlobLength = sizeof(BLOBHEADER) +
1812                         sizeof(RSAPUBKEY) +
1813                         (jKeyBitLength / 8);
1814     }
1815 
1816     jbyte* jBlobBytes = new jbyte[jBlobLength];
1817     jbyte* jBlobElement;
1818     jbyteArray jBlob = NULL;
1819     jsize  jElementLength;
1820 
1821     __try {
1822 
1823         BLOBHEADER *pBlobHeader = (BLOBHEADER *) jBlobBytes;
1824         if (bGeneratePrivateKeyBlob) {
1825             pBlobHeader->bType = PRIVATEKEYBLOB;  // 0x07
1826         } else {
1827             pBlobHeader->bType = PUBLICKEYBLOB;   // 0x06
1828         }
1829         pBlobHeader->bVersion = CUR_BLOB_VERSION; // 0x02
1830         pBlobHeader->reserved = 0;                // 0x0000
1831         pBlobHeader->aiKeyAlg = CALG_RSA_KEYX;    // 0x0000a400
1832 
1833         RSAPUBKEY *pRsaPubKey =
1834             (RSAPUBKEY *) (jBlobBytes + sizeof(PUBLICKEYSTRUC));
1835         if (bGeneratePrivateKeyBlob) {
1836             pRsaPubKey->magic = 0x32415352;       // "RSA2"
1837         } else {
1838             pRsaPubKey->magic = 0x31415352;       // "RSA1"
1839         }
1840         pRsaPubKey->bitlen = jKeyBitLength;
1841         pRsaPubKey->pubexp = 0; // init
1842 
1843         // Sanity check
1844         jsize jPublicExponentLength = env->GetArrayLength(jPublicExponent);
1845         if (jPublicExponentLength > sizeof(pRsaPubKey->pubexp)) {
1846             ThrowException(env, INVALID_KEY_EXCEPTION, NTE_BAD_TYPE);
1847             __leave;
1848         }
1849         // The length argument must be the smaller of jPublicExponentLength
1850         // and sizeof(pRsaPubKey->pubkey)
1851         if ((jElementLength = convertToLittleEndian(env, jPublicExponent,
1852             (jbyte *) &(pRsaPubKey->pubexp), jPublicExponentLength)) < 0) {
1853             __leave;
1854         }
1855 
1856         // Modulus n
1857         jBlobElement =
1858             (jbyte *) (jBlobBytes + sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY));
1859         if ((jElementLength = convertToLittleEndian(env, jModulus, jBlobElement,
1860             jKeyByteLength)) < 0) {
1861             __leave;
1862         }
1863 
1864         if (bGeneratePrivateKeyBlob) {
1865             // Prime p
1866             jBlobElement += jElementLength;
1867             if ((jElementLength = convertToLittleEndian(env, jPrimeP,
1868                 jBlobElement, jKeyByteLength / 2)) < 0) {
1869                 __leave;
1870             }
1871 
1872             // Prime q
1873             jBlobElement += jElementLength;
1874             if ((jElementLength = convertToLittleEndian(env, jPrimeQ,
1875                 jBlobElement, jKeyByteLength / 2)) < 0) {
1876                 __leave;
1877             }
1878 
1879             // Prime exponent p
1880             jBlobElement += jElementLength;
1881             if ((jElementLength = convertToLittleEndian(env, jExponentP,
1882                 jBlobElement, jKeyByteLength / 2)) < 0) {
1883                 __leave;
1884             }
1885 
1886             // Prime exponent q
1887             jBlobElement += jElementLength;
1888             if ((jElementLength = convertToLittleEndian(env, jExponentQ,
1889                 jBlobElement, jKeyByteLength / 2)) < 0) {
1890                 __leave;
1891             }
1892 
1893             // CRT coefficient
1894             jBlobElement += jElementLength;
1895             if ((jElementLength = convertToLittleEndian(env, jCrtCoefficient,
1896                 jBlobElement, jKeyByteLength / 2)) < 0) {
1897                 __leave;
1898             }
1899 
1900             // Private exponent
1901             jBlobElement += jElementLength;
1902             if ((jElementLength = convertToLittleEndian(env, jPrivateExponent,
1903                 jBlobElement, jKeyByteLength)) < 0) {
1904                 __leave;
1905             }
1906         }
1907 
1908         jBlob = env->NewByteArray(jBlobLength);
1909         env->SetByteArrayRegion(jBlob, 0, jBlobLength, jBlobBytes);
1910 
1911     }
1912     __finally
1913     {
1914         if (jBlobBytes)
1915             delete [] jBlobBytes;
1916     }
1917 
1918     return jBlob;
1919 }
1920 
1921 /*
1922  * Class:     sun_security_mscapi_KeyStore
1923  * Method:    generatePrivateKeyBlob
1924  * Signature: (I[B[B[B[B[B[B[B[B)[B
1925  */
1926 JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_KeyStore_generatePrivateKeyBlob
1927     (JNIEnv *env, jclass clazz,
1928         jint jKeyBitLength,
1929         jbyteArray jModulus,
1930         jbyteArray jPublicExponent,
1931         jbyteArray jPrivateExponent,
1932         jbyteArray jPrimeP,
1933         jbyteArray jPrimeQ,
1934         jbyteArray jExponentP,
1935         jbyteArray jExponentQ,
1936         jbyteArray jCrtCoefficient)
1937 {
1938     return generateKeyBlob(env, jKeyBitLength, jModulus, jPublicExponent,
1939         jPrivateExponent, jPrimeP, jPrimeQ, jExponentP, jExponentQ,
1940         jCrtCoefficient);
1941 }
1942 
1943 /*
1944  * Class:     sun_security_mscapi_RSASignature
1945  * Method:    generatePublicKeyBlob
1946  * Signature: (I[B[B)[B
1947  */
1948 JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_RSASignature_generatePublicKeyBlob
1949     (JNIEnv *env, jclass clazz,
1950         jint jKeyBitLength,
1951         jbyteArray jModulus,
1952         jbyteArray jPublicExponent)
1953 {
1954     return generateKeyBlob(env, jKeyBitLength, jModulus, jPublicExponent,
1955         NULL, NULL, NULL, NULL, NULL, NULL);
1956 }
1957 
1958 /*
1959  * Class:     sun_security_mscapi_KeyStore
1960  * Method:    storePrivateKey
1961  * Signature: ([BLjava/lang/String;I)Lsun/security/mscapi/RSAPrivateKey;
1962  */
1963 JNIEXPORT jobject JNICALL Java_sun_security_mscapi_KeyStore_storePrivateKey
1964     (JNIEnv *env, jclass clazz, jbyteArray keyBlob, jstring keyContainerName,
1965      jint keySize)
1966 {
1967     HCRYPTPROV hCryptProv = NULL;
1968     HCRYPTKEY hKey = NULL;
1969     DWORD dwBlobLen;
1970     BYTE * pbKeyBlob = NULL;
1971     const char* pszKeyContainerName = NULL; // UUID
1972     jobject privateKey = NULL;
1973 
1974     __try
1975     {
1976         if ((pszKeyContainerName =
1977             env->GetStringUTFChars(keyContainerName, NULL)) == NULL) {
1978             __leave;
1979         }
1980         dwBlobLen = env->GetArrayLength(keyBlob);
1981         if ((pbKeyBlob = (BYTE *) env->GetByteArrayElements(keyBlob, 0))
1982             == NULL) {
1983             __leave;
1984         }
1985 
1986         // Acquire a CSP context (create a new key container).
1987         if (::CryptAcquireContext(
1988             &hCryptProv,
1989             pszKeyContainerName,
1990             NULL,
1991             PROV_RSA_FULL,
1992             CRYPT_NEWKEYSET) == FALSE)
1993         {
1994             ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
1995             __leave;
1996         }
1997 
1998         // Import the private key
1999         if (::CryptImportKey(
2000             hCryptProv,
2001             pbKeyBlob,
2002             dwBlobLen,
2003             0,
2004             CRYPT_EXPORTABLE,
2005             &hKey) == FALSE)
2006         {
2007             ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
2008             __leave;
2009         }
2010 
2011         // Get the method ID for the RSAPrivateKey constructor
2012         jclass clazzRSAPrivateKey =
2013             env->FindClass("sun/security/mscapi/RSAPrivateKey");
2014         if (clazzRSAPrivateKey == NULL) {
2015             __leave;
2016         }
2017 
2018         jmethodID mNewRSAPrivateKey =
2019             env->GetMethodID(clazzRSAPrivateKey, "<init>", "(JJI)V");
2020         if (mNewRSAPrivateKey == NULL) {
2021             __leave;
2022         }
2023 
2024         // Create a new RSA private key
2025         privateKey = env->NewObject(clazzRSAPrivateKey, mNewRSAPrivateKey,
2026             (jlong) hCryptProv, (jlong) hKey, keySize);
2027 
2028     }
2029     __finally
2030     {
2031         //--------------------------------------------------------------------
2032         // Clean up.
2033 
2034         if (pszKeyContainerName)
2035             env->ReleaseStringUTFChars(keyContainerName, pszKeyContainerName);
2036 
2037         if (pbKeyBlob)
2038             env->ReleaseByteArrayElements(keyBlob, (jbyte *) pbKeyBlob,
2039                 JNI_ABORT);
2040     }
2041 
2042     return privateKey;
2043 }
2044 
2045 /*
2046  * Class:     sun_security_mscapi_RSASignature
2047  * Method:    importPublicKey
2048  * Signature: ([BI)Lsun/security/mscapi/RSAPublicKey;
2049  */
2050 JNIEXPORT jobject JNICALL Java_sun_security_mscapi_RSASignature_importPublicKey
2051     (JNIEnv *env, jclass clazz, jbyteArray keyBlob, jint keySize)
2052 {
2053     HCRYPTPROV hCryptProv = NULL;
2054     HCRYPTKEY hKey = NULL;
2055     DWORD dwBlobLen;
2056     BYTE * pbKeyBlob = NULL;
2057     jobject publicKey = NULL;
2058 
2059     __try
2060     {
2061         dwBlobLen = env->GetArrayLength(keyBlob);
2062         if ((pbKeyBlob = (BYTE *) env->GetByteArrayElements(keyBlob, 0))
2063             == NULL) {
2064             __leave;
2065         }
2066 
2067         // Acquire a CSP context (create a new key container).
2068         // Prefer a PROV_RSA_AES CSP, when available, due to its support
2069         // for SHA-2-based signatures.
2070         if (::CryptAcquireContext(
2071             &hCryptProv,
2072             NULL,
2073             NULL,
2074             PROV_RSA_AES,
2075             CRYPT_VERIFYCONTEXT) == FALSE)
2076         {
2077             // Failover to using the default CSP (PROV_RSA_FULL)
2078 
2079             if (::CryptAcquireContext(
2080                 &hCryptProv,
2081                 NULL,
2082                 NULL,
2083                 PROV_RSA_FULL,
2084                 CRYPT_VERIFYCONTEXT) == FALSE)
2085             {
2086                 ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
2087                 __leave;
2088             }
2089         }
2090 
2091         // Import the public key
2092         if (::CryptImportKey(
2093             hCryptProv,
2094             pbKeyBlob,
2095             dwBlobLen,
2096             0,
2097             CRYPT_EXPORTABLE,
2098             &hKey) == FALSE)
2099         {
2100             ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
2101             __leave;
2102         }
2103 
2104         // Get the method ID for the RSAPublicKey constructor
2105         jclass clazzRSAPublicKey =
2106             env->FindClass("sun/security/mscapi/RSAPublicKey");
2107         if (clazzRSAPublicKey == NULL) {
2108             __leave;
2109         }
2110 
2111         jmethodID mNewRSAPublicKey =
2112             env->GetMethodID(clazzRSAPublicKey, "<init>", "(JJI)V");
2113         if (mNewRSAPublicKey == NULL) {
2114             __leave;
2115         }
2116 
2117         // Create a new RSA public key
2118         publicKey = env->NewObject(clazzRSAPublicKey, mNewRSAPublicKey,
2119             (jlong) hCryptProv, (jlong) hKey, keySize);
2120 
2121     }
2122     __finally
2123     {
2124         //--------------------------------------------------------------------
2125         // Clean up.
2126 
2127         if (pbKeyBlob)
2128             env->ReleaseByteArrayElements(keyBlob, (jbyte *) pbKeyBlob,
2129                 JNI_ABORT);
2130     }
2131 
2132     return publicKey;
2133 }
2134 
2135 } /* extern "C" */