security.cpp revision 12300:455de3861b2d
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
51extern "C" {
52
53/*
54 * Throws an arbitrary Java exception.
55 * The exception message is a Windows system error message.
56 */
57void 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 */
78ALG_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 */
118bool 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 */
157JNIEXPORT 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 */
268JNIEXPORT 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 */
500JNIEXPORT 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 */
516JNIEXPORT 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 */
640JNIEXPORT 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 */
738JNIEXPORT 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 */
824JNIEXPORT 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 */
846JNIEXPORT 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 */
876JNIEXPORT 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 */
1120JNIEXPORT 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 */
1230JNIEXPORT 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 */
1282JNIEXPORT 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 */
1359JNIEXPORT 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 */
1436JNIEXPORT 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 */
1468JNIEXPORT 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 */
1538JNIEXPORT 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 */
1586JNIEXPORT 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 */
1638JNIEXPORT 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 */
1691int 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 */
1748jbyteArray 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 */
1895JNIEXPORT 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 */
1917JNIEXPORT 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 */
1932JNIEXPORT 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 */
2019JNIEXPORT 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" */
2105