mirror of
https://github.com/reactos/wine.git
synced 2024-11-29 06:30:37 +00:00
Implement encoding/decoding RSA public keys.
This commit is contained in:
parent
6389dbc979
commit
8c08dbfd12
@ -1690,6 +1690,47 @@ static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
|
||||
{
|
||||
BOOL ret;
|
||||
|
||||
__TRY
|
||||
{
|
||||
const BLOBHEADER *hdr =
|
||||
(const BLOBHEADER *)pvStructInfo;
|
||||
|
||||
if (hdr->bType != PUBLICKEYBLOB)
|
||||
{
|
||||
SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
|
||||
ret = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
const RSAPUBKEY *rsaPubKey = (const RSAPUBKEY *)
|
||||
((const BYTE *)pvStructInfo + sizeof(BLOBHEADER));
|
||||
CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8,
|
||||
(BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) };
|
||||
struct AsnEncodeSequenceItem items[] = {
|
||||
{ &blob, CRYPT_AsnEncodeInteger, 0 },
|
||||
{ &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 },
|
||||
};
|
||||
|
||||
ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
|
||||
sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
|
||||
pcbEncoded);
|
||||
}
|
||||
}
|
||||
__EXCEPT(page_fault)
|
||||
{
|
||||
SetLastError(STATUS_ACCESS_VIOLATION);
|
||||
ret = FALSE;
|
||||
}
|
||||
__ENDTRY
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
|
||||
@ -2277,6 +2318,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
|
||||
case (WORD)X509_BASIC_CONSTRAINTS2:
|
||||
encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
|
||||
break;
|
||||
case (WORD)RSA_CSP_PUBLICKEYBLOB:
|
||||
encodeFunc = CRYPT_AsnEncodeRsaPubKey;
|
||||
break;
|
||||
case (WORD)X509_OCTET_STRING:
|
||||
encodeFunc = CRYPT_AsnEncodeOctets;
|
||||
break;
|
||||
@ -2404,8 +2448,16 @@ static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded,
|
||||
}
|
||||
else if (pbEncoded[1] <= 0x7f)
|
||||
{
|
||||
*len = pbEncoded[1];
|
||||
ret = TRUE;
|
||||
if (pbEncoded[1] + 1 > cbEncoded)
|
||||
{
|
||||
SetLastError(CRYPT_E_ASN1_EOD);
|
||||
ret = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*len = pbEncoded[1];
|
||||
ret = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -4356,6 +4408,80 @@ static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define RSA1_MAGIC 0x31415352
|
||||
|
||||
struct DECODED_RSA_PUB_KEY
|
||||
{
|
||||
DWORD pubexp;
|
||||
CRYPT_INTEGER_BLOB modulus;
|
||||
};
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
|
||||
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
|
||||
{
|
||||
BOOL ret;
|
||||
|
||||
__TRY
|
||||
{
|
||||
struct AsnDecodeSequenceItem items[] = {
|
||||
{ offsetof(struct DECODED_RSA_PUB_KEY, modulus),
|
||||
CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_INTEGER_BLOB),
|
||||
FALSE, TRUE, offsetof(struct DECODED_RSA_PUB_KEY, modulus.pbData),
|
||||
0 },
|
||||
{ offsetof(struct DECODED_RSA_PUB_KEY, pubexp),
|
||||
CRYPT_AsnDecodeInt, sizeof(DWORD), FALSE, FALSE, 0, 0 },
|
||||
};
|
||||
struct DECODED_RSA_PUB_KEY *decodedKey = NULL;
|
||||
DWORD size = 0;
|
||||
|
||||
ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
|
||||
sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded,
|
||||
CRYPT_DECODE_ALLOC_FLAG, NULL, &decodedKey, &size, NULL);
|
||||
if (ret)
|
||||
{
|
||||
DWORD bytesNeeded = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
|
||||
decodedKey->modulus.cbData;
|
||||
|
||||
if (!pvStructInfo)
|
||||
{
|
||||
*pcbStructInfo = bytesNeeded;
|
||||
ret = TRUE;
|
||||
}
|
||||
else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
|
||||
pvStructInfo, pcbStructInfo, bytesNeeded)))
|
||||
{
|
||||
BLOBHEADER *hdr;
|
||||
RSAPUBKEY *rsaPubKey;
|
||||
|
||||
if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
|
||||
pvStructInfo = *(BYTE **)pvStructInfo;
|
||||
hdr = (BLOBHEADER *)pvStructInfo;
|
||||
hdr->bType = PUBLICKEYBLOB;
|
||||
hdr->bVersion = CUR_BLOB_VERSION;
|
||||
hdr->reserved = 0;
|
||||
hdr->aiKeyAlg = CALG_RSA_KEYX;
|
||||
rsaPubKey = (RSAPUBKEY *)((BYTE *)pvStructInfo +
|
||||
sizeof(BLOBHEADER));
|
||||
rsaPubKey->magic = RSA1_MAGIC;
|
||||
rsaPubKey->pubexp = decodedKey->pubexp;
|
||||
rsaPubKey->bitlen = decodedKey->modulus.cbData * 8;
|
||||
memcpy((BYTE *)pvStructInfo + sizeof(BLOBHEADER) +
|
||||
sizeof(RSAPUBKEY), decodedKey->modulus.pbData,
|
||||
decodedKey->modulus.cbData);
|
||||
}
|
||||
LocalFree(decodedKey);
|
||||
}
|
||||
}
|
||||
__EXCEPT(page_fault)
|
||||
{
|
||||
SetLastError(STATUS_ACCESS_VIOLATION);
|
||||
ret = FALSE;
|
||||
}
|
||||
__ENDTRY
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
|
||||
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
|
||||
@ -5268,6 +5394,9 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
|
||||
case (WORD)X509_BASIC_CONSTRAINTS2:
|
||||
decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
|
||||
break;
|
||||
case (WORD)RSA_CSP_PUBLICKEYBLOB:
|
||||
decodeFunc = CRYPT_AsnDecodeRsaPubKey;
|
||||
break;
|
||||
case (WORD)X509_OCTET_STRING:
|
||||
decodeFunc = CRYPT_AsnDecodeOctets;
|
||||
break;
|
||||
|
@ -847,16 +847,6 @@ static const BYTE localhost[] = { 127, 0, 0, 1 };
|
||||
static const BYTE encodedIPAddr[] = { 0x30, 0x06, 0x87, 0x04, 0x7f, 0x00, 0x00,
|
||||
0x01 };
|
||||
|
||||
static void printBytes(const char *hdr, const BYTE *pb, size_t cb)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
printf("%s:\n", hdr);
|
||||
for (i = 0; i < cb; i++)
|
||||
printf("%02x ", pb[i]);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
static void test_encodeAltName(DWORD dwEncoding)
|
||||
{
|
||||
static const WCHAR nihongo[] = { 0x226f, 0x575b, 0 };
|
||||
@ -1334,6 +1324,164 @@ static void test_decodeBasicConstraints(DWORD dwEncoding)
|
||||
"Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
|
||||
}
|
||||
|
||||
/* These are terrible public keys of course, I'm just testing encoding */
|
||||
static const BYTE modulus1[] = { 0,0,0,1,1,1,1,1 };
|
||||
static const BYTE modulus2[] = { 1,1,1,1,1,0,0,0 };
|
||||
|
||||
struct EncodedRSAPubKey
|
||||
{
|
||||
const BYTE *modulus;
|
||||
size_t modulusLen;
|
||||
const BYTE *encoded;
|
||||
size_t decodedModulusLen;
|
||||
};
|
||||
|
||||
struct EncodedRSAPubKey rsaPubKeys[] = {
|
||||
{ modulus1, sizeof(modulus1),
|
||||
"\x30\x0f\x02\x08\x01\x01\x01\x01\x01\x00\x00\x00\x02\x03\x01\x00\x01",
|
||||
sizeof(modulus1) },
|
||||
{ modulus2, sizeof(modulus2),
|
||||
"\x30\x0c\x02\x05\x01\x01\x01\x01\x01\x02\x03\x01\x00\x01",
|
||||
5 },
|
||||
};
|
||||
|
||||
static void test_encodeRsaPublicKey(DWORD dwEncoding)
|
||||
{
|
||||
BYTE toEncode[sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + sizeof(modulus1)];
|
||||
BLOBHEADER *hdr = (BLOBHEADER *)toEncode;
|
||||
RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(toEncode + sizeof(BLOBHEADER));
|
||||
BOOL ret;
|
||||
BYTE *buf = NULL;
|
||||
DWORD bufSize = 0;
|
||||
|
||||
/* Try with a bogus blob type */
|
||||
hdr->bType = 2;
|
||||
hdr->bVersion = CUR_BLOB_VERSION;
|
||||
hdr->reserved = 0;
|
||||
hdr->aiKeyAlg = CALG_RSA_KEYX;
|
||||
rsaPubKey->magic = 0x31415352;
|
||||
rsaPubKey->bitlen = sizeof(modulus1) * 8;
|
||||
rsaPubKey->pubexp = 65537;
|
||||
memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), modulus1,
|
||||
sizeof(modulus1));
|
||||
|
||||
ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
|
||||
toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
|
||||
&bufSize);
|
||||
ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
|
||||
"Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
|
||||
GetLastError());
|
||||
/* Now with a bogus reserved field */
|
||||
hdr->bType = PUBLICKEYBLOB;
|
||||
hdr->reserved = 1;
|
||||
ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
|
||||
toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
|
||||
&bufSize);
|
||||
if (buf)
|
||||
{
|
||||
ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
|
||||
"Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
|
||||
ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
|
||||
LocalFree(buf);
|
||||
}
|
||||
/* Now with a bogus blob version */
|
||||
hdr->reserved = 0;
|
||||
hdr->bVersion = 0;
|
||||
ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
|
||||
toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
|
||||
&bufSize);
|
||||
if (buf)
|
||||
{
|
||||
ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
|
||||
"Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
|
||||
ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
|
||||
LocalFree(buf);
|
||||
}
|
||||
/* And with a bogus alg ID */
|
||||
hdr->bVersion = CUR_BLOB_VERSION;
|
||||
hdr->aiKeyAlg = CALG_DES;
|
||||
ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
|
||||
toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
|
||||
&bufSize);
|
||||
if (buf)
|
||||
{
|
||||
ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
|
||||
"Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
|
||||
ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
|
||||
LocalFree(buf);
|
||||
}
|
||||
/* Finally, all valid, but change the modulus */
|
||||
hdr->aiKeyAlg = CALG_RSA_KEYX;
|
||||
memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), modulus2,
|
||||
sizeof(modulus2));
|
||||
ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
|
||||
toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
|
||||
&bufSize);
|
||||
if (buf)
|
||||
{
|
||||
ok(bufSize == rsaPubKeys[1].encoded[1] + 2,
|
||||
"Expected size %d, got %ld\n", rsaPubKeys[1].encoded[1] + 2, bufSize);
|
||||
ok(!memcmp(buf, rsaPubKeys[1].encoded, bufSize), "Unexpected value\n");
|
||||
LocalFree(buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_decodeRsaPublicKey(DWORD dwEncoding)
|
||||
{
|
||||
DWORD i;
|
||||
LPBYTE buf = NULL;
|
||||
DWORD bufSize = 0;
|
||||
BOOL ret;
|
||||
|
||||
/* Try with a bad length */
|
||||
ret = CryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
|
||||
rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1],
|
||||
CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
|
||||
ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
|
||||
"Expected CRYPT_E_ASN1_EOD, got %08lx\n", CRYPT_E_ASN1_EOD);
|
||||
/* Now try success cases */
|
||||
for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
|
||||
{
|
||||
bufSize = 0;
|
||||
ret = CryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
|
||||
rsaPubKeys[i].encoded, rsaPubKeys[i].encoded[1] + 2,
|
||||
CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
|
||||
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
|
||||
if (buf)
|
||||
{
|
||||
BLOBHEADER *hdr = (BLOBHEADER *)buf;
|
||||
RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
|
||||
|
||||
ok(bufSize >= sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
|
||||
rsaPubKeys[i].decodedModulusLen,
|
||||
"Expected size at least %d, got %ld\n",
|
||||
sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
|
||||
rsaPubKeys[i].decodedModulusLen, bufSize);
|
||||
ok(hdr->bType == PUBLICKEYBLOB,
|
||||
"Expected type PUBLICKEYBLOB (%d), got %d\n", PUBLICKEYBLOB,
|
||||
hdr->bType);
|
||||
ok(hdr->bVersion == CUR_BLOB_VERSION,
|
||||
"Expected version CUR_BLOB_VERSION (%d), got %d\n",
|
||||
CUR_BLOB_VERSION, hdr->bVersion);
|
||||
ok(hdr->reserved == 0, "Expected reserved 0, got %d\n",
|
||||
hdr->reserved);
|
||||
ok(hdr->aiKeyAlg == CALG_RSA_KEYX,
|
||||
"Expected CALG_RSA_KEYX, got %08x\n", hdr->aiKeyAlg);
|
||||
ok(rsaPubKey->magic == 0x31415352,
|
||||
"Expected magic RSA1, got %08lx\n", rsaPubKey->magic);
|
||||
ok(rsaPubKey->bitlen == rsaPubKeys[i].decodedModulusLen * 8,
|
||||
"Expected bit len %d, got %ld\n",
|
||||
rsaPubKeys[i].decodedModulusLen * 8, rsaPubKey->bitlen);
|
||||
ok(rsaPubKey->pubexp == 65537, "Expected pubexp 65537, got %ld\n",
|
||||
rsaPubKey->pubexp);
|
||||
ok(!memcmp(buf + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
|
||||
rsaPubKeys[i].modulus, rsaPubKeys[i].decodedModulusLen),
|
||||
"Unexpected modulus\n");
|
||||
LocalFree(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const BYTE intSequence[] = { 0x30, 0x1b, 0x02, 0x01, 0x01, 0x02, 0x01,
|
||||
0x7f, 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02,
|
||||
0x02, 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
|
||||
@ -2117,12 +2265,6 @@ static void test_decodeCRLToBeSigned(DWORD dwEncoding)
|
||||
info->Issuer.cbData);
|
||||
ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
|
||||
"Unexpected issuer\n");
|
||||
if (memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData))
|
||||
{
|
||||
printBytes("Expected", encodedCommonName,
|
||||
sizeof(encodedCommonName));
|
||||
printBytes("Got", info->Issuer.pbData, info->Issuer.cbData);
|
||||
}
|
||||
}
|
||||
/* and finally, with an extension */
|
||||
ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
|
||||
@ -2237,6 +2379,8 @@ START_TEST(encode)
|
||||
test_decodeBits(encodings[i]);
|
||||
test_encodeBasicConstraints(encodings[i]);
|
||||
test_decodeBasicConstraints(encodings[i]);
|
||||
test_encodeRsaPublicKey(encodings[i]);
|
||||
test_decodeRsaPublicKey(encodings[i]);
|
||||
test_encodeSequenceOfAny(encodings[i]);
|
||||
test_decodeSequenceOfAny(encodings[i]);
|
||||
test_encodeExtensions(encodings[i]);
|
||||
|
Loading…
Reference in New Issue
Block a user