- implement encoding/decoding of cert extensions

- remove some unnecessary parameters to internal functions
- tests for cert extensions
This commit is contained in:
Juan Lang 2005-07-01 15:40:45 +00:00 committed by Alexandre Julliard
parent 4b53c3aa18
commit 623e272c06
2 changed files with 486 additions and 80 deletions

View File

@ -62,12 +62,25 @@ WINE_DEFAULT_DEBUG_CHANNEL(crypt);
static const WCHAR szDllName[] = { 'D','l','l',0 }; static const WCHAR szDllName[] = { 'D','l','l',0 };
static BOOL WINAPI CRYPT_AsnEncodeOid(LPCSTR pszObjId, BYTE *pbEncoded,
DWORD *pcbEncoded);
static BOOL CRYPT_EncodeBool(BOOL val, BYTE *pbEncoded, DWORD *pcbEncoded);
static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType, static BOOL WINAPI CRYPT_AsnEncodeInt(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);
static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType, static BOOL WINAPI CRYPT_AsnEncodeInteger(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);
static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId);
static BOOL WINAPI CRYPT_DecodeBool(const BYTE *pbEncoded, DWORD cbEncoded,
BOOL *val);
static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType, static BOOL WINAPI CRYPT_AsnDecodeInt(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);
@ -444,8 +457,113 @@ static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
return TRUE; return TRUE;
} }
static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType, static BOOL CRYPT_AsnEncodeExtension(CERT_EXTENSION *ext, BYTE *pbEncoded,
LPCSTR pszObjId, BYTE *pbEncoded, DWORD *pcbEncoded) DWORD *pcbEncoded)
{
BOOL ret;
DWORD dataLen, octetsLen, lenBytes, size;
ret = CRYPT_AsnEncodeOid(ext->pszObjId, NULL, &size);
if (ret)
{
dataLen = size;
if (ext->fCritical)
{
ret = CRYPT_EncodeBool(TRUE, NULL, &size);
dataLen += size;
}
if (ret)
{
ret = CRYPT_AsnEncodeOctets(X509_ASN_ENCODING, X509_OCTET_STRING,
&ext->Value, 0, NULL, NULL, &octetsLen);
dataLen += octetsLen;
}
CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
*pcbEncoded = 1 + lenBytes + dataLen;
}
if (ret && pbEncoded)
{
*pbEncoded++ = ASN_SEQUENCE;
CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
pbEncoded += lenBytes;
ret = CRYPT_AsnEncodeOid(ext->pszObjId, pbEncoded, &size);
if (ret)
{
pbEncoded += size;
if (ext->fCritical)
{
ret = CRYPT_EncodeBool(TRUE, pbEncoded, &size);
pbEncoded += size;
}
if (ret)
{
ret = CRYPT_AsnEncodeOctets(X509_ASN_ENCODING,
X509_OCTET_STRING, &ext->Value, 0, NULL, pbEncoded,
&octetsLen);
pbEncoded += octetsLen;
}
}
}
return ret;
}
static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
{
BOOL ret;
__TRY
{
DWORD bytesNeeded, dataLen, lenBytes, i;
CERT_EXTENSIONS *exts = (CERT_EXTENSIONS *)pvStructInfo;
ret = TRUE;
for (i = 0, dataLen = 0; ret && i < exts->cExtension; i++)
{
DWORD size;
ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i], NULL, &size);
if (ret)
dataLen += size;
}
CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
bytesNeeded = 1 + lenBytes + dataLen;
if (!pbEncoded)
*pcbEncoded = bytesNeeded;
else
{
if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
pcbEncoded, bytesNeeded)))
{
if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
pbEncoded = *(BYTE **)pbEncoded;
*pbEncoded++ = ASN_SEQUENCEOF;
CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
pbEncoded += lenBytes;
for (i = 0; i < exts->cExtension; i++)
{
DWORD size;
ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i],
pbEncoded, &size);
if (ret)
pbEncoded += size;
}
}
}
}
__EXCEPT(page_fault)
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
}
__ENDTRY
return ret;
}
static BOOL WINAPI CRYPT_AsnEncodeOid(LPCSTR pszObjId, BYTE *pbEncoded,
DWORD *pcbEncoded)
{ {
DWORD bytesNeeded = 0, lenBytes; DWORD bytesNeeded = 0, lenBytes;
BOOL ret = TRUE; BOOL ret = TRUE;
@ -615,7 +733,7 @@ static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
DWORD bytesNeeded = 0, lenBytes, size; DWORD bytesNeeded = 0, lenBytes, size;
BOOL ret; BOOL ret;
ret = CRYPT_AsnEncodeOid(dwCertEncodingType, attr->pszObjId, NULL, &size); ret = CRYPT_AsnEncodeOid(attr->pszObjId, NULL, &size);
if (ret) if (ret)
{ {
bytesNeeded += size; bytesNeeded += size;
@ -643,8 +761,7 @@ static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
&lenBytes); &lenBytes);
pbEncoded += lenBytes; pbEncoded += lenBytes;
size = bytesNeeded - 1 - lenBytes; size = bytesNeeded - 1 - lenBytes;
ret = CRYPT_AsnEncodeOid(dwCertEncodingType, attr->pszObjId, ret = CRYPT_AsnEncodeOid(attr->pszObjId, pbEncoded, &size);
pbEncoded, &size);
if (ret) if (ret)
{ {
pbEncoded += size; pbEncoded += size;
@ -868,10 +985,7 @@ static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes); CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
bytesNeeded += 1 + lenBytes; bytesNeeded += 1 + lenBytes;
if (!pbEncoded) if (!pbEncoded)
{
*pcbEncoded = bytesNeeded; *pcbEncoded = bytesNeeded;
ret = TRUE;
}
else else
{ {
if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
@ -1424,6 +1538,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
{ {
switch (LOWORD(lpszStructType)) switch (LOWORD(lpszStructType))
{ {
case (WORD)X509_EXTENSIONS:
encodeFunc = CRYPT_AsnEncodeExtensions;
break;
case (WORD)X509_NAME: case (WORD)X509_NAME:
encodeFunc = CRYPT_AsnEncodeName; encodeFunc = CRYPT_AsnEncodeName;
break; break;
@ -1462,6 +1579,8 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
FIXME("%d: unimplemented\n", LOWORD(lpszStructType)); FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
} }
} }
else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
encodeFunc = CRYPT_AsnEncodeExtensions;
else if (!strcmp(lpszStructType, szOID_RSA_signingTime)) else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
encodeFunc = CRYPT_AsnEncodeUtcTime; encodeFunc = CRYPT_AsnEncodeUtcTime;
else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE)) else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
@ -1622,10 +1741,213 @@ static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
return ret; return ret;
} }
/* FIXME: honor the CRYPT_DECODE_SHARE_OID_FLAG. */ /* Warning: assumes ext->Value.pbData is set ahead of time! */
static BOOL WINAPI CRYPT_AsnDecodeOid(DWORD dwCertEncodingType, static BOOL CRYPT_AsnDecodeExtension(const BYTE *pbEncoded, DWORD cbEncoded,
const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, LPSTR pszObjId, DWORD dwFlags, CERT_EXTENSION *ext, DWORD *pcbExt)
DWORD *pcbObjId) {
BOOL ret = TRUE;
if (pbEncoded[0] == ASN_SEQUENCE)
{
DWORD dataLen, bytesNeeded;
if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
{
BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]), oidLenBytes = 0;
bytesNeeded = sizeof(CERT_EXTENSION);
if (dataLen)
{
const BYTE *ptr = pbEncoded + 1 + lenBytes;
DWORD encodedOidLen, oidLen;
CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
&encodedOidLen);
oidLenBytes = GET_LEN_BYTES(ptr[1]);
ret = CRYPT_AsnDecodeOid(ptr, cbEncoded - (ptr - pbEncoded),
dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &oidLen);
if (ret)
{
bytesNeeded += oidLen;
ptr += 1 + encodedOidLen + oidLenBytes;
if (*ptr == ASN_BOOL)
ptr += 3;
ret = CRYPT_AsnDecodeOctets(X509_ASN_ENCODING,
X509_OCTET_STRING, ptr, cbEncoded - (ptr - pbEncoded),
0, NULL, NULL, &dataLen);
bytesNeeded += dataLen;
if (ret)
{
if (!ext)
*pcbExt = bytesNeeded;
else if (*pcbExt < bytesNeeded)
{
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
else
{
ptr = pbEncoded + 2 + lenBytes + encodedOidLen +
oidLenBytes;
if (*ptr == ASN_BOOL)
{
CRYPT_DecodeBool(ptr, cbEncoded -
(ptr - pbEncoded), &ext->fCritical);
ptr += 3;
}
ret = CRYPT_AsnDecodeOctets(X509_ASN_ENCODING,
X509_OCTET_STRING, ptr,
cbEncoded - (ptr - pbEncoded),
dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
&ext->Value, &dataLen);
if (ret)
{
ext->pszObjId = ext->Value.pbData +
ext->Value.cbData;
ptr = pbEncoded + 1 + lenBytes;
ret = CRYPT_AsnDecodeOid(ptr,
cbEncoded - (ptr - pbEncoded),
dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
ext->pszObjId, &oidLen);
}
}
}
}
}
else
{
SetLastError(CRYPT_E_ASN1_EOD);
ret = FALSE;
}
}
}
else
{
SetLastError(CRYPT_E_ASN1_BADTAG);
ret = FALSE;
}
return ret;
}
static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
{
BOOL ret = TRUE;
__TRY
{
if (pbEncoded[0] == ASN_SEQUENCEOF)
{
DWORD dataLen, bytesNeeded;
if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
{
DWORD cExtension = 0;
BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
bytesNeeded = sizeof(CERT_EXTENSIONS);
if (dataLen)
{
const BYTE *ptr;
DWORD size;
for (ptr = pbEncoded + 1 + lenBytes; ret &&
ptr - pbEncoded - 1 - lenBytes < dataLen; )
{
ret = CRYPT_AsnDecodeExtension(ptr,
cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
if (ret)
{
DWORD nextLen;
cExtension++;
bytesNeeded += size;
ret = CRYPT_GetLen(ptr,
cbEncoded - (ptr - pbEncoded), &nextLen);
if (ret)
ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
}
}
}
if (ret)
{
if (!pvStructInfo)
*pcbStructInfo = bytesNeeded;
else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
{
DWORD size, i;
BYTE *nextData;
const BYTE *ptr;
CERT_EXTENSIONS *exts;
if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
pvStructInfo = *(BYTE **)pvStructInfo;
*pcbStructInfo = bytesNeeded;
exts = (CERT_EXTENSIONS *)pvStructInfo;
exts->cExtension = cExtension;
exts->rgExtension = (CERT_EXTENSION *)((BYTE *)exts +
sizeof(CERT_EXTENSIONS));
nextData = (BYTE *)exts->rgExtension +
exts->cExtension * sizeof(CERT_EXTENSION);
for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
i < cExtension && ptr - pbEncoded - 1 - lenBytes <
dataLen; i++)
{
exts->rgExtension[i].Value.pbData = nextData;
size = bytesNeeded;
ret = CRYPT_AsnDecodeExtension(ptr,
cbEncoded - (ptr - pbEncoded), dwFlags,
&exts->rgExtension[i], &size);
if (ret)
{
DWORD nextLen;
bytesNeeded -= size;
/* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the
* data may not have been copied.
*/
if (exts->rgExtension[i].Value.pbData ==
nextData)
nextData +=
exts->rgExtension[i].Value.cbData;
/* Ugly: the OID, if copied, is stored in
* memory after the value, so increment by its
* string length if it's set and points here.
*/
if ((const BYTE *)exts->rgExtension[i].pszObjId
== nextData)
nextData += strlen(
exts->rgExtension[i].pszObjId) + 1;
ret = CRYPT_GetLen(ptr,
cbEncoded - (ptr - pbEncoded), &nextLen);
if (ret)
ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
}
}
}
}
}
}
else
{
SetLastError(CRYPT_E_ASN1_BADTAG);
ret = FALSE;
}
}
__EXCEPT(page_fault)
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
}
__ENDTRY
return ret;
}
/* FIXME: honor the CRYPT_DECODE_SHARE_OID_STRING_FLAG. */
static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId)
{ {
BOOL ret = TRUE; BOOL ret = TRUE;
@ -1738,9 +2060,8 @@ static BOOL WINAPI CRYPT_AsnDecodeOid(DWORD dwCertEncodingType,
* order to avoid overwriting memory. (In some cases, it may change it, if it * order to avoid overwriting memory. (In some cases, it may change it, if it
* doesn't copy anything to memory.) Be sure to set it correctly! * doesn't copy anything to memory.) Be sure to set it correctly!
*/ */
static BOOL WINAPI CRYPT_AsnDecodeNameValue(DWORD dwCertEncodingType, static BOOL WINAPI CRYPT_AsnDecodeNameValue(const BYTE *pbEncoded,
const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_NAME_VALUE *value, DWORD cbEncoded, DWORD dwFlags, CERT_NAME_VALUE *value, DWORD *pcbValue)
DWORD *pcbValue)
{ {
BOOL ret = TRUE; BOOL ret = TRUE;
@ -1842,9 +2163,8 @@ static BOOL WINAPI CRYPT_AsnDecodeNameValue(DWORD dwCertEncodingType,
return ret; return ret;
} }
static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType, static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(const BYTE *pbEncoded,
const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_RDN_ATTR *attr, DWORD cbEncoded, DWORD dwFlags, CERT_RDN_ATTR *attr, DWORD *pcbAttr)
DWORD *pcbAttr)
{ {
BOOL ret; BOOL ret;
@ -1870,9 +2190,8 @@ static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType,
{ {
bytesNeeded = sizeof(CERT_RDN_ATTR); bytesNeeded = sizeof(CERT_RDN_ATTR);
lenBytes = GET_LEN_BYTES(pbEncoded[1]); lenBytes = GET_LEN_BYTES(pbEncoded[1]);
ret = CRYPT_AsnDecodeOid(dwCertEncodingType, pbEncoded + 1 ret = CRYPT_AsnDecodeOid(pbEncoded + 1 + lenBytes,
+ lenBytes, cbEncoded - 1 - lenBytes, dwFlags, NULL, cbEncoded - 1 - lenBytes, dwFlags, NULL, &size);
&size);
if (ret) if (ret)
{ {
/* ugly: need to know the size of the next element of /* ugly: need to know the size of the next element of
@ -1892,7 +2211,7 @@ static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType,
{ {
nameValueOffset = objIdOfset + objIdLen + 1 + nameValueOffset = objIdOfset + objIdLen + 1 +
GET_LEN_BYTES(pbEncoded[objIdOfset]); GET_LEN_BYTES(pbEncoded[objIdOfset]);
ret = CRYPT_AsnDecodeNameValue(dwCertEncodingType, ret = CRYPT_AsnDecodeNameValue(
pbEncoded + nameValueOffset, pbEncoded + nameValueOffset,
cbEncoded - nameValueOffset, dwFlags, NULL, &size); cbEncoded - nameValueOffset, dwFlags, NULL, &size);
} }
@ -1920,11 +2239,9 @@ static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType,
*/ */
size = bytesNeeded; size = bytesNeeded;
ret = CRYPT_AsnDecodeNameValue( ret = CRYPT_AsnDecodeNameValue(
dwCertEncodingType,
pbEncoded + nameValueOffset, pbEncoded + nameValueOffset,
cbEncoded - nameValueOffset, cbEncoded - nameValueOffset, dwFlags,
dwFlags, (CERT_NAME_VALUE *)&attr->dwValueType, (CERT_NAME_VALUE *)&attr->dwValueType, &size);
&size);
if (ret) if (ret)
{ {
if (objIdLen) if (objIdLen)
@ -1943,7 +2260,6 @@ static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType,
attr->pszObjId = originalData; attr->pszObjId = originalData;
size = bytesNeeded - size; size = bytesNeeded - size;
ret = CRYPT_AsnDecodeOid( ret = CRYPT_AsnDecodeOid(
dwCertEncodingType,
pbEncoded + objIdOfset, pbEncoded + objIdOfset,
cbEncoded - objIdOfset, cbEncoded - objIdOfset,
dwFlags, attr->pszObjId, &size); dwFlags, attr->pszObjId, &size);
@ -1972,10 +2288,8 @@ static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType,
return ret; return ret;
} }
/* FIXME: this is indenting-happy, try to break it up */ static BOOL WINAPI CRYPT_AsnDecodeRdn(const BYTE *pbEncoded, DWORD cbEncoded,
static BOOL WINAPI CRYPT_AsnDecodeRdn(DWORD dwCertEncodingType, DWORD dwFlags, CERT_RDN *rdn, DWORD *pcbRdn)
const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_RDN *rdn,
DWORD *pcbRdn)
{ {
BOOL ret = TRUE; BOOL ret = TRUE;
@ -1999,7 +2313,7 @@ static BOOL WINAPI CRYPT_AsnDecodeRdn(DWORD dwCertEncodingType,
for (ptr = pbEncoded + 1 + lenBytes; ret && for (ptr = pbEncoded + 1 + lenBytes; ret &&
ptr - pbEncoded - 1 - lenBytes < dataLen; ) ptr - pbEncoded - 1 - lenBytes < dataLen; )
{ {
ret = CRYPT_AsnDecodeRdnAttr(dwCertEncodingType, ptr, ret = CRYPT_AsnDecodeRdnAttr(ptr,
cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size); cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
if (ret) if (ret)
{ {
@ -2026,56 +2340,48 @@ static BOOL WINAPI CRYPT_AsnDecodeRdn(DWORD dwCertEncodingType,
} }
else else
{ {
DWORD size, i;
BYTE *nextData;
const BYTE *ptr;
*pcbRdn = bytesNeeded; *pcbRdn = bytesNeeded;
rdn->cRDNAttr = cRDNAttr; rdn->cRDNAttr = cRDNAttr;
if (rdn->cRDNAttr == 0) rdn->rgRDNAttr = (CERT_RDN_ATTR *)((BYTE *)rdn +
rdn->rgRDNAttr = NULL; sizeof(CERT_RDN));
else nextData = (BYTE *)rdn->rgRDNAttr +
rdn->cRDNAttr * sizeof(CERT_RDN_ATTR);
for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
i < cRDNAttr && ptr - pbEncoded - 1 - lenBytes <
dataLen; i++)
{ {
DWORD size, i; rdn->rgRDNAttr[i].Value.pbData = nextData;
BYTE *nextData; size = bytesNeeded;
const BYTE *ptr; ret = CRYPT_AsnDecodeRdnAttr(ptr,
cbEncoded - (ptr - pbEncoded), dwFlags,
rdn->rgRDNAttr = &rdn->rgRDNAttr[i], &size);
(CERT_RDN_ATTR *)((BYTE *)rdn + sizeof(CERT_RDN)); if (ret)
nextData = (BYTE *)rdn->rgRDNAttr +
rdn->cRDNAttr * sizeof(CERT_RDN_ATTR);
for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
i < cRDNAttr && ptr - pbEncoded - 1 - lenBytes <
dataLen; i++)
{ {
rdn->rgRDNAttr[i].Value.pbData = nextData; DWORD nextLen;
size = bytesNeeded;
ret = CRYPT_AsnDecodeRdnAttr(dwCertEncodingType,
ptr, cbEncoded - (ptr - pbEncoded), dwFlags,
&rdn->rgRDNAttr[i], &size);
if (ret)
{
DWORD nextLen;
bytesNeeded -= size; bytesNeeded -= size;
/* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the
* the data may not have been copied. * data may not have been copied.
*/ */
if (rdn->rgRDNAttr[i].Value.pbData == if (rdn->rgRDNAttr[i].Value.pbData == nextData)
nextData) nextData +=
nextData += rdn->rgRDNAttr[i].Value.cbData;
rdn->rgRDNAttr[i].Value.cbData; /* Ugly: the OID, if copied, is stored in
/* Ugly: the OID, if copied, is stored in * memory after the value, so increment by its
* memory after the value, so increment by * string length if it's set and points here.
* its string length if it's set and points */
* here. if ((const BYTE *)rdn->rgRDNAttr[i].pszObjId
*/ == nextData)
if ((const BYTE *)rdn->rgRDNAttr[i].pszObjId nextData += strlen(
== nextData) rdn->rgRDNAttr[i].pszObjId) + 1;
nextData += ret = CRYPT_GetLen(ptr,
strlen(rdn->rgRDNAttr[i].pszObjId) + 1; cbEncoded - (ptr - pbEncoded), &nextLen);
ret = CRYPT_GetLen(ptr, if (ret)
cbEncoded - (ptr - pbEncoded), &nextLen); ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
if (ret)
ptr += nextLen + 1 +
GET_LEN_BYTES(ptr[1]);
}
} }
} }
} }
@ -2124,7 +2430,7 @@ static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
{ {
DWORD size; DWORD size;
ret = CRYPT_AsnDecodeRdn(dwCertEncodingType, ptr, ret = CRYPT_AsnDecodeRdn(ptr,
cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size); cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
if (ret) if (ret)
{ {
@ -2171,8 +2477,8 @@ static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
info->rgRDN[i].rgRDNAttr = info->rgRDN[i].rgRDNAttr =
(CERT_RDN_ATTR *)nextData; (CERT_RDN_ATTR *)nextData;
size = bytesNeeded; size = bytesNeeded;
ret = CRYPT_AsnDecodeRdn(dwCertEncodingType, ret = CRYPT_AsnDecodeRdn(ptr,
ptr, cbEncoded - (ptr - pbEncoded), dwFlags, cbEncoded - (ptr - pbEncoded), dwFlags,
&info->rgRDN[i], &size); &info->rgRDN[i], &size);
if (ret) if (ret)
{ {
@ -3155,6 +3461,9 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
{ {
switch (LOWORD(lpszStructType)) switch (LOWORD(lpszStructType))
{ {
case (WORD)X509_EXTENSIONS:
decodeFunc = CRYPT_AsnDecodeExtensions;
break;
case (WORD)X509_NAME: case (WORD)X509_NAME:
decodeFunc = CRYPT_AsnDecodeName; decodeFunc = CRYPT_AsnDecodeName;
break; break;
@ -3193,6 +3502,8 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
FIXME("%d: unimplemented\n", LOWORD(lpszStructType)); FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
} }
} }
else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
decodeFunc = CRYPT_AsnDecodeExtensions;
else if (!strcmp(lpszStructType, szOID_RSA_signingTime)) else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
decodeFunc = CRYPT_AsnDecodeUtcTime; decodeFunc = CRYPT_AsnDecodeUtcTime;
else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE)) else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))

View File

@ -1214,6 +1214,99 @@ static void test_decodeSequenceOfAny(DWORD dwEncoding)
} }
} }
struct encodedExtensions
{
CERT_EXTENSIONS exts;
const BYTE *encoded;
};
static CERT_EXTENSION criticalExt =
{ szOID_BASIC_CONSTRAINTS2, TRUE, { 8, "\x30\x06\x01\x01\xff\x02\x01\x01" } };
static CERT_EXTENSION nonCriticalExt =
{ szOID_BASIC_CONSTRAINTS2, FALSE, { 8, "\x30\x06\x01\x01\xff\x02\x01\x01" } };
static const struct encodedExtensions exts[] = {
{ { 0, NULL }, "\x30\x00" },
{ { 1, &criticalExt }, "\x30\x14\x30\x12\x06\x03\x55\x1d\x13\x01\x01\xff"
"\x04\x08\x30\x06\x01\x01\xff\x02\x01\x01" },
{ { 1, &nonCriticalExt }, "\x30\x11\x30\x0f\x06\x03\x55\x1d\x13"
"\x04\x08\x30\x06\x01\x01\xff\x02\x01\x01" },
};
#if 0
static void printBytes(const BYTE *pbData, size_t cb)
{
size_t i;
for (i = 0; i < cb; i++)
printf("%02x ", pbData[i]);
putchar('\n');
}
#endif
static void test_encodeExtensions(DWORD dwEncoding)
{
DWORD i;
for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
{
BOOL ret;
BYTE *buf = NULL;
DWORD bufSize = 0;
ret = CryptEncodeObjectEx(dwEncoding, X509_EXTENSIONS, &exts[i].exts,
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
if (buf)
{
ok(bufSize == exts[i].encoded[1] + 2,
"Expected %d bytes, got %ld\n", exts[i].encoded[1] + 2, bufSize);
ok(!memcmp(buf, exts[i].encoded, exts[i].encoded[1] + 2),
"Unexpected value\n");
LocalFree(buf);
}
}
}
static void test_decodeExtensions(DWORD dwEncoding)
{
DWORD i;
for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
{
BOOL ret;
BYTE *buf = NULL;
DWORD bufSize = 0;
ret = CryptDecodeObjectEx(dwEncoding, X509_EXTENSIONS,
exts[i].encoded, exts[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
NULL, (BYTE *)&buf, &bufSize);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
if (buf)
{
CERT_EXTENSIONS *ext = (CERT_EXTENSIONS *)buf;
DWORD j;
ok(ext->cExtension == exts[i].exts.cExtension,
"Expected %ld extensions, see %ld\n", exts[i].exts.cExtension,
ext->cExtension);
for (j = 0; j < min(ext->cExtension, exts[i].exts.cExtension); j++)
{
ok(!strcmp(ext->rgExtension[j].pszObjId,
exts[i].exts.rgExtension[j].pszObjId),
"Expected OID %s, got %s\n",
exts[i].exts.rgExtension[j].pszObjId,
ext->rgExtension[j].pszObjId);
ok(!memcmp(ext->rgExtension[j].Value.pbData,
exts[i].exts.rgExtension[j].Value.pbData,
exts[i].exts.rgExtension[j].Value.cbData),
"Unexpected value\n");
}
LocalFree(buf);
}
}
}
static void test_registerOIDFunction(void) static void test_registerOIDFunction(void)
{ {
static const WCHAR bogusDll[] = { 'b','o','g','u','s','.','d','l','l',0 }; static const WCHAR bogusDll[] = { 'b','o','g','u','s','.','d','l','l',0 };
@ -1292,6 +1385,8 @@ START_TEST(encode)
test_decodeBasicConstraints(encodings[i]); test_decodeBasicConstraints(encodings[i]);
test_encodeSequenceOfAny(encodings[i]); test_encodeSequenceOfAny(encodings[i]);
test_decodeSequenceOfAny(encodings[i]); test_decodeSequenceOfAny(encodings[i]);
test_encodeExtensions(encodings[i]);
test_decodeExtensions(encodings[i]);
} }
test_registerOIDFunction(); test_registerOIDFunction();
} }