| /* |
| * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| //=--------------------------------------------------------------------------= |
| // security.cpp by Stanley Man-Kit Ho |
| //=--------------------------------------------------------------------------= |
| // |
| |
| #include <jni.h> |
| #include "jni_util.h" |
| #include <stdlib.h> |
| #include <string.h> |
| #include <windows.h> |
| #include <BaseTsd.h> |
| #include <wincrypt.h> |
| #include <stdio.h> |
| #include <memory> |
| |
| |
| #define OID_EKU_ANY "2.5.29.37.0" |
| |
| #define CERTIFICATE_PARSING_EXCEPTION \ |
| "java/security/cert/CertificateParsingException" |
| #define INVALID_KEY_EXCEPTION \ |
| "java/security/InvalidKeyException" |
| #define KEY_EXCEPTION "java/security/KeyException" |
| #define KEYSTORE_EXCEPTION "java/security/KeyStoreException" |
| #define PROVIDER_EXCEPTION "java/security/ProviderException" |
| #define SIGNATURE_EXCEPTION "java/security/SignatureException" |
| #define OUT_OF_MEMORY_ERROR "java/lang/OutOfMemoryError" |
| |
| extern "C" { |
| |
| /* |
| * Declare library specific JNI_Onload entry if static build |
| */ |
| DEF_STATIC_JNI_OnLoad |
| |
| /* |
| * Throws an arbitrary Java exception with the given message. |
| */ |
| void ThrowExceptionWithMessage(JNIEnv *env, const char *exceptionName, |
| const char *szMessage) |
| { |
| jclass exceptionClazz = env->FindClass(exceptionName); |
| if (exceptionClazz != NULL) { |
| env->ThrowNew(exceptionClazz, szMessage); |
| } |
| } |
| |
| /* |
| * Throws an arbitrary Java exception. |
| * The exception message is a Windows system error message. |
| */ |
| void ThrowException(JNIEnv *env, const char *exceptionName, DWORD dwError) |
| { |
| char szMessage[1024]; |
| szMessage[0] = '\0'; |
| |
| DWORD res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, |
| NULL, szMessage, sizeof(szMessage), NULL); |
| if (res == 0) { |
| strcpy(szMessage, "Unknown error"); |
| } |
| |
| ThrowExceptionWithMessage(env, exceptionName, szMessage); |
| } |
| |
| /* |
| * Overloaded 'operator new[]' variant, which will raise Java's |
| * OutOfMemoryError in the case of a failure. |
| */ |
| static void* operator new[](std::size_t size, JNIEnv *env) |
| { |
| void* buf = ::operator new[](size, std::nothrow); |
| if (buf == NULL) { |
| ThrowExceptionWithMessage(env, OUT_OF_MEMORY_ERROR, |
| "Native memory allocation failed"); |
| } |
| return buf; |
| } |
| |
| /* |
| * Maps the name of a hash algorithm to an algorithm identifier. |
| */ |
| ALG_ID MapHashAlgorithm(JNIEnv *env, jstring jHashAlgorithm) { |
| |
| const char* pszHashAlgorithm = NULL; |
| ALG_ID algId = 0; |
| |
| if ((pszHashAlgorithm = env->GetStringUTFChars(jHashAlgorithm, NULL)) |
| == NULL) { |
| return algId; |
| } |
| |
| if ((strcmp("SHA", pszHashAlgorithm) == 0) || |
| (strcmp("SHA1", pszHashAlgorithm) == 0) || |
| (strcmp("SHA-1", pszHashAlgorithm) == 0)) { |
| |
| algId = CALG_SHA1; |
| } else if (strcmp("SHA1+MD5", pszHashAlgorithm) == 0) { |
| algId = CALG_SSL3_SHAMD5; // a 36-byte concatenation of SHA-1 and MD5 |
| } else if (strcmp("SHA-256", pszHashAlgorithm) == 0) { |
| algId = CALG_SHA_256; |
| } else if (strcmp("SHA-384", pszHashAlgorithm) == 0) { |
| algId = CALG_SHA_384; |
| } else if (strcmp("SHA-512", pszHashAlgorithm) == 0) { |
| algId = CALG_SHA_512; |
| } else if (strcmp("MD5", pszHashAlgorithm) == 0) { |
| algId = CALG_MD5; |
| } else if (strcmp("MD2", pszHashAlgorithm) == 0) { |
| algId = CALG_MD2; |
| } |
| |
| if (pszHashAlgorithm) |
| env->ReleaseStringUTFChars(jHashAlgorithm, pszHashAlgorithm); |
| |
| return algId; |
| } |
| |
| |
| /* |
| * Returns a certificate chain context given a certificate context and key |
| * usage identifier. |
| */ |
| bool GetCertificateChain(LPSTR lpszKeyUsageIdentifier, PCCERT_CONTEXT pCertContext, PCCERT_CHAIN_CONTEXT* ppChainContext) |
| { |
| CERT_ENHKEY_USAGE EnhkeyUsage; |
| CERT_USAGE_MATCH CertUsage; |
| CERT_CHAIN_PARA ChainPara; |
| DWORD dwFlags = 0; |
| LPSTR szUsageIdentifierArray[1]; |
| |
| szUsageIdentifierArray[0] = lpszKeyUsageIdentifier; |
| EnhkeyUsage.cUsageIdentifier = 1; |
| EnhkeyUsage.rgpszUsageIdentifier = szUsageIdentifierArray; |
| CertUsage.dwType = USAGE_MATCH_TYPE_AND; |
| CertUsage.Usage = EnhkeyUsage; |
| ChainPara.cbSize = sizeof(CERT_CHAIN_PARA); |
| ChainPara.RequestedUsage=CertUsage; |
| |
| // Build a chain using CertGetCertificateChain |
| // and the certificate retrieved. |
| return (::CertGetCertificateChain(NULL, // use the default chain engine |
| pCertContext, // pointer to the end certificate |
| NULL, // use the default time |
| NULL, // search no additional stores |
| &ChainPara, // use AND logic and enhanced key usage |
| // as indicated in the ChainPara |
| // data structure |
| dwFlags, |
| NULL, // currently reserved |
| ppChainContext) == TRUE); // return a pointer to the chain created |
| } |
| |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // |
| |
| /* |
| * Class: sun_security_mscapi_PRNG |
| * Method: generateSeed |
| * Signature: (I[B)[B |
| */ |
| JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_PRNG_generateSeed |
| (JNIEnv *env, jclass clazz, jint length, jbyteArray seed) |
| { |
| |
| HCRYPTPROV hCryptProv = NULL; |
| BYTE* pbData = NULL; |
| jbyte* reseedBytes = NULL; |
| jbyte* seedBytes = NULL; |
| jbyteArray result = NULL; |
| |
| __try |
| { |
| // Acquire a CSP context. |
| if(::CryptAcquireContext( |
| &hCryptProv, |
| NULL, |
| NULL, |
| PROV_RSA_FULL, |
| CRYPT_VERIFYCONTEXT) == FALSE) |
| { |
| ThrowException(env, PROVIDER_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| /* |
| * If length is negative then use the supplied seed to re-seed the |
| * generator and return null. |
| * If length is non-zero then generate a new seed according to the |
| * requested length and return the new seed. |
| * If length is zero then overwrite the supplied seed with a new |
| * seed of the same length and return the seed. |
| */ |
| if (length < 0) { |
| length = env->GetArrayLength(seed); |
| if ((reseedBytes = env->GetByteArrayElements(seed, 0)) == NULL) { |
| __leave; |
| } |
| |
| if (::CryptGenRandom( |
| hCryptProv, |
| length, |
| (BYTE *) reseedBytes) == FALSE) { |
| |
| ThrowException(env, PROVIDER_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| result = NULL; |
| |
| } else if (length > 0) { |
| |
| pbData = new (env) BYTE[length]; |
| if (pbData == NULL) { |
| __leave; |
| } |
| |
| if (::CryptGenRandom( |
| hCryptProv, |
| length, |
| pbData) == FALSE) { |
| |
| ThrowException(env, PROVIDER_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| result = env->NewByteArray(length); |
| env->SetByteArrayRegion(result, 0, length, (jbyte*) pbData); |
| |
| } else { // length == 0 |
| |
| length = env->GetArrayLength(seed); |
| if ((seedBytes = env->GetByteArrayElements(seed, 0)) == NULL) { |
| __leave; |
| } |
| |
| if (::CryptGenRandom( |
| hCryptProv, |
| length, |
| (BYTE *) seedBytes) == FALSE) { |
| |
| ThrowException(env, PROVIDER_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| result = seed; // seed will be updated when seedBytes gets released |
| } |
| } |
| __finally |
| { |
| //-------------------------------------------------------------------- |
| // Clean up. |
| |
| if (reseedBytes) |
| env->ReleaseByteArrayElements(seed, reseedBytes, JNI_ABORT); |
| |
| if (pbData) |
| delete [] pbData; |
| |
| if (seedBytes) |
| env->ReleaseByteArrayElements(seed, seedBytes, 0); // update orig |
| |
| if (hCryptProv) |
| ::CryptReleaseContext(hCryptProv, 0); |
| } |
| |
| return result; |
| } |
| |
| |
| /* |
| * Class: sun_security_mscapi_KeyStore |
| * Method: loadKeysOrCertificateChains |
| * Signature: (Ljava/lang/String;Ljava/util/Collection;)V |
| */ |
| JNIEXPORT void JNICALL Java_sun_security_mscapi_KeyStore_loadKeysOrCertificateChains |
| (JNIEnv *env, jobject obj, jstring jCertStoreName) |
| { |
| /** |
| * Certificate in cert store has enhanced key usage extension |
| * property (or EKU property) that is not part of the certificate itself. To determine |
| * if the certificate should be returned, both the enhanced key usage in certificate |
| * extension block and the extension property stored along with the certificate in |
| * certificate store should be examined. Otherwise, we won't be able to determine |
| * the proper key usage from the Java side because the information is not stored as |
| * part of the encoded certificate. |
| */ |
| |
| const char* pszCertStoreName = NULL; |
| HCERTSTORE hCertStore = NULL; |
| PCCERT_CONTEXT pCertContext = NULL; |
| char* pszNameString = NULL; // certificate's friendly name |
| DWORD cchNameString = 0; |
| |
| |
| __try |
| { |
| // Open a system certificate store. |
| if ((pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL)) |
| == NULL) { |
| __leave; |
| } |
| if ((hCertStore = ::CertOpenSystemStore(NULL, pszCertStoreName)) |
| == NULL) { |
| |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Determine clazz and method ID to generate certificate |
| jclass clazzArrayList = env->FindClass("java/util/ArrayList"); |
| if (clazzArrayList == NULL) { |
| __leave; |
| } |
| |
| jmethodID mNewArrayList = env->GetMethodID(clazzArrayList, "<init>", "()V"); |
| if (mNewArrayList == NULL) { |
| __leave; |
| } |
| |
| jclass clazzOfThis = env->GetObjectClass(obj); |
| if (clazzOfThis == NULL) { |
| __leave; |
| } |
| |
| jmethodID mGenCert = env->GetMethodID(clazzOfThis, |
| "generateCertificate", |
| "([BLjava/util/Collection;)V"); |
| if (mGenCert == NULL) { |
| __leave; |
| } |
| |
| // Determine method ID to generate certificate chain |
| jmethodID mGenCertChain = env->GetMethodID(clazzOfThis, |
| "generateCertificateChain", |
| "(Ljava/lang/String;Ljava/util/Collection;)V"); |
| if (mGenCertChain == NULL) { |
| __leave; |
| } |
| |
| // Determine method ID to generate RSA certificate chain |
| jmethodID mGenRSAKeyAndCertChain = env->GetMethodID(clazzOfThis, |
| "generateRSAKeyAndCertificateChain", |
| "(Ljava/lang/String;JJILjava/util/Collection;)V"); |
| if (mGenRSAKeyAndCertChain == NULL) { |
| __leave; |
| } |
| |
| // Use CertEnumCertificatesInStore to get the certificates |
| // from the open store. pCertContext must be reset to |
| // NULL to retrieve the first certificate in the store. |
| while (pCertContext = ::CertEnumCertificatesInStore(hCertStore, pCertContext)) |
| { |
| // Check if private key available - client authentication certificate |
| // must have private key available. |
| HCRYPTPROV hCryptProv = NULL; |
| DWORD dwKeySpec = 0; |
| HCRYPTKEY hUserKey = NULL; |
| BOOL bCallerFreeProv = FALSE; |
| BOOL bHasNoPrivateKey = FALSE; |
| DWORD dwPublicKeyLength = 0; |
| |
| // First, probe it silently |
| if (::CryptAcquireCertificatePrivateKey(pCertContext, CRYPT_ACQUIRE_SILENT_FLAG, NULL, |
| &hCryptProv, &dwKeySpec, &bCallerFreeProv) == FALSE |
| && GetLastError() != NTE_SILENT_CONTEXT) |
| { |
| bHasNoPrivateKey = TRUE; |
| } |
| else |
| { |
| if (bCallerFreeProv == TRUE) { |
| ::CryptReleaseContext(hCryptProv, NULL); |
| bCallerFreeProv = FALSE; |
| } |
| |
| // Second, acquire the key normally (not silently) |
| if (::CryptAcquireCertificatePrivateKey(pCertContext, 0, NULL, |
| &hCryptProv, &dwKeySpec, &bCallerFreeProv) == FALSE) |
| { |
| bHasNoPrivateKey = TRUE; |
| } |
| else |
| { |
| // Private key is available |
| BOOL bGetUserKey = ::CryptGetUserKey(hCryptProv, dwKeySpec, &hUserKey); |
| |
| // Skip certificate if cannot find private key |
| if (bGetUserKey == FALSE) { |
| if (bCallerFreeProv) |
| ::CryptReleaseContext(hCryptProv, NULL); |
| continue; |
| } |
| |
| // Set cipher mode to ECB |
| DWORD dwCipherMode = CRYPT_MODE_ECB; |
| ::CryptSetKeyParam(hUserKey, KP_MODE, (BYTE*)&dwCipherMode, NULL); |
| |
| // If the private key is present in smart card, we may not be able to |
| // determine the key length by using the private key handle. However, |
| // since public/private key pairs must have the same length, we could |
| // determine the key length of the private key by using the public key |
| // in the certificate. |
| dwPublicKeyLength = ::CertGetPublicKeyLength(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, |
| &(pCertContext->pCertInfo->SubjectPublicKeyInfo)); |
| } |
| } |
| PCCERT_CHAIN_CONTEXT pCertChainContext = NULL; |
| |
| // Build certificate chain by using system certificate store. |
| // Add cert chain into collection for any key usage. |
| // |
| if (GetCertificateChain(OID_EKU_ANY, pCertContext, &pCertChainContext)) |
| { |
| for (DWORD i = 0; i < pCertChainContext->cChain; i++) |
| { |
| // Found cert chain |
| PCERT_SIMPLE_CHAIN rgpChain = |
| pCertChainContext->rgpChain[i]; |
| |
| // Create ArrayList to store certs in each chain |
| jobject jArrayList = |
| env->NewObject(clazzArrayList, mNewArrayList); |
| |
| for (unsigned int j=0; j < rgpChain->cElement; j++) |
| { |
| PCERT_CHAIN_ELEMENT rgpElement = |
| rgpChain->rgpElement[j]; |
| PCCERT_CONTEXT pc = rgpElement->pCertContext; |
| |
| // Retrieve the friendly name of the first certificate |
| // in the chain |
| if (j == 0) { |
| |
| // If the cert's name cannot be retrieved then |
| // pszNameString remains set to NULL. |
| // (An alias name will be generated automatically |
| // when storing this cert in the keystore.) |
| |
| // Get length of friendly name |
| if ((cchNameString = CertGetNameString(pc, |
| CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, |
| NULL, 0)) > 1) { |
| |
| // Found friendly name |
| pszNameString = new (env) char[cchNameString]; |
| if (pszNameString == NULL) { |
| __leave; |
| } |
| |
| CertGetNameString(pc, |
| CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, |
| pszNameString, cchNameString); |
| } |
| } |
| |
| BYTE* pbCertEncoded = pc->pbCertEncoded; |
| DWORD cbCertEncoded = pc->cbCertEncoded; |
| |
| // Allocate and populate byte array |
| jbyteArray byteArray = env->NewByteArray(cbCertEncoded); |
| env->SetByteArrayRegion(byteArray, 0, cbCertEncoded, |
| (jbyte*) pbCertEncoded); |
| |
| // Generate certificate from byte array and store into |
| // cert collection |
| env->CallVoidMethod(obj, mGenCert, byteArray, jArrayList); |
| } |
| |
| if (bHasNoPrivateKey) |
| { |
| // Generate certificate chain and store into cert chain |
| // collection |
| env->CallVoidMethod(obj, mGenCertChain, |
| env->NewStringUTF(pszNameString), |
| jArrayList); |
| } |
| else |
| { |
| // Determine key type: RSA or DSA |
| DWORD dwData = CALG_RSA_KEYX; |
| DWORD dwSize = sizeof(DWORD); |
| ::CryptGetKeyParam(hUserKey, KP_ALGID, (BYTE*)&dwData, |
| &dwSize, NULL); |
| |
| if ((dwData & ALG_TYPE_RSA) == ALG_TYPE_RSA) |
| { |
| // Generate RSA certificate chain and store into cert |
| // chain collection |
| env->CallVoidMethod(obj, mGenRSAKeyAndCertChain, |
| env->NewStringUTF(pszNameString), |
| (jlong) hCryptProv, (jlong) hUserKey, |
| dwPublicKeyLength, jArrayList); |
| } |
| } |
| } |
| |
| // Free cert chain |
| if (pCertChainContext) |
| ::CertFreeCertificateChain(pCertChainContext); |
| } |
| } |
| } |
| __finally |
| { |
| if (hCertStore) |
| ::CertCloseStore(hCertStore, 0); |
| |
| if (pszCertStoreName) |
| env->ReleaseStringUTFChars(jCertStoreName, pszCertStoreName); |
| |
| if (pszNameString) |
| delete [] pszNameString; |
| } |
| } |
| |
| |
| /* |
| * Class: sun_security_mscapi_Key |
| * Method: cleanUp |
| * Signature: (JJ)V |
| */ |
| JNIEXPORT void JNICALL Java_sun_security_mscapi_Key_cleanUp |
| (JNIEnv *env, jclass clazz, jlong hCryptProv, jlong hCryptKey) |
| { |
| if (hCryptKey != NULL) |
| ::CryptDestroyKey((HCRYPTKEY) hCryptKey); |
| |
| if (hCryptProv != NULL) |
| ::CryptReleaseContext((HCRYPTPROV) hCryptProv, NULL); |
| } |
| |
| |
| /* |
| * Class: sun_security_mscapi_RSASignature |
| * Method: signHash |
| * Signature: (Z[BILjava/lang/String;JJ)[B |
| */ |
| JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_RSASignature_signHash |
| (JNIEnv *env, jclass clazz, jboolean noHashOID, jbyteArray jHash, |
| jint jHashSize, jstring jHashAlgorithm, jlong hCryptProv, |
| jlong hCryptKey) |
| { |
| HCRYPTHASH hHash = NULL; |
| jbyte* pHashBuffer = NULL; |
| jbyte* pSignedHashBuffer = NULL; |
| jbyteArray jSignedHash = NULL; |
| HCRYPTPROV hCryptProvAlt = NULL; |
| |
| __try |
| { |
| // Map hash algorithm |
| ALG_ID algId = MapHashAlgorithm(env, jHashAlgorithm); |
| |
| // Acquire a hash object handle. |
| if (::CryptCreateHash(HCRYPTPROV(hCryptProv), algId, 0, 0, &hHash) == FALSE) |
| { |
| // Failover to using the PROV_RSA_AES CSP |
| |
| DWORD cbData = 256; |
| BYTE pbData[256]; |
| pbData[0] = '\0'; |
| |
| // Get name of the key container |
| ::CryptGetProvParam((HCRYPTPROV)hCryptProv, PP_CONTAINER, |
| (BYTE *)pbData, &cbData, 0); |
| |
| // Acquire an alternative CSP handle |
| if (::CryptAcquireContext(&hCryptProvAlt, LPCSTR(pbData), NULL, |
| PROV_RSA_AES, 0) == FALSE) |
| { |
| |
| ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Acquire a hash object handle. |
| if (::CryptCreateHash(HCRYPTPROV(hCryptProvAlt), algId, 0, 0, |
| &hHash) == FALSE) |
| { |
| ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| } |
| |
| // Copy hash from Java to native buffer |
| pHashBuffer = new (env) jbyte[jHashSize]; |
| if (pHashBuffer == NULL) { |
| __leave; |
| } |
| env->GetByteArrayRegion(jHash, 0, jHashSize, pHashBuffer); |
| |
| // Set hash value in the hash object |
| if (::CryptSetHashParam(hHash, HP_HASHVAL, (BYTE*)pHashBuffer, NULL) == FALSE) |
| { |
| ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Determine key spec. |
| DWORD dwKeySpec = AT_SIGNATURE; |
| ALG_ID dwAlgId; |
| DWORD dwAlgIdLen = sizeof(ALG_ID); |
| |
| if (! ::CryptGetKeyParam((HCRYPTKEY) hCryptKey, KP_ALGID, (BYTE*)&dwAlgId, &dwAlgIdLen, 0)) { |
| ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); |
| __leave; |
| |
| } |
| if (CALG_RSA_KEYX == dwAlgId) { |
| dwKeySpec = AT_KEYEXCHANGE; |
| } |
| |
| // Determine size of buffer |
| DWORD dwBufLen = 0; |
| DWORD dwFlags = 0; |
| |
| if (noHashOID == JNI_TRUE) { |
| dwFlags = CRYPT_NOHASHOID; // omit hash OID in NONEwithRSA signature |
| } |
| |
| if (::CryptSignHash(hHash, dwKeySpec, NULL, dwFlags, NULL, &dwBufLen) == FALSE) |
| { |
| ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| pSignedHashBuffer = new (env) jbyte[dwBufLen]; |
| if (pSignedHashBuffer == NULL) { |
| __leave; |
| } |
| if (::CryptSignHash(hHash, dwKeySpec, NULL, dwFlags, (BYTE*)pSignedHashBuffer, &dwBufLen) == FALSE) |
| { |
| ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Create new byte array |
| jbyteArray temp = env->NewByteArray(dwBufLen); |
| |
| // Copy data from native buffer |
| env->SetByteArrayRegion(temp, 0, dwBufLen, pSignedHashBuffer); |
| |
| jSignedHash = temp; |
| } |
| __finally |
| { |
| if (pSignedHashBuffer) |
| delete [] pSignedHashBuffer; |
| |
| if (pHashBuffer) |
| delete [] pHashBuffer; |
| |
| if (hHash) |
| ::CryptDestroyHash(hHash); |
| |
| if (hCryptProvAlt) |
| ::CryptReleaseContext(hCryptProvAlt, 0); |
| } |
| |
| return jSignedHash; |
| } |
| |
| /* |
| * Class: sun_security_mscapi_RSASignature |
| * Method: verifySignedHash |
| * Signature: ([BIL/java/lang/String;[BIJJ)Z |
| */ |
| JNIEXPORT jboolean JNICALL Java_sun_security_mscapi_RSASignature_verifySignedHash |
| (JNIEnv *env, jclass clazz, jbyteArray jHash, jint jHashSize, |
| jstring jHashAlgorithm, jbyteArray jSignedHash, jint jSignedHashSize, |
| jlong hCryptProv, jlong hCryptKey) |
| { |
| HCRYPTHASH hHash = NULL; |
| jbyte* pHashBuffer = NULL; |
| jbyte* pSignedHashBuffer = NULL; |
| DWORD dwSignedHashBufferLen = jSignedHashSize; |
| jboolean result = JNI_FALSE; |
| HCRYPTPROV hCryptProvAlt = NULL; |
| |
| __try |
| { |
| // Map hash algorithm |
| ALG_ID algId = MapHashAlgorithm(env, jHashAlgorithm); |
| |
| // Acquire a hash object handle. |
| if (::CryptCreateHash(HCRYPTPROV(hCryptProv), algId, 0, 0, &hHash) |
| == FALSE) |
| { |
| // Failover to using the PROV_RSA_AES CSP |
| |
| DWORD cbData = 256; |
| BYTE pbData[256]; |
| pbData[0] = '\0'; |
| |
| // Get name of the key container |
| ::CryptGetProvParam((HCRYPTPROV)hCryptProv, PP_CONTAINER, |
| (BYTE *)pbData, &cbData, 0); |
| |
| // Acquire an alternative CSP handle |
| if (::CryptAcquireContext(&hCryptProvAlt, LPCSTR(pbData), NULL, |
| PROV_RSA_AES, 0) == FALSE) |
| { |
| |
| ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Acquire a hash object handle. |
| if (::CryptCreateHash(HCRYPTPROV(hCryptProvAlt), algId, 0, 0, |
| &hHash) == FALSE) |
| { |
| ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| } |
| |
| // Copy hash and signedHash from Java to native buffer |
| pHashBuffer = new (env) jbyte[jHashSize]; |
| if (pHashBuffer == NULL) { |
| __leave; |
| } |
| env->GetByteArrayRegion(jHash, 0, jHashSize, pHashBuffer); |
| |
| pSignedHashBuffer = new (env) jbyte[jSignedHashSize]; |
| if (pSignedHashBuffer == NULL) { |
| __leave; |
| } |
| env->GetByteArrayRegion(jSignedHash, 0, jSignedHashSize, |
| pSignedHashBuffer); |
| |
| // Set hash value in the hash object |
| if (::CryptSetHashParam(hHash, HP_HASHVAL, (BYTE*) pHashBuffer, NULL) |
| == FALSE) |
| { |
| ThrowException(env, SIGNATURE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // For RSA, the hash encryption algorithm is normally the same as the |
| // public key algorithm, so AT_SIGNATURE is used. |
| |
| // Verify the signature |
| if (::CryptVerifySignatureA(hHash, (BYTE *) pSignedHashBuffer, |
| dwSignedHashBufferLen, (HCRYPTKEY) hCryptKey, NULL, 0) == TRUE) |
| { |
| result = JNI_TRUE; |
| } |
| } |
| |
| __finally |
| { |
| if (pSignedHashBuffer) |
| delete [] pSignedHashBuffer; |
| |
| if (pHashBuffer) |
| delete [] pHashBuffer; |
| |
| if (hHash) |
| ::CryptDestroyHash(hHash); |
| |
| if (hCryptProvAlt) |
| ::CryptReleaseContext(hCryptProvAlt, 0); |
| } |
| |
| return result; |
| } |
| |
| /* |
| * Class: sun_security_mscapi_RSAKeyPairGenerator |
| * Method: generateRSAKeyPair |
| * Signature: (ILjava/lang/String;)Lsun/security/mscapi/RSAKeyPair; |
| */ |
| JNIEXPORT jobject JNICALL Java_sun_security_mscapi_RSAKeyPairGenerator_generateRSAKeyPair |
| (JNIEnv *env, jclass clazz, jint keySize, jstring keyContainerName) |
| { |
| HCRYPTPROV hCryptProv = NULL; |
| HCRYPTKEY hKeyPair; |
| DWORD dwFlags = (keySize << 16) | CRYPT_EXPORTABLE; |
| jobject keypair = NULL; |
| const char* pszKeyContainerName = NULL; // UUID |
| |
| __try |
| { |
| if ((pszKeyContainerName = |
| env->GetStringUTFChars(keyContainerName, NULL)) == NULL) { |
| __leave; |
| } |
| |
| // Acquire a CSP context (create a new key container). |
| // Prefer a PROV_RSA_AES CSP, when available, due to its support |
| // for SHA-2-based signatures. |
| if (::CryptAcquireContext( |
| &hCryptProv, |
| pszKeyContainerName, |
| NULL, |
| PROV_RSA_AES, |
| CRYPT_NEWKEYSET) == FALSE) |
| { |
| // Failover to using the default CSP (PROV_RSA_FULL) |
| |
| if (::CryptAcquireContext( |
| &hCryptProv, |
| pszKeyContainerName, |
| NULL, |
| PROV_RSA_FULL, |
| CRYPT_NEWKEYSET) == FALSE) |
| { |
| ThrowException(env, KEY_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| } |
| |
| // Generate an RSA keypair |
| if(::CryptGenKey( |
| hCryptProv, |
| AT_KEYEXCHANGE, |
| dwFlags, |
| &hKeyPair) == FALSE) |
| { |
| ThrowException(env, KEY_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Get the method ID for the RSAKeyPair constructor |
| jclass clazzRSAKeyPair = |
| env->FindClass("sun/security/mscapi/RSAKeyPair"); |
| if (clazzRSAKeyPair == NULL) { |
| __leave; |
| } |
| |
| jmethodID mNewRSAKeyPair = |
| env->GetMethodID(clazzRSAKeyPair, "<init>", "(JJI)V"); |
| if (mNewRSAKeyPair == NULL) { |
| __leave; |
| } |
| |
| // Create a new RSA keypair |
| keypair = env->NewObject(clazzRSAKeyPair, mNewRSAKeyPair, |
| (jlong) hCryptProv, (jlong) hKeyPair, keySize); |
| |
| } |
| __finally |
| { |
| //-------------------------------------------------------------------- |
| // Clean up. |
| |
| if (pszKeyContainerName) |
| env->ReleaseStringUTFChars(keyContainerName, pszKeyContainerName); |
| } |
| |
| return keypair; |
| } |
| |
| /* |
| * Class: sun_security_mscapi_Key |
| * Method: getContainerName |
| * Signature: (J)Ljava/lang/String; |
| */ |
| JNIEXPORT jstring JNICALL Java_sun_security_mscapi_Key_getContainerName |
| (JNIEnv *env, jclass jclazz, jlong hCryptProv) |
| { |
| DWORD cbData = 256; |
| BYTE pbData[256]; |
| pbData[0] = '\0'; |
| |
| ::CryptGetProvParam( |
| (HCRYPTPROV)hCryptProv, |
| PP_CONTAINER, |
| (BYTE *)pbData, |
| &cbData, |
| 0); |
| |
| return env->NewStringUTF((const char*)pbData); |
| } |
| |
| /* |
| * Class: sun_security_mscapi_Key |
| * Method: getKeyType |
| * Signature: (J)Ljava/lang/String; |
| */ |
| JNIEXPORT jstring JNICALL Java_sun_security_mscapi_Key_getKeyType |
| (JNIEnv *env, jclass jclazz, jlong hCryptKey) |
| { |
| ALG_ID dwAlgId; |
| DWORD dwAlgIdLen = sizeof(ALG_ID); |
| |
| if (::CryptGetKeyParam((HCRYPTKEY) hCryptKey, KP_ALGID, (BYTE*)&dwAlgId, &dwAlgIdLen, 0)) { |
| |
| if (CALG_RSA_SIGN == dwAlgId) { |
| return env->NewStringUTF("Signature"); |
| |
| } else if (CALG_RSA_KEYX == dwAlgId) { |
| return env->NewStringUTF("Exchange"); |
| |
| } else { |
| char buffer[64]; |
| if (sprintf(buffer, "%lu", dwAlgId)) { |
| return env->NewStringUTF(buffer); |
| } |
| } |
| } |
| |
| return env->NewStringUTF("<Unknown>"); |
| } |
| |
| /* |
| * Class: sun_security_mscapi_KeyStore |
| * Method: storeCertificate |
| * Signature: (Ljava/lang/String;Ljava/lang/String;[BIJJ)V |
| */ |
| JNIEXPORT void JNICALL Java_sun_security_mscapi_KeyStore_storeCertificate |
| (JNIEnv *env, jobject obj, jstring jCertStoreName, jstring jCertAliasName, |
| jbyteArray jCertEncoding, jint jCertEncodingSize, jlong hCryptProv, |
| jlong hCryptKey) |
| { |
| const char* pszCertStoreName = NULL; |
| HCERTSTORE hCertStore = NULL; |
| PCCERT_CONTEXT pCertContext = NULL; |
| PWCHAR pszCertAliasName = NULL; |
| jbyte* pbCertEncoding = NULL; |
| const jchar* jCertAliasChars = NULL; |
| const char* pszContainerName = NULL; |
| const char* pszProviderName = NULL; |
| WCHAR * pwszContainerName = NULL; |
| WCHAR * pwszProviderName = NULL; |
| |
| __try |
| { |
| // Open a system certificate store. |
| if ((pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL)) |
| == NULL) { |
| __leave; |
| } |
| if ((hCertStore = ::CertOpenSystemStore(NULL, pszCertStoreName)) == NULL) { |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Copy encoding from Java to native buffer |
| pbCertEncoding = new (env) jbyte[jCertEncodingSize]; |
| if (pbCertEncoding == NULL) { |
| __leave; |
| } |
| env->GetByteArrayRegion(jCertEncoding, 0, jCertEncodingSize, pbCertEncoding); |
| |
| // Create a certificate context from the encoded cert |
| if (!(pCertContext = ::CertCreateCertificateContext(X509_ASN_ENCODING, |
| (BYTE*) pbCertEncoding, jCertEncodingSize))) { |
| |
| ThrowException(env, CERTIFICATE_PARSING_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Set the certificate's friendly name |
| int size = env->GetStringLength(jCertAliasName); |
| pszCertAliasName = new (env) WCHAR[size + 1]; |
| if (pszCertAliasName == NULL) { |
| __leave; |
| } |
| |
| jCertAliasChars = env->GetStringChars(jCertAliasName, NULL); |
| memcpy(pszCertAliasName, jCertAliasChars, size * sizeof(WCHAR)); |
| pszCertAliasName[size] = 0; // append the string terminator |
| |
| CRYPT_DATA_BLOB friendlyName = { |
| sizeof(WCHAR) * (size + 1), |
| (BYTE *) pszCertAliasName |
| }; |
| |
| env->ReleaseStringChars(jCertAliasName, jCertAliasChars); |
| |
| if (! ::CertSetCertificateContextProperty(pCertContext, |
| CERT_FRIENDLY_NAME_PROP_ID, 0, &friendlyName)) { |
| |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Attach the certificate's private key (if supplied) |
| if (hCryptProv != 0 && hCryptKey != 0) { |
| |
| CRYPT_KEY_PROV_INFO keyProviderInfo; |
| DWORD dwDataLen; |
| |
| // Get the name of the key container |
| if (! ::CryptGetProvParam( |
| (HCRYPTPROV) hCryptProv, |
| PP_CONTAINER, |
| NULL, |
| &dwDataLen, |
| 0)) { |
| |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| pszContainerName = new (env) char[dwDataLen]; |
| if (pszContainerName == NULL) { |
| __leave; |
| } |
| |
| if (! ::CryptGetProvParam( |
| (HCRYPTPROV) hCryptProv, |
| PP_CONTAINER, |
| (BYTE *) pszContainerName, |
| &dwDataLen, |
| 0)) { |
| |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Convert to a wide char string |
| pwszContainerName = new (env) WCHAR[dwDataLen]; |
| if (pwszContainerName == NULL) { |
| __leave; |
| } |
| |
| if (mbstowcs(pwszContainerName, pszContainerName, dwDataLen) == 0) { |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Set the name of the key container |
| keyProviderInfo.pwszContainerName = pwszContainerName; |
| |
| |
| // Get the name of the provider |
| if (! ::CryptGetProvParam( |
| (HCRYPTPROV) hCryptProv, |
| PP_NAME, |
| NULL, |
| &dwDataLen, |
| 0)) { |
| |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| pszProviderName = new (env) char[dwDataLen]; |
| if (pszProviderName == NULL) { |
| __leave; |
| } |
| |
| if (! ::CryptGetProvParam( |
| (HCRYPTPROV) hCryptProv, |
| PP_NAME, |
| (BYTE *) pszProviderName, |
| &dwDataLen, |
| 0)) { |
| |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Convert to a wide char string |
| pwszProviderName = new (env) WCHAR[dwDataLen]; |
| if (pwszProviderName == NULL) { |
| __leave; |
| } |
| |
| if (mbstowcs(pwszProviderName, pszProviderName, dwDataLen) == 0) { |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Set the name of the provider |
| keyProviderInfo.pwszProvName = pwszProviderName; |
| |
| // Get and set the type of the provider |
| if (! ::CryptGetProvParam( |
| (HCRYPTPROV) hCryptProv, |
| PP_PROVTYPE, |
| (LPBYTE) &keyProviderInfo.dwProvType, |
| &dwDataLen, |
| 0)) { |
| |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Set no provider flags |
| keyProviderInfo.dwFlags = 0; |
| |
| // Set no provider parameters |
| keyProviderInfo.cProvParam = 0; |
| keyProviderInfo.rgProvParam = NULL; |
| |
| // Get the key's algorithm ID |
| if (! ::CryptGetKeyParam( |
| (HCRYPTKEY) hCryptKey, |
| KP_ALGID, |
| (LPBYTE) &keyProviderInfo.dwKeySpec, |
| &dwDataLen, |
| 0)) { |
| |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| // Set the key spec (using the algorithm ID). |
| switch (keyProviderInfo.dwKeySpec) { |
| case CALG_RSA_KEYX: |
| case CALG_DH_SF: |
| keyProviderInfo.dwKeySpec = AT_KEYEXCHANGE; |
| break; |
| |
| case CALG_RSA_SIGN: |
| case CALG_DSS_SIGN: |
| keyProviderInfo.dwKeySpec = AT_SIGNATURE; |
| break; |
| |
| default: |
| ThrowException(env, KEYSTORE_EXCEPTION, NTE_BAD_ALGID); |
| __leave; |
| } |
| |
| if (! ::CertSetCertificateContextProperty(pCertContext, |
| CERT_KEY_PROV_INFO_PROP_ID, 0, &keyProviderInfo)) { |
| |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| } |
| |
| // Import encoded certificate |
| if (!::CertAddCertificateContextToStore(hCertStore, pCertContext, |
| CERT_STORE_ADD_REPLACE_EXISTING, NULL)) |
| { |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| } |
| __finally |
| { |
| //-------------------------------------------------------------------- |
| // Clean up. |
| |
| if (hCertStore) |
| ::CertCloseStore(hCertStore, 0); |
| |
| if (pszCertStoreName) |
| env->ReleaseStringUTFChars(jCertStoreName, pszCertStoreName); |
| |
| if (pbCertEncoding) |
| delete [] pbCertEncoding; |
| |
| if (pszCertAliasName) |
| delete [] pszCertAliasName; |
| |
| if (pszContainerName) |
| delete [] pszContainerName; |
| |
| if (pwszContainerName) |
| delete [] pwszContainerName; |
| |
| if (pszProviderName) |
| delete [] pszProviderName; |
| |
| if (pwszProviderName) |
| delete [] pwszProviderName; |
| |
| if (pCertContext) |
| ::CertFreeCertificateContext(pCertContext); |
| } |
| } |
| |
| /* |
| * Class: sun_security_mscapi_KeyStore |
| * Method: removeCertificate |
| * Signature: (Ljava/lang/String;Ljava/lang/String;[BI)V |
| */ |
| JNIEXPORT void JNICALL Java_sun_security_mscapi_KeyStore_removeCertificate |
| (JNIEnv *env, jobject obj, jstring jCertStoreName, jstring jCertAliasName, |
| jbyteArray jCertEncoding, jint jCertEncodingSize) { |
| |
| const char* pszCertStoreName = NULL; |
| const char* pszCertAliasName = NULL; |
| HCERTSTORE hCertStore = NULL; |
| PCCERT_CONTEXT pCertContext = NULL; |
| PCCERT_CONTEXT pTBDCertContext = NULL; |
| jbyte* pbCertEncoding = NULL; |
| DWORD cchNameString = 0; |
| char* pszNameString = NULL; // certificate's friendly name |
| BOOL bDeleteAttempted = FALSE; |
| |
| __try |
| { |
| // Open a system certificate store. |
| if ((pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL)) |
| == NULL) { |
| __leave; |
| } |
| if ((hCertStore = ::CertOpenSystemStore(NULL, pszCertStoreName)) == NULL) { |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Copy encoding from Java to native buffer |
| pbCertEncoding = new (env) jbyte[jCertEncodingSize]; |
| if (pbCertEncoding == NULL) { |
| __leave; |
| } |
| env->GetByteArrayRegion(jCertEncoding, 0, jCertEncodingSize, pbCertEncoding); |
| |
| // Create a certificate context from the encoded cert |
| if (!(pCertContext = ::CertCreateCertificateContext(X509_ASN_ENCODING, |
| (BYTE*) pbCertEncoding, jCertEncodingSize))) { |
| |
| ThrowException(env, CERTIFICATE_PARSING_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Find the certificate to be deleted |
| if (!(pTBDCertContext = ::CertFindCertificateInStore(hCertStore, |
| X509_ASN_ENCODING, 0, CERT_FIND_EXISTING, pCertContext, NULL))) { |
| |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Check that its friendly name matches the supplied alias |
| if ((cchNameString = ::CertGetNameString(pTBDCertContext, |
| CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, NULL, 0)) > 1) { |
| |
| pszNameString = new (env) char[cchNameString]; |
| if (pszNameString == NULL) { |
| __leave; |
| } |
| |
| ::CertGetNameString(pTBDCertContext, |
| CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, pszNameString, |
| cchNameString); |
| |
| // Compare the certificate's friendly name with supplied alias name |
| if ((pszCertAliasName = env->GetStringUTFChars(jCertAliasName, NULL)) |
| == NULL) { |
| __leave; |
| } |
| if (strcmp(pszCertAliasName, pszNameString) == 0) { |
| |
| // Only delete the certificate if the alias names matches |
| if (! ::CertDeleteCertificateFromStore(pTBDCertContext)) { |
| |
| // pTBDCertContext is always freed by the |
| // CertDeleteCertificateFromStore method |
| bDeleteAttempted = TRUE; |
| |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| } |
| } |
| |
| } |
| __finally |
| { |
| //-------------------------------------------------------------------- |
| // Clean up. |
| |
| if (hCertStore) |
| ::CertCloseStore(hCertStore, 0); |
| |
| if (pszCertStoreName) |
| env->ReleaseStringUTFChars(jCertStoreName, pszCertStoreName); |
| |
| if (pszCertAliasName) |
| env->ReleaseStringUTFChars(jCertAliasName, pszCertAliasName); |
| |
| if (pbCertEncoding) |
| delete [] pbCertEncoding; |
| |
| if (pszNameString) |
| delete [] pszNameString; |
| |
| if (pCertContext) |
| ::CertFreeCertificateContext(pCertContext); |
| |
| if (bDeleteAttempted && pTBDCertContext) |
| ::CertFreeCertificateContext(pTBDCertContext); |
| } |
| } |
| |
| /* |
| * Class: sun_security_mscapi_KeyStore |
| * Method: destroyKeyContainer |
| * Signature: (Ljava/lang/String;)V |
| */ |
| JNIEXPORT void JNICALL Java_sun_security_mscapi_KeyStore_destroyKeyContainer |
| (JNIEnv *env, jclass clazz, jstring keyContainerName) |
| { |
| HCRYPTPROV hCryptProv = NULL; |
| const char* pszKeyContainerName = NULL; |
| |
| __try |
| { |
| if ((pszKeyContainerName = |
| env->GetStringUTFChars(keyContainerName, NULL)) == NULL) { |
| __leave; |
| } |
| |
| // Destroying the default key container is not permitted |
| // (because it may contain more one keypair). |
| if (pszKeyContainerName == NULL) { |
| |
| ThrowException(env, KEYSTORE_EXCEPTION, NTE_BAD_KEYSET_PARAM); |
| __leave; |
| } |
| |
| // Acquire a CSP context (to the key container). |
| if (::CryptAcquireContext( |
| &hCryptProv, |
| pszKeyContainerName, |
| NULL, |
| PROV_RSA_FULL, |
| CRYPT_DELETEKEYSET) == FALSE) |
| { |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| } |
| __finally |
| { |
| //-------------------------------------------------------------------- |
| // Clean up. |
| |
| if (pszKeyContainerName) |
| env->ReleaseStringUTFChars(keyContainerName, pszKeyContainerName); |
| } |
| } |
| |
| |
| |
| |
| /* |
| * Class: sun_security_mscapi_RSACipher |
| * Method: findCertificateUsingAlias |
| * Signature: (Ljava/lang/String;Ljava/lang/String;)J |
| */ |
| JNIEXPORT jlong JNICALL Java_sun_security_mscapi_RSACipher_findCertificateUsingAlias |
| (JNIEnv *env, jobject obj, jstring jCertStoreName, jstring jCertAliasName) |
| { |
| const char* pszCertStoreName = NULL; |
| const char* pszCertAliasName = NULL; |
| HCERTSTORE hCertStore = NULL; |
| PCCERT_CONTEXT pCertContext = NULL; |
| char* pszNameString = NULL; // certificate's friendly name |
| DWORD cchNameString = 0; |
| |
| __try |
| { |
| if ((pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL)) |
| == NULL) { |
| __leave; |
| } |
| if ((pszCertAliasName = env->GetStringUTFChars(jCertAliasName, NULL)) |
| == NULL) { |
| __leave; |
| } |
| |
| // Open a system certificate store. |
| if ((hCertStore = ::CertOpenSystemStore(NULL, pszCertStoreName)) == NULL) { |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Use CertEnumCertificatesInStore to get the certificates |
| // from the open store. pCertContext must be reset to |
| // NULL to retrieve the first certificate in the store. |
| while (pCertContext = ::CertEnumCertificatesInStore(hCertStore, pCertContext)) |
| { |
| if ((cchNameString = ::CertGetNameString(pCertContext, |
| CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, NULL, 0)) == 1) { |
| |
| continue; // not found |
| } |
| |
| pszNameString = new (env) char[cchNameString]; |
| if (pszNameString == NULL) { |
| __leave; |
| } |
| |
| if (::CertGetNameString(pCertContext, |
| CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, pszNameString, |
| cchNameString) == 1) { |
| |
| continue; // not found |
| } |
| |
| // Compare the certificate's friendly name with supplied alias name |
| if (strcmp(pszCertAliasName, pszNameString) == 0) { |
| delete [] pszNameString; |
| break; |
| |
| } else { |
| delete [] pszNameString; |
| } |
| } |
| } |
| __finally |
| { |
| if (hCertStore) |
| ::CertCloseStore(hCertStore, 0); |
| |
| if (pszCertStoreName) |
| env->ReleaseStringUTFChars(jCertStoreName, pszCertStoreName); |
| |
| if (pszCertAliasName) |
| env->ReleaseStringUTFChars(jCertAliasName, pszCertAliasName); |
| } |
| |
| return (jlong) pCertContext; |
| } |
| |
| /* |
| * Class: sun_security_mscapi_RSACipher |
| * Method: getKeyFromCert |
| * Signature: (JZ)J |
| */ |
| JNIEXPORT jlong JNICALL Java_sun_security_mscapi_RSACipher_getKeyFromCert |
| (JNIEnv *env, jobject obj, jlong pCertContext, jboolean usePrivateKey) |
| { |
| HCRYPTPROV hCryptProv = NULL; |
| HCRYPTKEY hKey = NULL; |
| DWORD dwKeySpec; |
| BOOL bCallerFreeProv = FALSE; |
| BOOL bRes; |
| |
| __try |
| { |
| if (usePrivateKey == JNI_TRUE) { |
| // Locate the key container for the certificate's private key |
| |
| // First, probe it silently |
| bRes = ::CryptAcquireCertificatePrivateKey( |
| (PCCERT_CONTEXT) pCertContext, CRYPT_ACQUIRE_SILENT_FLAG, |
| NULL, &hCryptProv, &dwKeySpec, &bCallerFreeProv); |
| |
| if (bRes == FALSE && GetLastError() != NTE_SILENT_CONTEXT) |
| { |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| if (bCallerFreeProv == TRUE) { |
| ::CryptReleaseContext(hCryptProv, NULL); |
| bCallerFreeProv = FALSE; |
| } |
| |
| // Now, do it normally (not silently) |
| if (::CryptAcquireCertificatePrivateKey( |
| (PCCERT_CONTEXT) pCertContext, 0, NULL, &hCryptProv, |
| &dwKeySpec, &bCallerFreeProv) == FALSE) |
| { |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Get a handle to the private key |
| if (::CryptGetUserKey(hCryptProv, dwKeySpec, &hKey) == FALSE) { |
| ThrowException(env, KEY_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| } |
| else // use public key |
| { |
| bCallerFreeProv = TRUE; |
| |
| // Acquire a CSP context. |
| if (::CryptAcquireContext(&hCryptProv, "J2SE", NULL, |
| PROV_RSA_FULL, 0) == FALSE) |
| { |
| // If CSP context hasn't been created, create one. |
| // |
| if (::CryptAcquireContext(&hCryptProv, "J2SE", NULL, |
| PROV_RSA_FULL, CRYPT_NEWKEYSET) == FALSE) |
| { |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| } |
| |
| // Import the certificate's public key into the key container |
| if (::CryptImportPublicKeyInfo(hCryptProv, X509_ASN_ENCODING, |
| &(((PCCERT_CONTEXT) pCertContext)->pCertInfo->SubjectPublicKeyInfo), |
| &hKey) == FALSE) |
| { |
| ThrowException(env, KEY_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| } |
| } |
| __finally |
| { |
| //-------------------------------------------------------------------- |
| // Clean up. |
| |
| if (bCallerFreeProv == TRUE && hCryptProv != NULL) |
| ::CryptReleaseContext(hCryptProv, 0); |
| } |
| |
| return hKey; // TODO - when finished with this key, call |
| // CryptDestroyKey(hKey) |
| } |
| |
| /* |
| * Class: sun_security_mscapi_KeyStore |
| * Method: getKeyLength |
| * Signature: (J)I |
| */ |
| JNIEXPORT jint JNICALL Java_sun_security_mscapi_KeyStore_getKeyLength |
| (JNIEnv *env, jobject obj, jlong hKey) |
| { |
| DWORD dwDataLen = sizeof(DWORD); |
| BYTE pbData[sizeof(DWORD)]; |
| DWORD length = 0; |
| |
| __try |
| { |
| // Get key length (in bits) |
| //TODO - may need to use KP_BLOCKLEN instead? |
| if (!(::CryptGetKeyParam((HCRYPTKEY) hKey, KP_KEYLEN, (BYTE *)pbData, &dwDataLen, |
| 0))) { |
| |
| ThrowException(env, KEY_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| length = (DWORD) pbData; |
| } |
| __finally |
| { |
| // no cleanup required |
| } |
| |
| return (jint) length; |
| } |
| |
| /* |
| * Class: sun_security_mscapi_RSACipher |
| * Method: encryptDecrypt |
| * Signature: ([BIJZ)[B |
| */ |
| JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_RSACipher_encryptDecrypt |
| (JNIEnv *env, jclass clazz, jbyteArray jData, jint jDataSize, jlong hKey, |
| jboolean doEncrypt) |
| { |
| jbyteArray result = NULL; |
| jbyte* pData = NULL; |
| DWORD dwDataLen = jDataSize; |
| DWORD dwBufLen = env->GetArrayLength(jData); |
| DWORD i; |
| BYTE tmp; |
| |
| __try |
| { |
| // Copy data from Java buffer to native buffer |
| pData = new (env) jbyte[dwBufLen]; |
| if (pData == NULL) { |
| __leave; |
| } |
| env->GetByteArrayRegion(jData, 0, dwBufLen, pData); |
| |
| if (doEncrypt == JNI_TRUE) { |
| // encrypt |
| if (! ::CryptEncrypt((HCRYPTKEY) hKey, 0, TRUE, 0, (BYTE *)pData, |
| &dwDataLen, dwBufLen)) { |
| |
| ThrowException(env, KEY_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| dwBufLen = dwDataLen; |
| |
| // convert from little-endian |
| for (i = 0; i < dwBufLen / 2; i++) { |
| tmp = pData[i]; |
| pData[i] = pData[dwBufLen - i -1]; |
| pData[dwBufLen - i - 1] = tmp; |
| } |
| } else { |
| // convert to little-endian |
| for (i = 0; i < dwBufLen / 2; i++) { |
| tmp = pData[i]; |
| pData[i] = pData[dwBufLen - i -1]; |
| pData[dwBufLen - i - 1] = tmp; |
| } |
| |
| // decrypt |
| if (! ::CryptDecrypt((HCRYPTKEY) hKey, 0, TRUE, 0, (BYTE *)pData, |
| &dwBufLen)) { |
| |
| ThrowException(env, KEY_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| } |
| |
| // Create new byte array |
| result = env->NewByteArray(dwBufLen); |
| |
| // Copy data from native buffer to Java buffer |
| env->SetByteArrayRegion(result, 0, dwBufLen, (jbyte*) pData); |
| } |
| __finally |
| { |
| if (pData) |
| delete [] pData; |
| } |
| |
| return result; |
| } |
| |
| /* |
| * Class: sun_security_mscapi_RSAPublicKey |
| * Method: getPublicKeyBlob |
| * Signature: (J)[B |
| */ |
| JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_RSAPublicKey_getPublicKeyBlob |
| (JNIEnv *env, jclass clazz, jlong hCryptKey) { |
| |
| jbyteArray blob = NULL; |
| DWORD dwBlobLen; |
| BYTE* pbKeyBlob = NULL; |
| |
| __try |
| { |
| |
| // Determine the size of the blob |
| if (! ::CryptExportKey((HCRYPTKEY) hCryptKey, 0, PUBLICKEYBLOB, 0, NULL, |
| &dwBlobLen)) { |
| |
| ThrowException(env, KEY_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| pbKeyBlob = new (env) BYTE[dwBlobLen]; |
| if (pbKeyBlob == NULL) { |
| __leave; |
| } |
| |
| // Generate key blob |
| if (! ::CryptExportKey((HCRYPTKEY) hCryptKey, 0, PUBLICKEYBLOB, 0, |
| pbKeyBlob, &dwBlobLen)) { |
| |
| ThrowException(env, KEY_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Create new byte array |
| blob = env->NewByteArray(dwBlobLen); |
| |
| // Copy data from native buffer to Java buffer |
| env->SetByteArrayRegion(blob, 0, dwBlobLen, (jbyte*) pbKeyBlob); |
| } |
| __finally |
| { |
| if (pbKeyBlob) |
| delete [] pbKeyBlob; |
| } |
| |
| return blob; |
| } |
| |
| /* |
| * Class: sun_security_mscapi_RSAPublicKey |
| * Method: getExponent |
| * Signature: ([B)[B |
| */ |
| JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_RSAPublicKey_getExponent |
| (JNIEnv *env, jclass clazz, jbyteArray jKeyBlob) { |
| |
| jbyteArray exponent = NULL; |
| jbyte* exponentBytes = NULL; |
| jbyte* keyBlob = NULL; |
| |
| __try { |
| |
| jsize length = env->GetArrayLength(jKeyBlob); |
| if ((keyBlob = env->GetByteArrayElements(jKeyBlob, 0)) == NULL) { |
| __leave; |
| } |
| |
| PUBLICKEYSTRUC* pPublicKeyStruc = (PUBLICKEYSTRUC *) keyBlob; |
| |
| // Check BLOB type |
| if (pPublicKeyStruc->bType != PUBLICKEYBLOB) { |
| ThrowException(env, KEY_EXCEPTION, NTE_BAD_TYPE); |
| __leave; |
| } |
| |
| RSAPUBKEY* pRsaPubKey = |
| (RSAPUBKEY *) (keyBlob + sizeof(PUBLICKEYSTRUC)); |
| |
| int len = sizeof(pRsaPubKey->pubexp); |
| exponentBytes = new (env) jbyte[len]; |
| if (exponentBytes == NULL) { |
| __leave; |
| } |
| |
| // convert from little-endian while copying from blob |
| for (int i = 0, j = len - 1; i < len; i++, j--) { |
| exponentBytes[i] = ((BYTE*) &pRsaPubKey->pubexp)[j]; |
| } |
| |
| exponent = env->NewByteArray(len); |
| env->SetByteArrayRegion(exponent, 0, len, exponentBytes); |
| } |
| __finally |
| { |
| if (keyBlob) |
| env->ReleaseByteArrayElements(jKeyBlob, keyBlob, JNI_ABORT); |
| |
| if (exponentBytes) |
| delete [] exponentBytes; |
| } |
| |
| return exponent; |
| } |
| |
| /* |
| * Class: sun_security_mscapi_RSAPublicKey |
| * Method: getModulus |
| * Signature: ([B)[B |
| */ |
| JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_RSAPublicKey_getModulus |
| (JNIEnv *env, jclass clazz, jbyteArray jKeyBlob) { |
| |
| jbyteArray modulus = NULL; |
| jbyte* modulusBytes = NULL; |
| jbyte* keyBlob = NULL; |
| |
| __try { |
| |
| jsize length = env->GetArrayLength(jKeyBlob); |
| if ((keyBlob = env->GetByteArrayElements(jKeyBlob, 0)) == NULL) { |
| __leave; |
| } |
| |
| PUBLICKEYSTRUC* pPublicKeyStruc = (PUBLICKEYSTRUC *) keyBlob; |
| |
| // Check BLOB type |
| if (pPublicKeyStruc->bType != PUBLICKEYBLOB) { |
| ThrowException(env, KEY_EXCEPTION, NTE_BAD_TYPE); |
| __leave; |
| } |
| |
| RSAPUBKEY* pRsaPubKey = |
| (RSAPUBKEY *) (keyBlob + sizeof(PUBLICKEYSTRUC)); |
| |
| int len = pRsaPubKey->bitlen / 8; |
| modulusBytes = new (env) jbyte[len]; |
| if (modulusBytes == NULL) { |
| __leave; |
| } |
| BYTE * pbModulus = |
| (BYTE *) (keyBlob + sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY)); |
| |
| // convert from little-endian while copying from blob |
| for (int i = 0, j = len - 1; i < len; i++, j--) { |
| modulusBytes[i] = pbModulus[j]; |
| } |
| |
| modulus = env->NewByteArray(len); |
| env->SetByteArrayRegion(modulus, 0, len, modulusBytes); |
| } |
| __finally |
| { |
| if (keyBlob) |
| env->ReleaseByteArrayElements(jKeyBlob, keyBlob, JNI_ABORT); |
| |
| if (modulusBytes) |
| delete [] modulusBytes; |
| } |
| |
| return modulus; |
| } |
| |
| /* |
| * Convert an array in big-endian byte order into little-endian byte order. |
| */ |
| int convertToLittleEndian(JNIEnv *env, jbyteArray source, jbyte* destination, |
| int destinationLength) { |
| |
| int sourceLength = env->GetArrayLength(source); |
| |
| jbyte* sourceBytes = env->GetByteArrayElements(source, 0); |
| if (sourceBytes == NULL) { |
| return -1; |
| } |
| |
| int copyLen = sourceLength; |
| if (sourceLength > destinationLength) { |
| // source might include an extra sign byte |
| if (sourceLength == destinationLength + 1 && sourceBytes[0] == 0) { |
| copyLen--; |
| } else { |
| return -1; |
| } |
| } |
| |
| // Copy bytes from the end of the source array to the beginning of the |
| // destination array (until the destination array is full). |
| // This ensures that the sign byte from the source array will be excluded. |
| for (int i = 0; i < copyLen; i++) { |
| destination[i] = sourceBytes[sourceLength - 1 - i]; |
| } |
| if (copyLen < destinationLength) { |
| memset(destination + copyLen, 0, destinationLength - copyLen); |
| } |
| |
| env->ReleaseByteArrayElements(source, sourceBytes, JNI_ABORT); |
| |
| return destinationLength; |
| } |
| |
| /* |
| * The Microsoft Base Cryptographic Provider supports public-key BLOBs |
| * that have the following format: |
| * |
| * PUBLICKEYSTRUC publickeystruc; |
| * RSAPUBKEY rsapubkey; |
| * BYTE modulus[rsapubkey.bitlen/8]; |
| * |
| * and private-key BLOBs that have the following format: |
| * |
| * PUBLICKEYSTRUC publickeystruc; |
| * RSAPUBKEY rsapubkey; |
| * BYTE modulus[rsapubkey.bitlen/8]; |
| * BYTE prime1[rsapubkey.bitlen/16]; |
| * BYTE prime2[rsapubkey.bitlen/16]; |
| * BYTE exponent1[rsapubkey.bitlen/16]; |
| * BYTE exponent2[rsapubkey.bitlen/16]; |
| * BYTE coefficient[rsapubkey.bitlen/16]; |
| * BYTE privateExponent[rsapubkey.bitlen/8]; |
| * |
| * This method generates such BLOBs from the key elements supplied. |
| */ |
| jbyteArray generateKeyBlob( |
| JNIEnv *env, |
| jint jKeyBitLength, |
| jbyteArray jModulus, |
| jbyteArray jPublicExponent, |
| jbyteArray jPrivateExponent, |
| jbyteArray jPrimeP, |
| jbyteArray jPrimeQ, |
| jbyteArray jExponentP, |
| jbyteArray jExponentQ, |
| jbyteArray jCrtCoefficient) |
| { |
| jsize jKeyByteLength = jKeyBitLength / 8; |
| jsize jBlobLength; |
| BOOL bGeneratePrivateKeyBlob; |
| |
| // Determine whether to generate a public-key or a private-key BLOB |
| if (jPrivateExponent != NULL && |
| jPrimeP != NULL && |
| jPrimeQ != NULL && |
| jExponentP != NULL && |
| jExponentQ != NULL && |
| jCrtCoefficient != NULL) { |
| |
| bGeneratePrivateKeyBlob = TRUE; |
| jBlobLength = sizeof(BLOBHEADER) + |
| sizeof(RSAPUBKEY) + |
| ((jKeyBitLength / 8) * 4) + |
| (jKeyBitLength / 16); |
| |
| } else { |
| bGeneratePrivateKeyBlob = FALSE; |
| jBlobLength = sizeof(BLOBHEADER) + |
| sizeof(RSAPUBKEY) + |
| (jKeyBitLength / 8); |
| } |
| |
| jbyte* jBlobBytes = NULL; |
| jbyte* jBlobElement; |
| jbyteArray jBlob = NULL; |
| jsize jElementLength; |
| |
| __try { |
| jBlobBytes = new (env) jbyte[jBlobLength]; |
| if (jBlobBytes == NULL) { |
| __leave; |
| } |
| |
| BLOBHEADER *pBlobHeader = (BLOBHEADER *) jBlobBytes; |
| if (bGeneratePrivateKeyBlob) { |
| pBlobHeader->bType = PRIVATEKEYBLOB; // 0x07 |
| } else { |
| pBlobHeader->bType = PUBLICKEYBLOB; // 0x06 |
| } |
| pBlobHeader->bVersion = CUR_BLOB_VERSION; // 0x02 |
| pBlobHeader->reserved = 0; // 0x0000 |
| pBlobHeader->aiKeyAlg = CALG_RSA_KEYX; // 0x0000a400 |
| |
| RSAPUBKEY *pRsaPubKey = |
| (RSAPUBKEY *) (jBlobBytes + sizeof(PUBLICKEYSTRUC)); |
| if (bGeneratePrivateKeyBlob) { |
| pRsaPubKey->magic = 0x32415352; // "RSA2" |
| } else { |
| pRsaPubKey->magic = 0x31415352; // "RSA1" |
| } |
| pRsaPubKey->bitlen = jKeyBitLength; |
| pRsaPubKey->pubexp = 0; // init |
| |
| // Sanity check |
| jsize jPublicExponentLength = env->GetArrayLength(jPublicExponent); |
| if (jPublicExponentLength > sizeof(pRsaPubKey->pubexp)) { |
| ThrowException(env, INVALID_KEY_EXCEPTION, NTE_BAD_TYPE); |
| __leave; |
| } |
| // The length argument must be the smaller of jPublicExponentLength |
| // and sizeof(pRsaPubKey->pubkey) |
| if ((jElementLength = convertToLittleEndian(env, jPublicExponent, |
| (jbyte *) &(pRsaPubKey->pubexp), jPublicExponentLength)) < 0) { |
| __leave; |
| } |
| |
| // Modulus n |
| jBlobElement = |
| (jbyte *) (jBlobBytes + sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY)); |
| if ((jElementLength = convertToLittleEndian(env, jModulus, jBlobElement, |
| jKeyByteLength)) < 0) { |
| __leave; |
| } |
| |
| if (bGeneratePrivateKeyBlob) { |
| // Prime p |
| jBlobElement += jElementLength; |
| if ((jElementLength = convertToLittleEndian(env, jPrimeP, |
| jBlobElement, jKeyByteLength / 2)) < 0) { |
| __leave; |
| } |
| |
| // Prime q |
| jBlobElement += jElementLength; |
| if ((jElementLength = convertToLittleEndian(env, jPrimeQ, |
| jBlobElement, jKeyByteLength / 2)) < 0) { |
| __leave; |
| } |
| |
| // Prime exponent p |
| jBlobElement += jElementLength; |
| if ((jElementLength = convertToLittleEndian(env, jExponentP, |
| jBlobElement, jKeyByteLength / 2)) < 0) { |
| __leave; |
| } |
| |
| // Prime exponent q |
| jBlobElement += jElementLength; |
| if ((jElementLength = convertToLittleEndian(env, jExponentQ, |
| jBlobElement, jKeyByteLength / 2)) < 0) { |
| __leave; |
| } |
| |
| // CRT coefficient |
| jBlobElement += jElementLength; |
| if ((jElementLength = convertToLittleEndian(env, jCrtCoefficient, |
| jBlobElement, jKeyByteLength / 2)) < 0) { |
| __leave; |
| } |
| |
| // Private exponent |
| jBlobElement += jElementLength; |
| if ((jElementLength = convertToLittleEndian(env, jPrivateExponent, |
| jBlobElement, jKeyByteLength)) < 0) { |
| __leave; |
| } |
| } |
| |
| jBlob = env->NewByteArray(jBlobLength); |
| env->SetByteArrayRegion(jBlob, 0, jBlobLength, jBlobBytes); |
| |
| } |
| __finally |
| { |
| if (jBlobBytes) |
| delete [] jBlobBytes; |
| } |
| |
| return jBlob; |
| } |
| |
| /* |
| * Class: sun_security_mscapi_KeyStore |
| * Method: generatePrivateKeyBlob |
| * Signature: (I[B[B[B[B[B[B[B[B)[B |
| */ |
| JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_KeyStore_generatePrivateKeyBlob |
| (JNIEnv *env, jclass clazz, |
| jint jKeyBitLength, |
| jbyteArray jModulus, |
| jbyteArray jPublicExponent, |
| jbyteArray jPrivateExponent, |
| jbyteArray jPrimeP, |
| jbyteArray jPrimeQ, |
| jbyteArray jExponentP, |
| jbyteArray jExponentQ, |
| jbyteArray jCrtCoefficient) |
| { |
| return generateKeyBlob(env, jKeyBitLength, jModulus, jPublicExponent, |
| jPrivateExponent, jPrimeP, jPrimeQ, jExponentP, jExponentQ, |
| jCrtCoefficient); |
| } |
| |
| /* |
| * Class: sun_security_mscapi_RSASignature |
| * Method: generatePublicKeyBlob |
| * Signature: (I[B[B)[B |
| */ |
| JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_RSASignature_generatePublicKeyBlob |
| (JNIEnv *env, jclass clazz, |
| jint jKeyBitLength, |
| jbyteArray jModulus, |
| jbyteArray jPublicExponent) |
| { |
| return generateKeyBlob(env, jKeyBitLength, jModulus, jPublicExponent, |
| NULL, NULL, NULL, NULL, NULL, NULL); |
| } |
| |
| /* |
| * Class: sun_security_mscapi_KeyStore |
| * Method: storePrivateKey |
| * Signature: ([BLjava/lang/String;I)Lsun/security/mscapi/RSAPrivateKey; |
| */ |
| JNIEXPORT jobject JNICALL Java_sun_security_mscapi_KeyStore_storePrivateKey |
| (JNIEnv *env, jclass clazz, jbyteArray keyBlob, jstring keyContainerName, |
| jint keySize) |
| { |
| HCRYPTPROV hCryptProv = NULL; |
| HCRYPTKEY hKey = NULL; |
| DWORD dwBlobLen; |
| BYTE * pbKeyBlob = NULL; |
| const char* pszKeyContainerName = NULL; // UUID |
| jobject privateKey = NULL; |
| |
| __try |
| { |
| if ((pszKeyContainerName = |
| env->GetStringUTFChars(keyContainerName, NULL)) == NULL) { |
| __leave; |
| } |
| dwBlobLen = env->GetArrayLength(keyBlob); |
| if ((pbKeyBlob = (BYTE *) env->GetByteArrayElements(keyBlob, 0)) |
| == NULL) { |
| __leave; |
| } |
| |
| // Acquire a CSP context (create a new key container). |
| if (::CryptAcquireContext( |
| &hCryptProv, |
| pszKeyContainerName, |
| NULL, |
| PROV_RSA_FULL, |
| CRYPT_NEWKEYSET) == FALSE) |
| { |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Import the private key |
| if (::CryptImportKey( |
| hCryptProv, |
| pbKeyBlob, |
| dwBlobLen, |
| 0, |
| CRYPT_EXPORTABLE, |
| &hKey) == FALSE) |
| { |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Get the method ID for the RSAPrivateKey constructor |
| jclass clazzRSAPrivateKey = |
| env->FindClass("sun/security/mscapi/RSAPrivateKey"); |
| if (clazzRSAPrivateKey == NULL) { |
| __leave; |
| } |
| |
| jmethodID mNewRSAPrivateKey = |
| env->GetMethodID(clazzRSAPrivateKey, "<init>", "(JJI)V"); |
| if (mNewRSAPrivateKey == NULL) { |
| __leave; |
| } |
| |
| // Create a new RSA private key |
| privateKey = env->NewObject(clazzRSAPrivateKey, mNewRSAPrivateKey, |
| (jlong) hCryptProv, (jlong) hKey, keySize); |
| |
| } |
| __finally |
| { |
| //-------------------------------------------------------------------- |
| // Clean up. |
| |
| if (pszKeyContainerName) |
| env->ReleaseStringUTFChars(keyContainerName, pszKeyContainerName); |
| |
| if (pbKeyBlob) |
| env->ReleaseByteArrayElements(keyBlob, (jbyte *) pbKeyBlob, |
| JNI_ABORT); |
| } |
| |
| return privateKey; |
| } |
| |
| /* |
| * Class: sun_security_mscapi_RSASignature |
| * Method: importPublicKey |
| * Signature: ([BI)Lsun/security/mscapi/RSAPublicKey; |
| */ |
| JNIEXPORT jobject JNICALL Java_sun_security_mscapi_RSASignature_importPublicKey |
| (JNIEnv *env, jclass clazz, jbyteArray keyBlob, jint keySize) |
| { |
| HCRYPTPROV hCryptProv = NULL; |
| HCRYPTKEY hKey = NULL; |
| DWORD dwBlobLen; |
| BYTE * pbKeyBlob = NULL; |
| jobject publicKey = NULL; |
| |
| __try |
| { |
| dwBlobLen = env->GetArrayLength(keyBlob); |
| if ((pbKeyBlob = (BYTE *) env->GetByteArrayElements(keyBlob, 0)) |
| == NULL) { |
| __leave; |
| } |
| |
| // Acquire a CSP context (create a new key container). |
| // Prefer a PROV_RSA_AES CSP, when available, due to its support |
| // for SHA-2-based signatures. |
| if (::CryptAcquireContext( |
| &hCryptProv, |
| NULL, |
| NULL, |
| PROV_RSA_AES, |
| CRYPT_VERIFYCONTEXT) == FALSE) |
| { |
| // Failover to using the default CSP (PROV_RSA_FULL) |
| |
| if (::CryptAcquireContext( |
| &hCryptProv, |
| NULL, |
| NULL, |
| PROV_RSA_FULL, |
| CRYPT_VERIFYCONTEXT) == FALSE) |
| { |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| } |
| |
| // Import the public key |
| if (::CryptImportKey( |
| hCryptProv, |
| pbKeyBlob, |
| dwBlobLen, |
| 0, |
| CRYPT_EXPORTABLE, |
| &hKey) == FALSE) |
| { |
| ThrowException(env, KEYSTORE_EXCEPTION, GetLastError()); |
| __leave; |
| } |
| |
| // Get the method ID for the RSAPublicKey constructor |
| jclass clazzRSAPublicKey = |
| env->FindClass("sun/security/mscapi/RSAPublicKey"); |
| if (clazzRSAPublicKey == NULL) { |
| __leave; |
| } |
| |
| jmethodID mNewRSAPublicKey = |
| env->GetMethodID(clazzRSAPublicKey, "<init>", "(JJI)V"); |
| if (mNewRSAPublicKey == NULL) { |
| __leave; |
| } |
| |
| // Create a new RSA public key |
| publicKey = env->NewObject(clazzRSAPublicKey, mNewRSAPublicKey, |
| (jlong) hCryptProv, (jlong) hKey, keySize); |
| |
| } |
| __finally |
| { |
| //-------------------------------------------------------------------- |
| // Clean up. |
| |
| if (pbKeyBlob) |
| env->ReleaseByteArrayElements(keyBlob, (jbyte *) pbKeyBlob, |
| JNI_ABORT); |
| } |
| |
| return publicKey; |
| } |
| |
| } /* extern "C" */ |