push aea352fc3df615e3f4b48daf6f897ea93ad1fffd
[wine/hacks.git] / dlls / crypt32 / encode.c
blobaacef315ae61981d56b5a585e077e0262fbc5423
1 /*
2 * Copyright 2005 Juan Lang
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 * This file implements ASN.1 DER encoding of a limited set of types.
19 * It isn't a full ASN.1 implementation. Microsoft implements BER
20 * encoding of many of the basic types in msasn1.dll, but that interface is
21 * undocumented, so I implement them here.
23 * References:
24 * "A Layman's Guide to a Subset of ASN.1, BER, and DER", by Burton Kaliski
25 * (available online, look for a PDF copy as the HTML versions tend to have
26 * translation errors.)
28 * RFC3280, http://www.faqs.org/rfcs/rfc3280.html
30 * MSDN, especially:
31 * http://msdn.microsoft.com/library/en-us/seccrypto/security/constants_for_cryptencodeobject_and_cryptdecodeobject.asp
34 #include <assert.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stdlib.h>
39 #define NONAMELESSUNION
41 #include "windef.h"
42 #include "winbase.h"
43 #include "wincrypt.h"
44 #include "snmp.h"
45 #include "wine/debug.h"
46 #include "wine/exception.h"
47 #include "wine/unicode.h"
48 #include "crypt32_private.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
52 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
53 BYTE *, DWORD *);
54 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
55 DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
57 /* Prototypes for built-in encoders. They follow the Ex style prototypes.
58 * The dwCertEncodingType and lpszStructType are ignored by the built-in
59 * functions, but the parameters are retained to simplify CryptEncodeObjectEx,
60 * since it must call functions in external DLLs that follow these signatures.
62 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
63 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
64 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
65 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
66 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
67 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
68 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
69 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
70 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
71 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
72 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
73 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
74 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
75 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
76 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
77 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
78 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
79 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
80 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
81 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
82 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
83 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
84 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
85 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
86 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
87 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
88 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
89 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
90 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
91 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
92 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
93 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
94 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
95 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
96 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
97 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
99 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
100 const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
102 static HCRYPTOIDFUNCSET set = NULL;
103 BOOL ret = FALSE;
104 HCRYPTOIDFUNCADDR hFunc;
105 CryptEncodeObjectFunc pCryptEncodeObject;
107 TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
108 debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
109 pcbEncoded);
111 if (!pbEncoded && !pcbEncoded)
113 SetLastError(ERROR_INVALID_PARAMETER);
114 return FALSE;
117 /* Try registered DLL first.. */
118 if (!set)
119 set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_FUNC, 0);
120 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
121 (void **)&pCryptEncodeObject, &hFunc);
122 if (pCryptEncodeObject)
124 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
125 pvStructInfo, pbEncoded, pcbEncoded);
126 CryptFreeOIDFunctionAddress(hFunc, 0);
128 else
130 /* If not, use CryptEncodeObjectEx */
131 ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
132 pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
134 return ret;
137 /* Helper function to check *pcbEncoded, set it to the required size, and
138 * optionally to allocate memory. Assumes pbEncoded is not NULL.
139 * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
140 * pointer to the newly allocated memory.
142 static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
143 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
144 DWORD bytesNeeded)
146 BOOL ret = TRUE;
148 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
150 if (pEncodePara && pEncodePara->pfnAlloc)
151 *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
152 else
153 *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
154 if (!*(BYTE **)pbEncoded)
155 ret = FALSE;
156 else
157 *pcbEncoded = bytesNeeded;
159 else if (bytesNeeded > *pcbEncoded)
161 *pcbEncoded = bytesNeeded;
162 SetLastError(ERROR_MORE_DATA);
163 ret = FALSE;
165 else
166 *pcbEncoded = bytesNeeded;
167 return ret;
170 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
172 DWORD bytesNeeded, significantBytes = 0;
174 if (len <= 0x7f)
175 bytesNeeded = 1;
176 else
178 DWORD temp;
180 for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
181 temp <<= 8, significantBytes--)
183 bytesNeeded = significantBytes + 1;
185 if (!pbEncoded)
187 *pcbEncoded = bytesNeeded;
188 return TRUE;
190 if (*pcbEncoded < bytesNeeded)
192 SetLastError(ERROR_MORE_DATA);
193 return FALSE;
195 if (len <= 0x7f)
196 *pbEncoded = (BYTE)len;
197 else
199 DWORD i;
201 *pbEncoded++ = significantBytes | 0x80;
202 for (i = 0; i < significantBytes; i++)
204 *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
205 len >>= 8;
208 *pcbEncoded = bytesNeeded;
209 return TRUE;
212 struct AsnEncodeSequenceItem
214 const void *pvStructInfo;
215 CryptEncodeObjectExFunc encodeFunc;
216 DWORD size; /* used during encoding, not for your use */
219 static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
220 struct AsnEncodeSequenceItem items[], DWORD cItem, DWORD dwFlags,
221 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
223 BOOL ret;
224 DWORD i, dataLen = 0;
226 TRACE("%p, %d, %08x, %p, %p, %d\n", items, cItem, dwFlags, pEncodePara,
227 pbEncoded, *pcbEncoded);
228 for (i = 0, ret = TRUE; ret && i < cItem; i++)
230 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
231 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
232 NULL, &items[i].size);
233 /* Some functions propagate their errors through the size */
234 if (!ret)
235 *pcbEncoded = items[i].size;
236 dataLen += items[i].size;
238 if (ret)
240 DWORD lenBytes, bytesNeeded;
242 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
243 bytesNeeded = 1 + lenBytes + dataLen;
244 if (!pbEncoded)
245 *pcbEncoded = bytesNeeded;
246 else
248 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
249 pcbEncoded, bytesNeeded)))
251 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
252 pbEncoded = *(BYTE **)pbEncoded;
253 *pbEncoded++ = ASN_SEQUENCE;
254 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
255 pbEncoded += lenBytes;
256 for (i = 0; ret && i < cItem; i++)
258 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
259 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG,
260 NULL, pbEncoded, &items[i].size);
261 /* Some functions propagate their errors through the size */
262 if (!ret)
263 *pcbEncoded = items[i].size;
264 pbEncoded += items[i].size;
269 TRACE("returning %d (%08x)\n", ret, GetLastError());
270 return ret;
273 struct AsnConstructedItem
275 BYTE tag;
276 const void *pvStructInfo;
277 CryptEncodeObjectExFunc encodeFunc;
280 static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
281 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
282 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
284 BOOL ret;
285 const struct AsnConstructedItem *item =
286 (const struct AsnConstructedItem *)pvStructInfo;
287 DWORD len;
289 if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
290 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &len)))
292 DWORD dataLen, bytesNeeded;
294 CRYPT_EncodeLen(len, NULL, &dataLen);
295 bytesNeeded = 1 + dataLen + len;
296 if (!pbEncoded)
297 *pcbEncoded = bytesNeeded;
298 else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
299 pbEncoded, pcbEncoded, bytesNeeded)))
301 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
302 pbEncoded = *(BYTE **)pbEncoded;
303 *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
304 CRYPT_EncodeLen(len, pbEncoded, &dataLen);
305 pbEncoded += dataLen;
306 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
307 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
308 pbEncoded, &len);
309 if (!ret)
311 /* Some functions propagate their errors through the size */
312 *pcbEncoded = len;
316 else
318 /* Some functions propagate their errors through the size */
319 *pcbEncoded = len;
321 return ret;
324 struct AsnEncodeTagSwappedItem
326 BYTE tag;
327 const void *pvStructInfo;
328 CryptEncodeObjectExFunc encodeFunc;
331 /* Sort of a wacky hack, it encodes something using the struct
332 * AsnEncodeTagSwappedItem's encodeFunc, then replaces the tag byte with the tag
333 * given in the struct AsnEncodeTagSwappedItem.
335 static BOOL WINAPI CRYPT_AsnEncodeSwapTag(DWORD dwCertEncodingType,
336 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
337 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
339 BOOL ret;
340 const struct AsnEncodeTagSwappedItem *item =
341 (const struct AsnEncodeTagSwappedItem *)pvStructInfo;
343 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
344 item->pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
345 if (ret && pbEncoded)
346 *pbEncoded = item->tag;
347 return ret;
350 static BOOL WINAPI CRYPT_AsnEncodeCertVersion(DWORD dwCertEncodingType,
351 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
352 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
354 const DWORD *ver = (const DWORD *)pvStructInfo;
355 BOOL ret;
357 /* CERT_V1 is not encoded */
358 if (*ver == CERT_V1)
360 *pcbEncoded = 0;
361 ret = TRUE;
363 else
365 struct AsnConstructedItem item = { 0, ver, CRYPT_AsnEncodeInt };
367 ret = CRYPT_AsnEncodeConstructed(dwCertEncodingType, X509_INTEGER,
368 &item, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
370 return ret;
373 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
374 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
375 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
377 const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
378 BOOL ret;
380 if (!pbEncoded)
382 *pcbEncoded = blob->cbData;
383 ret = TRUE;
385 else
387 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
388 pcbEncoded, blob->cbData)))
390 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
391 pbEncoded = *(BYTE **)pbEncoded;
392 if (blob->cbData)
393 memcpy(pbEncoded, blob->pbData, blob->cbData);
394 *pcbEncoded = blob->cbData;
395 ret = TRUE;
398 return ret;
401 static BOOL WINAPI CRYPT_AsnEncodeValidity(DWORD dwCertEncodingType,
402 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
403 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
405 BOOL ret;
406 /* This has two filetimes in a row, a NotBefore and a NotAfter */
407 const FILETIME *timePtr = (const FILETIME *)pvStructInfo;
408 struct AsnEncodeSequenceItem items[] = {
409 { timePtr++, CRYPT_AsnEncodeChoiceOfTime, 0 },
410 { timePtr, CRYPT_AsnEncodeChoiceOfTime, 0 },
413 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
414 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
415 pcbEncoded);
416 return ret;
419 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmId(
420 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
421 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
422 DWORD *pcbEncoded)
424 const CRYPT_ALGORITHM_IDENTIFIER *algo =
425 (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
426 BOOL ret;
427 struct AsnEncodeSequenceItem items[] = {
428 { algo->pszObjId, CRYPT_AsnEncodeOid, 0 },
429 { &algo->Parameters, CRYPT_CopyEncodedBlob, 0 },
432 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
433 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
434 pcbEncoded);
435 return ret;
438 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
439 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
440 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
442 BOOL ret;
444 __TRY
446 const CERT_PUBLIC_KEY_INFO *info =
447 (const CERT_PUBLIC_KEY_INFO *)pvStructInfo;
448 struct AsnEncodeSequenceItem items[] = {
449 { &info->Algorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
450 { &info->PublicKey, CRYPT_AsnEncodeBits, 0 },
453 TRACE("Encoding public key with OID %s\n",
454 debugstr_a(info->Algorithm.pszObjId));
455 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
456 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
457 pcbEncoded);
459 __EXCEPT_PAGE_FAULT
461 SetLastError(STATUS_ACCESS_VIOLATION);
462 ret = FALSE;
464 __ENDTRY
465 return ret;
468 static BOOL WINAPI CRYPT_AsnEncodeCert(DWORD dwCertEncodingType,
469 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
470 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
472 BOOL ret;
474 __TRY
476 const CERT_SIGNED_CONTENT_INFO *info =
477 (const CERT_SIGNED_CONTENT_INFO *)pvStructInfo;
478 struct AsnEncodeSequenceItem items[] = {
479 { &info->ToBeSigned, CRYPT_CopyEncodedBlob, 0 },
480 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
481 { &info->Signature, CRYPT_AsnEncodeBitsSwapBytes, 0 },
484 if (dwFlags & CRYPT_ENCODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
485 items[2].encodeFunc = CRYPT_AsnEncodeBits;
486 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
487 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
488 pcbEncoded);
490 __EXCEPT_PAGE_FAULT
492 SetLastError(STATUS_ACCESS_VIOLATION);
493 ret = FALSE;
495 __ENDTRY
496 return ret;
499 /* Like in Windows, this blithely ignores the validity of the passed-in
500 * CERT_INFO, and just encodes it as-is. The resulting encoded data may not
501 * decode properly, see CRYPT_AsnDecodeCertInfo.
503 static BOOL WINAPI CRYPT_AsnEncodeCertInfo(DWORD dwCertEncodingType,
504 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
505 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
507 BOOL ret;
509 __TRY
511 const CERT_INFO *info = (const CERT_INFO *)pvStructInfo;
512 struct AsnEncodeSequenceItem items[10] = {
513 { &info->dwVersion, CRYPT_AsnEncodeCertVersion, 0 },
514 { &info->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
515 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
516 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
517 { &info->NotBefore, CRYPT_AsnEncodeValidity, 0 },
518 { &info->Subject, CRYPT_CopyEncodedBlob, 0 },
519 { &info->SubjectPublicKeyInfo, CRYPT_AsnEncodePubKeyInfo, 0 },
520 { 0 }
522 struct AsnConstructedItem constructed[3] = { { 0 } };
523 DWORD cItem = 7, cConstructed = 0;
525 if (info->IssuerUniqueId.cbData)
527 constructed[cConstructed].tag = 1;
528 constructed[cConstructed].pvStructInfo = &info->IssuerUniqueId;
529 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
530 items[cItem].pvStructInfo = &constructed[cConstructed];
531 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
532 cConstructed++;
533 cItem++;
535 if (info->SubjectUniqueId.cbData)
537 constructed[cConstructed].tag = 2;
538 constructed[cConstructed].pvStructInfo = &info->SubjectUniqueId;
539 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
540 items[cItem].pvStructInfo = &constructed[cConstructed];
541 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
542 cConstructed++;
543 cItem++;
545 if (info->cExtension)
547 constructed[cConstructed].tag = 3;
548 constructed[cConstructed].pvStructInfo = &info->cExtension;
549 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions;
550 items[cItem].pvStructInfo = &constructed[cConstructed];
551 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
552 cConstructed++;
553 cItem++;
556 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
557 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
559 __EXCEPT_PAGE_FAULT
561 SetLastError(STATUS_ACCESS_VIOLATION);
562 ret = FALSE;
564 __ENDTRY
565 return ret;
568 static BOOL WINAPI CRYPT_AsnEncodeCRLEntry(const CRL_ENTRY *entry,
569 BYTE *pbEncoded, DWORD *pcbEncoded)
571 struct AsnEncodeSequenceItem items[3] = {
572 { &entry->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
573 { &entry->RevocationDate, CRYPT_AsnEncodeChoiceOfTime, 0 },
574 { 0 }
576 DWORD cItem = 2;
577 BOOL ret;
579 TRACE("%p, %p, %p\n", entry, pbEncoded, pcbEncoded);
581 if (entry->cExtension)
583 items[cItem].pvStructInfo = &entry->cExtension;
584 items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
585 cItem++;
588 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
589 pbEncoded, pcbEncoded);
591 TRACE("returning %d (%08x)\n", ret, GetLastError());
592 return ret;
595 static BOOL WINAPI CRYPT_AsnEncodeCRLEntries(DWORD dwCertEncodingType,
596 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
597 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
599 DWORD cCRLEntry = *(const DWORD *)pvStructInfo;
600 DWORD bytesNeeded, dataLen, lenBytes, i;
601 const CRL_ENTRY *rgCRLEntry = *(const CRL_ENTRY *const *)
602 ((const BYTE *)pvStructInfo + sizeof(DWORD));
603 BOOL ret = TRUE;
605 for (i = 0, dataLen = 0; ret && i < cCRLEntry; i++)
607 DWORD size;
609 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], NULL, &size);
610 if (ret)
611 dataLen += size;
613 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
614 bytesNeeded = 1 + lenBytes + dataLen;
615 if (!pbEncoded)
616 *pcbEncoded = bytesNeeded;
617 else
619 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
620 pcbEncoded, bytesNeeded)))
622 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
623 pbEncoded = *(BYTE **)pbEncoded;
624 *pbEncoded++ = ASN_SEQUENCEOF;
625 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
626 pbEncoded += lenBytes;
627 for (i = 0; i < cCRLEntry; i++)
629 DWORD size = dataLen;
631 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], pbEncoded, &size);
632 pbEncoded += size;
633 dataLen -= size;
637 return ret;
640 static BOOL WINAPI CRYPT_AsnEncodeCRLVersion(DWORD dwCertEncodingType,
641 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
642 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
644 const DWORD *ver = (const DWORD *)pvStructInfo;
645 BOOL ret;
647 /* CRL_V1 is not encoded */
648 if (*ver == CRL_V1)
650 *pcbEncoded = 0;
651 ret = TRUE;
653 else
654 ret = CRYPT_AsnEncodeInt(dwCertEncodingType, X509_INTEGER, ver,
655 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
656 return ret;
659 /* Like in Windows, this blithely ignores the validity of the passed-in
660 * CRL_INFO, and just encodes it as-is. The resulting encoded data may not
661 * decode properly, see CRYPT_AsnDecodeCRLInfo.
663 static BOOL WINAPI CRYPT_AsnEncodeCRLInfo(DWORD dwCertEncodingType,
664 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
665 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
667 BOOL ret;
669 __TRY
671 const CRL_INFO *info = (const CRL_INFO *)pvStructInfo;
672 struct AsnEncodeSequenceItem items[7] = {
673 { &info->dwVersion, CRYPT_AsnEncodeCRLVersion, 0 },
674 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
675 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
676 { &info->ThisUpdate, CRYPT_AsnEncodeChoiceOfTime, 0 },
677 { 0 }
679 struct AsnConstructedItem constructed[1] = { { 0 } };
680 DWORD cItem = 4, cConstructed = 0;
682 if (info->NextUpdate.dwLowDateTime || info->NextUpdate.dwHighDateTime)
684 items[cItem].pvStructInfo = &info->NextUpdate;
685 items[cItem].encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
686 cItem++;
688 if (info->cCRLEntry)
690 items[cItem].pvStructInfo = &info->cCRLEntry;
691 items[cItem].encodeFunc = CRYPT_AsnEncodeCRLEntries;
692 cItem++;
694 if (info->cExtension)
696 constructed[cConstructed].tag = 0;
697 constructed[cConstructed].pvStructInfo = &info->cExtension;
698 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions;
699 items[cItem].pvStructInfo = &constructed[cConstructed];
700 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
701 cConstructed++;
702 cItem++;
705 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
706 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
708 __EXCEPT_PAGE_FAULT
710 SetLastError(STATUS_ACCESS_VIOLATION);
711 ret = FALSE;
713 __ENDTRY
714 return ret;
717 static BOOL CRYPT_AsnEncodeExtension(CERT_EXTENSION *ext, BYTE *pbEncoded,
718 DWORD *pcbEncoded)
720 BOOL ret;
721 struct AsnEncodeSequenceItem items[3] = {
722 { ext->pszObjId, CRYPT_AsnEncodeOid, 0 },
723 { NULL, NULL, 0 },
724 { NULL, NULL, 0 },
726 DWORD cItem = 1;
728 TRACE("%p, %p, %d\n", ext, pbEncoded, *pcbEncoded);
730 if (ext->fCritical)
732 items[cItem].pvStructInfo = &ext->fCritical;
733 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
734 cItem++;
736 items[cItem].pvStructInfo = &ext->Value;
737 items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
738 cItem++;
740 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
741 pbEncoded, pcbEncoded);
742 TRACE("returning %d (%08x)\n", ret, GetLastError());
743 return ret;
746 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
747 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
748 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
750 BOOL ret;
752 __TRY
754 DWORD bytesNeeded, dataLen, lenBytes, i;
755 const CERT_EXTENSIONS *exts = (const CERT_EXTENSIONS *)pvStructInfo;
757 ret = TRUE;
758 for (i = 0, dataLen = 0; ret && i < exts->cExtension; i++)
760 DWORD size;
762 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i], NULL, &size);
763 if (ret)
764 dataLen += size;
766 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
767 bytesNeeded = 1 + lenBytes + dataLen;
768 if (!pbEncoded)
769 *pcbEncoded = bytesNeeded;
770 else
772 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
773 pcbEncoded, bytesNeeded)))
775 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
776 pbEncoded = *(BYTE **)pbEncoded;
777 *pbEncoded++ = ASN_SEQUENCEOF;
778 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
779 pbEncoded += lenBytes;
780 for (i = 0; i < exts->cExtension; i++)
782 DWORD size = dataLen;
784 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i],
785 pbEncoded, &size);
786 pbEncoded += size;
787 dataLen -= size;
792 __EXCEPT_PAGE_FAULT
794 SetLastError(STATUS_ACCESS_VIOLATION);
795 ret = FALSE;
797 __ENDTRY
798 return ret;
801 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
802 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
803 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
805 LPCSTR pszObjId = (LPCSTR)pvStructInfo;
806 DWORD bytesNeeded = 0, lenBytes;
807 BOOL ret = TRUE;
808 int firstPos = 0;
809 BYTE firstByte = 0;
811 TRACE("%s\n", debugstr_a(pszObjId));
813 if (pszObjId)
815 const char *ptr;
816 int val1, val2;
818 if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
820 SetLastError(CRYPT_E_ASN1_ERROR);
821 return FALSE;
823 bytesNeeded++;
824 firstByte = val1 * 40 + val2;
825 ptr = pszObjId + firstPos;
826 while (ret && *ptr)
828 int pos;
830 /* note I assume each component is at most 32-bits long in base 2 */
831 if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
833 if (val1 >= 0x10000000)
834 bytesNeeded += 5;
835 else if (val1 >= 0x200000)
836 bytesNeeded += 4;
837 else if (val1 >= 0x4000)
838 bytesNeeded += 3;
839 else if (val1 >= 0x80)
840 bytesNeeded += 2;
841 else
842 bytesNeeded += 1;
843 ptr += pos;
844 if (*ptr == '.')
845 ptr++;
847 else
849 SetLastError(CRYPT_E_ASN1_ERROR);
850 return FALSE;
853 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
855 else
856 lenBytes = 1;
857 bytesNeeded += 1 + lenBytes;
858 if (pbEncoded)
860 if (*pcbEncoded < bytesNeeded)
862 SetLastError(ERROR_MORE_DATA);
863 ret = FALSE;
865 else
867 *pbEncoded++ = ASN_OBJECTIDENTIFIER;
868 CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
869 pbEncoded += lenBytes;
870 if (pszObjId)
872 const char *ptr;
873 int val, pos;
875 *pbEncoded++ = firstByte;
876 ptr = pszObjId + firstPos;
877 while (ret && *ptr)
879 sscanf(ptr, "%d%n", &val, &pos);
881 unsigned char outBytes[5];
882 int numBytes, i;
884 if (val >= 0x10000000)
885 numBytes = 5;
886 else if (val >= 0x200000)
887 numBytes = 4;
888 else if (val >= 0x4000)
889 numBytes = 3;
890 else if (val >= 0x80)
891 numBytes = 2;
892 else
893 numBytes = 1;
894 for (i = numBytes; i > 0; i--)
896 outBytes[i - 1] = val & 0x7f;
897 val >>= 7;
899 for (i = 0; i < numBytes - 1; i++)
900 *pbEncoded++ = outBytes[i] | 0x80;
901 *pbEncoded++ = outBytes[i];
902 ptr += pos;
903 if (*ptr == '.')
904 ptr++;
910 *pcbEncoded = bytesNeeded;
911 return ret;
914 static BOOL CRYPT_AsnEncodeStringCoerce(const CERT_NAME_VALUE *value,
915 BYTE tag, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
916 DWORD *pcbEncoded)
918 BOOL ret = TRUE;
919 LPCSTR str = (LPCSTR)value->Value.pbData;
920 DWORD bytesNeeded, lenBytes, encodedLen;
922 encodedLen = value->Value.cbData ? value->Value.cbData : lstrlenA(str);
923 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
924 bytesNeeded = 1 + lenBytes + encodedLen;
925 if (!pbEncoded)
926 *pcbEncoded = bytesNeeded;
927 else
929 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
930 pbEncoded, pcbEncoded, bytesNeeded)))
932 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
933 pbEncoded = *(BYTE **)pbEncoded;
934 *pbEncoded++ = tag;
935 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
936 pbEncoded += lenBytes;
937 memcpy(pbEncoded, str, encodedLen);
940 return ret;
943 static BOOL CRYPT_AsnEncodeBMPString(const CERT_NAME_VALUE *value,
944 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
945 DWORD *pcbEncoded)
947 BOOL ret = TRUE;
948 LPCWSTR str = (LPCWSTR)value->Value.pbData;
949 DWORD bytesNeeded, lenBytes, strLen;
951 strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
952 lstrlenW(str);
953 CRYPT_EncodeLen(strLen * 2, NULL, &lenBytes);
954 bytesNeeded = 1 + lenBytes + strLen * 2;
955 if (!pbEncoded)
956 *pcbEncoded = bytesNeeded;
957 else
959 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
960 pbEncoded, pcbEncoded, bytesNeeded)))
962 DWORD i;
964 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
965 pbEncoded = *(BYTE **)pbEncoded;
966 *pbEncoded++ = ASN_BMPSTRING;
967 CRYPT_EncodeLen(strLen * 2, pbEncoded, &lenBytes);
968 pbEncoded += lenBytes;
969 for (i = 0; i < strLen; i++)
971 *pbEncoded++ = (str[i] & 0xff00) >> 8;
972 *pbEncoded++ = str[i] & 0x00ff;
976 return ret;
979 static BOOL CRYPT_AsnEncodeUTF8String(const CERT_NAME_VALUE *value,
980 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
981 DWORD *pcbEncoded)
983 BOOL ret = TRUE;
984 LPCWSTR str = (LPCWSTR)value->Value.pbData;
985 DWORD bytesNeeded, lenBytes, encodedLen, strLen;
987 strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
988 lstrlenW(str);
989 encodedLen = WideCharToMultiByte(CP_UTF8, 0, str, strLen, NULL, 0, NULL,
990 NULL);
991 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
992 bytesNeeded = 1 + lenBytes + encodedLen;
993 if (!pbEncoded)
994 *pcbEncoded = bytesNeeded;
995 else
997 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
998 pbEncoded, pcbEncoded, bytesNeeded)))
1000 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1001 pbEncoded = *(BYTE **)pbEncoded;
1002 *pbEncoded++ = ASN_UTF8STRING;
1003 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1004 pbEncoded += lenBytes;
1005 WideCharToMultiByte(CP_UTF8, 0, str, strLen, (LPSTR)pbEncoded,
1006 bytesNeeded - lenBytes - 1, NULL, NULL);
1009 return ret;
1012 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
1013 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1014 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1016 BOOL ret = TRUE;
1018 __TRY
1020 const CERT_NAME_VALUE *value = (const CERT_NAME_VALUE *)pvStructInfo;
1022 switch (value->dwValueType)
1024 case CERT_RDN_ANY_TYPE:
1025 /* explicitly disallowed */
1026 SetLastError(E_INVALIDARG);
1027 ret = FALSE;
1028 break;
1029 case CERT_RDN_ENCODED_BLOB:
1030 ret = CRYPT_CopyEncodedBlob(dwCertEncodingType, NULL,
1031 &value->Value, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1032 break;
1033 case CERT_RDN_OCTET_STRING:
1034 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_OCTETSTRING,
1035 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1036 break;
1037 case CERT_RDN_NUMERIC_STRING:
1038 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_NUMERICSTRING,
1039 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1040 break;
1041 case CERT_RDN_PRINTABLE_STRING:
1042 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_PRINTABLESTRING,
1043 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1044 break;
1045 case CERT_RDN_TELETEX_STRING:
1046 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_T61STRING,
1047 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1048 break;
1049 case CERT_RDN_VIDEOTEX_STRING:
1050 ret = CRYPT_AsnEncodeStringCoerce(value,
1051 ASN_VIDEOTEXSTRING, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1052 break;
1053 case CERT_RDN_IA5_STRING:
1054 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_IA5STRING,
1055 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1056 break;
1057 case CERT_RDN_GRAPHIC_STRING:
1058 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_GRAPHICSTRING,
1059 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1060 break;
1061 case CERT_RDN_VISIBLE_STRING:
1062 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_VISIBLESTRING,
1063 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1064 break;
1065 case CERT_RDN_GENERAL_STRING:
1066 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_GENERALSTRING,
1067 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1068 break;
1069 case CERT_RDN_UNIVERSAL_STRING:
1070 FIXME("CERT_RDN_UNIVERSAL_STRING: unimplemented\n");
1071 SetLastError(CRYPT_E_ASN1_CHOICE);
1072 ret = FALSE;
1073 break;
1074 case CERT_RDN_BMP_STRING:
1075 ret = CRYPT_AsnEncodeBMPString(value, dwFlags, pEncodePara,
1076 pbEncoded, pcbEncoded);
1077 break;
1078 case CERT_RDN_UTF8_STRING:
1079 ret = CRYPT_AsnEncodeUTF8String(value, dwFlags, pEncodePara,
1080 pbEncoded, pcbEncoded);
1081 break;
1082 default:
1083 SetLastError(CRYPT_E_ASN1_CHOICE);
1084 ret = FALSE;
1087 __EXCEPT_PAGE_FAULT
1089 SetLastError(STATUS_ACCESS_VIOLATION);
1090 ret = FALSE;
1092 __ENDTRY
1093 return ret;
1096 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
1097 CERT_RDN_ATTR *attr, CryptEncodeObjectExFunc nameValueEncodeFunc,
1098 BYTE *pbEncoded, DWORD *pcbEncoded)
1100 DWORD bytesNeeded = 0, lenBytes, size;
1101 BOOL ret;
1103 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL, attr->pszObjId,
1104 0, NULL, NULL, &size);
1105 if (ret)
1107 bytesNeeded += size;
1108 /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
1109 * with dwValueType, so "cast" it to get its encoded size
1111 ret = nameValueEncodeFunc(dwCertEncodingType, NULL,
1112 (CERT_NAME_VALUE *)&attr->dwValueType, 0, NULL, NULL, &size);
1113 if (ret)
1115 bytesNeeded += size;
1116 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1117 bytesNeeded += 1 + lenBytes;
1118 if (pbEncoded)
1120 if (*pcbEncoded < bytesNeeded)
1122 SetLastError(ERROR_MORE_DATA);
1123 ret = FALSE;
1125 else
1127 *pbEncoded++ = ASN_SEQUENCE;
1128 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1129 &lenBytes);
1130 pbEncoded += lenBytes;
1131 size = bytesNeeded - 1 - lenBytes;
1132 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
1133 attr->pszObjId, 0, NULL, pbEncoded, &size);
1134 if (ret)
1136 pbEncoded += size;
1137 size = bytesNeeded - 1 - lenBytes - size;
1138 ret = nameValueEncodeFunc(dwCertEncodingType,
1139 NULL, (CERT_NAME_VALUE *)&attr->dwValueType,
1140 0, NULL, pbEncoded, &size);
1141 if (!ret)
1142 *pcbEncoded = size;
1146 if (ret)
1147 *pcbEncoded = bytesNeeded;
1149 else
1151 /* Have to propagate index of failing character */
1152 *pcbEncoded = size;
1155 return ret;
1158 static int BLOBComp(const void *l, const void *r)
1160 const CRYPT_DER_BLOB *a = (const CRYPT_DER_BLOB *)l, *b = (const CRYPT_DER_BLOB *)r;
1161 int ret;
1163 if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
1164 ret = a->cbData - b->cbData;
1165 return ret;
1168 typedef struct _CRYPT_SET_OF {
1169 DWORD cValue;
1170 PCRYPT_DER_BLOB rgValue;
1171 } CRYPT_SET_OF;
1173 /* This encodes a SET OF, which in DER must be lexicographically sorted.
1175 static BOOL WINAPI CRYPT_DEREncodeSet(DWORD dwCertEncodingType,
1176 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1177 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1179 const CRYPT_SET_OF *set = (const CRYPT_SET_OF *)pvStructInfo;
1180 DWORD bytesNeeded = 0, lenBytes, i;
1181 BOOL ret;
1183 for (i = 0; i < set->cValue; i++)
1184 bytesNeeded += set->rgValue[i].cbData;
1185 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1186 bytesNeeded += 1 + lenBytes;
1187 if (!pbEncoded)
1189 *pcbEncoded = bytesNeeded;
1190 ret = TRUE;
1192 else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1193 pbEncoded, pcbEncoded, bytesNeeded)))
1195 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1196 pbEncoded = *(BYTE **)pbEncoded;
1197 qsort(set->rgValue, set->cValue, sizeof(CRYPT_DER_BLOB), BLOBComp);
1198 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
1199 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded, &lenBytes);
1200 pbEncoded += lenBytes;
1201 for (i = 0; ret && i < set->cValue; i++)
1203 memcpy(pbEncoded, set->rgValue[i].pbData, set->rgValue[i].cbData);
1204 pbEncoded += set->rgValue[i].cbData;
1207 return ret;
1210 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
1211 CryptEncodeObjectExFunc nameValueEncodeFunc, BYTE *pbEncoded,
1212 DWORD *pcbEncoded)
1214 BOOL ret;
1215 CRYPT_SET_OF setOf = { 0, NULL };
1217 __TRY
1219 DWORD i;
1221 ret = TRUE;
1222 if (rdn->cRDNAttr)
1224 setOf.cValue = rdn->cRDNAttr;
1225 setOf.rgValue = CryptMemAlloc(rdn->cRDNAttr *
1226 sizeof(CRYPT_DER_BLOB));
1227 if (!setOf.rgValue)
1228 ret = FALSE;
1229 else
1230 memset(setOf.rgValue, 0, setOf.cValue * sizeof(CRYPT_DER_BLOB));
1232 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1234 setOf.rgValue[i].cbData = 0;
1235 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
1236 nameValueEncodeFunc, NULL, &setOf.rgValue[i].cbData);
1237 if (ret)
1239 setOf.rgValue[i].pbData =
1240 CryptMemAlloc(setOf.rgValue[i].cbData);
1241 if (!setOf.rgValue[i].pbData)
1242 ret = FALSE;
1243 else
1244 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
1245 &rdn->rgRDNAttr[i], nameValueEncodeFunc,
1246 setOf.rgValue[i].pbData, &setOf.rgValue[i].cbData);
1248 if (!ret)
1250 /* Have to propagate index of failing character */
1251 *pcbEncoded = setOf.rgValue[i].cbData;
1254 if (ret)
1255 ret = CRYPT_DEREncodeSet(X509_ASN_ENCODING, NULL, &setOf, 0, NULL,
1256 pbEncoded, pcbEncoded);
1257 for (i = 0; i < setOf.cValue; i++)
1258 CryptMemFree(setOf.rgValue[i].pbData);
1260 __EXCEPT_PAGE_FAULT
1262 SetLastError(STATUS_ACCESS_VIOLATION);
1263 ret = FALSE;
1265 __ENDTRY
1266 CryptMemFree(setOf.rgValue);
1267 return ret;
1270 static BOOL WINAPI CRYPT_AsnEncodeUnicodeNameValue(DWORD dwCertEncodingType,
1271 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1272 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
1274 static BOOL WINAPI CRYPT_AsnEncodeOrCopyUnicodeNameValue(
1275 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
1276 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1277 DWORD *pcbEncoded)
1279 const CERT_NAME_VALUE *value = (const CERT_NAME_VALUE *)pvStructInfo;
1280 BOOL ret;
1282 if (value->dwValueType == CERT_RDN_ENCODED_BLOB)
1283 ret = CRYPT_CopyEncodedBlob(dwCertEncodingType, NULL, &value->Value,
1284 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1285 else
1286 ret = CRYPT_AsnEncodeUnicodeNameValue(dwCertEncodingType, NULL, value,
1287 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1288 return ret;
1291 static BOOL WINAPI CRYPT_AsnEncodeUnicodeName(DWORD dwCertEncodingType,
1292 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1293 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1295 BOOL ret = TRUE;
1297 __TRY
1299 const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1300 DWORD bytesNeeded = 0, lenBytes, size, i;
1302 TRACE("encoding name with %d RDNs\n", info->cRDN);
1303 ret = TRUE;
1304 for (i = 0; ret && i < info->cRDN; i++)
1306 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i],
1307 CRYPT_AsnEncodeOrCopyUnicodeNameValue, NULL, &size);
1308 if (ret)
1309 bytesNeeded += size;
1310 else
1311 *pcbEncoded = size;
1313 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1314 bytesNeeded += 1 + lenBytes;
1315 if (ret)
1317 if (!pbEncoded)
1318 *pcbEncoded = bytesNeeded;
1319 else
1321 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1322 pbEncoded, pcbEncoded, bytesNeeded)))
1324 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1325 pbEncoded = *(BYTE **)pbEncoded;
1326 *pbEncoded++ = ASN_SEQUENCEOF;
1327 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1328 &lenBytes);
1329 pbEncoded += lenBytes;
1330 for (i = 0; ret && i < info->cRDN; i++)
1332 size = bytesNeeded;
1333 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1334 &info->rgRDN[i], CRYPT_AsnEncodeOrCopyUnicodeNameValue,
1335 pbEncoded, &size);
1336 if (ret)
1338 pbEncoded += size;
1339 bytesNeeded -= size;
1341 else
1342 *pcbEncoded = size;
1348 __EXCEPT_PAGE_FAULT
1350 SetLastError(STATUS_ACCESS_VIOLATION);
1351 ret = FALSE;
1353 __ENDTRY
1354 return ret;
1357 static BOOL WINAPI CRYPT_AsnEncodePKCSAttribute(DWORD dwCertEncodingType,
1358 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1359 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1361 BOOL ret = FALSE;
1363 __TRY
1365 const CRYPT_ATTRIBUTE *attr = (const CRYPT_ATTRIBUTE *)pvStructInfo;
1367 if (!attr->pszObjId)
1368 SetLastError(E_INVALIDARG);
1369 else
1371 struct AsnEncodeSequenceItem items[2] = {
1372 { attr->pszObjId, CRYPT_AsnEncodeOid, 0 },
1373 { &attr->cValue, CRYPT_DEREncodeSet, 0 },
1376 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
1377 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
1378 pcbEncoded);
1381 __EXCEPT_PAGE_FAULT
1383 SetLastError(STATUS_ACCESS_VIOLATION);
1385 __ENDTRY
1386 return ret;
1389 static BOOL WINAPI CRYPT_AsnEncodePKCSAttributes(DWORD dwCertEncodingType,
1390 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1391 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1393 BOOL ret = FALSE;
1394 CRYPT_SET_OF setOf = { 0, NULL };
1396 __TRY
1398 DWORD i;
1399 const CRYPT_ATTRIBUTES *attributes =
1400 (const CRYPT_ATTRIBUTES *)pvStructInfo;
1402 ret = TRUE;
1403 if (attributes->cAttr)
1405 setOf.cValue = attributes->cAttr;
1406 setOf.rgValue = CryptMemAlloc(attributes->cAttr *
1407 sizeof(CRYPT_DER_BLOB));
1408 if (!setOf.rgValue)
1409 ret = FALSE;
1410 else
1411 memset(setOf.rgValue, 0, setOf.cValue * sizeof(CRYPT_DER_BLOB));
1413 for (i = 0; ret && i < attributes->cAttr; i++)
1415 ret = CRYPT_AsnEncodePKCSAttribute(dwCertEncodingType, NULL,
1416 &attributes->rgAttr[i], 0, NULL, NULL, &setOf.rgValue[i].cbData);
1417 if (ret)
1419 setOf.rgValue[i].pbData =
1420 CryptMemAlloc(setOf.rgValue[i].cbData);
1421 if (!setOf.rgValue[i].pbData)
1422 ret = FALSE;
1423 else
1425 ret = CRYPT_AsnEncodePKCSAttribute(dwCertEncodingType, NULL,
1426 &attributes->rgAttr[i], 0, NULL, setOf.rgValue[i].pbData,
1427 &setOf.rgValue[i].cbData);
1431 if (ret)
1432 ret = CRYPT_DEREncodeSet(X509_ASN_ENCODING, NULL, &setOf, dwFlags,
1433 pEncodePara, pbEncoded, pcbEncoded);
1434 for (i = 0; i < setOf.cValue; i++)
1435 CryptMemFree(setOf.rgValue[i].pbData);
1437 __EXCEPT_PAGE_FAULT
1439 SetLastError(STATUS_ACCESS_VIOLATION);
1441 __ENDTRY
1442 CryptMemFree(setOf.rgValue);
1443 return ret;
1446 static BOOL WINAPI CRYPT_AsnEncodePKCSContentInfo(DWORD dwCertEncodingType,
1447 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1448 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1450 BOOL ret = FALSE;
1452 __TRY
1454 const CRYPT_CONTENT_INFO *info =
1455 (const CRYPT_CONTENT_INFO *)pvStructInfo;
1457 if (!info->pszObjId)
1458 SetLastError(E_INVALIDARG);
1459 else
1461 struct AsnEncodeSequenceItem items[2] = {
1462 { info->pszObjId, CRYPT_AsnEncodeOid, 0 },
1463 { NULL, NULL, 0 },
1465 struct AsnConstructedItem constructed = { 0 };
1466 DWORD cItem = 1;
1468 if (info->Content.cbData)
1470 constructed.tag = 0;
1471 constructed.pvStructInfo = &info->Content;
1472 constructed.encodeFunc = CRYPT_CopyEncodedBlob;
1473 items[cItem].pvStructInfo = &constructed;
1474 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
1475 cItem++;
1477 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
1478 cItem, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1482 __EXCEPT_PAGE_FAULT
1484 SetLastError(STATUS_ACCESS_VIOLATION);
1486 __ENDTRY
1487 return ret;
1490 static BOOL CRYPT_AsnEncodeUnicodeStringCoerce(const CERT_NAME_VALUE *value,
1491 BYTE tag, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1492 DWORD *pcbEncoded)
1494 BOOL ret = TRUE;
1495 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1496 DWORD bytesNeeded, lenBytes, encodedLen;
1498 encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1499 lstrlenW(str);
1500 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1501 bytesNeeded = 1 + lenBytes + encodedLen;
1502 if (!pbEncoded)
1503 *pcbEncoded = bytesNeeded;
1504 else
1506 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1507 pbEncoded, pcbEncoded, bytesNeeded)))
1509 DWORD i;
1511 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1512 pbEncoded = *(BYTE **)pbEncoded;
1513 *pbEncoded++ = tag;
1514 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1515 pbEncoded += lenBytes;
1516 for (i = 0; i < encodedLen; i++)
1517 *pbEncoded++ = (BYTE)str[i];
1520 return ret;
1523 static BOOL CRYPT_AsnEncodeNumericString(const CERT_NAME_VALUE *value,
1524 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1525 DWORD *pcbEncoded)
1527 BOOL ret = TRUE;
1528 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1529 DWORD bytesNeeded, lenBytes, encodedLen;
1531 encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1532 lstrlenW(str);
1533 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1534 bytesNeeded = 1 + lenBytes + encodedLen;
1535 if (!pbEncoded)
1536 *pcbEncoded = bytesNeeded;
1537 else
1539 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1540 pbEncoded, pcbEncoded, bytesNeeded)))
1542 DWORD i;
1544 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1545 pbEncoded = *(BYTE **)pbEncoded;
1546 *pbEncoded++ = ASN_NUMERICSTRING;
1547 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1548 pbEncoded += lenBytes;
1549 for (i = 0; ret && i < encodedLen; i++)
1551 if (isdigitW(str[i]))
1552 *pbEncoded++ = (BYTE)str[i];
1553 else
1555 *pcbEncoded = i;
1556 SetLastError(CRYPT_E_INVALID_NUMERIC_STRING);
1557 ret = FALSE;
1562 return ret;
1565 static inline int isprintableW(WCHAR wc)
1567 return isalnumW(wc) || isspaceW(wc) || wc == '\'' || wc == '(' ||
1568 wc == ')' || wc == '+' || wc == ',' || wc == '-' || wc == '.' ||
1569 wc == '/' || wc == ':' || wc == '=' || wc == '?';
1572 static BOOL CRYPT_AsnEncodePrintableString(const CERT_NAME_VALUE *value,
1573 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1574 DWORD *pcbEncoded)
1576 BOOL ret = TRUE;
1577 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1578 DWORD bytesNeeded, lenBytes, encodedLen;
1580 encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1581 lstrlenW(str);
1582 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1583 bytesNeeded = 1 + lenBytes + encodedLen;
1584 if (!pbEncoded)
1585 *pcbEncoded = bytesNeeded;
1586 else
1588 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1589 pbEncoded, pcbEncoded, bytesNeeded)))
1591 DWORD i;
1593 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1594 pbEncoded = *(BYTE **)pbEncoded;
1595 *pbEncoded++ = ASN_PRINTABLESTRING;
1596 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1597 pbEncoded += lenBytes;
1598 for (i = 0; ret && i < encodedLen; i++)
1600 if (isprintableW(str[i]))
1601 *pbEncoded++ = (BYTE)str[i];
1602 else
1604 *pcbEncoded = i;
1605 SetLastError(CRYPT_E_INVALID_PRINTABLE_STRING);
1606 ret = FALSE;
1611 return ret;
1614 static BOOL CRYPT_AsnEncodeIA5String(const CERT_NAME_VALUE *value,
1615 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1616 DWORD *pcbEncoded)
1618 BOOL ret = TRUE;
1619 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1620 DWORD bytesNeeded, lenBytes, encodedLen;
1622 encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1623 lstrlenW(str);
1624 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1625 bytesNeeded = 1 + lenBytes + encodedLen;
1626 if (!pbEncoded)
1627 *pcbEncoded = bytesNeeded;
1628 else
1630 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1631 pbEncoded, pcbEncoded, bytesNeeded)))
1633 DWORD i;
1635 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1636 pbEncoded = *(BYTE **)pbEncoded;
1637 *pbEncoded++ = ASN_IA5STRING;
1638 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1639 pbEncoded += lenBytes;
1640 for (i = 0; ret && i < encodedLen; i++)
1642 if (str[i] <= 0x7f)
1643 *pbEncoded++ = (BYTE)str[i];
1644 else
1646 *pcbEncoded = i;
1647 SetLastError(CRYPT_E_INVALID_IA5_STRING);
1648 ret = FALSE;
1653 return ret;
1656 static BOOL CRYPT_AsnEncodeUniversalString(const CERT_NAME_VALUE *value,
1657 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1658 DWORD *pcbEncoded)
1660 BOOL ret = TRUE;
1661 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1662 DWORD bytesNeeded, lenBytes, strLen;
1664 /* FIXME: doesn't handle composite characters */
1665 strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1666 lstrlenW(str);
1667 CRYPT_EncodeLen(strLen * 4, NULL, &lenBytes);
1668 bytesNeeded = 1 + lenBytes + strLen * 4;
1669 if (!pbEncoded)
1670 *pcbEncoded = bytesNeeded;
1671 else
1673 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1674 pbEncoded, pcbEncoded, bytesNeeded)))
1676 DWORD i;
1678 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1679 pbEncoded = *(BYTE **)pbEncoded;
1680 *pbEncoded++ = ASN_UNIVERSALSTRING;
1681 CRYPT_EncodeLen(strLen * 4, pbEncoded, &lenBytes);
1682 pbEncoded += lenBytes;
1683 for (i = 0; i < strLen; i++)
1685 *pbEncoded++ = 0;
1686 *pbEncoded++ = 0;
1687 *pbEncoded++ = (BYTE)((str[i] & 0xff00) >> 8);
1688 *pbEncoded++ = (BYTE)(str[i] & 0x00ff);
1692 return ret;
1695 static BOOL WINAPI CRYPT_AsnEncodeUnicodeNameValue(DWORD dwCertEncodingType,
1696 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1697 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1699 BOOL ret = FALSE;
1701 __TRY
1703 const CERT_NAME_VALUE *value = (const CERT_NAME_VALUE *)pvStructInfo;
1705 switch (value->dwValueType)
1707 case CERT_RDN_ANY_TYPE:
1708 case CERT_RDN_ENCODED_BLOB:
1709 case CERT_RDN_OCTET_STRING:
1710 SetLastError(CRYPT_E_NOT_CHAR_STRING);
1711 break;
1712 case CERT_RDN_NUMERIC_STRING:
1713 ret = CRYPT_AsnEncodeNumericString(value, dwFlags, pEncodePara,
1714 pbEncoded, pcbEncoded);
1715 break;
1716 case CERT_RDN_PRINTABLE_STRING:
1717 ret = CRYPT_AsnEncodePrintableString(value, dwFlags, pEncodePara,
1718 pbEncoded, pcbEncoded);
1719 break;
1720 case CERT_RDN_TELETEX_STRING:
1721 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_T61STRING,
1722 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1723 break;
1724 case CERT_RDN_VIDEOTEX_STRING:
1725 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value,
1726 ASN_VIDEOTEXSTRING, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1727 break;
1728 case CERT_RDN_IA5_STRING:
1729 ret = CRYPT_AsnEncodeIA5String(value, dwFlags, pEncodePara,
1730 pbEncoded, pcbEncoded);
1731 break;
1732 case CERT_RDN_GRAPHIC_STRING:
1733 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_GRAPHICSTRING,
1734 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1735 break;
1736 case CERT_RDN_VISIBLE_STRING:
1737 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_VISIBLESTRING,
1738 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1739 break;
1740 case CERT_RDN_GENERAL_STRING:
1741 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_GENERALSTRING,
1742 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1743 break;
1744 case CERT_RDN_UNIVERSAL_STRING:
1745 ret = CRYPT_AsnEncodeUniversalString(value, dwFlags, pEncodePara,
1746 pbEncoded, pcbEncoded);
1747 break;
1748 case CERT_RDN_BMP_STRING:
1749 ret = CRYPT_AsnEncodeBMPString(value, dwFlags, pEncodePara,
1750 pbEncoded, pcbEncoded);
1751 break;
1752 case CERT_RDN_UTF8_STRING:
1753 ret = CRYPT_AsnEncodeUTF8String(value, dwFlags, pEncodePara,
1754 pbEncoded, pcbEncoded);
1755 break;
1756 default:
1757 SetLastError(CRYPT_E_ASN1_CHOICE);
1760 __EXCEPT_PAGE_FAULT
1762 SetLastError(STATUS_ACCESS_VIOLATION);
1764 __ENDTRY
1765 return ret;
1768 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
1769 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1770 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1772 BOOL ret;
1774 __TRY
1776 const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1777 DWORD bytesNeeded = 0, lenBytes, size, i;
1779 TRACE("encoding name with %d RDNs\n", info->cRDN);
1780 ret = TRUE;
1781 for (i = 0; ret && i < info->cRDN; i++)
1783 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i],
1784 CRYPT_AsnEncodeNameValue, NULL, &size);
1785 if (ret)
1786 bytesNeeded += size;
1788 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1789 bytesNeeded += 1 + lenBytes;
1790 if (ret)
1792 if (!pbEncoded)
1793 *pcbEncoded = bytesNeeded;
1794 else
1796 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1797 pbEncoded, pcbEncoded, bytesNeeded)))
1799 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1800 pbEncoded = *(BYTE **)pbEncoded;
1801 *pbEncoded++ = ASN_SEQUENCEOF;
1802 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1803 &lenBytes);
1804 pbEncoded += lenBytes;
1805 for (i = 0; ret && i < info->cRDN; i++)
1807 size = bytesNeeded;
1808 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1809 &info->rgRDN[i], CRYPT_AsnEncodeNameValue, pbEncoded,
1810 &size);
1811 if (ret)
1813 pbEncoded += size;
1814 bytesNeeded -= size;
1821 __EXCEPT_PAGE_FAULT
1823 SetLastError(STATUS_ACCESS_VIOLATION);
1824 ret = FALSE;
1826 __ENDTRY
1827 return ret;
1830 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1831 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1832 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1834 BOOL val = *(const BOOL *)pvStructInfo, ret;
1836 TRACE("%d\n", val);
1838 if (!pbEncoded)
1840 *pcbEncoded = 3;
1841 ret = TRUE;
1843 else if (*pcbEncoded < 3)
1845 *pcbEncoded = 3;
1846 SetLastError(ERROR_MORE_DATA);
1847 ret = FALSE;
1849 else
1851 *pcbEncoded = 3;
1852 *pbEncoded++ = ASN_BOOL;
1853 *pbEncoded++ = 1;
1854 *pbEncoded++ = val ? 0xff : 0;
1855 ret = TRUE;
1857 TRACE("returning %d (%08x)\n", ret, GetLastError());
1858 return ret;
1861 static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry,
1862 BYTE *pbEncoded, DWORD *pcbEncoded)
1864 BOOL ret;
1865 DWORD dataLen;
1867 ret = TRUE;
1868 switch (entry->dwAltNameChoice)
1870 case CERT_ALT_NAME_RFC822_NAME:
1871 case CERT_ALT_NAME_DNS_NAME:
1872 case CERT_ALT_NAME_URL:
1873 if (entry->u.pwszURL)
1875 DWORD i;
1877 /* Not + 1: don't encode the NULL-terminator */
1878 dataLen = lstrlenW(entry->u.pwszURL);
1879 for (i = 0; ret && i < dataLen; i++)
1881 if (entry->u.pwszURL[i] > 0x7f)
1883 SetLastError(CRYPT_E_INVALID_IA5_STRING);
1884 ret = FALSE;
1885 *pcbEncoded = i;
1889 else
1890 dataLen = 0;
1891 break;
1892 case CERT_ALT_NAME_IP_ADDRESS:
1893 dataLen = entry->u.IPAddress.cbData;
1894 break;
1895 case CERT_ALT_NAME_REGISTERED_ID:
1896 /* FIXME: encode OID */
1897 case CERT_ALT_NAME_OTHER_NAME:
1898 case CERT_ALT_NAME_DIRECTORY_NAME:
1899 FIXME("name type %d unimplemented\n", entry->dwAltNameChoice);
1900 return FALSE;
1901 default:
1902 SetLastError(E_INVALIDARG);
1903 return FALSE;
1905 if (ret)
1907 DWORD bytesNeeded, lenBytes;
1909 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1910 bytesNeeded = 1 + dataLen + lenBytes;
1911 if (!pbEncoded)
1912 *pcbEncoded = bytesNeeded;
1913 else if (*pcbEncoded < bytesNeeded)
1915 SetLastError(ERROR_MORE_DATA);
1916 *pcbEncoded = bytesNeeded;
1917 ret = FALSE;
1919 else
1921 *pbEncoded++ = ASN_CONTEXT | (entry->dwAltNameChoice - 1);
1922 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1923 pbEncoded += lenBytes;
1924 switch (entry->dwAltNameChoice)
1926 case CERT_ALT_NAME_RFC822_NAME:
1927 case CERT_ALT_NAME_DNS_NAME:
1928 case CERT_ALT_NAME_URL:
1930 DWORD i;
1932 for (i = 0; i < dataLen; i++)
1933 *pbEncoded++ = (BYTE)entry->u.pwszURL[i];
1934 break;
1936 case CERT_ALT_NAME_IP_ADDRESS:
1937 memcpy(pbEncoded, entry->u.IPAddress.pbData, dataLen);
1938 break;
1940 if (ret)
1941 *pcbEncoded = bytesNeeded;
1944 TRACE("returning %d (%08x)\n", ret, GetLastError());
1945 return ret;
1948 static BOOL WINAPI CRYPT_AsnEncodeAuthorityKeyId(DWORD dwCertEncodingType,
1949 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1950 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1952 BOOL ret;
1954 __TRY
1956 const CERT_AUTHORITY_KEY_ID_INFO *info =
1957 (const CERT_AUTHORITY_KEY_ID_INFO *)pvStructInfo;
1958 struct AsnEncodeSequenceItem items[3] = { { 0 } };
1959 struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
1960 struct AsnConstructedItem constructed = { 0 };
1961 DWORD cItem = 0, cSwapped = 0;
1963 if (info->KeyId.cbData)
1965 swapped[cSwapped].tag = ASN_CONTEXT | 0;
1966 swapped[cSwapped].pvStructInfo = &info->KeyId;
1967 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
1968 items[cItem].pvStructInfo = &swapped[cSwapped];
1969 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
1970 cSwapped++;
1971 cItem++;
1973 if (info->CertIssuer.cbData)
1975 constructed.tag = 1;
1976 constructed.pvStructInfo = &info->CertIssuer;
1977 constructed.encodeFunc = CRYPT_CopyEncodedBlob;
1978 items[cItem].pvStructInfo = &constructed;
1979 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
1980 cItem++;
1982 if (info->CertSerialNumber.cbData)
1984 swapped[cSwapped].tag = ASN_CONTEXT | 2;
1985 swapped[cSwapped].pvStructInfo = &info->CertSerialNumber;
1986 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
1987 items[cItem].pvStructInfo = &swapped[cSwapped];
1988 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
1989 cSwapped++;
1990 cItem++;
1992 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, dwFlags,
1993 pEncodePara, pbEncoded, pcbEncoded);
1995 __EXCEPT_PAGE_FAULT
1997 SetLastError(STATUS_ACCESS_VIOLATION);
1998 ret = FALSE;
2000 __ENDTRY
2001 return ret;
2004 static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
2005 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2006 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2008 BOOL ret;
2010 __TRY
2012 const CERT_ALT_NAME_INFO *info =
2013 (const CERT_ALT_NAME_INFO *)pvStructInfo;
2014 DWORD bytesNeeded, dataLen, lenBytes, i;
2016 ret = TRUE;
2017 /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
2018 * can't encode an erroneous entry index if it's bigger than this.
2020 for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
2022 DWORD len;
2024 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i], NULL,
2025 &len);
2026 if (ret)
2027 dataLen += len;
2028 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
2030 /* CRYPT_AsnEncodeAltNameEntry encoded the index of
2031 * the bad character, now set the index of the bad
2032 * entry
2034 *pcbEncoded = (BYTE)i <<
2035 CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT | len;
2038 if (ret)
2040 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2041 bytesNeeded = 1 + lenBytes + dataLen;
2042 if (!pbEncoded)
2044 *pcbEncoded = bytesNeeded;
2045 ret = TRUE;
2047 else
2049 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2050 pbEncoded, pcbEncoded, bytesNeeded)))
2052 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2053 pbEncoded = *(BYTE **)pbEncoded;
2054 *pbEncoded++ = ASN_SEQUENCEOF;
2055 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2056 pbEncoded += lenBytes;
2057 for (i = 0; ret && i < info->cAltEntry; i++)
2059 DWORD len = dataLen;
2061 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i],
2062 pbEncoded, &len);
2063 if (ret)
2065 pbEncoded += len;
2066 dataLen -= len;
2073 __EXCEPT_PAGE_FAULT
2075 SetLastError(STATUS_ACCESS_VIOLATION);
2076 ret = FALSE;
2078 __ENDTRY
2079 return ret;
2082 static BOOL WINAPI CRYPT_AsnEncodeAuthorityKeyId2(DWORD dwCertEncodingType,
2083 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2084 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2086 BOOL ret;
2088 __TRY
2090 const CERT_AUTHORITY_KEY_ID2_INFO *info =
2091 (const CERT_AUTHORITY_KEY_ID2_INFO *)pvStructInfo;
2092 struct AsnEncodeSequenceItem items[3] = { { 0 } };
2093 struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2094 DWORD cItem = 0, cSwapped = 0;
2096 if (info->KeyId.cbData)
2098 swapped[cSwapped].tag = ASN_CONTEXT | 0;
2099 swapped[cSwapped].pvStructInfo = &info->KeyId;
2100 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
2101 items[cItem].pvStructInfo = &swapped[cSwapped];
2102 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2103 cSwapped++;
2104 cItem++;
2106 if (info->AuthorityCertIssuer.cAltEntry)
2108 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 1;
2109 swapped[cSwapped].pvStructInfo = &info->AuthorityCertIssuer;
2110 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2111 items[cItem].pvStructInfo = &swapped[cSwapped];
2112 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2113 cSwapped++;
2114 cItem++;
2116 if (info->AuthorityCertSerialNumber.cbData)
2118 swapped[cSwapped].tag = ASN_CONTEXT | 2;
2119 swapped[cSwapped].pvStructInfo = &info->AuthorityCertSerialNumber;
2120 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
2121 items[cItem].pvStructInfo = &swapped[cSwapped];
2122 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2123 cSwapped++;
2124 cItem++;
2126 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, dwFlags,
2127 pEncodePara, pbEncoded, pcbEncoded);
2129 __EXCEPT_PAGE_FAULT
2131 SetLastError(STATUS_ACCESS_VIOLATION);
2132 ret = FALSE;
2134 __ENDTRY
2135 return ret;
2138 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints(DWORD dwCertEncodingType,
2139 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2140 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2142 BOOL ret;
2144 __TRY
2146 const CERT_BASIC_CONSTRAINTS_INFO *info =
2147 (const CERT_BASIC_CONSTRAINTS_INFO *)pvStructInfo;
2148 struct AsnEncodeSequenceItem items[3] = {
2149 { &info->SubjectType, CRYPT_AsnEncodeBits, 0 },
2150 { 0 }
2152 DWORD cItem = 1;
2154 if (info->fPathLenConstraint)
2156 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
2157 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
2158 cItem++;
2160 if (info->cSubtreesConstraint)
2162 items[cItem].pvStructInfo = &info->cSubtreesConstraint;
2163 items[cItem].encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
2164 cItem++;
2166 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
2167 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2169 __EXCEPT_PAGE_FAULT
2171 SetLastError(STATUS_ACCESS_VIOLATION);
2172 ret = FALSE;
2174 __ENDTRY
2175 return ret;
2178 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
2179 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2180 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2182 BOOL ret;
2184 __TRY
2186 const CERT_BASIC_CONSTRAINTS2_INFO *info =
2187 (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
2188 struct AsnEncodeSequenceItem items[2] = { { 0 } };
2189 DWORD cItem = 0;
2191 if (info->fCA)
2193 items[cItem].pvStructInfo = &info->fCA;
2194 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
2195 cItem++;
2197 if (info->fPathLenConstraint)
2199 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
2200 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
2201 cItem++;
2203 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
2204 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2206 __EXCEPT_PAGE_FAULT
2208 SetLastError(STATUS_ACCESS_VIOLATION);
2209 ret = FALSE;
2211 __ENDTRY
2212 return ret;
2215 static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
2216 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2217 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2219 BOOL ret;
2221 __TRY
2223 const BLOBHEADER *hdr =
2224 (const BLOBHEADER *)pvStructInfo;
2226 if (hdr->bType != PUBLICKEYBLOB)
2228 SetLastError(E_INVALIDARG);
2229 ret = FALSE;
2231 else
2233 const RSAPUBKEY *rsaPubKey = (const RSAPUBKEY *)
2234 ((const BYTE *)pvStructInfo + sizeof(BLOBHEADER));
2235 CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8,
2236 (BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) };
2237 struct AsnEncodeSequenceItem items[] = {
2238 { &blob, CRYPT_AsnEncodeUnsignedInteger, 0 },
2239 { &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 },
2242 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
2243 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
2244 pcbEncoded);
2247 __EXCEPT_PAGE_FAULT
2249 SetLastError(STATUS_ACCESS_VIOLATION);
2250 ret = FALSE;
2252 __ENDTRY
2253 return ret;
2256 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
2257 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2258 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2260 BOOL ret;
2262 __TRY
2264 const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
2265 DWORD bytesNeeded, lenBytes;
2267 TRACE("(%d, %p), %08x, %p, %p, %d\n", blob->cbData, blob->pbData,
2268 dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
2270 CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
2271 bytesNeeded = 1 + lenBytes + blob->cbData;
2272 if (!pbEncoded)
2274 *pcbEncoded = bytesNeeded;
2275 ret = TRUE;
2277 else
2279 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2280 pcbEncoded, bytesNeeded)))
2282 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2283 pbEncoded = *(BYTE **)pbEncoded;
2284 *pbEncoded++ = ASN_OCTETSTRING;
2285 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
2286 pbEncoded += lenBytes;
2287 if (blob->cbData)
2288 memcpy(pbEncoded, blob->pbData, blob->cbData);
2292 __EXCEPT_PAGE_FAULT
2294 SetLastError(STATUS_ACCESS_VIOLATION);
2295 ret = FALSE;
2297 __ENDTRY
2298 TRACE("returning %d (%08x)\n", ret, GetLastError());
2299 return ret;
2302 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
2303 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2304 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2306 BOOL ret;
2308 __TRY
2310 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
2311 DWORD bytesNeeded, lenBytes, dataBytes;
2312 BYTE unusedBits;
2314 /* yep, MS allows cUnusedBits to be >= 8 */
2315 if (!blob->cUnusedBits)
2317 dataBytes = blob->cbData;
2318 unusedBits = 0;
2320 else if (blob->cbData * 8 > blob->cUnusedBits)
2322 dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
2323 unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
2324 blob->cUnusedBits;
2326 else
2328 dataBytes = 0;
2329 unusedBits = 0;
2331 CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
2332 bytesNeeded = 1 + lenBytes + dataBytes + 1;
2333 if (!pbEncoded)
2335 *pcbEncoded = bytesNeeded;
2336 ret = TRUE;
2338 else
2340 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2341 pcbEncoded, bytesNeeded)))
2343 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2344 pbEncoded = *(BYTE **)pbEncoded;
2345 *pbEncoded++ = ASN_BITSTRING;
2346 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
2347 pbEncoded += lenBytes;
2348 *pbEncoded++ = unusedBits;
2349 if (dataBytes)
2351 BYTE mask = 0xff << unusedBits;
2353 if (dataBytes > 1)
2355 memcpy(pbEncoded, blob->pbData, dataBytes - 1);
2356 pbEncoded += dataBytes - 1;
2358 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
2363 __EXCEPT_PAGE_FAULT
2365 SetLastError(STATUS_ACCESS_VIOLATION);
2366 ret = FALSE;
2368 __ENDTRY
2369 return ret;
2372 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
2373 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2374 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2376 BOOL ret;
2378 __TRY
2380 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
2381 CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
2383 ret = TRUE;
2384 if (newBlob.cbData)
2386 newBlob.pbData = CryptMemAlloc(newBlob.cbData);
2387 if (newBlob.pbData)
2389 DWORD i;
2391 for (i = 0; i < newBlob.cbData; i++)
2392 newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
2394 else
2395 ret = FALSE;
2397 if (ret)
2398 ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
2399 &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2400 CryptMemFree(newBlob.pbData);
2402 __EXCEPT_PAGE_FAULT
2404 SetLastError(STATUS_ACCESS_VIOLATION);
2405 ret = FALSE;
2407 __ENDTRY
2408 return ret;
2411 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
2412 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2413 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2415 CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
2417 return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
2418 &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2421 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
2422 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2423 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2425 BOOL ret;
2427 __TRY
2429 DWORD significantBytes, lenBytes;
2430 BYTE padByte = 0, bytesNeeded;
2431 BOOL pad = FALSE;
2432 const CRYPT_INTEGER_BLOB *blob =
2433 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
2435 significantBytes = blob->cbData;
2436 if (significantBytes)
2438 if (blob->pbData[significantBytes - 1] & 0x80)
2440 /* negative, lop off leading (little-endian) 0xffs */
2441 for (; significantBytes > 0 &&
2442 blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
2444 if (blob->pbData[significantBytes - 1] < 0x80)
2446 padByte = 0xff;
2447 pad = TRUE;
2450 else
2452 /* positive, lop off leading (little-endian) zeroes */
2453 for (; significantBytes > 0 &&
2454 !blob->pbData[significantBytes - 1]; significantBytes--)
2456 if (significantBytes == 0)
2457 significantBytes = 1;
2458 if (blob->pbData[significantBytes - 1] > 0x7f)
2460 padByte = 0;
2461 pad = TRUE;
2465 if (pad)
2466 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2467 else
2468 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2469 bytesNeeded = 1 + lenBytes + significantBytes;
2470 if (pad)
2471 bytesNeeded++;
2472 if (!pbEncoded)
2474 *pcbEncoded = bytesNeeded;
2475 ret = TRUE;
2477 else
2479 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2480 pcbEncoded, bytesNeeded)))
2482 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2483 pbEncoded = *(BYTE **)pbEncoded;
2484 *pbEncoded++ = ASN_INTEGER;
2485 if (pad)
2487 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2488 pbEncoded += lenBytes;
2489 *pbEncoded++ = padByte;
2491 else
2493 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2494 pbEncoded += lenBytes;
2496 for (; significantBytes > 0; significantBytes--)
2497 *(pbEncoded++) = blob->pbData[significantBytes - 1];
2501 __EXCEPT_PAGE_FAULT
2503 SetLastError(STATUS_ACCESS_VIOLATION);
2504 ret = FALSE;
2506 __ENDTRY
2507 return ret;
2510 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
2511 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2512 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2514 BOOL ret;
2516 __TRY
2518 DWORD significantBytes, lenBytes;
2519 BYTE bytesNeeded;
2520 BOOL pad = FALSE;
2521 const CRYPT_INTEGER_BLOB *blob =
2522 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
2524 significantBytes = blob->cbData;
2525 if (significantBytes)
2527 /* positive, lop off leading (little-endian) zeroes */
2528 for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
2529 significantBytes--)
2531 if (significantBytes == 0)
2532 significantBytes = 1;
2533 if (blob->pbData[significantBytes - 1] > 0x7f)
2534 pad = TRUE;
2536 if (pad)
2537 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2538 else
2539 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2540 bytesNeeded = 1 + lenBytes + significantBytes;
2541 if (pad)
2542 bytesNeeded++;
2543 if (!pbEncoded)
2545 *pcbEncoded = bytesNeeded;
2546 ret = TRUE;
2548 else
2550 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2551 pcbEncoded, bytesNeeded)))
2553 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2554 pbEncoded = *(BYTE **)pbEncoded;
2555 *pbEncoded++ = ASN_INTEGER;
2556 if (pad)
2558 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2559 pbEncoded += lenBytes;
2560 *pbEncoded++ = 0;
2562 else
2564 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2565 pbEncoded += lenBytes;
2567 for (; significantBytes > 0; significantBytes--)
2568 *(pbEncoded++) = blob->pbData[significantBytes - 1];
2572 __EXCEPT_PAGE_FAULT
2574 SetLastError(STATUS_ACCESS_VIOLATION);
2575 ret = FALSE;
2577 __ENDTRY
2578 return ret;
2581 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
2582 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2583 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2585 CRYPT_INTEGER_BLOB blob;
2586 BOOL ret;
2588 /* Encode as an unsigned integer, then change the tag to enumerated */
2589 blob.cbData = sizeof(DWORD);
2590 blob.pbData = (BYTE *)pvStructInfo;
2591 ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
2592 X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2593 if (ret && pbEncoded)
2595 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2596 pbEncoded = *(BYTE **)pbEncoded;
2597 pbEncoded[0] = ASN_ENUMERATED;
2599 return ret;
2602 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
2603 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2604 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2606 BOOL ret;
2608 __TRY
2610 SYSTEMTIME sysTime;
2611 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
2612 * temporary buffer because the output buffer is not NULL-terminated.
2614 char buf[16];
2615 static const DWORD bytesNeeded = sizeof(buf) - 1;
2617 if (!pbEncoded)
2619 *pcbEncoded = bytesNeeded;
2620 ret = TRUE;
2622 else
2624 /* Sanity check the year, this is a two-digit year format */
2625 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2626 &sysTime);
2627 if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
2629 SetLastError(CRYPT_E_BAD_ENCODE);
2630 ret = FALSE;
2632 if (ret)
2634 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2635 pbEncoded, pcbEncoded, bytesNeeded)))
2637 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2638 pbEncoded = *(BYTE **)pbEncoded;
2639 buf[0] = ASN_UTCTIME;
2640 buf[1] = bytesNeeded - 2;
2641 snprintf(buf + 2, sizeof(buf) - 2,
2642 "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
2643 sysTime.wYear - 2000 : sysTime.wYear - 1900,
2644 sysTime.wMonth, sysTime.wDay, sysTime.wHour,
2645 sysTime.wMinute, sysTime.wSecond);
2646 memcpy(pbEncoded, buf, bytesNeeded);
2651 __EXCEPT_PAGE_FAULT
2653 SetLastError(STATUS_ACCESS_VIOLATION);
2654 ret = FALSE;
2656 __ENDTRY
2657 return ret;
2660 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
2661 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2662 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2664 BOOL ret;
2666 __TRY
2668 SYSTEMTIME sysTime;
2669 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
2670 * temporary buffer because the output buffer is not NULL-terminated.
2672 char buf[18];
2673 static const DWORD bytesNeeded = sizeof(buf) - 1;
2675 if (!pbEncoded)
2677 *pcbEncoded = bytesNeeded;
2678 ret = TRUE;
2680 else
2682 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2683 &sysTime);
2684 if (ret)
2685 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2686 pcbEncoded, bytesNeeded);
2687 if (ret)
2689 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2690 pbEncoded = *(BYTE **)pbEncoded;
2691 buf[0] = ASN_GENERALTIME;
2692 buf[1] = bytesNeeded - 2;
2693 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
2694 sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour,
2695 sysTime.wMinute, sysTime.wSecond);
2696 memcpy(pbEncoded, buf, bytesNeeded);
2700 __EXCEPT_PAGE_FAULT
2702 SetLastError(STATUS_ACCESS_VIOLATION);
2703 ret = FALSE;
2705 __ENDTRY
2706 return ret;
2709 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
2710 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2711 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2713 BOOL ret;
2715 __TRY
2717 SYSTEMTIME sysTime;
2719 /* Check the year, if it's in the UTCTime range call that encode func */
2720 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
2721 return FALSE;
2722 if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
2723 ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
2724 pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2725 else
2726 ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
2727 lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
2728 pcbEncoded);
2730 __EXCEPT_PAGE_FAULT
2732 SetLastError(STATUS_ACCESS_VIOLATION);
2733 ret = FALSE;
2735 __ENDTRY
2736 return ret;
2739 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
2740 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2741 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2743 BOOL ret;
2745 __TRY
2747 DWORD bytesNeeded, dataLen, lenBytes, i;
2748 const CRYPT_SEQUENCE_OF_ANY *seq =
2749 (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
2751 for (i = 0, dataLen = 0; i < seq->cValue; i++)
2752 dataLen += seq->rgValue[i].cbData;
2753 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2754 bytesNeeded = 1 + lenBytes + dataLen;
2755 if (!pbEncoded)
2757 *pcbEncoded = bytesNeeded;
2758 ret = TRUE;
2760 else
2762 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2763 pcbEncoded, bytesNeeded)))
2765 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2766 pbEncoded = *(BYTE **)pbEncoded;
2767 *pbEncoded++ = ASN_SEQUENCEOF;
2768 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2769 pbEncoded += lenBytes;
2770 for (i = 0; i < seq->cValue; i++)
2772 memcpy(pbEncoded, seq->rgValue[i].pbData,
2773 seq->rgValue[i].cbData);
2774 pbEncoded += seq->rgValue[i].cbData;
2779 __EXCEPT_PAGE_FAULT
2781 SetLastError(STATUS_ACCESS_VIOLATION);
2782 ret = FALSE;
2784 __ENDTRY
2785 return ret;
2788 static BOOL CRYPT_AsnEncodeDistPoint(const CRL_DIST_POINT *distPoint,
2789 BYTE *pbEncoded, DWORD *pcbEncoded)
2791 BOOL ret = TRUE;
2792 struct AsnEncodeSequenceItem items[3] = { { 0 } };
2793 struct AsnConstructedItem constructed = { 0 };
2794 struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2795 DWORD cItem = 0, cSwapped = 0;
2797 switch (distPoint->DistPointName.dwDistPointNameChoice)
2799 case CRL_DIST_POINT_NO_NAME:
2800 /* do nothing */
2801 break;
2802 case CRL_DIST_POINT_FULL_NAME:
2803 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
2804 swapped[cSwapped].pvStructInfo = &distPoint->DistPointName.u.FullName;
2805 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2806 constructed.tag = 0;
2807 constructed.pvStructInfo = &swapped[cSwapped];
2808 constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
2809 items[cItem].pvStructInfo = &constructed;
2810 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2811 cSwapped++;
2812 cItem++;
2813 break;
2814 case CRL_DIST_POINT_ISSUER_RDN_NAME:
2815 FIXME("unimplemented for CRL_DIST_POINT_ISSUER_RDN_NAME\n");
2816 ret = FALSE;
2817 break;
2818 default:
2819 ret = FALSE;
2821 if (ret && distPoint->ReasonFlags.cbData)
2823 swapped[cSwapped].tag = ASN_CONTEXT | 1;
2824 swapped[cSwapped].pvStructInfo = &distPoint->ReasonFlags;
2825 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
2826 items[cItem].pvStructInfo = &swapped[cSwapped];
2827 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2828 cSwapped++;
2829 cItem++;
2831 if (ret && distPoint->CRLIssuer.cAltEntry)
2833 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 2;
2834 swapped[cSwapped].pvStructInfo = &distPoint->CRLIssuer;
2835 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2836 items[cItem].pvStructInfo = &swapped[cSwapped];
2837 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2838 cSwapped++;
2839 cItem++;
2841 if (ret)
2842 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
2843 pbEncoded, pcbEncoded);
2844 return ret;
2847 static BOOL WINAPI CRYPT_AsnEncodeCRLDistPoints(DWORD dwCertEncodingType,
2848 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2849 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2851 BOOL ret;
2853 __TRY
2855 const CRL_DIST_POINTS_INFO *info =
2856 (const CRL_DIST_POINTS_INFO *)pvStructInfo;
2858 if (!info->cDistPoint)
2860 SetLastError(E_INVALIDARG);
2861 ret = FALSE;
2863 else
2865 DWORD bytesNeeded, dataLen, lenBytes, i;
2867 ret = TRUE;
2868 for (i = 0, dataLen = 0; ret && i < info->cDistPoint; i++)
2870 DWORD len;
2872 ret = CRYPT_AsnEncodeDistPoint(&info->rgDistPoint[i], NULL,
2873 &len);
2874 if (ret)
2875 dataLen += len;
2876 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
2878 /* Have to propagate index of failing character */
2879 *pcbEncoded = len;
2882 if (ret)
2884 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2885 bytesNeeded = 1 + lenBytes + dataLen;
2886 if (!pbEncoded)
2888 *pcbEncoded = bytesNeeded;
2889 ret = TRUE;
2891 else
2893 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2894 pbEncoded, pcbEncoded, bytesNeeded)))
2896 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2897 pbEncoded = *(BYTE **)pbEncoded;
2898 *pbEncoded++ = ASN_SEQUENCEOF;
2899 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2900 pbEncoded += lenBytes;
2901 for (i = 0; ret && i < info->cDistPoint; i++)
2903 DWORD len = dataLen;
2905 ret = CRYPT_AsnEncodeDistPoint(
2906 &info->rgDistPoint[i], pbEncoded, &len);
2907 if (ret)
2909 pbEncoded += len;
2910 dataLen -= len;
2918 __EXCEPT_PAGE_FAULT
2920 SetLastError(STATUS_ACCESS_VIOLATION);
2921 ret = FALSE;
2923 __ENDTRY
2924 return ret;
2927 static BOOL WINAPI CRYPT_AsnEncodeEnhancedKeyUsage(DWORD dwCertEncodingType,
2928 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2929 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2931 BOOL ret;
2933 __TRY
2935 const CERT_ENHKEY_USAGE *usage =
2936 (const CERT_ENHKEY_USAGE *)pvStructInfo;
2937 DWORD bytesNeeded = 0, lenBytes, size, i;
2939 ret = TRUE;
2940 for (i = 0; ret && i < usage->cUsageIdentifier; i++)
2942 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
2943 usage->rgpszUsageIdentifier[i],
2944 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &size);
2945 if (ret)
2946 bytesNeeded += size;
2948 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
2949 bytesNeeded += 1 + lenBytes;
2950 if (ret)
2952 if (!pbEncoded)
2953 *pcbEncoded = bytesNeeded;
2954 else
2956 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2957 pbEncoded, pcbEncoded, bytesNeeded)))
2959 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2960 pbEncoded = *(BYTE **)pbEncoded;
2961 *pbEncoded++ = ASN_SEQUENCEOF;
2962 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
2963 &lenBytes);
2964 pbEncoded += lenBytes;
2965 for (i = 0; ret && i < usage->cUsageIdentifier; i++)
2967 size = bytesNeeded;
2968 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
2969 usage->rgpszUsageIdentifier[i],
2970 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pbEncoded,
2971 &size);
2972 if (ret)
2974 pbEncoded += size;
2975 bytesNeeded -= size;
2982 __EXCEPT_PAGE_FAULT
2984 SetLastError(STATUS_ACCESS_VIOLATION);
2985 ret = FALSE;
2987 __ENDTRY
2988 return ret;
2991 static BOOL WINAPI CRYPT_AsnEncodeIssuingDistPoint(DWORD dwCertEncodingType,
2992 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2993 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2995 BOOL ret;
2997 __TRY
2999 const CRL_ISSUING_DIST_POINT *point =
3000 (const CRL_ISSUING_DIST_POINT *)pvStructInfo;
3001 struct AsnEncodeSequenceItem items[6] = { { 0 } };
3002 struct AsnConstructedItem constructed = { 0 };
3003 struct AsnEncodeTagSwappedItem swapped[5] = { { 0 } };
3004 DWORD cItem = 0, cSwapped = 0;
3006 ret = TRUE;
3007 switch (point->DistPointName.dwDistPointNameChoice)
3009 case CRL_DIST_POINT_NO_NAME:
3010 /* do nothing */
3011 break;
3012 case CRL_DIST_POINT_FULL_NAME:
3013 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
3014 swapped[cSwapped].pvStructInfo = &point->DistPointName.u.FullName;
3015 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
3016 constructed.tag = 0;
3017 constructed.pvStructInfo = &swapped[cSwapped];
3018 constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
3019 items[cItem].pvStructInfo = &constructed;
3020 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
3021 cSwapped++;
3022 cItem++;
3023 break;
3024 default:
3025 SetLastError(E_INVALIDARG);
3026 ret = FALSE;
3028 if (ret && point->fOnlyContainsUserCerts)
3030 swapped[cSwapped].tag = ASN_CONTEXT | 1;
3031 swapped[cSwapped].pvStructInfo = &point->fOnlyContainsUserCerts;
3032 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
3033 items[cItem].pvStructInfo = &swapped[cSwapped];
3034 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3035 cSwapped++;
3036 cItem++;
3038 if (ret && point->fOnlyContainsCACerts)
3040 swapped[cSwapped].tag = ASN_CONTEXT | 2;
3041 swapped[cSwapped].pvStructInfo = &point->fOnlyContainsCACerts;
3042 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
3043 items[cItem].pvStructInfo = &swapped[cSwapped];
3044 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3045 cSwapped++;
3046 cItem++;
3048 if (ret && point->OnlySomeReasonFlags.cbData)
3050 swapped[cSwapped].tag = ASN_CONTEXT | 3;
3051 swapped[cSwapped].pvStructInfo = &point->OnlySomeReasonFlags;
3052 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
3053 items[cItem].pvStructInfo = &swapped[cSwapped];
3054 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3055 cSwapped++;
3056 cItem++;
3058 if (ret && point->fIndirectCRL)
3060 swapped[cSwapped].tag = ASN_CONTEXT | 4;
3061 swapped[cSwapped].pvStructInfo = &point->fIndirectCRL;
3062 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
3063 items[cItem].pvStructInfo = &swapped[cSwapped];
3064 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3065 cSwapped++;
3066 cItem++;
3068 if (ret)
3069 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
3070 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
3072 __EXCEPT_PAGE_FAULT
3074 SetLastError(STATUS_ACCESS_VIOLATION);
3075 ret = FALSE;
3077 __ENDTRY
3078 return ret;
3081 static BOOL WINAPI CRYPT_AsnEncodeIssuerSerialNumber(
3082 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
3083 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
3084 DWORD *pcbEncoded)
3086 BOOL ret;
3087 const CERT_ISSUER_SERIAL_NUMBER *issuerSerial =
3088 (const CERT_ISSUER_SERIAL_NUMBER *)pvStructInfo;
3089 struct AsnEncodeSequenceItem items[] = {
3090 { &issuerSerial->Issuer, CRYPT_CopyEncodedBlob, 0 },
3091 { &issuerSerial->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
3094 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
3095 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
3096 pcbEncoded);
3097 return ret;
3100 static BOOL WINAPI CRYPT_AsnEncodePKCSSignerInfo(DWORD dwCertEncodingType,
3101 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3102 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3104 BOOL ret = FALSE;
3106 if (!(dwCertEncodingType & PKCS_7_ASN_ENCODING))
3108 SetLastError(E_INVALIDARG);
3109 return FALSE;
3112 __TRY
3114 const CMSG_SIGNER_INFO *info = (const CMSG_SIGNER_INFO *)pvStructInfo;
3116 if (!info->Issuer.cbData)
3117 SetLastError(E_INVALIDARG);
3118 else
3120 struct AsnEncodeSequenceItem items[7] = {
3121 { &info->dwVersion, CRYPT_AsnEncodeInt, 0 },
3122 { &info->Issuer, CRYPT_AsnEncodeIssuerSerialNumber, 0 },
3123 { &info->HashAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
3124 { &info->HashEncryptionAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
3126 DWORD cItem = 4;
3128 if (info->AuthAttrs.cAttr)
3130 items[cItem].pvStructInfo = &info->AuthAttrs;
3131 items[cItem].encodeFunc = CRYPT_AsnEncodePKCSAttributes;
3132 cItem++;
3134 if (info->UnauthAttrs.cAttr)
3136 items[cItem].pvStructInfo = &info->UnauthAttrs;
3137 items[cItem].encodeFunc = CRYPT_AsnEncodePKCSAttributes;
3138 cItem++;
3140 items[cItem].pvStructInfo = &info->EncryptedHash;
3141 items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
3142 cItem++;
3143 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
3144 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
3147 __EXCEPT_PAGE_FAULT
3149 SetLastError(STATUS_ACCESS_VIOLATION);
3151 __ENDTRY
3152 return ret;
3155 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
3156 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
3157 void *pvEncoded, DWORD *pcbEncoded)
3159 static HCRYPTOIDFUNCSET set = NULL;
3160 BOOL ret = FALSE;
3161 CryptEncodeObjectExFunc encodeFunc = NULL;
3162 HCRYPTOIDFUNCADDR hFunc = NULL;
3164 TRACE("(0x%08x, %s, %p, 0x%08x, %p, %p, %p)\n", dwCertEncodingType,
3165 debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
3166 pvEncoded, pcbEncoded);
3168 if (!pvEncoded && !pcbEncoded)
3170 SetLastError(ERROR_INVALID_PARAMETER);
3171 return FALSE;
3173 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
3174 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
3176 SetLastError(ERROR_FILE_NOT_FOUND);
3177 return FALSE;
3180 SetLastError(NOERROR);
3181 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
3182 *(BYTE **)pvEncoded = NULL;
3183 if (!HIWORD(lpszStructType))
3185 switch (LOWORD(lpszStructType))
3187 case (WORD)X509_CERT:
3188 encodeFunc = CRYPT_AsnEncodeCert;
3189 break;
3190 case (WORD)X509_CERT_TO_BE_SIGNED:
3191 encodeFunc = CRYPT_AsnEncodeCertInfo;
3192 break;
3193 case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
3194 encodeFunc = CRYPT_AsnEncodeCRLInfo;
3195 break;
3196 case (WORD)X509_EXTENSIONS:
3197 encodeFunc = CRYPT_AsnEncodeExtensions;
3198 break;
3199 case (WORD)X509_NAME_VALUE:
3200 encodeFunc = CRYPT_AsnEncodeNameValue;
3201 break;
3202 case (WORD)X509_NAME:
3203 encodeFunc = CRYPT_AsnEncodeName;
3204 break;
3205 case (WORD)X509_PUBLIC_KEY_INFO:
3206 encodeFunc = CRYPT_AsnEncodePubKeyInfo;
3207 break;
3208 case (WORD)X509_AUTHORITY_KEY_ID:
3209 encodeFunc = CRYPT_AsnEncodeAuthorityKeyId;
3210 break;
3211 case (WORD)X509_ALTERNATE_NAME:
3212 encodeFunc = CRYPT_AsnEncodeAltName;
3213 break;
3214 case (WORD)X509_BASIC_CONSTRAINTS:
3215 encodeFunc = CRYPT_AsnEncodeBasicConstraints;
3216 break;
3217 case (WORD)X509_BASIC_CONSTRAINTS2:
3218 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
3219 break;
3220 case (WORD)RSA_CSP_PUBLICKEYBLOB:
3221 encodeFunc = CRYPT_AsnEncodeRsaPubKey;
3222 break;
3223 case (WORD)X509_UNICODE_NAME:
3224 encodeFunc = CRYPT_AsnEncodeUnicodeName;
3225 break;
3226 case (WORD)PKCS_CONTENT_INFO:
3227 encodeFunc = CRYPT_AsnEncodePKCSContentInfo;
3228 break;
3229 case (WORD)PKCS_ATTRIBUTE:
3230 encodeFunc = CRYPT_AsnEncodePKCSAttribute;
3231 break;
3232 case (WORD)X509_UNICODE_NAME_VALUE:
3233 encodeFunc = CRYPT_AsnEncodeUnicodeNameValue;
3234 break;
3235 case (WORD)X509_OCTET_STRING:
3236 encodeFunc = CRYPT_AsnEncodeOctets;
3237 break;
3238 case (WORD)X509_BITS:
3239 case (WORD)X509_KEY_USAGE:
3240 encodeFunc = CRYPT_AsnEncodeBits;
3241 break;
3242 case (WORD)X509_INTEGER:
3243 encodeFunc = CRYPT_AsnEncodeInt;
3244 break;
3245 case (WORD)X509_MULTI_BYTE_INTEGER:
3246 encodeFunc = CRYPT_AsnEncodeInteger;
3247 break;
3248 case (WORD)X509_MULTI_BYTE_UINT:
3249 encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
3250 break;
3251 case (WORD)X509_ENUMERATED:
3252 encodeFunc = CRYPT_AsnEncodeEnumerated;
3253 break;
3254 case (WORD)X509_CHOICE_OF_TIME:
3255 encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
3256 break;
3257 case (WORD)X509_AUTHORITY_KEY_ID2:
3258 encodeFunc = CRYPT_AsnEncodeAuthorityKeyId2;
3259 break;
3260 case (WORD)X509_SEQUENCE_OF_ANY:
3261 encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
3262 break;
3263 case (WORD)PKCS_UTC_TIME:
3264 encodeFunc = CRYPT_AsnEncodeUtcTime;
3265 break;
3266 case (WORD)X509_CRL_DIST_POINTS:
3267 encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
3268 break;
3269 case (WORD)X509_ENHANCED_KEY_USAGE:
3270 encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
3271 break;
3272 case (WORD)PKCS_ATTRIBUTES:
3273 encodeFunc = CRYPT_AsnEncodePKCSAttributes;
3274 break;
3275 case (WORD)X509_ISSUING_DIST_POINT:
3276 encodeFunc = CRYPT_AsnEncodeIssuingDistPoint;
3277 break;
3278 case (WORD)PKCS7_SIGNER_INFO:
3279 encodeFunc = CRYPT_AsnEncodePKCSSignerInfo;
3280 break;
3281 default:
3282 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
3285 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
3286 encodeFunc = CRYPT_AsnEncodeExtensions;
3287 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
3288 encodeFunc = CRYPT_AsnEncodeUtcTime;
3289 else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER))
3290 encodeFunc = CRYPT_AsnEncodeAuthorityKeyId;
3291 else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2))
3292 encodeFunc = CRYPT_AsnEncodeAuthorityKeyId2;
3293 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
3294 encodeFunc = CRYPT_AsnEncodeEnumerated;
3295 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
3296 encodeFunc = CRYPT_AsnEncodeBits;
3297 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
3298 encodeFunc = CRYPT_AsnEncodeOctets;
3299 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS))
3300 encodeFunc = CRYPT_AsnEncodeBasicConstraints;
3301 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
3302 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
3303 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
3304 encodeFunc = CRYPT_AsnEncodeAltName;
3305 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
3306 encodeFunc = CRYPT_AsnEncodeAltName;
3307 else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
3308 encodeFunc = CRYPT_AsnEncodeAltName;
3309 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
3310 encodeFunc = CRYPT_AsnEncodeAltName;
3311 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
3312 encodeFunc = CRYPT_AsnEncodeAltName;
3313 else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
3314 encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
3315 else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
3316 encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
3317 else if (!strcmp(lpszStructType, szOID_ISSUING_DIST_POINT))
3318 encodeFunc = CRYPT_AsnEncodeIssuingDistPoint;
3319 else
3320 TRACE("OID %s not found or unimplemented, looking for DLL\n",
3321 debugstr_a(lpszStructType));
3322 if (!encodeFunc)
3324 if (!set)
3325 set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_EX_FUNC, 0);
3326 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
3327 (void **)&encodeFunc, &hFunc);
3329 if (encodeFunc)
3330 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
3331 dwFlags, pEncodePara, pvEncoded, pcbEncoded);
3332 else
3333 SetLastError(ERROR_FILE_NOT_FOUND);
3334 if (hFunc)
3335 CryptFreeOIDFunctionAddress(hFunc, 0);
3336 return ret;
3339 BOOL WINAPI CryptExportPublicKeyInfo(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
3340 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3342 return CryptExportPublicKeyInfoEx(hCryptProv, dwKeySpec, dwCertEncodingType,
3343 NULL, 0, NULL, pInfo, pcbInfo);
3346 static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3347 DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
3348 DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3350 BOOL ret;
3351 HCRYPTKEY key;
3352 static CHAR oid[] = szOID_RSA_RSA;
3354 TRACE("(%08lx, %d, %08x, %s, %08x, %p, %p, %p)\n", hCryptProv, dwKeySpec,
3355 dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
3356 pInfo, pcbInfo);
3358 if (!pszPublicKeyObjId)
3359 pszPublicKeyObjId = oid;
3360 if ((ret = CryptGetUserKey(hCryptProv, dwKeySpec, &key)))
3362 DWORD keySize = 0;
3364 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &keySize);
3365 if (ret)
3367 LPBYTE pubKey = CryptMemAlloc(keySize);
3369 if (pubKey)
3371 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, pubKey,
3372 &keySize);
3373 if (ret)
3375 DWORD encodedLen = 0;
3377 ret = CryptEncodeObject(dwCertEncodingType,
3378 RSA_CSP_PUBLICKEYBLOB, pubKey, NULL, &encodedLen);
3379 if (ret)
3381 DWORD sizeNeeded = sizeof(CERT_PUBLIC_KEY_INFO) +
3382 strlen(pszPublicKeyObjId) + 1 + encodedLen;
3384 if (!pInfo)
3385 *pcbInfo = sizeNeeded;
3386 else if (*pcbInfo < sizeNeeded)
3388 SetLastError(ERROR_MORE_DATA);
3389 *pcbInfo = sizeNeeded;
3390 ret = FALSE;
3392 else
3394 pInfo->Algorithm.pszObjId = (char *)pInfo +
3395 sizeof(CERT_PUBLIC_KEY_INFO);
3396 lstrcpyA(pInfo->Algorithm.pszObjId,
3397 pszPublicKeyObjId);
3398 pInfo->Algorithm.Parameters.cbData = 0;
3399 pInfo->Algorithm.Parameters.pbData = NULL;
3400 pInfo->PublicKey.pbData =
3401 (BYTE *)pInfo->Algorithm.pszObjId
3402 + lstrlenA(pInfo->Algorithm.pszObjId) + 1;
3403 pInfo->PublicKey.cbData = encodedLen;
3404 pInfo->PublicKey.cUnusedBits = 0;
3405 ret = CryptEncodeObject(dwCertEncodingType,
3406 RSA_CSP_PUBLICKEYBLOB, pubKey,
3407 pInfo->PublicKey.pbData, &pInfo->PublicKey.cbData);
3411 CryptMemFree(pubKey);
3413 else
3414 ret = FALSE;
3416 CryptDestroyKey(key);
3418 return ret;
3421 typedef BOOL (WINAPI *ExportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
3422 DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
3423 DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo);
3425 BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
3426 DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId, DWORD dwFlags,
3427 void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3429 static HCRYPTOIDFUNCSET set = NULL;
3430 BOOL ret;
3431 ExportPublicKeyInfoExFunc exportFunc = NULL;
3432 HCRYPTOIDFUNCADDR hFunc = NULL;
3434 TRACE("(%08lx, %d, %08x, %s, %08x, %p, %p, %p)\n", hCryptProv, dwKeySpec,
3435 dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
3436 pInfo, pcbInfo);
3438 if (!hCryptProv)
3440 SetLastError(ERROR_INVALID_PARAMETER);
3441 return FALSE;
3444 if (pszPublicKeyObjId)
3446 if (!set)
3447 set = CryptInitOIDFunctionSet(CRYPT_OID_EXPORT_PUBLIC_KEY_INFO_FUNC,
3449 CryptGetOIDFunctionAddress(set, dwCertEncodingType, pszPublicKeyObjId,
3450 0, (void **)&exportFunc, &hFunc);
3452 if (!exportFunc)
3453 exportFunc = CRYPT_ExportRsaPublicKeyInfoEx;
3454 ret = exportFunc(hCryptProv, dwKeySpec, dwCertEncodingType,
3455 pszPublicKeyObjId, dwFlags, pvAuxInfo, pInfo, pcbInfo);
3456 if (hFunc)
3457 CryptFreeOIDFunctionAddress(hFunc, 0);
3458 return ret;
3461 BOOL WINAPI CryptImportPublicKeyInfo(HCRYPTPROV hCryptProv,
3462 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
3464 return CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType, pInfo,
3465 0, 0, NULL, phKey);
3468 static BOOL WINAPI CRYPT_ImportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3469 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3470 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
3472 BOOL ret;
3473 DWORD pubKeySize = 0;
3475 TRACE("(%08lx, %d, %p, %d, %08x, %p, %p)\n", hCryptProv,
3476 dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
3478 ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
3479 pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, NULL, &pubKeySize);
3480 if (ret)
3482 LPBYTE pubKey = CryptMemAlloc(pubKeySize);
3484 if (pubKey)
3486 ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
3487 pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, pubKey,
3488 &pubKeySize);
3489 if (ret)
3490 ret = CryptImportKey(hCryptProv, pubKey, pubKeySize, 0, 0,
3491 phKey);
3492 CryptMemFree(pubKey);
3494 else
3495 ret = FALSE;
3497 return ret;
3500 typedef BOOL (WINAPI *ImportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
3501 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3502 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey);
3504 BOOL WINAPI CryptImportPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3505 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3506 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
3508 static HCRYPTOIDFUNCSET set = NULL;
3509 BOOL ret;
3510 ImportPublicKeyInfoExFunc importFunc = NULL;
3511 HCRYPTOIDFUNCADDR hFunc = NULL;
3513 TRACE("(%08lx, %d, %p, %d, %08x, %p, %p)\n", hCryptProv,
3514 dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
3516 if (!set)
3517 set = CryptInitOIDFunctionSet(CRYPT_OID_IMPORT_PUBLIC_KEY_INFO_FUNC, 0);
3518 CryptGetOIDFunctionAddress(set, dwCertEncodingType,
3519 pInfo->Algorithm.pszObjId, 0, (void **)&importFunc, &hFunc);
3520 if (!importFunc)
3521 importFunc = CRYPT_ImportRsaPublicKeyInfoEx;
3522 ret = importFunc(hCryptProv, dwCertEncodingType, pInfo, aiKeyAlg, dwFlags,
3523 pvAuxInfo, phKey);
3524 if (hFunc)
3525 CryptFreeOIDFunctionAddress(hFunc, 0);
3526 return ret;