winmm/tests: Add tests for visibility of video window.
[wine.git] / dlls / crypt32 / str.c
blobd74df308e4a2e87e295ab8840cf50b6eb4b5f1ed
1 /*
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
18 #include <stdarg.h>
20 #define NONAMELESSUNION
22 #include "windef.h"
23 #include "winbase.h"
24 #include "winnls.h"
25 #include "winuser.h"
26 #include "wincrypt.h"
27 #include "wine/debug.h"
28 #include "crypt32_private.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
32 DWORD WINAPI CertRDNValueToStrA(DWORD type, PCERT_RDN_VALUE_BLOB value_blob,
33 LPSTR value, DWORD value_len)
35 DWORD len, len_mb, ret;
36 LPWSTR valueW;
38 TRACE("(%ld, %p, %p, %ld)\n", type, value_blob, value, value_len);
40 len = CertRDNValueToStrW(type, value_blob, NULL, 0);
42 if (!(valueW = CryptMemAlloc(len * sizeof(*valueW))))
44 ERR("No memory.\n");
45 if (value && value_len) *value = 0;
46 return 1;
49 len = CertRDNValueToStrW(type, value_blob, valueW, len);
50 len_mb = WideCharToMultiByte(CP_ACP, 0, valueW, len, NULL, 0, NULL, NULL);
51 if (!value || !value_len)
53 CryptMemFree(valueW);
54 return len_mb;
57 ret = WideCharToMultiByte(CP_ACP, 0, valueW, len, value, value_len, NULL, NULL);
58 if (ret < len_mb)
60 value[0] = 0;
61 ret = 1;
63 CryptMemFree(valueW);
64 return ret;
67 static DWORD rdn_value_to_strW(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
68 LPWSTR psz, DWORD csz, BOOL partial_copy)
70 DWORD ret = 0, len, i;
72 TRACE("(%ld, %p, %p, %ld)\n", dwValueType, pValue, psz, csz);
74 switch (dwValueType)
76 case CERT_RDN_ANY_TYPE:
77 break;
78 case CERT_RDN_NUMERIC_STRING:
79 case CERT_RDN_PRINTABLE_STRING:
80 case CERT_RDN_TELETEX_STRING:
81 case CERT_RDN_VIDEOTEX_STRING:
82 case CERT_RDN_IA5_STRING:
83 case CERT_RDN_GRAPHIC_STRING:
84 case CERT_RDN_VISIBLE_STRING:
85 case CERT_RDN_GENERAL_STRING:
86 len = pValue->cbData;
87 if (!psz || !csz) ret = len;
88 else if (len < csz || partial_copy)
90 len = min(len, csz - 1);
91 for (i = 0; i < len; ++i)
92 psz[i] = pValue->pbData[i];
93 ret = len;
95 break;
96 case CERT_RDN_BMP_STRING:
97 case CERT_RDN_UTF8_STRING:
98 len = pValue->cbData / sizeof(WCHAR);
99 if (!psz || !csz)
100 ret = len;
101 else if (len < csz || partial_copy)
103 WCHAR *ptr = psz;
105 len = min(len, csz - 1);
106 for (i = 0; i < len; ++i)
107 ptr[i] = ((LPCWSTR)pValue->pbData)[i];
108 ret = len;
110 break;
111 default:
112 FIXME("string type %ld unimplemented\n", dwValueType);
114 if (psz && csz) psz[ret] = 0;
115 TRACE("returning %ld (%s)\n", ret + 1, debugstr_w(psz));
116 return ret + 1;
119 DWORD WINAPI CertRDNValueToStrW(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
120 LPWSTR psz, DWORD csz)
122 return rdn_value_to_strW(dwValueType, pValue, psz, csz, FALSE);
125 static inline BOOL is_quotable_char(WCHAR c)
127 switch(c)
129 case '+':
130 case ',':
131 case '"':
132 case '=':
133 case '<':
134 case '>':
135 case ';':
136 case '#':
137 case '\n':
138 return TRUE;
139 default:
140 return FALSE;
144 static DWORD quote_rdn_value_to_str_w(DWORD dwValueType,
145 PCERT_RDN_VALUE_BLOB pValue, LPWSTR psz, DWORD csz)
147 DWORD ret = 0, len, i, strLen;
148 BOOL needsQuotes = FALSE;
150 TRACE("(%ld, %p, %p, %ld)\n", dwValueType, pValue, psz, csz);
152 switch (dwValueType)
154 case CERT_RDN_ANY_TYPE:
155 break;
156 case CERT_RDN_NUMERIC_STRING:
157 case CERT_RDN_PRINTABLE_STRING:
158 case CERT_RDN_TELETEX_STRING:
159 case CERT_RDN_VIDEOTEX_STRING:
160 case CERT_RDN_IA5_STRING:
161 case CERT_RDN_GRAPHIC_STRING:
162 case CERT_RDN_VISIBLE_STRING:
163 case CERT_RDN_GENERAL_STRING:
164 len = pValue->cbData;
165 if (pValue->cbData && isspace(pValue->pbData[0]))
166 needsQuotes = TRUE;
167 if (pValue->cbData && isspace(pValue->pbData[pValue->cbData - 1]))
168 needsQuotes = TRUE;
169 for (i = 0; i < pValue->cbData; i++)
171 if (is_quotable_char(pValue->pbData[i]))
172 needsQuotes = TRUE;
173 if (pValue->pbData[i] == '"')
174 len += 1;
176 if (needsQuotes)
177 len += 2;
178 if (!psz || !csz)
179 ret = len;
180 else
182 WCHAR *ptr = psz;
184 if (needsQuotes)
185 *ptr++ = '"';
186 for (i = 0; i < pValue->cbData && ptr - psz < csz; ptr++, i++)
188 *ptr = pValue->pbData[i];
189 if (pValue->pbData[i] == '"' && ptr - psz < csz - 1)
190 *(++ptr) = '"';
192 if (needsQuotes && ptr - psz < csz)
193 *ptr++ = '"';
194 ret = ptr - psz;
196 break;
197 case CERT_RDN_BMP_STRING:
198 case CERT_RDN_UTF8_STRING:
199 strLen = len = pValue->cbData / sizeof(WCHAR);
200 if (pValue->cbData && isspace(pValue->pbData[0]))
201 needsQuotes = TRUE;
202 if (pValue->cbData && isspace(pValue->pbData[strLen - 1]))
203 needsQuotes = TRUE;
204 for (i = 0; i < strLen; i++)
206 if (is_quotable_char(((LPCWSTR)pValue->pbData)[i]))
207 needsQuotes = TRUE;
208 if (((LPCWSTR)pValue->pbData)[i] == '"')
209 len += 1;
211 if (needsQuotes)
212 len += 2;
213 if (!psz || !csz)
214 ret = len;
215 else
217 WCHAR *ptr = psz;
219 if (needsQuotes)
220 *ptr++ = '"';
221 for (i = 0; i < strLen && ptr - psz < csz; ptr++, i++)
223 *ptr = ((LPCWSTR)pValue->pbData)[i];
224 if (((LPCWSTR)pValue->pbData)[i] == '"' && ptr - psz < csz - 1)
225 *(++ptr) = '"';
227 if (needsQuotes && ptr - psz < csz)
228 *ptr++ = '"';
229 ret = ptr - psz;
231 break;
232 default:
233 FIXME("string type %ld unimplemented\n", dwValueType);
235 TRACE("returning %ld (%s)\n", ret, debugstr_w(psz));
236 return ret;
239 DWORD WINAPI CertNameToStrA(DWORD encoding_type, PCERT_NAME_BLOB name_blob, DWORD str_type, LPSTR str, DWORD str_len)
241 DWORD len, len_mb, ret;
242 LPWSTR strW;
244 TRACE("(%ld, %p, %08lx, %p, %ld)\n", encoding_type, name_blob, str_type, str, str_len);
246 len = CertNameToStrW(encoding_type, name_blob, str_type, NULL, 0);
248 if (!(strW = CryptMemAlloc(len * sizeof(*strW))))
250 ERR("No memory.\n");
251 if (str && str_len) *str = 0;
252 return 1;
255 len = CertNameToStrW(encoding_type, name_blob, str_type, strW, len);
256 len_mb = WideCharToMultiByte(CP_ACP, 0, strW, len, NULL, 0, NULL, NULL);
257 if (!str || !str_len)
259 CryptMemFree(strW);
260 return len_mb;
263 ret = WideCharToMultiByte(CP_ACP, 0, strW, len, str, str_len, NULL, NULL);
264 if (ret < len_mb)
266 str[0] = 0;
267 ret = 1;
269 CryptMemFree(strW);
270 return ret;
273 /* Adds the prefix prefix to the wide-character string pointed to by psz,
274 * followed by the character '='. Copies no more than csz characters. Returns
275 * the number of characters copied. If psz is NULL, returns the number of
276 * characters that would be copied.
277 * Assumes the characters in prefix are ASCII (not multibyte characters.)
279 static DWORD CRYPT_AddPrefixAToW(LPCSTR prefix, LPWSTR psz, DWORD csz)
281 DWORD chars;
283 TRACE("(%s, %p, %ld)\n", debugstr_a(prefix), psz, csz);
285 if (psz)
287 DWORD i;
289 chars = min(strlen(prefix), csz);
290 for (i = 0; i < chars; i++)
291 *(psz + i) = prefix[i];
292 *(psz + chars) = '=';
293 chars++;
295 else
296 chars = lstrlenA(prefix) + 1;
297 return chars;
300 /* Adds the prefix prefix to the string pointed to by psz, followed by the
301 * character '='. Copies no more than csz characters. Returns the number of
302 * characters copied. If psz is NULL, returns the number of characters that
303 * would be copied.
305 static DWORD CRYPT_AddPrefixW(LPCWSTR prefix, LPWSTR psz, DWORD csz)
307 DWORD chars;
309 TRACE("(%s, %p, %ld)\n", debugstr_w(prefix), psz, csz);
311 if (psz)
313 chars = min(lstrlenW(prefix), csz);
314 memcpy(psz, prefix, chars * sizeof(WCHAR));
315 *(psz + chars) = '=';
316 chars++;
318 else
319 chars = lstrlenW(prefix) + 1;
320 return chars;
323 static const WCHAR indent[] = L" ";
325 DWORD cert_name_to_str_with_indent(DWORD dwCertEncodingType, DWORD indentLevel,
326 const CERT_NAME_BLOB *pName, DWORD dwStrType, LPWSTR psz, DWORD csz)
328 static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG |
329 CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG;
330 DWORD ret = 0, bytes = 0;
331 BOOL bRet;
332 CERT_NAME_INFO *info;
333 DWORD chars;
335 if (dwStrType & unsupportedFlags)
336 FIXME("unsupported flags: %08lx\n", dwStrType & unsupportedFlags);
338 bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData,
339 pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes);
340 if (bRet)
342 DWORD i, j, sepLen, rdnSepLen;
343 LPCWSTR sep, rdnSep;
344 BOOL reverse = dwStrType & CERT_NAME_STR_REVERSE_FLAG;
345 const CERT_RDN *rdn = info->rgRDN;
347 if(reverse && info->cRDN > 1) rdn += (info->cRDN - 1);
349 if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
350 sep = L"; ";
351 else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
352 sep = L"\r\n";
353 else
354 sep = L", ";
355 sepLen = lstrlenW(sep);
356 if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
357 rdnSep = L" ";
358 else
359 rdnSep = L" + ";
360 rdnSepLen = lstrlenW(rdnSep);
361 if (!csz) psz = NULL;
362 for (i = 0; i < info->cRDN; i++)
364 if (psz && ret + 1 == csz) break;
365 for (j = 0; j < rdn->cRDNAttr; j++)
367 LPCSTR prefixA = NULL;
368 LPCWSTR prefixW = NULL;
370 if (psz && ret + 1 == csz) break;
372 if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR)
373 prefixA = rdn->rgRDNAttr[j].pszObjId;
374 else if ((dwStrType & 0x000000ff) == CERT_X500_NAME_STR)
376 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(
377 CRYPT_OID_INFO_OID_KEY,
378 rdn->rgRDNAttr[j].pszObjId,
379 CRYPT_RDN_ATTR_OID_GROUP_ID);
381 if (oidInfo)
382 prefixW = oidInfo->pwszName;
383 else
384 prefixA = rdn->rgRDNAttr[j].pszObjId;
386 if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
388 DWORD k;
390 for (k = 0; k < indentLevel; k++)
392 if (psz)
394 chars = min(lstrlenW(indent), csz - ret - 1);
395 memcpy(psz + ret, indent, chars * sizeof(WCHAR));
397 else
398 chars = lstrlenW(indent);
399 ret += chars;
401 if (psz && ret + 1 == csz) break;
403 if (prefixW)
405 /* - 1 is needed to account for the NULL terminator. */
406 chars = CRYPT_AddPrefixW(prefixW,
407 psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
408 ret += chars;
410 else if (prefixA)
412 /* - 1 is needed to account for the NULL terminator. */
413 chars = CRYPT_AddPrefixAToW(prefixA,
414 psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
415 ret += chars;
417 if (psz && ret + 1 == csz) break;
419 chars = quote_rdn_value_to_str_w(rdn->rgRDNAttr[j].dwValueType, &rdn->rgRDNAttr[j].Value,
420 psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
421 ret += chars;
422 if (j < rdn->cRDNAttr - 1)
424 if (psz)
426 chars = min(rdnSepLen, csz - ret - 1);
427 memcpy(psz + ret, rdnSep, chars * sizeof(WCHAR));
428 ret += chars;
430 else ret += rdnSepLen;
433 if (psz && ret + 1 == csz) break;
434 if (i < info->cRDN - 1)
436 if (psz)
438 chars = min(sepLen, csz - ret - 1);
439 memcpy(psz + ret, sep, chars * sizeof(WCHAR));
440 ret += chars;
442 else ret += sepLen;
444 if(reverse) rdn--;
445 else rdn++;
447 LocalFree(info);
449 if (psz && csz) psz[ret] = 0;
450 return ret + 1;
453 DWORD WINAPI CertNameToStrW(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
454 DWORD dwStrType, LPWSTR psz, DWORD csz)
456 BOOL ret;
458 TRACE("(%ld, %p, %08lx, %p, %ld)\n", dwCertEncodingType, pName, dwStrType,
459 psz, csz);
461 ret = cert_name_to_str_with_indent(dwCertEncodingType, 0, pName, dwStrType,
462 psz, csz);
463 TRACE("Returning %s\n", debugstr_w(psz));
464 return ret;
467 BOOL WINAPI CertStrToNameA(DWORD dwCertEncodingType, LPCSTR pszX500,
468 DWORD dwStrType, void *pvReserved, BYTE *pbEncoded, DWORD *pcbEncoded,
469 LPCSTR *ppszError)
471 BOOL ret;
472 int len;
474 TRACE("(%08lx, %s, %08lx, %p, %p, %p, %p)\n", dwCertEncodingType,
475 debugstr_a(pszX500), dwStrType, pvReserved, pbEncoded, pcbEncoded,
476 ppszError);
478 len = MultiByteToWideChar(CP_ACP, 0, pszX500, -1, NULL, 0);
479 if (len)
481 LPWSTR x500, errorStr;
483 if ((x500 = CryptMemAlloc(len * sizeof(WCHAR))))
485 MultiByteToWideChar(CP_ACP, 0, pszX500, -1, x500, len);
486 ret = CertStrToNameW(dwCertEncodingType, x500, dwStrType,
487 pvReserved, pbEncoded, pcbEncoded,
488 ppszError ? (LPCWSTR *)&errorStr : NULL);
489 if (ppszError)
491 if (!ret)
493 LONG i;
495 *ppszError = pszX500;
496 for (i = 0; i < errorStr - x500; i++)
497 *ppszError = CharNextA(*ppszError);
499 else
500 *ppszError = NULL;
502 CryptMemFree(x500);
504 else
506 SetLastError(ERROR_OUTOFMEMORY);
507 ret = FALSE;
510 else
512 SetLastError(CRYPT_E_INVALID_X500_STRING);
513 if (ppszError)
514 *ppszError = pszX500;
515 ret = FALSE;
517 return ret;
520 struct KeynameKeeper
522 WCHAR buf[10]; /* big enough for L"GivenName" */
523 LPWSTR keyName; /* usually = buf, but may be allocated */
524 DWORD keyLen; /* full available buffer size in WCHARs */
527 static void CRYPT_InitializeKeynameKeeper(struct KeynameKeeper *keeper)
529 keeper->keyName = keeper->buf;
530 keeper->keyLen = ARRAY_SIZE(keeper->buf);
533 static void CRYPT_FreeKeynameKeeper(struct KeynameKeeper *keeper)
535 if (keeper->keyName != keeper->buf)
536 CryptMemFree(keeper->keyName);
539 struct X500TokenW
541 LPCWSTR start;
542 LPCWSTR end;
545 static void CRYPT_KeynameKeeperFromTokenW(struct KeynameKeeper *keeper,
546 const struct X500TokenW *key)
548 DWORD len = key->end - key->start;
550 if (len >= keeper->keyLen)
552 CRYPT_FreeKeynameKeeper( keeper );
553 keeper->keyLen = len + 1;
554 keeper->keyName = CryptMemAlloc(keeper->keyLen * sizeof(WCHAR));
556 memcpy(keeper->keyName, key->start, len * sizeof(WCHAR));
557 keeper->keyName[len] = '\0';
558 TRACE("Keyname is %s\n", debugstr_w(keeper->keyName));
561 static BOOL CRYPT_GetNextKeyW(LPCWSTR str, struct X500TokenW *token,
562 LPCWSTR *ppszError)
564 BOOL ret = TRUE;
566 while (*str && iswspace(*str))
567 str++;
568 if (*str)
570 token->start = str;
571 while (*str && *str != '=' && !iswspace(*str))
572 str++;
573 if (*str && (*str == '=' || iswspace(*str)))
574 token->end = str;
575 else
577 TRACE("missing equals char at %s\n", debugstr_w(token->start));
578 if (ppszError)
579 *ppszError = token->start;
580 SetLastError(CRYPT_E_INVALID_X500_STRING);
581 ret = FALSE;
584 else
585 token->start = NULL;
586 return ret;
589 /* Assumes separators are characters in the 0-255 range */
590 static BOOL CRYPT_GetNextValueW(LPCWSTR str, DWORD dwFlags, LPCWSTR separators,
591 WCHAR *separator_used, struct X500TokenW *token, LPCWSTR *ppszError)
593 BOOL ret = TRUE;
595 TRACE("(%s, %s, %p, %p)\n", debugstr_w(str), debugstr_w(separators), token,
596 ppszError);
598 *separator_used = 0;
599 while (*str && iswspace(*str))
600 str++;
601 if (*str)
603 token->start = str;
604 if (!(dwFlags & CERT_NAME_STR_NO_QUOTING_FLAG) && *str == '"')
606 token->end = NULL;
607 str++;
608 while (!token->end && ret)
610 while (*str && *str != '"')
611 str++;
612 if (*str == '"')
614 if (*(str + 1) != '"')
615 token->end = str + 1;
616 else
617 str += 2;
619 else
621 TRACE("unterminated quote at %s\n", debugstr_w(str));
622 if (ppszError)
623 *ppszError = str;
624 SetLastError(CRYPT_E_INVALID_X500_STRING);
625 ret = FALSE;
629 else
631 WCHAR map[256] = { 0 };
633 while (*separators)
634 map[*separators++] = 1;
635 while (*str && (*str >= 0xff || !map[*str]))
636 str++;
637 token->end = str;
638 if (map[*str]) *separator_used = *str;
641 else
643 TRACE("missing value at %s\n", debugstr_w(str));
644 if (ppszError)
645 *ppszError = str;
646 SetLastError(CRYPT_E_INVALID_X500_STRING);
647 ret = FALSE;
649 return ret;
652 /* Encodes the string represented by value as the string type type into the
653 * CERT_NAME_BLOB output. If there is an error and ppszError is not NULL,
654 * *ppszError is set to the first failing character. If there is no error,
655 * output's pbData must be freed with LocalFree.
657 static BOOL CRYPT_EncodeValueWithType(DWORD dwCertEncodingType,
658 const struct X500TokenW *value, PCERT_NAME_BLOB output, DWORD type,
659 LPCWSTR *ppszError)
661 CERT_NAME_VALUE nameValue = { type, { 0, NULL } };
662 BOOL ret = TRUE;
664 if (value->end > value->start)
666 LONG i;
667 LPWSTR ptr;
669 nameValue.Value.pbData = CryptMemAlloc((value->end - value->start + 1) *
670 sizeof(WCHAR));
671 if (!nameValue.Value.pbData)
673 SetLastError(ERROR_OUTOFMEMORY);
674 return FALSE;
676 ptr = (LPWSTR)nameValue.Value.pbData;
677 for (i = 0; i < value->end - value->start; i++)
679 *ptr++ = value->start[i];
680 if (value->start[i] == '"')
681 i++;
683 /* The string is NULL terminated because of a quirk in encoding
684 * unicode names values: if the length is given as 0, the value is
685 * assumed to be a NULL-terminated string.
687 *ptr = 0;
688 nameValue.Value.cbData = (LPBYTE)ptr - nameValue.Value.pbData;
690 ret = CryptEncodeObjectEx(dwCertEncodingType, X509_UNICODE_NAME_VALUE,
691 &nameValue, CRYPT_ENCODE_ALLOC_FLAG, NULL, &output->pbData,
692 &output->cbData);
693 if (!ret && ppszError)
695 if (type == CERT_RDN_NUMERIC_STRING &&
696 GetLastError() == CRYPT_E_INVALID_NUMERIC_STRING)
697 *ppszError = value->start + output->cbData;
698 else if (type == CERT_RDN_PRINTABLE_STRING &&
699 GetLastError() == CRYPT_E_INVALID_PRINTABLE_STRING)
700 *ppszError = value->start + output->cbData;
701 else if (type == CERT_RDN_IA5_STRING &&
702 GetLastError() == CRYPT_E_INVALID_IA5_STRING)
703 *ppszError = value->start + output->cbData;
705 CryptMemFree(nameValue.Value.pbData);
706 return ret;
709 static BOOL CRYPT_EncodeValue(DWORD dwCertEncodingType,
710 const struct X500TokenW *value, PCERT_NAME_BLOB output, const DWORD *types,
711 LPCWSTR *ppszError)
713 DWORD i;
714 BOOL ret;
716 ret = FALSE;
717 for (i = 0; !ret && types[i]; i++)
718 ret = CRYPT_EncodeValueWithType(dwCertEncodingType, value, output,
719 types[i], ppszError);
720 return ret;
723 static BOOL CRYPT_ValueToRDN(DWORD dwCertEncodingType, PCERT_NAME_INFO info,
724 PCCRYPT_OID_INFO keyOID, struct X500TokenW *value, DWORD dwStrType, LPCWSTR *ppszError)
726 BOOL ret = FALSE;
728 TRACE("OID %s, value %s\n", debugstr_a(keyOID->pszOID),
729 debugstr_wn(value->start, value->end - value->start));
731 if (!info->rgRDN)
732 info->rgRDN = CryptMemAlloc(sizeof(CERT_RDN));
733 else
734 info->rgRDN = CryptMemRealloc(info->rgRDN,
735 (info->cRDN + 1) * sizeof(CERT_RDN));
736 if (info->rgRDN)
738 /* FIXME: support multiple RDN attrs */
739 info->rgRDN[info->cRDN].rgRDNAttr =
740 CryptMemAlloc(sizeof(CERT_RDN_ATTR));
741 if (info->rgRDN[info->cRDN].rgRDNAttr)
743 static const DWORD defaultTypes[] = { CERT_RDN_PRINTABLE_STRING,
744 CERT_RDN_BMP_STRING, 0 };
745 const DWORD *types;
747 info->rgRDN[info->cRDN].cRDNAttr = 1;
748 info->rgRDN[info->cRDN].rgRDNAttr[0].pszObjId =
749 (LPSTR)keyOID->pszOID;
750 info->rgRDN[info->cRDN].rgRDNAttr[0].dwValueType =
751 CERT_RDN_ENCODED_BLOB;
752 if (keyOID->ExtraInfo.cbData)
753 types = (const DWORD *)keyOID->ExtraInfo.pbData;
754 else
755 types = defaultTypes;
757 /* Remove surrounding quotes */
758 if (value->start[0] == '"' && !(dwStrType & CERT_NAME_STR_NO_QUOTING_FLAG))
760 value->start++;
761 value->end--;
763 ret = CRYPT_EncodeValue(dwCertEncodingType, value,
764 &info->rgRDN[info->cRDN].rgRDNAttr[0].Value, types, ppszError);
766 else
767 SetLastError(ERROR_OUTOFMEMORY);
768 info->cRDN++;
770 else
771 SetLastError(ERROR_OUTOFMEMORY);
772 return ret;
775 BOOL WINAPI CertStrToNameW(DWORD dwCertEncodingType, LPCWSTR pszX500,
776 DWORD dwStrType, void *pvReserved, BYTE *pbEncoded, DWORD *pcbEncoded,
777 LPCWSTR *ppszError)
779 CERT_NAME_INFO info = { 0, NULL };
780 LPCWSTR str;
781 struct KeynameKeeper keeper;
782 DWORD i;
783 BOOL ret = TRUE;
785 TRACE("(%08lx, %s, %08lx, %p, %p, %p, %p)\n", dwCertEncodingType,
786 debugstr_w(pszX500), dwStrType, pvReserved, pbEncoded, pcbEncoded,
787 ppszError);
789 CRYPT_InitializeKeynameKeeper(&keeper);
790 str = pszX500;
791 while (str && *str && ret)
793 struct X500TokenW token;
795 ret = CRYPT_GetNextKeyW(str, &token, ppszError);
796 if (ret && token.start)
798 PCCRYPT_OID_INFO keyOID;
800 CRYPT_KeynameKeeperFromTokenW(&keeper, &token);
801 keyOID = CryptFindOIDInfo(CRYPT_OID_INFO_NAME_KEY, keeper.keyName,
802 CRYPT_RDN_ATTR_OID_GROUP_ID);
803 if (!keyOID)
805 if (ppszError)
806 *ppszError = token.start;
807 SetLastError(CRYPT_E_INVALID_X500_STRING);
808 ret = FALSE;
810 else
812 str = token.end;
813 while (iswspace(*str))
814 str++;
815 if (*str != '=')
817 if (ppszError)
818 *ppszError = str;
819 SetLastError(CRYPT_E_INVALID_X500_STRING);
820 ret = FALSE;
822 else
824 LPCWSTR sep;
825 WCHAR sep_used;
827 str++;
828 if (dwStrType & CERT_NAME_STR_COMMA_FLAG)
829 sep = L",";
830 else if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
831 sep = L";";
832 else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
833 sep = L"\r\n";
834 else if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
835 sep = L",;\r\n";
836 else
837 sep = L"+,;\r\n";
838 ret = CRYPT_GetNextValueW(str, dwStrType, sep, &sep_used, &token,
839 ppszError);
840 if (ret)
842 str = token.end;
843 /* if token.end points to the separator, skip it */
844 if (str && sep_used && *str == sep_used) str++;
846 ret = CRYPT_ValueToRDN(dwCertEncodingType, &info,
847 keyOID, &token, dwStrType, ppszError);
853 CRYPT_FreeKeynameKeeper(&keeper);
854 if (ret)
856 if (ppszError)
857 *ppszError = NULL;
858 ret = CryptEncodeObjectEx(dwCertEncodingType, X509_NAME, &info,
859 0, NULL, pbEncoded, pcbEncoded);
861 for (i = 0; i < info.cRDN; i++)
863 DWORD j;
865 for (j = 0; j < info.rgRDN[i].cRDNAttr; j++)
866 LocalFree(info.rgRDN[i].rgRDNAttr[j].Value.pbData);
867 CryptMemFree(info.rgRDN[i].rgRDNAttr);
869 CryptMemFree(info.rgRDN);
870 return ret;
873 DWORD WINAPI CertGetNameStringA(PCCERT_CONTEXT cert, DWORD type,
874 DWORD flags, void *type_para, LPSTR name, DWORD name_len)
876 DWORD len, len_mb, ret;
877 LPWSTR nameW;
879 TRACE("(%p, %ld, %08lx, %p, %p, %ld)\n", cert, type, flags, type_para, name, name_len);
881 len = CertGetNameStringW(cert, type, flags, type_para, NULL, 0);
883 if (!(nameW = CryptMemAlloc(len * sizeof(*nameW))))
885 ERR("No memory.\n");
886 if (name && name_len) *name = 0;
887 return 1;
890 len = CertGetNameStringW(cert, type, flags, type_para, nameW, len);
891 len_mb = WideCharToMultiByte(CP_ACP, 0, nameW, len, NULL, 0, NULL, NULL);
892 if (!name || !name_len)
894 CryptMemFree(nameW);
895 return len_mb;
898 ret = WideCharToMultiByte(CP_ACP, 0, nameW, len, name, name_len, NULL, NULL);
899 if (ret < len_mb)
901 name[0] = 0;
902 ret = 1;
904 CryptMemFree(nameW);
905 return ret;
908 static BOOL cert_get_alt_name_info(PCCERT_CONTEXT cert, BOOL alt_name_issuer, PCERT_ALT_NAME_INFO *info)
910 static const char *oids[][2] =
912 { szOID_SUBJECT_ALT_NAME2, szOID_SUBJECT_ALT_NAME },
913 { szOID_ISSUER_ALT_NAME2, szOID_ISSUER_ALT_NAME },
915 PCERT_EXTENSION ext;
916 DWORD bytes = 0;
918 ext = CertFindExtension(oids[!!alt_name_issuer][0], cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
919 if (!ext)
920 ext = CertFindExtension(oids[!!alt_name_issuer][1], cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
921 if (!ext) return FALSE;
923 return CryptDecodeObjectEx(cert->dwCertEncodingType, X509_ALTERNATE_NAME, ext->Value.pbData, ext->Value.cbData,
924 CRYPT_DECODE_ALLOC_FLAG, NULL, info, &bytes);
927 static PCERT_ALT_NAME_ENTRY cert_find_next_alt_name_entry(PCERT_ALT_NAME_INFO info, DWORD entry_type,
928 unsigned int *index)
930 unsigned int i;
932 for (i = *index; i < info->cAltEntry; ++i)
933 if (info->rgAltEntry[i].dwAltNameChoice == entry_type)
935 *index = i + 1;
936 return &info->rgAltEntry[i];
938 return NULL;
941 /* Searches cert's extensions for the alternate name extension with OID
942 * altNameOID, and if found, searches it for the alternate name type entryType.
943 * If found, returns a pointer to the entry, otherwise returns NULL.
944 * Regardless of whether an entry of the desired type is found, if the
945 * alternate name extension is present, sets *info to the decoded alternate
946 * name extension, which you must free using LocalFree.
947 * The return value is a pointer within *info, so don't free *info before
948 * you're done with the return value.
950 static PCERT_ALT_NAME_ENTRY cert_find_alt_name_entry(PCCERT_CONTEXT cert, BOOL alt_name_issuer,
951 DWORD entry_type, PCERT_ALT_NAME_INFO *info)
953 unsigned int index = 0;
955 if (!cert_get_alt_name_info(cert, alt_name_issuer, info)) return NULL;
956 return cert_find_next_alt_name_entry(*info, entry_type, &index);
959 static DWORD cert_get_name_from_rdn_attr(DWORD encodingType,
960 const CERT_NAME_BLOB *name, LPCSTR oid, LPWSTR pszNameString, DWORD cchNameString)
962 CERT_NAME_INFO *nameInfo;
963 DWORD bytes = 0, ret = 0;
965 if (CryptDecodeObjectEx(encodingType, X509_NAME, name->pbData,
966 name->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &nameInfo, &bytes))
968 PCERT_RDN_ATTR nameAttr;
970 if (!oid)
971 oid = szOID_RSA_emailAddr;
972 nameAttr = CertFindRDNAttr(oid, nameInfo);
973 if (nameAttr)
974 ret = rdn_value_to_strW(nameAttr->dwValueType, &nameAttr->Value,
975 pszNameString, cchNameString, TRUE);
976 LocalFree(nameInfo);
978 return ret;
981 static DWORD copy_output_str(WCHAR *dst, const WCHAR *src, DWORD dst_size)
983 DWORD len = wcslen(src);
985 if (!dst || !dst_size) return len + 1;
986 len = min(len, dst_size - 1);
987 memcpy(dst, src, len * sizeof(*dst));
988 dst[len] = 0;
989 return len + 1;
992 DWORD WINAPI CertGetNameStringW(PCCERT_CONTEXT cert, DWORD type, DWORD flags, void *type_para,
993 LPWSTR name_string, DWORD name_len)
995 static const DWORD supported_flags = CERT_NAME_ISSUER_FLAG | CERT_NAME_SEARCH_ALL_NAMES_FLAG;
996 BOOL alt_name_issuer, search_all_names;
997 CERT_ALT_NAME_INFO *info = NULL;
998 PCERT_ALT_NAME_ENTRY entry;
999 PCERT_NAME_BLOB name;
1000 DWORD ret = 0;
1002 TRACE("(%p, %ld, %08lx, %p, %p, %ld)\n", cert, type, flags, type_para, name_string, name_len);
1004 if (!cert)
1005 goto done;
1007 if (flags & ~supported_flags)
1008 FIXME("Unsupported flags %#lx.\n", flags);
1010 search_all_names = flags & CERT_NAME_SEARCH_ALL_NAMES_FLAG;
1011 if (search_all_names && type != CERT_NAME_DNS_TYPE)
1013 WARN("CERT_NAME_SEARCH_ALL_NAMES_FLAG used with type %lu.\n", type);
1014 goto done;
1017 alt_name_issuer = flags & CERT_NAME_ISSUER_FLAG;
1018 name = alt_name_issuer ? &cert->pCertInfo->Issuer : &cert->pCertInfo->Subject;
1020 switch (type)
1022 case CERT_NAME_EMAIL_TYPE:
1024 entry = cert_find_alt_name_entry(cert, alt_name_issuer, CERT_ALT_NAME_RFC822_NAME, &info);
1026 if (entry)
1028 ret = copy_output_str(name_string, entry->u.pwszRfc822Name, name_len);
1029 break;
1031 ret = cert_get_name_from_rdn_attr(cert->dwCertEncodingType, name, szOID_RSA_emailAddr,
1032 name_string, name_len);
1033 break;
1035 case CERT_NAME_RDN_TYPE:
1037 DWORD param = type_para ? *(DWORD *)type_para : 0;
1039 if (name->cbData)
1041 ret = CertNameToStrW(cert->dwCertEncodingType, name, param, name_string, name_len);
1043 else
1045 entry = cert_find_alt_name_entry(cert, alt_name_issuer, CERT_ALT_NAME_DIRECTORY_NAME, &info);
1047 if (entry)
1048 ret = CertNameToStrW(cert->dwCertEncodingType, &entry->u.DirectoryName,
1049 param, name_string, name_len);
1051 break;
1053 case CERT_NAME_ATTR_TYPE:
1054 ret = cert_get_name_from_rdn_attr(cert->dwCertEncodingType, name, type_para,
1055 name_string, name_len);
1056 if (ret) break;
1058 entry = cert_find_alt_name_entry(cert, alt_name_issuer, CERT_ALT_NAME_DIRECTORY_NAME, &info);
1060 if (entry)
1061 ret = cert_name_to_str_with_indent(X509_ASN_ENCODING, 0, &entry->u.DirectoryName,
1062 0, name_string, name_len);
1063 break;
1064 case CERT_NAME_SIMPLE_DISPLAY_TYPE:
1066 static const LPCSTR simpleAttributeOIDs[] =
1068 szOID_COMMON_NAME, szOID_ORGANIZATIONAL_UNIT_NAME, szOID_ORGANIZATION_NAME, szOID_RSA_emailAddr
1070 CERT_NAME_INFO *nameInfo = NULL;
1071 DWORD bytes = 0, i;
1073 if (CryptDecodeObjectEx(cert->dwCertEncodingType, X509_NAME, name->pbData, name->cbData,
1074 CRYPT_DECODE_ALLOC_FLAG, NULL, &nameInfo, &bytes))
1076 PCERT_RDN_ATTR nameAttr = NULL;
1078 for (i = 0; !nameAttr && i < ARRAY_SIZE(simpleAttributeOIDs); i++)
1079 nameAttr = CertFindRDNAttr(simpleAttributeOIDs[i], nameInfo);
1080 if (nameAttr)
1081 ret = rdn_value_to_strW(nameAttr->dwValueType, &nameAttr->Value, name_string, name_len, TRUE);
1082 LocalFree(nameInfo);
1084 if (ret) break;
1085 entry = cert_find_alt_name_entry(cert, alt_name_issuer, CERT_ALT_NAME_RFC822_NAME, &info);
1086 if (!info) break;
1087 if (!entry && info->cAltEntry)
1088 entry = &info->rgAltEntry[0];
1089 if (entry) ret = copy_output_str(name_string, entry->u.pwszRfc822Name, name_len);
1090 break;
1092 case CERT_NAME_FRIENDLY_DISPLAY_TYPE:
1094 DWORD len = name_len;
1096 if (CertGetCertificateContextProperty(cert, CERT_FRIENDLY_NAME_PROP_ID, name_string, &len))
1097 ret = len;
1098 else
1099 ret = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, flags,
1100 type_para, name_string, name_len);
1101 break;
1103 case CERT_NAME_DNS_TYPE:
1105 unsigned int index = 0, len;
1107 if (cert_get_alt_name_info(cert, alt_name_issuer, &info)
1108 && (entry = cert_find_next_alt_name_entry(info, CERT_ALT_NAME_DNS_NAME, &index)))
1110 if (search_all_names)
1114 if (name_string && name_len == 1) break;
1115 ret += len = copy_output_str(name_string, entry->u.pwszDNSName, name_len ? name_len - 1 : 0);
1116 if (name_string && name_len)
1118 name_string += len;
1119 name_len -= len;
1122 while ((entry = cert_find_next_alt_name_entry(info, CERT_ALT_NAME_DNS_NAME, &index)));
1124 else ret = copy_output_str(name_string, entry->u.pwszDNSName, name_len);
1126 else
1128 if (!search_all_names || name_len != 1)
1130 len = search_all_names && name_len ? name_len - 1 : name_len;
1131 ret = cert_get_name_from_rdn_attr(cert->dwCertEncodingType, name, szOID_COMMON_NAME,
1132 name_string, len);
1133 if (name_string) name_string += ret;
1137 if (search_all_names)
1139 if (name_string && name_len) *name_string = 0;
1140 ++ret;
1142 break;
1144 case CERT_NAME_URL_TYPE:
1146 if ((entry = cert_find_alt_name_entry(cert, alt_name_issuer, CERT_ALT_NAME_URL, &info)))
1147 ret = copy_output_str(name_string, entry->u.pwszURL, name_len);
1148 break;
1150 default:
1151 FIXME("unimplemented for type %lu.\n", type);
1152 ret = 0;
1153 break;
1155 done:
1156 if (info)
1157 LocalFree(info);
1159 if (!ret)
1161 ret = 1;
1162 if (name_string && name_len) name_string[0] = 0;
1164 return ret;