crypt32: Separate set encoding into a separate function.
[wine.git] / dlls / crypt32 / encode.c
blob77485987333fee2f57d021f335018842740a3fc3
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 CRYPT_SET_OF *set = (CRYPT_SET_OF *)pvStructInfo;
1180 DWORD bytesNeeded = 0, lenBytes, i;
1181 BOOL ret = FALSE;
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 if (*pcbEncoded < bytesNeeded)
1191 *pcbEncoded = bytesNeeded;
1192 SetLastError(ERROR_MORE_DATA);
1194 else
1196 ret = TRUE;
1197 *pcbEncoded = bytesNeeded;
1198 qsort(set->rgValue, set->cValue, sizeof(CRYPT_DER_BLOB), BLOBComp);
1199 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
1200 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded, &lenBytes);
1201 pbEncoded += lenBytes;
1202 for (i = 0; ret && i < set->cValue; i++)
1204 memcpy(pbEncoded, set->rgValue[i].pbData,
1205 set->rgValue[i].cbData);
1206 pbEncoded += set->rgValue[i].cbData;
1210 else
1212 *pcbEncoded = bytesNeeded;
1213 ret = TRUE;
1215 return ret;
1218 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
1219 CryptEncodeObjectExFunc nameValueEncodeFunc, BYTE *pbEncoded,
1220 DWORD *pcbEncoded)
1222 BOOL ret;
1223 CRYPT_SET_OF setOf = { 0, NULL };
1225 __TRY
1227 DWORD i;
1229 ret = TRUE;
1230 if (rdn->cRDNAttr)
1232 setOf.cValue = rdn->cRDNAttr;
1233 setOf.rgValue = CryptMemAlloc(rdn->cRDNAttr *
1234 sizeof(CRYPT_DER_BLOB));
1235 if (!setOf.rgValue)
1236 ret = FALSE;
1237 else
1238 memset(setOf.rgValue, 0, setOf.cValue * sizeof(CRYPT_DER_BLOB));
1240 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1242 setOf.rgValue[i].cbData = 0;
1243 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
1244 nameValueEncodeFunc, NULL, &setOf.rgValue[i].cbData);
1245 if (ret)
1247 setOf.rgValue[i].pbData =
1248 CryptMemAlloc(setOf.rgValue[i].cbData);
1249 if (!setOf.rgValue[i].pbData)
1250 ret = FALSE;
1251 else
1252 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
1253 &rdn->rgRDNAttr[i], nameValueEncodeFunc,
1254 setOf.rgValue[i].pbData, &setOf.rgValue[i].cbData);
1256 if (!ret)
1258 /* Have to propagate index of failing character */
1259 *pcbEncoded = setOf.rgValue[i].cbData;
1262 if (ret)
1263 ret = CRYPT_DEREncodeSet(X509_ASN_ENCODING, NULL, &setOf, 0, NULL,
1264 pbEncoded, pcbEncoded);
1265 for (i = 0; i < setOf.cValue; i++)
1266 CryptMemFree(setOf.rgValue[i].pbData);
1268 __EXCEPT_PAGE_FAULT
1270 SetLastError(STATUS_ACCESS_VIOLATION);
1271 ret = FALSE;
1273 __ENDTRY
1274 CryptMemFree(setOf.rgValue);
1275 return ret;
1278 static BOOL WINAPI CRYPT_AsnEncodeUnicodeNameValue(DWORD dwCertEncodingType,
1279 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1280 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
1282 static BOOL WINAPI CRYPT_AsnEncodeOrCopyUnicodeNameValue(
1283 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
1284 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1285 DWORD *pcbEncoded)
1287 const CERT_NAME_VALUE *value = (const CERT_NAME_VALUE *)pvStructInfo;
1288 BOOL ret;
1290 if (value->dwValueType == CERT_RDN_ENCODED_BLOB)
1291 ret = CRYPT_CopyEncodedBlob(dwCertEncodingType, NULL, &value->Value,
1292 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1293 else
1294 ret = CRYPT_AsnEncodeUnicodeNameValue(dwCertEncodingType, NULL, value,
1295 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1296 return ret;
1299 static BOOL WINAPI CRYPT_AsnEncodeUnicodeName(DWORD dwCertEncodingType,
1300 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1301 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1303 BOOL ret = TRUE;
1305 __TRY
1307 const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1308 DWORD bytesNeeded = 0, lenBytes, size, i;
1310 TRACE("encoding name with %d RDNs\n", info->cRDN);
1311 ret = TRUE;
1312 for (i = 0; ret && i < info->cRDN; i++)
1314 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i],
1315 CRYPT_AsnEncodeOrCopyUnicodeNameValue, NULL, &size);
1316 if (ret)
1317 bytesNeeded += size;
1318 else
1319 *pcbEncoded = size;
1321 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1322 bytesNeeded += 1 + lenBytes;
1323 if (ret)
1325 if (!pbEncoded)
1326 *pcbEncoded = bytesNeeded;
1327 else
1329 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1330 pbEncoded, pcbEncoded, bytesNeeded)))
1332 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1333 pbEncoded = *(BYTE **)pbEncoded;
1334 *pbEncoded++ = ASN_SEQUENCEOF;
1335 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1336 &lenBytes);
1337 pbEncoded += lenBytes;
1338 for (i = 0; ret && i < info->cRDN; i++)
1340 size = bytesNeeded;
1341 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1342 &info->rgRDN[i], CRYPT_AsnEncodeOrCopyUnicodeNameValue,
1343 pbEncoded, &size);
1344 if (ret)
1346 pbEncoded += size;
1347 bytesNeeded -= size;
1349 else
1350 *pcbEncoded = size;
1356 __EXCEPT_PAGE_FAULT
1358 SetLastError(STATUS_ACCESS_VIOLATION);
1359 ret = FALSE;
1361 __ENDTRY
1362 return ret;
1365 static BOOL WINAPI CRYPT_AsnEncodePKCSContentInfo(DWORD dwCertEncodingType,
1366 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1367 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1369 BOOL ret = FALSE;
1371 __TRY
1373 const CRYPT_CONTENT_INFO *info =
1374 (const CRYPT_CONTENT_INFO *)pvStructInfo;
1376 if (!info->pszObjId)
1377 SetLastError(E_INVALIDARG);
1378 else
1380 struct AsnEncodeSequenceItem items[2] = {
1381 { info->pszObjId, CRYPT_AsnEncodeOid, 0 },
1382 { NULL, NULL, 0 },
1384 struct AsnConstructedItem constructed = { 0 };
1385 DWORD cItem = 1;
1387 if (info->Content.cbData)
1389 constructed.tag = 0;
1390 constructed.pvStructInfo = &info->Content;
1391 constructed.encodeFunc = CRYPT_CopyEncodedBlob;
1392 items[cItem].pvStructInfo = &constructed;
1393 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
1394 cItem++;
1396 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
1397 cItem, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1401 __EXCEPT_PAGE_FAULT
1403 SetLastError(STATUS_ACCESS_VIOLATION);
1405 __ENDTRY
1406 return ret;
1409 static BOOL CRYPT_AsnEncodeUnicodeStringCoerce(const CERT_NAME_VALUE *value,
1410 BYTE tag, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1411 DWORD *pcbEncoded)
1413 BOOL ret = TRUE;
1414 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1415 DWORD bytesNeeded, lenBytes, encodedLen;
1417 encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1418 lstrlenW(str);
1419 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1420 bytesNeeded = 1 + lenBytes + encodedLen;
1421 if (!pbEncoded)
1422 *pcbEncoded = bytesNeeded;
1423 else
1425 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1426 pbEncoded, pcbEncoded, bytesNeeded)))
1428 DWORD i;
1430 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1431 pbEncoded = *(BYTE **)pbEncoded;
1432 *pbEncoded++ = tag;
1433 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1434 pbEncoded += lenBytes;
1435 for (i = 0; i < encodedLen; i++)
1436 *pbEncoded++ = (BYTE)str[i];
1439 return ret;
1442 static BOOL CRYPT_AsnEncodeNumericString(const CERT_NAME_VALUE *value,
1443 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1444 DWORD *pcbEncoded)
1446 BOOL ret = TRUE;
1447 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1448 DWORD bytesNeeded, lenBytes, encodedLen;
1450 encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1451 lstrlenW(str);
1452 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1453 bytesNeeded = 1 + lenBytes + encodedLen;
1454 if (!pbEncoded)
1455 *pcbEncoded = bytesNeeded;
1456 else
1458 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1459 pbEncoded, pcbEncoded, bytesNeeded)))
1461 DWORD i;
1463 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1464 pbEncoded = *(BYTE **)pbEncoded;
1465 *pbEncoded++ = ASN_NUMERICSTRING;
1466 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1467 pbEncoded += lenBytes;
1468 for (i = 0; ret && i < encodedLen; i++)
1470 if (isdigitW(str[i]))
1471 *pbEncoded++ = (BYTE)str[i];
1472 else
1474 *pcbEncoded = i;
1475 SetLastError(CRYPT_E_INVALID_NUMERIC_STRING);
1476 ret = FALSE;
1481 return ret;
1484 static inline int isprintableW(WCHAR wc)
1486 return isalnumW(wc) || isspaceW(wc) || wc == '\'' || wc == '(' ||
1487 wc == ')' || wc == '+' || wc == ',' || wc == '-' || wc == '.' ||
1488 wc == '/' || wc == ':' || wc == '=' || wc == '?';
1491 static BOOL CRYPT_AsnEncodePrintableString(const CERT_NAME_VALUE *value,
1492 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1493 DWORD *pcbEncoded)
1495 BOOL ret = TRUE;
1496 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1497 DWORD bytesNeeded, lenBytes, encodedLen;
1499 encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1500 lstrlenW(str);
1501 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1502 bytesNeeded = 1 + lenBytes + encodedLen;
1503 if (!pbEncoded)
1504 *pcbEncoded = bytesNeeded;
1505 else
1507 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1508 pbEncoded, pcbEncoded, bytesNeeded)))
1510 DWORD i;
1512 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1513 pbEncoded = *(BYTE **)pbEncoded;
1514 *pbEncoded++ = ASN_PRINTABLESTRING;
1515 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1516 pbEncoded += lenBytes;
1517 for (i = 0; ret && i < encodedLen; i++)
1519 if (isprintableW(str[i]))
1520 *pbEncoded++ = (BYTE)str[i];
1521 else
1523 *pcbEncoded = i;
1524 SetLastError(CRYPT_E_INVALID_PRINTABLE_STRING);
1525 ret = FALSE;
1530 return ret;
1533 static BOOL CRYPT_AsnEncodeIA5String(const CERT_NAME_VALUE *value,
1534 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1535 DWORD *pcbEncoded)
1537 BOOL ret = TRUE;
1538 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1539 DWORD bytesNeeded, lenBytes, encodedLen;
1541 encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1542 lstrlenW(str);
1543 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1544 bytesNeeded = 1 + lenBytes + encodedLen;
1545 if (!pbEncoded)
1546 *pcbEncoded = bytesNeeded;
1547 else
1549 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1550 pbEncoded, pcbEncoded, bytesNeeded)))
1552 DWORD i;
1554 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1555 pbEncoded = *(BYTE **)pbEncoded;
1556 *pbEncoded++ = ASN_IA5STRING;
1557 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1558 pbEncoded += lenBytes;
1559 for (i = 0; ret && i < encodedLen; i++)
1561 if (str[i] <= 0x7f)
1562 *pbEncoded++ = (BYTE)str[i];
1563 else
1565 *pcbEncoded = i;
1566 SetLastError(CRYPT_E_INVALID_IA5_STRING);
1567 ret = FALSE;
1572 return ret;
1575 static BOOL CRYPT_AsnEncodeUniversalString(const CERT_NAME_VALUE *value,
1576 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1577 DWORD *pcbEncoded)
1579 BOOL ret = TRUE;
1580 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1581 DWORD bytesNeeded, lenBytes, strLen;
1583 /* FIXME: doesn't handle composite characters */
1584 strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1585 lstrlenW(str);
1586 CRYPT_EncodeLen(strLen * 4, NULL, &lenBytes);
1587 bytesNeeded = 1 + lenBytes + strLen * 4;
1588 if (!pbEncoded)
1589 *pcbEncoded = bytesNeeded;
1590 else
1592 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1593 pbEncoded, pcbEncoded, bytesNeeded)))
1595 DWORD i;
1597 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1598 pbEncoded = *(BYTE **)pbEncoded;
1599 *pbEncoded++ = ASN_UNIVERSALSTRING;
1600 CRYPT_EncodeLen(strLen * 4, pbEncoded, &lenBytes);
1601 pbEncoded += lenBytes;
1602 for (i = 0; i < strLen; i++)
1604 *pbEncoded++ = 0;
1605 *pbEncoded++ = 0;
1606 *pbEncoded++ = (BYTE)((str[i] & 0xff00) >> 8);
1607 *pbEncoded++ = (BYTE)(str[i] & 0x00ff);
1611 return ret;
1614 static BOOL WINAPI CRYPT_AsnEncodeUnicodeNameValue(DWORD dwCertEncodingType,
1615 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1616 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1618 BOOL ret = FALSE;
1620 __TRY
1622 const CERT_NAME_VALUE *value = (const CERT_NAME_VALUE *)pvStructInfo;
1624 switch (value->dwValueType)
1626 case CERT_RDN_ANY_TYPE:
1627 case CERT_RDN_ENCODED_BLOB:
1628 case CERT_RDN_OCTET_STRING:
1629 SetLastError(CRYPT_E_NOT_CHAR_STRING);
1630 break;
1631 case CERT_RDN_NUMERIC_STRING:
1632 ret = CRYPT_AsnEncodeNumericString(value, dwFlags, pEncodePara,
1633 pbEncoded, pcbEncoded);
1634 break;
1635 case CERT_RDN_PRINTABLE_STRING:
1636 ret = CRYPT_AsnEncodePrintableString(value, dwFlags, pEncodePara,
1637 pbEncoded, pcbEncoded);
1638 break;
1639 case CERT_RDN_TELETEX_STRING:
1640 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_T61STRING,
1641 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1642 break;
1643 case CERT_RDN_VIDEOTEX_STRING:
1644 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value,
1645 ASN_VIDEOTEXSTRING, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1646 break;
1647 case CERT_RDN_IA5_STRING:
1648 ret = CRYPT_AsnEncodeIA5String(value, dwFlags, pEncodePara,
1649 pbEncoded, pcbEncoded);
1650 break;
1651 case CERT_RDN_GRAPHIC_STRING:
1652 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_GRAPHICSTRING,
1653 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1654 break;
1655 case CERT_RDN_VISIBLE_STRING:
1656 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_VISIBLESTRING,
1657 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1658 break;
1659 case CERT_RDN_GENERAL_STRING:
1660 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_GENERALSTRING,
1661 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1662 break;
1663 case CERT_RDN_UNIVERSAL_STRING:
1664 ret = CRYPT_AsnEncodeUniversalString(value, dwFlags, pEncodePara,
1665 pbEncoded, pcbEncoded);
1666 break;
1667 case CERT_RDN_BMP_STRING:
1668 ret = CRYPT_AsnEncodeBMPString(value, dwFlags, pEncodePara,
1669 pbEncoded, pcbEncoded);
1670 break;
1671 case CERT_RDN_UTF8_STRING:
1672 ret = CRYPT_AsnEncodeUTF8String(value, dwFlags, pEncodePara,
1673 pbEncoded, pcbEncoded);
1674 break;
1675 default:
1676 SetLastError(CRYPT_E_ASN1_CHOICE);
1679 __EXCEPT_PAGE_FAULT
1681 SetLastError(STATUS_ACCESS_VIOLATION);
1683 __ENDTRY
1684 return ret;
1687 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
1688 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1689 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1691 BOOL ret;
1693 __TRY
1695 const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1696 DWORD bytesNeeded = 0, lenBytes, size, i;
1698 TRACE("encoding name with %d RDNs\n", info->cRDN);
1699 ret = TRUE;
1700 for (i = 0; ret && i < info->cRDN; i++)
1702 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i],
1703 CRYPT_AsnEncodeNameValue, NULL, &size);
1704 if (ret)
1705 bytesNeeded += size;
1707 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1708 bytesNeeded += 1 + lenBytes;
1709 if (ret)
1711 if (!pbEncoded)
1712 *pcbEncoded = bytesNeeded;
1713 else
1715 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1716 pbEncoded, pcbEncoded, bytesNeeded)))
1718 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1719 pbEncoded = *(BYTE **)pbEncoded;
1720 *pbEncoded++ = ASN_SEQUENCEOF;
1721 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1722 &lenBytes);
1723 pbEncoded += lenBytes;
1724 for (i = 0; ret && i < info->cRDN; i++)
1726 size = bytesNeeded;
1727 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1728 &info->rgRDN[i], CRYPT_AsnEncodeNameValue, pbEncoded,
1729 &size);
1730 if (ret)
1732 pbEncoded += size;
1733 bytesNeeded -= size;
1740 __EXCEPT_PAGE_FAULT
1742 SetLastError(STATUS_ACCESS_VIOLATION);
1743 ret = FALSE;
1745 __ENDTRY
1746 return ret;
1749 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1750 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1751 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1753 BOOL val = *(const BOOL *)pvStructInfo, ret;
1755 TRACE("%d\n", val);
1757 if (!pbEncoded)
1759 *pcbEncoded = 3;
1760 ret = TRUE;
1762 else if (*pcbEncoded < 3)
1764 *pcbEncoded = 3;
1765 SetLastError(ERROR_MORE_DATA);
1766 ret = FALSE;
1768 else
1770 *pcbEncoded = 3;
1771 *pbEncoded++ = ASN_BOOL;
1772 *pbEncoded++ = 1;
1773 *pbEncoded++ = val ? 0xff : 0;
1774 ret = TRUE;
1776 TRACE("returning %d (%08x)\n", ret, GetLastError());
1777 return ret;
1780 static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry,
1781 BYTE *pbEncoded, DWORD *pcbEncoded)
1783 BOOL ret;
1784 DWORD dataLen;
1786 ret = TRUE;
1787 switch (entry->dwAltNameChoice)
1789 case CERT_ALT_NAME_RFC822_NAME:
1790 case CERT_ALT_NAME_DNS_NAME:
1791 case CERT_ALT_NAME_URL:
1792 if (entry->u.pwszURL)
1794 DWORD i;
1796 /* Not + 1: don't encode the NULL-terminator */
1797 dataLen = lstrlenW(entry->u.pwszURL);
1798 for (i = 0; ret && i < dataLen; i++)
1800 if (entry->u.pwszURL[i] > 0x7f)
1802 SetLastError(CRYPT_E_INVALID_IA5_STRING);
1803 ret = FALSE;
1804 *pcbEncoded = i;
1808 else
1809 dataLen = 0;
1810 break;
1811 case CERT_ALT_NAME_IP_ADDRESS:
1812 dataLen = entry->u.IPAddress.cbData;
1813 break;
1814 case CERT_ALT_NAME_REGISTERED_ID:
1815 /* FIXME: encode OID */
1816 case CERT_ALT_NAME_OTHER_NAME:
1817 case CERT_ALT_NAME_DIRECTORY_NAME:
1818 FIXME("name type %d unimplemented\n", entry->dwAltNameChoice);
1819 return FALSE;
1820 default:
1821 SetLastError(E_INVALIDARG);
1822 return FALSE;
1824 if (ret)
1826 DWORD bytesNeeded, lenBytes;
1828 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1829 bytesNeeded = 1 + dataLen + lenBytes;
1830 if (!pbEncoded)
1831 *pcbEncoded = bytesNeeded;
1832 else if (*pcbEncoded < bytesNeeded)
1834 SetLastError(ERROR_MORE_DATA);
1835 *pcbEncoded = bytesNeeded;
1836 ret = FALSE;
1838 else
1840 *pbEncoded++ = ASN_CONTEXT | (entry->dwAltNameChoice - 1);
1841 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1842 pbEncoded += lenBytes;
1843 switch (entry->dwAltNameChoice)
1845 case CERT_ALT_NAME_RFC822_NAME:
1846 case CERT_ALT_NAME_DNS_NAME:
1847 case CERT_ALT_NAME_URL:
1849 DWORD i;
1851 for (i = 0; i < dataLen; i++)
1852 *pbEncoded++ = (BYTE)entry->u.pwszURL[i];
1853 break;
1855 case CERT_ALT_NAME_IP_ADDRESS:
1856 memcpy(pbEncoded, entry->u.IPAddress.pbData, dataLen);
1857 break;
1859 if (ret)
1860 *pcbEncoded = bytesNeeded;
1863 TRACE("returning %d (%08x)\n", ret, GetLastError());
1864 return ret;
1867 static BOOL WINAPI CRYPT_AsnEncodeAuthorityKeyId(DWORD dwCertEncodingType,
1868 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1869 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1871 BOOL ret;
1873 __TRY
1875 const CERT_AUTHORITY_KEY_ID_INFO *info =
1876 (const CERT_AUTHORITY_KEY_ID_INFO *)pvStructInfo;
1877 struct AsnEncodeSequenceItem items[3] = { { 0 } };
1878 struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
1879 struct AsnConstructedItem constructed = { 0 };
1880 DWORD cItem = 0, cSwapped = 0;
1882 if (info->KeyId.cbData)
1884 swapped[cSwapped].tag = ASN_CONTEXT | 0;
1885 swapped[cSwapped].pvStructInfo = &info->KeyId;
1886 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
1887 items[cItem].pvStructInfo = &swapped[cSwapped];
1888 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
1889 cSwapped++;
1890 cItem++;
1892 if (info->CertIssuer.cbData)
1894 constructed.tag = 1;
1895 constructed.pvStructInfo = &info->CertIssuer;
1896 constructed.encodeFunc = CRYPT_CopyEncodedBlob;
1897 items[cItem].pvStructInfo = &constructed;
1898 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
1899 cItem++;
1901 if (info->CertSerialNumber.cbData)
1903 swapped[cSwapped].tag = ASN_CONTEXT | 2;
1904 swapped[cSwapped].pvStructInfo = &info->CertSerialNumber;
1905 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
1906 items[cItem].pvStructInfo = &swapped[cSwapped];
1907 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
1908 cSwapped++;
1909 cItem++;
1911 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, dwFlags,
1912 pEncodePara, pbEncoded, pcbEncoded);
1914 __EXCEPT_PAGE_FAULT
1916 SetLastError(STATUS_ACCESS_VIOLATION);
1917 ret = FALSE;
1919 __ENDTRY
1920 return ret;
1923 static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
1924 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1925 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1927 BOOL ret;
1929 __TRY
1931 const CERT_ALT_NAME_INFO *info =
1932 (const CERT_ALT_NAME_INFO *)pvStructInfo;
1933 DWORD bytesNeeded, dataLen, lenBytes, i;
1935 ret = TRUE;
1936 /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
1937 * can't encode an erroneous entry index if it's bigger than this.
1939 for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
1941 DWORD len;
1943 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i], NULL,
1944 &len);
1945 if (ret)
1946 dataLen += len;
1947 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
1949 /* CRYPT_AsnEncodeAltNameEntry encoded the index of
1950 * the bad character, now set the index of the bad
1951 * entry
1953 *pcbEncoded = (BYTE)i <<
1954 CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT | len;
1957 if (ret)
1959 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1960 bytesNeeded = 1 + lenBytes + dataLen;
1961 if (!pbEncoded)
1963 *pcbEncoded = bytesNeeded;
1964 ret = TRUE;
1966 else
1968 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1969 pbEncoded, pcbEncoded, bytesNeeded)))
1971 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1972 pbEncoded = *(BYTE **)pbEncoded;
1973 *pbEncoded++ = ASN_SEQUENCEOF;
1974 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1975 pbEncoded += lenBytes;
1976 for (i = 0; ret && i < info->cAltEntry; i++)
1978 DWORD len = dataLen;
1980 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i],
1981 pbEncoded, &len);
1982 if (ret)
1984 pbEncoded += len;
1985 dataLen -= len;
1992 __EXCEPT_PAGE_FAULT
1994 SetLastError(STATUS_ACCESS_VIOLATION);
1995 ret = FALSE;
1997 __ENDTRY
1998 return ret;
2001 static BOOL WINAPI CRYPT_AsnEncodeAuthorityKeyId2(DWORD dwCertEncodingType,
2002 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2003 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2005 BOOL ret;
2007 __TRY
2009 const CERT_AUTHORITY_KEY_ID2_INFO *info =
2010 (const CERT_AUTHORITY_KEY_ID2_INFO *)pvStructInfo;
2011 struct AsnEncodeSequenceItem items[3] = { { 0 } };
2012 struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2013 DWORD cItem = 0, cSwapped = 0;
2015 if (info->KeyId.cbData)
2017 swapped[cSwapped].tag = ASN_CONTEXT | 0;
2018 swapped[cSwapped].pvStructInfo = &info->KeyId;
2019 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
2020 items[cItem].pvStructInfo = &swapped[cSwapped];
2021 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2022 cSwapped++;
2023 cItem++;
2025 if (info->AuthorityCertIssuer.cAltEntry)
2027 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 1;
2028 swapped[cSwapped].pvStructInfo = &info->AuthorityCertIssuer;
2029 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2030 items[cItem].pvStructInfo = &swapped[cSwapped];
2031 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2032 cSwapped++;
2033 cItem++;
2035 if (info->AuthorityCertSerialNumber.cbData)
2037 swapped[cSwapped].tag = ASN_CONTEXT | 2;
2038 swapped[cSwapped].pvStructInfo = &info->AuthorityCertSerialNumber;
2039 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
2040 items[cItem].pvStructInfo = &swapped[cSwapped];
2041 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2042 cSwapped++;
2043 cItem++;
2045 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, dwFlags,
2046 pEncodePara, pbEncoded, pcbEncoded);
2048 __EXCEPT_PAGE_FAULT
2050 SetLastError(STATUS_ACCESS_VIOLATION);
2051 ret = FALSE;
2053 __ENDTRY
2054 return ret;
2057 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints(DWORD dwCertEncodingType,
2058 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2059 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2061 BOOL ret;
2063 __TRY
2065 const CERT_BASIC_CONSTRAINTS_INFO *info =
2066 (const CERT_BASIC_CONSTRAINTS_INFO *)pvStructInfo;
2067 struct AsnEncodeSequenceItem items[3] = {
2068 { &info->SubjectType, CRYPT_AsnEncodeBits, 0 },
2069 { 0 }
2071 DWORD cItem = 1;
2073 if (info->fPathLenConstraint)
2075 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
2076 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
2077 cItem++;
2079 if (info->cSubtreesConstraint)
2081 items[cItem].pvStructInfo = &info->cSubtreesConstraint;
2082 items[cItem].encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
2083 cItem++;
2085 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
2086 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2088 __EXCEPT_PAGE_FAULT
2090 SetLastError(STATUS_ACCESS_VIOLATION);
2091 ret = FALSE;
2093 __ENDTRY
2094 return ret;
2097 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
2098 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2099 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2101 BOOL ret;
2103 __TRY
2105 const CERT_BASIC_CONSTRAINTS2_INFO *info =
2106 (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
2107 struct AsnEncodeSequenceItem items[2] = { { 0 } };
2108 DWORD cItem = 0;
2110 if (info->fCA)
2112 items[cItem].pvStructInfo = &info->fCA;
2113 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
2114 cItem++;
2116 if (info->fPathLenConstraint)
2118 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
2119 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
2120 cItem++;
2122 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
2123 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2125 __EXCEPT_PAGE_FAULT
2127 SetLastError(STATUS_ACCESS_VIOLATION);
2128 ret = FALSE;
2130 __ENDTRY
2131 return ret;
2134 static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
2135 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2136 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2138 BOOL ret;
2140 __TRY
2142 const BLOBHEADER *hdr =
2143 (const BLOBHEADER *)pvStructInfo;
2145 if (hdr->bType != PUBLICKEYBLOB)
2147 SetLastError(E_INVALIDARG);
2148 ret = FALSE;
2150 else
2152 const RSAPUBKEY *rsaPubKey = (const RSAPUBKEY *)
2153 ((const BYTE *)pvStructInfo + sizeof(BLOBHEADER));
2154 CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8,
2155 (BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) };
2156 struct AsnEncodeSequenceItem items[] = {
2157 { &blob, CRYPT_AsnEncodeUnsignedInteger, 0 },
2158 { &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 },
2161 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
2162 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
2163 pcbEncoded);
2166 __EXCEPT_PAGE_FAULT
2168 SetLastError(STATUS_ACCESS_VIOLATION);
2169 ret = FALSE;
2171 __ENDTRY
2172 return ret;
2175 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
2176 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2177 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2179 BOOL ret;
2181 __TRY
2183 const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
2184 DWORD bytesNeeded, lenBytes;
2186 TRACE("(%d, %p), %08x, %p, %p, %d\n", blob->cbData, blob->pbData,
2187 dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
2189 CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
2190 bytesNeeded = 1 + lenBytes + blob->cbData;
2191 if (!pbEncoded)
2193 *pcbEncoded = bytesNeeded;
2194 ret = TRUE;
2196 else
2198 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2199 pcbEncoded, bytesNeeded)))
2201 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2202 pbEncoded = *(BYTE **)pbEncoded;
2203 *pbEncoded++ = ASN_OCTETSTRING;
2204 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
2205 pbEncoded += lenBytes;
2206 if (blob->cbData)
2207 memcpy(pbEncoded, blob->pbData, blob->cbData);
2211 __EXCEPT_PAGE_FAULT
2213 SetLastError(STATUS_ACCESS_VIOLATION);
2214 ret = FALSE;
2216 __ENDTRY
2217 TRACE("returning %d (%08x)\n", ret, GetLastError());
2218 return ret;
2221 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
2222 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2223 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2225 BOOL ret;
2227 __TRY
2229 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
2230 DWORD bytesNeeded, lenBytes, dataBytes;
2231 BYTE unusedBits;
2233 /* yep, MS allows cUnusedBits to be >= 8 */
2234 if (!blob->cUnusedBits)
2236 dataBytes = blob->cbData;
2237 unusedBits = 0;
2239 else if (blob->cbData * 8 > blob->cUnusedBits)
2241 dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
2242 unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
2243 blob->cUnusedBits;
2245 else
2247 dataBytes = 0;
2248 unusedBits = 0;
2250 CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
2251 bytesNeeded = 1 + lenBytes + dataBytes + 1;
2252 if (!pbEncoded)
2254 *pcbEncoded = bytesNeeded;
2255 ret = TRUE;
2257 else
2259 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2260 pcbEncoded, bytesNeeded)))
2262 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2263 pbEncoded = *(BYTE **)pbEncoded;
2264 *pbEncoded++ = ASN_BITSTRING;
2265 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
2266 pbEncoded += lenBytes;
2267 *pbEncoded++ = unusedBits;
2268 if (dataBytes)
2270 BYTE mask = 0xff << unusedBits;
2272 if (dataBytes > 1)
2274 memcpy(pbEncoded, blob->pbData, dataBytes - 1);
2275 pbEncoded += dataBytes - 1;
2277 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
2282 __EXCEPT_PAGE_FAULT
2284 SetLastError(STATUS_ACCESS_VIOLATION);
2285 ret = FALSE;
2287 __ENDTRY
2288 return ret;
2291 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
2292 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2293 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2295 BOOL ret;
2297 __TRY
2299 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
2300 CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
2302 ret = TRUE;
2303 if (newBlob.cbData)
2305 newBlob.pbData = CryptMemAlloc(newBlob.cbData);
2306 if (newBlob.pbData)
2308 DWORD i;
2310 for (i = 0; i < newBlob.cbData; i++)
2311 newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
2313 else
2314 ret = FALSE;
2316 if (ret)
2317 ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
2318 &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2319 CryptMemFree(newBlob.pbData);
2321 __EXCEPT_PAGE_FAULT
2323 SetLastError(STATUS_ACCESS_VIOLATION);
2324 ret = FALSE;
2326 __ENDTRY
2327 return ret;
2330 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
2331 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2332 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2334 CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
2336 return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
2337 &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2340 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
2341 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2342 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2344 BOOL ret;
2346 __TRY
2348 DWORD significantBytes, lenBytes;
2349 BYTE padByte = 0, bytesNeeded;
2350 BOOL pad = FALSE;
2351 const CRYPT_INTEGER_BLOB *blob =
2352 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
2354 significantBytes = blob->cbData;
2355 if (significantBytes)
2357 if (blob->pbData[significantBytes - 1] & 0x80)
2359 /* negative, lop off leading (little-endian) 0xffs */
2360 for (; significantBytes > 0 &&
2361 blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
2363 if (blob->pbData[significantBytes - 1] < 0x80)
2365 padByte = 0xff;
2366 pad = TRUE;
2369 else
2371 /* positive, lop off leading (little-endian) zeroes */
2372 for (; significantBytes > 0 &&
2373 !blob->pbData[significantBytes - 1]; significantBytes--)
2375 if (significantBytes == 0)
2376 significantBytes = 1;
2377 if (blob->pbData[significantBytes - 1] > 0x7f)
2379 padByte = 0;
2380 pad = TRUE;
2384 if (pad)
2385 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2386 else
2387 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2388 bytesNeeded = 1 + lenBytes + significantBytes;
2389 if (pad)
2390 bytesNeeded++;
2391 if (!pbEncoded)
2393 *pcbEncoded = bytesNeeded;
2394 ret = TRUE;
2396 else
2398 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2399 pcbEncoded, bytesNeeded)))
2401 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2402 pbEncoded = *(BYTE **)pbEncoded;
2403 *pbEncoded++ = ASN_INTEGER;
2404 if (pad)
2406 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2407 pbEncoded += lenBytes;
2408 *pbEncoded++ = padByte;
2410 else
2412 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2413 pbEncoded += lenBytes;
2415 for (; significantBytes > 0; significantBytes--)
2416 *(pbEncoded++) = blob->pbData[significantBytes - 1];
2420 __EXCEPT_PAGE_FAULT
2422 SetLastError(STATUS_ACCESS_VIOLATION);
2423 ret = FALSE;
2425 __ENDTRY
2426 return ret;
2429 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
2430 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2431 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2433 BOOL ret;
2435 __TRY
2437 DWORD significantBytes, lenBytes;
2438 BYTE bytesNeeded;
2439 BOOL pad = FALSE;
2440 const CRYPT_INTEGER_BLOB *blob =
2441 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
2443 significantBytes = blob->cbData;
2444 if (significantBytes)
2446 /* positive, lop off leading (little-endian) zeroes */
2447 for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
2448 significantBytes--)
2450 if (significantBytes == 0)
2451 significantBytes = 1;
2452 if (blob->pbData[significantBytes - 1] > 0x7f)
2453 pad = TRUE;
2455 if (pad)
2456 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2457 else
2458 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2459 bytesNeeded = 1 + lenBytes + significantBytes;
2460 if (pad)
2461 bytesNeeded++;
2462 if (!pbEncoded)
2464 *pcbEncoded = bytesNeeded;
2465 ret = TRUE;
2467 else
2469 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2470 pcbEncoded, bytesNeeded)))
2472 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2473 pbEncoded = *(BYTE **)pbEncoded;
2474 *pbEncoded++ = ASN_INTEGER;
2475 if (pad)
2477 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2478 pbEncoded += lenBytes;
2479 *pbEncoded++ = 0;
2481 else
2483 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2484 pbEncoded += lenBytes;
2486 for (; significantBytes > 0; significantBytes--)
2487 *(pbEncoded++) = blob->pbData[significantBytes - 1];
2491 __EXCEPT_PAGE_FAULT
2493 SetLastError(STATUS_ACCESS_VIOLATION);
2494 ret = FALSE;
2496 __ENDTRY
2497 return ret;
2500 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
2501 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2502 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2504 CRYPT_INTEGER_BLOB blob;
2505 BOOL ret;
2507 /* Encode as an unsigned integer, then change the tag to enumerated */
2508 blob.cbData = sizeof(DWORD);
2509 blob.pbData = (BYTE *)pvStructInfo;
2510 ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
2511 X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2512 if (ret && pbEncoded)
2514 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2515 pbEncoded = *(BYTE **)pbEncoded;
2516 pbEncoded[0] = ASN_ENUMERATED;
2518 return ret;
2521 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
2522 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2523 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2525 BOOL ret;
2527 __TRY
2529 SYSTEMTIME sysTime;
2530 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
2531 * temporary buffer because the output buffer is not NULL-terminated.
2533 char buf[16];
2534 static const DWORD bytesNeeded = sizeof(buf) - 1;
2536 if (!pbEncoded)
2538 *pcbEncoded = bytesNeeded;
2539 ret = TRUE;
2541 else
2543 /* Sanity check the year, this is a two-digit year format */
2544 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2545 &sysTime);
2546 if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
2548 SetLastError(CRYPT_E_BAD_ENCODE);
2549 ret = FALSE;
2551 if (ret)
2553 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2554 pbEncoded, pcbEncoded, bytesNeeded)))
2556 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2557 pbEncoded = *(BYTE **)pbEncoded;
2558 buf[0] = ASN_UTCTIME;
2559 buf[1] = bytesNeeded - 2;
2560 snprintf(buf + 2, sizeof(buf) - 2,
2561 "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
2562 sysTime.wYear - 2000 : sysTime.wYear - 1900,
2563 sysTime.wMonth, sysTime.wDay, sysTime.wHour,
2564 sysTime.wMinute, sysTime.wSecond);
2565 memcpy(pbEncoded, buf, bytesNeeded);
2570 __EXCEPT_PAGE_FAULT
2572 SetLastError(STATUS_ACCESS_VIOLATION);
2573 ret = FALSE;
2575 __ENDTRY
2576 return ret;
2579 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
2580 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2581 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2583 BOOL ret;
2585 __TRY
2587 SYSTEMTIME sysTime;
2588 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
2589 * temporary buffer because the output buffer is not NULL-terminated.
2591 char buf[18];
2592 static const DWORD bytesNeeded = sizeof(buf) - 1;
2594 if (!pbEncoded)
2596 *pcbEncoded = bytesNeeded;
2597 ret = TRUE;
2599 else
2601 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2602 &sysTime);
2603 if (ret)
2604 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2605 pcbEncoded, bytesNeeded);
2606 if (ret)
2608 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2609 pbEncoded = *(BYTE **)pbEncoded;
2610 buf[0] = ASN_GENERALTIME;
2611 buf[1] = bytesNeeded - 2;
2612 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
2613 sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour,
2614 sysTime.wMinute, sysTime.wSecond);
2615 memcpy(pbEncoded, buf, bytesNeeded);
2619 __EXCEPT_PAGE_FAULT
2621 SetLastError(STATUS_ACCESS_VIOLATION);
2622 ret = FALSE;
2624 __ENDTRY
2625 return ret;
2628 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
2629 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2630 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2632 BOOL ret;
2634 __TRY
2636 SYSTEMTIME sysTime;
2638 /* Check the year, if it's in the UTCTime range call that encode func */
2639 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
2640 return FALSE;
2641 if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
2642 ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
2643 pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2644 else
2645 ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
2646 lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
2647 pcbEncoded);
2649 __EXCEPT_PAGE_FAULT
2651 SetLastError(STATUS_ACCESS_VIOLATION);
2652 ret = FALSE;
2654 __ENDTRY
2655 return ret;
2658 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
2659 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2660 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2662 BOOL ret;
2664 __TRY
2666 DWORD bytesNeeded, dataLen, lenBytes, i;
2667 const CRYPT_SEQUENCE_OF_ANY *seq =
2668 (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
2670 for (i = 0, dataLen = 0; i < seq->cValue; i++)
2671 dataLen += seq->rgValue[i].cbData;
2672 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2673 bytesNeeded = 1 + lenBytes + dataLen;
2674 if (!pbEncoded)
2676 *pcbEncoded = bytesNeeded;
2677 ret = TRUE;
2679 else
2681 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2682 pcbEncoded, bytesNeeded)))
2684 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2685 pbEncoded = *(BYTE **)pbEncoded;
2686 *pbEncoded++ = ASN_SEQUENCEOF;
2687 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2688 pbEncoded += lenBytes;
2689 for (i = 0; i < seq->cValue; i++)
2691 memcpy(pbEncoded, seq->rgValue[i].pbData,
2692 seq->rgValue[i].cbData);
2693 pbEncoded += seq->rgValue[i].cbData;
2698 __EXCEPT_PAGE_FAULT
2700 SetLastError(STATUS_ACCESS_VIOLATION);
2701 ret = FALSE;
2703 __ENDTRY
2704 return ret;
2707 static BOOL CRYPT_AsnEncodeDistPoint(const CRL_DIST_POINT *distPoint,
2708 BYTE *pbEncoded, DWORD *pcbEncoded)
2710 BOOL ret = TRUE;
2711 struct AsnEncodeSequenceItem items[3] = { { 0 } };
2712 struct AsnConstructedItem constructed = { 0 };
2713 struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2714 DWORD cItem = 0, cSwapped = 0;
2716 switch (distPoint->DistPointName.dwDistPointNameChoice)
2718 case CRL_DIST_POINT_NO_NAME:
2719 /* do nothing */
2720 break;
2721 case CRL_DIST_POINT_FULL_NAME:
2722 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
2723 swapped[cSwapped].pvStructInfo = &distPoint->DistPointName.u.FullName;
2724 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2725 constructed.tag = 0;
2726 constructed.pvStructInfo = &swapped[cSwapped];
2727 constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
2728 items[cItem].pvStructInfo = &constructed;
2729 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2730 cSwapped++;
2731 cItem++;
2732 break;
2733 case CRL_DIST_POINT_ISSUER_RDN_NAME:
2734 FIXME("unimplemented for CRL_DIST_POINT_ISSUER_RDN_NAME\n");
2735 ret = FALSE;
2736 break;
2737 default:
2738 ret = FALSE;
2740 if (ret && distPoint->ReasonFlags.cbData)
2742 swapped[cSwapped].tag = ASN_CONTEXT | 1;
2743 swapped[cSwapped].pvStructInfo = &distPoint->ReasonFlags;
2744 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
2745 items[cItem].pvStructInfo = &swapped[cSwapped];
2746 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2747 cSwapped++;
2748 cItem++;
2750 if (ret && distPoint->CRLIssuer.cAltEntry)
2752 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 2;
2753 swapped[cSwapped].pvStructInfo = &distPoint->CRLIssuer;
2754 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2755 items[cItem].pvStructInfo = &swapped[cSwapped];
2756 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2757 cSwapped++;
2758 cItem++;
2760 if (ret)
2761 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
2762 pbEncoded, pcbEncoded);
2763 return ret;
2766 static BOOL WINAPI CRYPT_AsnEncodeCRLDistPoints(DWORD dwCertEncodingType,
2767 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2768 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2770 BOOL ret;
2772 __TRY
2774 const CRL_DIST_POINTS_INFO *info =
2775 (const CRL_DIST_POINTS_INFO *)pvStructInfo;
2777 if (!info->cDistPoint)
2779 SetLastError(E_INVALIDARG);
2780 ret = FALSE;
2782 else
2784 DWORD bytesNeeded, dataLen, lenBytes, i;
2786 ret = TRUE;
2787 for (i = 0, dataLen = 0; ret && i < info->cDistPoint; i++)
2789 DWORD len;
2791 ret = CRYPT_AsnEncodeDistPoint(&info->rgDistPoint[i], NULL,
2792 &len);
2793 if (ret)
2794 dataLen += len;
2795 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
2797 /* Have to propagate index of failing character */
2798 *pcbEncoded = len;
2801 if (ret)
2803 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2804 bytesNeeded = 1 + lenBytes + dataLen;
2805 if (!pbEncoded)
2807 *pcbEncoded = bytesNeeded;
2808 ret = TRUE;
2810 else
2812 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2813 pbEncoded, pcbEncoded, bytesNeeded)))
2815 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2816 pbEncoded = *(BYTE **)pbEncoded;
2817 *pbEncoded++ = ASN_SEQUENCEOF;
2818 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2819 pbEncoded += lenBytes;
2820 for (i = 0; ret && i < info->cDistPoint; i++)
2822 DWORD len = dataLen;
2824 ret = CRYPT_AsnEncodeDistPoint(
2825 &info->rgDistPoint[i], pbEncoded, &len);
2826 if (ret)
2828 pbEncoded += len;
2829 dataLen -= len;
2837 __EXCEPT_PAGE_FAULT
2839 SetLastError(STATUS_ACCESS_VIOLATION);
2840 ret = FALSE;
2842 __ENDTRY
2843 return ret;
2846 static BOOL WINAPI CRYPT_AsnEncodeEnhancedKeyUsage(DWORD dwCertEncodingType,
2847 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2848 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2850 BOOL ret;
2852 __TRY
2854 const CERT_ENHKEY_USAGE *usage =
2855 (const CERT_ENHKEY_USAGE *)pvStructInfo;
2856 DWORD bytesNeeded = 0, lenBytes, size, i;
2858 ret = TRUE;
2859 for (i = 0; ret && i < usage->cUsageIdentifier; i++)
2861 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
2862 usage->rgpszUsageIdentifier[i],
2863 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &size);
2864 if (ret)
2865 bytesNeeded += size;
2867 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
2868 bytesNeeded += 1 + lenBytes;
2869 if (ret)
2871 if (!pbEncoded)
2872 *pcbEncoded = bytesNeeded;
2873 else
2875 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2876 pbEncoded, pcbEncoded, bytesNeeded)))
2878 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2879 pbEncoded = *(BYTE **)pbEncoded;
2880 *pbEncoded++ = ASN_SEQUENCEOF;
2881 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
2882 &lenBytes);
2883 pbEncoded += lenBytes;
2884 for (i = 0; ret && i < usage->cUsageIdentifier; i++)
2886 size = bytesNeeded;
2887 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
2888 usage->rgpszUsageIdentifier[i],
2889 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pbEncoded,
2890 &size);
2891 if (ret)
2893 pbEncoded += size;
2894 bytesNeeded -= size;
2901 __EXCEPT_PAGE_FAULT
2903 SetLastError(STATUS_ACCESS_VIOLATION);
2904 ret = FALSE;
2906 __ENDTRY
2907 return ret;
2910 static BOOL WINAPI CRYPT_AsnEncodeIssuingDistPoint(DWORD dwCertEncodingType,
2911 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2912 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2914 BOOL ret;
2916 __TRY
2918 const CRL_ISSUING_DIST_POINT *point =
2919 (const CRL_ISSUING_DIST_POINT *)pvStructInfo;
2920 struct AsnEncodeSequenceItem items[6] = { { 0 } };
2921 struct AsnConstructedItem constructed = { 0 };
2922 struct AsnEncodeTagSwappedItem swapped[5] = { { 0 } };
2923 DWORD cItem = 0, cSwapped = 0;
2925 ret = TRUE;
2926 switch (point->DistPointName.dwDistPointNameChoice)
2928 case CRL_DIST_POINT_NO_NAME:
2929 /* do nothing */
2930 break;
2931 case CRL_DIST_POINT_FULL_NAME:
2932 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
2933 swapped[cSwapped].pvStructInfo = &point->DistPointName.u.FullName;
2934 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2935 constructed.tag = 0;
2936 constructed.pvStructInfo = &swapped[cSwapped];
2937 constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
2938 items[cItem].pvStructInfo = &constructed;
2939 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2940 cSwapped++;
2941 cItem++;
2942 break;
2943 default:
2944 SetLastError(E_INVALIDARG);
2945 ret = FALSE;
2947 if (ret && point->fOnlyContainsUserCerts)
2949 swapped[cSwapped].tag = ASN_CONTEXT | 1;
2950 swapped[cSwapped].pvStructInfo = &point->fOnlyContainsUserCerts;
2951 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
2952 items[cItem].pvStructInfo = &swapped[cSwapped];
2953 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2954 cSwapped++;
2955 cItem++;
2957 if (ret && point->fOnlyContainsCACerts)
2959 swapped[cSwapped].tag = ASN_CONTEXT | 2;
2960 swapped[cSwapped].pvStructInfo = &point->fOnlyContainsCACerts;
2961 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
2962 items[cItem].pvStructInfo = &swapped[cSwapped];
2963 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2964 cSwapped++;
2965 cItem++;
2967 if (ret && point->OnlySomeReasonFlags.cbData)
2969 swapped[cSwapped].tag = ASN_CONTEXT | 3;
2970 swapped[cSwapped].pvStructInfo = &point->OnlySomeReasonFlags;
2971 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
2972 items[cItem].pvStructInfo = &swapped[cSwapped];
2973 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2974 cSwapped++;
2975 cItem++;
2977 if (ret && point->fIndirectCRL)
2979 swapped[cSwapped].tag = ASN_CONTEXT | 4;
2980 swapped[cSwapped].pvStructInfo = &point->fIndirectCRL;
2981 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
2982 items[cItem].pvStructInfo = &swapped[cSwapped];
2983 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2984 cSwapped++;
2985 cItem++;
2987 if (ret)
2988 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
2989 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2991 __EXCEPT_PAGE_FAULT
2993 SetLastError(STATUS_ACCESS_VIOLATION);
2994 ret = FALSE;
2996 __ENDTRY
2997 return ret;
3000 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
3001 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
3002 void *pvEncoded, DWORD *pcbEncoded)
3004 static HCRYPTOIDFUNCSET set = NULL;
3005 BOOL ret = FALSE;
3006 CryptEncodeObjectExFunc encodeFunc = NULL;
3007 HCRYPTOIDFUNCADDR hFunc = NULL;
3009 TRACE("(0x%08x, %s, %p, 0x%08x, %p, %p, %p)\n", dwCertEncodingType,
3010 debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
3011 pvEncoded, pcbEncoded);
3013 if (!pvEncoded && !pcbEncoded)
3015 SetLastError(ERROR_INVALID_PARAMETER);
3016 return FALSE;
3018 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
3019 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
3021 SetLastError(ERROR_FILE_NOT_FOUND);
3022 return FALSE;
3025 SetLastError(NOERROR);
3026 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
3027 *(BYTE **)pvEncoded = NULL;
3028 if (!HIWORD(lpszStructType))
3030 switch (LOWORD(lpszStructType))
3032 case (WORD)X509_CERT:
3033 encodeFunc = CRYPT_AsnEncodeCert;
3034 break;
3035 case (WORD)X509_CERT_TO_BE_SIGNED:
3036 encodeFunc = CRYPT_AsnEncodeCertInfo;
3037 break;
3038 case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
3039 encodeFunc = CRYPT_AsnEncodeCRLInfo;
3040 break;
3041 case (WORD)X509_EXTENSIONS:
3042 encodeFunc = CRYPT_AsnEncodeExtensions;
3043 break;
3044 case (WORD)X509_NAME_VALUE:
3045 encodeFunc = CRYPT_AsnEncodeNameValue;
3046 break;
3047 case (WORD)X509_NAME:
3048 encodeFunc = CRYPT_AsnEncodeName;
3049 break;
3050 case (WORD)X509_PUBLIC_KEY_INFO:
3051 encodeFunc = CRYPT_AsnEncodePubKeyInfo;
3052 break;
3053 case (WORD)X509_AUTHORITY_KEY_ID:
3054 encodeFunc = CRYPT_AsnEncodeAuthorityKeyId;
3055 break;
3056 case (WORD)X509_ALTERNATE_NAME:
3057 encodeFunc = CRYPT_AsnEncodeAltName;
3058 break;
3059 case (WORD)X509_BASIC_CONSTRAINTS:
3060 encodeFunc = CRYPT_AsnEncodeBasicConstraints;
3061 break;
3062 case (WORD)X509_BASIC_CONSTRAINTS2:
3063 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
3064 break;
3065 case (WORD)RSA_CSP_PUBLICKEYBLOB:
3066 encodeFunc = CRYPT_AsnEncodeRsaPubKey;
3067 break;
3068 case (WORD)X509_UNICODE_NAME:
3069 encodeFunc = CRYPT_AsnEncodeUnicodeName;
3070 break;
3071 case (WORD)PKCS_CONTENT_INFO:
3072 encodeFunc = CRYPT_AsnEncodePKCSContentInfo;
3073 break;
3074 case (WORD)X509_UNICODE_NAME_VALUE:
3075 encodeFunc = CRYPT_AsnEncodeUnicodeNameValue;
3076 break;
3077 case (WORD)X509_OCTET_STRING:
3078 encodeFunc = CRYPT_AsnEncodeOctets;
3079 break;
3080 case (WORD)X509_BITS:
3081 case (WORD)X509_KEY_USAGE:
3082 encodeFunc = CRYPT_AsnEncodeBits;
3083 break;
3084 case (WORD)X509_INTEGER:
3085 encodeFunc = CRYPT_AsnEncodeInt;
3086 break;
3087 case (WORD)X509_MULTI_BYTE_INTEGER:
3088 encodeFunc = CRYPT_AsnEncodeInteger;
3089 break;
3090 case (WORD)X509_MULTI_BYTE_UINT:
3091 encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
3092 break;
3093 case (WORD)X509_ENUMERATED:
3094 encodeFunc = CRYPT_AsnEncodeEnumerated;
3095 break;
3096 case (WORD)X509_CHOICE_OF_TIME:
3097 encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
3098 break;
3099 case (WORD)X509_AUTHORITY_KEY_ID2:
3100 encodeFunc = CRYPT_AsnEncodeAuthorityKeyId2;
3101 break;
3102 case (WORD)X509_SEQUENCE_OF_ANY:
3103 encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
3104 break;
3105 case (WORD)PKCS_UTC_TIME:
3106 encodeFunc = CRYPT_AsnEncodeUtcTime;
3107 break;
3108 case (WORD)X509_CRL_DIST_POINTS:
3109 encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
3110 break;
3111 case (WORD)X509_ENHANCED_KEY_USAGE:
3112 encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
3113 break;
3114 case (WORD)X509_ISSUING_DIST_POINT:
3115 encodeFunc = CRYPT_AsnEncodeIssuingDistPoint;
3116 break;
3117 default:
3118 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
3121 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
3122 encodeFunc = CRYPT_AsnEncodeExtensions;
3123 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
3124 encodeFunc = CRYPT_AsnEncodeUtcTime;
3125 else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER))
3126 encodeFunc = CRYPT_AsnEncodeAuthorityKeyId;
3127 else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2))
3128 encodeFunc = CRYPT_AsnEncodeAuthorityKeyId2;
3129 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
3130 encodeFunc = CRYPT_AsnEncodeEnumerated;
3131 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
3132 encodeFunc = CRYPT_AsnEncodeBits;
3133 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
3134 encodeFunc = CRYPT_AsnEncodeOctets;
3135 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS))
3136 encodeFunc = CRYPT_AsnEncodeBasicConstraints;
3137 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
3138 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
3139 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
3140 encodeFunc = CRYPT_AsnEncodeAltName;
3141 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
3142 encodeFunc = CRYPT_AsnEncodeAltName;
3143 else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
3144 encodeFunc = CRYPT_AsnEncodeAltName;
3145 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
3146 encodeFunc = CRYPT_AsnEncodeAltName;
3147 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
3148 encodeFunc = CRYPT_AsnEncodeAltName;
3149 else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
3150 encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
3151 else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
3152 encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
3153 else if (!strcmp(lpszStructType, szOID_ISSUING_DIST_POINT))
3154 encodeFunc = CRYPT_AsnEncodeIssuingDistPoint;
3155 else
3156 TRACE("OID %s not found or unimplemented, looking for DLL\n",
3157 debugstr_a(lpszStructType));
3158 if (!encodeFunc)
3160 if (!set)
3161 set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_EX_FUNC, 0);
3162 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
3163 (void **)&encodeFunc, &hFunc);
3165 if (encodeFunc)
3166 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
3167 dwFlags, pEncodePara, pvEncoded, pcbEncoded);
3168 else
3169 SetLastError(ERROR_FILE_NOT_FOUND);
3170 if (hFunc)
3171 CryptFreeOIDFunctionAddress(hFunc, 0);
3172 return ret;
3175 BOOL WINAPI CryptExportPublicKeyInfo(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
3176 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3178 return CryptExportPublicKeyInfoEx(hCryptProv, dwKeySpec, dwCertEncodingType,
3179 NULL, 0, NULL, pInfo, pcbInfo);
3182 static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3183 DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
3184 DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3186 BOOL ret;
3187 HCRYPTKEY key;
3188 static CHAR oid[] = szOID_RSA_RSA;
3190 TRACE("(%08lx, %d, %08x, %s, %08x, %p, %p, %p)\n", hCryptProv, dwKeySpec,
3191 dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
3192 pInfo, pcbInfo);
3194 if (!pszPublicKeyObjId)
3195 pszPublicKeyObjId = oid;
3196 if ((ret = CryptGetUserKey(hCryptProv, dwKeySpec, &key)))
3198 DWORD keySize = 0;
3200 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &keySize);
3201 if (ret)
3203 LPBYTE pubKey = CryptMemAlloc(keySize);
3205 if (pubKey)
3207 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, pubKey,
3208 &keySize);
3209 if (ret)
3211 DWORD encodedLen = 0;
3213 ret = CryptEncodeObject(dwCertEncodingType,
3214 RSA_CSP_PUBLICKEYBLOB, pubKey, NULL, &encodedLen);
3215 if (ret)
3217 DWORD sizeNeeded = sizeof(CERT_PUBLIC_KEY_INFO) +
3218 strlen(pszPublicKeyObjId) + 1 + encodedLen;
3220 if (!pInfo)
3221 *pcbInfo = sizeNeeded;
3222 else if (*pcbInfo < sizeNeeded)
3224 SetLastError(ERROR_MORE_DATA);
3225 *pcbInfo = sizeNeeded;
3226 ret = FALSE;
3228 else
3230 pInfo->Algorithm.pszObjId = (char *)pInfo +
3231 sizeof(CERT_PUBLIC_KEY_INFO);
3232 lstrcpyA(pInfo->Algorithm.pszObjId,
3233 pszPublicKeyObjId);
3234 pInfo->Algorithm.Parameters.cbData = 0;
3235 pInfo->Algorithm.Parameters.pbData = NULL;
3236 pInfo->PublicKey.pbData =
3237 (BYTE *)pInfo->Algorithm.pszObjId
3238 + lstrlenA(pInfo->Algorithm.pszObjId) + 1;
3239 pInfo->PublicKey.cbData = encodedLen;
3240 pInfo->PublicKey.cUnusedBits = 0;
3241 ret = CryptEncodeObject(dwCertEncodingType,
3242 RSA_CSP_PUBLICKEYBLOB, pubKey,
3243 pInfo->PublicKey.pbData, &pInfo->PublicKey.cbData);
3247 CryptMemFree(pubKey);
3249 else
3250 ret = FALSE;
3252 CryptDestroyKey(key);
3254 return ret;
3257 typedef BOOL (WINAPI *ExportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
3258 DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
3259 DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo);
3261 BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
3262 DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId, DWORD dwFlags,
3263 void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3265 static HCRYPTOIDFUNCSET set = NULL;
3266 BOOL ret;
3267 ExportPublicKeyInfoExFunc exportFunc = NULL;
3268 HCRYPTOIDFUNCADDR hFunc = NULL;
3270 TRACE("(%08lx, %d, %08x, %s, %08x, %p, %p, %p)\n", hCryptProv, dwKeySpec,
3271 dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
3272 pInfo, pcbInfo);
3274 if (!hCryptProv)
3276 SetLastError(ERROR_INVALID_PARAMETER);
3277 return FALSE;
3280 if (pszPublicKeyObjId)
3282 if (!set)
3283 set = CryptInitOIDFunctionSet(CRYPT_OID_EXPORT_PUBLIC_KEY_INFO_FUNC,
3285 CryptGetOIDFunctionAddress(set, dwCertEncodingType, pszPublicKeyObjId,
3286 0, (void **)&exportFunc, &hFunc);
3288 if (!exportFunc)
3289 exportFunc = CRYPT_ExportRsaPublicKeyInfoEx;
3290 ret = exportFunc(hCryptProv, dwKeySpec, dwCertEncodingType,
3291 pszPublicKeyObjId, dwFlags, pvAuxInfo, pInfo, pcbInfo);
3292 if (hFunc)
3293 CryptFreeOIDFunctionAddress(hFunc, 0);
3294 return ret;
3297 BOOL WINAPI CryptImportPublicKeyInfo(HCRYPTPROV hCryptProv,
3298 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
3300 return CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType, pInfo,
3301 0, 0, NULL, phKey);
3304 static BOOL WINAPI CRYPT_ImportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3305 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3306 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
3308 BOOL ret;
3309 DWORD pubKeySize = 0;
3311 TRACE("(%08lx, %d, %p, %d, %08x, %p, %p)\n", hCryptProv,
3312 dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
3314 ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
3315 pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, NULL, &pubKeySize);
3316 if (ret)
3318 LPBYTE pubKey = CryptMemAlloc(pubKeySize);
3320 if (pubKey)
3322 ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
3323 pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, pubKey,
3324 &pubKeySize);
3325 if (ret)
3326 ret = CryptImportKey(hCryptProv, pubKey, pubKeySize, 0, 0,
3327 phKey);
3328 CryptMemFree(pubKey);
3330 else
3331 ret = FALSE;
3333 return ret;
3336 typedef BOOL (WINAPI *ImportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
3337 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3338 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey);
3340 BOOL WINAPI CryptImportPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3341 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3342 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
3344 static HCRYPTOIDFUNCSET set = NULL;
3345 BOOL ret;
3346 ImportPublicKeyInfoExFunc importFunc = NULL;
3347 HCRYPTOIDFUNCADDR hFunc = NULL;
3349 TRACE("(%08lx, %d, %p, %d, %08x, %p, %p)\n", hCryptProv,
3350 dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
3352 if (!set)
3353 set = CryptInitOIDFunctionSet(CRYPT_OID_IMPORT_PUBLIC_KEY_INFO_FUNC, 0);
3354 CryptGetOIDFunctionAddress(set, dwCertEncodingType,
3355 pInfo->Algorithm.pszObjId, 0, (void **)&importFunc, &hFunc);
3356 if (!importFunc)
3357 importFunc = CRYPT_ImportRsaPublicKeyInfoEx;
3358 ret = importFunc(hCryptProv, dwCertEncodingType, pInfo, aiKeyAlg, dwFlags,
3359 pvAuxInfo, phKey);
3360 if (hFunc)
3361 CryptFreeOIDFunctionAddress(hFunc, 0);
3362 return ret;