push 46d7c5ab81dbd26521afad86048775d05a228dc3
[wine/hacks.git] / dlls / crypt32 / encode.c
blob9522b967dc316cbf95514579f317c8b992232652
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 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
1170 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
1171 CryptEncodeObjectExFunc nameValueEncodeFunc, BYTE *pbEncoded,
1172 DWORD *pcbEncoded)
1174 BOOL ret;
1175 CRYPT_DER_BLOB *blobs = NULL;
1177 __TRY
1179 DWORD bytesNeeded = 0, lenBytes, i;
1181 blobs = NULL;
1182 ret = TRUE;
1183 if (rdn->cRDNAttr)
1185 blobs = CryptMemAlloc(rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1186 if (!blobs)
1187 ret = FALSE;
1188 else
1189 memset(blobs, 0, rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1191 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1193 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
1194 nameValueEncodeFunc, NULL, &blobs[i].cbData);
1195 if (ret)
1196 bytesNeeded += blobs[i].cbData;
1197 else
1199 /* Have to propagate index of failing character */
1200 *pcbEncoded = blobs[i].cbData;
1203 if (ret)
1205 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1206 bytesNeeded += 1 + lenBytes;
1207 if (pbEncoded)
1209 if (*pcbEncoded < bytesNeeded)
1211 SetLastError(ERROR_MORE_DATA);
1212 ret = FALSE;
1214 else
1216 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1218 blobs[i].pbData = CryptMemAlloc(blobs[i].cbData);
1219 if (!blobs[i].pbData)
1220 ret = FALSE;
1221 else
1223 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
1224 &rdn->rgRDNAttr[i], nameValueEncodeFunc,
1225 blobs[i].pbData, &blobs[i].cbData);
1226 if (!ret)
1227 *pcbEncoded = blobs[i].cbData;
1230 if (ret)
1232 qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
1233 BLOBComp);
1234 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
1235 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1236 &lenBytes);
1237 pbEncoded += lenBytes;
1238 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1240 memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
1241 pbEncoded += blobs[i].cbData;
1246 if (ret)
1247 *pcbEncoded = bytesNeeded;
1249 if (blobs)
1251 for (i = 0; i < rdn->cRDNAttr; i++)
1252 CryptMemFree(blobs[i].pbData);
1255 __EXCEPT_PAGE_FAULT
1257 SetLastError(STATUS_ACCESS_VIOLATION);
1258 ret = FALSE;
1260 __ENDTRY
1261 CryptMemFree(blobs);
1262 return ret;
1265 static BOOL WINAPI CRYPT_AsnEncodeUnicodeNameValue(DWORD dwCertEncodingType,
1266 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1267 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
1269 static BOOL WINAPI CRYPT_AsnEncodeOrCopyUnicodeNameValue(
1270 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
1271 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1272 DWORD *pcbEncoded)
1274 const CERT_NAME_VALUE *value = (const CERT_NAME_VALUE *)pvStructInfo;
1275 BOOL ret;
1277 if (value->dwValueType == CERT_RDN_ENCODED_BLOB)
1278 ret = CRYPT_CopyEncodedBlob(dwCertEncodingType, NULL, &value->Value,
1279 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1280 else
1281 ret = CRYPT_AsnEncodeUnicodeNameValue(dwCertEncodingType, NULL, value,
1282 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1283 return ret;
1286 static BOOL WINAPI CRYPT_AsnEncodeUnicodeName(DWORD dwCertEncodingType,
1287 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1288 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1290 BOOL ret = TRUE;
1292 __TRY
1294 const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1295 DWORD bytesNeeded = 0, lenBytes, size, i;
1297 TRACE("encoding name with %d RDNs\n", info->cRDN);
1298 ret = TRUE;
1299 for (i = 0; ret && i < info->cRDN; i++)
1301 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i],
1302 CRYPT_AsnEncodeOrCopyUnicodeNameValue, NULL, &size);
1303 if (ret)
1304 bytesNeeded += size;
1305 else
1306 *pcbEncoded = size;
1308 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1309 bytesNeeded += 1 + lenBytes;
1310 if (ret)
1312 if (!pbEncoded)
1313 *pcbEncoded = bytesNeeded;
1314 else
1316 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1317 pbEncoded, pcbEncoded, bytesNeeded)))
1319 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1320 pbEncoded = *(BYTE **)pbEncoded;
1321 *pbEncoded++ = ASN_SEQUENCEOF;
1322 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1323 &lenBytes);
1324 pbEncoded += lenBytes;
1325 for (i = 0; ret && i < info->cRDN; i++)
1327 size = bytesNeeded;
1328 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1329 &info->rgRDN[i], CRYPT_AsnEncodeOrCopyUnicodeNameValue,
1330 pbEncoded, &size);
1331 if (ret)
1333 pbEncoded += size;
1334 bytesNeeded -= size;
1336 else
1337 *pcbEncoded = size;
1343 __EXCEPT_PAGE_FAULT
1345 SetLastError(STATUS_ACCESS_VIOLATION);
1346 ret = FALSE;
1348 __ENDTRY
1349 return ret;
1352 static BOOL CRYPT_AsnEncodeUnicodeStringCoerce(const CERT_NAME_VALUE *value,
1353 BYTE tag, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1354 DWORD *pcbEncoded)
1356 BOOL ret = TRUE;
1357 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1358 DWORD bytesNeeded, lenBytes, encodedLen;
1360 encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1361 lstrlenW(str);
1362 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1363 bytesNeeded = 1 + lenBytes + encodedLen;
1364 if (!pbEncoded)
1365 *pcbEncoded = bytesNeeded;
1366 else
1368 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1369 pbEncoded, pcbEncoded, bytesNeeded)))
1371 DWORD i;
1373 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1374 pbEncoded = *(BYTE **)pbEncoded;
1375 *pbEncoded++ = tag;
1376 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1377 pbEncoded += lenBytes;
1378 for (i = 0; i < encodedLen; i++)
1379 *pbEncoded++ = (BYTE)str[i];
1382 return ret;
1385 static BOOL CRYPT_AsnEncodeNumericString(const CERT_NAME_VALUE *value,
1386 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1387 DWORD *pcbEncoded)
1389 BOOL ret = TRUE;
1390 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1391 DWORD bytesNeeded, lenBytes, encodedLen;
1393 encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1394 lstrlenW(str);
1395 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1396 bytesNeeded = 1 + lenBytes + encodedLen;
1397 if (!pbEncoded)
1398 *pcbEncoded = bytesNeeded;
1399 else
1401 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1402 pbEncoded, pcbEncoded, bytesNeeded)))
1404 DWORD i;
1406 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1407 pbEncoded = *(BYTE **)pbEncoded;
1408 *pbEncoded++ = ASN_NUMERICSTRING;
1409 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1410 pbEncoded += lenBytes;
1411 for (i = 0; ret && i < encodedLen; i++)
1413 if (isdigitW(str[i]))
1414 *pbEncoded++ = (BYTE)str[i];
1415 else
1417 *pcbEncoded = i;
1418 SetLastError(CRYPT_E_INVALID_NUMERIC_STRING);
1419 ret = FALSE;
1424 return ret;
1427 static inline int isprintableW(WCHAR wc)
1429 return isalnumW(wc) || isspaceW(wc) || wc == '\'' || wc == '(' ||
1430 wc == ')' || wc == '+' || wc == ',' || wc == '-' || wc == '.' ||
1431 wc == '/' || wc == ':' || wc == '=' || wc == '?';
1434 static BOOL CRYPT_AsnEncodePrintableString(const CERT_NAME_VALUE *value,
1435 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1436 DWORD *pcbEncoded)
1438 BOOL ret = TRUE;
1439 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1440 DWORD bytesNeeded, lenBytes, encodedLen;
1442 encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1443 lstrlenW(str);
1444 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1445 bytesNeeded = 1 + lenBytes + encodedLen;
1446 if (!pbEncoded)
1447 *pcbEncoded = bytesNeeded;
1448 else
1450 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1451 pbEncoded, pcbEncoded, bytesNeeded)))
1453 DWORD i;
1455 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1456 pbEncoded = *(BYTE **)pbEncoded;
1457 *pbEncoded++ = ASN_PRINTABLESTRING;
1458 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1459 pbEncoded += lenBytes;
1460 for (i = 0; ret && i < encodedLen; i++)
1462 if (isprintableW(str[i]))
1463 *pbEncoded++ = (BYTE)str[i];
1464 else
1466 *pcbEncoded = i;
1467 SetLastError(CRYPT_E_INVALID_PRINTABLE_STRING);
1468 ret = FALSE;
1473 return ret;
1476 static BOOL CRYPT_AsnEncodeIA5String(const CERT_NAME_VALUE *value,
1477 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1478 DWORD *pcbEncoded)
1480 BOOL ret = TRUE;
1481 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1482 DWORD bytesNeeded, lenBytes, encodedLen;
1484 encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1485 lstrlenW(str);
1486 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1487 bytesNeeded = 1 + lenBytes + encodedLen;
1488 if (!pbEncoded)
1489 *pcbEncoded = bytesNeeded;
1490 else
1492 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1493 pbEncoded, pcbEncoded, bytesNeeded)))
1495 DWORD i;
1497 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1498 pbEncoded = *(BYTE **)pbEncoded;
1499 *pbEncoded++ = ASN_IA5STRING;
1500 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1501 pbEncoded += lenBytes;
1502 for (i = 0; ret && i < encodedLen; i++)
1504 if (str[i] <= 0x7f)
1505 *pbEncoded++ = (BYTE)str[i];
1506 else
1508 *pcbEncoded = i;
1509 SetLastError(CRYPT_E_INVALID_IA5_STRING);
1510 ret = FALSE;
1515 return ret;
1518 static BOOL CRYPT_AsnEncodeUniversalString(const CERT_NAME_VALUE *value,
1519 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1520 DWORD *pcbEncoded)
1522 BOOL ret = TRUE;
1523 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1524 DWORD bytesNeeded, lenBytes, strLen;
1526 /* FIXME: doesn't handle composite characters */
1527 strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1528 lstrlenW(str);
1529 CRYPT_EncodeLen(strLen * 4, NULL, &lenBytes);
1530 bytesNeeded = 1 + lenBytes + strLen * 4;
1531 if (!pbEncoded)
1532 *pcbEncoded = bytesNeeded;
1533 else
1535 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1536 pbEncoded, pcbEncoded, bytesNeeded)))
1538 DWORD i;
1540 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1541 pbEncoded = *(BYTE **)pbEncoded;
1542 *pbEncoded++ = ASN_UNIVERSALSTRING;
1543 CRYPT_EncodeLen(strLen * 4, pbEncoded, &lenBytes);
1544 pbEncoded += lenBytes;
1545 for (i = 0; i < strLen; i++)
1547 *pbEncoded++ = 0;
1548 *pbEncoded++ = 0;
1549 *pbEncoded++ = (BYTE)((str[i] & 0xff00) >> 8);
1550 *pbEncoded++ = (BYTE)(str[i] & 0x00ff);
1554 return ret;
1557 static BOOL WINAPI CRYPT_AsnEncodeUnicodeNameValue(DWORD dwCertEncodingType,
1558 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1559 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1561 BOOL ret = FALSE;
1563 __TRY
1565 const CERT_NAME_VALUE *value = (const CERT_NAME_VALUE *)pvStructInfo;
1567 switch (value->dwValueType)
1569 case CERT_RDN_ANY_TYPE:
1570 case CERT_RDN_ENCODED_BLOB:
1571 case CERT_RDN_OCTET_STRING:
1572 SetLastError(CRYPT_E_NOT_CHAR_STRING);
1573 break;
1574 case CERT_RDN_NUMERIC_STRING:
1575 ret = CRYPT_AsnEncodeNumericString(value, dwFlags, pEncodePara,
1576 pbEncoded, pcbEncoded);
1577 break;
1578 case CERT_RDN_PRINTABLE_STRING:
1579 ret = CRYPT_AsnEncodePrintableString(value, dwFlags, pEncodePara,
1580 pbEncoded, pcbEncoded);
1581 break;
1582 case CERT_RDN_TELETEX_STRING:
1583 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_T61STRING,
1584 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1585 break;
1586 case CERT_RDN_VIDEOTEX_STRING:
1587 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value,
1588 ASN_VIDEOTEXSTRING, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1589 break;
1590 case CERT_RDN_IA5_STRING:
1591 ret = CRYPT_AsnEncodeIA5String(value, dwFlags, pEncodePara,
1592 pbEncoded, pcbEncoded);
1593 break;
1594 case CERT_RDN_GRAPHIC_STRING:
1595 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_GRAPHICSTRING,
1596 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1597 break;
1598 case CERT_RDN_VISIBLE_STRING:
1599 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_VISIBLESTRING,
1600 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1601 break;
1602 case CERT_RDN_GENERAL_STRING:
1603 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_GENERALSTRING,
1604 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1605 break;
1606 case CERT_RDN_UNIVERSAL_STRING:
1607 ret = CRYPT_AsnEncodeUniversalString(value, dwFlags, pEncodePara,
1608 pbEncoded, pcbEncoded);
1609 break;
1610 case CERT_RDN_BMP_STRING:
1611 ret = CRYPT_AsnEncodeBMPString(value, dwFlags, pEncodePara,
1612 pbEncoded, pcbEncoded);
1613 break;
1614 case CERT_RDN_UTF8_STRING:
1615 ret = CRYPT_AsnEncodeUTF8String(value, dwFlags, pEncodePara,
1616 pbEncoded, pcbEncoded);
1617 break;
1618 default:
1619 SetLastError(CRYPT_E_ASN1_CHOICE);
1622 __EXCEPT_PAGE_FAULT
1624 SetLastError(STATUS_ACCESS_VIOLATION);
1626 __ENDTRY
1627 return ret;
1630 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
1631 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1632 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1634 BOOL ret;
1636 __TRY
1638 const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1639 DWORD bytesNeeded = 0, lenBytes, size, i;
1641 TRACE("encoding name with %d RDNs\n", info->cRDN);
1642 ret = TRUE;
1643 for (i = 0; ret && i < info->cRDN; i++)
1645 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i],
1646 CRYPT_AsnEncodeNameValue, NULL, &size);
1647 if (ret)
1648 bytesNeeded += size;
1650 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1651 bytesNeeded += 1 + lenBytes;
1652 if (ret)
1654 if (!pbEncoded)
1655 *pcbEncoded = bytesNeeded;
1656 else
1658 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1659 pbEncoded, pcbEncoded, bytesNeeded)))
1661 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1662 pbEncoded = *(BYTE **)pbEncoded;
1663 *pbEncoded++ = ASN_SEQUENCEOF;
1664 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1665 &lenBytes);
1666 pbEncoded += lenBytes;
1667 for (i = 0; ret && i < info->cRDN; i++)
1669 size = bytesNeeded;
1670 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1671 &info->rgRDN[i], CRYPT_AsnEncodeNameValue, pbEncoded,
1672 &size);
1673 if (ret)
1675 pbEncoded += size;
1676 bytesNeeded -= size;
1683 __EXCEPT_PAGE_FAULT
1685 SetLastError(STATUS_ACCESS_VIOLATION);
1686 ret = FALSE;
1688 __ENDTRY
1689 return ret;
1692 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1693 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1694 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1696 BOOL val = *(const BOOL *)pvStructInfo, ret;
1698 TRACE("%d\n", val);
1700 if (!pbEncoded)
1702 *pcbEncoded = 3;
1703 ret = TRUE;
1705 else if (*pcbEncoded < 3)
1707 *pcbEncoded = 3;
1708 SetLastError(ERROR_MORE_DATA);
1709 ret = FALSE;
1711 else
1713 *pcbEncoded = 3;
1714 *pbEncoded++ = ASN_BOOL;
1715 *pbEncoded++ = 1;
1716 *pbEncoded++ = val ? 0xff : 0;
1717 ret = TRUE;
1719 TRACE("returning %d (%08x)\n", ret, GetLastError());
1720 return ret;
1723 static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry,
1724 BYTE *pbEncoded, DWORD *pcbEncoded)
1726 BOOL ret;
1727 DWORD dataLen;
1729 ret = TRUE;
1730 switch (entry->dwAltNameChoice)
1732 case CERT_ALT_NAME_RFC822_NAME:
1733 case CERT_ALT_NAME_DNS_NAME:
1734 case CERT_ALT_NAME_URL:
1735 if (entry->u.pwszURL)
1737 DWORD i;
1739 /* Not + 1: don't encode the NULL-terminator */
1740 dataLen = lstrlenW(entry->u.pwszURL);
1741 for (i = 0; ret && i < dataLen; i++)
1743 if (entry->u.pwszURL[i] > 0x7f)
1745 SetLastError(CRYPT_E_INVALID_IA5_STRING);
1746 ret = FALSE;
1747 *pcbEncoded = i;
1751 else
1752 dataLen = 0;
1753 break;
1754 case CERT_ALT_NAME_IP_ADDRESS:
1755 dataLen = entry->u.IPAddress.cbData;
1756 break;
1757 case CERT_ALT_NAME_REGISTERED_ID:
1758 /* FIXME: encode OID */
1759 case CERT_ALT_NAME_OTHER_NAME:
1760 case CERT_ALT_NAME_DIRECTORY_NAME:
1761 FIXME("name type %d unimplemented\n", entry->dwAltNameChoice);
1762 return FALSE;
1763 default:
1764 SetLastError(E_INVALIDARG);
1765 return FALSE;
1767 if (ret)
1769 DWORD bytesNeeded, lenBytes;
1771 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1772 bytesNeeded = 1 + dataLen + lenBytes;
1773 if (!pbEncoded)
1774 *pcbEncoded = bytesNeeded;
1775 else if (*pcbEncoded < bytesNeeded)
1777 SetLastError(ERROR_MORE_DATA);
1778 *pcbEncoded = bytesNeeded;
1779 ret = FALSE;
1781 else
1783 *pbEncoded++ = ASN_CONTEXT | (entry->dwAltNameChoice - 1);
1784 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1785 pbEncoded += lenBytes;
1786 switch (entry->dwAltNameChoice)
1788 case CERT_ALT_NAME_RFC822_NAME:
1789 case CERT_ALT_NAME_DNS_NAME:
1790 case CERT_ALT_NAME_URL:
1792 DWORD i;
1794 for (i = 0; i < dataLen; i++)
1795 *pbEncoded++ = (BYTE)entry->u.pwszURL[i];
1796 break;
1798 case CERT_ALT_NAME_IP_ADDRESS:
1799 memcpy(pbEncoded, entry->u.IPAddress.pbData, dataLen);
1800 break;
1802 if (ret)
1803 *pcbEncoded = bytesNeeded;
1806 TRACE("returning %d (%08x)\n", ret, GetLastError());
1807 return ret;
1810 static BOOL WINAPI CRYPT_AsnEncodeAuthorityKeyId(DWORD dwCertEncodingType,
1811 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1812 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1814 BOOL ret;
1816 __TRY
1818 const CERT_AUTHORITY_KEY_ID_INFO *info =
1819 (const CERT_AUTHORITY_KEY_ID_INFO *)pvStructInfo;
1820 struct AsnEncodeSequenceItem items[3] = { { 0 } };
1821 struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
1822 struct AsnConstructedItem constructed = { 0 };
1823 DWORD cItem = 0, cSwapped = 0;
1825 if (info->KeyId.cbData)
1827 swapped[cSwapped].tag = ASN_CONTEXT | 0;
1828 swapped[cSwapped].pvStructInfo = &info->KeyId;
1829 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
1830 items[cItem].pvStructInfo = &swapped[cSwapped];
1831 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
1832 cSwapped++;
1833 cItem++;
1835 if (info->CertIssuer.cbData)
1837 constructed.tag = 1;
1838 constructed.pvStructInfo = &info->CertIssuer;
1839 constructed.encodeFunc = CRYPT_CopyEncodedBlob;
1840 items[cItem].pvStructInfo = &constructed;
1841 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
1842 cItem++;
1844 if (info->CertSerialNumber.cbData)
1846 swapped[cSwapped].tag = ASN_CONTEXT | 2;
1847 swapped[cSwapped].pvStructInfo = &info->CertSerialNumber;
1848 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
1849 items[cItem].pvStructInfo = &swapped[cSwapped];
1850 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
1851 cSwapped++;
1852 cItem++;
1854 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, dwFlags,
1855 pEncodePara, pbEncoded, pcbEncoded);
1857 __EXCEPT_PAGE_FAULT
1859 SetLastError(STATUS_ACCESS_VIOLATION);
1860 ret = FALSE;
1862 __ENDTRY
1863 return ret;
1866 static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
1867 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1868 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1870 BOOL ret;
1872 __TRY
1874 const CERT_ALT_NAME_INFO *info =
1875 (const CERT_ALT_NAME_INFO *)pvStructInfo;
1876 DWORD bytesNeeded, dataLen, lenBytes, i;
1878 ret = TRUE;
1879 /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
1880 * can't encode an erroneous entry index if it's bigger than this.
1882 for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
1884 DWORD len;
1886 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i], NULL,
1887 &len);
1888 if (ret)
1889 dataLen += len;
1890 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
1892 /* CRYPT_AsnEncodeAltNameEntry encoded the index of
1893 * the bad character, now set the index of the bad
1894 * entry
1896 *pcbEncoded = (BYTE)i <<
1897 CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT | len;
1900 if (ret)
1902 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1903 bytesNeeded = 1 + lenBytes + dataLen;
1904 if (!pbEncoded)
1906 *pcbEncoded = bytesNeeded;
1907 ret = TRUE;
1909 else
1911 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1912 pbEncoded, pcbEncoded, bytesNeeded)))
1914 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1915 pbEncoded = *(BYTE **)pbEncoded;
1916 *pbEncoded++ = ASN_SEQUENCEOF;
1917 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1918 pbEncoded += lenBytes;
1919 for (i = 0; ret && i < info->cAltEntry; i++)
1921 DWORD len = dataLen;
1923 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i],
1924 pbEncoded, &len);
1925 if (ret)
1927 pbEncoded += len;
1928 dataLen -= len;
1935 __EXCEPT_PAGE_FAULT
1937 SetLastError(STATUS_ACCESS_VIOLATION);
1938 ret = FALSE;
1940 __ENDTRY
1941 return ret;
1944 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints(DWORD dwCertEncodingType,
1945 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1946 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1948 BOOL ret;
1950 __TRY
1952 const CERT_BASIC_CONSTRAINTS_INFO *info =
1953 (const CERT_BASIC_CONSTRAINTS_INFO *)pvStructInfo;
1954 struct AsnEncodeSequenceItem items[3] = {
1955 { &info->SubjectType, CRYPT_AsnEncodeBits, 0 },
1956 { 0 }
1958 DWORD cItem = 1;
1960 if (info->fPathLenConstraint)
1962 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1963 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1964 cItem++;
1966 if (info->cSubtreesConstraint)
1968 items[cItem].pvStructInfo = &info->cSubtreesConstraint;
1969 items[cItem].encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
1970 cItem++;
1972 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1973 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1975 __EXCEPT_PAGE_FAULT
1977 SetLastError(STATUS_ACCESS_VIOLATION);
1978 ret = FALSE;
1980 __ENDTRY
1981 return ret;
1984 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
1985 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1986 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1988 BOOL ret;
1990 __TRY
1992 const CERT_BASIC_CONSTRAINTS2_INFO *info =
1993 (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
1994 struct AsnEncodeSequenceItem items[2] = { { 0 } };
1995 DWORD cItem = 0;
1997 if (info->fCA)
1999 items[cItem].pvStructInfo = &info->fCA;
2000 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
2001 cItem++;
2003 if (info->fPathLenConstraint)
2005 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
2006 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
2007 cItem++;
2009 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
2010 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2012 __EXCEPT_PAGE_FAULT
2014 SetLastError(STATUS_ACCESS_VIOLATION);
2015 ret = FALSE;
2017 __ENDTRY
2018 return ret;
2021 static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
2022 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2023 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2025 BOOL ret;
2027 __TRY
2029 const BLOBHEADER *hdr =
2030 (const BLOBHEADER *)pvStructInfo;
2032 if (hdr->bType != PUBLICKEYBLOB)
2034 SetLastError(E_INVALIDARG);
2035 ret = FALSE;
2037 else
2039 const RSAPUBKEY *rsaPubKey = (const RSAPUBKEY *)
2040 ((const BYTE *)pvStructInfo + sizeof(BLOBHEADER));
2041 CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8,
2042 (BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) };
2043 struct AsnEncodeSequenceItem items[] = {
2044 { &blob, CRYPT_AsnEncodeUnsignedInteger, 0 },
2045 { &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 },
2048 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
2049 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
2050 pcbEncoded);
2053 __EXCEPT_PAGE_FAULT
2055 SetLastError(STATUS_ACCESS_VIOLATION);
2056 ret = FALSE;
2058 __ENDTRY
2059 return ret;
2062 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
2063 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2064 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2066 BOOL ret;
2068 __TRY
2070 const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
2071 DWORD bytesNeeded, lenBytes;
2073 TRACE("(%d, %p), %08x, %p, %p, %d\n", blob->cbData, blob->pbData,
2074 dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
2076 CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
2077 bytesNeeded = 1 + lenBytes + blob->cbData;
2078 if (!pbEncoded)
2080 *pcbEncoded = bytesNeeded;
2081 ret = TRUE;
2083 else
2085 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2086 pcbEncoded, bytesNeeded)))
2088 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2089 pbEncoded = *(BYTE **)pbEncoded;
2090 *pbEncoded++ = ASN_OCTETSTRING;
2091 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
2092 pbEncoded += lenBytes;
2093 if (blob->cbData)
2094 memcpy(pbEncoded, blob->pbData, blob->cbData);
2098 __EXCEPT_PAGE_FAULT
2100 SetLastError(STATUS_ACCESS_VIOLATION);
2101 ret = FALSE;
2103 __ENDTRY
2104 TRACE("returning %d (%08x)\n", ret, GetLastError());
2105 return ret;
2108 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
2109 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2110 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2112 BOOL ret;
2114 __TRY
2116 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
2117 DWORD bytesNeeded, lenBytes, dataBytes;
2118 BYTE unusedBits;
2120 /* yep, MS allows cUnusedBits to be >= 8 */
2121 if (!blob->cUnusedBits)
2123 dataBytes = blob->cbData;
2124 unusedBits = 0;
2126 else if (blob->cbData * 8 > blob->cUnusedBits)
2128 dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
2129 unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
2130 blob->cUnusedBits;
2132 else
2134 dataBytes = 0;
2135 unusedBits = 0;
2137 CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
2138 bytesNeeded = 1 + lenBytes + dataBytes + 1;
2139 if (!pbEncoded)
2141 *pcbEncoded = bytesNeeded;
2142 ret = TRUE;
2144 else
2146 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2147 pcbEncoded, bytesNeeded)))
2149 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2150 pbEncoded = *(BYTE **)pbEncoded;
2151 *pbEncoded++ = ASN_BITSTRING;
2152 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
2153 pbEncoded += lenBytes;
2154 *pbEncoded++ = unusedBits;
2155 if (dataBytes)
2157 BYTE mask = 0xff << unusedBits;
2159 if (dataBytes > 1)
2161 memcpy(pbEncoded, blob->pbData, dataBytes - 1);
2162 pbEncoded += dataBytes - 1;
2164 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
2169 __EXCEPT_PAGE_FAULT
2171 SetLastError(STATUS_ACCESS_VIOLATION);
2172 ret = FALSE;
2174 __ENDTRY
2175 return ret;
2178 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(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 CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
2187 CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
2189 ret = TRUE;
2190 if (newBlob.cbData)
2192 newBlob.pbData = CryptMemAlloc(newBlob.cbData);
2193 if (newBlob.pbData)
2195 DWORD i;
2197 for (i = 0; i < newBlob.cbData; i++)
2198 newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
2200 else
2201 ret = FALSE;
2203 if (ret)
2204 ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
2205 &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2206 CryptMemFree(newBlob.pbData);
2208 __EXCEPT_PAGE_FAULT
2210 SetLastError(STATUS_ACCESS_VIOLATION);
2211 ret = FALSE;
2213 __ENDTRY
2214 return ret;
2217 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
2218 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2219 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2221 CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
2223 return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
2224 &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2227 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
2228 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2229 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2231 BOOL ret;
2233 __TRY
2235 DWORD significantBytes, lenBytes;
2236 BYTE padByte = 0, bytesNeeded;
2237 BOOL pad = FALSE;
2238 const CRYPT_INTEGER_BLOB *blob =
2239 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
2241 significantBytes = blob->cbData;
2242 if (significantBytes)
2244 if (blob->pbData[significantBytes - 1] & 0x80)
2246 /* negative, lop off leading (little-endian) 0xffs */
2247 for (; significantBytes > 0 &&
2248 blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
2250 if (blob->pbData[significantBytes - 1] < 0x80)
2252 padByte = 0xff;
2253 pad = TRUE;
2256 else
2258 /* positive, lop off leading (little-endian) zeroes */
2259 for (; significantBytes > 0 &&
2260 !blob->pbData[significantBytes - 1]; significantBytes--)
2262 if (significantBytes == 0)
2263 significantBytes = 1;
2264 if (blob->pbData[significantBytes - 1] > 0x7f)
2266 padByte = 0;
2267 pad = TRUE;
2271 if (pad)
2272 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2273 else
2274 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2275 bytesNeeded = 1 + lenBytes + significantBytes;
2276 if (pad)
2277 bytesNeeded++;
2278 if (!pbEncoded)
2280 *pcbEncoded = bytesNeeded;
2281 ret = TRUE;
2283 else
2285 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2286 pcbEncoded, bytesNeeded)))
2288 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2289 pbEncoded = *(BYTE **)pbEncoded;
2290 *pbEncoded++ = ASN_INTEGER;
2291 if (pad)
2293 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2294 pbEncoded += lenBytes;
2295 *pbEncoded++ = padByte;
2297 else
2299 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2300 pbEncoded += lenBytes;
2302 for (; significantBytes > 0; significantBytes--)
2303 *(pbEncoded++) = blob->pbData[significantBytes - 1];
2307 __EXCEPT_PAGE_FAULT
2309 SetLastError(STATUS_ACCESS_VIOLATION);
2310 ret = FALSE;
2312 __ENDTRY
2313 return ret;
2316 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
2317 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2318 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2320 BOOL ret;
2322 __TRY
2324 DWORD significantBytes, lenBytes;
2325 BYTE bytesNeeded;
2326 BOOL pad = FALSE;
2327 const CRYPT_INTEGER_BLOB *blob =
2328 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
2330 significantBytes = blob->cbData;
2331 if (significantBytes)
2333 /* positive, lop off leading (little-endian) zeroes */
2334 for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
2335 significantBytes--)
2337 if (significantBytes == 0)
2338 significantBytes = 1;
2339 if (blob->pbData[significantBytes - 1] > 0x7f)
2340 pad = TRUE;
2342 if (pad)
2343 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2344 else
2345 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2346 bytesNeeded = 1 + lenBytes + significantBytes;
2347 if (pad)
2348 bytesNeeded++;
2349 if (!pbEncoded)
2351 *pcbEncoded = bytesNeeded;
2352 ret = TRUE;
2354 else
2356 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2357 pcbEncoded, bytesNeeded)))
2359 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2360 pbEncoded = *(BYTE **)pbEncoded;
2361 *pbEncoded++ = ASN_INTEGER;
2362 if (pad)
2364 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2365 pbEncoded += lenBytes;
2366 *pbEncoded++ = 0;
2368 else
2370 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2371 pbEncoded += lenBytes;
2373 for (; significantBytes > 0; significantBytes--)
2374 *(pbEncoded++) = blob->pbData[significantBytes - 1];
2378 __EXCEPT_PAGE_FAULT
2380 SetLastError(STATUS_ACCESS_VIOLATION);
2381 ret = FALSE;
2383 __ENDTRY
2384 return ret;
2387 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
2388 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2389 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2391 CRYPT_INTEGER_BLOB blob;
2392 BOOL ret;
2394 /* Encode as an unsigned integer, then change the tag to enumerated */
2395 blob.cbData = sizeof(DWORD);
2396 blob.pbData = (BYTE *)pvStructInfo;
2397 ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
2398 X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2399 if (ret && pbEncoded)
2401 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2402 pbEncoded = *(BYTE **)pbEncoded;
2403 pbEncoded[0] = ASN_ENUMERATED;
2405 return ret;
2408 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
2409 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2410 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2412 BOOL ret;
2414 __TRY
2416 SYSTEMTIME sysTime;
2417 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
2418 * temporary buffer because the output buffer is not NULL-terminated.
2420 char buf[16];
2421 static const DWORD bytesNeeded = sizeof(buf) - 1;
2423 if (!pbEncoded)
2425 *pcbEncoded = bytesNeeded;
2426 ret = TRUE;
2428 else
2430 /* Sanity check the year, this is a two-digit year format */
2431 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2432 &sysTime);
2433 if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
2435 SetLastError(CRYPT_E_BAD_ENCODE);
2436 ret = FALSE;
2438 if (ret)
2440 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2441 pbEncoded, pcbEncoded, bytesNeeded)))
2443 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2444 pbEncoded = *(BYTE **)pbEncoded;
2445 buf[0] = ASN_UTCTIME;
2446 buf[1] = bytesNeeded - 2;
2447 snprintf(buf + 2, sizeof(buf) - 2,
2448 "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
2449 sysTime.wYear - 2000 : sysTime.wYear - 1900,
2450 sysTime.wMonth, sysTime.wDay, sysTime.wHour,
2451 sysTime.wMinute, sysTime.wSecond);
2452 memcpy(pbEncoded, buf, bytesNeeded);
2457 __EXCEPT_PAGE_FAULT
2459 SetLastError(STATUS_ACCESS_VIOLATION);
2460 ret = FALSE;
2462 __ENDTRY
2463 return ret;
2466 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
2467 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2468 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2470 BOOL ret;
2472 __TRY
2474 SYSTEMTIME sysTime;
2475 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
2476 * temporary buffer because the output buffer is not NULL-terminated.
2478 char buf[18];
2479 static const DWORD bytesNeeded = sizeof(buf) - 1;
2481 if (!pbEncoded)
2483 *pcbEncoded = bytesNeeded;
2484 ret = TRUE;
2486 else
2488 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2489 &sysTime);
2490 if (ret)
2491 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2492 pcbEncoded, bytesNeeded);
2493 if (ret)
2495 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2496 pbEncoded = *(BYTE **)pbEncoded;
2497 buf[0] = ASN_GENERALTIME;
2498 buf[1] = bytesNeeded - 2;
2499 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
2500 sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour,
2501 sysTime.wMinute, sysTime.wSecond);
2502 memcpy(pbEncoded, buf, bytesNeeded);
2506 __EXCEPT_PAGE_FAULT
2508 SetLastError(STATUS_ACCESS_VIOLATION);
2509 ret = FALSE;
2511 __ENDTRY
2512 return ret;
2515 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
2516 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2517 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2519 BOOL ret;
2521 __TRY
2523 SYSTEMTIME sysTime;
2525 /* Check the year, if it's in the UTCTime range call that encode func */
2526 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
2527 return FALSE;
2528 if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
2529 ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
2530 pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2531 else
2532 ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
2533 lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
2534 pcbEncoded);
2536 __EXCEPT_PAGE_FAULT
2538 SetLastError(STATUS_ACCESS_VIOLATION);
2539 ret = FALSE;
2541 __ENDTRY
2542 return ret;
2545 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
2546 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2547 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2549 BOOL ret;
2551 __TRY
2553 DWORD bytesNeeded, dataLen, lenBytes, i;
2554 const CRYPT_SEQUENCE_OF_ANY *seq =
2555 (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
2557 for (i = 0, dataLen = 0; i < seq->cValue; i++)
2558 dataLen += seq->rgValue[i].cbData;
2559 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2560 bytesNeeded = 1 + lenBytes + dataLen;
2561 if (!pbEncoded)
2563 *pcbEncoded = bytesNeeded;
2564 ret = TRUE;
2566 else
2568 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2569 pcbEncoded, bytesNeeded)))
2571 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2572 pbEncoded = *(BYTE **)pbEncoded;
2573 *pbEncoded++ = ASN_SEQUENCEOF;
2574 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2575 pbEncoded += lenBytes;
2576 for (i = 0; i < seq->cValue; i++)
2578 memcpy(pbEncoded, seq->rgValue[i].pbData,
2579 seq->rgValue[i].cbData);
2580 pbEncoded += seq->rgValue[i].cbData;
2585 __EXCEPT_PAGE_FAULT
2587 SetLastError(STATUS_ACCESS_VIOLATION);
2588 ret = FALSE;
2590 __ENDTRY
2591 return ret;
2594 static BOOL CRYPT_AsnEncodeDistPoint(const CRL_DIST_POINT *distPoint,
2595 BYTE *pbEncoded, DWORD *pcbEncoded)
2597 BOOL ret = TRUE;
2598 struct AsnEncodeSequenceItem items[3] = { { 0 } };
2599 struct AsnConstructedItem constructed = { 0 };
2600 struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2601 DWORD cItem = 0, cSwapped = 0;
2603 switch (distPoint->DistPointName.dwDistPointNameChoice)
2605 case CRL_DIST_POINT_NO_NAME:
2606 /* do nothing */
2607 break;
2608 case CRL_DIST_POINT_FULL_NAME:
2609 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
2610 swapped[cSwapped].pvStructInfo = &distPoint->DistPointName.u.FullName;
2611 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2612 constructed.tag = 0;
2613 constructed.pvStructInfo = &swapped[cSwapped];
2614 constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
2615 items[cItem].pvStructInfo = &constructed;
2616 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2617 cSwapped++;
2618 cItem++;
2619 break;
2620 case CRL_DIST_POINT_ISSUER_RDN_NAME:
2621 FIXME("unimplemented for CRL_DIST_POINT_ISSUER_RDN_NAME\n");
2622 ret = FALSE;
2623 break;
2624 default:
2625 ret = FALSE;
2627 if (ret && distPoint->ReasonFlags.cbData)
2629 swapped[cSwapped].tag = ASN_CONTEXT | 1;
2630 swapped[cSwapped].pvStructInfo = &distPoint->ReasonFlags;
2631 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
2632 items[cItem].pvStructInfo = &swapped[cSwapped];
2633 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2634 cSwapped++;
2635 cItem++;
2637 if (ret && distPoint->CRLIssuer.cAltEntry)
2639 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 2;
2640 swapped[cSwapped].pvStructInfo = &distPoint->CRLIssuer;
2641 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2642 items[cItem].pvStructInfo = &swapped[cSwapped];
2643 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2644 cSwapped++;
2645 cItem++;
2647 if (ret)
2648 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
2649 pbEncoded, pcbEncoded);
2650 return ret;
2653 static BOOL WINAPI CRYPT_AsnEncodeCRLDistPoints(DWORD dwCertEncodingType,
2654 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2655 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2657 BOOL ret;
2659 __TRY
2661 const CRL_DIST_POINTS_INFO *info =
2662 (const CRL_DIST_POINTS_INFO *)pvStructInfo;
2664 if (!info->cDistPoint)
2666 SetLastError(E_INVALIDARG);
2667 ret = FALSE;
2669 else
2671 DWORD bytesNeeded, dataLen, lenBytes, i;
2673 ret = TRUE;
2674 for (i = 0, dataLen = 0; ret && i < info->cDistPoint; i++)
2676 DWORD len;
2678 ret = CRYPT_AsnEncodeDistPoint(&info->rgDistPoint[i], NULL,
2679 &len);
2680 if (ret)
2681 dataLen += len;
2682 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
2684 /* Have to propagate index of failing character */
2685 *pcbEncoded = len;
2688 if (ret)
2690 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2691 bytesNeeded = 1 + lenBytes + dataLen;
2692 if (!pbEncoded)
2694 *pcbEncoded = bytesNeeded;
2695 ret = TRUE;
2697 else
2699 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2700 pbEncoded, pcbEncoded, bytesNeeded)))
2702 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2703 pbEncoded = *(BYTE **)pbEncoded;
2704 *pbEncoded++ = ASN_SEQUENCEOF;
2705 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2706 pbEncoded += lenBytes;
2707 for (i = 0; ret && i < info->cDistPoint; i++)
2709 DWORD len = dataLen;
2711 ret = CRYPT_AsnEncodeDistPoint(
2712 &info->rgDistPoint[i], pbEncoded, &len);
2713 if (ret)
2715 pbEncoded += len;
2716 dataLen -= len;
2724 __EXCEPT_PAGE_FAULT
2726 SetLastError(STATUS_ACCESS_VIOLATION);
2727 ret = FALSE;
2729 __ENDTRY
2730 return ret;
2733 static BOOL WINAPI CRYPT_AsnEncodeEnhancedKeyUsage(DWORD dwCertEncodingType,
2734 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2735 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2737 BOOL ret;
2739 __TRY
2741 const CERT_ENHKEY_USAGE *usage =
2742 (const CERT_ENHKEY_USAGE *)pvStructInfo;
2743 DWORD bytesNeeded = 0, lenBytes, size, i;
2745 ret = TRUE;
2746 for (i = 0; ret && i < usage->cUsageIdentifier; i++)
2748 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
2749 usage->rgpszUsageIdentifier[i],
2750 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &size);
2751 if (ret)
2752 bytesNeeded += size;
2754 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
2755 bytesNeeded += 1 + lenBytes;
2756 if (ret)
2758 if (!pbEncoded)
2759 *pcbEncoded = bytesNeeded;
2760 else
2762 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2763 pbEncoded, pcbEncoded, bytesNeeded)))
2765 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2766 pbEncoded = *(BYTE **)pbEncoded;
2767 *pbEncoded++ = ASN_SEQUENCEOF;
2768 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
2769 &lenBytes);
2770 pbEncoded += lenBytes;
2771 for (i = 0; ret && i < usage->cUsageIdentifier; i++)
2773 size = bytesNeeded;
2774 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
2775 usage->rgpszUsageIdentifier[i],
2776 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pbEncoded,
2777 &size);
2778 if (ret)
2780 pbEncoded += size;
2781 bytesNeeded -= size;
2788 __EXCEPT_PAGE_FAULT
2790 SetLastError(STATUS_ACCESS_VIOLATION);
2791 ret = FALSE;
2793 __ENDTRY
2794 return ret;
2797 static BOOL WINAPI CRYPT_AsnEncodeIssuingDistPoint(DWORD dwCertEncodingType,
2798 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2799 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2801 BOOL ret;
2803 __TRY
2805 const CRL_ISSUING_DIST_POINT *point =
2806 (const CRL_ISSUING_DIST_POINT *)pvStructInfo;
2807 struct AsnEncodeSequenceItem items[6] = { { 0 } };
2808 struct AsnConstructedItem constructed = { 0 };
2809 struct AsnEncodeTagSwappedItem swapped[5] = { { 0 } };
2810 DWORD cItem = 0, cSwapped = 0;
2812 ret = TRUE;
2813 switch (point->DistPointName.dwDistPointNameChoice)
2815 case CRL_DIST_POINT_NO_NAME:
2816 /* do nothing */
2817 break;
2818 case CRL_DIST_POINT_FULL_NAME:
2819 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
2820 swapped[cSwapped].pvStructInfo = &point->DistPointName.u.FullName;
2821 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2822 constructed.tag = 0;
2823 constructed.pvStructInfo = &swapped[cSwapped];
2824 constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
2825 items[cItem].pvStructInfo = &constructed;
2826 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2827 cSwapped++;
2828 cItem++;
2829 break;
2830 default:
2831 SetLastError(E_INVALIDARG);
2832 ret = FALSE;
2834 if (ret && point->fOnlyContainsUserCerts)
2836 swapped[cSwapped].tag = ASN_CONTEXT | 1;
2837 swapped[cSwapped].pvStructInfo = &point->fOnlyContainsUserCerts;
2838 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
2839 items[cItem].pvStructInfo = &swapped[cSwapped];
2840 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2841 cSwapped++;
2842 cItem++;
2844 if (ret && point->fOnlyContainsCACerts)
2846 swapped[cSwapped].tag = ASN_CONTEXT | 2;
2847 swapped[cSwapped].pvStructInfo = &point->fOnlyContainsCACerts;
2848 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
2849 items[cItem].pvStructInfo = &swapped[cSwapped];
2850 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2851 cSwapped++;
2852 cItem++;
2854 if (ret && point->OnlySomeReasonFlags.cbData)
2856 swapped[cSwapped].tag = ASN_CONTEXT | 3;
2857 swapped[cSwapped].pvStructInfo = &point->OnlySomeReasonFlags;
2858 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
2859 items[cItem].pvStructInfo = &swapped[cSwapped];
2860 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2861 cSwapped++;
2862 cItem++;
2864 if (ret && point->fIndirectCRL)
2866 swapped[cSwapped].tag = ASN_CONTEXT | 4;
2867 swapped[cSwapped].pvStructInfo = &point->fIndirectCRL;
2868 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
2869 items[cItem].pvStructInfo = &swapped[cSwapped];
2870 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2871 cSwapped++;
2872 cItem++;
2874 if (ret)
2875 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
2876 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2878 __EXCEPT_PAGE_FAULT
2880 SetLastError(STATUS_ACCESS_VIOLATION);
2881 ret = FALSE;
2883 __ENDTRY
2884 return ret;
2887 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2888 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
2889 void *pvEncoded, DWORD *pcbEncoded)
2891 static HCRYPTOIDFUNCSET set = NULL;
2892 BOOL ret = FALSE;
2893 CryptEncodeObjectExFunc encodeFunc = NULL;
2894 HCRYPTOIDFUNCADDR hFunc = NULL;
2896 TRACE("(0x%08x, %s, %p, 0x%08x, %p, %p, %p)\n", dwCertEncodingType,
2897 debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
2898 pvEncoded, pcbEncoded);
2900 if (!pvEncoded && !pcbEncoded)
2902 SetLastError(ERROR_INVALID_PARAMETER);
2903 return FALSE;
2905 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
2906 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
2908 SetLastError(ERROR_FILE_NOT_FOUND);
2909 return FALSE;
2912 SetLastError(NOERROR);
2913 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
2914 *(BYTE **)pvEncoded = NULL;
2915 if (!HIWORD(lpszStructType))
2917 switch (LOWORD(lpszStructType))
2919 case (WORD)X509_CERT:
2920 encodeFunc = CRYPT_AsnEncodeCert;
2921 break;
2922 case (WORD)X509_CERT_TO_BE_SIGNED:
2923 encodeFunc = CRYPT_AsnEncodeCertInfo;
2924 break;
2925 case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
2926 encodeFunc = CRYPT_AsnEncodeCRLInfo;
2927 break;
2928 case (WORD)X509_EXTENSIONS:
2929 encodeFunc = CRYPT_AsnEncodeExtensions;
2930 break;
2931 case (WORD)X509_NAME_VALUE:
2932 encodeFunc = CRYPT_AsnEncodeNameValue;
2933 break;
2934 case (WORD)X509_NAME:
2935 encodeFunc = CRYPT_AsnEncodeName;
2936 break;
2937 case (WORD)X509_PUBLIC_KEY_INFO:
2938 encodeFunc = CRYPT_AsnEncodePubKeyInfo;
2939 break;
2940 case (WORD)X509_AUTHORITY_KEY_ID:
2941 encodeFunc = CRYPT_AsnEncodeAuthorityKeyId;
2942 break;
2943 case (WORD)X509_ALTERNATE_NAME:
2944 encodeFunc = CRYPT_AsnEncodeAltName;
2945 break;
2946 case (WORD)X509_BASIC_CONSTRAINTS:
2947 encodeFunc = CRYPT_AsnEncodeBasicConstraints;
2948 break;
2949 case (WORD)X509_BASIC_CONSTRAINTS2:
2950 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2951 break;
2952 case (WORD)RSA_CSP_PUBLICKEYBLOB:
2953 encodeFunc = CRYPT_AsnEncodeRsaPubKey;
2954 break;
2955 case (WORD)X509_UNICODE_NAME:
2956 encodeFunc = CRYPT_AsnEncodeUnicodeName;
2957 break;
2958 case (WORD)X509_UNICODE_NAME_VALUE:
2959 encodeFunc = CRYPT_AsnEncodeUnicodeNameValue;
2960 break;
2961 case (WORD)X509_OCTET_STRING:
2962 encodeFunc = CRYPT_AsnEncodeOctets;
2963 break;
2964 case (WORD)X509_BITS:
2965 case (WORD)X509_KEY_USAGE:
2966 encodeFunc = CRYPT_AsnEncodeBits;
2967 break;
2968 case (WORD)X509_INTEGER:
2969 encodeFunc = CRYPT_AsnEncodeInt;
2970 break;
2971 case (WORD)X509_MULTI_BYTE_INTEGER:
2972 encodeFunc = CRYPT_AsnEncodeInteger;
2973 break;
2974 case (WORD)X509_MULTI_BYTE_UINT:
2975 encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
2976 break;
2977 case (WORD)X509_ENUMERATED:
2978 encodeFunc = CRYPT_AsnEncodeEnumerated;
2979 break;
2980 case (WORD)X509_CHOICE_OF_TIME:
2981 encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
2982 break;
2983 case (WORD)X509_SEQUENCE_OF_ANY:
2984 encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
2985 break;
2986 case (WORD)PKCS_UTC_TIME:
2987 encodeFunc = CRYPT_AsnEncodeUtcTime;
2988 break;
2989 case (WORD)X509_CRL_DIST_POINTS:
2990 encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
2991 break;
2992 case (WORD)X509_ENHANCED_KEY_USAGE:
2993 encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
2994 break;
2995 case (WORD)X509_ISSUING_DIST_POINT:
2996 encodeFunc = CRYPT_AsnEncodeIssuingDistPoint;
2997 break;
2998 default:
2999 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
3002 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
3003 encodeFunc = CRYPT_AsnEncodeExtensions;
3004 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
3005 encodeFunc = CRYPT_AsnEncodeUtcTime;
3006 else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER))
3007 encodeFunc = CRYPT_AsnEncodeAuthorityKeyId;
3008 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
3009 encodeFunc = CRYPT_AsnEncodeEnumerated;
3010 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
3011 encodeFunc = CRYPT_AsnEncodeBits;
3012 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
3013 encodeFunc = CRYPT_AsnEncodeOctets;
3014 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS))
3015 encodeFunc = CRYPT_AsnEncodeBasicConstraints;
3016 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
3017 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
3018 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
3019 encodeFunc = CRYPT_AsnEncodeAltName;
3020 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
3021 encodeFunc = CRYPT_AsnEncodeAltName;
3022 else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
3023 encodeFunc = CRYPT_AsnEncodeAltName;
3024 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
3025 encodeFunc = CRYPT_AsnEncodeAltName;
3026 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
3027 encodeFunc = CRYPT_AsnEncodeAltName;
3028 else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
3029 encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
3030 else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
3031 encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
3032 else if (!strcmp(lpszStructType, szOID_ISSUING_DIST_POINT))
3033 encodeFunc = CRYPT_AsnEncodeIssuingDistPoint;
3034 else
3035 TRACE("OID %s not found or unimplemented, looking for DLL\n",
3036 debugstr_a(lpszStructType));
3037 if (!encodeFunc)
3039 if (!set)
3040 set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_EX_FUNC, 0);
3041 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
3042 (void **)&encodeFunc, &hFunc);
3044 if (encodeFunc)
3045 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
3046 dwFlags, pEncodePara, pvEncoded, pcbEncoded);
3047 else
3048 SetLastError(ERROR_FILE_NOT_FOUND);
3049 if (hFunc)
3050 CryptFreeOIDFunctionAddress(hFunc, 0);
3051 return ret;
3054 BOOL WINAPI CryptExportPublicKeyInfo(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
3055 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3057 return CryptExportPublicKeyInfoEx(hCryptProv, dwKeySpec, dwCertEncodingType,
3058 NULL, 0, NULL, pInfo, pcbInfo);
3061 static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3062 DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
3063 DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3065 BOOL ret;
3066 HCRYPTKEY key;
3067 static CHAR oid[] = szOID_RSA_RSA;
3069 TRACE("(%08lx, %d, %08x, %s, %08x, %p, %p, %p)\n", hCryptProv, dwKeySpec,
3070 dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
3071 pInfo, pcbInfo);
3073 if (!pszPublicKeyObjId)
3074 pszPublicKeyObjId = oid;
3075 if ((ret = CryptGetUserKey(hCryptProv, dwKeySpec, &key)))
3077 DWORD keySize = 0;
3079 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &keySize);
3080 if (ret)
3082 LPBYTE pubKey = CryptMemAlloc(keySize);
3084 if (pubKey)
3086 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, pubKey,
3087 &keySize);
3088 if (ret)
3090 DWORD encodedLen = 0;
3092 ret = CryptEncodeObject(dwCertEncodingType,
3093 RSA_CSP_PUBLICKEYBLOB, pubKey, NULL, &encodedLen);
3094 if (ret)
3096 DWORD sizeNeeded = sizeof(CERT_PUBLIC_KEY_INFO) +
3097 strlen(pszPublicKeyObjId) + 1 + encodedLen;
3099 if (!pInfo)
3100 *pcbInfo = sizeNeeded;
3101 else if (*pcbInfo < sizeNeeded)
3103 SetLastError(ERROR_MORE_DATA);
3104 *pcbInfo = sizeNeeded;
3105 ret = FALSE;
3107 else
3109 pInfo->Algorithm.pszObjId = (char *)pInfo +
3110 sizeof(CERT_PUBLIC_KEY_INFO);
3111 lstrcpyA(pInfo->Algorithm.pszObjId,
3112 pszPublicKeyObjId);
3113 pInfo->Algorithm.Parameters.cbData = 0;
3114 pInfo->Algorithm.Parameters.pbData = NULL;
3115 pInfo->PublicKey.pbData =
3116 (BYTE *)pInfo->Algorithm.pszObjId
3117 + lstrlenA(pInfo->Algorithm.pszObjId) + 1;
3118 pInfo->PublicKey.cbData = encodedLen;
3119 pInfo->PublicKey.cUnusedBits = 0;
3120 ret = CryptEncodeObject(dwCertEncodingType,
3121 RSA_CSP_PUBLICKEYBLOB, pubKey,
3122 pInfo->PublicKey.pbData, &pInfo->PublicKey.cbData);
3126 CryptMemFree(pubKey);
3128 else
3129 ret = FALSE;
3131 CryptDestroyKey(key);
3133 return ret;
3136 typedef BOOL (WINAPI *ExportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
3137 DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
3138 DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo);
3140 BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
3141 DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId, DWORD dwFlags,
3142 void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3144 static HCRYPTOIDFUNCSET set = NULL;
3145 BOOL ret;
3146 ExportPublicKeyInfoExFunc exportFunc = NULL;
3147 HCRYPTOIDFUNCADDR hFunc = NULL;
3149 TRACE("(%08lx, %d, %08x, %s, %08x, %p, %p, %p)\n", hCryptProv, dwKeySpec,
3150 dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
3151 pInfo, pcbInfo);
3153 if (!hCryptProv)
3155 SetLastError(ERROR_INVALID_PARAMETER);
3156 return FALSE;
3159 if (pszPublicKeyObjId)
3161 if (!set)
3162 set = CryptInitOIDFunctionSet(CRYPT_OID_EXPORT_PUBLIC_KEY_INFO_FUNC,
3164 CryptGetOIDFunctionAddress(set, dwCertEncodingType, pszPublicKeyObjId,
3165 0, (void **)&exportFunc, &hFunc);
3167 if (!exportFunc)
3168 exportFunc = CRYPT_ExportRsaPublicKeyInfoEx;
3169 ret = exportFunc(hCryptProv, dwKeySpec, dwCertEncodingType,
3170 pszPublicKeyObjId, dwFlags, pvAuxInfo, pInfo, pcbInfo);
3171 if (hFunc)
3172 CryptFreeOIDFunctionAddress(hFunc, 0);
3173 return ret;
3176 BOOL WINAPI CryptImportPublicKeyInfo(HCRYPTPROV hCryptProv,
3177 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
3179 return CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType, pInfo,
3180 0, 0, NULL, phKey);
3183 static BOOL WINAPI CRYPT_ImportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3184 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3185 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
3187 BOOL ret;
3188 DWORD pubKeySize = 0;
3190 TRACE("(%08lx, %d, %p, %d, %08x, %p, %p)\n", hCryptProv,
3191 dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
3193 ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
3194 pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, NULL, &pubKeySize);
3195 if (ret)
3197 LPBYTE pubKey = CryptMemAlloc(pubKeySize);
3199 if (pubKey)
3201 ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
3202 pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, pubKey,
3203 &pubKeySize);
3204 if (ret)
3205 ret = CryptImportKey(hCryptProv, pubKey, pubKeySize, 0, 0,
3206 phKey);
3207 CryptMemFree(pubKey);
3209 else
3210 ret = FALSE;
3212 return ret;
3215 typedef BOOL (WINAPI *ImportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
3216 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3217 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey);
3219 BOOL WINAPI CryptImportPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3220 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3221 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
3223 static HCRYPTOIDFUNCSET set = NULL;
3224 BOOL ret;
3225 ImportPublicKeyInfoExFunc importFunc = NULL;
3226 HCRYPTOIDFUNCADDR hFunc = NULL;
3228 TRACE("(%08lx, %d, %p, %d, %08x, %p, %p)\n", hCryptProv,
3229 dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
3231 if (!set)
3232 set = CryptInitOIDFunctionSet(CRYPT_OID_IMPORT_PUBLIC_KEY_INFO_FUNC, 0);
3233 CryptGetOIDFunctionAddress(set, dwCertEncodingType,
3234 pInfo->Algorithm.pszObjId, 0, (void **)&importFunc, &hFunc);
3235 if (!importFunc)
3236 importFunc = CRYPT_ImportRsaPublicKeyInfoEx;
3237 ret = importFunc(hCryptProv, dwCertEncodingType, pInfo, aiKeyAlg, dwFlags,
3238 pvAuxInfo, phKey);
3239 if (hFunc)
3240 CryptFreeOIDFunctionAddress(hFunc, 0);
3241 return ret;