#include "winbase.h"
#include "winreg.h"
#include "wincrypt.h"
-#include "objbase.h"
#include "handle.h"
#include "implglue.h"
+#include "objbase.h"
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
HCRYPTHASH hHash
);
-BOOL WINAPI
-RSAENH_CPExportKey(
- HCRYPTPROV hProv,
- HCRYPTKEY hKey,
+static BOOL crypt_export_key(
+ CRYPTKEY *pCryptKey,
HCRYPTKEY hPubKey,
DWORD dwBlobType,
DWORD dwFlags,
+ BOOL force,
BYTE *pbData,
DWORD *pdwDataLen
);
-BOOL WINAPI
-RSAENH_CPImportKey(
+static BOOL import_key(
HCRYPTPROV hProv,
CONST BYTE *pbData,
DWORD dwDataLen,
HCRYPTKEY hPubKey,
DWORD dwFlags,
+ BOOL fStoreKey,
HCRYPTKEY *phKey
);
/******************************************************************************
* CSP's handle table (used by all acquired key containers)
*/
-static HANDLETABLE handle_table;
+static struct handle_table handle_table;
/******************************************************************************
* DllMain (RSAENH.@)
pbTemp = HeapAlloc(GetProcessHeap(), 0, dwDataLen);
if (!pbTemp) return;
memcpy(pbTemp, pbData, dwDataLen);
- RSAENH_CPEncrypt(pCryptHash->hProv, pCryptHash->hKey, (HCRYPTHASH)NULL, FALSE, 0,
+ RSAENH_CPEncrypt(pCryptHash->hProv, pCryptHash->hKey, 0, FALSE, 0,
pbTemp, &dwDataLen, dwDataLen);
HeapFree(GetProcessHeap(), 0, pbTemp);
break;
case CALG_MAC:
dwDataLen = 0;
- RSAENH_CPEncrypt(pCryptHash->hProv, pCryptHash->hKey, (HCRYPTHASH)NULL, TRUE, 0,
+ RSAENH_CPEncrypt(pCryptHash->hProv, pCryptHash->hKey, 0, TRUE, 0,
pCryptHash->abHashValue, &dwDataLen, pCryptHash->dwHashSize);
break;
* hProv [I] Handle to the provider to which the created key will belong.
* aiAlgid [I] The new key shall use the crypto algorithm idenfied by aiAlgid.
* dwFlags [I] Upper 16 bits give the key length.
- * Lower 16 bits: CRYPT_CREATE_SALT, CRYPT_NO_SALT
+ * Lower 16 bits: CRYPT_EXPORTABLE, CRYPT_CREATE_SALT,
+ * CRYPT_NO_SALT
* ppCryptKey [O] Pointer to the created key
*
* RETURNS
peaAlgidInfo = get_algid_info(hProv, aiAlgid);
if (!peaAlgidInfo) return (HCRYPTKEY)INVALID_HANDLE_VALUE;
+ TRACE("alg = %s, dwKeyLen = %d\n", debugstr_a(peaAlgidInfo->szName),
+ dwKeyLen);
/*
* Assume the default key length, if none is specified explicitly
*/
dwKeyLen > peaAlgidInfo->dwMaxLen ||
dwKeyLen < peaAlgidInfo->dwMinLen)
{
- SetLastError(NTE_BAD_FLAGS);
+ TRACE("key len %d out of bounds (%d, %d)\n", dwKeyLen,
+ peaAlgidInfo->dwMinLen, peaAlgidInfo->dwMaxLen);
+ SetLastError(NTE_BAD_DATA);
return (HCRYPTKEY)INVALID_HANDLE_VALUE;
}
}
pCryptKey->dwModeBits = 0;
pCryptKey->dwPermissions = CRYPT_ENCRYPT | CRYPT_DECRYPT | CRYPT_READ | CRYPT_WRITE |
CRYPT_MAC;
+ if (dwFlags & CRYPT_EXPORTABLE)
+ pCryptKey->dwPermissions |= CRYPT_EXPORT;
pCryptKey->dwKeyLen = dwKeyLen >> 3;
pCryptKey->dwEffectiveKeyLen = 0;
if ((dwFlags & CRYPT_CREATE_SALT) || (dwKeyLen == 40 && !(dwFlags & CRYPT_NO_SALT)))
return hCryptKey;
}
+/******************************************************************************
+ * map_key_spec_to_key_pair_name [Internal]
+ *
+ * Returns the name of the registry value associated with a key spec.
+ *
+ * PARAMS
+ * dwKeySpec [I] AT_KEYEXCHANGE or AT_SIGNATURE
+ *
+ * RETURNS
+ * Success: Name of registry value.
+ * Failure: NULL
+ */
+static LPCSTR map_key_spec_to_key_pair_name(DWORD dwKeySpec)
+{
+ LPCSTR szValueName;
+
+ switch (dwKeySpec)
+ {
+ case AT_KEYEXCHANGE:
+ szValueName = "KeyExchangeKeyPair";
+ break;
+ case AT_SIGNATURE:
+ szValueName = "SignatureKeyPair";
+ break;
+ default:
+ WARN("invalid key spec %d\n", dwKeySpec);
+ szValueName = NULL;
+ }
+ return szValueName;
+}
+
/******************************************************************************
* store_key_pair [Internal]
*
* PARAMS
* hCryptKey [I] Handle to the key to be stored
* hKey [I] Registry key where the key pair is to be stored
- * szValueName [I] Registry value where key pair's value is to be stored
+ * dwKeySpec [I] AT_KEYEXCHANGE or AT_SIGNATURE
* dwFlags [I] Flags for protecting the key
*/
-static void store_key_pair(HCRYPTKEY hCryptKey, HKEY hKey, LPCSTR szValueName, DWORD dwFlags)
+static void store_key_pair(HCRYPTKEY hCryptKey, HKEY hKey, DWORD dwKeySpec, DWORD dwFlags)
{
+ LPCSTR szValueName;
DATA_BLOB blobIn, blobOut;
CRYPTKEY *pKey;
DWORD dwLen;
BYTE *pbKey;
+ if (!(szValueName = map_key_spec_to_key_pair_name(dwKeySpec)))
+ return;
if (lookup_handle(&handle_table, hCryptKey, RSAENH_MAGIC_KEY,
(OBJECTHDR**)&pKey))
{
- if (RSAENH_CPExportKey(pKey->hProv, hCryptKey, 0, PRIVATEKEYBLOB, 0, 0,
- &dwLen))
+ if (crypt_export_key(pKey, 0, PRIVATEKEYBLOB, 0, TRUE, 0, &dwLen))
{
pbKey = HeapAlloc(GetProcessHeap(), 0, dwLen);
if (pbKey)
{
- if (RSAENH_CPExportKey(pKey->hProv, hCryptKey, 0,
- PRIVATEKEYBLOB, 0, pbKey, &dwLen))
+ if (crypt_export_key(pKey, 0, PRIVATEKEYBLOB, 0, TRUE, pbKey,
+ &dwLen))
{
blobIn.pbData = pbKey;
blobIn.cbData = dwLen;
HeapFree(GetProcessHeap(), 0, pbKey);
}
}
- release_handle(&handle_table, hCryptKey, RSAENH_MAGIC_KEY);
}
}
+/******************************************************************************
+ * map_key_spec_to_permissions_name [Internal]
+ *
+ * Returns the name of the registry value associated with the permissions for
+ * a key spec.
+ *
+ * PARAMS
+ * dwKeySpec [I] AT_KEYEXCHANGE or AT_SIGNATURE
+ *
+ * RETURNS
+ * Success: Name of registry value.
+ * Failure: NULL
+ */
+static LPCSTR map_key_spec_to_permissions_name(DWORD dwKeySpec)
+{
+ LPCSTR szValueName;
+
+ switch (dwKeySpec)
+ {
+ case AT_KEYEXCHANGE:
+ szValueName = "KeyExchangePermissions";
+ break;
+ case AT_SIGNATURE:
+ szValueName = "SignaturePermissions";
+ break;
+ default:
+ WARN("invalid key spec %d\n", dwKeySpec);
+ szValueName = NULL;
+ }
+ return szValueName;
+}
+
+/******************************************************************************
+ * store_key_permissions [Internal]
+ *
+ * Stores a key's permissions to the registry
+ *
+ * PARAMS
+ * hCryptKey [I] Handle to the key whose permissions are to be stored
+ * hKey [I] Registry key where the key permissions are to be stored
+ * dwKeySpec [I] AT_KEYEXCHANGE or AT_SIGNATURE
+ */
+static void store_key_permissions(HCRYPTKEY hCryptKey, HKEY hKey, DWORD dwKeySpec)
+{
+ LPCSTR szValueName;
+ CRYPTKEY *pKey;
+
+ if (!(szValueName = map_key_spec_to_permissions_name(dwKeySpec)))
+ return;
+ if (lookup_handle(&handle_table, hCryptKey, RSAENH_MAGIC_KEY,
+ (OBJECTHDR**)&pKey))
+ RegSetValueExA(hKey, szValueName, 0, REG_DWORD,
+ (BYTE *)&pKey->dwPermissions,
+ sizeof(pKey->dwPermissions));
+}
+
/******************************************************************************
* create_container_key [Internal]
*
if (create_container_key(pKeyContainer, KEY_WRITE, &hKey))
{
store_key_pair(pKeyContainer->hKeyExchangeKeyPair, hKey,
- "KeyExchangeKeyPair", dwFlags);
+ AT_KEYEXCHANGE, dwFlags);
store_key_pair(pKeyContainer->hSignatureKeyPair, hKey,
- "SignatureKeyPair", dwFlags);
+ AT_SIGNATURE, dwFlags);
+ RegCloseKey(hKey);
+ }
+}
+
+/******************************************************************************
+ * store_key_container_permissions [Internal]
+ *
+ * Stores key container's key permissions in a persistent location.
+ *
+ * PARAMS
+ * pKeyContainer [I] Pointer to the key container whose key permissions are to
+ * be saved
+ */
+static void store_key_container_permissions(KEYCONTAINER *pKeyContainer)
+{
+ HKEY hKey;
+ DWORD dwFlags;
+
+ /* On WinXP, persistent keys are stored in a file located at:
+ * $AppData$\\Microsoft\\Crypto\\RSA\\$SID$\\some_hex_string
+ */
+
+ if (pKeyContainer->dwFlags & CRYPT_MACHINE_KEYSET)
+ dwFlags = CRYPTPROTECT_LOCAL_MACHINE;
+ else
+ dwFlags = 0;
+
+ if (create_container_key(pKeyContainer, KEY_WRITE, &hKey))
+ {
+ store_key_permissions(pKeyContainer->hKeyExchangeKeyPair, hKey,
+ AT_KEYEXCHANGE);
+ store_key_permissions(pKeyContainer->hSignatureKeyPair, hKey,
+ AT_SIGNATURE);
RegCloseKey(hKey);
}
}
+/******************************************************************************
+ * release_key_container_keys [Internal]
+ *
+ * Releases key container's keys.
+ *
+ * PARAMS
+ * pKeyContainer [I] Pointer to the key container whose keys are to be released.
+ */
+static void release_key_container_keys(KEYCONTAINER *pKeyContainer)
+{
+ release_handle(&handle_table, pKeyContainer->hKeyExchangeKeyPair,
+ RSAENH_MAGIC_KEY);
+ release_handle(&handle_table, pKeyContainer->hSignatureKeyPair,
+ RSAENH_MAGIC_KEY);
+}
+
/******************************************************************************
* destroy_key_container [Internal]
*
KEYCONTAINER *pKeyContainer = (KEYCONTAINER*)pObjectHdr;
if (!(pKeyContainer->dwFlags & CRYPT_VERIFYCONTEXT))
+ {
store_key_container_keys(pKeyContainer);
+ store_key_container_permissions(pKeyContainer);
+ release_key_container_keys(pKeyContainer);
+ }
+ else
+ release_key_container_keys(pKeyContainer);
HeapFree( GetProcessHeap(), 0, pKeyContainer );
}
* PARAMS
* hKeyContainer [I] Crypt provider to use to import the key
* hKey [I] Registry key from which to read the key pair
- * szValueName [I] Registry value from which to read the key pair's value
+ * dwKeySpec [I] AT_KEYEXCHANGE or AT_SIGNATURE
* dwFlags [I] Flags for unprotecting the key
* phCryptKey [O] Returned key
*/
-static BOOL read_key_value(HCRYPTPROV hKeyContainer, HKEY hKey, LPCSTR szValueName, DWORD dwFlags, HCRYPTKEY *phCryptKey)
+static BOOL read_key_value(HCRYPTPROV hKeyContainer, HKEY hKey, DWORD dwKeySpec, DWORD dwFlags, HCRYPTKEY *phCryptKey)
{
+ LPCSTR szValueName;
DWORD dwValueType, dwLen;
BYTE *pbKey;
DATA_BLOB blobIn, blobOut;
BOOL ret = FALSE;
+ if (!(szValueName = map_key_spec_to_key_pair_name(dwKeySpec)))
+ return FALSE;
if (RegQueryValueExA(hKey, szValueName, 0, &dwValueType, NULL, &dwLen) ==
ERROR_SUCCESS)
{
if (CryptUnprotectData(&blobIn, NULL, NULL, NULL, NULL,
dwFlags, &blobOut))
{
- ret = RSAENH_CPImportKey(hKeyContainer, blobOut.pbData, blobOut.cbData, 0, 0,
- phCryptKey);
+ ret = import_key(hKeyContainer, blobOut.pbData, blobOut.cbData, 0, 0,
+ FALSE, phCryptKey);
LocalFree(blobOut.pbData);
}
}
HeapFree(GetProcessHeap(), 0, pbKey);
}
}
+ if (ret)
+ {
+ CRYPTKEY *pKey;
+
+ if (lookup_handle(&handle_table, *phCryptKey, RSAENH_MAGIC_KEY,
+ (OBJECTHDR**)&pKey))
+ {
+ if ((szValueName = map_key_spec_to_permissions_name(dwKeySpec)))
+ {
+ dwLen = sizeof(pKey->dwPermissions);
+ RegQueryValueExA(hKey, szValueName, 0, NULL,
+ (BYTE *)&pKey->dwPermissions, &dwLen);
+ }
+ }
+ }
return ret;
}
(OBJECTHDR**)&pKeyContainer))
return (HCRYPTPROV)INVALID_HANDLE_VALUE;
- if (read_key_value(hKeyContainer, hKey, "KeyExchangeKeyPair",
+ /* read_key_value calls import_key, which calls import_private_key,
+ * which implicitly installs the key value into the appropriate key
+ * container key. Thus the ref count is incremented twice, once for
+ * the output key value, and once for the implicit install, and needs
+ * to be decremented to balance the two.
+ */
+ if (read_key_value(hKeyContainer, hKey, AT_KEYEXCHANGE,
dwProtectFlags, &hCryptKey))
- pKeyContainer->hKeyExchangeKeyPair = hCryptKey;
- if (read_key_value(hKeyContainer, hKey, "SignatureKeyPair",
+ release_handle(&handle_table, hCryptKey, RSAENH_MAGIC_KEY);
+ if (read_key_value(hKeyContainer, hKey, AT_SIGNATURE,
dwProtectFlags, &hCryptKey))
- pKeyContainer->hSignatureKeyPair = hCryptKey;
+ release_handle(&handle_table, hCryptKey, RSAENH_MAGIC_KEY);
}
return hKeyContainer;
0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 } },
{ CALG_SHA, 15, { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 } },
- { 0, 0, {} }
+ { 0, 0, { 0 } }
};
DWORD dwIdxOID, i, j;
pCryptHash->hKey = hKey;
pCryptHash->hProv = hProv;
pCryptHash->dwState = RSAENH_HASHSTATE_HASHING;
- pCryptHash->pHMACInfo = (PHMAC_INFO)NULL;
+ pCryptHash->pHMACInfo = NULL;
pCryptHash->dwHashSize = peaAlgidInfo->dwDefaultLen >> 3;
init_data_blob(&pCryptHash->tpPRFParams.blobLabel);
init_data_blob(&pCryptHash->tpPRFParams.blobSeed);
if (Final) {
if (pbData[*pdwDataLen-1] &&
pbData[*pdwDataLen-1] <= pCryptKey->dwBlockLen &&
- pbData[*pdwDataLen-1] < *pdwDataLen) {
+ pbData[*pdwDataLen-1] <= *pdwDataLen) {
BOOL padOkay = TRUE;
/* check that every bad byte has the same value */
return TRUE;
}
+static BOOL crypt_export_simple(CRYPTKEY *pCryptKey, CRYPTKEY *pPubKey,
+ DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen)
+{
+ BLOBHEADER *pBlobHeader = (BLOBHEADER*)pbData;
+ ALG_ID *pAlgid = (ALG_ID*)(pBlobHeader+1);
+ DWORD dwDataLen;
+
+ if (!(GET_ALG_CLASS(pCryptKey->aiAlgid)&(ALG_CLASS_DATA_ENCRYPT|ALG_CLASS_MSG_ENCRYPT))) {
+ SetLastError(NTE_BAD_KEY); /* FIXME: error code? */
+ return FALSE;
+ }
+
+ dwDataLen = sizeof(BLOBHEADER) + sizeof(ALG_ID) + pPubKey->dwBlockLen;
+ if (pbData) {
+ if (*pdwDataLen < dwDataLen) {
+ SetLastError(ERROR_MORE_DATA);
+ *pdwDataLen = dwDataLen;
+ return FALSE;
+ }
+
+ pBlobHeader->bType = SIMPLEBLOB;
+ pBlobHeader->bVersion = CUR_BLOB_VERSION;
+ pBlobHeader->reserved = 0;
+ pBlobHeader->aiKeyAlg = pCryptKey->aiAlgid;
+
+ *pAlgid = pPubKey->aiAlgid;
+
+ if (!pad_data(pCryptKey->abKeyValue, pCryptKey->dwKeyLen, (BYTE*)(pAlgid+1),
+ pPubKey->dwBlockLen, dwFlags))
+ {
+ return FALSE;
+ }
+
+ encrypt_block_impl(pPubKey->aiAlgid, PK_PUBLIC, &pPubKey->context, (BYTE*)(pAlgid+1),
+ (BYTE*)(pAlgid+1), RSAENH_ENCRYPT);
+ }
+ *pdwDataLen = dwDataLen;
+ return TRUE;
+}
+
+static BOOL crypt_export_public_key(CRYPTKEY *pCryptKey, BYTE *pbData,
+ DWORD *pdwDataLen)
+{
+ BLOBHEADER *pBlobHeader = (BLOBHEADER*)pbData;
+ RSAPUBKEY *pRSAPubKey = (RSAPUBKEY*)(pBlobHeader+1);
+ DWORD dwDataLen;
+
+ if ((pCryptKey->aiAlgid != CALG_RSA_KEYX) && (pCryptKey->aiAlgid != CALG_RSA_SIGN)) {
+ SetLastError(NTE_BAD_KEY);
+ return FALSE;
+ }
+
+ dwDataLen = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + pCryptKey->dwKeyLen;
+ if (pbData) {
+ if (*pdwDataLen < dwDataLen) {
+ SetLastError(ERROR_MORE_DATA);
+ *pdwDataLen = dwDataLen;
+ return FALSE;
+ }
+
+ pBlobHeader->bType = PUBLICKEYBLOB;
+ pBlobHeader->bVersion = CUR_BLOB_VERSION;
+ pBlobHeader->reserved = 0;
+ pBlobHeader->aiKeyAlg = pCryptKey->aiAlgid;
+
+ pRSAPubKey->magic = RSAENH_MAGIC_RSA1;
+ pRSAPubKey->bitlen = pCryptKey->dwKeyLen << 3;
+
+ export_public_key_impl((BYTE*)(pRSAPubKey+1), &pCryptKey->context,
+ pCryptKey->dwKeyLen, &pRSAPubKey->pubexp);
+ }
+ *pdwDataLen = dwDataLen;
+ return TRUE;
+}
+
+static BOOL crypt_export_private_key(CRYPTKEY *pCryptKey, BOOL force,
+ BYTE *pbData, DWORD *pdwDataLen)
+{
+ BLOBHEADER *pBlobHeader = (BLOBHEADER*)pbData;
+ RSAPUBKEY *pRSAPubKey = (RSAPUBKEY*)(pBlobHeader+1);
+ DWORD dwDataLen;
+
+ if ((pCryptKey->aiAlgid != CALG_RSA_KEYX) && (pCryptKey->aiAlgid != CALG_RSA_SIGN)) {
+ SetLastError(NTE_BAD_KEY);
+ return FALSE;
+ }
+ if (!force && !(pCryptKey->dwPermissions & CRYPT_EXPORT))
+ {
+ SetLastError(NTE_BAD_KEY_STATE);
+ return FALSE;
+ }
+
+ dwDataLen = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
+ 2 * pCryptKey->dwKeyLen + 5 * ((pCryptKey->dwKeyLen + 1) >> 1);
+ if (pbData) {
+ if (*pdwDataLen < dwDataLen) {
+ SetLastError(ERROR_MORE_DATA);
+ *pdwDataLen = dwDataLen;
+ return FALSE;
+ }
+
+ pBlobHeader->bType = PRIVATEKEYBLOB;
+ pBlobHeader->bVersion = CUR_BLOB_VERSION;
+ pBlobHeader->reserved = 0;
+ pBlobHeader->aiKeyAlg = pCryptKey->aiAlgid;
+
+ pRSAPubKey->magic = RSAENH_MAGIC_RSA2;
+ pRSAPubKey->bitlen = pCryptKey->dwKeyLen << 3;
+
+ export_private_key_impl((BYTE*)(pRSAPubKey+1), &pCryptKey->context,
+ pCryptKey->dwKeyLen, &pRSAPubKey->pubexp);
+ }
+ *pdwDataLen = dwDataLen;
+ return TRUE;
+}
+
+static BOOL crypt_export_plaintext_key(CRYPTKEY *pCryptKey, BYTE *pbData,
+ DWORD *pdwDataLen)
+{
+ BLOBHEADER *pBlobHeader = (BLOBHEADER*)pbData;
+ DWORD *pKeyLen = (DWORD*)(pBlobHeader+1);
+ BYTE *pbKey = (BYTE*)(pKeyLen+1);
+ DWORD dwDataLen;
+
+ dwDataLen = sizeof(BLOBHEADER) + sizeof(DWORD) + pCryptKey->dwKeyLen;
+ if (pbData) {
+ if (*pdwDataLen < dwDataLen) {
+ SetLastError(ERROR_MORE_DATA);
+ *pdwDataLen = dwDataLen;
+ return FALSE;
+ }
+
+ pBlobHeader->bType = PLAINTEXTKEYBLOB;
+ pBlobHeader->bVersion = CUR_BLOB_VERSION;
+ pBlobHeader->reserved = 0;
+ pBlobHeader->aiKeyAlg = pCryptKey->aiAlgid;
+
+ *pKeyLen = pCryptKey->dwKeyLen;
+ memcpy(pbKey, &pCryptKey->abKeyValue, pCryptKey->dwKeyLen);
+ }
+ *pdwDataLen = dwDataLen;
+ return TRUE;
+}
/******************************************************************************
- * CPExportKey (RSAENH.@)
+ * crypt_export_key [Internal]
*
- * Export a key into a binary large object (BLOB).
+ * Export a key into a binary large object (BLOB). Called by CPExportKey and
+ * by store_key_pair.
*
* PARAMS
- * hProv [I] Key container from which a key is to be exported.
- * hKey [I] Key to be exported.
+ * pCryptKey [I] Key to be exported.
* hPubKey [I] Key used to encrypt sensitive BLOB data.
* dwBlobType [I] SIMPLEBLOB, PUBLICKEYBLOB or PRIVATEKEYBLOB.
* dwFlags [I] Currently none defined.
+ * force [I] If TRUE, the key is written no matter what the key's
+ * permissions are. Otherwise the key's permissions are
+ * checked before exporting.
* pbData [O] Pointer to a buffer where the BLOB will be written to.
* pdwDataLen [I/O] I: Size of buffer at pbData, O: Size of BLOB
*
* Success: TRUE.
* Failure: FALSE.
*/
-BOOL WINAPI RSAENH_CPExportKey(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTKEY hPubKey,
- DWORD dwBlobType, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen)
+static BOOL crypt_export_key(CRYPTKEY *pCryptKey, HCRYPTKEY hPubKey,
+ DWORD dwBlobType, DWORD dwFlags, BOOL force,
+ BYTE *pbData, DWORD *pdwDataLen)
{
- CRYPTKEY *pCryptKey, *pPubKey;
- BLOBHEADER *pBlobHeader = (BLOBHEADER*)pbData;
- RSAPUBKEY *pRSAPubKey = (RSAPUBKEY*)(pBlobHeader+1);
- ALG_ID *pAlgid = (ALG_ID*)(pBlobHeader+1);
- DWORD dwDataLen;
+ CRYPTKEY *pPubKey;
- TRACE("(hProv=%08lx, hKey=%08lx, hPubKey=%08lx, dwBlobType=%08x, dwFlags=%08x, pbData=%p,"
- "pdwDataLen=%p)\n", hProv, hKey, hPubKey, dwBlobType, dwFlags, pbData, pdwDataLen);
-
- if (!is_valid_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER))
- {
- SetLastError(NTE_BAD_UID);
- return FALSE;
- }
-
- if (!lookup_handle(&handle_table, hKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pCryptKey))
- {
- SetLastError(NTE_BAD_KEY);
- return FALSE;
- }
-
if (dwFlags & CRYPT_SSL2_FALLBACK) {
if (pCryptKey->aiAlgid != CALG_SSL2_MASTER) {
SetLastError(NTE_BAD_KEY);
SetLastError(NTE_BAD_PUBLIC_KEY); /* FIXME: error_code? */
return FALSE;
}
-
- if (!(GET_ALG_CLASS(pCryptKey->aiAlgid)&(ALG_CLASS_DATA_ENCRYPT|ALG_CLASS_MSG_ENCRYPT))) {
- SetLastError(NTE_BAD_KEY); /* FIXME: error code? */
- return FALSE;
- }
-
- dwDataLen = sizeof(BLOBHEADER) + sizeof(ALG_ID) + pPubKey->dwBlockLen;
- if (pbData) {
- if (*pdwDataLen < dwDataLen) {
- SetLastError(ERROR_MORE_DATA);
- *pdwDataLen = dwDataLen;
- return FALSE;
- }
-
- pBlobHeader->bType = SIMPLEBLOB;
- pBlobHeader->bVersion = CUR_BLOB_VERSION;
- pBlobHeader->reserved = 0;
- pBlobHeader->aiKeyAlg = pCryptKey->aiAlgid;
-
- *pAlgid = pPubKey->aiAlgid;
-
- if (!pad_data(pCryptKey->abKeyValue, pCryptKey->dwKeyLen, (BYTE*)(pAlgid+1),
- pPubKey->dwBlockLen, dwFlags))
- {
- return FALSE;
- }
-
- encrypt_block_impl(pPubKey->aiAlgid, PK_PUBLIC, &pPubKey->context, (BYTE*)(pAlgid+1),
- (BYTE*)(pAlgid+1), RSAENH_ENCRYPT);
- }
- *pdwDataLen = dwDataLen;
- return TRUE;
+ return crypt_export_simple(pCryptKey, pPubKey, dwFlags, pbData,
+ pdwDataLen);
case PUBLICKEYBLOB:
if (is_valid_handle(&handle_table, hPubKey, RSAENH_MAGIC_KEY)) {
return FALSE;
}
- if ((pCryptKey->aiAlgid != CALG_RSA_KEYX) && (pCryptKey->aiAlgid != CALG_RSA_SIGN)) {
- SetLastError(NTE_BAD_KEY);
- return FALSE;
- }
-
- dwDataLen = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + pCryptKey->dwKeyLen;
- if (pbData) {
- if (*pdwDataLen < dwDataLen) {
- SetLastError(ERROR_MORE_DATA);
- *pdwDataLen = dwDataLen;
- return FALSE;
- }
-
- pBlobHeader->bType = PUBLICKEYBLOB;
- pBlobHeader->bVersion = CUR_BLOB_VERSION;
- pBlobHeader->reserved = 0;
- pBlobHeader->aiKeyAlg = pCryptKey->aiAlgid;
-
- pRSAPubKey->magic = RSAENH_MAGIC_RSA1;
- pRSAPubKey->bitlen = pCryptKey->dwKeyLen << 3;
-
- export_public_key_impl((BYTE*)(pRSAPubKey+1), &pCryptKey->context,
- pCryptKey->dwKeyLen, &pRSAPubKey->pubexp);
- }
- *pdwDataLen = dwDataLen;
- return TRUE;
+ return crypt_export_public_key(pCryptKey, pbData, pdwDataLen);
case PRIVATEKEYBLOB:
- if ((pCryptKey->aiAlgid != CALG_RSA_KEYX) && (pCryptKey->aiAlgid != CALG_RSA_SIGN)) {
- SetLastError(NTE_BAD_KEY);
- return FALSE;
- }
-
- dwDataLen = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
- 2 * pCryptKey->dwKeyLen + 5 * ((pCryptKey->dwKeyLen + 1) >> 1);
- if (pbData) {
- if (*pdwDataLen < dwDataLen) {
- SetLastError(ERROR_MORE_DATA);
- *pdwDataLen = dwDataLen;
- return FALSE;
- }
-
- pBlobHeader->bType = PRIVATEKEYBLOB;
- pBlobHeader->bVersion = CUR_BLOB_VERSION;
- pBlobHeader->reserved = 0;
- pBlobHeader->aiKeyAlg = pCryptKey->aiAlgid;
+ return crypt_export_private_key(pCryptKey, force, pbData, pdwDataLen);
- pRSAPubKey->magic = RSAENH_MAGIC_RSA2;
- pRSAPubKey->bitlen = pCryptKey->dwKeyLen << 3;
-
- export_private_key_impl((BYTE*)(pRSAPubKey+1), &pCryptKey->context,
- pCryptKey->dwKeyLen, &pRSAPubKey->pubexp);
- }
- *pdwDataLen = dwDataLen;
- return TRUE;
+ case PLAINTEXTKEYBLOB:
+ return crypt_export_plaintext_key(pCryptKey, pbData, pdwDataLen);
default:
SetLastError(NTE_BAD_TYPE); /* FIXME: error code? */
}
/******************************************************************************
- * CPImportKey (RSAENH.@)
+ * CPExportKey (RSAENH.@)
*
- * Import a BLOB'ed key into a key container.
+ * Export a key into a binary large object (BLOB).
*
* PARAMS
- * hProv [I] Key container into which the key is to be imported.
- * pbData [I] Pointer to a buffer which holds the BLOB.
- * dwDataLen [I] Length of data in buffer at pbData.
- * hPubKey [I] Key used to decrypt sensitive BLOB data.
- * dwFlags [I] Currently none defined.
- * phKey [O] Handle to the imported key.
+ * hProv [I] Key container from which a key is to be exported.
+ * hKey [I] Key to be exported.
+ * hPubKey [I] Key used to encrypt sensitive BLOB data.
+ * dwBlobType [I] SIMPLEBLOB, PUBLICKEYBLOB or PRIVATEKEYBLOB.
+ * dwFlags [I] Currently none defined.
+ * pbData [O] Pointer to a buffer where the BLOB will be written to.
+ * pdwDataLen [I/O] I: Size of buffer at pbData, O: Size of BLOB
*
* RETURNS
* Success: TRUE.
* Failure: FALSE.
*/
-BOOL WINAPI RSAENH_CPImportKey(HCRYPTPROV hProv, CONST BYTE *pbData, DWORD dwDataLen,
- HCRYPTKEY hPubKey, DWORD dwFlags, HCRYPTKEY *phKey)
+BOOL WINAPI RSAENH_CPExportKey(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTKEY hPubKey,
+ DWORD dwBlobType, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen)
{
- KEYCONTAINER *pKeyContainer;
- CRYPTKEY *pCryptKey, *pPubKey;
- CONST BLOBHEADER *pBlobHeader = (CONST BLOBHEADER*)pbData;
- CONST RSAPUBKEY *pRSAPubKey = (CONST RSAPUBKEY*)(pBlobHeader+1);
- CONST ALG_ID *pAlgid = (CONST ALG_ID*)(pBlobHeader+1);
- CONST BYTE *pbKeyStream = (CONST BYTE*)(pAlgid + 1);
+ CRYPTKEY *pCryptKey;
+
+ TRACE("(hProv=%08lx, hKey=%08lx, hPubKey=%08lx, dwBlobType=%08x, dwFlags=%08x, pbData=%p,"
+ "pdwDataLen=%p)\n", hProv, hKey, hPubKey, dwBlobType, dwFlags, pbData, pdwDataLen);
+
+ if (!is_valid_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER))
+ {
+ SetLastError(NTE_BAD_UID);
+ return FALSE;
+ }
+
+ if (!lookup_handle(&handle_table, hKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pCryptKey))
+ {
+ SetLastError(NTE_BAD_KEY);
+ return FALSE;
+ }
+
+ return crypt_export_key(pCryptKey, hPubKey, dwBlobType, dwFlags, FALSE,
+ pbData, pdwDataLen);
+}
+
+/******************************************************************************
+ * release_and_install_key [Internal]
+ *
+ * Release an existing key, if present, and replaces it with a new one.
+ *
+ * PARAMS
+ * hProv [I] Key container into which the key is to be imported.
+ * src [I] Key which will replace *dest
+ * dest [I] Points to key to be released and replaced with src
+ * fStoreKey [I] If TRUE, the newly installed key is stored to the registry.
+ */
+static void release_and_install_key(HCRYPTPROV hProv, HCRYPTKEY src,
+ HCRYPTKEY *dest, DWORD fStoreKey)
+{
+ RSAENH_CPDestroyKey(hProv, *dest);
+ copy_handle(&handle_table, src, RSAENH_MAGIC_KEY, dest);
+ if (fStoreKey)
+ {
+ KEYCONTAINER *pKeyContainer;
+
+ if (lookup_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER,
+ (OBJECTHDR**)&pKeyContainer))
+ {
+ store_key_container_keys(pKeyContainer);
+ store_key_container_permissions(pKeyContainer);
+ }
+ }
+}
+
+/******************************************************************************
+ * import_private_key [Internal]
+ *
+ * Import a BLOB'ed private key into a key container.
+ *
+ * PARAMS
+ * hProv [I] Key container into which the private key is to be imported.
+ * pbData [I] Pointer to a buffer which holds the private key BLOB.
+ * dwDataLen [I] Length of data in buffer at pbData.
+ * dwFlags [I] One of:
+ * CRYPT_EXPORTABLE: the imported key is marked exportable
+ * fStoreKey [I] If TRUE, the imported key is stored to the registry.
+ * phKey [O] Handle to the imported key.
+ *
+ *
+ * NOTES
+ * Assumes the caller has already checked the BLOBHEADER at pbData to ensure
+ * it's a PRIVATEKEYBLOB.
+ *
+ * RETURNS
+ * Success: TRUE.
+ * Failure: FALSE.
+ */
+static BOOL import_private_key(HCRYPTPROV hProv, CONST BYTE *pbData, DWORD dwDataLen,
+ DWORD dwFlags, BOOL fStoreKey, HCRYPTKEY *phKey)
+{
+ KEYCONTAINER *pKeyContainer;
+ CRYPTKEY *pCryptKey;
+ CONST BLOBHEADER *pBlobHeader = (CONST BLOBHEADER*)pbData;
+ CONST RSAPUBKEY *pRSAPubKey = (CONST RSAPUBKEY*)(pBlobHeader+1);
+ BOOL ret;
+
+ if (!lookup_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER,
+ (OBJECTHDR**)&pKeyContainer))
+ {
+ SetLastError(NTE_BAD_UID);
+ return FALSE;
+ }
+
+ if ((dwDataLen < sizeof(BLOBHEADER) + sizeof(RSAPUBKEY)) ||
+ (pRSAPubKey->magic != RSAENH_MAGIC_RSA2) ||
+ (dwDataLen < sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
+ (2 * pRSAPubKey->bitlen >> 3) + (5 * ((pRSAPubKey->bitlen+8)>>4))))
+ {
+ SetLastError(NTE_BAD_DATA);
+ return FALSE;
+ }
+
+ *phKey = new_key(hProv, pBlobHeader->aiKeyAlg, MAKELONG(0,pRSAPubKey->bitlen), &pCryptKey);
+ if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE) return FALSE;
+ setup_key(pCryptKey);
+ ret = import_private_key_impl((CONST BYTE*)(pRSAPubKey+1), &pCryptKey->context,
+ pRSAPubKey->bitlen/8, pRSAPubKey->pubexp);
+ if (ret) {
+ if (dwFlags & CRYPT_EXPORTABLE)
+ pCryptKey->dwPermissions |= CRYPT_EXPORT;
+ switch (pBlobHeader->aiKeyAlg)
+ {
+ case AT_SIGNATURE:
+ case CALG_RSA_SIGN:
+ TRACE("installing signing key\n");
+ release_and_install_key(hProv, *phKey, &pKeyContainer->hSignatureKeyPair,
+ fStoreKey);
+ break;
+ case AT_KEYEXCHANGE:
+ case CALG_RSA_KEYX:
+ TRACE("installing key exchange key\n");
+ release_and_install_key(hProv, *phKey, &pKeyContainer->hKeyExchangeKeyPair,
+ fStoreKey);
+ break;
+ }
+ }
+ return ret;
+}
+
+/******************************************************************************
+ * import_public_key [Internal]
+ *
+ * Import a BLOB'ed public key into a key container.
+ *
+ * PARAMS
+ * hProv [I] Key container into which the public key is to be imported.
+ * pbData [I] Pointer to a buffer which holds the public key BLOB.
+ * dwDataLen [I] Length of data in buffer at pbData.
+ * dwFlags [I] One of:
+ * CRYPT_EXPORTABLE: the imported key is marked exportable
+ * fStoreKey [I] If TRUE, the imported key is stored to the registry.
+ * phKey [O] Handle to the imported key.
+ *
+ *
+ * NOTES
+ * Assumes the caller has already checked the BLOBHEADER at pbData to ensure
+ * it's a PUBLICKEYBLOB.
+ *
+ * RETURNS
+ * Success: TRUE.
+ * Failure: FALSE.
+ */
+static BOOL import_public_key(HCRYPTPROV hProv, CONST BYTE *pbData, DWORD dwDataLen,
+ DWORD dwFlags, BOOL fStoreKey, HCRYPTKEY *phKey)
+{
+ KEYCONTAINER *pKeyContainer;
+ CRYPTKEY *pCryptKey;
+ CONST BLOBHEADER *pBlobHeader = (CONST BLOBHEADER*)pbData;
+ CONST RSAPUBKEY *pRSAPubKey = (CONST RSAPUBKEY*)(pBlobHeader+1);
ALG_ID algID;
+ BOOL ret;
+
+ if (!lookup_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER,
+ (OBJECTHDR**)&pKeyContainer))
+ {
+ SetLastError(NTE_BAD_UID);
+ return FALSE;
+ }
+
+ if ((dwDataLen < sizeof(BLOBHEADER) + sizeof(RSAPUBKEY)) ||
+ (pRSAPubKey->magic != RSAENH_MAGIC_RSA1) ||
+ (dwDataLen < sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + (pRSAPubKey->bitlen >> 3)))
+ {
+ SetLastError(NTE_BAD_DATA);
+ return FALSE;
+ }
+
+ /* Since this is a public key blob, only the public key is
+ * available, so only signature verification is possible.
+ */
+ algID = pBlobHeader->aiKeyAlg;
+ *phKey = new_key(hProv, algID, MAKELONG(0,pRSAPubKey->bitlen), &pCryptKey);
+ if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE) return FALSE;
+ setup_key(pCryptKey);
+ ret = import_public_key_impl((CONST BYTE*)(pRSAPubKey+1), &pCryptKey->context,
+ pRSAPubKey->bitlen >> 3, pRSAPubKey->pubexp);
+ if (ret) {
+ if (dwFlags & CRYPT_EXPORTABLE)
+ pCryptKey->dwPermissions |= CRYPT_EXPORT;
+ switch (pBlobHeader->aiKeyAlg)
+ {
+ case AT_KEYEXCHANGE:
+ case CALG_RSA_KEYX:
+ TRACE("installing public key\n");
+ release_and_install_key(hProv, *phKey, &pKeyContainer->hKeyExchangeKeyPair,
+ fStoreKey);
+ break;
+ }
+ }
+ return ret;
+}
+
+/******************************************************************************
+ * import_symmetric_key [Internal]
+ *
+ * Import a BLOB'ed symmetric key into a key container.
+ *
+ * PARAMS
+ * hProv [I] Key container into which the symmetric key is to be imported.
+ * pbData [I] Pointer to a buffer which holds the symmetric key BLOB.
+ * dwDataLen [I] Length of data in buffer at pbData.
+ * hPubKey [I] Key used to decrypt sensitive BLOB data.
+ * dwFlags [I] One of:
+ * CRYPT_EXPORTABLE: the imported key is marked exportable
+ * phKey [O] Handle to the imported key.
+ *
+ *
+ * NOTES
+ * Assumes the caller has already checked the BLOBHEADER at pbData to ensure
+ * it's a SIMPLEBLOB.
+ *
+ * RETURNS
+ * Success: TRUE.
+ * Failure: FALSE.
+ */
+static BOOL import_symmetric_key(HCRYPTPROV hProv, CONST BYTE *pbData,
+ DWORD dwDataLen, HCRYPTKEY hPubKey,
+ DWORD dwFlags, HCRYPTKEY *phKey)
+{
+ CRYPTKEY *pCryptKey, *pPubKey;
+ CONST BLOBHEADER *pBlobHeader = (CONST BLOBHEADER*)pbData;
+ CONST ALG_ID *pAlgid = (CONST ALG_ID*)(pBlobHeader+1);
+ CONST BYTE *pbKeyStream = (CONST BYTE*)(pAlgid + 1);
BYTE *pbDecrypted;
DWORD dwKeyLen;
- BOOL ret;
- TRACE("(hProv=%08lx, pbData=%p, dwDataLen=%d, hPubKey=%08lx, dwFlags=%08x, phKey=%p)\n",
- hProv, pbData, dwDataLen, hPubKey, dwFlags, phKey);
-
+ if (!lookup_handle(&handle_table, hPubKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pPubKey) ||
+ pPubKey->aiAlgid != CALG_RSA_KEYX)
+ {
+ SetLastError(NTE_BAD_PUBLIC_KEY); /* FIXME: error code? */
+ return FALSE;
+ }
+
+ if (dwDataLen < sizeof(BLOBHEADER)+sizeof(ALG_ID)+pPubKey->dwBlockLen)
+ {
+ SetLastError(NTE_BAD_DATA); /* FIXME: error code */
+ return FALSE;
+ }
+
+ pbDecrypted = HeapAlloc(GetProcessHeap(), 0, pPubKey->dwBlockLen);
+ if (!pbDecrypted) return FALSE;
+ encrypt_block_impl(pPubKey->aiAlgid, PK_PRIVATE, &pPubKey->context, pbKeyStream, pbDecrypted,
+ RSAENH_DECRYPT);
+
+ dwKeyLen = RSAENH_MAX_KEY_SIZE;
+ if (!unpad_data(pbDecrypted, pPubKey->dwBlockLen, pbDecrypted, &dwKeyLen, dwFlags)) {
+ HeapFree(GetProcessHeap(), 0, pbDecrypted);
+ return FALSE;
+ }
+
+ *phKey = new_key(hProv, pBlobHeader->aiKeyAlg, dwKeyLen<<19, &pCryptKey);
+ if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE)
+ {
+ HeapFree(GetProcessHeap(), 0, pbDecrypted);
+ return FALSE;
+ }
+ memcpy(pCryptKey->abKeyValue, pbDecrypted, dwKeyLen);
+ HeapFree(GetProcessHeap(), 0, pbDecrypted);
+ setup_key(pCryptKey);
+ if (dwFlags & CRYPT_EXPORTABLE)
+ pCryptKey->dwPermissions |= CRYPT_EXPORT;
+ return TRUE;
+}
+
+/******************************************************************************
+ * import_plaintext_key [Internal]
+ *
+ * Import a plaintext key into a key container.
+ *
+ * PARAMS
+ * hProv [I] Key container into which the symmetric key is to be imported.
+ * pbData [I] Pointer to a buffer which holds the plaintext key BLOB.
+ * dwDataLen [I] Length of data in buffer at pbData.
+ * dwFlags [I] One of:
+ * CRYPT_EXPORTABLE: the imported key is marked exportable
+ * phKey [O] Handle to the imported key.
+ *
+ *
+ * NOTES
+ * Assumes the caller has already checked the BLOBHEADER at pbData to ensure
+ * it's a PLAINTEXTKEYBLOB.
+ *
+ * RETURNS
+ * Success: TRUE.
+ * Failure: FALSE.
+ */
+static BOOL import_plaintext_key(HCRYPTPROV hProv, CONST BYTE *pbData,
+ DWORD dwDataLen, DWORD dwFlags,
+ HCRYPTKEY *phKey)
+{
+ CRYPTKEY *pCryptKey;
+ CONST BLOBHEADER *pBlobHeader = (CONST BLOBHEADER*)pbData;
+ CONST DWORD *pKeyLen = (CONST DWORD *)(pBlobHeader + 1);
+ CONST BYTE *pbKeyStream = (CONST BYTE*)(pKeyLen + 1);
+
+ if (dwDataLen < sizeof(BLOBHEADER)+sizeof(DWORD)+*pKeyLen)
+ {
+ SetLastError(NTE_BAD_DATA); /* FIXME: error code */
+ return FALSE;
+ }
+
+ *phKey = new_key(hProv, pBlobHeader->aiKeyAlg, *pKeyLen<<19, &pCryptKey);
+ if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE)
+ return FALSE;
+ memcpy(pCryptKey->abKeyValue, pbKeyStream, *pKeyLen);
+ setup_key(pCryptKey);
+ if (dwFlags & CRYPT_EXPORTABLE)
+ pCryptKey->dwPermissions |= CRYPT_EXPORT;
+ return TRUE;
+}
+
+/******************************************************************************
+ * import_key [Internal]
+ *
+ * Import a BLOB'ed key into a key container, optionally storing the key's
+ * value to the registry.
+ *
+ * PARAMS
+ * hProv [I] Key container into which the key is to be imported.
+ * pbData [I] Pointer to a buffer which holds the BLOB.
+ * dwDataLen [I] Length of data in buffer at pbData.
+ * hPubKey [I] Key used to decrypt sensitive BLOB data.
+ * dwFlags [I] One of:
+ * CRYPT_EXPORTABLE: the imported key is marked exportable
+ * fStoreKey [I] If TRUE, the imported key is stored to the registry.
+ * phKey [O] Handle to the imported key.
+ *
+ * RETURNS
+ * Success: TRUE.
+ * Failure: FALSE.
+ */
+static BOOL import_key(HCRYPTPROV hProv, CONST BYTE *pbData, DWORD dwDataLen,
+ HCRYPTKEY hPubKey, DWORD dwFlags, BOOL fStoreKey,
+ HCRYPTKEY *phKey)
+{
+ KEYCONTAINER *pKeyContainer;
+ CONST BLOBHEADER *pBlobHeader = (CONST BLOBHEADER*)pbData;
+
if (!lookup_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER,
(OBJECTHDR**)&pKeyContainer))
{
pBlobHeader->bVersion != CUR_BLOB_VERSION ||
pBlobHeader->reserved != 0)
{
+ TRACE("bVersion = %d, reserved = %d\n", pBlobHeader->bVersion,
+ pBlobHeader->reserved);
SetLastError(NTE_BAD_DATA);
return FALSE;
}
+ /* If this is a verify-only context, the key is not persisted regardless of
+ * fStoreKey's original value.
+ */
+ fStoreKey = fStoreKey && !(dwFlags & CRYPT_VERIFYCONTEXT);
+ TRACE("blob type: %x\n", pBlobHeader->bType);
switch (pBlobHeader->bType)
{
case PRIVATEKEYBLOB:
- if ((dwDataLen < sizeof(BLOBHEADER) + sizeof(RSAPUBKEY)) ||
- (pRSAPubKey->magic != RSAENH_MAGIC_RSA2) ||
- (dwDataLen < sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
- (2 * pRSAPubKey->bitlen >> 3) + (5 * ((pRSAPubKey->bitlen+8)>>4))))
- {
- SetLastError(NTE_BAD_DATA);
- return FALSE;
- }
-
- *phKey = new_key(hProv, pBlobHeader->aiKeyAlg, MAKELONG(0,pRSAPubKey->bitlen), &pCryptKey);
- if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE) return FALSE;
- setup_key(pCryptKey);
- ret = import_private_key_impl((CONST BYTE*)(pRSAPubKey+1), &pCryptKey->context,
- pRSAPubKey->bitlen/8, pRSAPubKey->pubexp);
- if (ret) {
- switch (pBlobHeader->aiKeyAlg)
- {
- case AT_SIGNATURE:
- case CALG_RSA_SIGN:
- TRACE("installing signing key\n");
- RSAENH_CPDestroyKey(hProv, pKeyContainer->hSignatureKeyPair);
- copy_handle(&handle_table, *phKey, RSAENH_MAGIC_KEY,
- &pKeyContainer->hSignatureKeyPair);
- break;
- case AT_KEYEXCHANGE:
- case CALG_RSA_KEYX:
- TRACE("installing key exchange key\n");
- RSAENH_CPDestroyKey(hProv, pKeyContainer->hKeyExchangeKeyPair);
- copy_handle(&handle_table, *phKey, RSAENH_MAGIC_KEY,
- &pKeyContainer->hKeyExchangeKeyPair);
- break;
- }
- }
- return ret;
+ return import_private_key(hProv, pbData, dwDataLen, dwFlags,
+ fStoreKey, phKey);
case PUBLICKEYBLOB:
- if ((dwDataLen < sizeof(BLOBHEADER) + sizeof(RSAPUBKEY)) ||
- (pRSAPubKey->magic != RSAENH_MAGIC_RSA1) ||
- (dwDataLen < sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + (pRSAPubKey->bitlen >> 3)))
- {
- SetLastError(NTE_BAD_DATA);
- return FALSE;
- }
-
- /* Since this is a public key blob, only the public key is
- * available, so only signature verification is possible.
- */
- algID = pBlobHeader->aiKeyAlg;
- *phKey = new_key(hProv, algID, MAKELONG(0,pRSAPubKey->bitlen), &pCryptKey);
- if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE) return FALSE;
- setup_key(pCryptKey);
- ret = import_public_key_impl((CONST BYTE*)(pRSAPubKey+1), &pCryptKey->context,
- pRSAPubKey->bitlen >> 3, pRSAPubKey->pubexp);
- if (ret) {
- switch (pBlobHeader->aiKeyAlg)
- {
- case AT_KEYEXCHANGE:
- case CALG_RSA_KEYX:
- TRACE("installing public key\n");
- RSAENH_CPDestroyKey(hProv, pKeyContainer->hKeyExchangeKeyPair);
- copy_handle(&handle_table, *phKey, RSAENH_MAGIC_KEY,
- &pKeyContainer->hKeyExchangeKeyPair);
- break;
- }
- }
- return ret;
+ return import_public_key(hProv, pbData, dwDataLen, dwFlags,
+ fStoreKey, phKey);
case SIMPLEBLOB:
- if (!lookup_handle(&handle_table, hPubKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pPubKey) ||
- pPubKey->aiAlgid != CALG_RSA_KEYX)
- {
- SetLastError(NTE_BAD_PUBLIC_KEY); /* FIXME: error code? */
- return FALSE;
- }
-
- if (dwDataLen < sizeof(BLOBHEADER)+sizeof(ALG_ID)+pPubKey->dwBlockLen)
- {
- SetLastError(NTE_BAD_DATA); /* FIXME: error code */
- return FALSE;
- }
+ return import_symmetric_key(hProv, pbData, dwDataLen, hPubKey,
+ dwFlags, phKey);
- pbDecrypted = HeapAlloc(GetProcessHeap(), 0, pPubKey->dwBlockLen);
- if (!pbDecrypted) return FALSE;
- encrypt_block_impl(pPubKey->aiAlgid, PK_PRIVATE, &pPubKey->context, pbKeyStream, pbDecrypted,
- RSAENH_DECRYPT);
-
- dwKeyLen = RSAENH_MAX_KEY_SIZE;
- if (!unpad_data(pbDecrypted, pPubKey->dwBlockLen, pbDecrypted, &dwKeyLen, dwFlags)) {
- HeapFree(GetProcessHeap(), 0, pbDecrypted);
- return FALSE;
- }
-
- *phKey = new_key(hProv, pBlobHeader->aiKeyAlg, dwKeyLen<<19, &pCryptKey);
- if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE)
- {
- HeapFree(GetProcessHeap(), 0, pbDecrypted);
- return FALSE;
- }
- memcpy(pCryptKey->abKeyValue, pbDecrypted, dwKeyLen);
- HeapFree(GetProcessHeap(), 0, pbDecrypted);
- setup_key(pCryptKey);
- return TRUE;
+ case PLAINTEXTKEYBLOB:
+ return import_plaintext_key(hProv, pbData, dwDataLen, dwFlags,
+ phKey);
default:
SetLastError(NTE_BAD_TYPE); /* FIXME: error code? */
}
}
+/******************************************************************************
+ * CPImportKey (RSAENH.@)
+ *
+ * Import a BLOB'ed key into a key container.
+ *
+ * PARAMS
+ * hProv [I] Key container into which the key is to be imported.
+ * pbData [I] Pointer to a buffer which holds the BLOB.
+ * dwDataLen [I] Length of data in buffer at pbData.
+ * hPubKey [I] Key used to decrypt sensitive BLOB data.
+ * dwFlags [I] One of:
+ * CRYPT_EXPORTABLE: the imported key is marked exportable
+ * phKey [O] Handle to the imported key.
+ *
+ * RETURNS
+ * Success: TRUE.
+ * Failure: FALSE.
+ */
+BOOL WINAPI RSAENH_CPImportKey(HCRYPTPROV hProv, CONST BYTE *pbData, DWORD dwDataLen,
+ HCRYPTKEY hPubKey, DWORD dwFlags, HCRYPTKEY *phKey)
+{
+ TRACE("(hProv=%08lx, pbData=%p, dwDataLen=%d, hPubKey=%08lx, dwFlags=%08x, phKey=%p)\n",
+ hProv, pbData, dwDataLen, hPubKey, dwFlags, phKey);
+
+ if (dwFlags & CRYPT_IPSEC_HMAC_KEY)
+ {
+ FIXME("unimplemented for CRYPT_IPSEC_HMAC_KEY\n");
+ SetLastError(NTE_BAD_FLAGS);
+ return FALSE;
+ }
+ return import_key(hProv, pbData, dwDataLen, hPubKey, dwFlags, TRUE, phKey);
+}
+
/******************************************************************************
* CPGenKey (RSAENH.@)
*
if (pCryptKey) {
new_key_impl(pCryptKey->aiAlgid, &pCryptKey->context, pCryptKey->dwKeyLen);
setup_key(pCryptKey);
- if (Algid == AT_SIGNATURE) {
- RSAENH_CPDestroyKey(hProv, pKeyContainer->hSignatureKeyPair);
- copy_handle(&handle_table, *phKey, RSAENH_MAGIC_KEY,
- &pKeyContainer->hSignatureKeyPair);
- }
+ release_and_install_key(hProv, *phKey,
+ &pKeyContainer->hSignatureKeyPair,
+ FALSE);
}
break;
if (pCryptKey) {
new_key_impl(pCryptKey->aiAlgid, &pCryptKey->context, pCryptKey->dwKeyLen);
setup_key(pCryptKey);
- if (Algid == AT_KEYEXCHANGE) {
- RSAENH_CPDestroyKey(hProv, pKeyContainer->hKeyExchangeKeyPair);
- copy_handle(&handle_table, *phKey, RSAENH_MAGIC_KEY,
- &pKeyContainer->hKeyExchangeKeyPair);
- }
+ release_and_install_key(hProv, *phKey,
+ &pKeyContainer->hKeyExchangeKeyPair,
+ FALSE);
}
break;
finalize_hash(pCryptHash);
pCryptHash->dwState = RSAENH_HASHSTATE_FINISHED;
}
-
- return copy_param(pbData, pdwDataLen, (CONST BYTE*)pCryptHash->abHashValue,
+
+ return copy_param(pbData, pdwDataLen, pCryptHash->abHashValue,
pCryptHash->dwHashSize);
default:
return TRUE;
case KP_PERMISSIONS:
- pCryptKey->dwPermissions = *(DWORD*)pbData;
+ {
+ DWORD perms = *(DWORD *)pbData;
+
+ if ((perms & CRYPT_EXPORT) &&
+ !(pCryptKey->dwPermissions & CRYPT_EXPORT))
+ {
+ SetLastError(NTE_BAD_DATA);
+ return FALSE;
+ }
+ else if (!(perms & CRYPT_EXPORT) &&
+ (pCryptKey->dwPermissions & CRYPT_EXPORT))
+ {
+ /* Clearing the export permission appears to be ignored,
+ * see tests.
+ */
+ perms |= CRYPT_EXPORT;
+ }
+ pCryptKey->dwPermissions = perms;
return TRUE;
+ }
case KP_IV:
memcpy(pCryptKey->abInitVector, pbData, pCryptKey->dwBlockLen);
{
CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pbData;
- /* salt length can't be greater than 128 bits = 16 bytes */
- if (blob->cbData > 16)
+ /* salt length can't be greater than 184 bits = 24 bytes */
+ if (blob->cbData > 24)
{
- SetLastError(ERROR_INVALID_PARAMETER);
+ SetLastError(NTE_BAD_DATA);
return FALSE;
}
memcpy(pCryptKey->abKeyValue + pCryptKey->dwKeyLen, blob->pbData,
switch (dwParam)
{
case KP_IV:
- return copy_param(pbData, pdwDataLen, (CONST BYTE*)pCryptKey->abInitVector,
+ return copy_param(pbData, pdwDataLen, pCryptKey->abInitVector,
pCryptKey->dwBlockLen);
case KP_SALT:
return copy_param(pbData, pdwDataLen,
- (CONST BYTE*)&pCryptKey->abKeyValue[pCryptKey->dwKeyLen], pCryptKey->dwSaltLen);
-
+ &pCryptKey->abKeyValue[pCryptKey->dwKeyLen], pCryptKey->dwSaltLen);
+
case KP_PADDING:
dwValue = PKCS5_PADDING;
return copy_param(pbData, pdwDataLen, (CONST BYTE*)&dwValue, sizeof(DWORD));
{
CRYPTHASH *pCryptHash;
CRYPTKEY *pCryptKey;
- int i;
+ DWORD i;
TRACE("(hProv=%08lx, hHash=%08lx, dwParam=%08x, pbData=%p, dwFlags=%08x)\n",
hProv, hHash, dwParam, pbData, dwFlags);
LPCWSTR sDescription, DWORD dwFlags, BYTE *pbSignature,
DWORD *pdwSigLen)
{
- HCRYPTKEY hCryptKey;
+ HCRYPTKEY hCryptKey = (HCRYPTKEY)INVALID_HANDLE_VALUE;
CRYPTKEY *pCryptKey;
DWORD dwHashLen;
BYTE abHashValue[RSAENH_MAX_HASH_SIZE];
ALG_ID aiAlgid;
+ BOOL ret = FALSE;
TRACE("(hProv=%08lx, hHash=%08lx, dwKeySpec=%08x, sDescription=%s, dwFlags=%08x, "
"pbSignature=%p, pdwSigLen=%p)\n", hProv, hHash, dwKeySpec, debugstr_w(sDescription),
(OBJECTHDR**)&pCryptKey))
{
SetLastError(NTE_NO_KEY);
- return FALSE;
+ goto out;
}
if (!pbSignature) {
*pdwSigLen = pCryptKey->dwKeyLen;
- return TRUE;
+ ret = TRUE;
+ goto out;
}
if (pCryptKey->dwKeyLen > *pdwSigLen)
{
SetLastError(ERROR_MORE_DATA);
*pdwSigLen = pCryptKey->dwKeyLen;
- return FALSE;
+ goto out;
}
*pdwSigLen = pCryptKey->dwKeyLen;
if (!RSAENH_CPHashData(hProv, hHash, (CONST BYTE*)sDescription,
(DWORD)lstrlenW(sDescription)*sizeof(WCHAR), 0))
{
- return FALSE;
+ goto out;
}
}
dwHashLen = sizeof(DWORD);
- if (!RSAENH_CPGetHashParam(hProv, hHash, HP_ALGID, (BYTE*)&aiAlgid, &dwHashLen, 0)) return FALSE;
+ if (!RSAENH_CPGetHashParam(hProv, hHash, HP_ALGID, (BYTE*)&aiAlgid, &dwHashLen, 0)) goto out;
dwHashLen = RSAENH_MAX_HASH_SIZE;
- if (!RSAENH_CPGetHashParam(hProv, hHash, HP_HASHVAL, abHashValue, &dwHashLen, 0)) return FALSE;
+ if (!RSAENH_CPGetHashParam(hProv, hHash, HP_HASHVAL, abHashValue, &dwHashLen, 0)) goto out;
if (!build_hash_signature(pbSignature, *pdwSigLen, aiAlgid, abHashValue, dwHashLen, dwFlags)) {
- return FALSE;
+ goto out;
}
- return encrypt_block_impl(pCryptKey->aiAlgid, PK_PRIVATE, &pCryptKey->context, pbSignature, pbSignature, RSAENH_ENCRYPT);
+ ret = encrypt_block_impl(pCryptKey->aiAlgid, PK_PRIVATE, &pCryptKey->context, pbSignature, pbSignature, RSAENH_ENCRYPT);
+out:
+ RSAENH_CPDestroyKey(hProv, hCryptKey);
+ return ret;
}
/******************************************************************************
return res;
}
-static const WCHAR szProviderKeys[5][104] = {
+static const WCHAR szProviderKeys[6][116] = {
{ 'S','o','f','t','w','a','r','e','\\',
'M','i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r',
'a','p','h','y','\\','D','e','f','a','u','l','t','s','\\','P','r','o','v',
'C','r','y','p','t','o','g','r','a','p','h','y','\\','D','e','f','a','u','l','t','s','\\',
'P','r','o','v','i','d','e','r','\\','M','i','c','r','o','s','o','f','t',' ',
'E','n','h','a','n','c','e','d',' ','R','S','A',' ','a','n','d',' ','A','E','S',' ',
- 'C','r','y','p','t','o','g','r','a','p','h','i','c',' ','P','r','o','v','i','d','e','r',0 }
+ 'C','r','y','p','t','o','g','r','a','p','h','i','c',' ','P','r','o','v','i','d','e','r',0 },
+ { 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
+ 'C','r','y','p','t','o','g','r','a','p','h','y','\\','D','e','f','a','u','l','t','s','\\',
+ 'P','r','o','v','i','d','e','r','\\','M','i','c','r','o','s','o','f','t',' ',
+ 'E','n','h','a','n','c','e','d',' ','R','S','A',' ','a','n','d',' ','A','E','S',' ',
+ 'C','r','y','p','t','o','g','r','a','p','h','i','c',' ','P','r','o','v','i','d','e','r',
+ ' ','(','P','r','o','t','o','t','y','p','e',')',0 }
};
static const WCHAR szDefaultKeys[3][65] = {
{ 'S','o','f','t','w','a','r','e','\\',
long apiRet;
int i;
- for (i=0; i<5; i++) {
+ for (i=0; i<6; i++) {
apiRet = RegCreateKeyExW(HKEY_LOCAL_MACHINE, szProviderKeys[i], 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &key, &dp);
type=PROV_RSA_SCHANNEL;
break;
case 4:
+ case 5:
type=PROV_RSA_AES;
break;
default:
{
static const WCHAR szName[] = { 'N','a','m','e',0 };
static const WCHAR szRSAName[3][54] = {
- { 'M','i','c','r','o','s','o','f','t',' ', 'B','a','s','e',' ',
+ { 'M','i','c','r','o','s','o','f','t',' ',
+ 'E','n','h','a','n','c','e','d',' ',
'C','r','y','p','t','o','g','r','a','p','h','i','c',' ',
'P','r','o','v','i','d','e','r',' ','v','1','.','0',0 },
{ 'M','i','c','r','o','s','o','f','t',' ','R','S','A',' ',
RegDeleteKeyW(HKEY_LOCAL_MACHINE, szProviderKeys[2]);
RegDeleteKeyW(HKEY_LOCAL_MACHINE, szProviderKeys[3]);
RegDeleteKeyW(HKEY_LOCAL_MACHINE, szProviderKeys[4]);
+ RegDeleteKeyW(HKEY_LOCAL_MACHINE, szProviderKeys[5]);
RegDeleteKeyW(HKEY_LOCAL_MACHINE, szDefaultKeys[0]);
RegDeleteKeyW(HKEY_LOCAL_MACHINE, szDefaultKeys[1]);
RegDeleteKeyW(HKEY_LOCAL_MACHINE, szDefaultKeys[2]);