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