From d6a89fbae30a8e37dcc52f81854c30c7bac93e49 Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Wed, 28 Sep 2005 10:15:37 +0000 Subject: [PATCH] Implement CryptImport/ExportPublicKeyInfo. --- dlls/crypt32/crypt32.spec | 8 +-- dlls/crypt32/encode.c | 129 ++++++++++++++++++++++++++++++++++++ dlls/crypt32/tests/encode.c | 109 ++++++++++++++++++++++++++++++ 3 files changed, 242 insertions(+), 4 deletions(-) diff --git a/dlls/crypt32/crypt32.spec b/dlls/crypt32/crypt32.spec index 2384b0d116d..4c03bd3672a 100644 --- a/dlls/crypt32/crypt32.spec +++ b/dlls/crypt32/crypt32.spec @@ -98,8 +98,8 @@ @ stub CryptEnumOIDInfo @ stub CryptEnumProvidersU @ stub CryptExportPKCS8 -@ stub CryptExportPublicKeyInfo -@ stub CryptExportPublicKeyInfoEx +@ stdcall CryptExportPublicKeyInfo(long long long ptr ptr) +@ stdcall CryptExportPublicKeyInfoEx(long long long str long ptr ptr ptr) @ stub CryptFindOIDInfo @ stub CryptFormatObject @ stub CryptFreeOIDFunctionAddress @@ -115,8 +115,8 @@ @ stub CryptHashPublicKeyInfo @ stub CryptHashToBeSigned @ stub CryptImportPKCS8 -@ stub CryptImportPublicKeyInfo -@ stub CryptImportPublicKeyInfoEx +@ stdcall CryptImportPublicKeyInfo(long long ptr ptr) +@ stdcall CryptImportPublicKeyInfoEx(long long ptr long long ptr ptr) @ stdcall CryptInitOIDFunctionSet(str long) @ stub CryptInstallOIDFunctionAddress @ stub CryptLoadSip diff --git a/dlls/crypt32/encode.c b/dlls/crypt32/encode.c index 7f6b7c0369f..60a1bcdcf53 100644 --- a/dlls/crypt32/encode.c +++ b/dlls/crypt32/encode.c @@ -2352,6 +2352,8 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, } else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS)) encodeFunc = CRYPT_AsnEncodeExtensions; + else if (!strcmp(lpszStructType, szOID_RSA_RSA)) + encodeFunc = CRYPT_AsnEncodeRsaPubKey; else if (!strcmp(lpszStructType, szOID_RSA_signingTime)) encodeFunc = CRYPT_AsnEncodeUtcTime; else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE)) @@ -5438,6 +5440,8 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, } else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS)) decodeFunc = CRYPT_AsnDecodeExtensions; + else if (!strcmp(lpszStructType, szOID_RSA_RSA)) + decodeFunc = CRYPT_AsnDecodeRsaPubKey; else if (!strcmp(lpszStructType, szOID_RSA_signingTime)) decodeFunc = CRYPT_AsnDecodeUtcTime; else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE)) @@ -5473,3 +5477,128 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, FreeLibrary(lib); return ret; } + +BOOL WINAPI CryptExportPublicKeyInfo(HCRYPTPROV hCryptProv, DWORD dwKeySpec, + DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo) +{ + return CryptExportPublicKeyInfoEx(hCryptProv, dwKeySpec, dwCertEncodingType, + NULL, 0, NULL, pInfo, pcbInfo); +} + +BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV hCryptProv, DWORD dwKeySpec, + DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId, DWORD dwFlags, + void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo) +{ + BOOL ret; + HCRYPTKEY key; + + TRACE("(%ld, %ld, %08lx, %s, %08lx, %p, %p, %p)\n", hCryptProv, dwKeySpec, + dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo, + pInfo, pcbInfo); + + if (!hCryptProv) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (!pszPublicKeyObjId) + pszPublicKeyObjId = szOID_RSA_RSA; + if ((ret = CryptGetUserKey(hCryptProv, dwKeySpec, &key))) + { + DWORD keySize = 0; + + ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &keySize); + if (ret) + { + LPBYTE pubKey = HeapAlloc(GetProcessHeap(), 0, keySize); + + if (pubKey) + { + ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, pubKey, + &keySize); + if (ret) + { + DWORD encodedLen = 0; + + ret = CryptEncodeObject(dwCertEncodingType, + pszPublicKeyObjId, pubKey, NULL, &encodedLen); + if (ret) + { + DWORD sizeNeeded = sizeof(CERT_PUBLIC_KEY_INFO) + + strlen(pszPublicKeyObjId) + 1 + encodedLen; + + if (!pInfo) + *pcbInfo = sizeNeeded; + else if (*pcbInfo < sizeNeeded) + { + SetLastError(ERROR_MORE_DATA); + *pcbInfo = sizeNeeded; + ret = FALSE; + } + else + { + pInfo->Algorithm.pszObjId = (char *)pInfo + + sizeof(CERT_PUBLIC_KEY_INFO); + lstrcpyA(pInfo->Algorithm.pszObjId, + pszPublicKeyObjId); + pInfo->Algorithm.Parameters.cbData = 0; + pInfo->Algorithm.Parameters.pbData = NULL; + pInfo->PublicKey.pbData = (BYTE *)pInfo->Algorithm.pszObjId + + lstrlenA(pInfo->Algorithm.pszObjId) + 1; + pInfo->PublicKey.cbData = encodedLen; + pInfo->PublicKey.cUnusedBits = 0; + ret = CryptEncodeObject(dwCertEncodingType, + pszPublicKeyObjId, pubKey, pInfo->PublicKey.pbData, + &pInfo->PublicKey.cbData); + } + } + } + HeapFree(GetProcessHeap(), 0, pubKey); + } + else + ret = FALSE; + } + CryptDestroyKey(key); + } + return ret; +} + +BOOL WINAPI CryptImportPublicKeyInfo(HCRYPTPROV hCryptProv, + DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey) +{ + return CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType, pInfo, + 0, 0, NULL, phKey); +} + +BOOL WINAPI CryptImportPublicKeyInfoEx(HCRYPTPROV hCryptProv, + DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg, + DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey) +{ + BOOL ret; + DWORD pubKeySize = 0; + + TRACE("(%ld, %ld, %p, %d, %08lx, %p, %p)\n", hCryptProv, + dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey); + + ret = CryptDecodeObject(dwCertEncodingType, pInfo->Algorithm.pszObjId, + pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, NULL, &pubKeySize); + if (ret) + { + LPBYTE pubKey = HeapAlloc(GetProcessHeap(), 0, pubKeySize); + + if (pubKey) + { + ret = CryptDecodeObject(dwCertEncodingType, + pInfo->Algorithm.pszObjId, pInfo->PublicKey.pbData, + pInfo->PublicKey.cbData, 0, pubKey, &pubKeySize); + if (ret) + ret = CryptImportKey(hCryptProv, pubKey, pubKeySize, 0, 0, + phKey); + HeapFree(GetProcessHeap(), 0, pubKey); + } + else + ret = FALSE; + } + return ret; +} diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c index 92728546940..3e02de41d77 100644 --- a/dlls/crypt32/tests/encode.c +++ b/dlls/crypt32/tests/encode.c @@ -2470,6 +2470,114 @@ static void test_registerOIDFunction(void) ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError()); } +/* Free *pInfo with HeapFree */ +static void testExportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO *pInfo) +{ + BOOL ret; + DWORD size = 0; + HCRYPTKEY key; + + /* This crashes + ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, NULL); + */ + ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, &size); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError()); + ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, 0, NULL, 0, NULL, NULL, + &size); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError()); + ret = CryptExportPublicKeyInfoEx(0, 0, X509_ASN_ENCODING, NULL, 0, NULL, + NULL, &size); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError()); + ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, X509_ASN_ENCODING, NULL, + 0, NULL, NULL, &size); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError()); + /* Test with no key */ + ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING, NULL, + 0, NULL, NULL, &size); + ok(!ret && GetLastError() == NTE_NO_KEY, "Expected NTE_NO_KEY, got %08lx\n", + GetLastError()); + ret = CryptGenKey(csp, AT_SIGNATURE, 0, &key); + ok(ret, "CryptGenKey failed: %08lx\n", GetLastError()); + if (ret) + { + ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING, + NULL, 0, NULL, NULL, &size); + ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n", GetLastError()); + *pInfo = HeapAlloc(GetProcessHeap(), 0, size); + if (*pInfo) + { + ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, + X509_ASN_ENCODING, NULL, 0, NULL, *pInfo, &size); + ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n", + GetLastError()); + if (ret) + { + /* By default (we passed NULL as the OID) the OID is + * szOID_RSA_RSA. + */ + ok(!strcmp((*pInfo)->Algorithm.pszObjId, szOID_RSA_RSA), + "Expected %s, got %s\n", szOID_RSA_RSA, + (*pInfo)->Algorithm.pszObjId); + } + } + } +} + +static void testImportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO info) +{ + BOOL ret; + HCRYPTKEY key; + + /* These crash + ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, NULL); + ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, &key); + ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, NULL); + ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL, + NULL); + */ + ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, &key); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError()); + ret = CryptImportPublicKeyInfoEx(csp, 0, info, 0, 0, NULL, &key); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError()); + ret = CryptImportPublicKeyInfoEx(0, X509_ASN_ENCODING, info, 0, 0, NULL, + &key); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError()); + ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL, + &key); + ok(ret, "CryptImportPublicKeyInfoEx failed: %08lx\n", GetLastError()); + CryptDestroyKey(key); +} + +static const char cspName[] = "WineCryptTemp"; + +static void testPortPublicKeyInfo(void) +{ + HCRYPTPROV csp; + BOOL ret; + PCERT_PUBLIC_KEY_INFO info = NULL; + + /* Just in case a previous run failed, delete this thing */ + CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL, + CRYPT_DELETEKEYSET); + ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL, + CRYPT_NEWKEYSET); + + testExportPublicKey(csp, &info); + testImportPublicKey(csp, info); + + HeapFree(GetProcessHeap(), 0, info); + CryptReleaseContext(csp, 0); + ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL, + CRYPT_DELETEKEYSET); +} + START_TEST(encode) { static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING, @@ -2510,4 +2618,5 @@ START_TEST(encode) test_decodeCRLToBeSigned(encodings[i]); } test_registerOIDFunction(); + testPortPublicKeyInfo(); }