crypt32: Implement CertGetPublicKeyLength.
diff --git a/dlls/crypt32/cert.c b/dlls/crypt32/cert.c
index b131f11..185f133 100644
--- a/dlls/crypt32/cert.c
+++ b/dlls/crypt32/cert.c
@@ -772,6 +772,45 @@
return ret;
}
+DWORD WINAPI CertGetPublicKeyLength(DWORD dwCertEncodingType,
+ PCERT_PUBLIC_KEY_INFO pPublicKey)
+{
+ DWORD len = 0;
+
+ TRACE("(%08lx, %p)\n", dwCertEncodingType, pPublicKey);
+
+ if (dwCertEncodingType != X509_ASN_ENCODING)
+ {
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ return 0;
+ }
+ if (pPublicKey->Algorithm.pszObjId &&
+ !strcmp(pPublicKey->Algorithm.pszObjId, szOID_RSA_DH))
+ {
+ FIXME("unimplemented for DH public keys\n");
+ SetLastError(CRYPT_E_ASN1_BADTAG);
+ }
+ else
+ {
+ DWORD size;
+ PBYTE buf;
+ BOOL ret = CryptDecodeObjectEx(dwCertEncodingType,
+ RSA_CSP_PUBLICKEYBLOB, pPublicKey->PublicKey.pbData,
+ pPublicKey->PublicKey.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf,
+ &size);
+
+ if (ret)
+ {
+ RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)((LPBYTE)buf +
+ sizeof(BLOBHEADER));
+
+ len = rsaPubKey->bitlen;
+ LocalFree(buf);
+ }
+ }
+ return len;
+}
+
typedef BOOL (*CertCompareFunc)(PCCERT_CONTEXT pCertContext, DWORD dwType,
DWORD dwFlags, const void *pvPara);
diff --git a/dlls/crypt32/crypt32.spec b/dlls/crypt32/crypt32.spec
index ab2c947..8da0dad 100644
--- a/dlls/crypt32/crypt32.spec
+++ b/dlls/crypt32/crypt32.spec
@@ -57,7 +57,7 @@
@ stdcall CertGetIssuerCertificateFromStore(long ptr ptr ptr)
@ stdcall CertGetNameStringA(ptr long long ptr ptr long)
@ stdcall CertGetNameStringW(ptr long long ptr ptr long)
-@ stub CertGetPublicKeyLength
+@ stdcall CertGetPublicKeyLength(long ptr)
@ stdcall CertGetSubjectCertificateFromStore(ptr long ptr)
@ stdcall CertGetValidUsages(long ptr ptr ptr ptr)
@ stub CertIsRDNAttrsInCertificateName
diff --git a/dlls/crypt32/tests/cert.c b/dlls/crypt32/tests/cert.c
index f1bec9f..398ef15 100644
--- a/dlls/crypt32/tests/cert.c
+++ b/dlls/crypt32/tests/cert.c
@@ -1903,6 +1903,82 @@
CertFreeCertificateContext(cert);
}
+static void testGetPublicKeyLength(void)
+{
+ static char oid_rsa_rsa[] = szOID_RSA_RSA;
+ static char oid_rsa_dh[] = szOID_RSA_DH;
+ static char bogusOID[] = "1.2.3";
+ DWORD ret;
+ CERT_PUBLIC_KEY_INFO info = { { 0 } };
+ BYTE bogusKey[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
+ BYTE key[] = { 0x30,0x0f,0x02,0x08,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+ 0x02,0x03,0x01,0x00,0x01 };
+
+ /* Crashes
+ ret = CertGetPublicKeyLength(0, NULL);
+ */
+ /* With an empty public key info */
+ SetLastError(0xdeadbeef);
+ ret = CertGetPublicKeyLength(0, &info);
+ ok(ret == 0 && GetLastError() == ERROR_FILE_NOT_FOUND,
+ "Expected length 0 and ERROR_FILE_NOT_FOUND, got length %ld, %08lx\n",
+ ret, GetLastError());
+ SetLastError(0xdeadbeef);
+ ret = CertGetPublicKeyLength(X509_ASN_ENCODING, &info);
+ ok(ret == 0 && GetLastError() == CRYPT_E_ASN1_EOD,
+ "Expected length 0 and CRYPT_E_ASN1_EOD, got length %ld, %08lx\n",
+ ret, GetLastError());
+ /* With a nearly-empty public key info */
+ info.Algorithm.pszObjId = oid_rsa_rsa;
+ SetLastError(0xdeadbeef);
+ ret = CertGetPublicKeyLength(0, &info);
+ ok(ret == 0 && GetLastError() == ERROR_FILE_NOT_FOUND,
+ "Expected length 0 and ERROR_FILE_NOT_FOUND, got length %ld, %08lx\n",
+ ret, GetLastError());
+ SetLastError(0xdeadbeef);
+ ret = CertGetPublicKeyLength(X509_ASN_ENCODING, &info);
+ ok(ret == 0 && GetLastError() == CRYPT_E_ASN1_EOD,
+ "Expected length 0 and CRYPT_E_ASN1_EOD, got length %ld, %08lx\n",
+ ret, GetLastError());
+ /* With a bogus key */
+ info.PublicKey.cbData = sizeof(bogusKey);
+ info.PublicKey.pbData = bogusKey;
+ SetLastError(0xdeadbeef);
+ ret = CertGetPublicKeyLength(0, &info);
+ ok(ret == 0 && GetLastError() == ERROR_FILE_NOT_FOUND,
+ "Expected length 0 and ERROR_FILE_NOT_FOUND, got length %ld, %08lx\n",
+ ret, GetLastError());
+ SetLastError(0xdeadbeef);
+ ret = CertGetPublicKeyLength(X509_ASN_ENCODING, &info);
+ ok(ret == 0 && GetLastError() == CRYPT_E_ASN1_BADTAG,
+ "Expected length 0 and CRYPT_E_ASN1_BADTAGTAG, got length %ld, %08lx\n",
+ ret, GetLastError());
+ /* With a believable RSA key but a bogus OID */
+ info.Algorithm.pszObjId = bogusOID;
+ info.PublicKey.cbData = sizeof(key);
+ info.PublicKey.pbData = key;
+ SetLastError(0xdeadbeef);
+ ret = CertGetPublicKeyLength(0, &info);
+ ok(ret == 0 && GetLastError() == ERROR_FILE_NOT_FOUND,
+ "Expected length 0 and ERROR_FILE_NOT_FOUND, got length %ld, %08lx\n",
+ ret, GetLastError());
+ SetLastError(0xdeadbeef);
+ ret = CertGetPublicKeyLength(X509_ASN_ENCODING, &info);
+ ok(ret == 56, "Expected length 56, got %ld\n", ret);
+ /* An RSA key with the DH OID */
+ info.Algorithm.pszObjId = oid_rsa_dh;
+ SetLastError(0xdeadbeef);
+ ret = CertGetPublicKeyLength(X509_ASN_ENCODING, &info);
+ ok(ret == 0 && GetLastError() == CRYPT_E_ASN1_BADTAG,
+ "Expected length 0 and CRYPT_E_ASN1_BADTAG, got length %ld, %08lx\n",
+ ret, GetLastError());
+ /* With the RSA OID */
+ info.Algorithm.pszObjId = oid_rsa_rsa;
+ SetLastError(0xdeadbeef);
+ ret = CertGetPublicKeyLength(X509_ASN_ENCODING, &info);
+ ok(ret == 56, "Expected length 56, got %ld\n", ret);
+}
+
START_TEST(cert)
{
init_function_pointers();
@@ -1925,4 +2001,5 @@
testCompareCert();
testVerifySubjectCert();
testAcquireCertPrivateKey();
+ testGetPublicKeyLength();
}