2 * Copyright 2006 Juan Lang for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #define NONAMELESSUNION
27 #include "wine/debug.h"
28 #include "wine/unicode.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
32 static inline BOOL is_quotable_char(char c)
50 DWORD WINAPI CertRDNValueToStrA(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
53 DWORD ret = 0, len, i;
54 BOOL needsQuotes = FALSE;
56 TRACE("(%d, %p, %p, %d)\n", dwValueType, pValue, psz, csz);
60 case CERT_RDN_ANY_TYPE:
62 case CERT_RDN_NUMERIC_STRING:
63 case CERT_RDN_PRINTABLE_STRING:
64 case CERT_RDN_TELETEX_STRING:
65 case CERT_RDN_VIDEOTEX_STRING:
66 case CERT_RDN_IA5_STRING:
67 case CERT_RDN_GRAPHIC_STRING:
68 case CERT_RDN_VISIBLE_STRING:
69 case CERT_RDN_GENERAL_STRING:
71 if (pValue->cbData && isspace(pValue->pbData[0]))
73 if (pValue->cbData && isspace(pValue->pbData[pValue->cbData - 1]))
75 for (i = 0; i < pValue->cbData; i++)
77 if (is_quotable_char(pValue->pbData[i]))
79 if (pValue->pbData[i] == '"')
92 for (i = 0; i < pValue->cbData && ptr - psz < csz; ptr++, i++)
94 *ptr = pValue->pbData[i];
95 if (pValue->pbData[i] == '"' && ptr - psz < csz - 1)
98 if (needsQuotes && ptr - psz < csz)
103 case CERT_RDN_BMP_STRING:
104 len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pValue->pbData,
105 pValue->cbData / sizeof(WCHAR), NULL, 0, NULL, NULL);
106 if (pValue->cbData && isspaceW(((LPCWSTR)pValue->pbData)[0]))
108 if (pValue->cbData &&
109 isspaceW(((LPCWSTR)pValue->pbData)[pValue->cbData / sizeof(WCHAR)-1]))
111 for (i = 0; i < pValue->cbData / sizeof(WCHAR); i++)
113 if (is_quotable_char(((LPCWSTR)pValue->pbData)[i]))
115 if (((LPCWSTR)pValue->pbData)[i] == '"')
128 for (i = 0; i < pValue->cbData / sizeof(WCHAR) &&
129 dst - psz < csz; dst++, i++)
131 LPCWSTR src = (LPCWSTR)pValue->pbData + i;
133 WideCharToMultiByte(CP_ACP, 0, src, 1, dst,
134 csz - (dst - psz) - 1, NULL, NULL);
135 if (*src == '"' && dst - psz < csz - 1)
138 if (needsQuotes && dst - psz < csz)
144 FIXME("string type %d unimplemented\n", dwValueType);
154 TRACE("returning %d (%s)\n", ret, debugstr_a(psz));
158 DWORD WINAPI CertRDNValueToStrW(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
159 LPWSTR psz, DWORD csz)
161 DWORD ret = 0, len, i;
162 BOOL needsQuotes = FALSE;
164 TRACE("(%d, %p, %p, %d)\n", dwValueType, pValue, psz, csz);
168 case CERT_RDN_ANY_TYPE:
170 case CERT_RDN_NUMERIC_STRING:
171 case CERT_RDN_PRINTABLE_STRING:
172 case CERT_RDN_TELETEX_STRING:
173 case CERT_RDN_VIDEOTEX_STRING:
174 case CERT_RDN_IA5_STRING:
175 case CERT_RDN_GRAPHIC_STRING:
176 case CERT_RDN_VISIBLE_STRING:
177 case CERT_RDN_GENERAL_STRING:
178 case CERT_RDN_BMP_STRING:
179 len = pValue->cbData;
180 if (pValue->cbData && isspace(pValue->pbData[0]))
182 if (pValue->cbData && isspace(pValue->pbData[pValue->cbData - 1]))
184 for (i = 0; i < pValue->cbData; i++)
186 if (is_quotable_char(pValue->pbData[i]))
188 if (pValue->pbData[i] == '"')
201 for (i = 0; i < pValue->cbData && ptr - psz < csz; ptr++, i++)
203 *ptr = pValue->pbData[i];
204 if (pValue->pbData[i] == '"' && ptr - psz < csz - 1)
207 if (needsQuotes && ptr - psz < csz)
213 FIXME("string type %d unimplemented\n", dwValueType);
223 TRACE("returning %d (%s)\n", ret, debugstr_w(psz));
227 /* Adds the prefix prefix to the string pointed to by psz, followed by the
228 * character '='. Copies no more than csz characters. Returns the number of
229 * characters copied. If psz is NULL, returns the number of characters that
232 static DWORD CRYPT_AddPrefixA(LPCSTR prefix, LPSTR psz, DWORD csz)
236 TRACE("(%s, %p, %d)\n", debugstr_a(prefix), psz, csz);
240 chars = min(strlen(prefix), csz);
241 memcpy(psz, prefix, chars);
242 *(psz + chars) = '=';
246 chars = lstrlenA(prefix) + 1;
250 DWORD WINAPI CertNameToStrA(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
251 DWORD dwStrType, LPSTR psz, DWORD csz)
253 static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG |
254 CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG;
255 static const char commaSep[] = ", ";
256 static const char semiSep[] = "; ";
257 static const char crlfSep[] = "\r\n";
258 static const char plusSep[] = " + ";
259 static const char spaceSep[] = " ";
260 DWORD ret = 0, bytes = 0;
262 CERT_NAME_INFO *info;
264 TRACE("(%d, %p, %08x, %p, %d)\n", dwCertEncodingType, pName, dwStrType,
266 if (dwStrType & unsupportedFlags)
267 FIXME("unsupported flags: %08x\n", dwStrType & unsupportedFlags);
269 bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData,
270 pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes);
273 DWORD i, j, sepLen, rdnSepLen;
275 BOOL reverse = dwStrType & CERT_NAME_STR_REVERSE_FLAG;
276 const CERT_RDN *rdn = info->rgRDN;
278 if(reverse && info->cRDN > 1) rdn += (info->cRDN - 1);
280 if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
282 else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
286 sepLen = strlen(sep);
287 if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
291 rdnSepLen = strlen(rdnSep);
292 for (i = 0; (!psz || ret < csz) && i < info->cRDN; i++)
294 for (j = 0; (!psz || ret < csz) && j < rdn->cRDNAttr; j++)
297 char prefixBuf[10]; /* big enough for GivenName */
298 LPCSTR prefix = NULL;
300 if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR)
301 prefix = rdn->rgRDNAttr[j].pszObjId;
302 else if ((dwStrType & 0x000000ff) == CERT_X500_NAME_STR)
304 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(
305 CRYPT_OID_INFO_OID_KEY,
306 rdn->rgRDNAttr[j].pszObjId,
307 CRYPT_RDN_ATTR_OID_GROUP_ID);
311 WideCharToMultiByte(CP_ACP, 0, oidInfo->pwszName, -1,
312 prefixBuf, sizeof(prefixBuf), NULL, NULL);
316 prefix = rdn->rgRDNAttr[j].pszObjId;
320 /* - 1 is needed to account for the NULL terminator. */
321 chars = CRYPT_AddPrefixA(prefix,
322 psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
325 /* FIXME: handle quoting */
326 chars = CertRDNValueToStrA(
327 rdn->rgRDNAttr[j].dwValueType,
328 &rdn->rgRDNAttr[j].Value, psz ? psz + ret : NULL,
329 psz ? csz - ret : 0);
332 if (j < rdn->cRDNAttr - 1)
334 if (psz && ret < csz - rdnSepLen - 1)
335 memcpy(psz + ret, rdnSep, rdnSepLen);
339 if (i < info->cRDN - 1)
341 if (psz && ret < csz - sepLen - 1)
342 memcpy(psz + ret, sep, sepLen);
357 TRACE("Returning %s\n", debugstr_a(psz));
361 /* Adds the prefix prefix to the wide-character string pointed to by psz,
362 * followed by the character '='. Copies no more than csz characters. Returns
363 * the number of characters copied. If psz is NULL, returns the number of
364 * characters that would be copied.
365 * Assumes the characters in prefix are ASCII (not multibyte characters.)
367 static DWORD CRYPT_AddPrefixAToW(LPCSTR prefix, LPWSTR psz, DWORD csz)
371 TRACE("(%s, %p, %d)\n", debugstr_a(prefix), psz, csz);
377 chars = min(strlen(prefix), csz);
378 for (i = 0; i < chars; i++)
379 *(psz + i) = prefix[i];
380 *(psz + chars) = '=';
384 chars = lstrlenA(prefix) + 1;
388 /* Adds the prefix prefix to the string pointed to by psz, followed by the
389 * character '='. Copies no more than csz characters. Returns the number of
390 * characters copied. If psz is NULL, returns the number of characters that
393 static DWORD CRYPT_AddPrefixW(LPCWSTR prefix, LPWSTR psz, DWORD csz)
397 TRACE("(%s, %p, %d)\n", debugstr_w(prefix), psz, csz);
401 chars = min(strlenW(prefix), csz);
402 memcpy(psz, prefix, chars * sizeof(WCHAR));
403 *(psz + chars) = '=';
407 chars = lstrlenW(prefix) + 1;
411 static const WCHAR indent[] = { ' ',' ',' ',' ',' ',0 };
413 DWORD cert_name_to_str_with_indent(DWORD dwCertEncodingType, DWORD indentLevel,
414 const CERT_NAME_BLOB *pName, DWORD dwStrType, LPWSTR psz, DWORD csz)
416 static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG |
417 CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG;
418 static const WCHAR commaSep[] = { ',',' ',0 };
419 static const WCHAR semiSep[] = { ';',' ',0 };
420 static const WCHAR crlfSep[] = { '\r','\n',0 };
421 static const WCHAR plusSep[] = { ' ','+',' ',0 };
422 static const WCHAR spaceSep[] = { ' ',0 };
423 DWORD ret = 0, bytes = 0;
425 CERT_NAME_INFO *info;
427 if (dwStrType & unsupportedFlags)
428 FIXME("unsupported flags: %08x\n", dwStrType & unsupportedFlags);
430 bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData,
431 pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes);
434 DWORD i, j, sepLen, rdnSepLen;
436 BOOL reverse = dwStrType & CERT_NAME_STR_REVERSE_FLAG;
437 const CERT_RDN *rdn = info->rgRDN;
439 if(reverse && info->cRDN > 1) rdn += (info->cRDN - 1);
441 if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
443 else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
447 sepLen = lstrlenW(sep);
448 if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
452 rdnSepLen = lstrlenW(rdnSep);
453 for (i = 0; (!psz || ret < csz) && i < info->cRDN; i++)
455 for (j = 0; (!psz || ret < csz) && j < rdn->cRDNAttr; j++)
458 LPCSTR prefixA = NULL;
459 LPCWSTR prefixW = NULL;
461 if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR)
462 prefixA = rdn->rgRDNAttr[j].pszObjId;
463 else if ((dwStrType & 0x000000ff) == CERT_X500_NAME_STR)
465 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(
466 CRYPT_OID_INFO_OID_KEY,
467 rdn->rgRDNAttr[j].pszObjId,
468 CRYPT_RDN_ATTR_OID_GROUP_ID);
471 prefixW = oidInfo->pwszName;
473 prefixA = rdn->rgRDNAttr[j].pszObjId;
475 if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
479 for (k = 0; k < indentLevel; k++)
483 chars = min(strlenW(indent), csz - ret - 1);
484 memcpy(psz + ret, indent, chars * sizeof(WCHAR));
487 chars = strlenW(indent);
493 /* - 1 is needed to account for the NULL terminator. */
494 chars = CRYPT_AddPrefixW(prefixW,
495 psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
500 /* - 1 is needed to account for the NULL terminator. */
501 chars = CRYPT_AddPrefixAToW(prefixA,
502 psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
505 /* FIXME: handle quoting */
506 chars = CertRDNValueToStrW(
507 rdn->rgRDNAttr[j].dwValueType,
508 &rdn->rgRDNAttr[j].Value, psz ? psz + ret : NULL,
509 psz ? csz - ret : 0);
512 if (j < rdn->cRDNAttr - 1)
514 if (psz && ret < csz - rdnSepLen - 1)
515 memcpy(psz + ret, rdnSep, rdnSepLen * sizeof(WCHAR));
519 if (i < info->cRDN - 1)
521 if (psz && ret < csz - sepLen - 1)
522 memcpy(psz + ret, sep, sepLen * sizeof(WCHAR));
540 DWORD WINAPI CertNameToStrW(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
541 DWORD dwStrType, LPWSTR psz, DWORD csz)
545 TRACE("(%d, %p, %08x, %p, %d)\n", dwCertEncodingType, pName, dwStrType,
548 ret = cert_name_to_str_with_indent(dwCertEncodingType, 0, pName, dwStrType,
550 TRACE("Returning %s\n", debugstr_w(psz));
554 BOOL WINAPI CertStrToNameA(DWORD dwCertEncodingType, LPCSTR pszX500,
555 DWORD dwStrType, void *pvReserved, BYTE *pbEncoded, DWORD *pcbEncoded,
561 TRACE("(%08x, %s, %08x, %p, %p, %p, %p)\n", dwCertEncodingType,
562 debugstr_a(pszX500), dwStrType, pvReserved, pbEncoded, pcbEncoded,
565 len = MultiByteToWideChar(CP_ACP, 0, pszX500, -1, NULL, 0);
568 LPWSTR x500, errorStr;
570 if ((x500 = CryptMemAlloc(len * sizeof(WCHAR))))
572 MultiByteToWideChar(CP_ACP, 0, pszX500, -1, x500, len);
573 ret = CertStrToNameW(dwCertEncodingType, x500, dwStrType,
574 pvReserved, pbEncoded, pcbEncoded,
575 ppszError ? (LPCWSTR *)&errorStr : NULL);
582 *ppszError = pszX500;
583 for (i = 0; i < errorStr - x500; i++)
584 *ppszError = CharNextA(*ppszError);
593 SetLastError(ERROR_OUTOFMEMORY);
599 SetLastError(CRYPT_E_INVALID_X500_STRING);
601 *ppszError = pszX500;
609 WCHAR buf[10]; /* big enough for L"GivenName" */
610 LPWSTR keyName; /* usually = buf, but may be allocated */
614 static void CRYPT_InitializeKeynameKeeper(struct KeynameKeeper *keeper)
616 keeper->keyName = keeper->buf;
617 keeper->keyLen = sizeof(keeper->buf) / sizeof(keeper->buf[0]);
620 static void CRYPT_FreeKeynameKeeper(struct KeynameKeeper *keeper)
622 if (keeper->keyName != keeper->buf)
623 CryptMemFree(keeper->keyName);
632 static void CRYPT_KeynameKeeperFromTokenW(struct KeynameKeeper *keeper,
633 const struct X500TokenW *key)
635 DWORD len = key->end - key->start;
637 if (len > keeper->keyLen)
639 if (keeper->keyName == keeper->buf)
640 keeper->keyName = CryptMemAlloc(len * sizeof(WCHAR));
642 keeper->keyName = CryptMemRealloc(keeper->keyName,
643 len * sizeof(WCHAR));
644 keeper->keyLen = len;
646 memcpy(keeper->keyName, key->start, (key->end - key->start) *
648 keeper->keyName[len] = '\0';
649 TRACE("Keyname is %s\n", debugstr_w(keeper->keyName));
652 static BOOL CRYPT_GetNextKeyW(LPCWSTR str, struct X500TokenW *token,
657 while (*str && isspaceW(*str))
662 while (*str && *str != '=' && !isspaceW(*str))
664 if (*str && (*str == '=' || isspaceW(*str)))
668 TRACE("missing equals char at %s\n", debugstr_w(token->start));
670 *ppszError = token->start;
671 SetLastError(CRYPT_E_INVALID_X500_STRING);
680 /* Assumes separators are characters in the 0-255 range */
681 static BOOL CRYPT_GetNextValueW(LPCWSTR str, DWORD dwFlags, LPCWSTR separators,
682 struct X500TokenW *token, LPCWSTR *ppszError)
686 TRACE("(%s, %s, %p, %p)\n", debugstr_w(str), debugstr_w(separators), token,
689 while (*str && isspaceW(*str))
694 if (!(dwFlags & CERT_NAME_STR_NO_QUOTING_FLAG) && *str == '"')
698 while (!token->end && ret)
700 while (*str && *str != '"')
704 if (*(str + 1) != '"')
705 token->end = str + 1;
711 TRACE("unterminated quote at %s\n", debugstr_w(str));
714 SetLastError(CRYPT_E_INVALID_X500_STRING);
721 WCHAR map[256] = { 0 };
724 map[*separators++] = 1;
725 while (*str && (*str >= 0xff || !map[*str]))
732 TRACE("missing value at %s\n", debugstr_w(str));
735 SetLastError(CRYPT_E_INVALID_X500_STRING);
741 /* Encodes the string represented by value as the string type type into the
742 * CERT_NAME_BLOB output. If there is an error and ppszError is not NULL,
743 * *ppszError is set to the first failing character. If there is no error,
744 * output's pbData must be freed with LocalFree.
746 static BOOL CRYPT_EncodeValueWithType(DWORD dwCertEncodingType,
747 const struct X500TokenW *value, PCERT_NAME_BLOB output, DWORD type,
750 CERT_NAME_VALUE nameValue = { type, { 0, NULL } };
753 if (value->end > value->start)
755 nameValue.Value.pbData = CryptMemAlloc((value->end - value->start) *
757 if (!nameValue.Value.pbData)
759 SetLastError(ERROR_OUTOFMEMORY);
765 if (value->end > value->start)
768 LPWSTR ptr = (LPWSTR)nameValue.Value.pbData;
770 for (i = 0; i < value->end - value->start; i++)
772 *ptr++ = value->start[i];
773 if (value->start[i] == '"')
776 nameValue.Value.cbData = (LPBYTE)ptr - nameValue.Value.pbData;
778 ret = CryptEncodeObjectEx(dwCertEncodingType, X509_UNICODE_NAME_VALUE,
779 &nameValue, CRYPT_ENCODE_ALLOC_FLAG, NULL, &output->pbData,
781 if (!ret && ppszError)
783 if (type == CERT_RDN_NUMERIC_STRING &&
784 GetLastError() == CRYPT_E_INVALID_NUMERIC_STRING)
785 *ppszError = value->start + output->cbData;
786 else if (type == CERT_RDN_PRINTABLE_STRING &&
787 GetLastError() == CRYPT_E_INVALID_PRINTABLE_STRING)
788 *ppszError = value->start + output->cbData;
789 else if (type == CERT_RDN_IA5_STRING &&
790 GetLastError() == CRYPT_E_INVALID_IA5_STRING)
791 *ppszError = value->start + output->cbData;
793 CryptMemFree(nameValue.Value.pbData);
798 static BOOL CRYPT_EncodeValue(DWORD dwCertEncodingType,
799 const struct X500TokenW *value, PCERT_NAME_BLOB output, const DWORD *types,
806 for (i = 0; !ret && types[i]; i++)
807 ret = CRYPT_EncodeValueWithType(dwCertEncodingType, value, output,
808 types[i], ppszError);
812 static BOOL CRYPT_ValueToRDN(DWORD dwCertEncodingType, PCERT_NAME_INFO info,
813 PCCRYPT_OID_INFO keyOID, struct X500TokenW *value, LPCWSTR *ppszError)
817 TRACE("OID %s, value %s\n", debugstr_a(keyOID->pszOID),
818 debugstr_wn(value->start, value->end - value->start));
821 info->rgRDN = CryptMemAlloc(sizeof(CERT_RDN));
823 info->rgRDN = CryptMemRealloc(info->rgRDN,
824 (info->cRDN + 1) * sizeof(CERT_RDN));
827 /* FIXME: support multiple RDN attrs */
828 info->rgRDN[info->cRDN].rgRDNAttr =
829 CryptMemAlloc(sizeof(CERT_RDN_ATTR));
830 if (info->rgRDN[info->cRDN].rgRDNAttr)
832 static const DWORD defaultTypes[] = { CERT_RDN_PRINTABLE_STRING,
833 CERT_RDN_BMP_STRING, 0 };
836 info->rgRDN[info->cRDN].cRDNAttr = 1;
837 info->rgRDN[info->cRDN].rgRDNAttr[0].pszObjId =
838 (LPSTR)keyOID->pszOID;
839 info->rgRDN[info->cRDN].rgRDNAttr[0].dwValueType =
840 CERT_RDN_ENCODED_BLOB;
841 if (keyOID->ExtraInfo.cbData)
842 types = (const DWORD *)keyOID->ExtraInfo.pbData;
844 types = defaultTypes;
846 /* Remove surrounding quotes */
847 if (value->start[0] == '"')
852 ret = CRYPT_EncodeValue(dwCertEncodingType, value,
853 &info->rgRDN[info->cRDN].rgRDNAttr[0].Value, types, ppszError);
856 SetLastError(ERROR_OUTOFMEMORY);
860 SetLastError(ERROR_OUTOFMEMORY);
864 BOOL WINAPI CertStrToNameW(DWORD dwCertEncodingType, LPCWSTR pszX500,
865 DWORD dwStrType, void *pvReserved, BYTE *pbEncoded, DWORD *pcbEncoded,
868 CERT_NAME_INFO info = { 0, NULL };
870 struct KeynameKeeper keeper;
874 TRACE("(%08x, %s, %08x, %p, %p, %p, %p)\n", dwCertEncodingType,
875 debugstr_w(pszX500), dwStrType, pvReserved, pbEncoded, pcbEncoded,
878 CRYPT_InitializeKeynameKeeper(&keeper);
880 while (str && *str && ret)
882 struct X500TokenW token;
884 ret = CRYPT_GetNextKeyW(str, &token, ppszError);
885 if (ret && token.start)
887 PCCRYPT_OID_INFO keyOID;
889 CRYPT_KeynameKeeperFromTokenW(&keeper, &token);
890 keyOID = CryptFindOIDInfo(CRYPT_OID_INFO_NAME_KEY, keeper.keyName,
891 CRYPT_RDN_ATTR_OID_GROUP_ID);
895 *ppszError = token.start;
896 SetLastError(CRYPT_E_INVALID_X500_STRING);
902 while (isspace(*str))
908 SetLastError(CRYPT_E_INVALID_X500_STRING);
913 static const WCHAR commaSep[] = { ',',0 };
914 static const WCHAR semiSep[] = { ';',0 };
915 static const WCHAR crlfSep[] = { '\r','\n',0 };
916 static const WCHAR allSeps[] = { ',',';','\r','\n',0 };
920 if (dwStrType & CERT_NAME_STR_COMMA_FLAG)
922 else if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
924 else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
928 ret = CRYPT_GetNextValueW(str, dwStrType, sep, &token,
933 ret = CRYPT_ValueToRDN(dwCertEncodingType, &info,
934 keyOID, &token, ppszError);
940 CRYPT_FreeKeynameKeeper(&keeper);
945 ret = CryptEncodeObjectEx(dwCertEncodingType, X509_NAME, &info,
946 0, NULL, pbEncoded, pcbEncoded);
948 for (i = 0; i < info.cRDN; i++)
952 for (j = 0; j < info.rgRDN[i].cRDNAttr; j++)
953 LocalFree(info.rgRDN[i].rgRDNAttr[j].Value.pbData);
954 CryptMemFree(info.rgRDN[i].rgRDNAttr);
956 CryptMemFree(info.rgRDN);
960 DWORD WINAPI CertGetNameStringA(PCCERT_CONTEXT pCertContext, DWORD dwType,
961 DWORD dwFlags, void *pvTypePara, LPSTR pszNameString, DWORD cchNameString)
965 TRACE("(%p, %d, %08x, %p, %p, %d)\n", pCertContext, dwType, dwFlags,
966 pvTypePara, pszNameString, cchNameString);
973 nameLen = CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
975 wideName = CryptMemAlloc(nameLen * sizeof(WCHAR));
978 CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
980 nameLen = WideCharToMultiByte(CP_ACP, 0, wideName, nameLen,
981 pszNameString, cchNameString, NULL, NULL);
982 if (nameLen <= cchNameString)
986 pszNameString[cchNameString - 1] = '\0';
989 CryptMemFree(wideName);
993 *pszNameString = '\0';
998 ret = CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
1003 /* Searches cert's extensions for the alternate name extension with OID
1004 * altNameOID, and if found, searches it for the alternate name type entryType.
1005 * If found, returns a pointer to the entry, otherwise returns NULL.
1006 * Regardless of whether an entry of the desired type is found, if the
1007 * alternate name extension is present, sets *info to the decoded alternate
1008 * name extension, which you must free using LocalFree.
1009 * The return value is a pointer within *info, so don't free *info before
1010 * you're done with the return value.
1012 static PCERT_ALT_NAME_ENTRY cert_find_alt_name_entry(PCCERT_CONTEXT cert,
1013 LPCSTR altNameOID, DWORD entryType, PCERT_ALT_NAME_INFO *info)
1015 PCERT_ALT_NAME_ENTRY entry = NULL;
1016 PCERT_EXTENSION ext = CertFindExtension(altNameOID,
1017 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
1023 if (CryptDecodeObjectEx(cert->dwCertEncodingType, X509_ALTERNATE_NAME,
1024 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
1029 for (i = 0; !entry && i < (*info)->cAltEntry; i++)
1030 if ((*info)->rgAltEntry[i].dwAltNameChoice == entryType)
1031 entry = &(*info)->rgAltEntry[i];
1039 static DWORD cert_get_name_from_rdn_attr(DWORD encodingType,
1040 const CERT_NAME_BLOB *name, LPCSTR oid, LPWSTR pszNameString, DWORD cchNameString)
1042 CERT_NAME_INFO *nameInfo;
1043 DWORD bytes = 0, ret = 0;
1045 if (CryptDecodeObjectEx(encodingType, X509_NAME, name->pbData,
1046 name->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &nameInfo, &bytes))
1048 PCERT_RDN_ATTR nameAttr = CertFindRDNAttr(oid, nameInfo);
1051 ret = CertRDNValueToStrW(nameAttr->dwValueType, &nameAttr->Value,
1052 pszNameString, cchNameString);
1053 LocalFree(nameInfo);
1058 DWORD WINAPI CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType,
1059 DWORD dwFlags, void *pvTypePara, LPWSTR pszNameString, DWORD cchNameString)
1062 PCERT_NAME_BLOB name;
1065 TRACE("(%p, %d, %08x, %p, %p, %d)\n", pCertContext, dwType,
1066 dwFlags, pvTypePara, pszNameString, cchNameString);
1068 if (dwFlags & CERT_NAME_ISSUER_FLAG)
1070 name = &pCertContext->pCertInfo->Issuer;
1071 altNameOID = szOID_ISSUER_ALT_NAME;
1075 name = &pCertContext->pCertInfo->Subject;
1076 altNameOID = szOID_SUBJECT_ALT_NAME;
1081 case CERT_NAME_EMAIL_TYPE:
1083 CERT_ALT_NAME_INFO *info;
1084 PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1085 altNameOID, CERT_ALT_NAME_RFC822_NAME, &info);
1090 ret = strlenW(entry->u.pwszRfc822Name) + 1;
1091 else if (cchNameString)
1093 ret = min(strlenW(entry->u.pwszRfc822Name), cchNameString - 1);
1094 memcpy(pszNameString, entry->u.pwszRfc822Name,
1095 ret * sizeof(WCHAR));
1096 pszNameString[ret++] = 0;
1102 ret = cert_get_name_from_rdn_attr(pCertContext->dwCertEncodingType,
1103 name, szOID_RSA_emailAddr, pszNameString, cchNameString);
1106 case CERT_NAME_RDN_TYPE:
1108 ret = CertNameToStrW(pCertContext->dwCertEncodingType, name,
1109 *(DWORD *)pvTypePara, pszNameString, cchNameString);
1112 CERT_ALT_NAME_INFO *info;
1113 PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1114 altNameOID, CERT_ALT_NAME_DIRECTORY_NAME, &info);
1117 ret = CertNameToStrW(pCertContext->dwCertEncodingType,
1118 &entry->u.DirectoryName, *(DWORD *)pvTypePara, pszNameString,
1124 case CERT_NAME_ATTR_TYPE:
1125 ret = cert_get_name_from_rdn_attr(pCertContext->dwCertEncodingType,
1126 name, pvTypePara, pszNameString, cchNameString);
1129 CERT_ALT_NAME_INFO *altInfo;
1130 PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1131 altNameOID, CERT_ALT_NAME_DIRECTORY_NAME, &altInfo);
1134 ret = cert_name_to_str_with_indent(X509_ASN_ENCODING, 0,
1135 &entry->u.DirectoryName, 0, pszNameString, cchNameString);
1140 case CERT_NAME_SIMPLE_DISPLAY_TYPE:
1142 static const LPCSTR simpleAttributeOIDs[] = { szOID_COMMON_NAME,
1143 szOID_ORGANIZATIONAL_UNIT_NAME, szOID_ORGANIZATION_NAME,
1144 szOID_RSA_emailAddr };
1145 CERT_NAME_INFO *nameInfo = NULL;
1148 if (CryptDecodeObjectEx(pCertContext->dwCertEncodingType, X509_NAME,
1149 name->pbData, name->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &nameInfo,
1152 PCERT_RDN_ATTR nameAttr = NULL;
1154 for (i = 0; !nameAttr && i < sizeof(simpleAttributeOIDs) /
1155 sizeof(simpleAttributeOIDs[0]); i++)
1156 nameAttr = CertFindRDNAttr(simpleAttributeOIDs[i], nameInfo);
1158 ret = CertRDNValueToStrW(nameAttr->dwValueType,
1159 &nameAttr->Value, pszNameString, cchNameString);
1160 LocalFree(nameInfo);
1164 CERT_ALT_NAME_INFO *altInfo;
1165 PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1166 altNameOID, CERT_ALT_NAME_RFC822_NAME, &altInfo);
1170 if (!entry && altInfo->cAltEntry)
1171 entry = &altInfo->rgAltEntry[0];
1175 ret = strlenW(entry->u.pwszRfc822Name) + 1;
1176 else if (cchNameString)
1178 ret = min(strlenW(entry->u.pwszRfc822Name),
1180 memcpy(pszNameString, entry->u.pwszRfc822Name,
1181 ret * sizeof(WCHAR));
1182 pszNameString[ret++] = 0;
1190 case CERT_NAME_FRIENDLY_DISPLAY_TYPE:
1192 DWORD cch = cchNameString;
1194 if (CertGetCertificateContextProperty(pCertContext,
1195 CERT_FRIENDLY_NAME_PROP_ID, pszNameString, &cch))
1198 ret = CertGetNameStringW(pCertContext,
1199 CERT_NAME_SIMPLE_DISPLAY_TYPE, dwFlags, pvTypePara, pszNameString,
1203 case CERT_NAME_DNS_TYPE:
1205 CERT_ALT_NAME_INFO *info;
1206 PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1207 altNameOID, CERT_ALT_NAME_DNS_NAME, &info);
1212 ret = strlenW(entry->u.pwszDNSName) + 1;
1213 else if (cchNameString)
1215 ret = min(strlenW(entry->u.pwszDNSName), cchNameString - 1);
1216 memcpy(pszNameString, entry->u.pwszDNSName, ret * sizeof(WCHAR));
1217 pszNameString[ret++] = 0;
1223 ret = cert_get_name_from_rdn_attr(pCertContext->dwCertEncodingType,
1224 name, szOID_COMMON_NAME, pszNameString, cchNameString);
1227 case CERT_NAME_URL_TYPE:
1229 CERT_ALT_NAME_INFO *info;
1230 PCERT_ALT_NAME_ENTRY entry = cert_find_alt_name_entry(pCertContext,
1231 altNameOID, CERT_ALT_NAME_URL, &info);
1236 ret = strlenW(entry->u.pwszURL) + 1;
1237 else if (cchNameString)
1239 ret = min(strlenW(entry->u.pwszURL), cchNameString - 1);
1240 memcpy(pszNameString, entry->u.pwszURL, ret * sizeof(WCHAR));
1241 pszNameString[ret++] = 0;
1249 FIXME("unimplemented for type %d\n", dwType);
1256 else if (cchNameString)
1258 pszNameString[0] = 0;