Commit 9153d39c authored by Juan Lang's avatar Juan Lang Committed by Alexandre Julliard

crypt32: Encode/decode authority key ids.

parent 2f599176
......@@ -113,7 +113,8 @@ static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
/* Like CRYPT_AsnDecodeInteger, but assumes the CRYPT_INTEGER_BLOB's pbData
* member has been initialized, doesn't do exception handling, and doesn't do
* memory allocation.
* memory allocation. Also doesn't check tag, assumes the caller has checked
* it.
*/
static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
......@@ -2054,6 +2055,41 @@ static BOOL WINAPI CRYPT_AsnDecodeAltNameInternal(DWORD dwCertEncodingType,
return ret;
}
static BOOL WINAPI CRYPT_AsnDecodeAuthorityKeyId(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[] = {
{ ASN_CONTEXT | 0, offsetof(CERT_AUTHORITY_KEY_ID_INFO, KeyId),
CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_DATA_BLOB),
TRUE, TRUE, offsetof(CERT_AUTHORITY_KEY_ID_INFO, KeyId.pbData), 0 },
{ ASN_CONTEXT | ASN_CONSTRUCTOR| 1,
offsetof(CERT_AUTHORITY_KEY_ID_INFO, CertIssuer),
CRYPT_AsnDecodeOctetsInternal, sizeof(CERT_NAME_BLOB), TRUE, TRUE,
offsetof(CERT_AUTHORITY_KEY_ID_INFO, CertIssuer.pbData), 0 },
{ ASN_CONTEXT | 2, offsetof(CERT_AUTHORITY_KEY_ID_INFO,
CertSerialNumber), CRYPT_AsnDecodeIntegerInternal,
sizeof(CRYPT_INTEGER_BLOB), TRUE, TRUE,
offsetof(CERT_AUTHORITY_KEY_ID_INFO, CertSerialNumber.pbData), 0 },
};
ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
pDecodePara, pvStructInfo, pcbStructInfo, NULL);
}
__EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
}
__ENDTRY
return ret;
}
static BOOL WINAPI CRYPT_AsnDecodeAltName(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
......@@ -2518,8 +2554,15 @@ static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
DWORD size = sizeof(buf);
blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB);
ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
X509_MULTI_BYTE_INTEGER, pbEncoded, cbEncoded, 0, NULL, &buf, &size);
if (pbEncoded[0] != ASN_INTEGER)
{
SetLastError(CRYPT_E_ASN1_BADTAG);
ret = FALSE;
}
else
ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
X509_MULTI_BYTE_INTEGER, pbEncoded, cbEncoded, 0, NULL, &buf,
&size);
if (ret)
{
if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
......@@ -2561,48 +2604,39 @@ static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
{
BOOL ret;
DWORD bytesNeeded, dataLen;
if (pbEncoded[0] == ASN_INTEGER)
if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
{
DWORD bytesNeeded, dataLen;
BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
if (!pvStructInfo)
*pcbStructInfo = bytesNeeded;
else if (*pcbStructInfo < bytesNeeded)
{
BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
*pcbStructInfo = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
if (!pvStructInfo)
*pcbStructInfo = bytesNeeded;
else if (*pcbStructInfo < bytesNeeded)
{
*pcbStructInfo = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
blob->cbData = dataLen;
assert(blob->pbData);
if (blob->cbData)
{
CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
DWORD i;
blob->cbData = dataLen;
assert(blob->pbData);
if (blob->cbData)
for (i = 0; i < blob->cbData; i++)
{
DWORD i;
for (i = 0; i < blob->cbData; i++)
{
blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
dataLen - i - 1);
}
blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
dataLen - i - 1);
}
}
}
}
else
{
SetLastError(CRYPT_E_ASN1_BADTAG);
ret = FALSE;
}
return ret;
}
......@@ -2616,9 +2650,16 @@ static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
{
DWORD bytesNeeded;
if ((ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
lpszStructType, pbEncoded, cbEncoded,
dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
if (pbEncoded[0] != ASN_INTEGER)
{
SetLastError(CRYPT_E_ASN1_BADTAG);
ret = FALSE;
}
else
ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
lpszStructType, pbEncoded, cbEncoded,
dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded);
if (ret)
{
if (!pvStructInfo)
*pcbStructInfo = bytesNeeded;
......@@ -3469,6 +3510,9 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
case (WORD)X509_PUBLIC_KEY_INFO:
decodeFunc = CRYPT_AsnDecodePubKeyInfo;
break;
case (WORD)X509_AUTHORITY_KEY_ID:
decodeFunc = CRYPT_AsnDecodeAuthorityKeyId;
break;
case (WORD)X509_ALTERNATE_NAME:
decodeFunc = CRYPT_AsnDecodeAltName;
break;
......@@ -3532,6 +3576,8 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
decodeFunc = CRYPT_AsnDecodeExtensions;
else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
decodeFunc = CRYPT_AsnDecodeUtcTime;
else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER))
decodeFunc = CRYPT_AsnDecodeAuthorityKeyId;
else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
decodeFunc = CRYPT_AsnDecodeEnumerated;
else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
......
......@@ -1809,6 +1809,62 @@ static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry,
return ret;
}
static BOOL WINAPI CRYPT_AsnEncodeAuthorityKeyId(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
{
BOOL ret;
__TRY
{
const CERT_AUTHORITY_KEY_ID_INFO *info =
(const CERT_AUTHORITY_KEY_ID_INFO *)pvStructInfo;
struct AsnEncodeSequenceItem items[3] = { { 0 } };
struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
struct AsnConstructedItem constructed = { 0 };
DWORD cItem = 0, cSwapped = 0;
if (info->KeyId.cbData)
{
swapped[cSwapped].tag = ASN_CONTEXT | 0;
swapped[cSwapped].pvStructInfo = &info->KeyId;
swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
items[cItem].pvStructInfo = &swapped[cSwapped];
items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
cSwapped++;
cItem++;
}
if (info->CertIssuer.cbData)
{
constructed.tag = 1;
constructed.pvStructInfo = &info->CertIssuer;
constructed.encodeFunc = CRYPT_CopyEncodedBlob;
items[cItem].pvStructInfo = &constructed;
items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
cItem++;
}
if (info->CertSerialNumber.cbData)
{
swapped[cSwapped].tag = ASN_CONTEXT | 2;
swapped[cSwapped].pvStructInfo = &info->CertSerialNumber;
swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
items[cItem].pvStructInfo = &swapped[cSwapped];
items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
cSwapped++;
cItem++;
}
ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, dwFlags,
pEncodePara, pbEncoded, pcbEncoded);
}
__EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
}
__ENDTRY
return ret;
}
static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
......@@ -2883,6 +2939,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
case (WORD)X509_PUBLIC_KEY_INFO:
encodeFunc = CRYPT_AsnEncodePubKeyInfo;
break;
case (WORD)X509_AUTHORITY_KEY_ID:
encodeFunc = CRYPT_AsnEncodeAuthorityKeyId;
break;
case (WORD)X509_ALTERNATE_NAME:
encodeFunc = CRYPT_AsnEncodeAltName;
break;
......@@ -2946,6 +3005,8 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
encodeFunc = CRYPT_AsnEncodeExtensions;
else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
encodeFunc = CRYPT_AsnEncodeUtcTime;
else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER))
encodeFunc = CRYPT_AsnEncodeAuthorityKeyId;
else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
encodeFunc = CRYPT_AsnEncodeEnumerated;
else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
......
......@@ -4224,6 +4224,147 @@ static void test_decodeEnhancedKeyUsage(DWORD dwEncoding)
}
}
static const BYTE authorityKeyIdWithId[] = { 0x30,0x03,0x80,0x01,0x01 };
static const BYTE authorityKeyIdWithIssuer[] = { 0x30,0x19,0xa1,0x17,0x30,0x15,
0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,
0x20,0x4c,0x61,0x6e,0x67,0x00 };
static const BYTE authorityKeyIdWithSerial[] = { 0x30,0x03,0x82,0x01,0x01 };
static void test_encodeAuthorityKeyId(DWORD dwEncoding)
{
CERT_AUTHORITY_KEY_ID_INFO info = { { 0 } };
BOOL ret;
BYTE *buf = NULL;
DWORD size = 0;
/* Test with empty id */
ret = CryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID, &info,
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
if (buf)
{
ok(size == sizeof(emptySequence), "Unexpected size %ld\n", size);
ok(!memcmp(buf, emptySequence, size), "Unexpected value\n");
LocalFree(buf);
}
/* With just a key id */
info.KeyId.cbData = sizeof(serialNum);
info.KeyId.pbData = (BYTE *)serialNum;
ret = CryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID, &info,
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
if (buf)
{
ok(size == sizeof(authorityKeyIdWithId), "Unexpected size %ld\n", size);
ok(!memcmp(buf, authorityKeyIdWithId, size), "Unexpected value\n");
LocalFree(buf);
}
/* With just an issuer */
info.KeyId.cbData = 0;
info.CertIssuer.cbData = sizeof(encodedCommonName);
info.CertIssuer.pbData = (BYTE *)encodedCommonName;
ret = CryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID, &info,
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
if (buf)
{
ok(size == sizeof(authorityKeyIdWithIssuer), "Unexpected size %ld\n",
size);
ok(!memcmp(buf, authorityKeyIdWithIssuer, size), "Unexpected value\n");
LocalFree(buf);
}
/* With just a serial number */
info.CertIssuer.cbData = 0;
info.CertSerialNumber.cbData = sizeof(serialNum);
info.CertSerialNumber.pbData = (BYTE *)serialNum;
ret = CryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID, &info,
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
if (buf)
{
ok(size == sizeof(authorityKeyIdWithSerial), "Unexpected size %ld\n",
size);
ok(!memcmp(buf, authorityKeyIdWithSerial, size), "Unexpected value\n");
LocalFree(buf);
}
}
static void test_decodeAuthorityKeyId(DWORD dwEncoding)
{
BOOL ret;
LPBYTE buf = NULL;
DWORD size = 0;
ret = CryptDecodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID,
emptySequence, sizeof(emptySequence), CRYPT_DECODE_ALLOC_FLAG, NULL,
(BYTE *)&buf, &size);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
if (buf)
{
CERT_AUTHORITY_KEY_ID_INFO *info = (CERT_AUTHORITY_KEY_ID_INFO *)buf;
ok(size >= sizeof(CERT_AUTHORITY_KEY_ID_INFO), "Unexpected size %ld\n",
size);
ok(info->KeyId.cbData == 0, "Expected no key id\n");
ok(info->CertIssuer.cbData == 0, "Expected no issuer name\n");
ok(info->CertSerialNumber.cbData == 0, "Expected no serial number\n");
LocalFree(buf);
}
ret = CryptDecodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID,
authorityKeyIdWithId, sizeof(authorityKeyIdWithId),
CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
if (buf)
{
CERT_AUTHORITY_KEY_ID_INFO *info = (CERT_AUTHORITY_KEY_ID_INFO *)buf;
ok(size >= sizeof(CERT_AUTHORITY_KEY_ID_INFO), "Unexpected size %ld\n",
size);
ok(info->KeyId.cbData == sizeof(serialNum), "Unexpected key id len\n");
ok(!memcmp(info->KeyId.pbData, serialNum, sizeof(serialNum)),
"Unexpected key id\n");
ok(info->CertIssuer.cbData == 0, "Expected no issuer name\n");
ok(info->CertSerialNumber.cbData == 0, "Expected no serial number\n");
LocalFree(buf);
}
ret = CryptDecodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID,
authorityKeyIdWithIssuer, sizeof(authorityKeyIdWithIssuer),
CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
if (buf)
{
CERT_AUTHORITY_KEY_ID_INFO *info = (CERT_AUTHORITY_KEY_ID_INFO *)buf;
ok(size >= sizeof(CERT_AUTHORITY_KEY_ID_INFO), "Unexpected size %ld\n",
size);
ok(info->KeyId.cbData == 0, "Expected no key id\n");
ok(info->CertIssuer.cbData == sizeof(encodedCommonName),
"Unexpected issuer len\n");
ok(!memcmp(info->CertIssuer.pbData, encodedCommonName,
sizeof(encodedCommonName)), "Unexpected issuer\n");
ok(info->CertSerialNumber.cbData == 0, "Expected no serial number\n");
LocalFree(buf);
}
ret = CryptDecodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID,
authorityKeyIdWithSerial, sizeof(authorityKeyIdWithSerial),
CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
if (buf)
{
CERT_AUTHORITY_KEY_ID_INFO *info = (CERT_AUTHORITY_KEY_ID_INFO *)buf;
ok(size >= sizeof(CERT_AUTHORITY_KEY_ID_INFO), "Unexpected size %ld\n",
size);
ok(info->KeyId.cbData == 0, "Expected no key id\n");
ok(info->CertIssuer.cbData == 0, "Expected no issuer name\n");
ok(info->CertSerialNumber.cbData == sizeof(serialNum),
"Unexpected serial number len\n");
ok(!memcmp(info->CertSerialNumber.pbData, serialNum, sizeof(serialNum)),
"Unexpected serial number\n");
LocalFree(buf);
}
}
/* Free *pInfo with HeapFree */
static void testExportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO *pInfo)
{
......@@ -4427,6 +4568,8 @@ START_TEST(encode)
test_decodeCRLToBeSigned(encodings[i]);
test_encodeEnhancedKeyUsage(encodings[i]);
test_decodeEnhancedKeyUsage(encodings[i]);
test_encodeAuthorityKeyId(encodings[i]);
test_decodeAuthorityKeyId(encodings[i]);
}
testPortPublicKeyInfo();
}
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