Commit 8c08dbfd authored by Juan Lang's avatar Juan Lang Committed by Alexandre Julliard

Implement encoding/decoding RSA public keys.

parent 6389dbc9
...@@ -1690,6 +1690,47 @@ static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType, ...@@ -1690,6 +1690,47 @@ static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
return ret; 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, static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
...@@ -2277,6 +2318,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, ...@@ -2277,6 +2318,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
case (WORD)X509_BASIC_CONSTRAINTS2: case (WORD)X509_BASIC_CONSTRAINTS2:
encodeFunc = CRYPT_AsnEncodeBasicConstraints2; encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
break; break;
case (WORD)RSA_CSP_PUBLICKEYBLOB:
encodeFunc = CRYPT_AsnEncodeRsaPubKey;
break;
case (WORD)X509_OCTET_STRING: case (WORD)X509_OCTET_STRING:
encodeFunc = CRYPT_AsnEncodeOctets; encodeFunc = CRYPT_AsnEncodeOctets;
break; break;
...@@ -2404,8 +2448,16 @@ static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded, ...@@ -2404,8 +2448,16 @@ static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded,
} }
else if (pbEncoded[1] <= 0x7f) else if (pbEncoded[1] <= 0x7f)
{ {
*len = pbEncoded[1]; if (pbEncoded[1] + 1 > cbEncoded)
ret = TRUE; {
SetLastError(CRYPT_E_ASN1_EOD);
ret = FALSE;
}
else
{
*len = pbEncoded[1];
ret = TRUE;
}
} }
else else
{ {
...@@ -4356,6 +4408,80 @@ static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType, ...@@ -4356,6 +4408,80 @@ static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType,
return ret; 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, static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
...@@ -5268,6 +5394,9 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType, ...@@ -5268,6 +5394,9 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
case (WORD)X509_BASIC_CONSTRAINTS2: case (WORD)X509_BASIC_CONSTRAINTS2:
decodeFunc = CRYPT_AsnDecodeBasicConstraints2; decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
break; break;
case (WORD)RSA_CSP_PUBLICKEYBLOB:
decodeFunc = CRYPT_AsnDecodeRsaPubKey;
break;
case (WORD)X509_OCTET_STRING: case (WORD)X509_OCTET_STRING:
decodeFunc = CRYPT_AsnDecodeOctets; decodeFunc = CRYPT_AsnDecodeOctets;
break; break;
......
...@@ -847,16 +847,6 @@ static const BYTE localhost[] = { 127, 0, 0, 1 }; ...@@ -847,16 +847,6 @@ static const BYTE localhost[] = { 127, 0, 0, 1 };
static const BYTE encodedIPAddr[] = { 0x30, 0x06, 0x87, 0x04, 0x7f, 0x00, 0x00, static const BYTE encodedIPAddr[] = { 0x30, 0x06, 0x87, 0x04, 0x7f, 0x00, 0x00,
0x01 }; 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 void test_encodeAltName(DWORD dwEncoding)
{ {
static const WCHAR nihongo[] = { 0x226f, 0x575b, 0 }; static const WCHAR nihongo[] = { 0x226f, 0x575b, 0 };
...@@ -1334,6 +1324,164 @@ static void test_decodeBasicConstraints(DWORD dwEncoding) ...@@ -1334,6 +1324,164 @@ static void test_decodeBasicConstraints(DWORD dwEncoding)
"Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError()); "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, static const BYTE intSequence[] = { 0x30, 0x1b, 0x02, 0x01, 0x01, 0x02, 0x01,
0x7f, 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02, 0x7f, 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02,
0x02, 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d }; 0x02, 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
...@@ -2117,12 +2265,6 @@ static void test_decodeCRLToBeSigned(DWORD dwEncoding) ...@@ -2117,12 +2265,6 @@ static void test_decodeCRLToBeSigned(DWORD dwEncoding)
info->Issuer.cbData); info->Issuer.cbData);
ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData), ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
"Unexpected issuer\n"); "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 */ /* and finally, with an extension */
ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
...@@ -2237,6 +2379,8 @@ START_TEST(encode) ...@@ -2237,6 +2379,8 @@ START_TEST(encode)
test_decodeBits(encodings[i]); test_decodeBits(encodings[i]);
test_encodeBasicConstraints(encodings[i]); test_encodeBasicConstraints(encodings[i]);
test_decodeBasicConstraints(encodings[i]); test_decodeBasicConstraints(encodings[i]);
test_encodeRsaPublicKey(encodings[i]);
test_decodeRsaPublicKey(encodings[i]);
test_encodeSequenceOfAny(encodings[i]); test_encodeSequenceOfAny(encodings[i]);
test_decodeSequenceOfAny(encodings[i]); test_decodeSequenceOfAny(encodings[i]);
test_encodeExtensions(encodings[i]); test_encodeExtensions(encodings[i]);
......
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