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