Commit f5b48061 authored by Juan Lang's avatar Juan Lang Committed by Alexandre Julliard

crypt32: Implement CryptVerifyMessageSignature.

parent 3a9e1d66
......@@ -235,15 +235,3 @@ BOOL WINAPI CryptQueryObject(DWORD dwObjectType, const void* pvObject,
phCertStore, phMsg, ppvContext);
return FALSE;
}
BOOL WINAPI CryptVerifyMessageSignature(PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara,
DWORD dwSignerIndex, const BYTE* pbSignedBlob, DWORD cbSignedBlob,
BYTE* pbDecoded, DWORD* pcbDecoded, PCCERT_CONTEXT* ppSignerCert)
{
FIXME("stub: %p, %d, %p, %d, %p, %p, %p\n",
pVerifyPara, dwSignerIndex, pbSignedBlob, cbSignedBlob,
pbDecoded, pcbDecoded, ppSignerCert);
if (ppSignerCert)
*ppSignerCert = NULL;
return FALSE;
}
......@@ -2321,3 +2321,135 @@ LONG WINAPI CryptGetMessageSignerCount(DWORD dwMsgEncodingType,
}
return count;
}
static CERT_INFO *CRYPT_GetSignerCertInfoFromMsg(HCRYPTMSG msg,
DWORD dwSignerIndex)
{
CERT_INFO *certInfo = NULL;
DWORD size;
if (CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM, dwSignerIndex, NULL,
&size))
{
certInfo = CryptMemAlloc(size);
if (certInfo)
{
if (!CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM,
dwSignerIndex, certInfo, &size))
{
CryptMemFree(certInfo);
certInfo = NULL;
}
}
}
return certInfo;
}
static PCCERT_CONTEXT WINAPI CRYPT_DefaultGetSignerCertificate(void *pvGetArg,
DWORD dwCertEncodingType, PCERT_INFO pSignerId, HCERTSTORE hMsgCertStore)
{
return CertFindCertificateInStore(hMsgCertStore, dwCertEncodingType, 0,
CERT_FIND_SUBJECT_CERT, pSignerId, NULL);
}
static inline PCCERT_CONTEXT CRYPT_GetSignerCertificate(HCRYPTMSG msg,
PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara, PCERT_INFO certInfo, HCERTSTORE store)
{
PFN_CRYPT_GET_SIGNER_CERTIFICATE getCert;
if (pVerifyPara->pfnGetSignerCertificate)
getCert = pVerifyPara->pfnGetSignerCertificate;
else
getCert = CRYPT_DefaultGetSignerCertificate;
return getCert(pVerifyPara->pvGetArg,
pVerifyPara->dwMsgAndCertEncodingType, certInfo, store);
}
BOOL WINAPI CryptVerifyMessageSignature(PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara,
DWORD dwSignerIndex, const BYTE* pbSignedBlob, DWORD cbSignedBlob,
BYTE* pbDecoded, DWORD* pcbDecoded, PCCERT_CONTEXT* ppSignerCert)
{
BOOL ret = FALSE;
DWORD size;
CRYPT_CONTENT_INFO *contentInfo;
TRACE("(%p, %d, %p, %d, %p, %p, %p)\n",
pVerifyPara, dwSignerIndex, pbSignedBlob, cbSignedBlob,
pbDecoded, pcbDecoded, ppSignerCert);
if (ppSignerCert)
*ppSignerCert = NULL;
if (pcbDecoded)
*pcbDecoded = 0;
if (!pVerifyPara ||
pVerifyPara->cbSize != sizeof(CRYPT_VERIFY_MESSAGE_PARA) ||
GET_CMSG_ENCODING_TYPE(pVerifyPara->dwMsgAndCertEncodingType) !=
PKCS_7_ASN_ENCODING)
{
SetLastError(E_INVALIDARG);
return FALSE;
}
ret = CryptDecodeObjectEx(pVerifyPara->dwMsgAndCertEncodingType,
PKCS_CONTENT_INFO, pbSignedBlob, cbSignedBlob,
CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
(LPBYTE)&contentInfo, &size);
if (ret)
{
if (strcmp(contentInfo->pszObjId, szOID_RSA_signedData))
{
SetLastError(CRYPT_E_UNEXPECTED_MSG_TYPE);
ret = FALSE;
}
else
{
HCRYPTMSG msg = CryptMsgOpenToDecode(
pVerifyPara->dwMsgAndCertEncodingType, 0, CMSG_SIGNED,
pVerifyPara->hCryptProv, NULL, NULL);
if (msg)
{
ret = CryptMsgUpdate(msg, contentInfo->Content.pbData,
contentInfo->Content.cbData, TRUE);
if (ret && pcbDecoded)
ret = CRYPT_CopyParam(pbDecoded, pcbDecoded,
contentInfo->Content.pbData, contentInfo->Content.cbData);
if (ret)
{
CERT_INFO *certInfo = CRYPT_GetSignerCertInfoFromMsg(msg,
dwSignerIndex);
ret = FALSE;
if (certInfo)
{
HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MSG,
pVerifyPara->dwMsgAndCertEncodingType,
pVerifyPara->hCryptProv, 0, msg);
if (store)
{
PCCERT_CONTEXT cert = CRYPT_GetSignerCertificate(
msg, pVerifyPara, certInfo, store);
if (cert)
{
ret = CryptMsgControl(msg, 0,
CMSG_CTRL_VERIFY_SIGNATURE, cert->pCertInfo);
if (ret && ppSignerCert)
*ppSignerCert = cert;
else
CertFreeCertificateContext(cert);
}
CertCloseStore(store, 0);
}
}
CryptMemFree(certInfo);
}
CryptMsgClose(msg);
}
}
LocalFree(contentInfo);
}
TRACE("returning %d\n", ret);
return ret;
}
......@@ -2487,6 +2487,145 @@ static void test_msg_get_signer_count(void)
ok(count == 1, "Expected 1, got %d\n", count);
}
static const BYTE signedWithCertEmptyContent[] = {
0x30,0x81,0xdf,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0,
0x81,0xd1,0x30,0x81,0xce,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,
0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0xa0,0x7c,
0x30,0x7a,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11,
0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,
0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,
0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,
0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,
0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,
0x00,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,0xa3,0x16,0x30,0x14,0x30,
0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,
0xff,0x02,0x01,0x01,0x31,0x37,0x30,0x35,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,
0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,
0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,
0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x04,
0x00 };
static const BYTE signedWithCertContent[] = {
0x30,0x82,0x01,0x32,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,
0xa0,0x82,0x01,0x23,0x30,0x82,0x01,0x1f,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,
0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x13,0x06,
0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x06,0x04,0x04,0x01,
0x02,0x03,0x04,0xa0,0x7c,0x30,0x7a,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,
0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,
0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,
0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,
0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,
0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,
0x20,0x4c,0x61,0x6e,0x67,0x00,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,
0xa3,0x16,0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,
0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01,0x31,0x77,0x30,0x75,0x02,0x01,
0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,
0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,
0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04,
0x06,0x00,0x05,0x00,0x04,0x40,0x81,0xa6,0x70,0xb3,0xef,0x59,0xd1,0x66,0xd1,
0x9b,0xc0,0x9a,0xb6,0x9a,0x5e,0x6d,0x6f,0x6d,0x0d,0x59,0xa9,0xaa,0x6e,0xe9,
0x2c,0xa0,0x1e,0xee,0xc2,0x60,0xbc,0x59,0xbe,0x3f,0x63,0x06,0x8d,0xc9,0x11,
0x1d,0x23,0x64,0x92,0xef,0x2e,0xfc,0x57,0x29,0xa4,0xaf,0xe0,0xee,0x93,0x19,
0x39,0x51,0xe4,0x44,0xb8,0x0b,0x28,0xf4,0xa8,0x0d };
static const BYTE signedWithCertWithPubKeyContent[] = {
0x30,0x81,0xfc,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0,
0x81,0xee,0x30,0x81,0xeb,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,
0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0xa0,0x81,
0x98,0x30,0x81,0x95,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,
0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,
0x61,0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,
0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,
0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,
0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,
0x6e,0x67,0x00,0x30,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,
0x01,0x01,0x01,0x05,0x00,0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,
0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xa3,0x16,0x30,0x14,0x30,0x12,
0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,
0x02,0x01,0x01,0x31,0x37,0x30,0x35,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31,
0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,
0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,
0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x04,0x00 };
static void test_verify_message_signature(void)
{
BOOL ret;
CRYPT_VERIFY_MESSAGE_PARA para = { 0 };
PCCERT_CONTEXT cert;
DWORD cbDecoded;
SetLastError(0xdeadbeef);
ret = CryptVerifyMessageSignature(NULL, 0, NULL, 0, NULL, 0, NULL);
ok(!ret && GetLastError() == E_INVALIDARG,
"Expected E_INVALIDARG, got %08x\n", GetLastError());
SetLastError(0xdeadbeef);
ret = CryptVerifyMessageSignature(&para, 0, NULL, 0, NULL, 0, NULL);
ok(!ret && GetLastError() == E_INVALIDARG,
"Expected E_INVALIDARG, got %08x\n", GetLastError());
para.cbSize = sizeof(para);
SetLastError(0xdeadbeef);
ret = CryptVerifyMessageSignature(&para, 0, NULL, 0, NULL, 0, NULL);
ok(!ret && GetLastError() == E_INVALIDARG,
"Expected E_INVALIDARG, got %08x\n", GetLastError());
para.cbSize = 0;
para.dwMsgAndCertEncodingType = PKCS_7_ASN_ENCODING;
SetLastError(0xdeadbeef);
ret = CryptVerifyMessageSignature(&para, 0, NULL, 0, NULL, 0, NULL);
ok(!ret && GetLastError() == E_INVALIDARG,
"Expected E_INVALIDARG, got %08x\n", GetLastError());
para.cbSize = sizeof(para);
SetLastError(0xdeadbeef);
ret = CryptVerifyMessageSignature(&para, 0, NULL, 0, NULL, 0, NULL);
ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
"Expected CRYPT_E_ASN1_EOD, got %08x\n", GetLastError());
/* Check whether cert is set on error */
cert = (PCCERT_CONTEXT)0xdeadbeef;
ret = CryptVerifyMessageSignature(&para, 0, NULL, 0, NULL, 0, &cert);
ok(cert == NULL, "Expected NULL cert\n");
/* Check whether cbDecoded is set on error */
cbDecoded = 0xdeadbeef;
ret = CryptVerifyMessageSignature(&para, 0, NULL, 0, NULL, &cbDecoded,
NULL);
ok(!cbDecoded, "Expected 0\n");
SetLastError(0xdeadbeef);
ret = CryptVerifyMessageSignature(&para, 0, dataEmptyBareContent,
sizeof(dataEmptyBareContent), NULL, 0, NULL);
ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
"Expected CRYPT_E_ASN1_BADTAG, got %08x\n", GetLastError());
SetLastError(0xdeadbeef);
ret = CryptVerifyMessageSignature(&para, 0, dataEmptyContent,
sizeof(dataEmptyContent), NULL, 0, NULL);
ok(!ret && GetLastError() == CRYPT_E_UNEXPECTED_MSG_TYPE,
"Expected CRYPT_E_UNEXPECTED_MSG_TYPE, got %08x\n", GetLastError());
SetLastError(0xdeadbeef);
ret = CryptVerifyMessageSignature(&para, 0, signedEmptyBareContent,
sizeof(signedEmptyBareContent), NULL, 0, NULL);
ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
"Expected CRYPT_E_ASN1_BADTAG, got %08x\n", GetLastError());
SetLastError(0xdeadbeef);
ret = CryptVerifyMessageSignature(&para, 0, signedEmptyContent,
sizeof(signedEmptyContent), NULL, 0, NULL);
ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
"Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
SetLastError(0xdeadbeef);
ret = CryptVerifyMessageSignature(&para, 0, signedContent,
sizeof(signedContent), NULL, 0, NULL);
ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
"Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
/* FIXME: Windows fails with CRYPT_E_NOT_FOUND for these messages, but
* their signer certs have invalid public keys that fail to decode. In
* Wine therefore the failure is an ASN error. Need some messages with
* valid public keys and invalid signatures to check against.
*/
ret = CryptVerifyMessageSignature(&para, 0, signedWithCertEmptyContent,
sizeof(signedWithCertEmptyContent), NULL, 0, NULL);
ok(!ret, "Expected failure\n");
ret = CryptVerifyMessageSignature(&para, 0, signedWithCertContent,
sizeof(signedWithCertContent), NULL, 0, NULL);
ok(!ret, "Expected failure\n");
ret = CryptVerifyMessageSignature(&para, 0, signedWithCertWithPubKeyContent,
sizeof(signedWithCertWithPubKeyContent), NULL, 0, NULL);
ok(!ret, "Expected failure\n");
}
START_TEST(msg)
{
init_function_pointers();
......@@ -2506,4 +2645,5 @@ START_TEST(msg)
/* simplified message functions */
test_msg_get_signer_count();
test_verify_message_signature();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment