crypt32: Implement X509_UNICODE_NAME encoding/decoding.
This commit is contained in:
parent
c562957375
commit
8ccbdb801e
|
@ -1469,48 +1469,48 @@ static BOOL WINAPI CRYPT_AsnDecodeUnicodeNameValueInternal(
|
|||
{
|
||||
case ASN_NUMERICSTRING:
|
||||
valueType = CERT_RDN_NUMERIC_STRING;
|
||||
bytesNeeded += (dataLen + 1) * 2;
|
||||
bytesNeeded += dataLen * 2;
|
||||
break;
|
||||
case ASN_PRINTABLESTRING:
|
||||
valueType = CERT_RDN_PRINTABLE_STRING;
|
||||
bytesNeeded += (dataLen + 1) * 2;
|
||||
bytesNeeded += dataLen * 2;
|
||||
break;
|
||||
case ASN_IA5STRING:
|
||||
valueType = CERT_RDN_IA5_STRING;
|
||||
bytesNeeded += (dataLen + 1) * 2;
|
||||
bytesNeeded += dataLen * 2;
|
||||
break;
|
||||
case ASN_T61STRING:
|
||||
valueType = CERT_RDN_T61_STRING;
|
||||
bytesNeeded += (dataLen + 1) * 2;
|
||||
bytesNeeded += dataLen * 2;
|
||||
break;
|
||||
case ASN_VIDEOTEXSTRING:
|
||||
valueType = CERT_RDN_VIDEOTEX_STRING;
|
||||
bytesNeeded += (dataLen + 1) * 2;
|
||||
bytesNeeded += dataLen * 2;
|
||||
break;
|
||||
case ASN_GRAPHICSTRING:
|
||||
valueType = CERT_RDN_GRAPHIC_STRING;
|
||||
bytesNeeded += (dataLen + 1) * 2;
|
||||
bytesNeeded += dataLen * 2;
|
||||
break;
|
||||
case ASN_VISIBLESTRING:
|
||||
valueType = CERT_RDN_VISIBLE_STRING;
|
||||
bytesNeeded += (dataLen + 1) * 2;
|
||||
bytesNeeded += dataLen * 2;
|
||||
break;
|
||||
case ASN_GENERALSTRING:
|
||||
valueType = CERT_RDN_GENERAL_STRING;
|
||||
bytesNeeded += (dataLen + 1) * 2;
|
||||
bytesNeeded += dataLen * 2;
|
||||
break;
|
||||
case ASN_UNIVERSALSTRING:
|
||||
valueType = CERT_RDN_UNIVERSAL_STRING;
|
||||
bytesNeeded += dataLen / 2 + 2;
|
||||
bytesNeeded += dataLen / 2;
|
||||
break;
|
||||
case ASN_BMPSTRING:
|
||||
valueType = CERT_RDN_BMP_STRING;
|
||||
bytesNeeded += dataLen + 2;
|
||||
bytesNeeded += dataLen;
|
||||
break;
|
||||
case ASN_UTF8STRING:
|
||||
valueType = CERT_RDN_UTF8_STRING;
|
||||
bytesNeeded += MultiByteToWideChar(CP_UTF8, 0,
|
||||
(LPSTR)pbEncoded + 1 + lenBytes, dataLen, NULL, 0) * 2 + 2;
|
||||
(LPSTR)pbEncoded + 1 + lenBytes, dataLen, NULL, 0) * 2;
|
||||
break;
|
||||
default:
|
||||
SetLastError(CRYPT_E_ASN1_BADTAG);
|
||||
|
@ -1546,31 +1546,26 @@ static BOOL WINAPI CRYPT_AsnDecodeUnicodeNameValueInternal(
|
|||
case ASN_GRAPHICSTRING:
|
||||
case ASN_VISIBLESTRING:
|
||||
case ASN_GENERALSTRING:
|
||||
value->Value.cbData = dataLen * 2 + 2;
|
||||
value->Value.cbData = dataLen * 2;
|
||||
for (i = 0; i < dataLen; i++)
|
||||
str[i] = pbEncoded[1 + lenBytes + i];
|
||||
str[i] = 0;
|
||||
break;
|
||||
case ASN_UNIVERSALSTRING:
|
||||
value->Value.cbData = dataLen / 2 + 2;
|
||||
value->Value.cbData = dataLen / 2;
|
||||
for (i = 0; i < dataLen / 4; i++)
|
||||
str[i] = (pbEncoded[1 + lenBytes + 2 * i + 2] << 8)
|
||||
| pbEncoded[1 + lenBytes + 2 * i + 3];
|
||||
str[i] = 0;
|
||||
break;
|
||||
case ASN_BMPSTRING:
|
||||
value->Value.cbData = dataLen + 2;
|
||||
value->Value.cbData = dataLen;
|
||||
for (i = 0; i < dataLen / 2; i++)
|
||||
str[i] = (pbEncoded[1 + lenBytes + 2 * i] << 8) |
|
||||
pbEncoded[1 + lenBytes + 2 * i + 1];
|
||||
str[i] = 0;
|
||||
break;
|
||||
case ASN_UTF8STRING:
|
||||
value->Value.cbData = MultiByteToWideChar(CP_UTF8, 0,
|
||||
(LPSTR)pbEncoded + 1 + lenBytes, dataLen,
|
||||
str, bytesNeeded - sizeof(CERT_NAME_VALUE)) * 2;
|
||||
str[value->Value.cbData / 2] = 0;
|
||||
value->Value.cbData += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1696,6 +1691,78 @@ static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnDecodeUnicodeRdnAttr(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
|
||||
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
|
||||
{
|
||||
BOOL ret;
|
||||
struct AsnDecodeSequenceItem items[] = {
|
||||
{ ASN_OBJECTIDENTIFIER, offsetof(CERT_RDN_ATTR, pszObjId),
|
||||
CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), FALSE, TRUE,
|
||||
offsetof(CERT_RDN_ATTR, pszObjId), 0 },
|
||||
{ 0, offsetof(CERT_RDN_ATTR, dwValueType),
|
||||
CRYPT_AsnDecodeUnicodeNameValueInternal, sizeof(CERT_NAME_VALUE),
|
||||
FALSE, TRUE, offsetof(CERT_RDN_ATTR, Value.pbData), 0 },
|
||||
};
|
||||
CERT_RDN_ATTR *attr = (CERT_RDN_ATTR *)pvStructInfo;
|
||||
|
||||
TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
|
||||
pvStructInfo, *pcbStructInfo);
|
||||
|
||||
if (attr)
|
||||
TRACE("attr->pszObjId is %p\n", attr->pszObjId);
|
||||
ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
|
||||
sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, NULL,
|
||||
attr, pcbStructInfo, attr ? attr->pszObjId : NULL);
|
||||
if (attr)
|
||||
{
|
||||
TRACE("attr->pszObjId is %p (%s)\n", attr->pszObjId,
|
||||
debugstr_a(attr->pszObjId));
|
||||
TRACE("attr->dwValueType is %ld\n", attr->dwValueType);
|
||||
}
|
||||
TRACE("returning %d (%08lx)\n", ret, GetLastError());
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnDecodeUnicodeRdn(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
|
||||
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
|
||||
{
|
||||
BOOL ret = TRUE;
|
||||
struct AsnArrayDescriptor arrayDesc = { ASN_CONSTRUCTOR | ASN_SETOF,
|
||||
CRYPT_AsnDecodeUnicodeRdnAttr, sizeof(CERT_RDN_ATTR), TRUE,
|
||||
offsetof(CERT_RDN_ATTR, pszObjId) };
|
||||
PCERT_RDN rdn = (PCERT_RDN)pvStructInfo;
|
||||
|
||||
ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
|
||||
pDecodePara, pvStructInfo, pcbStructInfo, rdn ? rdn->rgRDNAttr : NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnDecodeUnicodeName(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
|
||||
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
|
||||
{
|
||||
BOOL ret = TRUE;
|
||||
|
||||
__TRY
|
||||
{
|
||||
struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
|
||||
CRYPT_AsnDecodeUnicodeRdn, sizeof(CERT_RDN), TRUE,
|
||||
offsetof(CERT_RDN, rgRDNAttr) };
|
||||
|
||||
ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
|
||||
pDecodePara, pvStructInfo, pcbStructInfo, NULL);
|
||||
}
|
||||
__EXCEPT_PAGE_FAULT
|
||||
{
|
||||
SetLastError(STATUS_ACCESS_VIOLATION);
|
||||
ret = FALSE;
|
||||
}
|
||||
__ENDTRY
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
|
||||
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
|
||||
|
@ -3419,6 +3486,9 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
|
|||
case (WORD)RSA_CSP_PUBLICKEYBLOB:
|
||||
decodeFunc = CRYPT_AsnDecodeRsaPubKey;
|
||||
break;
|
||||
case (WORD)X509_UNICODE_NAME:
|
||||
decodeFunc = CRYPT_AsnDecodeUnicodeName;
|
||||
break;
|
||||
case (WORD)X509_UNICODE_NAME_VALUE:
|
||||
decodeFunc = CRYPT_AsnDecodeUnicodeNameValue;
|
||||
break;
|
||||
|
|
|
@ -1095,6 +1095,262 @@ static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
|
||||
CERT_RDN_ATTR *attr, CryptEncodeObjectExFunc nameValueEncodeFunc,
|
||||
BYTE *pbEncoded, DWORD *pcbEncoded)
|
||||
{
|
||||
DWORD bytesNeeded = 0, lenBytes, size;
|
||||
BOOL ret;
|
||||
|
||||
ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL, attr->pszObjId,
|
||||
0, NULL, NULL, &size);
|
||||
if (ret)
|
||||
{
|
||||
bytesNeeded += size;
|
||||
/* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
|
||||
* with dwValueType, so "cast" it to get its encoded size
|
||||
*/
|
||||
ret = nameValueEncodeFunc(dwCertEncodingType, NULL,
|
||||
(CERT_NAME_VALUE *)&attr->dwValueType, 0, NULL, NULL, &size);
|
||||
if (ret)
|
||||
{
|
||||
bytesNeeded += size;
|
||||
CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
|
||||
bytesNeeded += 1 + lenBytes;
|
||||
if (pbEncoded)
|
||||
{
|
||||
if (*pcbEncoded < bytesNeeded)
|
||||
{
|
||||
SetLastError(ERROR_MORE_DATA);
|
||||
ret = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pbEncoded++ = ASN_SEQUENCE;
|
||||
CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
|
||||
&lenBytes);
|
||||
pbEncoded += lenBytes;
|
||||
size = bytesNeeded - 1 - lenBytes;
|
||||
ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
|
||||
attr->pszObjId, 0, NULL, pbEncoded, &size);
|
||||
if (ret)
|
||||
{
|
||||
pbEncoded += size;
|
||||
size = bytesNeeded - 1 - lenBytes - size;
|
||||
ret = nameValueEncodeFunc(dwCertEncodingType,
|
||||
NULL, (CERT_NAME_VALUE *)&attr->dwValueType,
|
||||
0, NULL, pbEncoded, &size);
|
||||
if (!ret)
|
||||
*pcbEncoded = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret)
|
||||
*pcbEncoded = bytesNeeded;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Have to propagate index of failing character */
|
||||
*pcbEncoded = size;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int BLOBComp(const void *l, const void *r)
|
||||
{
|
||||
CRYPT_DER_BLOB *a = (CRYPT_DER_BLOB *)l, *b = (CRYPT_DER_BLOB *)r;
|
||||
int ret;
|
||||
|
||||
if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
|
||||
ret = a->cbData - b->cbData;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* This encodes as a SET OF, which in DER must be lexicographically sorted.
|
||||
*/
|
||||
static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
|
||||
CryptEncodeObjectExFunc nameValueEncodeFunc, BYTE *pbEncoded,
|
||||
DWORD *pcbEncoded)
|
||||
{
|
||||
BOOL ret;
|
||||
CRYPT_DER_BLOB *blobs = NULL;
|
||||
|
||||
__TRY
|
||||
{
|
||||
DWORD bytesNeeded = 0, lenBytes, i;
|
||||
|
||||
blobs = NULL;
|
||||
ret = TRUE;
|
||||
if (rdn->cRDNAttr)
|
||||
{
|
||||
blobs = CryptMemAlloc(rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
|
||||
if (!blobs)
|
||||
ret = FALSE;
|
||||
else
|
||||
memset(blobs, 0, rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
|
||||
}
|
||||
for (i = 0; ret && i < rdn->cRDNAttr; i++)
|
||||
{
|
||||
ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
|
||||
nameValueEncodeFunc, NULL, &blobs[i].cbData);
|
||||
if (ret)
|
||||
bytesNeeded += blobs[i].cbData;
|
||||
else
|
||||
{
|
||||
/* Have to propagate index of failing character */
|
||||
*pcbEncoded = blobs[i].cbData;
|
||||
}
|
||||
}
|
||||
if (ret)
|
||||
{
|
||||
CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
|
||||
bytesNeeded += 1 + lenBytes;
|
||||
if (pbEncoded)
|
||||
{
|
||||
if (*pcbEncoded < bytesNeeded)
|
||||
{
|
||||
SetLastError(ERROR_MORE_DATA);
|
||||
ret = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; ret && i < rdn->cRDNAttr; i++)
|
||||
{
|
||||
blobs[i].pbData = CryptMemAlloc(blobs[i].cbData);
|
||||
if (!blobs[i].pbData)
|
||||
ret = FALSE;
|
||||
else
|
||||
{
|
||||
ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
|
||||
&rdn->rgRDNAttr[i], nameValueEncodeFunc,
|
||||
blobs[i].pbData, &blobs[i].cbData);
|
||||
if (!ret)
|
||||
*pcbEncoded = blobs[i].cbData;
|
||||
}
|
||||
}
|
||||
if (ret)
|
||||
{
|
||||
qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
|
||||
BLOBComp);
|
||||
*pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
|
||||
CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
|
||||
&lenBytes);
|
||||
pbEncoded += lenBytes;
|
||||
for (i = 0; ret && i < rdn->cRDNAttr; i++)
|
||||
{
|
||||
memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
|
||||
pbEncoded += blobs[i].cbData;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret)
|
||||
*pcbEncoded = bytesNeeded;
|
||||
}
|
||||
if (blobs)
|
||||
{
|
||||
for (i = 0; i < rdn->cRDNAttr; i++)
|
||||
CryptMemFree(blobs[i].pbData);
|
||||
}
|
||||
}
|
||||
__EXCEPT_PAGE_FAULT
|
||||
{
|
||||
SetLastError(STATUS_ACCESS_VIOLATION);
|
||||
ret = FALSE;
|
||||
}
|
||||
__ENDTRY
|
||||
CryptMemFree(blobs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnEncodeUnicodeNameValue(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnEncodeOrCopyUnicodeNameValue(
|
||||
DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
|
||||
DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
|
||||
DWORD *pcbEncoded)
|
||||
{
|
||||
const CERT_NAME_VALUE *value = (const CERT_NAME_VALUE *)pvStructInfo;
|
||||
BOOL ret;
|
||||
|
||||
if (value->dwValueType == CERT_RDN_ENCODED_BLOB)
|
||||
ret = CRYPT_CopyEncodedBlob(dwCertEncodingType, NULL, &value->Value,
|
||||
dwFlags, pEncodePara, pbEncoded, pcbEncoded);
|
||||
else
|
||||
ret = CRYPT_AsnEncodeUnicodeNameValue(dwCertEncodingType, NULL, value,
|
||||
dwFlags, pEncodePara, pbEncoded, pcbEncoded);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnEncodeUnicodeName(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
|
||||
{
|
||||
BOOL ret = TRUE;
|
||||
|
||||
__TRY
|
||||
{
|
||||
const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
|
||||
DWORD bytesNeeded = 0, lenBytes, size, i;
|
||||
|
||||
TRACE("encoding name with %ld RDNs\n", info->cRDN);
|
||||
ret = TRUE;
|
||||
for (i = 0; ret && i < info->cRDN; i++)
|
||||
{
|
||||
ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i],
|
||||
CRYPT_AsnEncodeOrCopyUnicodeNameValue, NULL, &size);
|
||||
if (ret)
|
||||
bytesNeeded += size;
|
||||
else
|
||||
*pcbEncoded = size;
|
||||
}
|
||||
CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
|
||||
bytesNeeded += 1 + lenBytes;
|
||||
if (ret)
|
||||
{
|
||||
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(bytesNeeded - lenBytes - 1, pbEncoded,
|
||||
&lenBytes);
|
||||
pbEncoded += lenBytes;
|
||||
for (i = 0; ret && i < info->cRDN; i++)
|
||||
{
|
||||
size = bytesNeeded;
|
||||
ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
|
||||
&info->rgRDN[i], CRYPT_AsnEncodeOrCopyUnicodeNameValue,
|
||||
pbEncoded, &size);
|
||||
if (ret)
|
||||
{
|
||||
pbEncoded += size;
|
||||
bytesNeeded -= size;
|
||||
}
|
||||
else
|
||||
*pcbEncoded = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
__EXCEPT_PAGE_FAULT
|
||||
{
|
||||
SetLastError(STATUS_ACCESS_VIOLATION);
|
||||
ret = FALSE;
|
||||
}
|
||||
__ENDTRY
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL CRYPT_AsnEncodeUnicodeStringCoerce(const CERT_NAME_VALUE *value,
|
||||
BYTE tag, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
|
||||
DWORD *pcbEncoded)
|
||||
|
@ -1373,155 +1629,6 @@ static BOOL WINAPI CRYPT_AsnEncodeUnicodeNameValue(DWORD dwCertEncodingType,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
|
||||
CERT_RDN_ATTR *attr, BYTE *pbEncoded, DWORD *pcbEncoded)
|
||||
{
|
||||
DWORD bytesNeeded = 0, lenBytes, size;
|
||||
BOOL ret;
|
||||
|
||||
ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL, attr->pszObjId,
|
||||
0, NULL, NULL, &size);
|
||||
if (ret)
|
||||
{
|
||||
bytesNeeded += size;
|
||||
/* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
|
||||
* with dwValueType, so "cast" it to get its encoded size
|
||||
*/
|
||||
ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType, X509_NAME_VALUE,
|
||||
(CERT_NAME_VALUE *)&attr->dwValueType, 0, NULL, NULL, &size);
|
||||
if (ret)
|
||||
{
|
||||
bytesNeeded += size;
|
||||
CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
|
||||
bytesNeeded += 1 + lenBytes;
|
||||
if (pbEncoded)
|
||||
{
|
||||
if (*pcbEncoded < bytesNeeded)
|
||||
{
|
||||
SetLastError(ERROR_MORE_DATA);
|
||||
ret = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pbEncoded++ = ASN_SEQUENCE;
|
||||
CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
|
||||
&lenBytes);
|
||||
pbEncoded += lenBytes;
|
||||
size = bytesNeeded - 1 - lenBytes;
|
||||
ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
|
||||
attr->pszObjId, 0, NULL, pbEncoded, &size);
|
||||
if (ret)
|
||||
{
|
||||
pbEncoded += size;
|
||||
size = bytesNeeded - 1 - lenBytes - size;
|
||||
ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
|
||||
X509_NAME_VALUE, (CERT_NAME_VALUE *)&attr->dwValueType,
|
||||
0, NULL, pbEncoded, &size);
|
||||
}
|
||||
}
|
||||
}
|
||||
*pcbEncoded = bytesNeeded;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int BLOBComp(const void *l, const void *r)
|
||||
{
|
||||
CRYPT_DER_BLOB *a = (CRYPT_DER_BLOB *)l, *b = (CRYPT_DER_BLOB *)r;
|
||||
int ret;
|
||||
|
||||
if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
|
||||
ret = a->cbData - b->cbData;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* This encodes as a SET OF, which in DER must be lexicographically sorted.
|
||||
*/
|
||||
static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
|
||||
BYTE *pbEncoded, DWORD *pcbEncoded)
|
||||
{
|
||||
BOOL ret;
|
||||
CRYPT_DER_BLOB *blobs = NULL;
|
||||
|
||||
__TRY
|
||||
{
|
||||
DWORD bytesNeeded = 0, lenBytes, i;
|
||||
|
||||
blobs = NULL;
|
||||
ret = TRUE;
|
||||
if (rdn->cRDNAttr)
|
||||
{
|
||||
blobs = CryptMemAlloc(rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
|
||||
if (!blobs)
|
||||
ret = FALSE;
|
||||
else
|
||||
memset(blobs, 0, rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
|
||||
}
|
||||
for (i = 0; ret && i < rdn->cRDNAttr; i++)
|
||||
{
|
||||
ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
|
||||
NULL, &blobs[i].cbData);
|
||||
if (ret)
|
||||
bytesNeeded += blobs[i].cbData;
|
||||
}
|
||||
if (ret)
|
||||
{
|
||||
CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
|
||||
bytesNeeded += 1 + lenBytes;
|
||||
if (pbEncoded)
|
||||
{
|
||||
if (*pcbEncoded < bytesNeeded)
|
||||
{
|
||||
SetLastError(ERROR_MORE_DATA);
|
||||
ret = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; ret && i < rdn->cRDNAttr; i++)
|
||||
{
|
||||
blobs[i].pbData = CryptMemAlloc(blobs[i].cbData);
|
||||
if (!blobs[i].pbData)
|
||||
ret = FALSE;
|
||||
else
|
||||
ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
|
||||
&rdn->rgRDNAttr[i], blobs[i].pbData,
|
||||
&blobs[i].cbData);
|
||||
}
|
||||
if (ret)
|
||||
{
|
||||
qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
|
||||
BLOBComp);
|
||||
*pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
|
||||
CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
|
||||
&lenBytes);
|
||||
pbEncoded += lenBytes;
|
||||
for (i = 0; ret && i < rdn->cRDNAttr; i++)
|
||||
{
|
||||
memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
|
||||
pbEncoded += blobs[i].cbData;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*pcbEncoded = bytesNeeded;
|
||||
}
|
||||
if (blobs)
|
||||
{
|
||||
for (i = 0; i < rdn->cRDNAttr; i++)
|
||||
CryptMemFree(blobs[i].pbData);
|
||||
}
|
||||
}
|
||||
__EXCEPT_PAGE_FAULT
|
||||
{
|
||||
SetLastError(STATUS_ACCESS_VIOLATION);
|
||||
ret = FALSE;
|
||||
}
|
||||
__ENDTRY
|
||||
CryptMemFree(blobs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
|
||||
|
@ -1537,8 +1644,8 @@ static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
|
|||
ret = TRUE;
|
||||
for (i = 0; ret && i < info->cRDN; i++)
|
||||
{
|
||||
ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i], NULL,
|
||||
&size);
|
||||
ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i],
|
||||
CRYPT_AsnEncodeNameValue, NULL, &size);
|
||||
if (ret)
|
||||
bytesNeeded += size;
|
||||
}
|
||||
|
@ -1563,7 +1670,8 @@ static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
|
|||
{
|
||||
size = bytesNeeded;
|
||||
ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
|
||||
&info->rgRDN[i], pbEncoded, &size);
|
||||
&info->rgRDN[i], CRYPT_AsnEncodeNameValue, pbEncoded,
|
||||
&size);
|
||||
if (ret)
|
||||
{
|
||||
pbEncoded += size;
|
||||
|
@ -2787,6 +2895,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
|
|||
case (WORD)RSA_CSP_PUBLICKEYBLOB:
|
||||
encodeFunc = CRYPT_AsnEncodeRsaPubKey;
|
||||
break;
|
||||
case (WORD)X509_UNICODE_NAME:
|
||||
encodeFunc = CRYPT_AsnEncodeUnicodeName;
|
||||
break;
|
||||
case (WORD)X509_UNICODE_NAME_VALUE:
|
||||
encodeFunc = CRYPT_AsnEncodeUnicodeNameValue;
|
||||
break;
|
||||
|
@ -2896,7 +3007,7 @@ static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
|
|||
HCRYPTKEY key;
|
||||
static CHAR oid[] = szOID_RSA_RSA;
|
||||
|
||||
TRACE("(%ld, %ld, %08lx, %s, %08lx, %p, %p, %p)\n", hCryptProv, dwKeySpec,
|
||||
TRACE("(%08lx, %ld, %08lx, %s, %08lx, %p, %p, %p)\n", hCryptProv, dwKeySpec,
|
||||
dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
|
||||
pInfo, pcbInfo);
|
||||
|
||||
|
@ -2976,7 +3087,7 @@ BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
|
|||
ExportPublicKeyInfoExFunc exportFunc = NULL;
|
||||
HCRYPTOIDFUNCADDR hFunc = NULL;
|
||||
|
||||
TRACE("(%ld, %ld, %08lx, %s, %08lx, %p, %p, %p)\n", hCryptProv, dwKeySpec,
|
||||
TRACE("(%08lx, %ld, %08lx, %s, %08lx, %p, %p, %p)\n", hCryptProv, dwKeySpec,
|
||||
dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
|
||||
pInfo, pcbInfo);
|
||||
|
||||
|
|
|
@ -788,6 +788,114 @@ static void test_encodeName(DWORD dwEncoding)
|
|||
}
|
||||
}
|
||||
|
||||
static WCHAR commonNameW[] = { 'J','u','a','n',' ','L','a','n','g',0 };
|
||||
static WCHAR surNameW[] = { 'L','a','n','g',0 };
|
||||
|
||||
static const BYTE twoRDNsNoNull[] = {
|
||||
0x30,0x21,0x31,0x1f,0x30,0x0b,0x06,0x03,0x55,0x04,0x04,0x13,0x04,0x4c,0x61,
|
||||
0x6e,0x67,0x30,0x10,0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e,
|
||||
0x20,0x4c,0x61,0x6e,0x67 };
|
||||
static const BYTE anyType[] = {
|
||||
0x30,0x2f,0x31,0x2d,0x30,0x2b,0x06,0x03,0x55,0x04,0x03,0x1e,0x24,0x23,0x30,
|
||||
0x21,0x31,0x0c,0x30,0x03,0x06,0x04,0x55,0x13,0x04,0x4c,0x05,0x6e,0x61,0x00,
|
||||
0x67,0x11,0x30,0x03,0x06,0x04,0x55,0x13,0x03,0x4a,0x0a,0x61,0x75,0x20,0x6e,
|
||||
0x61,0x4c,0x67,0x6e };
|
||||
|
||||
static void test_encodeUnicodeName(DWORD dwEncoding)
|
||||
{
|
||||
CERT_RDN_ATTR attrs[2];
|
||||
CERT_RDN rdn;
|
||||
CERT_NAME_INFO info;
|
||||
BYTE *buf = NULL;
|
||||
DWORD size = 0;
|
||||
BOOL ret;
|
||||
|
||||
/* Test with NULL pvStructInfo */
|
||||
ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, NULL,
|
||||
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
|
||||
ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
|
||||
"Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
|
||||
/* Test with empty CERT_NAME_INFO */
|
||||
info.cRDN = 0;
|
||||
info.rgRDN = NULL;
|
||||
ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, &info,
|
||||
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
|
||||
ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
|
||||
if (buf)
|
||||
{
|
||||
ok(!memcmp(buf, emptySequence, sizeof(emptySequence)),
|
||||
"Got unexpected encoding for empty name\n");
|
||||
LocalFree(buf);
|
||||
}
|
||||
/* Check with one CERT_RDN_ATTR, that has an invalid character for the
|
||||
* encoding (the NULL).
|
||||
*/
|
||||
attrs[0].pszObjId = szOID_COMMON_NAME;
|
||||
attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
|
||||
attrs[0].Value.cbData = sizeof(commonNameW);
|
||||
attrs[0].Value.pbData = (BYTE *)commonNameW;
|
||||
rdn.cRDNAttr = 1;
|
||||
rdn.rgRDNAttr = attrs;
|
||||
info.cRDN = 1;
|
||||
info.rgRDN = &rdn;
|
||||
ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, &info,
|
||||
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
|
||||
ok(!ret && GetLastError() == CRYPT_E_INVALID_PRINTABLE_STRING,
|
||||
"Expected CRYPT_E_INVALID_PRINTABLE_STRING, got %08lx\n", GetLastError());
|
||||
ok(size == 9, "Unexpected error index %08lx\n", size);
|
||||
/* Check with two NULL-terminated CERT_RDN_ATTRs. Note DER encoding
|
||||
* forces the order of the encoded attributes to be swapped.
|
||||
*/
|
||||
attrs[0].pszObjId = szOID_COMMON_NAME;
|
||||
attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
|
||||
attrs[0].Value.cbData = 0;
|
||||
attrs[0].Value.pbData = (BYTE *)commonNameW;
|
||||
attrs[1].pszObjId = szOID_SUR_NAME;
|
||||
attrs[1].dwValueType = CERT_RDN_PRINTABLE_STRING;
|
||||
attrs[1].Value.cbData = 0;
|
||||
attrs[1].Value.pbData = (BYTE *)surNameW;
|
||||
rdn.cRDNAttr = 2;
|
||||
rdn.rgRDNAttr = attrs;
|
||||
info.cRDN = 1;
|
||||
info.rgRDN = &rdn;
|
||||
ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, &info,
|
||||
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
|
||||
ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
|
||||
if (buf)
|
||||
{
|
||||
ok(!memcmp(buf, twoRDNsNoNull, sizeof(twoRDNsNoNull)),
|
||||
"Got unexpected encoding for two RDN array\n");
|
||||
LocalFree(buf);
|
||||
}
|
||||
/* A name can be "encoded" with previously encoded RDN attrs. */
|
||||
attrs[0].dwValueType = CERT_RDN_ENCODED_BLOB;
|
||||
attrs[0].Value.pbData = (LPBYTE)twoRDNs;
|
||||
attrs[0].Value.cbData = sizeof(twoRDNs);
|
||||
rdn.cRDNAttr = 1;
|
||||
ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, &info,
|
||||
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
|
||||
ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
|
||||
if (buf)
|
||||
{
|
||||
ok(size == sizeof(encodedTwoRDNs), "Unexpected size %ld\n", size);
|
||||
ok(!memcmp(buf, encodedTwoRDNs, size),
|
||||
"Unexpected value for re-endoded two RDN array\n");
|
||||
LocalFree(buf);
|
||||
}
|
||||
/* Unicode names infer the type for CERT_RDN_ANY_TYPE */
|
||||
rdn.cRDNAttr = 1;
|
||||
attrs[0].dwValueType = CERT_RDN_ANY_TYPE;
|
||||
ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, &info,
|
||||
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
|
||||
todo_wine ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
|
||||
if (buf)
|
||||
{
|
||||
ok(size == sizeof(anyType), "Unexpected size %ld\n", size);
|
||||
ok(!memcmp(buf, anyType, size), "Unexpected value\n");
|
||||
LocalFree(buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void compareNameValues(const CERT_NAME_VALUE *expected,
|
||||
const CERT_NAME_VALUE *got)
|
||||
{
|
||||
|
@ -926,6 +1034,69 @@ static void test_decodeName(DWORD dwEncoding)
|
|||
}
|
||||
}
|
||||
|
||||
static void test_decodeUnicodeName(DWORD dwEncoding)
|
||||
{
|
||||
BYTE *buf = NULL;
|
||||
DWORD bufSize = 0;
|
||||
BOOL ret;
|
||||
CERT_RDN rdn;
|
||||
CERT_NAME_INFO info = { 1, &rdn };
|
||||
|
||||
/* test empty name */
|
||||
bufSize = 0;
|
||||
ret = CryptDecodeObjectEx(dwEncoding, X509_UNICODE_NAME, emptySequence,
|
||||
emptySequence[1] + 2,
|
||||
CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
|
||||
(BYTE *)&buf, &bufSize);
|
||||
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
|
||||
if (buf)
|
||||
{
|
||||
ok(bufSize == sizeof(CERT_NAME_INFO),
|
||||
"Expected bufSize %d, got %ld\n", sizeof(CERT_NAME_INFO), bufSize);
|
||||
ok(((CERT_NAME_INFO *)buf)->cRDN == 0,
|
||||
"Expected 0 RDNs in empty info, got %ld\n",
|
||||
((CERT_NAME_INFO *)buf)->cRDN);
|
||||
LocalFree(buf);
|
||||
}
|
||||
/* test empty RDN */
|
||||
bufSize = 0;
|
||||
ret = CryptDecodeObjectEx(dwEncoding, X509_UNICODE_NAME, emptyRDNs,
|
||||
emptyRDNs[1] + 2,
|
||||
CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
|
||||
(BYTE *)&buf, &bufSize);
|
||||
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
|
||||
if (buf)
|
||||
{
|
||||
CERT_NAME_INFO *info = (CERT_NAME_INFO *)buf;
|
||||
|
||||
ok(bufSize == sizeof(CERT_NAME_INFO) + sizeof(CERT_RDN) &&
|
||||
info->cRDN == 1 && info->rgRDN && info->rgRDN[0].cRDNAttr == 0,
|
||||
"Got unexpected value for empty RDN\n");
|
||||
LocalFree(buf);
|
||||
}
|
||||
/* test two RDN attrs */
|
||||
bufSize = 0;
|
||||
ret = CryptDecodeObjectEx(dwEncoding, X509_UNICODE_NAME, twoRDNsNoNull,
|
||||
sizeof(twoRDNsNoNull),
|
||||
CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
|
||||
(BYTE *)&buf, &bufSize);
|
||||
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
|
||||
if (buf)
|
||||
{
|
||||
CERT_RDN_ATTR attrs[] = {
|
||||
{ szOID_SUR_NAME, CERT_RDN_PRINTABLE_STRING,
|
||||
{ lstrlenW(surNameW) * sizeof(WCHAR), (BYTE *)surNameW } },
|
||||
{ szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING,
|
||||
{ lstrlenW(commonNameW) * sizeof(WCHAR), (BYTE *)commonNameW } },
|
||||
};
|
||||
|
||||
rdn.cRDNAttr = sizeof(attrs) / sizeof(attrs[0]);
|
||||
rdn.rgRDNAttr = attrs;
|
||||
compareNames(&info, (CERT_NAME_INFO *)buf);
|
||||
LocalFree(buf);
|
||||
}
|
||||
}
|
||||
|
||||
struct EncodedNameValue
|
||||
{
|
||||
CERT_NAME_VALUE value;
|
||||
|
@ -936,7 +1107,6 @@ struct EncodedNameValue
|
|||
static const char bogusIA5[] = "\x80";
|
||||
static const char bogusPrintable[] = "~";
|
||||
static const char bogusNumeric[] = "A";
|
||||
static WCHAR commonNameW[] = { 'J','u','a','n',' ','L','a','n','g',0 };
|
||||
static const BYTE bin42[] = { 0x16,0x02,0x80,0x00 };
|
||||
static const BYTE bin43[] = { 0x13,0x02,0x7e,0x00 };
|
||||
static const BYTE bin44[] = { 0x12,0x02,0x41,0x00 };
|
||||
|
@ -1448,6 +1618,13 @@ static void test_encodeUnicodeNameValue(DWORD dwEncoding)
|
|||
}
|
||||
}
|
||||
|
||||
static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
|
||||
{
|
||||
if (n <= 0) return 0;
|
||||
while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
|
||||
return *str1 - *str2;
|
||||
}
|
||||
|
||||
static void test_decodeUnicodeNameValue(DWORD dwEncoding)
|
||||
{
|
||||
DWORD i;
|
||||
|
@ -1469,7 +1646,8 @@ static void test_decodeUnicodeNameValue(DWORD dwEncoding)
|
|||
ok(value->dwValueType == unicodeResults[i].valueType,
|
||||
"Expected value type %ld, got %ld\n", unicodeResults[i].valueType,
|
||||
value->dwValueType);
|
||||
ok(!lstrcmpW((LPWSTR)value->Value.pbData, unicodeResults[i].str),
|
||||
ok(!strncmpW((LPWSTR)value->Value.pbData, unicodeResults[i].str,
|
||||
value->Value.cbData / sizeof(WCHAR)),
|
||||
"Unexpected decoded value for index %ld (value type %ld)\n", i,
|
||||
unicodeResults[i].valueType);
|
||||
LocalFree(buf);
|
||||
|
@ -3668,6 +3846,8 @@ START_TEST(encode)
|
|||
test_decodeFiletime(encodings[i]);
|
||||
test_encodeName(encodings[i]);
|
||||
test_decodeName(encodings[i]);
|
||||
test_encodeUnicodeName(encodings[i]);
|
||||
test_decodeUnicodeName(encodings[i]);
|
||||
test_encodeNameValue(encodings[i]);
|
||||
test_decodeNameValue(encodings[i]);
|
||||
test_encodeUnicodeNameValue(encodings[i]);
|
||||
|
|
Loading…
Reference in New Issue