1 /*
2 * Copyright 2006 Juan Lang for CodeWeavers
3 *
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.
8 *
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.
13 *
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
17 */
18 #include <stdarg.h>
19 #include "windef.h"
20 #include "winbase.h"
21 #include "winnls.h"
22 #include "winuser.h"
23 #include "wincrypt.h"
24 #include "wine/debug.h"
25 #include "wine/unicode.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
28
29 DWORD WINAPI CertRDNValueToStrA(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
30 LPSTR psz, DWORD csz)
31 {
32 DWORD ret = 0;
33
34 TRACE("(%d, %p, %p, %d)\n", dwValueType, pValue, psz, csz);
35
36 switch (dwValueType)
37 {
38 case CERT_RDN_ANY_TYPE:
39 break;
40 case CERT_RDN_NUMERIC_STRING:
41 case CERT_RDN_PRINTABLE_STRING:
42 case CERT_RDN_TELETEX_STRING:
43 case CERT_RDN_VIDEOTEX_STRING:
44 case CERT_RDN_IA5_STRING:
45 case CERT_RDN_GRAPHIC_STRING:
46 case CERT_RDN_VISIBLE_STRING:
47 case CERT_RDN_GENERAL_STRING:
48 if (!psz || !csz)
49 ret = pValue->cbData;
50 else
51 {
52 DWORD chars = min(pValue->cbData, csz - 1);
53
54 if (chars)
55 {
56 memcpy(psz, pValue->pbData, chars);
57 ret += chars;
58 csz -= chars;
59 }
60 }
61 break;
62 case CERT_RDN_UTF8_STRING:
63 if (!psz || !csz)
64 ret = WideCharToMultiByte(CP_UTF8, 0, (LPWSTR)pValue->pbData,
65 pValue->cbData / sizeof(WCHAR) + 1, NULL, 0, NULL, NULL);
66 else
67 {
68 ret = WideCharToMultiByte(CP_UTF8, 0, (LPWSTR)pValue->pbData,
69 pValue->cbData / sizeof(WCHAR) + 1, psz, csz - 1, NULL, NULL);
70 csz -= ret;
71 }
72 break;
73 default:
74 FIXME("string type %d unimplemented\n", dwValueType);
75 }
76 if (psz && csz)
77 {
78 *(psz + ret) = '\0';
79 csz--;
80 ret++;
81 }
82 else
83 ret++;
84 TRACE("returning %d (%s)\n", ret, debugstr_a(psz));
85 return ret;
86 }
87
88 DWORD WINAPI CertRDNValueToStrW(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
89 LPWSTR psz, DWORD csz)
90 {
91 DWORD ret = 0;
92
93 TRACE("(%d, %p, %p, %d)\n", dwValueType, pValue, psz, csz);
94
95 switch (dwValueType)
96 {
97 case CERT_RDN_ANY_TYPE:
98 break;
99 case CERT_RDN_NUMERIC_STRING:
100 case CERT_RDN_PRINTABLE_STRING:
101 case CERT_RDN_TELETEX_STRING:
102 case CERT_RDN_VIDEOTEX_STRING:
103 case CERT_RDN_IA5_STRING:
104 case CERT_RDN_GRAPHIC_STRING:
105 case CERT_RDN_VISIBLE_STRING:
106 case CERT_RDN_GENERAL_STRING:
107 if (!psz || !csz)
108 ret = pValue->cbData;
109 else
110 {
111 DWORD chars = min(pValue->cbData, csz - 1);
112
113 if (chars)
114 {
115 DWORD i;
116
117 for (i = 0; i < chars; i++)
118 psz[i] = pValue->pbData[i];
119 ret += chars;
120 csz -= chars;
121 }
122 }
123 break;
124 case CERT_RDN_UTF8_STRING:
125 if (!psz || !csz)
126 ret = pValue->cbData / sizeof(WCHAR);
127 else
128 {
129 DWORD chars = min(pValue->cbData / sizeof(WCHAR), csz - 1);
130
131 if (chars)
132 {
133 DWORD i;
134
135 for (i = 0; i < chars; i++)
136 psz[i] = *((LPWSTR)pValue->pbData + i);
137 ret += chars;
138 csz -= chars;
139 }
140 }
141 break;
142 default:
143 FIXME("string type %d unimplemented\n", dwValueType);
144 }
145 if (psz && csz)
146 {
147 *(psz + ret) = '\0';
148 csz--;
149 ret++;
150 }
151 else
152 ret++;
153 TRACE("returning %d (%s)\n", ret, debugstr_w(psz));
154 return ret;
155 }
156
157 /* Adds the prefix prefix to the string pointed to by psz, followed by the
158 * character '='. Copies no more than csz characters. Returns the number of
159 * characters copied. If psz is NULL, returns the number of characters that
160 * would be copied.
161 */
162 static DWORD CRYPT_AddPrefixA(LPCSTR prefix, LPSTR psz, DWORD csz)
163 {
164 DWORD chars;
165
166 TRACE("(%s, %p, %d)\n", debugstr_a(prefix), psz, csz);
167
168 if (psz)
169 {
170 chars = min(lstrlenA(prefix), csz);
171 memcpy(psz, prefix, chars);
172 *(psz + chars) = '=';
173 chars++;
174 }
175 else
176 chars = lstrlenA(prefix) + 1;
177 return chars;
178 }
179
180 DWORD WINAPI CertNameToStrA(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
181 DWORD dwStrType, LPSTR psz, DWORD csz)
182 {
183 static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG |
184 CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG;
185 static const char commaSep[] = ", ";
186 static const char semiSep[] = "; ";
187 static const char crlfSep[] = "\r\n";
188 static const char plusSep[] = " + ";
189 static const char spaceSep[] = " ";
190 DWORD ret = 0, bytes = 0;
191 BOOL bRet;
192 CERT_NAME_INFO *info;
193
194 TRACE("(%d, %p, %08x, %p, %d)\n", dwCertEncodingType, pName, dwStrType,
195 psz, csz);
196 if (dwStrType & unsupportedFlags)
197 FIXME("unsupported flags: %08x\n", dwStrType & unsupportedFlags);
198
199 bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData,
200 pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes);
201 if (bRet)
202 {
203 DWORD i, j, sepLen, rdnSepLen;
204 LPCSTR sep, rdnSep;
205
206 if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
207 sep = semiSep;
208 else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
209 sep = crlfSep;
210 else
211 sep = commaSep;
212 sepLen = strlen(sep);
213 if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
214 rdnSep = spaceSep;
215 else
216 rdnSep = plusSep;
217 rdnSepLen = strlen(rdnSep);
218 for (i = 0; (!psz || ret < csz) && i < info->cRDN; i++)
219 {
220 for (j = 0; (!psz || ret < csz) && j < info->rgRDN[i].cRDNAttr; j++)
221 {
222 DWORD chars;
223 char prefixBuf[10]; /* big enough for GivenName */
224 LPCSTR prefix = NULL;
225
226 if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR)
227 prefix = info->rgRDN[i].rgRDNAttr[j].pszObjId;
228 else if ((dwStrType & 0x000000ff) == CERT_X500_NAME_STR)
229 {
230 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(
231 CRYPT_OID_INFO_OID_KEY,
232 info->rgRDN[i].rgRDNAttr[j].pszObjId,
233 CRYPT_RDN_ATTR_OID_GROUP_ID);
234
235 if (oidInfo)
236 {
237 WideCharToMultiByte(CP_ACP, 0, oidInfo->pwszName, -1,
238 prefixBuf, sizeof(prefixBuf), NULL, NULL);
239 prefix = prefixBuf;
240 }
241 else
242 prefix = info->rgRDN[i].rgRDNAttr[j].pszObjId;
243 }
244 if (prefix)
245 {
246 /* - 1 is needed to account for the NULL terminator. */
247 chars = CRYPT_AddPrefixA(prefix,
248 psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
249 ret += chars;
250 }
251 /* FIXME: handle quoting */
252 chars = CertRDNValueToStrA(
253 info->rgRDN[i].rgRDNAttr[j].dwValueType,
254 &info->rgRDN[i].rgRDNAttr[j].Value, psz ? psz + ret : NULL,
255 psz ? csz - ret : 0);
256 if (chars)
257 ret += chars - 1;
258 if (j < info->rgRDN[i].cRDNAttr - 1)
259 {
260 if (psz && ret < csz - rdnSepLen - 1)
261 memcpy(psz + ret, rdnSep, rdnSepLen);
262 ret += rdnSepLen;
263 }
264 }
265 if (i < info->cRDN - 1)
266 {
267 if (psz && ret < csz - sepLen - 1)
268 memcpy(psz + ret, sep, sepLen);
269 ret += sepLen;
270 }
271 }
272 LocalFree(info);
273 }
274 if (psz && csz)
275 {
276 *(psz + ret) = '\0';
277 ret++;
278 }
279 else
280 ret++;
281 TRACE("Returning %s\n", debugstr_a(psz));
282 return ret;
283 }
284
285 /* Adds the prefix prefix to the wide-character string pointed to by psz,
286 * followed by the character '='. Copies no more than csz characters. Returns
287 * the number of characters copied. If psz is NULL, returns the number of
288 * characters that would be copied.
289 * Assumes the characters in prefix are ASCII (not multibyte characters.)
290 */
291 static DWORD CRYPT_AddPrefixAToW(LPCSTR prefix, LPWSTR psz, DWORD csz)
292 {
293 DWORD chars;
294
295 TRACE("(%s, %p, %d)\n", debugstr_a(prefix), psz, csz);
296
297 if (psz)
298 {
299 DWORD i;
300
301 chars = min(lstrlenA(prefix), csz);
302 for (i = 0; i < chars; i++)
303 *(psz + i) = prefix[i];
304 *(psz + chars) = '=';
305 chars++;
306 }
307 else
308 chars = lstrlenA(prefix) + 1;
309 return chars;
310 }
311
312 /* Adds the prefix prefix to the string pointed to by psz, followed by the
313 * character '='. Copies no more than csz characters. Returns the number of
314 * characters copied. If psz is NULL, returns the number of characters that
315 * would be copied.
316 */
317 static DWORD CRYPT_AddPrefixW(LPCWSTR prefix, LPWSTR psz, DWORD csz)
318 {
319 DWORD chars;
320
321 TRACE("(%s, %p, %d)\n", debugstr_w(prefix), psz, csz);
322
323 if (psz)
324 {
325 chars = min(lstrlenW(prefix), csz);
326 memcpy(psz, prefix, chars * sizeof(WCHAR));
327 *(psz + chars) = '=';
328 chars++;
329 }
330 else
331 chars = lstrlenW(prefix) + 1;
332 return chars;
333 }
334
335 DWORD WINAPI CertNameToStrW(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
336 DWORD dwStrType, LPWSTR psz, DWORD csz)
337 {
338 static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG |
339 CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG;
340 static const WCHAR commaSep[] = { ',',' ',0 };
341 static const WCHAR semiSep[] = { ';',' ',0 };
342 static const WCHAR crlfSep[] = { '\r','\n',0 };
343 static const WCHAR plusSep[] = { ' ','+',' ',0 };
344 static const WCHAR spaceSep[] = { ' ',0 };
345 DWORD ret = 0, bytes = 0;
346 BOOL bRet;
347 CERT_NAME_INFO *info;
348
349 TRACE("(%d, %p, %08x, %p, %d)\n", dwCertEncodingType, pName, dwStrType,
350 psz, csz);
351 if (dwStrType & unsupportedFlags)
352 FIXME("unsupported flags: %08x\n", dwStrType & unsupportedFlags);
353
354 bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData,
355 pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes);
356 if (bRet)
357 {
358 DWORD i, j, sepLen, rdnSepLen;
359 LPCWSTR sep, rdnSep;
360
361 if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
362 sep = semiSep;
363 else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
364 sep = crlfSep;
365 else
366 sep = commaSep;
367 sepLen = lstrlenW(sep);
368 if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
369 rdnSep = spaceSep;
370 else
371 rdnSep = plusSep;
372 rdnSepLen = lstrlenW(rdnSep);
373 for (i = 0; (!psz || ret < csz) && i < info->cRDN; i++)
374 {
375 for (j = 0; (!psz || ret < csz) && j < info->rgRDN[i].cRDNAttr; j++)
376 {
377 DWORD chars;
378 LPCSTR prefixA = NULL;
379 LPCWSTR prefixW = NULL;
380
381 if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR)
382 prefixA = info->rgRDN[i].rgRDNAttr[j].pszObjId;
383 else if ((dwStrType & 0x000000ff) == CERT_X500_NAME_STR)
384 {
385 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(
386 CRYPT_OID_INFO_OID_KEY,
387 info->rgRDN[i].rgRDNAttr[j].pszObjId,
388 CRYPT_RDN_ATTR_OID_GROUP_ID);
389
390 if (oidInfo)
391 prefixW = oidInfo->pwszName;
392 else
393 prefixA = info->rgRDN[i].rgRDNAttr[j].pszObjId;
394 }
395 if (prefixW)
396 {
397 /* - 1 is needed to account for the NULL terminator. */
398 chars = CRYPT_AddPrefixW(prefixW,
399 psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
400 ret += chars;
401 }
402 else if (prefixA)
403 {
404 /* - 1 is needed to account for the NULL terminator. */
405 chars = CRYPT_AddPrefixAToW(prefixA,
406 psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
407 ret += chars;
408 }
409 /* FIXME: handle quoting */
410 chars = CertRDNValueToStrW(
411 info->rgRDN[i].rgRDNAttr[j].dwValueType,
412 &info->rgRDN[i].rgRDNAttr[j].Value, psz ? psz + ret : NULL,
413 psz ? csz - ret : 0);
414 if (chars)
415 ret += chars - 1;
416 if (j < info->rgRDN[i].cRDNAttr - 1)
417 {
418 if (psz && ret < csz - rdnSepLen - 1)
419 memcpy(psz + ret, rdnSep, rdnSepLen * sizeof(WCHAR));
420 ret += rdnSepLen;
421 }
422 }
423 if (i < info->cRDN - 1)
424 {
425 if (psz && ret < csz - sepLen - 1)
426 memcpy(psz + ret, sep, sepLen * sizeof(WCHAR));
427 ret += sepLen;
428 }
429 }
430 LocalFree(info);
431 }
432 if (psz && csz)
433 {
434 *(psz + ret) = '\0';
435 ret++;
436 }
437 else
438 ret++;
439 TRACE("Returning %s\n", debugstr_w(psz));
440 return ret;
441 }
442
443 BOOL WINAPI CertStrToNameA(DWORD dwCertEncodingType, LPCSTR pszX500,
444 DWORD dwStrType, void *pvReserved, BYTE *pbEncoded, DWORD *pcbEncoded,
445 LPCSTR *ppszError)
446 {
447 BOOL ret;
448 int len;
449
450 TRACE("(%08x, %s, %08x, %p, %p, %p, %p)\n", dwCertEncodingType,
451 debugstr_a(pszX500), dwStrType, pvReserved, pbEncoded, pcbEncoded,
452 ppszError);
453
454 len = MultiByteToWideChar(CP_ACP, 0, pszX500, -1, NULL, 0);
455 if (len)
456 {
457 LPWSTR x500, errorStr;
458
459 if ((x500 = CryptMemAlloc(len * sizeof(WCHAR))))
460 {
461 MultiByteToWideChar(CP_ACP, 0, pszX500, -1, x500, len);
462 ret = CertStrToNameW(dwCertEncodingType, x500, dwStrType,
463 pvReserved, pbEncoded, pcbEncoded,
464 ppszError ? (LPCWSTR *)&errorStr : NULL);
465 if (ppszError)
466 {
467 if (!ret)
468 {
469 DWORD i;
470
471 *ppszError = pszX500;
472 for (i = 0; i < errorStr - x500; i++)
473 *ppszError = CharNextA(*ppszError);
474 }
475 else
476 *ppszError = NULL;
477 }
478 CryptMemFree(x500);
479 }
480 else
481 {
482 SetLastError(ERROR_OUTOFMEMORY);
483 ret = FALSE;
484 }
485 }
486 else
487 {
488 SetLastError(CRYPT_E_INVALID_X500_STRING);
489 if (ppszError)
490 *ppszError = pszX500;
491 ret = FALSE;
492 }
493 return ret;
494 }
495
496 struct KeynameKeeper
497 {
498 WCHAR buf[10]; /* big enough for L"GivenName" */
499 LPWSTR keyName; /* usually = buf, but may be allocated */
500 DWORD keyLen;
501 };
502
503 static void CRYPT_InitializeKeynameKeeper(struct KeynameKeeper *keeper)
504 {
505 keeper->keyName = keeper->buf;
506 keeper->keyLen = sizeof(keeper->buf) / sizeof(keeper->buf[0]);
507 }
508
509 static void CRYPT_FreeKeynameKeeper(struct KeynameKeeper *keeper)
510 {
511 if (keeper->keyName != keeper->buf)
512 CryptMemFree(keeper->keyName);
513 }
514
515 struct X500TokenW
516 {
517 LPCWSTR start;
518 LPCWSTR end;
519 };
520
521 static void CRYPT_KeynameKeeperFromTokenW(struct KeynameKeeper *keeper,
522 const struct X500TokenW *key)
523 {
524 DWORD len = key->end - key->start;
525
526 if (len > keeper->keyLen)
527 {
528 if (keeper->keyName == keeper->buf)
529 keeper->keyName = CryptMemAlloc(len * sizeof(WCHAR));
530 else
531 keeper->keyName = CryptMemRealloc(keeper->keyName,
532 len * sizeof(WCHAR));
533 keeper->keyLen = len;
534 }
535 memcpy(keeper->keyName, key->start, (key->end - key->start) *
536 sizeof(WCHAR));
537 keeper->keyName[len] = '\0';
538 TRACE("Keyname is %s\n", debugstr_w(keeper->keyName));
539 }
540
541 static BOOL CRYPT_GetNextKeyW(LPCWSTR str, struct X500TokenW *token,
542 LPCWSTR *ppszError)
543 {
544 BOOL ret = TRUE;
545
546 while (*str && isspaceW(*str))
547 str++;
548 if (*str)
549 {
550 token->start = str;
551 while (*str && *str != '=' && !isspaceW(*str))
552 str++;
553 if (*str && (*str == '=' || isspaceW(*str)))
554 token->end = str;
555 else
556 {
557 TRACE("missing equals char at %s\n", debugstr_w(token->start));
558 if (ppszError)
559 *ppszError = token->start;
560 SetLastError(CRYPT_E_INVALID_X500_STRING);
561 ret = FALSE;
562 }
563 }
564 else
565 token->start = NULL;
566 return ret;
567 }
568
569 /* Assumes separators are characters in the 0-255 range */
570 static BOOL CRYPT_GetNextValueW(LPCWSTR str, DWORD dwFlags, LPCWSTR separators,
571 struct X500TokenW *token, LPCWSTR *ppszError)
572 {
573 BOOL ret = TRUE;
574
575 TRACE("(%s, %s, %p, %p)\n", debugstr_w(str), debugstr_w(separators), token,
576 ppszError);
577
578 while (*str && isspaceW(*str))
579 str++;
580 if (*str)
581 {
582 token->start = str;
583 if (!(dwFlags & CERT_NAME_STR_NO_QUOTING_FLAG) && *str == '"')
584 {
585 token->end = NULL;
586 str++;
587 while (!token->end && ret)
588 {
589 while (*str && *str != '"')
590 str++;
591 if (*str == '"')
592 {
593 if (*(str + 1) != '"')
594 token->end = str + 1;
595 else
596 str += 2;
597 }
598 else
599 {
600 TRACE("unterminated quote at %s\n", debugstr_w(str));
601 if (ppszError)
602 *ppszError = str;
603 SetLastError(CRYPT_E_INVALID_X500_STRING);
604 ret = FALSE;
605 }
606 }
607 }
608 else
609 {
610 WCHAR map[256] = { 0 };
611
612 while (*separators)
613 map[*separators++] = 1;
614 while (*str && (*str >= 0xff || !map[*str]))
615 str++;
616 token->end = str;
617 }
618 }
619 else
620 {
621 TRACE("missing value at %s\n", debugstr_w(str));
622 if (ppszError)
623 *ppszError = str;
624 SetLastError(CRYPT_E_INVALID_X500_STRING);
625 ret = FALSE;
626 }
627 return ret;
628 }
629
630 /* Encodes the string represented by value as the string type type into the
631 * CERT_NAME_BLOB output. If there is an error and ppszError is not NULL,
632 * *ppszError is set to the first failing character. If there is no error,
633 * output's pbData must be freed with LocalFree.
634 */
635 static BOOL CRYPT_EncodeValueWithType(DWORD dwCertEncodingType,
636 const struct X500TokenW *value, PCERT_NAME_BLOB output, DWORD type,
637 LPCWSTR *ppszError)
638 {
639 CERT_NAME_VALUE nameValue = { type, { 0, NULL } };
640 BOOL ret = TRUE;
641
642 if (value->end > value->start)
643 {
644 nameValue.Value.pbData = CryptMemAlloc((value->end - value->start) *
645 sizeof(WCHAR));
646 if (!nameValue.Value.pbData)
647 {
648 SetLastError(ERROR_OUTOFMEMORY);
649 ret = FALSE;
650 }
651 }
652 if (ret)
653 {
654 if (value->end > value->start)
655 {
656 DWORD i;
657 LPWSTR ptr = (LPWSTR)nameValue.Value.pbData;
658
659 for (i = 0; i < value->end - value->start; i++)
660 {
661 *ptr++ = value->start[i];
662 if (value->start[i] == '"')
663 i++;
664 }
665 nameValue.Value.cbData = (LPBYTE)ptr - nameValue.Value.pbData;
666 }
667 ret = CryptEncodeObjectEx(dwCertEncodingType, X509_UNICODE_NAME_VALUE,
668 &nameValue, CRYPT_ENCODE_ALLOC_FLAG, NULL, &output->pbData,
669 &output->cbData);
670 if (!ret && ppszError)
671 {
672 if (type == CERT_RDN_NUMERIC_STRING &&
673 GetLastError() == CRYPT_E_INVALID_NUMERIC_STRING)
674 *ppszError = value->start + output->cbData;
675 else if (type == CERT_RDN_PRINTABLE_STRING &&
676 GetLastError() == CRYPT_E_INVALID_PRINTABLE_STRING)
677 *ppszError = value->start + output->cbData;
678 else if (type == CERT_RDN_IA5_STRING &&
679 GetLastError() == CRYPT_E_INVALID_IA5_STRING)
680 *ppszError = value->start + output->cbData;
681 }
682 CryptMemFree(nameValue.Value.pbData);
683 }
684 return ret;
685 }
686
687 static BOOL CRYPT_EncodeValue(DWORD dwCertEncodingType,
688 const struct X500TokenW *value, PCERT_NAME_BLOB output, const DWORD *types,
689 LPCWSTR *ppszError)
690 {
691 DWORD i;
692 BOOL ret;
693
694 ret = FALSE;
695 for (i = 0; !ret && types[i]; i++)
696 ret = CRYPT_EncodeValueWithType(dwCertEncodingType, value, output,
697 types[i], ppszError);
698 return ret;
699 }
700
701 static BOOL CRYPT_ValueToRDN(DWORD dwCertEncodingType, PCERT_NAME_INFO info,
702 PCCRYPT_OID_INFO keyOID, struct X500TokenW *value, LPCWSTR *ppszError)
703 {
704 BOOL ret = FALSE;
705
706 TRACE("OID %s, value %s\n", debugstr_a(keyOID->pszOID),
707 debugstr_wn(value->start, value->end - value->start));
708
709 if (!info->rgRDN)
710 info->rgRDN = CryptMemAlloc(sizeof(CERT_RDN));
711 else
712 info->rgRDN = CryptMemRealloc(info->rgRDN,
713 (info->cRDN + 1) * sizeof(CERT_RDN));
714 if (info->rgRDN)
715 {
716 /* FIXME: support multiple RDN attrs */
717 info->rgRDN[info->cRDN].rgRDNAttr =
718 CryptMemAlloc(sizeof(CERT_RDN_ATTR));
719 if (info->rgRDN[info->cRDN].rgRDNAttr)
720 {
721 static const DWORD defaultTypes[] = { CERT_RDN_PRINTABLE_STRING,
722 CERT_RDN_BMP_STRING, 0 };
723 const DWORD *types;
724
725 info->rgRDN[info->cRDN].cRDNAttr = 1;
726 info->rgRDN[info->cRDN].rgRDNAttr[0].pszObjId =
727 (LPSTR)keyOID->pszOID;
728 info->rgRDN[info->cRDN].rgRDNAttr[0].dwValueType =
729 CERT_RDN_ENCODED_BLOB;
730 if (keyOID->ExtraInfo.cbData)
731 types = (const DWORD *)keyOID->ExtraInfo.pbData;
732 else
733 types = defaultTypes;
734
735 /* Remove surrounding quotes */
736 if (value->start[0] == '"')
737 {
738 value->start++;
739 value->end--;
740 }
741 ret = CRYPT_EncodeValue(dwCertEncodingType, value,
742 &info->rgRDN[info->cRDN].rgRDNAttr[0].Value, types, ppszError);
743 }
744 else
745 SetLastError(ERROR_OUTOFMEMORY);
746 info->cRDN++;
747 }
748 else
749 SetLastError(ERROR_OUTOFMEMORY);
750 return ret;
751 }
752
753 BOOL WINAPI CertStrToNameW(DWORD dwCertEncodingType, LPCWSTR pszX500,
754 DWORD dwStrType, void *pvReserved, BYTE *pbEncoded, DWORD *pcbEncoded,
755 LPCWSTR *ppszError)
756 {
757 CERT_NAME_INFO info = { 0, NULL };
758 LPCWSTR str;
759 struct KeynameKeeper keeper;
760 DWORD i;
761 BOOL ret = TRUE;
762
763 TRACE("(%08x, %s, %08x, %p, %p, %p, %p)\n", dwCertEncodingType,
764 debugstr_w(pszX500), dwStrType, pvReserved, pbEncoded, pcbEncoded,
765 ppszError);
766
767 CRYPT_InitializeKeynameKeeper(&keeper);
768 str = pszX500;
769 while (str && *str && ret)
770 {
771 struct X500TokenW token;
772
773 ret = CRYPT_GetNextKeyW(str, &token, ppszError);
774 if (ret && token.start)
775 {
776 PCCRYPT_OID_INFO keyOID;
777
778 CRYPT_KeynameKeeperFromTokenW(&keeper, &token);
779 keyOID = CryptFindOIDInfo(CRYPT_OID_INFO_NAME_KEY, keeper.keyName,
780 CRYPT_RDN_ATTR_OID_GROUP_ID);
781 if (!keyOID)
782 {
783 if (ppszError)
784 *ppszError = token.start;
785 SetLastError(CRYPT_E_INVALID_X500_STRING);
786 ret = FALSE;
787 }
788 else
789 {
790 str = token.end;
791 while (isspace(*str))
792 str++;
793 if (*str != '=')
794 {
795 if (ppszError)
796 *ppszError = str;
797 SetLastError(CRYPT_E_INVALID_X500_STRING);
798 ret = FALSE;
799 }
800 else
801 {
802 static const WCHAR commaSep[] = { ',',0 };
803 static const WCHAR semiSep[] = { ';',0 };
804 static const WCHAR crlfSep[] = { '\r','\n',0 };
805 static const WCHAR allSeps[] = { ',',';','\r','\n',0 };
806 LPCWSTR sep;
807
808 str++;
809 if (dwStrType & CERT_NAME_STR_COMMA_FLAG)
810 sep = commaSep;
811 else if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
812 sep = semiSep;
813 else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
814 sep = crlfSep;
815 else
816 sep = allSeps;
817 ret = CRYPT_GetNextValueW(str, dwStrType, sep, &token,
818 ppszError);
819 if (ret)
820 {
821 str = token.end;
822 ret = CRYPT_ValueToRDN(dwCertEncodingType, &info,
823 keyOID, &token, ppszError);
824 }
825 }
826 }
827 }
828 }
829 CRYPT_FreeKeynameKeeper(&keeper);
830 if (ret)
831 {
832 if (ppszError)
833 *ppszError = NULL;
834 ret = CryptEncodeObjectEx(dwCertEncodingType, X509_NAME, &info,
835 0, NULL, pbEncoded, pcbEncoded);
836 }
837 for (i = 0; i < info.cRDN; i++)
838 {
839 DWORD j;
840
841 for (j = 0; j < info.rgRDN[i].cRDNAttr; j++)
842 LocalFree(info.rgRDN[i].rgRDNAttr[j].Value.pbData);
843 CryptMemFree(info.rgRDN[i].rgRDNAttr);
844 }
845 CryptMemFree(info.rgRDN);
846 return ret;
847 }
848
849 DWORD WINAPI CertGetNameStringA(PCCERT_CONTEXT pCertContext, DWORD dwType,
850 DWORD dwFlags, void *pvTypePara, LPSTR pszNameString, DWORD cchNameString)
851 {
852 DWORD ret;
853
854 TRACE("(%p, %d, %08x, %p, %p, %d)\n", pCertContext, dwType, dwFlags,
855 pvTypePara, pszNameString, cchNameString);
856
857 if (pszNameString)
858 {
859 LPWSTR wideName;
860 DWORD nameLen;
861
862 nameLen = CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
863 NULL, 0);
864 wideName = CryptMemAlloc(nameLen * sizeof(WCHAR));
865 if (wideName)
866 {
867 CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
868 wideName, nameLen);
869 nameLen = WideCharToMultiByte(CP_ACP, 0, wideName, nameLen,
870 pszNameString, cchNameString, NULL, NULL);
871 if (nameLen <= cchNameString)
872 ret = nameLen;
873 else
874 {
875 pszNameString[cchNameString - 1] = '\0';
876 ret = cchNameString;
877 }
878 CryptMemFree(wideName);
879 }
880 else
881 {
882 *pszNameString = '\0';
883 ret = 1;
884 }
885 }
886 else
887 ret = CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
888 NULL, 0);
889 return ret;
890 }
891
892 DWORD WINAPI CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType,
893 DWORD dwFlags, void *pvTypePara, LPWSTR pszNameString, DWORD cchNameString)
894 {
895 DWORD ret;
896 PCERT_NAME_BLOB name;
897 LPCSTR altNameOID;
898
899 TRACE("(%p, %d, %08x, %p, %p, %d)\n", pCertContext, dwType,
900 dwFlags, pvTypePara, pszNameString, cchNameString);
901
902 if (dwFlags & CERT_NAME_ISSUER_FLAG)
903 {
904 name = &pCertContext->pCertInfo->Issuer;
905 altNameOID = szOID_ISSUER_ALT_NAME;
906 }
907 else
908 {
909 name = &pCertContext->pCertInfo->Subject;
910 altNameOID = szOID_SUBJECT_ALT_NAME;
911 }
912
913 switch (dwType)
914 {
915 case CERT_NAME_SIMPLE_DISPLAY_TYPE:
916 {
917 static const LPCSTR simpleAttributeOIDs[] = { szOID_COMMON_NAME,
918 szOID_ORGANIZATIONAL_UNIT_NAME, szOID_ORGANIZATION_NAME,
919 szOID_RSA_emailAddr };
920 CERT_NAME_INFO *info = NULL;
921 PCERT_RDN_ATTR nameAttr = NULL;
922 DWORD bytes = 0, i;
923
924 if (CryptDecodeObjectEx(pCertContext->dwCertEncodingType, X509_NAME,
925 name->pbData, name->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info,
926 &bytes))
927 {
928 for (i = 0; !nameAttr && i < sizeof(simpleAttributeOIDs) /
929 sizeof(simpleAttributeOIDs[0]); i++)
930 nameAttr = CertFindRDNAttr(simpleAttributeOIDs[i], info);
931 }
932 if (!nameAttr)
933 {
934 PCERT_EXTENSION ext = CertFindExtension(altNameOID,
935 pCertContext->pCertInfo->cExtension,
936 pCertContext->pCertInfo->rgExtension);
937
938 if (ext)
939 {
940 for (i = 0; !nameAttr && i < sizeof(simpleAttributeOIDs) /
941 sizeof(simpleAttributeOIDs[0]); i++)
942 nameAttr = CertFindRDNAttr(simpleAttributeOIDs[i], info);
943 if (!nameAttr)
944 {
945 /* FIXME: gotta then look for a rfc822Name choice in ext.
946 * Failing that, look for the first attribute.
947 */
948 FIXME("CERT_NAME_SIMPLE_DISPLAY_TYPE: stub\n");
949 }
950 }
951 }
952 if (nameAttr)
953 ret = CertRDNValueToStrW(nameAttr->dwValueType, &nameAttr->Value,
954 pszNameString, cchNameString);
955 else
956 ret = 0;
957 if (info)
958 LocalFree(info);
959 break;
960 }
961 case CERT_NAME_FRIENDLY_DISPLAY_TYPE:
962 {
963 DWORD cch = cchNameString;
964
965 if (CertGetCertificateContextProperty(pCertContext,
966 CERT_FRIENDLY_NAME_PROP_ID, pszNameString, &cch))
967 ret = cch;
968 else
969 ret = CertGetNameStringW(pCertContext,
970 CERT_NAME_SIMPLE_DISPLAY_TYPE, dwFlags, pvTypePara, pszNameString,
971 cchNameString);
972 break;
973 }
974 default:
975 FIXME("unimplemented for type %d\n", dwType);
976 ret = 0;
977 }
978 return ret;
979 }
980
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.