msi: Implement ACTION_AppSearchIni.
[wine/wine64.git] / dlls / crypt32 / str.c
blobef67a9a49527b58d0693c94e49cd715fb07b1af4
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>
19 #include "windef.h"
20 #include "winbase.h"
21 #include "winnls.h"
22 #include "wincrypt.h"
23 #include "wine/debug.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
27 DWORD WINAPI CertRDNValueToStrA(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
28 LPSTR psz, DWORD csz)
30 DWORD ret = 0;
32 TRACE("(%ld, %p, %p, %ld)\n", dwValueType, pValue, psz, csz);
34 switch (dwValueType)
36 case CERT_RDN_ANY_TYPE:
37 break;
38 case CERT_RDN_PRINTABLE_STRING:
39 case CERT_RDN_IA5_STRING:
40 if (!psz || !csz)
41 ret = pValue->cbData;
42 else
44 DWORD chars = min(pValue->cbData, csz - 1);
46 if (chars)
48 memcpy(psz, pValue->pbData, chars);
49 ret += chars;
50 csz -= chars;
53 break;
54 default:
55 FIXME("string type %ld unimplemented\n", dwValueType);
57 if (psz && csz)
59 *(psz + ret) = '\0';
60 csz--;
61 ret++;
63 else
64 ret++;
65 return ret;
68 DWORD WINAPI CertRDNValueToStrW(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
69 LPWSTR psz, DWORD csz)
71 DWORD ret = 0;
73 TRACE("(%ld, %p, %p, %ld)\n", dwValueType, pValue, psz, csz);
75 switch (dwValueType)
77 case CERT_RDN_ANY_TYPE:
78 break;
79 case CERT_RDN_PRINTABLE_STRING:
80 case CERT_RDN_IA5_STRING:
81 if (!psz || !csz)
82 ret = pValue->cbData;
83 else
85 DWORD chars = min(pValue->cbData, csz - 1);
87 if (chars)
89 DWORD i;
91 for (i = 0; i < chars; i++)
92 psz[i] = pValue->pbData[i];
93 ret += chars;
94 csz -= chars;
97 break;
98 default:
99 FIXME("string type %ld unimplemented\n", dwValueType);
101 if (psz && csz)
103 *(psz + ret) = '\0';
104 csz--;
105 ret++;
107 else
108 ret++;
109 return ret;
112 /* Adds the prefix prefix to the string pointed to by psz, followed by the
113 * character '='. Copies no more than csz characters. Returns the number of
114 * characters copied. If psz is NULL, returns the number of characters that
115 * would be copied.
117 static DWORD CRYPT_AddPrefixA(LPCSTR prefix, LPSTR psz, DWORD csz)
119 DWORD chars = min(lstrlenA(prefix), csz);
121 TRACE("(%s, %p, %ld)\n", debugstr_a(prefix), psz, csz);
123 if (psz && chars)
124 memcpy(psz, prefix, chars);
125 csz -= chars;
126 if (csz > 1)
128 if (psz)
129 *(psz + chars) = '=';
130 chars++;
131 csz--;
133 return chars;
136 DWORD WINAPI CertNameToStrA(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
137 DWORD dwStrType, LPSTR psz, DWORD csz)
139 static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG |
140 CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG;
141 static const char commaSep[] = ", ";
142 static const char semiSep[] = "; ";
143 static const char crlfSep[] = "\r\n";
144 static const char plusSep[] = " + ";
145 static const char spaceSep[] = " ";
146 DWORD ret = 0, bytes = 0;
147 BOOL bRet;
148 CERT_NAME_INFO *info;
150 TRACE("(%ld, %p, %08lx, %p, %ld)\n", dwCertEncodingType, pName, dwStrType,
151 psz, csz);
152 if (dwStrType & unsupportedFlags)
153 FIXME("unsupported flags: %08lx\n", dwStrType & unsupportedFlags);
155 bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData,
156 pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes);
157 if (bRet)
159 DWORD i, j, sepLen, rdnSepLen;
160 LPCSTR sep, rdnSep;
162 if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
163 sep = semiSep;
164 else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
165 sep = crlfSep;
166 else
167 sep = commaSep;
168 sepLen = strlen(sep);
169 if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
170 rdnSep = spaceSep;
171 else
172 rdnSep = plusSep;
173 rdnSepLen = strlen(rdnSep);
174 for (i = 0; ret < csz && i < info->cRDN; i++)
176 for (j = 0; ret < csz && j < info->rgRDN[i].cRDNAttr; j++)
178 DWORD chars;
179 char prefixBuf[10]; /* big enough for GivenName */
180 LPCSTR prefix = NULL;
182 if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR)
183 prefix = info->rgRDN[i].rgRDNAttr[j].pszObjId;
184 else if ((dwStrType & 0x000000ff) == CERT_X500_NAME_STR)
186 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(
187 CRYPT_OID_INFO_OID_KEY,
188 info->rgRDN[i].rgRDNAttr[j].pszObjId,
189 CRYPT_RDN_ATTR_OID_GROUP_ID);
191 if (oidInfo)
193 WideCharToMultiByte(CP_ACP, 0, oidInfo->pwszName, -1,
194 prefixBuf, sizeof(prefixBuf), NULL, NULL);
195 prefix = prefixBuf;
197 else
198 prefix = info->rgRDN[i].rgRDNAttr[j].pszObjId;
200 if (prefix)
202 /* - 1 is needed to account for the NULL terminator. */
203 chars = CRYPT_AddPrefixA(prefix, psz + ret, csz - ret - 1);
204 ret += chars;
205 csz -= chars;
207 /* FIXME: handle quoting */
208 chars = CertRDNValueToStrA(
209 info->rgRDN[i].rgRDNAttr[j].dwValueType,
210 &info->rgRDN[i].rgRDNAttr[j].Value, psz ? psz + ret : NULL,
211 csz - ret - 1);
212 if (chars)
213 ret += chars - 1;
214 if (j < info->rgRDN[i].cRDNAttr - 1)
216 if (psz && ret < csz - rdnSepLen - 1)
217 memcpy(psz + ret, rdnSep, rdnSepLen);
218 ret += rdnSepLen;
221 if (i < info->cRDN - 1)
223 if (psz && ret < csz - sepLen - 1)
224 memcpy(psz + ret, sep, sepLen);
225 ret += sepLen;
228 LocalFree(info);
230 if (psz && csz)
232 *(psz + ret) = '\0';
233 csz--;
234 ret++;
236 else
237 ret++;
238 return ret;
241 /* Adds the prefix prefix to the wide-character string pointed to by psz,
242 * followed by the character '='. Copies no more than csz characters. Returns
243 * the number of characters copied. If psz is NULL, returns the number of
244 * characters that would be copied.
245 * Assumes the characters in prefix are ASCII (not multibyte characters.)
247 static DWORD CRYPT_AddPrefixAToW(LPCSTR prefix, LPWSTR psz, DWORD csz)
249 DWORD chars = min(lstrlenA(prefix), csz);
251 TRACE("(%s, %p, %ld)\n", debugstr_a(prefix), psz, csz);
253 if (psz && chars)
255 DWORD i;
257 for (i = 0; i < chars; i++)
258 *(psz + i) = prefix[i];
260 csz -= chars;
261 if (csz > 1)
263 if (psz)
264 *(psz + chars) = '=';
265 chars++;
266 csz--;
268 return chars;
271 /* Adds the prefix prefix to the string pointed to by psz, followed by the
272 * character '='. Copies no more than csz characters. Returns the number of
273 * characters copied. If psz is NULL, returns the number of characters that
274 * would be copied.
276 static DWORD CRYPT_AddPrefixW(LPCWSTR prefix, LPWSTR psz, DWORD csz)
278 DWORD chars = min(lstrlenW(prefix), csz);
280 TRACE("(%s, %p, %ld)\n", debugstr_w(prefix), psz, csz);
282 if (psz && chars)
283 memcpy(psz, prefix, chars * sizeof(WCHAR));
284 csz -= chars;
285 if (csz > 1)
287 if (psz)
288 *(psz + chars) = '=';
289 chars++;
290 csz--;
292 return chars;
295 DWORD WINAPI CertNameToStrW(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
296 DWORD dwStrType, LPWSTR psz, DWORD csz)
298 static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG |
299 CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG;
300 static const WCHAR commaSep[] = { ',',' ',0 };
301 static const WCHAR semiSep[] = { ';',' ',0 };
302 static const WCHAR crlfSep[] = { '\r','\n',0 };
303 static const WCHAR plusSep[] = { ' ','+',' ',0 };
304 static const WCHAR spaceSep[] = { ' ',0 };
305 DWORD ret = 0, bytes = 0;
306 BOOL bRet;
307 CERT_NAME_INFO *info;
309 TRACE("(%ld, %p, %08lx, %p, %ld)\n", dwCertEncodingType, pName, dwStrType,
310 psz, csz);
311 if (dwStrType & unsupportedFlags)
312 FIXME("unsupported flags: %08lx\n", dwStrType & unsupportedFlags);
314 bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData,
315 pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes);
316 if (bRet)
318 DWORD i, j, sepLen, rdnSepLen;
319 LPCWSTR sep, rdnSep;
321 if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
322 sep = semiSep;
323 else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
324 sep = crlfSep;
325 else
326 sep = commaSep;
327 sepLen = lstrlenW(sep);
328 if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
329 rdnSep = spaceSep;
330 else
331 rdnSep = plusSep;
332 rdnSepLen = lstrlenW(rdnSep);
333 for (i = 0; ret < csz && i < info->cRDN; i++)
335 for (j = 0; ret < csz && j < info->rgRDN[i].cRDNAttr; j++)
337 DWORD chars;
338 LPCSTR prefixA = NULL;
339 LPCWSTR prefixW = NULL;
341 if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR)
342 prefixA = info->rgRDN[i].rgRDNAttr[j].pszObjId;
343 else if ((dwStrType & 0x000000ff) == CERT_X500_NAME_STR)
345 PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(
346 CRYPT_OID_INFO_OID_KEY,
347 info->rgRDN[i].rgRDNAttr[j].pszObjId,
348 CRYPT_RDN_ATTR_OID_GROUP_ID);
350 if (oidInfo)
351 prefixW = oidInfo->pwszName;
352 else
353 prefixA = info->rgRDN[i].rgRDNAttr[j].pszObjId;
355 if (prefixW)
357 /* - 1 is needed to account for the NULL terminator. */
358 chars = CRYPT_AddPrefixW(prefixW, psz + ret, csz - ret - 1);
359 ret += chars;
360 csz -= chars;
362 else if (prefixA)
364 /* - 1 is needed to account for the NULL terminator. */
365 chars = CRYPT_AddPrefixAToW(prefixA, psz + ret,
366 csz - ret - 1);
367 ret += chars;
368 csz -= chars;
370 /* FIXME: handle quoting */
371 chars = CertRDNValueToStrW(
372 info->rgRDN[i].rgRDNAttr[j].dwValueType,
373 &info->rgRDN[i].rgRDNAttr[j].Value, psz ? psz + ret : NULL,
374 csz - ret - 1);
375 if (chars)
376 ret += chars - 1;
377 if (j < info->rgRDN[i].cRDNAttr - 1)
379 if (psz && ret < csz - rdnSepLen - 1)
380 memcpy(psz + ret, rdnSep, rdnSepLen * sizeof(WCHAR));
381 ret += rdnSepLen;
384 if (i < info->cRDN - 1)
386 if (psz && ret < csz - sepLen - 1)
387 memcpy(psz + ret, sep, sepLen * sizeof(WCHAR));
388 ret += sepLen;
391 LocalFree(info);
393 if (psz && csz)
395 *(psz + ret) = '\0';
396 csz--;
397 ret++;
399 else
400 ret++;
401 return ret;
404 DWORD WINAPI CertGetNameStringA(PCCERT_CONTEXT pCertContext, DWORD dwType,
405 DWORD dwFlags, void *pvTypePara, LPSTR pszNameString, DWORD cchNameString)
407 DWORD ret;
409 TRACE("(%p, %ld, %08lx, %p, %p, %ld)\n", pCertContext, dwType, dwFlags,
410 pvTypePara, pszNameString, cchNameString);
412 if (pszNameString)
414 LPWSTR wideName;
415 DWORD nameLen;
417 nameLen = CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
418 NULL, 0);
419 wideName = CryptMemAlloc(nameLen * sizeof(WCHAR));
420 if (wideName)
422 CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
423 wideName, nameLen);
424 nameLen = WideCharToMultiByte(CP_ACP, 0, wideName, nameLen,
425 pszNameString, cchNameString, NULL, NULL);
426 if (nameLen <= cchNameString)
427 ret = nameLen;
428 else
430 pszNameString[cchNameString - 1] = '\0';
431 ret = cchNameString;
433 CryptMemFree(wideName);
435 else
437 *pszNameString = '\0';
438 ret = 1;
441 else
442 ret = CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara,
443 NULL, 0);
444 return ret;
447 DWORD WINAPI CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType,
448 DWORD dwFlags, void *pvTypePara, LPWSTR pszNameString, DWORD cchNameString)
450 DWORD ret;
451 PCERT_NAME_BLOB name;
452 LPCSTR altNameOID;
454 TRACE("(%p, %ld, %08lx, %p, %p, %ld)\n", pCertContext, dwType,
455 dwFlags, pvTypePara, pszNameString, cchNameString);
457 if (dwFlags & CERT_NAME_ISSUER_FLAG)
459 name = &pCertContext->pCertInfo->Issuer;
460 altNameOID = szOID_ISSUER_ALT_NAME;
462 else
464 name = &pCertContext->pCertInfo->Subject;
465 altNameOID = szOID_SUBJECT_ALT_NAME;
468 switch (dwType)
470 case CERT_NAME_SIMPLE_DISPLAY_TYPE:
472 static const LPCSTR simpleAttributeOIDs[] = { szOID_COMMON_NAME,
473 szOID_ORGANIZATIONAL_UNIT_NAME, szOID_ORGANIZATION_NAME,
474 szOID_RSA_emailAddr };
475 CERT_NAME_INFO *info = NULL;
476 PCERT_RDN_ATTR nameAttr = NULL;
477 DWORD bytes = 0, i;
479 if (CryptDecodeObjectEx(pCertContext->dwCertEncodingType, X509_NAME,
480 name->pbData, name->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info,
481 &bytes))
483 for (i = 0; !nameAttr && i < sizeof(simpleAttributeOIDs) /
484 sizeof(simpleAttributeOIDs[0]); i++)
485 nameAttr = CertFindRDNAttr(simpleAttributeOIDs[i], info);
487 else
488 ret = 0;
489 if (!nameAttr)
491 PCERT_EXTENSION ext = CertFindExtension(altNameOID,
492 pCertContext->pCertInfo->cExtension,
493 pCertContext->pCertInfo->rgExtension);
495 if (ext)
497 for (i = 0; !nameAttr && i < sizeof(simpleAttributeOIDs) /
498 sizeof(simpleAttributeOIDs[0]); i++)
499 nameAttr = CertFindRDNAttr(simpleAttributeOIDs[i], info);
500 if (!nameAttr)
502 /* FIXME: gotta then look for a rfc822Name choice in ext.
503 * Failing that, look for the first attribute.
505 FIXME("CERT_NAME_SIMPLE_DISPLAY_TYPE: stub\n");
506 ret = 0;
510 ret = CertRDNValueToStrW(nameAttr->dwValueType, &nameAttr->Value,
511 pszNameString, cchNameString);
512 if (info)
513 LocalFree(info);
514 break;
516 case CERT_NAME_FRIENDLY_DISPLAY_TYPE:
518 DWORD cch = cchNameString;
520 if (CertGetCertificateContextProperty(pCertContext,
521 CERT_FRIENDLY_NAME_PROP_ID, pszNameString, &cch))
522 ret = cch;
523 else
524 ret = CertGetNameStringW(pCertContext,
525 CERT_NAME_SIMPLE_DISPLAY_TYPE, dwFlags, pvTypePara, pszNameString,
526 cchNameString);
527 break;
529 default:
530 FIXME("unimplemented for type %ld\n", dwType);
531 ret = 0;
533 return ret;