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