From 7fb8ee199521241d637f82ebf1f662de819b1e9b Mon Sep 17 00:00:00 2001 From: Vincent Povirk Date: Thu, 26 Feb 2015 14:48:05 -0600 Subject: [PATCH] crypt32: Implement PKCS_RSA_PRIVATE_KEY decoding. --- dlls/crypt32/decode.c | 144 ++++++++++++++++++++++++++++++++++++ dlls/crypt32/tests/encode.c | 4 +- 2 files changed, 146 insertions(+), 2 deletions(-) diff --git a/dlls/crypt32/decode.c b/dlls/crypt32/decode.c index e5f8baff0bf..90d8cdf8ac7 100644 --- a/dlls/crypt32/decode.c +++ b/dlls/crypt32/decode.c @@ -3936,6 +3936,147 @@ static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType, return ret; } +#define RSA2_MAGIC 0x32415352 + +struct DECODED_RSA_PRIV_KEY +{ + DWORD version; + DWORD pubexp; + CRYPT_INTEGER_BLOB modulus; + CRYPT_INTEGER_BLOB privexp; + CRYPT_INTEGER_BLOB prime1; + CRYPT_INTEGER_BLOB prime2; + CRYPT_INTEGER_BLOB exponent1; + CRYPT_INTEGER_BLOB exponent2; + CRYPT_INTEGER_BLOB coefficient; +}; + +static BOOL WINAPI CRYPT_AsnDecodeRsaPrivKey(DWORD dwCertEncodingType, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, + PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) +{ + BOOL ret; + DWORD halflen; + + __TRY + { + struct AsnDecodeSequenceItem items[] = { + { ASN_INTEGER, offsetof(struct DECODED_RSA_PRIV_KEY, version), + CRYPT_AsnDecodeIntInternal, sizeof(DWORD), FALSE, FALSE, 0, 0 }, + { ASN_INTEGER, offsetof(struct DECODED_RSA_PRIV_KEY, modulus), + CRYPT_AsnDecodeUnsignedIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), + FALSE, TRUE, offsetof(struct DECODED_RSA_PRIV_KEY, modulus.pbData), + 0 }, + { ASN_INTEGER, offsetof(struct DECODED_RSA_PRIV_KEY, pubexp), + CRYPT_AsnDecodeIntInternal, sizeof(DWORD), FALSE, FALSE, 0, 0 }, + { ASN_INTEGER, offsetof(struct DECODED_RSA_PRIV_KEY, privexp), + CRYPT_AsnDecodeUnsignedIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), + FALSE, TRUE, offsetof(struct DECODED_RSA_PRIV_KEY, privexp.pbData), + 0 }, + { ASN_INTEGER, offsetof(struct DECODED_RSA_PRIV_KEY, prime1), + CRYPT_AsnDecodeUnsignedIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), + FALSE, TRUE, offsetof(struct DECODED_RSA_PRIV_KEY, prime1.pbData), + 0 }, + { ASN_INTEGER, offsetof(struct DECODED_RSA_PRIV_KEY, prime2), + CRYPT_AsnDecodeUnsignedIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), + FALSE, TRUE, offsetof(struct DECODED_RSA_PRIV_KEY, prime2.pbData), + 0 }, + { ASN_INTEGER, offsetof(struct DECODED_RSA_PRIV_KEY, exponent1), + CRYPT_AsnDecodeUnsignedIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), + FALSE, TRUE, offsetof(struct DECODED_RSA_PRIV_KEY, exponent1.pbData), + 0 }, + { ASN_INTEGER, offsetof(struct DECODED_RSA_PRIV_KEY, exponent2), + CRYPT_AsnDecodeUnsignedIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), + FALSE, TRUE, offsetof(struct DECODED_RSA_PRIV_KEY, exponent2.pbData), + 0 }, + { ASN_INTEGER, offsetof(struct DECODED_RSA_PRIV_KEY, coefficient), + CRYPT_AsnDecodeUnsignedIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), + FALSE, TRUE, offsetof(struct DECODED_RSA_PRIV_KEY, coefficient.pbData), + 0 }, + }; + struct DECODED_RSA_PRIV_KEY *decodedKey = NULL; + DWORD size = 0; + + ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]), + pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &decodedKey, + &size, NULL, NULL); + if (ret) + { + halflen = decodedKey->modulus.cbData / 2; + if ((decodedKey->modulus.cbData != halflen * 2) || + (decodedKey->prime1.cbData != halflen) || + (decodedKey->prime2.cbData != halflen) || + (decodedKey->exponent1.cbData != halflen) || + (decodedKey->exponent2.cbData != halflen) || + (decodedKey->coefficient.cbData != halflen) || + (decodedKey->privexp.cbData != halflen * 2)) + { + ret = FALSE; + SetLastError(CRYPT_E_BAD_ENCODE); + } + + if (ret) + { + DWORD bytesNeeded = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + + (halflen * 9); + + if (!pvStructInfo) + { + *pcbStructInfo = bytesNeeded; + ret = TRUE; + } + else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, + pvStructInfo, pcbStructInfo, bytesNeeded))) + { + BLOBHEADER *hdr; + RSAPUBKEY *rsaPubKey; + BYTE *vardata; + + if (dwFlags & CRYPT_DECODE_ALLOC_FLAG) + pvStructInfo = *(BYTE **)pvStructInfo; + + hdr = pvStructInfo; + hdr->bType = PRIVATEKEYBLOB; + hdr->bVersion = CUR_BLOB_VERSION; + hdr->reserved = 0; + hdr->aiKeyAlg = CALG_RSA_KEYX; + + rsaPubKey = (RSAPUBKEY *)((BYTE *)pvStructInfo + + sizeof(BLOBHEADER)); + rsaPubKey->magic = RSA2_MAGIC; + rsaPubKey->pubexp = decodedKey->pubexp; + rsaPubKey->bitlen = halflen * 16; + + vardata = (BYTE*)(rsaPubKey + 1); + memcpy(vardata, + decodedKey->modulus.pbData, halflen * 2); + memcpy(vardata + halflen * 2, + decodedKey->prime1.pbData, halflen); + memcpy(vardata + halflen * 3, + decodedKey->prime2.pbData, halflen); + memcpy(vardata + halflen * 4, + decodedKey->exponent1.pbData, halflen); + memcpy(vardata + halflen * 5, + decodedKey->exponent2.pbData, halflen); + memcpy(vardata + halflen * 6, + decodedKey->coefficient.pbData, halflen); + memcpy(vardata + halflen * 7, + decodedKey->privexp.pbData, halflen * 2); + } + } + + LocalFree(decodedKey); + } + } + __EXCEPT_PAGE_FAULT + { + SetLastError(STATUS_ACCESS_VIOLATION); + ret = FALSE; + } + __ENDTRY + return ret; +} + static BOOL CRYPT_AsnDecodeOctetsInternal(const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded) @@ -5798,6 +5939,9 @@ static CryptDecodeObjectExFunc CRYPT_GetBuiltinDecoder(DWORD dwCertEncodingType, case LOWORD(RSA_CSP_PUBLICKEYBLOB): decodeFunc = CRYPT_AsnDecodeRsaPubKey; break; + case LOWORD(PKCS_RSA_PRIVATE_KEY): + decodeFunc = CRYPT_AsnDecodeRsaPrivKey; + break; case LOWORD(X509_UNICODE_NAME): decodeFunc = CRYPT_AsnDecodeUnicodeName; break; diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c index 3240a84fcac..b45b5f2eea9 100644 --- a/dlls/crypt32/tests/encode.c +++ b/dlls/crypt32/tests/encode.c @@ -8101,7 +8101,7 @@ static void test_decodeRsaPrivateKey(DWORD dwEncoding) ret = pCryptDecodeObjectEx(dwEncoding, PKCS_RSA_PRIVATE_KEY, rsaPrivKeyDer, sizeof(rsaPrivKeyDer)-10, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); - todo_wine ok(!ret && (GetLastError() == CRYPT_E_ASN1_EOD), + ok(!ret && (GetLastError() == CRYPT_E_ASN1_EOD), "Expected CRYPT_E_ASN1_EOD, got %08x\n", GetLastError()); @@ -8110,7 +8110,7 @@ static void test_decodeRsaPrivateKey(DWORD dwEncoding) ret = pCryptDecodeObjectEx(dwEncoding, PKCS_RSA_PRIVATE_KEY, rsaPrivKeyDer, sizeof(rsaPrivKeyDer), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); - todo_wine ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); if (ret) {