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