crypt32: Implement X509_UNICODE_NAME encoding/decoding.

This commit is contained in:
Juan Lang 2006-07-26 07:44:47 -07:00 committed by Alexandre Julliard
parent c562957375
commit 8ccbdb801e
3 changed files with 536 additions and 175 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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]);