From 1eefa005da6aaf8d2edad75ac275d4c61434c74c Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Wed, 19 Jul 2006 16:46:37 -0700 Subject: [PATCH] crypt32: Implement more string types for X509_NAME_VALUE. --- dlls/crypt32/decode.c | 127 +++++++++++----- dlls/crypt32/encode.c | 290 ++++++++++++++++++++---------------- dlls/crypt32/tests/encode.c | 125 +++++++++++++--- 3 files changed, 356 insertions(+), 186 deletions(-) diff --git a/dlls/crypt32/decode.c b/dlls/crypt32/decode.c index a53ec79cfb5..f4e18853ccc 100644 --- a/dlls/crypt32/decode.c +++ b/dlls/crypt32/decode.c @@ -1272,33 +1272,75 @@ static BOOL WINAPI CRYPT_AsnDecodeNameValueInternal(DWORD dwCertEncodingType, if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) { BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); + DWORD bytesNeeded = sizeof(CERT_NAME_VALUE), valueType; switch (pbEncoded[0]) { + case ASN_OCTETSTRING: + valueType = CERT_RDN_OCTET_STRING; + if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) + bytesNeeded += dataLen; + break; case ASN_NUMERICSTRING: + valueType = CERT_RDN_NUMERIC_STRING; + if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) + bytesNeeded += dataLen; + break; case ASN_PRINTABLESTRING: + valueType = CERT_RDN_PRINTABLE_STRING; + if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) + bytesNeeded += dataLen; + break; case ASN_IA5STRING: + valueType = CERT_RDN_IA5_STRING; + if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) + bytesNeeded += dataLen; + break; case ASN_T61STRING: + valueType = CERT_RDN_T61_STRING; + if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) + bytesNeeded += dataLen; + break; + case ASN_VIDEOTEXSTRING: + valueType = CERT_RDN_VIDEOTEX_STRING; + if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) + bytesNeeded += dataLen; + break; + case ASN_GRAPHICSTRING: + valueType = CERT_RDN_GRAPHIC_STRING; + if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) + bytesNeeded += dataLen; + break; + case ASN_VISIBLESTRING: + valueType = CERT_RDN_VISIBLE_STRING; + if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) + bytesNeeded += dataLen; + break; + case ASN_GENERALSTRING: + valueType = CERT_RDN_GENERAL_STRING; + if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) + bytesNeeded += dataLen; + break; + case ASN_UNIVERSALSTRING: + FIXME("ASN_UNIVERSALSTRING: unimplemented\n"); + SetLastError(CRYPT_E_ASN1_BADTAG); + ret = FALSE; + break; + case ASN_BMPSTRING: + valueType = CERT_RDN_BMP_STRING; + bytesNeeded += dataLen; + break; + case ASN_UTF8STRING: + valueType = CERT_RDN_UTF8_STRING; + bytesNeeded += MultiByteToWideChar(CP_UTF8, 0, + (LPSTR)pbEncoded + 1 + lenBytes, dataLen, NULL, 0) * 2; break; default: - FIXME("Unimplemented string type %02x\n", pbEncoded[0]); - SetLastError(OSS_UNIMPLEMENTED); + SetLastError(CRYPT_E_ASN1_BADTAG); ret = FALSE; } if (ret) { - DWORD bytesNeeded = sizeof(CERT_NAME_VALUE); - - switch (pbEncoded[0]) - { - case ASN_NUMERICSTRING: - case ASN_PRINTABLESTRING: - case ASN_IA5STRING: - case ASN_T61STRING: - if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) - bytesNeeded += dataLen; - break; - } if (!value) *pcbStructInfo = bytesNeeded; else if (*pcbStructInfo < bytesNeeded) @@ -1310,40 +1352,53 @@ static BOOL WINAPI CRYPT_AsnDecodeNameValueInternal(DWORD dwCertEncodingType, else { *pcbStructInfo = bytesNeeded; - switch (pbEncoded[0]) - { - case ASN_NUMERICSTRING: - value->dwValueType = CERT_RDN_NUMERIC_STRING; - break; - case ASN_PRINTABLESTRING: - value->dwValueType = CERT_RDN_PRINTABLE_STRING; - break; - case ASN_IA5STRING: - value->dwValueType = CERT_RDN_IA5_STRING; - break; - case ASN_T61STRING: - value->dwValueType = CERT_RDN_T61_STRING; - break; - } + value->dwValueType = valueType; if (dataLen) { + DWORD i; + + assert(value->Value.pbData); switch (pbEncoded[0]) { + case ASN_OCTETSTRING: case ASN_NUMERICSTRING: case ASN_PRINTABLESTRING: case ASN_IA5STRING: case ASN_T61STRING: + case ASN_VIDEOTEXSTRING: + case ASN_GRAPHICSTRING: + case ASN_VISIBLESTRING: + case ASN_GENERALSTRING: value->Value.cbData = dataLen; - if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) - value->Value.pbData = (BYTE *)pbEncoded + 1 + - lenBytes; - else + if (dataLen) { - assert(value->Value.pbData); - memcpy(value->Value.pbData, - pbEncoded + 1 + lenBytes, dataLen); + if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) + memcpy(value->Value.pbData, + pbEncoded + 1 + lenBytes, dataLen); + else + value->Value.pbData = (LPBYTE)pbEncoded + 1 + + lenBytes; } break; + case ASN_BMPSTRING: + { + LPWSTR str = (LPWSTR)value->Value.pbData; + + 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]; + break; + } + case ASN_UTF8STRING: + { + LPWSTR str = (LPWSTR)value->Value.pbData; + + value->Value.cbData = MultiByteToWideChar(CP_UTF8, 0, + (LPSTR)pbEncoded + 1 + lenBytes, dataLen, + str, bytesNeeded - sizeof(CERT_NAME_VALUE)) * 2; + break; + } } } else diff --git a/dlls/crypt32/encode.c b/dlls/crypt32/encode.c index 33139aed833..d1c8ff72489 100644 --- a/dlls/crypt32/encode.c +++ b/dlls/crypt32/encode.c @@ -384,18 +384,18 @@ static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType, *pcbEncoded = blob->cbData; ret = TRUE; } - else if (*pcbEncoded < blob->cbData) - { - *pcbEncoded = blob->cbData; - SetLastError(ERROR_MORE_DATA); - ret = FALSE; - } else { - if (blob->cbData) - memcpy(pbEncoded, blob->pbData, blob->cbData); - *pcbEncoded = blob->cbData; - ret = TRUE; + if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, + pcbEncoded, blob->cbData))) + { + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) + pbEncoded = *(BYTE **)pbEncoded; + if (blob->cbData) + memcpy(pbEncoded, blob->pbData, blob->cbData); + *pcbEncoded = blob->cbData; + ret = TRUE; + } } return ret; } @@ -913,6 +913,104 @@ static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType, return ret; } +static BOOL CRYPT_AsnEncodeStringCoerce(const CERT_NAME_VALUE *value, + BYTE tag, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, + DWORD *pcbEncoded) +{ + BOOL ret = TRUE; + LPCSTR str = (LPCSTR)value->Value.pbData; + DWORD bytesNeeded, lenBytes, encodedLen; + + encodedLen = value->Value.cbData ? value->Value.cbData : lstrlenA(str); + CRYPT_EncodeLen(encodedLen, NULL, &lenBytes); + bytesNeeded = 1 + lenBytes + encodedLen; + if (!pbEncoded) + *pcbEncoded = bytesNeeded; + else + { + if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, + pbEncoded, pcbEncoded, bytesNeeded))) + { + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) + pbEncoded = *(BYTE **)pbEncoded; + *pbEncoded++ = tag; + CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes); + pbEncoded += lenBytes; + memcpy(pbEncoded, str, encodedLen); + } + } + return ret; +} + +static BOOL CRYPT_AsnEncodeBMPString(const CERT_NAME_VALUE *value, + DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, + DWORD *pcbEncoded) +{ + BOOL ret = TRUE; + LPCWSTR str = (LPCWSTR)value->Value.pbData; + DWORD bytesNeeded, lenBytes, strLen; + + strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) : + lstrlenW(str); + CRYPT_EncodeLen(strLen * 2, NULL, &lenBytes); + bytesNeeded = 1 + lenBytes + strLen * 2; + if (!pbEncoded) + *pcbEncoded = bytesNeeded; + else + { + if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, + pbEncoded, pcbEncoded, bytesNeeded))) + { + DWORD i; + + if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) + pbEncoded = *(BYTE **)pbEncoded; + *pbEncoded++ = ASN_BMPSTRING; + CRYPT_EncodeLen(strLen * 2, pbEncoded, &lenBytes); + pbEncoded += lenBytes; + for (i = 0; i < strLen; i++) + { + *pbEncoded++ = (str[i] & 0xff00) >> 8; + *pbEncoded++ = str[i] & 0x00ff; + } + } + } + return ret; +} + +static BOOL CRYPT_AsnEncodeUTF8String(const CERT_NAME_VALUE *value, + DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, + DWORD *pcbEncoded) +{ + BOOL ret = TRUE; + LPCWSTR str = (LPCWSTR)value->Value.pbData; + DWORD bytesNeeded, lenBytes, encodedLen, strLen; + + strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) : + lstrlenW(str); + encodedLen = WideCharToMultiByte(CP_UTF8, 0, str, strLen, NULL, 0, NULL, + NULL); + CRYPT_EncodeLen(encodedLen, NULL, &lenBytes); + bytesNeeded = 1 + lenBytes + encodedLen; + 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_UTF8STRING; + CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes); + pbEncoded += lenBytes; + WideCharToMultiByte(CP_UTF8, 0, str, strLen, (LPSTR)pbEncoded, + bytesNeeded - lenBytes - 1, NULL, NULL); + } + } + return ret; +} + static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) @@ -921,64 +1019,71 @@ static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType, __TRY { - BYTE tag; - DWORD bytesNeeded, lenBytes, encodedLen; const CERT_NAME_VALUE *value = (CERT_NAME_VALUE *)pvStructInfo; switch (value->dwValueType) { - case CERT_RDN_NUMERIC_STRING: - tag = ASN_NUMERICSTRING; - encodedLen = value->Value.cbData; - break; - case CERT_RDN_PRINTABLE_STRING: - tag = ASN_PRINTABLESTRING; - encodedLen = value->Value.cbData; - break; - case CERT_RDN_T61_STRING: - tag = ASN_T61STRING; - encodedLen = value->Value.cbData; - break; - case CERT_RDN_IA5_STRING: - tag = ASN_IA5STRING; - encodedLen = value->Value.cbData; - break; case CERT_RDN_ANY_TYPE: /* explicitly disallowed */ SetLastError(E_INVALIDARG); ret = FALSE; break; - default: - FIXME("String type %ld unimplemented\n", value->dwValueType); + case CERT_RDN_ENCODED_BLOB: + ret = CRYPT_CopyEncodedBlob(dwCertEncodingType, NULL, + &value->Value, dwFlags, pEncodePara, pbEncoded, pcbEncoded); + break; + case CERT_RDN_OCTET_STRING: + ret = CRYPT_AsnEncodeStringCoerce(value, ASN_OCTETSTRING, + dwFlags, pEncodePara, pbEncoded, pcbEncoded); + break; + case CERT_RDN_NUMERIC_STRING: + ret = CRYPT_AsnEncodeStringCoerce(value, ASN_NUMERICSTRING, + dwFlags, pEncodePara, pbEncoded, pcbEncoded); + break; + case CERT_RDN_PRINTABLE_STRING: + ret = CRYPT_AsnEncodeStringCoerce(value, ASN_PRINTABLESTRING, + dwFlags, pEncodePara, pbEncoded, pcbEncoded); + break; + case CERT_RDN_TELETEX_STRING: + ret = CRYPT_AsnEncodeStringCoerce(value, ASN_T61STRING, + dwFlags, pEncodePara, pbEncoded, pcbEncoded); + break; + case CERT_RDN_VIDEOTEX_STRING: + ret = CRYPT_AsnEncodeStringCoerce(value, + ASN_VIDEOTEXSTRING, dwFlags, pEncodePara, pbEncoded, pcbEncoded); + break; + case CERT_RDN_IA5_STRING: + ret = CRYPT_AsnEncodeStringCoerce(value, ASN_IA5STRING, + dwFlags, pEncodePara, pbEncoded, pcbEncoded); + break; + case CERT_RDN_GRAPHIC_STRING: + ret = CRYPT_AsnEncodeStringCoerce(value, ASN_GRAPHICSTRING, + dwFlags, pEncodePara, pbEncoded, pcbEncoded); + break; + case CERT_RDN_VISIBLE_STRING: + ret = CRYPT_AsnEncodeStringCoerce(value, ASN_VISIBLESTRING, + dwFlags, pEncodePara, pbEncoded, pcbEncoded); + break; + case CERT_RDN_GENERAL_STRING: + ret = CRYPT_AsnEncodeStringCoerce(value, ASN_GENERALSTRING, + dwFlags, pEncodePara, pbEncoded, pcbEncoded); + break; + case CERT_RDN_UNIVERSAL_STRING: + FIXME("CERT_RDN_UNIVERSAL_STRING: unimplemented\n"); + SetLastError(CRYPT_E_ASN1_CHOICE); + ret = FALSE; + break; + case CERT_RDN_BMP_STRING: + ret = CRYPT_AsnEncodeBMPString(value, dwFlags, pEncodePara, + pbEncoded, pcbEncoded); + break; + case CERT_RDN_UTF8_STRING: + ret = CRYPT_AsnEncodeUTF8String(value, dwFlags, pEncodePara, + pbEncoded, pcbEncoded); + break; + default: + SetLastError(CRYPT_E_ASN1_CHOICE); ret = FALSE; - } - if (ret) - { - CRYPT_EncodeLen(encodedLen, NULL, &lenBytes); - bytesNeeded = 1 + lenBytes + encodedLen; - if (!pbEncoded) - *pcbEncoded = bytesNeeded; - else - { - if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, - pbEncoded, pcbEncoded, bytesNeeded))) - { - if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) - pbEncoded = *(BYTE **)pbEncoded; - *pbEncoded++ = tag; - CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes); - pbEncoded += lenBytes; - switch (value->dwValueType) - { - case CERT_RDN_NUMERIC_STRING: - case CERT_RDN_PRINTABLE_STRING: - case CERT_RDN_T61_STRING: - case CERT_RDN_IA5_STRING: - memcpy(pbEncoded, value->Value.pbData, - value->Value.cbData); - } - } - } } } __EXCEPT_PAGE_FAULT @@ -1156,39 +1261,6 @@ static BOOL CRYPT_AsnEncodeIA5String(const CERT_NAME_VALUE *value, return ret; } -static BOOL CRYPT_AsnEncodeUTF8String(const CERT_NAME_VALUE *value, - DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, - DWORD *pcbEncoded) -{ - BOOL ret = TRUE; - LPCWSTR str = (LPCWSTR)value->Value.pbData; - DWORD bytesNeeded, lenBytes, encodedLen, strLen; - - strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) : - lstrlenW(str); - encodedLen = WideCharToMultiByte(CP_UTF8, 0, str, strLen, NULL, 0, NULL, - NULL); - CRYPT_EncodeLen(encodedLen, NULL, &lenBytes); - bytesNeeded = 1 + lenBytes + encodedLen; - 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_UTF8STRING; - CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes); - pbEncoded += lenBytes; - WideCharToMultiByte(CP_UTF8, 0, str, strLen, (LPSTR)pbEncoded, - bytesNeeded - lenBytes - 1, NULL, NULL); - } - } - return ret; -} - static BOOL CRYPT_AsnEncodeUniversalString(const CERT_NAME_VALUE *value, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) @@ -1228,42 +1300,6 @@ static BOOL CRYPT_AsnEncodeUniversalString(const CERT_NAME_VALUE *value, return ret; } -static BOOL CRYPT_AsnEncodeBMPString(const CERT_NAME_VALUE *value, - DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, - DWORD *pcbEncoded) -{ - BOOL ret = TRUE; - LPCWSTR str = (LPCWSTR)value->Value.pbData; - DWORD bytesNeeded, lenBytes, strLen; - - strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) : - lstrlenW(str); - CRYPT_EncodeLen(strLen * 2, NULL, &lenBytes); - bytesNeeded = 1 + lenBytes + strLen * 2; - if (!pbEncoded) - *pcbEncoded = bytesNeeded; - else - { - if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, - pbEncoded, pcbEncoded, bytesNeeded))) - { - DWORD i; - - if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) - pbEncoded = *(BYTE **)pbEncoded; - *pbEncoded++ = ASN_BMPSTRING; - CRYPT_EncodeLen(strLen * 2, pbEncoded, &lenBytes); - pbEncoded += lenBytes; - for (i = 0; i < strLen; i++) - { - *pbEncoded++ = (str[i] & 0xff00) >> 8; - *pbEncoded++ = str[i] & 0x00ff; - } - } - } - return ret; -} - static BOOL WINAPI CRYPT_AsnEncodeUnicodeNameValue(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c index 1f30ae4c41f..2783b7900f5 100644 --- a/dlls/crypt32/tests/encode.c +++ b/dlls/crypt32/tests/encode.c @@ -605,6 +605,12 @@ static const BYTE twoRDNs[] = { 0x30,0x23,0x31,0x21,0x30,0x0c,0x06,0x03,0x55,0x04,0x04, 0x13,0x05,0x4c,0x61,0x6e,0x67,0x00,0x30,0x11,0x06,0x03,0x55,0x04,0x03, 0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0}; +static const BYTE encodedTwoRDNs[] = { +0x30,0x2e,0x31,0x2c,0x30,0x2a,0x06,0x03,0x55,0x04,0x03,0x30,0x23,0x31,0x21, +0x30,0x0c,0x06,0x03,0x55,0x04,0x04,0x13,0x05,0x4c,0x61,0x6e,0x67,0x00,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00, +}; static const BYTE us[] = { 0x55, 0x53 }; static const BYTE minnesota[] = { 0x4d, 0x69, 0x6e, 0x6e, 0x65, 0x73, 0x6f, @@ -742,6 +748,21 @@ static void test_encodeName(DWORD dwEncoding) "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_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); + } /* CERT_RDN_ANY_TYPE is too vague for X509_NAMEs, check the return */ rdn.cRDNAttr = 1; attrs[0].dwValueType = CERT_RDN_ANY_TYPE; @@ -774,11 +795,12 @@ static void compareNameValues(const CERT_NAME_VALUE *expected, "Expected string type %ld, got %ld\n", expected->dwValueType, got->dwValueType); ok(got->Value.cbData == expected->Value.cbData, - "Unexpected data size, got %ld, expected %ld\n", got->Value.cbData, - expected->Value.cbData); + "String type %ld: unexpected data size, got %ld, expected %ld\n", + expected->dwValueType, got->Value.cbData, expected->Value.cbData); if (got->Value.cbData && got->Value.pbData) ok(!memcmp(got->Value.pbData, expected->Value.pbData, - min(got->Value.cbData, expected->Value.cbData)), "Unexpected value\n"); + min(got->Value.cbData, expected->Value.cbData)), + "String type %ld: unexpected value\n", expected->dwValueType); } static void compareRDNAttrs(const CERT_RDN_ATTR *expected, @@ -908,56 +930,112 @@ struct EncodedNameValue { CERT_NAME_VALUE value; const BYTE *encoded; + DWORD encodedSize; }; static const char bogusIA5[] = "\x80"; static const char bogusPrintable[] = "~"; static const char bogusNumeric[] = "A"; -static const char bogusT61[] = "\xff"; -static const BYTE bin39[] = { 0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, - 0x67,0x00 }; -static const BYTE bin40[] = { 0x16,0x05,0x4c,0x61,0x6e,0x67,0x00 }; -static const BYTE bin41[] = { 0x14,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, - 0x67,0x00 }; +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 }; -static const BYTE bin45[] = { 0x14,0x02,0xff,0x00 }; +static BYTE octetCommonNameValue[] = { + 0x04,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; +static BYTE numericCommonNameValue[] = { + 0x12,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; +static BYTE printableCommonNameValue[] = { + 0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; +static BYTE t61CommonNameValue[] = { + 0x14,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; +static BYTE videotexCommonNameValue[] = { + 0x15,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; +static BYTE ia5CommonNameValue[] = { + 0x16,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; +static BYTE graphicCommonNameValue[] = { + 0x19,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; +static BYTE visibleCommonNameValue[] = { + 0x1a,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; +static BYTE generalCommonNameValue[] = { + 0x1b,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; +static BYTE bmpCommonNameValue[] = { + 0x1e,0x14,0x00,0x4a,0x00,0x75,0x00,0x61,0x00,0x6e,0x00,0x20,0x00,0x4c,0x00, + 0x61,0x00,0x6e,0x00,0x67,0x00,0x00 }; +static BYTE utf8CommonNameValue[] = { + 0x0c,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; -struct EncodedNameValue nameValues[] = { +static struct EncodedNameValue nameValues[] = { + { { CERT_RDN_OCTET_STRING, { sizeof(commonName), (BYTE *)commonName } }, + octetCommonNameValue, sizeof(octetCommonNameValue) }, + { { CERT_RDN_NUMERIC_STRING, { sizeof(commonName), (BYTE *)commonName } }, + numericCommonNameValue, sizeof(numericCommonNameValue) }, { { CERT_RDN_PRINTABLE_STRING, { sizeof(commonName), (BYTE *)commonName } }, - bin39 }, - { { CERT_RDN_IA5_STRING, { sizeof(surName), (BYTE *)surName } }, bin40 }, - { { CERT_RDN_T61_STRING, { sizeof(commonName), (BYTE *)commonName } }, bin41 }, + printableCommonNameValue, sizeof(printableCommonNameValue) }, + { { CERT_RDN_T61_STRING, { sizeof(commonName), (BYTE *)commonName } }, + t61CommonNameValue, sizeof(t61CommonNameValue) }, + { { CERT_RDN_VIDEOTEX_STRING, { sizeof(commonName), (BYTE *)commonName } }, + videotexCommonNameValue, sizeof(videotexCommonNameValue) }, + { { CERT_RDN_IA5_STRING, { sizeof(commonName), (BYTE *)commonName } }, + ia5CommonNameValue, sizeof(ia5CommonNameValue) }, + { { CERT_RDN_GRAPHIC_STRING, { sizeof(commonName), (BYTE *)commonName } }, + graphicCommonNameValue, sizeof(graphicCommonNameValue) }, + { { CERT_RDN_VISIBLE_STRING, { sizeof(commonName), (BYTE *)commonName } }, + visibleCommonNameValue, sizeof(visibleCommonNameValue) }, + { { CERT_RDN_GENERAL_STRING, { sizeof(commonName), (BYTE *)commonName } }, + generalCommonNameValue, sizeof(generalCommonNameValue) }, + { { CERT_RDN_BMP_STRING, { sizeof(commonNameW), (BYTE *)commonNameW } }, + bmpCommonNameValue, sizeof(bmpCommonNameValue) }, + { { CERT_RDN_UTF8_STRING, { sizeof(commonNameW), (BYTE *)commonNameW } }, + utf8CommonNameValue, sizeof(utf8CommonNameValue) }, /* The following tests succeed under Windows, but really should fail, * they contain characters that are illegal for the encoding. I'm * including them to justify my lazy encoding. */ - { { CERT_RDN_IA5_STRING, { sizeof(bogusIA5), (BYTE *)bogusIA5 } }, bin42 }, + { { CERT_RDN_IA5_STRING, { sizeof(bogusIA5), (BYTE *)bogusIA5 } }, bin42, + sizeof(bin42) }, { { CERT_RDN_PRINTABLE_STRING, { sizeof(bogusPrintable), - (BYTE *)bogusPrintable } }, bin43 }, + (BYTE *)bogusPrintable } }, bin43, sizeof(bin43) }, { { CERT_RDN_NUMERIC_STRING, { sizeof(bogusNumeric), (BYTE *)bogusNumeric } }, - bin44 }, - { { CERT_RDN_T61_STRING, { sizeof(bogusT61), (BYTE *)bogusT61 } }, bin45 }, + bin44, sizeof(bin44) }, }; - static void test_encodeNameValue(DWORD dwEncoding) { BYTE *buf = NULL; DWORD size = 0, i; BOOL ret; + CERT_NAME_VALUE value = { 0, { 0, NULL } }; + value.dwValueType = 14; + ret = CryptEncodeObjectEx(dwEncoding, X509_NAME_VALUE, &value, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(!ret && GetLastError() == CRYPT_E_ASN1_CHOICE, + "Expected CRYPT_E_ASN1_CHOICE, got %08lx\n", GetLastError()); + value.dwValueType = CERT_RDN_ENCODED_BLOB; + value.Value.pbData = printableCommonNameValue; + value.Value.cbData = sizeof(printableCommonNameValue); + ret = CryptEncodeObjectEx(dwEncoding, X509_NAME_VALUE, &value, + CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError()); + if (buf) + { + ok(size == sizeof(printableCommonNameValue), "Unexpected size %ld\n", + size); + ok(!memcmp(buf, printableCommonNameValue, size), + "Unexpected encoding\n"); + LocalFree(buf); + } for (i = 0; i < sizeof(nameValues) / sizeof(nameValues[0]); i++) { ret = CryptEncodeObjectEx(dwEncoding, X509_NAME_VALUE, &nameValues[i].value, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); - ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError()); + ok(ret, "Type %ld: CryptEncodeObjectEx failed: %08lx\n", + nameValues[i].value.dwValueType, GetLastError()); if (buf) { - ok(size == nameValues[i].encoded[1] + 2, - "Expected size %d, got %ld\n", nameValues[i].encoded[1] + 2, size); + ok(size == nameValues[i].encodedSize, + "Expected size %ld, got %ld\n", nameValues[i].encodedSize, size); ok(!memcmp(buf, nameValues[i].encoded, size), "Got unexpected encoding\n"); LocalFree(buf); @@ -978,7 +1056,8 @@ static void test_decodeNameValue(DWORD dwEncoding) nameValues[i].encoded, nameValues[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL, (BYTE *)&buf, &bufSize); - ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError()); + ok(ret, "Value type %ld: CryptDecodeObjectEx failed: %08lx\n", + nameValues[i].value.dwValueType, GetLastError()); if (buf) { compareNameValues(&nameValues[i].value,