crypt32: Implement PKCS_CONTENT_INFO encoding/decoding.
[wine.git] / dlls / crypt32 / encode.c
blob2f6fca7f9838eb12755c7de5044f4a9c94b59e83
1 /*
2 * Copyright 2005 Juan Lang
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 * This file implements ASN.1 DER encoding of a limited set of types.
19 * It isn't a full ASN.1 implementation. Microsoft implements BER
20 * encoding of many of the basic types in msasn1.dll, but that interface is
21 * undocumented, so I implement them here.
23 * References:
24 * "A Layman's Guide to a Subset of ASN.1, BER, and DER", by Burton Kaliski
25 * (available online, look for a PDF copy as the HTML versions tend to have
26 * translation errors.)
28 * RFC3280, http://www.faqs.org/rfcs/rfc3280.html
30 * MSDN, especially:
31 * http://msdn.microsoft.com/library/en-us/seccrypto/security/constants_for_cryptencodeobject_and_cryptdecodeobject.asp
34 #include <assert.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stdlib.h>
39 #define NONAMELESSUNION
41 #include "windef.h"
42 #include "winbase.h"
43 #include "wincrypt.h"
44 #include "snmp.h"
45 #include "wine/debug.h"
46 #include "wine/exception.h"
47 #include "wine/unicode.h"
48 #include "crypt32_private.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
52 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
53 BYTE *, DWORD *);
54 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
55 DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
57 /* Prototypes for built-in encoders. They follow the Ex style prototypes.
58 * The dwCertEncodingType and lpszStructType are ignored by the built-in
59 * functions, but the parameters are retained to simplify CryptEncodeObjectEx,
60 * since it must call functions in external DLLs that follow these signatures.
62 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
63 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
64 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
65 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
66 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
67 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
68 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
69 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
70 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
71 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
72 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
73 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
74 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
75 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
76 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
77 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
78 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
79 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
80 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
81 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
82 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
83 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
84 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
85 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
86 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
87 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
88 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
89 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
90 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
91 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
92 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
93 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
94 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
95 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
96 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
97 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
99 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
100 const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
102 static HCRYPTOIDFUNCSET set = NULL;
103 BOOL ret = FALSE;
104 HCRYPTOIDFUNCADDR hFunc;
105 CryptEncodeObjectFunc pCryptEncodeObject;
107 TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
108 debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
109 pcbEncoded);
111 if (!pbEncoded && !pcbEncoded)
113 SetLastError(ERROR_INVALID_PARAMETER);
114 return FALSE;
117 /* Try registered DLL first.. */
118 if (!set)
119 set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_FUNC, 0);
120 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
121 (void **)&pCryptEncodeObject, &hFunc);
122 if (pCryptEncodeObject)
124 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
125 pvStructInfo, pbEncoded, pcbEncoded);
126 CryptFreeOIDFunctionAddress(hFunc, 0);
128 else
130 /* If not, use CryptEncodeObjectEx */
131 ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
132 pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
134 return ret;
137 /* Helper function to check *pcbEncoded, set it to the required size, and
138 * optionally to allocate memory. Assumes pbEncoded is not NULL.
139 * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
140 * pointer to the newly allocated memory.
142 static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
143 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
144 DWORD bytesNeeded)
146 BOOL ret = TRUE;
148 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
150 if (pEncodePara && pEncodePara->pfnAlloc)
151 *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
152 else
153 *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
154 if (!*(BYTE **)pbEncoded)
155 ret = FALSE;
156 else
157 *pcbEncoded = bytesNeeded;
159 else if (bytesNeeded > *pcbEncoded)
161 *pcbEncoded = bytesNeeded;
162 SetLastError(ERROR_MORE_DATA);
163 ret = FALSE;
165 else
166 *pcbEncoded = bytesNeeded;
167 return ret;
170 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
172 DWORD bytesNeeded, significantBytes = 0;
174 if (len <= 0x7f)
175 bytesNeeded = 1;
176 else
178 DWORD temp;
180 for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
181 temp <<= 8, significantBytes--)
183 bytesNeeded = significantBytes + 1;
185 if (!pbEncoded)
187 *pcbEncoded = bytesNeeded;
188 return TRUE;
190 if (*pcbEncoded < bytesNeeded)
192 SetLastError(ERROR_MORE_DATA);
193 return FALSE;
195 if (len <= 0x7f)
196 *pbEncoded = (BYTE)len;
197 else
199 DWORD i;
201 *pbEncoded++ = significantBytes | 0x80;
202 for (i = 0; i < significantBytes; i++)
204 *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
205 len >>= 8;
208 *pcbEncoded = bytesNeeded;
209 return TRUE;
212 struct AsnEncodeSequenceItem
214 const void *pvStructInfo;
215 CryptEncodeObjectExFunc encodeFunc;
216 DWORD size; /* used during encoding, not for your use */
219 static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
220 struct AsnEncodeSequenceItem items[], DWORD cItem, DWORD dwFlags,
221 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
223 BOOL ret;
224 DWORD i, dataLen = 0;
226 TRACE("%p, %d, %08x, %p, %p, %d\n", items, cItem, dwFlags, pEncodePara,
227 pbEncoded, *pcbEncoded);
228 for (i = 0, ret = TRUE; ret && i < cItem; i++)
230 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
231 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
232 NULL, &items[i].size);
233 /* Some functions propagate their errors through the size */
234 if (!ret)
235 *pcbEncoded = items[i].size;
236 dataLen += items[i].size;
238 if (ret)
240 DWORD lenBytes, bytesNeeded;
242 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
243 bytesNeeded = 1 + lenBytes + dataLen;
244 if (!pbEncoded)
245 *pcbEncoded = bytesNeeded;
246 else
248 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
249 pcbEncoded, bytesNeeded)))
251 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
252 pbEncoded = *(BYTE **)pbEncoded;
253 *pbEncoded++ = ASN_SEQUENCE;
254 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
255 pbEncoded += lenBytes;
256 for (i = 0; ret && i < cItem; i++)
258 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
259 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG,
260 NULL, pbEncoded, &items[i].size);
261 /* Some functions propagate their errors through the size */
262 if (!ret)
263 *pcbEncoded = items[i].size;
264 pbEncoded += items[i].size;
269 TRACE("returning %d (%08x)\n", ret, GetLastError());
270 return ret;
273 struct AsnConstructedItem
275 BYTE tag;
276 const void *pvStructInfo;
277 CryptEncodeObjectExFunc encodeFunc;
280 static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
281 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
282 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
284 BOOL ret;
285 const struct AsnConstructedItem *item =
286 (const struct AsnConstructedItem *)pvStructInfo;
287 DWORD len;
289 if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
290 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &len)))
292 DWORD dataLen, bytesNeeded;
294 CRYPT_EncodeLen(len, NULL, &dataLen);
295 bytesNeeded = 1 + dataLen + len;
296 if (!pbEncoded)
297 *pcbEncoded = bytesNeeded;
298 else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
299 pbEncoded, pcbEncoded, bytesNeeded)))
301 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
302 pbEncoded = *(BYTE **)pbEncoded;
303 *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
304 CRYPT_EncodeLen(len, pbEncoded, &dataLen);
305 pbEncoded += dataLen;
306 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
307 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
308 pbEncoded, &len);
309 if (!ret)
311 /* Some functions propagate their errors through the size */
312 *pcbEncoded = len;
316 else
318 /* Some functions propagate their errors through the size */
319 *pcbEncoded = len;
321 return ret;
324 struct AsnEncodeTagSwappedItem
326 BYTE tag;
327 const void *pvStructInfo;
328 CryptEncodeObjectExFunc encodeFunc;
331 /* Sort of a wacky hack, it encodes something using the struct
332 * AsnEncodeTagSwappedItem's encodeFunc, then replaces the tag byte with the tag
333 * given in the struct AsnEncodeTagSwappedItem.
335 static BOOL WINAPI CRYPT_AsnEncodeSwapTag(DWORD dwCertEncodingType,
336 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
337 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
339 BOOL ret;
340 const struct AsnEncodeTagSwappedItem *item =
341 (const struct AsnEncodeTagSwappedItem *)pvStructInfo;
343 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
344 item->pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
345 if (ret && pbEncoded)
346 *pbEncoded = item->tag;
347 return ret;
350 static BOOL WINAPI CRYPT_AsnEncodeCertVersion(DWORD dwCertEncodingType,
351 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
352 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
354 const DWORD *ver = (const DWORD *)pvStructInfo;
355 BOOL ret;
357 /* CERT_V1 is not encoded */
358 if (*ver == CERT_V1)
360 *pcbEncoded = 0;
361 ret = TRUE;
363 else
365 struct AsnConstructedItem item = { 0, ver, CRYPT_AsnEncodeInt };
367 ret = CRYPT_AsnEncodeConstructed(dwCertEncodingType, X509_INTEGER,
368 &item, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
370 return ret;
373 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
374 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
375 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
377 const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
378 BOOL ret;
380 if (!pbEncoded)
382 *pcbEncoded = blob->cbData;
383 ret = TRUE;
385 else
387 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
388 pcbEncoded, blob->cbData)))
390 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
391 pbEncoded = *(BYTE **)pbEncoded;
392 if (blob->cbData)
393 memcpy(pbEncoded, blob->pbData, blob->cbData);
394 *pcbEncoded = blob->cbData;
395 ret = TRUE;
398 return ret;
401 static BOOL WINAPI CRYPT_AsnEncodeValidity(DWORD dwCertEncodingType,
402 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
403 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
405 BOOL ret;
406 /* This has two filetimes in a row, a NotBefore and a NotAfter */
407 const FILETIME *timePtr = (const FILETIME *)pvStructInfo;
408 struct AsnEncodeSequenceItem items[] = {
409 { timePtr++, CRYPT_AsnEncodeChoiceOfTime, 0 },
410 { timePtr, CRYPT_AsnEncodeChoiceOfTime, 0 },
413 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
414 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
415 pcbEncoded);
416 return ret;
419 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmId(
420 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
421 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
422 DWORD *pcbEncoded)
424 const CRYPT_ALGORITHM_IDENTIFIER *algo =
425 (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
426 BOOL ret;
427 struct AsnEncodeSequenceItem items[] = {
428 { algo->pszObjId, CRYPT_AsnEncodeOid, 0 },
429 { &algo->Parameters, CRYPT_CopyEncodedBlob, 0 },
432 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
433 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
434 pcbEncoded);
435 return ret;
438 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
439 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
440 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
442 BOOL ret;
444 __TRY
446 const CERT_PUBLIC_KEY_INFO *info =
447 (const CERT_PUBLIC_KEY_INFO *)pvStructInfo;
448 struct AsnEncodeSequenceItem items[] = {
449 { &info->Algorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
450 { &info->PublicKey, CRYPT_AsnEncodeBits, 0 },
453 TRACE("Encoding public key with OID %s\n",
454 debugstr_a(info->Algorithm.pszObjId));
455 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
456 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
457 pcbEncoded);
459 __EXCEPT_PAGE_FAULT
461 SetLastError(STATUS_ACCESS_VIOLATION);
462 ret = FALSE;
464 __ENDTRY
465 return ret;
468 static BOOL WINAPI CRYPT_AsnEncodeCert(DWORD dwCertEncodingType,
469 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
470 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
472 BOOL ret;
474 __TRY
476 const CERT_SIGNED_CONTENT_INFO *info =
477 (const CERT_SIGNED_CONTENT_INFO *)pvStructInfo;
478 struct AsnEncodeSequenceItem items[] = {
479 { &info->ToBeSigned, CRYPT_CopyEncodedBlob, 0 },
480 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
481 { &info->Signature, CRYPT_AsnEncodeBitsSwapBytes, 0 },
484 if (dwFlags & CRYPT_ENCODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
485 items[2].encodeFunc = CRYPT_AsnEncodeBits;
486 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
487 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
488 pcbEncoded);
490 __EXCEPT_PAGE_FAULT
492 SetLastError(STATUS_ACCESS_VIOLATION);
493 ret = FALSE;
495 __ENDTRY
496 return ret;
499 /* Like in Windows, this blithely ignores the validity of the passed-in
500 * CERT_INFO, and just encodes it as-is. The resulting encoded data may not
501 * decode properly, see CRYPT_AsnDecodeCertInfo.
503 static BOOL WINAPI CRYPT_AsnEncodeCertInfo(DWORD dwCertEncodingType,
504 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
505 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
507 BOOL ret;
509 __TRY
511 const CERT_INFO *info = (const CERT_INFO *)pvStructInfo;
512 struct AsnEncodeSequenceItem items[10] = {
513 { &info->dwVersion, CRYPT_AsnEncodeCertVersion, 0 },
514 { &info->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
515 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
516 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
517 { &info->NotBefore, CRYPT_AsnEncodeValidity, 0 },
518 { &info->Subject, CRYPT_CopyEncodedBlob, 0 },
519 { &info->SubjectPublicKeyInfo, CRYPT_AsnEncodePubKeyInfo, 0 },
520 { 0 }
522 struct AsnConstructedItem constructed[3] = { { 0 } };
523 DWORD cItem = 7, cConstructed = 0;
525 if (info->IssuerUniqueId.cbData)
527 constructed[cConstructed].tag = 1;
528 constructed[cConstructed].pvStructInfo = &info->IssuerUniqueId;
529 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
530 items[cItem].pvStructInfo = &constructed[cConstructed];
531 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
532 cConstructed++;
533 cItem++;
535 if (info->SubjectUniqueId.cbData)
537 constructed[cConstructed].tag = 2;
538 constructed[cConstructed].pvStructInfo = &info->SubjectUniqueId;
539 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
540 items[cItem].pvStructInfo = &constructed[cConstructed];
541 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
542 cConstructed++;
543 cItem++;
545 if (info->cExtension)
547 constructed[cConstructed].tag = 3;
548 constructed[cConstructed].pvStructInfo = &info->cExtension;
549 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions;
550 items[cItem].pvStructInfo = &constructed[cConstructed];
551 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
552 cConstructed++;
553 cItem++;
556 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
557 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
559 __EXCEPT_PAGE_FAULT
561 SetLastError(STATUS_ACCESS_VIOLATION);
562 ret = FALSE;
564 __ENDTRY
565 return ret;
568 static BOOL WINAPI CRYPT_AsnEncodeCRLEntry(const CRL_ENTRY *entry,
569 BYTE *pbEncoded, DWORD *pcbEncoded)
571 struct AsnEncodeSequenceItem items[3] = {
572 { &entry->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
573 { &entry->RevocationDate, CRYPT_AsnEncodeChoiceOfTime, 0 },
574 { 0 }
576 DWORD cItem = 2;
577 BOOL ret;
579 TRACE("%p, %p, %p\n", entry, pbEncoded, pcbEncoded);
581 if (entry->cExtension)
583 items[cItem].pvStructInfo = &entry->cExtension;
584 items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
585 cItem++;
588 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
589 pbEncoded, pcbEncoded);
591 TRACE("returning %d (%08x)\n", ret, GetLastError());
592 return ret;
595 static BOOL WINAPI CRYPT_AsnEncodeCRLEntries(DWORD dwCertEncodingType,
596 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
597 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
599 DWORD cCRLEntry = *(const DWORD *)pvStructInfo;
600 DWORD bytesNeeded, dataLen, lenBytes, i;
601 const CRL_ENTRY *rgCRLEntry = *(const CRL_ENTRY *const *)
602 ((const BYTE *)pvStructInfo + sizeof(DWORD));
603 BOOL ret = TRUE;
605 for (i = 0, dataLen = 0; ret && i < cCRLEntry; i++)
607 DWORD size;
609 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], NULL, &size);
610 if (ret)
611 dataLen += size;
613 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
614 bytesNeeded = 1 + lenBytes + dataLen;
615 if (!pbEncoded)
616 *pcbEncoded = bytesNeeded;
617 else
619 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
620 pcbEncoded, bytesNeeded)))
622 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
623 pbEncoded = *(BYTE **)pbEncoded;
624 *pbEncoded++ = ASN_SEQUENCEOF;
625 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
626 pbEncoded += lenBytes;
627 for (i = 0; i < cCRLEntry; i++)
629 DWORD size = dataLen;
631 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], pbEncoded, &size);
632 pbEncoded += size;
633 dataLen -= size;
637 return ret;
640 static BOOL WINAPI CRYPT_AsnEncodeCRLVersion(DWORD dwCertEncodingType,
641 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
642 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
644 const DWORD *ver = (const DWORD *)pvStructInfo;
645 BOOL ret;
647 /* CRL_V1 is not encoded */
648 if (*ver == CRL_V1)
650 *pcbEncoded = 0;
651 ret = TRUE;
653 else
654 ret = CRYPT_AsnEncodeInt(dwCertEncodingType, X509_INTEGER, ver,
655 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
656 return ret;
659 /* Like in Windows, this blithely ignores the validity of the passed-in
660 * CRL_INFO, and just encodes it as-is. The resulting encoded data may not
661 * decode properly, see CRYPT_AsnDecodeCRLInfo.
663 static BOOL WINAPI CRYPT_AsnEncodeCRLInfo(DWORD dwCertEncodingType,
664 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
665 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
667 BOOL ret;
669 __TRY
671 const CRL_INFO *info = (const CRL_INFO *)pvStructInfo;
672 struct AsnEncodeSequenceItem items[7] = {
673 { &info->dwVersion, CRYPT_AsnEncodeCRLVersion, 0 },
674 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
675 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
676 { &info->ThisUpdate, CRYPT_AsnEncodeChoiceOfTime, 0 },
677 { 0 }
679 struct AsnConstructedItem constructed[1] = { { 0 } };
680 DWORD cItem = 4, cConstructed = 0;
682 if (info->NextUpdate.dwLowDateTime || info->NextUpdate.dwHighDateTime)
684 items[cItem].pvStructInfo = &info->NextUpdate;
685 items[cItem].encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
686 cItem++;
688 if (info->cCRLEntry)
690 items[cItem].pvStructInfo = &info->cCRLEntry;
691 items[cItem].encodeFunc = CRYPT_AsnEncodeCRLEntries;
692 cItem++;
694 if (info->cExtension)
696 constructed[cConstructed].tag = 0;
697 constructed[cConstructed].pvStructInfo = &info->cExtension;
698 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions;
699 items[cItem].pvStructInfo = &constructed[cConstructed];
700 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
701 cConstructed++;
702 cItem++;
705 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
706 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
708 __EXCEPT_PAGE_FAULT
710 SetLastError(STATUS_ACCESS_VIOLATION);
711 ret = FALSE;
713 __ENDTRY
714 return ret;
717 static BOOL CRYPT_AsnEncodeExtension(CERT_EXTENSION *ext, BYTE *pbEncoded,
718 DWORD *pcbEncoded)
720 BOOL ret;
721 struct AsnEncodeSequenceItem items[3] = {
722 { ext->pszObjId, CRYPT_AsnEncodeOid, 0 },
723 { NULL, NULL, 0 },
724 { NULL, NULL, 0 },
726 DWORD cItem = 1;
728 TRACE("%p, %p, %d\n", ext, pbEncoded, *pcbEncoded);
730 if (ext->fCritical)
732 items[cItem].pvStructInfo = &ext->fCritical;
733 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
734 cItem++;
736 items[cItem].pvStructInfo = &ext->Value;
737 items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
738 cItem++;
740 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
741 pbEncoded, pcbEncoded);
742 TRACE("returning %d (%08x)\n", ret, GetLastError());
743 return ret;
746 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
747 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
748 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
750 BOOL ret;
752 __TRY
754 DWORD bytesNeeded, dataLen, lenBytes, i;
755 const CERT_EXTENSIONS *exts = (const CERT_EXTENSIONS *)pvStructInfo;
757 ret = TRUE;
758 for (i = 0, dataLen = 0; ret && i < exts->cExtension; i++)
760 DWORD size;
762 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i], NULL, &size);
763 if (ret)
764 dataLen += size;
766 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
767 bytesNeeded = 1 + lenBytes + dataLen;
768 if (!pbEncoded)
769 *pcbEncoded = bytesNeeded;
770 else
772 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
773 pcbEncoded, bytesNeeded)))
775 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
776 pbEncoded = *(BYTE **)pbEncoded;
777 *pbEncoded++ = ASN_SEQUENCEOF;
778 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
779 pbEncoded += lenBytes;
780 for (i = 0; i < exts->cExtension; i++)
782 DWORD size = dataLen;
784 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i],
785 pbEncoded, &size);
786 pbEncoded += size;
787 dataLen -= size;
792 __EXCEPT_PAGE_FAULT
794 SetLastError(STATUS_ACCESS_VIOLATION);
795 ret = FALSE;
797 __ENDTRY
798 return ret;
801 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
802 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
803 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
805 LPCSTR pszObjId = (LPCSTR)pvStructInfo;
806 DWORD bytesNeeded = 0, lenBytes;
807 BOOL ret = TRUE;
808 int firstPos = 0;
809 BYTE firstByte = 0;
811 TRACE("%s\n", debugstr_a(pszObjId));
813 if (pszObjId)
815 const char *ptr;
816 int val1, val2;
818 if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
820 SetLastError(CRYPT_E_ASN1_ERROR);
821 return FALSE;
823 bytesNeeded++;
824 firstByte = val1 * 40 + val2;
825 ptr = pszObjId + firstPos;
826 while (ret && *ptr)
828 int pos;
830 /* note I assume each component is at most 32-bits long in base 2 */
831 if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
833 if (val1 >= 0x10000000)
834 bytesNeeded += 5;
835 else if (val1 >= 0x200000)
836 bytesNeeded += 4;
837 else if (val1 >= 0x4000)
838 bytesNeeded += 3;
839 else if (val1 >= 0x80)
840 bytesNeeded += 2;
841 else
842 bytesNeeded += 1;
843 ptr += pos;
844 if (*ptr == '.')
845 ptr++;
847 else
849 SetLastError(CRYPT_E_ASN1_ERROR);
850 return FALSE;
853 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
855 else
856 lenBytes = 1;
857 bytesNeeded += 1 + lenBytes;
858 if (pbEncoded)
860 if (*pcbEncoded < bytesNeeded)
862 SetLastError(ERROR_MORE_DATA);
863 ret = FALSE;
865 else
867 *pbEncoded++ = ASN_OBJECTIDENTIFIER;
868 CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
869 pbEncoded += lenBytes;
870 if (pszObjId)
872 const char *ptr;
873 int val, pos;
875 *pbEncoded++ = firstByte;
876 ptr = pszObjId + firstPos;
877 while (ret && *ptr)
879 sscanf(ptr, "%d%n", &val, &pos);
881 unsigned char outBytes[5];
882 int numBytes, i;
884 if (val >= 0x10000000)
885 numBytes = 5;
886 else if (val >= 0x200000)
887 numBytes = 4;
888 else if (val >= 0x4000)
889 numBytes = 3;
890 else if (val >= 0x80)
891 numBytes = 2;
892 else
893 numBytes = 1;
894 for (i = numBytes; i > 0; i--)
896 outBytes[i - 1] = val & 0x7f;
897 val >>= 7;
899 for (i = 0; i < numBytes - 1; i++)
900 *pbEncoded++ = outBytes[i] | 0x80;
901 *pbEncoded++ = outBytes[i];
902 ptr += pos;
903 if (*ptr == '.')
904 ptr++;
910 *pcbEncoded = bytesNeeded;
911 return ret;
914 static BOOL CRYPT_AsnEncodeStringCoerce(const CERT_NAME_VALUE *value,
915 BYTE tag, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
916 DWORD *pcbEncoded)
918 BOOL ret = TRUE;
919 LPCSTR str = (LPCSTR)value->Value.pbData;
920 DWORD bytesNeeded, lenBytes, encodedLen;
922 encodedLen = value->Value.cbData ? value->Value.cbData : lstrlenA(str);
923 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
924 bytesNeeded = 1 + lenBytes + encodedLen;
925 if (!pbEncoded)
926 *pcbEncoded = bytesNeeded;
927 else
929 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
930 pbEncoded, pcbEncoded, bytesNeeded)))
932 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
933 pbEncoded = *(BYTE **)pbEncoded;
934 *pbEncoded++ = tag;
935 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
936 pbEncoded += lenBytes;
937 memcpy(pbEncoded, str, encodedLen);
940 return ret;
943 static BOOL CRYPT_AsnEncodeBMPString(const CERT_NAME_VALUE *value,
944 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
945 DWORD *pcbEncoded)
947 BOOL ret = TRUE;
948 LPCWSTR str = (LPCWSTR)value->Value.pbData;
949 DWORD bytesNeeded, lenBytes, strLen;
951 strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
952 lstrlenW(str);
953 CRYPT_EncodeLen(strLen * 2, NULL, &lenBytes);
954 bytesNeeded = 1 + lenBytes + strLen * 2;
955 if (!pbEncoded)
956 *pcbEncoded = bytesNeeded;
957 else
959 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
960 pbEncoded, pcbEncoded, bytesNeeded)))
962 DWORD i;
964 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
965 pbEncoded = *(BYTE **)pbEncoded;
966 *pbEncoded++ = ASN_BMPSTRING;
967 CRYPT_EncodeLen(strLen * 2, pbEncoded, &lenBytes);
968 pbEncoded += lenBytes;
969 for (i = 0; i < strLen; i++)
971 *pbEncoded++ = (str[i] & 0xff00) >> 8;
972 *pbEncoded++ = str[i] & 0x00ff;
976 return ret;
979 static BOOL CRYPT_AsnEncodeUTF8String(const CERT_NAME_VALUE *value,
980 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
981 DWORD *pcbEncoded)
983 BOOL ret = TRUE;
984 LPCWSTR str = (LPCWSTR)value->Value.pbData;
985 DWORD bytesNeeded, lenBytes, encodedLen, strLen;
987 strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
988 lstrlenW(str);
989 encodedLen = WideCharToMultiByte(CP_UTF8, 0, str, strLen, NULL, 0, NULL,
990 NULL);
991 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
992 bytesNeeded = 1 + lenBytes + encodedLen;
993 if (!pbEncoded)
994 *pcbEncoded = bytesNeeded;
995 else
997 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
998 pbEncoded, pcbEncoded, bytesNeeded)))
1000 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1001 pbEncoded = *(BYTE **)pbEncoded;
1002 *pbEncoded++ = ASN_UTF8STRING;
1003 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1004 pbEncoded += lenBytes;
1005 WideCharToMultiByte(CP_UTF8, 0, str, strLen, (LPSTR)pbEncoded,
1006 bytesNeeded - lenBytes - 1, NULL, NULL);
1009 return ret;
1012 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
1013 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1014 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1016 BOOL ret = TRUE;
1018 __TRY
1020 const CERT_NAME_VALUE *value = (const CERT_NAME_VALUE *)pvStructInfo;
1022 switch (value->dwValueType)
1024 case CERT_RDN_ANY_TYPE:
1025 /* explicitly disallowed */
1026 SetLastError(E_INVALIDARG);
1027 ret = FALSE;
1028 break;
1029 case CERT_RDN_ENCODED_BLOB:
1030 ret = CRYPT_CopyEncodedBlob(dwCertEncodingType, NULL,
1031 &value->Value, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1032 break;
1033 case CERT_RDN_OCTET_STRING:
1034 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_OCTETSTRING,
1035 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1036 break;
1037 case CERT_RDN_NUMERIC_STRING:
1038 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_NUMERICSTRING,
1039 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1040 break;
1041 case CERT_RDN_PRINTABLE_STRING:
1042 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_PRINTABLESTRING,
1043 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1044 break;
1045 case CERT_RDN_TELETEX_STRING:
1046 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_T61STRING,
1047 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1048 break;
1049 case CERT_RDN_VIDEOTEX_STRING:
1050 ret = CRYPT_AsnEncodeStringCoerce(value,
1051 ASN_VIDEOTEXSTRING, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1052 break;
1053 case CERT_RDN_IA5_STRING:
1054 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_IA5STRING,
1055 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1056 break;
1057 case CERT_RDN_GRAPHIC_STRING:
1058 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_GRAPHICSTRING,
1059 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1060 break;
1061 case CERT_RDN_VISIBLE_STRING:
1062 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_VISIBLESTRING,
1063 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1064 break;
1065 case CERT_RDN_GENERAL_STRING:
1066 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_GENERALSTRING,
1067 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1068 break;
1069 case CERT_RDN_UNIVERSAL_STRING:
1070 FIXME("CERT_RDN_UNIVERSAL_STRING: unimplemented\n");
1071 SetLastError(CRYPT_E_ASN1_CHOICE);
1072 ret = FALSE;
1073 break;
1074 case CERT_RDN_BMP_STRING:
1075 ret = CRYPT_AsnEncodeBMPString(value, dwFlags, pEncodePara,
1076 pbEncoded, pcbEncoded);
1077 break;
1078 case CERT_RDN_UTF8_STRING:
1079 ret = CRYPT_AsnEncodeUTF8String(value, dwFlags, pEncodePara,
1080 pbEncoded, pcbEncoded);
1081 break;
1082 default:
1083 SetLastError(CRYPT_E_ASN1_CHOICE);
1084 ret = FALSE;
1087 __EXCEPT_PAGE_FAULT
1089 SetLastError(STATUS_ACCESS_VIOLATION);
1090 ret = FALSE;
1092 __ENDTRY
1093 return ret;
1096 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
1097 CERT_RDN_ATTR *attr, CryptEncodeObjectExFunc nameValueEncodeFunc,
1098 BYTE *pbEncoded, DWORD *pcbEncoded)
1100 DWORD bytesNeeded = 0, lenBytes, size;
1101 BOOL ret;
1103 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL, attr->pszObjId,
1104 0, NULL, NULL, &size);
1105 if (ret)
1107 bytesNeeded += size;
1108 /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
1109 * with dwValueType, so "cast" it to get its encoded size
1111 ret = nameValueEncodeFunc(dwCertEncodingType, NULL,
1112 (CERT_NAME_VALUE *)&attr->dwValueType, 0, NULL, NULL, &size);
1113 if (ret)
1115 bytesNeeded += size;
1116 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1117 bytesNeeded += 1 + lenBytes;
1118 if (pbEncoded)
1120 if (*pcbEncoded < bytesNeeded)
1122 SetLastError(ERROR_MORE_DATA);
1123 ret = FALSE;
1125 else
1127 *pbEncoded++ = ASN_SEQUENCE;
1128 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1129 &lenBytes);
1130 pbEncoded += lenBytes;
1131 size = bytesNeeded - 1 - lenBytes;
1132 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
1133 attr->pszObjId, 0, NULL, pbEncoded, &size);
1134 if (ret)
1136 pbEncoded += size;
1137 size = bytesNeeded - 1 - lenBytes - size;
1138 ret = nameValueEncodeFunc(dwCertEncodingType,
1139 NULL, (CERT_NAME_VALUE *)&attr->dwValueType,
1140 0, NULL, pbEncoded, &size);
1141 if (!ret)
1142 *pcbEncoded = size;
1146 if (ret)
1147 *pcbEncoded = bytesNeeded;
1149 else
1151 /* Have to propagate index of failing character */
1152 *pcbEncoded = size;
1155 return ret;
1158 static int BLOBComp(const void *l, const void *r)
1160 const CRYPT_DER_BLOB *a = (const CRYPT_DER_BLOB *)l, *b = (const CRYPT_DER_BLOB *)r;
1161 int ret;
1163 if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
1164 ret = a->cbData - b->cbData;
1165 return ret;
1168 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
1170 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
1171 CryptEncodeObjectExFunc nameValueEncodeFunc, BYTE *pbEncoded,
1172 DWORD *pcbEncoded)
1174 BOOL ret;
1175 CRYPT_DER_BLOB *blobs = NULL;
1177 __TRY
1179 DWORD bytesNeeded = 0, lenBytes, i;
1181 blobs = NULL;
1182 ret = TRUE;
1183 if (rdn->cRDNAttr)
1185 blobs = CryptMemAlloc(rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1186 if (!blobs)
1187 ret = FALSE;
1188 else
1189 memset(blobs, 0, rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1191 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1193 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
1194 nameValueEncodeFunc, NULL, &blobs[i].cbData);
1195 if (ret)
1196 bytesNeeded += blobs[i].cbData;
1197 else
1199 /* Have to propagate index of failing character */
1200 *pcbEncoded = blobs[i].cbData;
1203 if (ret)
1205 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1206 bytesNeeded += 1 + lenBytes;
1207 if (pbEncoded)
1209 if (*pcbEncoded < bytesNeeded)
1211 SetLastError(ERROR_MORE_DATA);
1212 ret = FALSE;
1214 else
1216 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1218 blobs[i].pbData = CryptMemAlloc(blobs[i].cbData);
1219 if (!blobs[i].pbData)
1220 ret = FALSE;
1221 else
1223 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
1224 &rdn->rgRDNAttr[i], nameValueEncodeFunc,
1225 blobs[i].pbData, &blobs[i].cbData);
1226 if (!ret)
1227 *pcbEncoded = blobs[i].cbData;
1230 if (ret)
1232 qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
1233 BLOBComp);
1234 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
1235 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1236 &lenBytes);
1237 pbEncoded += lenBytes;
1238 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1240 memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
1241 pbEncoded += blobs[i].cbData;
1246 if (ret)
1247 *pcbEncoded = bytesNeeded;
1249 if (blobs)
1251 for (i = 0; i < rdn->cRDNAttr; i++)
1252 CryptMemFree(blobs[i].pbData);
1255 __EXCEPT_PAGE_FAULT
1257 SetLastError(STATUS_ACCESS_VIOLATION);
1258 ret = FALSE;
1260 __ENDTRY
1261 CryptMemFree(blobs);
1262 return ret;
1265 static BOOL WINAPI CRYPT_AsnEncodeUnicodeNameValue(DWORD dwCertEncodingType,
1266 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1267 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
1269 static BOOL WINAPI CRYPT_AsnEncodeOrCopyUnicodeNameValue(
1270 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
1271 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1272 DWORD *pcbEncoded)
1274 const CERT_NAME_VALUE *value = (const CERT_NAME_VALUE *)pvStructInfo;
1275 BOOL ret;
1277 if (value->dwValueType == CERT_RDN_ENCODED_BLOB)
1278 ret = CRYPT_CopyEncodedBlob(dwCertEncodingType, NULL, &value->Value,
1279 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1280 else
1281 ret = CRYPT_AsnEncodeUnicodeNameValue(dwCertEncodingType, NULL, value,
1282 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1283 return ret;
1286 static BOOL WINAPI CRYPT_AsnEncodeUnicodeName(DWORD dwCertEncodingType,
1287 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1288 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1290 BOOL ret = TRUE;
1292 __TRY
1294 const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1295 DWORD bytesNeeded = 0, lenBytes, size, i;
1297 TRACE("encoding name with %d RDNs\n", info->cRDN);
1298 ret = TRUE;
1299 for (i = 0; ret && i < info->cRDN; i++)
1301 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i],
1302 CRYPT_AsnEncodeOrCopyUnicodeNameValue, NULL, &size);
1303 if (ret)
1304 bytesNeeded += size;
1305 else
1306 *pcbEncoded = size;
1308 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1309 bytesNeeded += 1 + lenBytes;
1310 if (ret)
1312 if (!pbEncoded)
1313 *pcbEncoded = bytesNeeded;
1314 else
1316 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1317 pbEncoded, pcbEncoded, bytesNeeded)))
1319 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1320 pbEncoded = *(BYTE **)pbEncoded;
1321 *pbEncoded++ = ASN_SEQUENCEOF;
1322 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1323 &lenBytes);
1324 pbEncoded += lenBytes;
1325 for (i = 0; ret && i < info->cRDN; i++)
1327 size = bytesNeeded;
1328 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1329 &info->rgRDN[i], CRYPT_AsnEncodeOrCopyUnicodeNameValue,
1330 pbEncoded, &size);
1331 if (ret)
1333 pbEncoded += size;
1334 bytesNeeded -= size;
1336 else
1337 *pcbEncoded = size;
1343 __EXCEPT_PAGE_FAULT
1345 SetLastError(STATUS_ACCESS_VIOLATION);
1346 ret = FALSE;
1348 __ENDTRY
1349 return ret;
1352 static BOOL WINAPI CRYPT_AsnEncodePKCSContentInfo(DWORD dwCertEncodingType,
1353 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1354 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1356 BOOL ret = FALSE;
1358 __TRY
1360 const CRYPT_CONTENT_INFO *info =
1361 (const CRYPT_CONTENT_INFO *)pvStructInfo;
1363 if (!info->pszObjId)
1364 SetLastError(E_INVALIDARG);
1365 else
1367 struct AsnEncodeSequenceItem items[2] = {
1368 { info->pszObjId, CRYPT_AsnEncodeOid, 0 },
1369 { NULL, NULL, 0 },
1371 struct AsnConstructedItem constructed = { 0 };
1372 DWORD cItem = 1;
1374 if (info->Content.cbData)
1376 constructed.tag = 0;
1377 constructed.pvStructInfo = &info->Content;
1378 constructed.encodeFunc = CRYPT_CopyEncodedBlob;
1379 items[cItem].pvStructInfo = &constructed;
1380 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
1381 cItem++;
1383 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
1384 cItem, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1388 __EXCEPT_PAGE_FAULT
1390 SetLastError(STATUS_ACCESS_VIOLATION);
1392 __ENDTRY
1393 return ret;
1396 static BOOL CRYPT_AsnEncodeUnicodeStringCoerce(const CERT_NAME_VALUE *value,
1397 BYTE tag, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1398 DWORD *pcbEncoded)
1400 BOOL ret = TRUE;
1401 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1402 DWORD bytesNeeded, lenBytes, encodedLen;
1404 encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1405 lstrlenW(str);
1406 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1407 bytesNeeded = 1 + lenBytes + encodedLen;
1408 if (!pbEncoded)
1409 *pcbEncoded = bytesNeeded;
1410 else
1412 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1413 pbEncoded, pcbEncoded, bytesNeeded)))
1415 DWORD i;
1417 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1418 pbEncoded = *(BYTE **)pbEncoded;
1419 *pbEncoded++ = tag;
1420 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1421 pbEncoded += lenBytes;
1422 for (i = 0; i < encodedLen; i++)
1423 *pbEncoded++ = (BYTE)str[i];
1426 return ret;
1429 static BOOL CRYPT_AsnEncodeNumericString(const CERT_NAME_VALUE *value,
1430 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1431 DWORD *pcbEncoded)
1433 BOOL ret = TRUE;
1434 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1435 DWORD bytesNeeded, lenBytes, encodedLen;
1437 encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1438 lstrlenW(str);
1439 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1440 bytesNeeded = 1 + lenBytes + encodedLen;
1441 if (!pbEncoded)
1442 *pcbEncoded = bytesNeeded;
1443 else
1445 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1446 pbEncoded, pcbEncoded, bytesNeeded)))
1448 DWORD i;
1450 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1451 pbEncoded = *(BYTE **)pbEncoded;
1452 *pbEncoded++ = ASN_NUMERICSTRING;
1453 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1454 pbEncoded += lenBytes;
1455 for (i = 0; ret && i < encodedLen; i++)
1457 if (isdigitW(str[i]))
1458 *pbEncoded++ = (BYTE)str[i];
1459 else
1461 *pcbEncoded = i;
1462 SetLastError(CRYPT_E_INVALID_NUMERIC_STRING);
1463 ret = FALSE;
1468 return ret;
1471 static inline int isprintableW(WCHAR wc)
1473 return isalnumW(wc) || isspaceW(wc) || wc == '\'' || wc == '(' ||
1474 wc == ')' || wc == '+' || wc == ',' || wc == '-' || wc == '.' ||
1475 wc == '/' || wc == ':' || wc == '=' || wc == '?';
1478 static BOOL CRYPT_AsnEncodePrintableString(const CERT_NAME_VALUE *value,
1479 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1480 DWORD *pcbEncoded)
1482 BOOL ret = TRUE;
1483 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1484 DWORD bytesNeeded, lenBytes, encodedLen;
1486 encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1487 lstrlenW(str);
1488 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1489 bytesNeeded = 1 + lenBytes + encodedLen;
1490 if (!pbEncoded)
1491 *pcbEncoded = bytesNeeded;
1492 else
1494 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1495 pbEncoded, pcbEncoded, bytesNeeded)))
1497 DWORD i;
1499 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1500 pbEncoded = *(BYTE **)pbEncoded;
1501 *pbEncoded++ = ASN_PRINTABLESTRING;
1502 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1503 pbEncoded += lenBytes;
1504 for (i = 0; ret && i < encodedLen; i++)
1506 if (isprintableW(str[i]))
1507 *pbEncoded++ = (BYTE)str[i];
1508 else
1510 *pcbEncoded = i;
1511 SetLastError(CRYPT_E_INVALID_PRINTABLE_STRING);
1512 ret = FALSE;
1517 return ret;
1520 static BOOL CRYPT_AsnEncodeIA5String(const CERT_NAME_VALUE *value,
1521 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1522 DWORD *pcbEncoded)
1524 BOOL ret = TRUE;
1525 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1526 DWORD bytesNeeded, lenBytes, encodedLen;
1528 encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1529 lstrlenW(str);
1530 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1531 bytesNeeded = 1 + lenBytes + encodedLen;
1532 if (!pbEncoded)
1533 *pcbEncoded = bytesNeeded;
1534 else
1536 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1537 pbEncoded, pcbEncoded, bytesNeeded)))
1539 DWORD i;
1541 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1542 pbEncoded = *(BYTE **)pbEncoded;
1543 *pbEncoded++ = ASN_IA5STRING;
1544 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1545 pbEncoded += lenBytes;
1546 for (i = 0; ret && i < encodedLen; i++)
1548 if (str[i] <= 0x7f)
1549 *pbEncoded++ = (BYTE)str[i];
1550 else
1552 *pcbEncoded = i;
1553 SetLastError(CRYPT_E_INVALID_IA5_STRING);
1554 ret = FALSE;
1559 return ret;
1562 static BOOL CRYPT_AsnEncodeUniversalString(const CERT_NAME_VALUE *value,
1563 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1564 DWORD *pcbEncoded)
1566 BOOL ret = TRUE;
1567 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1568 DWORD bytesNeeded, lenBytes, strLen;
1570 /* FIXME: doesn't handle composite characters */
1571 strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1572 lstrlenW(str);
1573 CRYPT_EncodeLen(strLen * 4, NULL, &lenBytes);
1574 bytesNeeded = 1 + lenBytes + strLen * 4;
1575 if (!pbEncoded)
1576 *pcbEncoded = bytesNeeded;
1577 else
1579 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1580 pbEncoded, pcbEncoded, bytesNeeded)))
1582 DWORD i;
1584 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1585 pbEncoded = *(BYTE **)pbEncoded;
1586 *pbEncoded++ = ASN_UNIVERSALSTRING;
1587 CRYPT_EncodeLen(strLen * 4, pbEncoded, &lenBytes);
1588 pbEncoded += lenBytes;
1589 for (i = 0; i < strLen; i++)
1591 *pbEncoded++ = 0;
1592 *pbEncoded++ = 0;
1593 *pbEncoded++ = (BYTE)((str[i] & 0xff00) >> 8);
1594 *pbEncoded++ = (BYTE)(str[i] & 0x00ff);
1598 return ret;
1601 static BOOL WINAPI CRYPT_AsnEncodeUnicodeNameValue(DWORD dwCertEncodingType,
1602 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1603 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1605 BOOL ret = FALSE;
1607 __TRY
1609 const CERT_NAME_VALUE *value = (const CERT_NAME_VALUE *)pvStructInfo;
1611 switch (value->dwValueType)
1613 case CERT_RDN_ANY_TYPE:
1614 case CERT_RDN_ENCODED_BLOB:
1615 case CERT_RDN_OCTET_STRING:
1616 SetLastError(CRYPT_E_NOT_CHAR_STRING);
1617 break;
1618 case CERT_RDN_NUMERIC_STRING:
1619 ret = CRYPT_AsnEncodeNumericString(value, dwFlags, pEncodePara,
1620 pbEncoded, pcbEncoded);
1621 break;
1622 case CERT_RDN_PRINTABLE_STRING:
1623 ret = CRYPT_AsnEncodePrintableString(value, dwFlags, pEncodePara,
1624 pbEncoded, pcbEncoded);
1625 break;
1626 case CERT_RDN_TELETEX_STRING:
1627 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_T61STRING,
1628 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1629 break;
1630 case CERT_RDN_VIDEOTEX_STRING:
1631 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value,
1632 ASN_VIDEOTEXSTRING, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1633 break;
1634 case CERT_RDN_IA5_STRING:
1635 ret = CRYPT_AsnEncodeIA5String(value, dwFlags, pEncodePara,
1636 pbEncoded, pcbEncoded);
1637 break;
1638 case CERT_RDN_GRAPHIC_STRING:
1639 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_GRAPHICSTRING,
1640 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1641 break;
1642 case CERT_RDN_VISIBLE_STRING:
1643 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_VISIBLESTRING,
1644 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1645 break;
1646 case CERT_RDN_GENERAL_STRING:
1647 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_GENERALSTRING,
1648 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1649 break;
1650 case CERT_RDN_UNIVERSAL_STRING:
1651 ret = CRYPT_AsnEncodeUniversalString(value, dwFlags, pEncodePara,
1652 pbEncoded, pcbEncoded);
1653 break;
1654 case CERT_RDN_BMP_STRING:
1655 ret = CRYPT_AsnEncodeBMPString(value, dwFlags, pEncodePara,
1656 pbEncoded, pcbEncoded);
1657 break;
1658 case CERT_RDN_UTF8_STRING:
1659 ret = CRYPT_AsnEncodeUTF8String(value, dwFlags, pEncodePara,
1660 pbEncoded, pcbEncoded);
1661 break;
1662 default:
1663 SetLastError(CRYPT_E_ASN1_CHOICE);
1666 __EXCEPT_PAGE_FAULT
1668 SetLastError(STATUS_ACCESS_VIOLATION);
1670 __ENDTRY
1671 return ret;
1674 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
1675 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1676 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1678 BOOL ret;
1680 __TRY
1682 const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1683 DWORD bytesNeeded = 0, lenBytes, size, i;
1685 TRACE("encoding name with %d RDNs\n", info->cRDN);
1686 ret = TRUE;
1687 for (i = 0; ret && i < info->cRDN; i++)
1689 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i],
1690 CRYPT_AsnEncodeNameValue, NULL, &size);
1691 if (ret)
1692 bytesNeeded += size;
1694 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1695 bytesNeeded += 1 + lenBytes;
1696 if (ret)
1698 if (!pbEncoded)
1699 *pcbEncoded = bytesNeeded;
1700 else
1702 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1703 pbEncoded, pcbEncoded, bytesNeeded)))
1705 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1706 pbEncoded = *(BYTE **)pbEncoded;
1707 *pbEncoded++ = ASN_SEQUENCEOF;
1708 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1709 &lenBytes);
1710 pbEncoded += lenBytes;
1711 for (i = 0; ret && i < info->cRDN; i++)
1713 size = bytesNeeded;
1714 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1715 &info->rgRDN[i], CRYPT_AsnEncodeNameValue, pbEncoded,
1716 &size);
1717 if (ret)
1719 pbEncoded += size;
1720 bytesNeeded -= size;
1727 __EXCEPT_PAGE_FAULT
1729 SetLastError(STATUS_ACCESS_VIOLATION);
1730 ret = FALSE;
1732 __ENDTRY
1733 return ret;
1736 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1737 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1738 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1740 BOOL val = *(const BOOL *)pvStructInfo, ret;
1742 TRACE("%d\n", val);
1744 if (!pbEncoded)
1746 *pcbEncoded = 3;
1747 ret = TRUE;
1749 else if (*pcbEncoded < 3)
1751 *pcbEncoded = 3;
1752 SetLastError(ERROR_MORE_DATA);
1753 ret = FALSE;
1755 else
1757 *pcbEncoded = 3;
1758 *pbEncoded++ = ASN_BOOL;
1759 *pbEncoded++ = 1;
1760 *pbEncoded++ = val ? 0xff : 0;
1761 ret = TRUE;
1763 TRACE("returning %d (%08x)\n", ret, GetLastError());
1764 return ret;
1767 static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry,
1768 BYTE *pbEncoded, DWORD *pcbEncoded)
1770 BOOL ret;
1771 DWORD dataLen;
1773 ret = TRUE;
1774 switch (entry->dwAltNameChoice)
1776 case CERT_ALT_NAME_RFC822_NAME:
1777 case CERT_ALT_NAME_DNS_NAME:
1778 case CERT_ALT_NAME_URL:
1779 if (entry->u.pwszURL)
1781 DWORD i;
1783 /* Not + 1: don't encode the NULL-terminator */
1784 dataLen = lstrlenW(entry->u.pwszURL);
1785 for (i = 0; ret && i < dataLen; i++)
1787 if (entry->u.pwszURL[i] > 0x7f)
1789 SetLastError(CRYPT_E_INVALID_IA5_STRING);
1790 ret = FALSE;
1791 *pcbEncoded = i;
1795 else
1796 dataLen = 0;
1797 break;
1798 case CERT_ALT_NAME_IP_ADDRESS:
1799 dataLen = entry->u.IPAddress.cbData;
1800 break;
1801 case CERT_ALT_NAME_REGISTERED_ID:
1802 /* FIXME: encode OID */
1803 case CERT_ALT_NAME_OTHER_NAME:
1804 case CERT_ALT_NAME_DIRECTORY_NAME:
1805 FIXME("name type %d unimplemented\n", entry->dwAltNameChoice);
1806 return FALSE;
1807 default:
1808 SetLastError(E_INVALIDARG);
1809 return FALSE;
1811 if (ret)
1813 DWORD bytesNeeded, lenBytes;
1815 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1816 bytesNeeded = 1 + dataLen + lenBytes;
1817 if (!pbEncoded)
1818 *pcbEncoded = bytesNeeded;
1819 else if (*pcbEncoded < bytesNeeded)
1821 SetLastError(ERROR_MORE_DATA);
1822 *pcbEncoded = bytesNeeded;
1823 ret = FALSE;
1825 else
1827 *pbEncoded++ = ASN_CONTEXT | (entry->dwAltNameChoice - 1);
1828 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1829 pbEncoded += lenBytes;
1830 switch (entry->dwAltNameChoice)
1832 case CERT_ALT_NAME_RFC822_NAME:
1833 case CERT_ALT_NAME_DNS_NAME:
1834 case CERT_ALT_NAME_URL:
1836 DWORD i;
1838 for (i = 0; i < dataLen; i++)
1839 *pbEncoded++ = (BYTE)entry->u.pwszURL[i];
1840 break;
1842 case CERT_ALT_NAME_IP_ADDRESS:
1843 memcpy(pbEncoded, entry->u.IPAddress.pbData, dataLen);
1844 break;
1846 if (ret)
1847 *pcbEncoded = bytesNeeded;
1850 TRACE("returning %d (%08x)\n", ret, GetLastError());
1851 return ret;
1854 static BOOL WINAPI CRYPT_AsnEncodeAuthorityKeyId(DWORD dwCertEncodingType,
1855 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1856 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1858 BOOL ret;
1860 __TRY
1862 const CERT_AUTHORITY_KEY_ID_INFO *info =
1863 (const CERT_AUTHORITY_KEY_ID_INFO *)pvStructInfo;
1864 struct AsnEncodeSequenceItem items[3] = { { 0 } };
1865 struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
1866 struct AsnConstructedItem constructed = { 0 };
1867 DWORD cItem = 0, cSwapped = 0;
1869 if (info->KeyId.cbData)
1871 swapped[cSwapped].tag = ASN_CONTEXT | 0;
1872 swapped[cSwapped].pvStructInfo = &info->KeyId;
1873 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
1874 items[cItem].pvStructInfo = &swapped[cSwapped];
1875 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
1876 cSwapped++;
1877 cItem++;
1879 if (info->CertIssuer.cbData)
1881 constructed.tag = 1;
1882 constructed.pvStructInfo = &info->CertIssuer;
1883 constructed.encodeFunc = CRYPT_CopyEncodedBlob;
1884 items[cItem].pvStructInfo = &constructed;
1885 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
1886 cItem++;
1888 if (info->CertSerialNumber.cbData)
1890 swapped[cSwapped].tag = ASN_CONTEXT | 2;
1891 swapped[cSwapped].pvStructInfo = &info->CertSerialNumber;
1892 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
1893 items[cItem].pvStructInfo = &swapped[cSwapped];
1894 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
1895 cSwapped++;
1896 cItem++;
1898 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, dwFlags,
1899 pEncodePara, pbEncoded, pcbEncoded);
1901 __EXCEPT_PAGE_FAULT
1903 SetLastError(STATUS_ACCESS_VIOLATION);
1904 ret = FALSE;
1906 __ENDTRY
1907 return ret;
1910 static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
1911 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1912 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1914 BOOL ret;
1916 __TRY
1918 const CERT_ALT_NAME_INFO *info =
1919 (const CERT_ALT_NAME_INFO *)pvStructInfo;
1920 DWORD bytesNeeded, dataLen, lenBytes, i;
1922 ret = TRUE;
1923 /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
1924 * can't encode an erroneous entry index if it's bigger than this.
1926 for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
1928 DWORD len;
1930 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i], NULL,
1931 &len);
1932 if (ret)
1933 dataLen += len;
1934 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
1936 /* CRYPT_AsnEncodeAltNameEntry encoded the index of
1937 * the bad character, now set the index of the bad
1938 * entry
1940 *pcbEncoded = (BYTE)i <<
1941 CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT | len;
1944 if (ret)
1946 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1947 bytesNeeded = 1 + lenBytes + dataLen;
1948 if (!pbEncoded)
1950 *pcbEncoded = bytesNeeded;
1951 ret = TRUE;
1953 else
1955 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1956 pbEncoded, pcbEncoded, bytesNeeded)))
1958 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1959 pbEncoded = *(BYTE **)pbEncoded;
1960 *pbEncoded++ = ASN_SEQUENCEOF;
1961 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1962 pbEncoded += lenBytes;
1963 for (i = 0; ret && i < info->cAltEntry; i++)
1965 DWORD len = dataLen;
1967 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i],
1968 pbEncoded, &len);
1969 if (ret)
1971 pbEncoded += len;
1972 dataLen -= len;
1979 __EXCEPT_PAGE_FAULT
1981 SetLastError(STATUS_ACCESS_VIOLATION);
1982 ret = FALSE;
1984 __ENDTRY
1985 return ret;
1988 static BOOL WINAPI CRYPT_AsnEncodeAuthorityKeyId2(DWORD dwCertEncodingType,
1989 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1990 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1992 BOOL ret;
1994 __TRY
1996 const CERT_AUTHORITY_KEY_ID2_INFO *info =
1997 (const CERT_AUTHORITY_KEY_ID2_INFO *)pvStructInfo;
1998 struct AsnEncodeSequenceItem items[3] = { { 0 } };
1999 struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2000 DWORD cItem = 0, cSwapped = 0;
2002 if (info->KeyId.cbData)
2004 swapped[cSwapped].tag = ASN_CONTEXT | 0;
2005 swapped[cSwapped].pvStructInfo = &info->KeyId;
2006 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
2007 items[cItem].pvStructInfo = &swapped[cSwapped];
2008 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2009 cSwapped++;
2010 cItem++;
2012 if (info->AuthorityCertIssuer.cAltEntry)
2014 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 1;
2015 swapped[cSwapped].pvStructInfo = &info->AuthorityCertIssuer;
2016 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2017 items[cItem].pvStructInfo = &swapped[cSwapped];
2018 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2019 cSwapped++;
2020 cItem++;
2022 if (info->AuthorityCertSerialNumber.cbData)
2024 swapped[cSwapped].tag = ASN_CONTEXT | 2;
2025 swapped[cSwapped].pvStructInfo = &info->AuthorityCertSerialNumber;
2026 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
2027 items[cItem].pvStructInfo = &swapped[cSwapped];
2028 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2029 cSwapped++;
2030 cItem++;
2032 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, dwFlags,
2033 pEncodePara, pbEncoded, pcbEncoded);
2035 __EXCEPT_PAGE_FAULT
2037 SetLastError(STATUS_ACCESS_VIOLATION);
2038 ret = FALSE;
2040 __ENDTRY
2041 return ret;
2044 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints(DWORD dwCertEncodingType,
2045 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2046 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2048 BOOL ret;
2050 __TRY
2052 const CERT_BASIC_CONSTRAINTS_INFO *info =
2053 (const CERT_BASIC_CONSTRAINTS_INFO *)pvStructInfo;
2054 struct AsnEncodeSequenceItem items[3] = {
2055 { &info->SubjectType, CRYPT_AsnEncodeBits, 0 },
2056 { 0 }
2058 DWORD cItem = 1;
2060 if (info->fPathLenConstraint)
2062 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
2063 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
2064 cItem++;
2066 if (info->cSubtreesConstraint)
2068 items[cItem].pvStructInfo = &info->cSubtreesConstraint;
2069 items[cItem].encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
2070 cItem++;
2072 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
2073 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2075 __EXCEPT_PAGE_FAULT
2077 SetLastError(STATUS_ACCESS_VIOLATION);
2078 ret = FALSE;
2080 __ENDTRY
2081 return ret;
2084 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
2085 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2086 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2088 BOOL ret;
2090 __TRY
2092 const CERT_BASIC_CONSTRAINTS2_INFO *info =
2093 (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
2094 struct AsnEncodeSequenceItem items[2] = { { 0 } };
2095 DWORD cItem = 0;
2097 if (info->fCA)
2099 items[cItem].pvStructInfo = &info->fCA;
2100 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
2101 cItem++;
2103 if (info->fPathLenConstraint)
2105 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
2106 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
2107 cItem++;
2109 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
2110 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2112 __EXCEPT_PAGE_FAULT
2114 SetLastError(STATUS_ACCESS_VIOLATION);
2115 ret = FALSE;
2117 __ENDTRY
2118 return ret;
2121 static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
2122 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2123 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2125 BOOL ret;
2127 __TRY
2129 const BLOBHEADER *hdr =
2130 (const BLOBHEADER *)pvStructInfo;
2132 if (hdr->bType != PUBLICKEYBLOB)
2134 SetLastError(E_INVALIDARG);
2135 ret = FALSE;
2137 else
2139 const RSAPUBKEY *rsaPubKey = (const RSAPUBKEY *)
2140 ((const BYTE *)pvStructInfo + sizeof(BLOBHEADER));
2141 CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8,
2142 (BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) };
2143 struct AsnEncodeSequenceItem items[] = {
2144 { &blob, CRYPT_AsnEncodeUnsignedInteger, 0 },
2145 { &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 },
2148 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
2149 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
2150 pcbEncoded);
2153 __EXCEPT_PAGE_FAULT
2155 SetLastError(STATUS_ACCESS_VIOLATION);
2156 ret = FALSE;
2158 __ENDTRY
2159 return ret;
2162 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
2163 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2164 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2166 BOOL ret;
2168 __TRY
2170 const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
2171 DWORD bytesNeeded, lenBytes;
2173 TRACE("(%d, %p), %08x, %p, %p, %d\n", blob->cbData, blob->pbData,
2174 dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
2176 CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
2177 bytesNeeded = 1 + lenBytes + blob->cbData;
2178 if (!pbEncoded)
2180 *pcbEncoded = bytesNeeded;
2181 ret = TRUE;
2183 else
2185 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2186 pcbEncoded, bytesNeeded)))
2188 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2189 pbEncoded = *(BYTE **)pbEncoded;
2190 *pbEncoded++ = ASN_OCTETSTRING;
2191 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
2192 pbEncoded += lenBytes;
2193 if (blob->cbData)
2194 memcpy(pbEncoded, blob->pbData, blob->cbData);
2198 __EXCEPT_PAGE_FAULT
2200 SetLastError(STATUS_ACCESS_VIOLATION);
2201 ret = FALSE;
2203 __ENDTRY
2204 TRACE("returning %d (%08x)\n", ret, GetLastError());
2205 return ret;
2208 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
2209 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2210 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2212 BOOL ret;
2214 __TRY
2216 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
2217 DWORD bytesNeeded, lenBytes, dataBytes;
2218 BYTE unusedBits;
2220 /* yep, MS allows cUnusedBits to be >= 8 */
2221 if (!blob->cUnusedBits)
2223 dataBytes = blob->cbData;
2224 unusedBits = 0;
2226 else if (blob->cbData * 8 > blob->cUnusedBits)
2228 dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
2229 unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
2230 blob->cUnusedBits;
2232 else
2234 dataBytes = 0;
2235 unusedBits = 0;
2237 CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
2238 bytesNeeded = 1 + lenBytes + dataBytes + 1;
2239 if (!pbEncoded)
2241 *pcbEncoded = bytesNeeded;
2242 ret = TRUE;
2244 else
2246 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2247 pcbEncoded, bytesNeeded)))
2249 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2250 pbEncoded = *(BYTE **)pbEncoded;
2251 *pbEncoded++ = ASN_BITSTRING;
2252 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
2253 pbEncoded += lenBytes;
2254 *pbEncoded++ = unusedBits;
2255 if (dataBytes)
2257 BYTE mask = 0xff << unusedBits;
2259 if (dataBytes > 1)
2261 memcpy(pbEncoded, blob->pbData, dataBytes - 1);
2262 pbEncoded += dataBytes - 1;
2264 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
2269 __EXCEPT_PAGE_FAULT
2271 SetLastError(STATUS_ACCESS_VIOLATION);
2272 ret = FALSE;
2274 __ENDTRY
2275 return ret;
2278 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
2279 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2280 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2282 BOOL ret;
2284 __TRY
2286 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
2287 CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
2289 ret = TRUE;
2290 if (newBlob.cbData)
2292 newBlob.pbData = CryptMemAlloc(newBlob.cbData);
2293 if (newBlob.pbData)
2295 DWORD i;
2297 for (i = 0; i < newBlob.cbData; i++)
2298 newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
2300 else
2301 ret = FALSE;
2303 if (ret)
2304 ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
2305 &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2306 CryptMemFree(newBlob.pbData);
2308 __EXCEPT_PAGE_FAULT
2310 SetLastError(STATUS_ACCESS_VIOLATION);
2311 ret = FALSE;
2313 __ENDTRY
2314 return ret;
2317 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
2318 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2319 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2321 CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
2323 return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
2324 &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2327 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
2328 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2329 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2331 BOOL ret;
2333 __TRY
2335 DWORD significantBytes, lenBytes;
2336 BYTE padByte = 0, bytesNeeded;
2337 BOOL pad = FALSE;
2338 const CRYPT_INTEGER_BLOB *blob =
2339 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
2341 significantBytes = blob->cbData;
2342 if (significantBytes)
2344 if (blob->pbData[significantBytes - 1] & 0x80)
2346 /* negative, lop off leading (little-endian) 0xffs */
2347 for (; significantBytes > 0 &&
2348 blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
2350 if (blob->pbData[significantBytes - 1] < 0x80)
2352 padByte = 0xff;
2353 pad = TRUE;
2356 else
2358 /* positive, lop off leading (little-endian) zeroes */
2359 for (; significantBytes > 0 &&
2360 !blob->pbData[significantBytes - 1]; significantBytes--)
2362 if (significantBytes == 0)
2363 significantBytes = 1;
2364 if (blob->pbData[significantBytes - 1] > 0x7f)
2366 padByte = 0;
2367 pad = TRUE;
2371 if (pad)
2372 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2373 else
2374 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2375 bytesNeeded = 1 + lenBytes + significantBytes;
2376 if (pad)
2377 bytesNeeded++;
2378 if (!pbEncoded)
2380 *pcbEncoded = bytesNeeded;
2381 ret = TRUE;
2383 else
2385 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2386 pcbEncoded, bytesNeeded)))
2388 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2389 pbEncoded = *(BYTE **)pbEncoded;
2390 *pbEncoded++ = ASN_INTEGER;
2391 if (pad)
2393 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2394 pbEncoded += lenBytes;
2395 *pbEncoded++ = padByte;
2397 else
2399 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2400 pbEncoded += lenBytes;
2402 for (; significantBytes > 0; significantBytes--)
2403 *(pbEncoded++) = blob->pbData[significantBytes - 1];
2407 __EXCEPT_PAGE_FAULT
2409 SetLastError(STATUS_ACCESS_VIOLATION);
2410 ret = FALSE;
2412 __ENDTRY
2413 return ret;
2416 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
2417 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2418 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2420 BOOL ret;
2422 __TRY
2424 DWORD significantBytes, lenBytes;
2425 BYTE bytesNeeded;
2426 BOOL pad = FALSE;
2427 const CRYPT_INTEGER_BLOB *blob =
2428 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
2430 significantBytes = blob->cbData;
2431 if (significantBytes)
2433 /* positive, lop off leading (little-endian) zeroes */
2434 for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
2435 significantBytes--)
2437 if (significantBytes == 0)
2438 significantBytes = 1;
2439 if (blob->pbData[significantBytes - 1] > 0x7f)
2440 pad = TRUE;
2442 if (pad)
2443 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2444 else
2445 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2446 bytesNeeded = 1 + lenBytes + significantBytes;
2447 if (pad)
2448 bytesNeeded++;
2449 if (!pbEncoded)
2451 *pcbEncoded = bytesNeeded;
2452 ret = TRUE;
2454 else
2456 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2457 pcbEncoded, bytesNeeded)))
2459 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2460 pbEncoded = *(BYTE **)pbEncoded;
2461 *pbEncoded++ = ASN_INTEGER;
2462 if (pad)
2464 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2465 pbEncoded += lenBytes;
2466 *pbEncoded++ = 0;
2468 else
2470 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2471 pbEncoded += lenBytes;
2473 for (; significantBytes > 0; significantBytes--)
2474 *(pbEncoded++) = blob->pbData[significantBytes - 1];
2478 __EXCEPT_PAGE_FAULT
2480 SetLastError(STATUS_ACCESS_VIOLATION);
2481 ret = FALSE;
2483 __ENDTRY
2484 return ret;
2487 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
2488 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2489 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2491 CRYPT_INTEGER_BLOB blob;
2492 BOOL ret;
2494 /* Encode as an unsigned integer, then change the tag to enumerated */
2495 blob.cbData = sizeof(DWORD);
2496 blob.pbData = (BYTE *)pvStructInfo;
2497 ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
2498 X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2499 if (ret && pbEncoded)
2501 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2502 pbEncoded = *(BYTE **)pbEncoded;
2503 pbEncoded[0] = ASN_ENUMERATED;
2505 return ret;
2508 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
2509 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2510 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2512 BOOL ret;
2514 __TRY
2516 SYSTEMTIME sysTime;
2517 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
2518 * temporary buffer because the output buffer is not NULL-terminated.
2520 char buf[16];
2521 static const DWORD bytesNeeded = sizeof(buf) - 1;
2523 if (!pbEncoded)
2525 *pcbEncoded = bytesNeeded;
2526 ret = TRUE;
2528 else
2530 /* Sanity check the year, this is a two-digit year format */
2531 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2532 &sysTime);
2533 if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
2535 SetLastError(CRYPT_E_BAD_ENCODE);
2536 ret = FALSE;
2538 if (ret)
2540 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2541 pbEncoded, pcbEncoded, bytesNeeded)))
2543 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2544 pbEncoded = *(BYTE **)pbEncoded;
2545 buf[0] = ASN_UTCTIME;
2546 buf[1] = bytesNeeded - 2;
2547 snprintf(buf + 2, sizeof(buf) - 2,
2548 "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
2549 sysTime.wYear - 2000 : sysTime.wYear - 1900,
2550 sysTime.wMonth, sysTime.wDay, sysTime.wHour,
2551 sysTime.wMinute, sysTime.wSecond);
2552 memcpy(pbEncoded, buf, bytesNeeded);
2557 __EXCEPT_PAGE_FAULT
2559 SetLastError(STATUS_ACCESS_VIOLATION);
2560 ret = FALSE;
2562 __ENDTRY
2563 return ret;
2566 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
2567 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2568 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2570 BOOL ret;
2572 __TRY
2574 SYSTEMTIME sysTime;
2575 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
2576 * temporary buffer because the output buffer is not NULL-terminated.
2578 char buf[18];
2579 static const DWORD bytesNeeded = sizeof(buf) - 1;
2581 if (!pbEncoded)
2583 *pcbEncoded = bytesNeeded;
2584 ret = TRUE;
2586 else
2588 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2589 &sysTime);
2590 if (ret)
2591 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2592 pcbEncoded, bytesNeeded);
2593 if (ret)
2595 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2596 pbEncoded = *(BYTE **)pbEncoded;
2597 buf[0] = ASN_GENERALTIME;
2598 buf[1] = bytesNeeded - 2;
2599 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
2600 sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour,
2601 sysTime.wMinute, sysTime.wSecond);
2602 memcpy(pbEncoded, buf, bytesNeeded);
2606 __EXCEPT_PAGE_FAULT
2608 SetLastError(STATUS_ACCESS_VIOLATION);
2609 ret = FALSE;
2611 __ENDTRY
2612 return ret;
2615 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
2616 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2617 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2619 BOOL ret;
2621 __TRY
2623 SYSTEMTIME sysTime;
2625 /* Check the year, if it's in the UTCTime range call that encode func */
2626 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
2627 return FALSE;
2628 if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
2629 ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
2630 pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2631 else
2632 ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
2633 lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
2634 pcbEncoded);
2636 __EXCEPT_PAGE_FAULT
2638 SetLastError(STATUS_ACCESS_VIOLATION);
2639 ret = FALSE;
2641 __ENDTRY
2642 return ret;
2645 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
2646 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2647 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2649 BOOL ret;
2651 __TRY
2653 DWORD bytesNeeded, dataLen, lenBytes, i;
2654 const CRYPT_SEQUENCE_OF_ANY *seq =
2655 (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
2657 for (i = 0, dataLen = 0; i < seq->cValue; i++)
2658 dataLen += seq->rgValue[i].cbData;
2659 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2660 bytesNeeded = 1 + lenBytes + dataLen;
2661 if (!pbEncoded)
2663 *pcbEncoded = bytesNeeded;
2664 ret = TRUE;
2666 else
2668 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2669 pcbEncoded, bytesNeeded)))
2671 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2672 pbEncoded = *(BYTE **)pbEncoded;
2673 *pbEncoded++ = ASN_SEQUENCEOF;
2674 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2675 pbEncoded += lenBytes;
2676 for (i = 0; i < seq->cValue; i++)
2678 memcpy(pbEncoded, seq->rgValue[i].pbData,
2679 seq->rgValue[i].cbData);
2680 pbEncoded += seq->rgValue[i].cbData;
2685 __EXCEPT_PAGE_FAULT
2687 SetLastError(STATUS_ACCESS_VIOLATION);
2688 ret = FALSE;
2690 __ENDTRY
2691 return ret;
2694 static BOOL CRYPT_AsnEncodeDistPoint(const CRL_DIST_POINT *distPoint,
2695 BYTE *pbEncoded, DWORD *pcbEncoded)
2697 BOOL ret = TRUE;
2698 struct AsnEncodeSequenceItem items[3] = { { 0 } };
2699 struct AsnConstructedItem constructed = { 0 };
2700 struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2701 DWORD cItem = 0, cSwapped = 0;
2703 switch (distPoint->DistPointName.dwDistPointNameChoice)
2705 case CRL_DIST_POINT_NO_NAME:
2706 /* do nothing */
2707 break;
2708 case CRL_DIST_POINT_FULL_NAME:
2709 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
2710 swapped[cSwapped].pvStructInfo = &distPoint->DistPointName.u.FullName;
2711 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2712 constructed.tag = 0;
2713 constructed.pvStructInfo = &swapped[cSwapped];
2714 constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
2715 items[cItem].pvStructInfo = &constructed;
2716 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2717 cSwapped++;
2718 cItem++;
2719 break;
2720 case CRL_DIST_POINT_ISSUER_RDN_NAME:
2721 FIXME("unimplemented for CRL_DIST_POINT_ISSUER_RDN_NAME\n");
2722 ret = FALSE;
2723 break;
2724 default:
2725 ret = FALSE;
2727 if (ret && distPoint->ReasonFlags.cbData)
2729 swapped[cSwapped].tag = ASN_CONTEXT | 1;
2730 swapped[cSwapped].pvStructInfo = &distPoint->ReasonFlags;
2731 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
2732 items[cItem].pvStructInfo = &swapped[cSwapped];
2733 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2734 cSwapped++;
2735 cItem++;
2737 if (ret && distPoint->CRLIssuer.cAltEntry)
2739 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 2;
2740 swapped[cSwapped].pvStructInfo = &distPoint->CRLIssuer;
2741 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2742 items[cItem].pvStructInfo = &swapped[cSwapped];
2743 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2744 cSwapped++;
2745 cItem++;
2747 if (ret)
2748 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
2749 pbEncoded, pcbEncoded);
2750 return ret;
2753 static BOOL WINAPI CRYPT_AsnEncodeCRLDistPoints(DWORD dwCertEncodingType,
2754 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2755 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2757 BOOL ret;
2759 __TRY
2761 const CRL_DIST_POINTS_INFO *info =
2762 (const CRL_DIST_POINTS_INFO *)pvStructInfo;
2764 if (!info->cDistPoint)
2766 SetLastError(E_INVALIDARG);
2767 ret = FALSE;
2769 else
2771 DWORD bytesNeeded, dataLen, lenBytes, i;
2773 ret = TRUE;
2774 for (i = 0, dataLen = 0; ret && i < info->cDistPoint; i++)
2776 DWORD len;
2778 ret = CRYPT_AsnEncodeDistPoint(&info->rgDistPoint[i], NULL,
2779 &len);
2780 if (ret)
2781 dataLen += len;
2782 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
2784 /* Have to propagate index of failing character */
2785 *pcbEncoded = len;
2788 if (ret)
2790 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2791 bytesNeeded = 1 + lenBytes + dataLen;
2792 if (!pbEncoded)
2794 *pcbEncoded = bytesNeeded;
2795 ret = TRUE;
2797 else
2799 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2800 pbEncoded, pcbEncoded, bytesNeeded)))
2802 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2803 pbEncoded = *(BYTE **)pbEncoded;
2804 *pbEncoded++ = ASN_SEQUENCEOF;
2805 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2806 pbEncoded += lenBytes;
2807 for (i = 0; ret && i < info->cDistPoint; i++)
2809 DWORD len = dataLen;
2811 ret = CRYPT_AsnEncodeDistPoint(
2812 &info->rgDistPoint[i], pbEncoded, &len);
2813 if (ret)
2815 pbEncoded += len;
2816 dataLen -= len;
2824 __EXCEPT_PAGE_FAULT
2826 SetLastError(STATUS_ACCESS_VIOLATION);
2827 ret = FALSE;
2829 __ENDTRY
2830 return ret;
2833 static BOOL WINAPI CRYPT_AsnEncodeEnhancedKeyUsage(DWORD dwCertEncodingType,
2834 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2835 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2837 BOOL ret;
2839 __TRY
2841 const CERT_ENHKEY_USAGE *usage =
2842 (const CERT_ENHKEY_USAGE *)pvStructInfo;
2843 DWORD bytesNeeded = 0, lenBytes, size, i;
2845 ret = TRUE;
2846 for (i = 0; ret && i < usage->cUsageIdentifier; i++)
2848 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
2849 usage->rgpszUsageIdentifier[i],
2850 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &size);
2851 if (ret)
2852 bytesNeeded += size;
2854 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
2855 bytesNeeded += 1 + lenBytes;
2856 if (ret)
2858 if (!pbEncoded)
2859 *pcbEncoded = bytesNeeded;
2860 else
2862 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2863 pbEncoded, pcbEncoded, bytesNeeded)))
2865 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2866 pbEncoded = *(BYTE **)pbEncoded;
2867 *pbEncoded++ = ASN_SEQUENCEOF;
2868 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
2869 &lenBytes);
2870 pbEncoded += lenBytes;
2871 for (i = 0; ret && i < usage->cUsageIdentifier; i++)
2873 size = bytesNeeded;
2874 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
2875 usage->rgpszUsageIdentifier[i],
2876 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pbEncoded,
2877 &size);
2878 if (ret)
2880 pbEncoded += size;
2881 bytesNeeded -= size;
2888 __EXCEPT_PAGE_FAULT
2890 SetLastError(STATUS_ACCESS_VIOLATION);
2891 ret = FALSE;
2893 __ENDTRY
2894 return ret;
2897 static BOOL WINAPI CRYPT_AsnEncodeIssuingDistPoint(DWORD dwCertEncodingType,
2898 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2899 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2901 BOOL ret;
2903 __TRY
2905 const CRL_ISSUING_DIST_POINT *point =
2906 (const CRL_ISSUING_DIST_POINT *)pvStructInfo;
2907 struct AsnEncodeSequenceItem items[6] = { { 0 } };
2908 struct AsnConstructedItem constructed = { 0 };
2909 struct AsnEncodeTagSwappedItem swapped[5] = { { 0 } };
2910 DWORD cItem = 0, cSwapped = 0;
2912 ret = TRUE;
2913 switch (point->DistPointName.dwDistPointNameChoice)
2915 case CRL_DIST_POINT_NO_NAME:
2916 /* do nothing */
2917 break;
2918 case CRL_DIST_POINT_FULL_NAME:
2919 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
2920 swapped[cSwapped].pvStructInfo = &point->DistPointName.u.FullName;
2921 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2922 constructed.tag = 0;
2923 constructed.pvStructInfo = &swapped[cSwapped];
2924 constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
2925 items[cItem].pvStructInfo = &constructed;
2926 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2927 cSwapped++;
2928 cItem++;
2929 break;
2930 default:
2931 SetLastError(E_INVALIDARG);
2932 ret = FALSE;
2934 if (ret && point->fOnlyContainsUserCerts)
2936 swapped[cSwapped].tag = ASN_CONTEXT | 1;
2937 swapped[cSwapped].pvStructInfo = &point->fOnlyContainsUserCerts;
2938 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
2939 items[cItem].pvStructInfo = &swapped[cSwapped];
2940 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2941 cSwapped++;
2942 cItem++;
2944 if (ret && point->fOnlyContainsCACerts)
2946 swapped[cSwapped].tag = ASN_CONTEXT | 2;
2947 swapped[cSwapped].pvStructInfo = &point->fOnlyContainsCACerts;
2948 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
2949 items[cItem].pvStructInfo = &swapped[cSwapped];
2950 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2951 cSwapped++;
2952 cItem++;
2954 if (ret && point->OnlySomeReasonFlags.cbData)
2956 swapped[cSwapped].tag = ASN_CONTEXT | 3;
2957 swapped[cSwapped].pvStructInfo = &point->OnlySomeReasonFlags;
2958 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
2959 items[cItem].pvStructInfo = &swapped[cSwapped];
2960 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2961 cSwapped++;
2962 cItem++;
2964 if (ret && point->fIndirectCRL)
2966 swapped[cSwapped].tag = ASN_CONTEXT | 4;
2967 swapped[cSwapped].pvStructInfo = &point->fIndirectCRL;
2968 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
2969 items[cItem].pvStructInfo = &swapped[cSwapped];
2970 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2971 cSwapped++;
2972 cItem++;
2974 if (ret)
2975 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
2976 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2978 __EXCEPT_PAGE_FAULT
2980 SetLastError(STATUS_ACCESS_VIOLATION);
2981 ret = FALSE;
2983 __ENDTRY
2984 return ret;
2987 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2988 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
2989 void *pvEncoded, DWORD *pcbEncoded)
2991 static HCRYPTOIDFUNCSET set = NULL;
2992 BOOL ret = FALSE;
2993 CryptEncodeObjectExFunc encodeFunc = NULL;
2994 HCRYPTOIDFUNCADDR hFunc = NULL;
2996 TRACE("(0x%08x, %s, %p, 0x%08x, %p, %p, %p)\n", dwCertEncodingType,
2997 debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
2998 pvEncoded, pcbEncoded);
3000 if (!pvEncoded && !pcbEncoded)
3002 SetLastError(ERROR_INVALID_PARAMETER);
3003 return FALSE;
3005 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
3006 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
3008 SetLastError(ERROR_FILE_NOT_FOUND);
3009 return FALSE;
3012 SetLastError(NOERROR);
3013 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
3014 *(BYTE **)pvEncoded = NULL;
3015 if (!HIWORD(lpszStructType))
3017 switch (LOWORD(lpszStructType))
3019 case (WORD)X509_CERT:
3020 encodeFunc = CRYPT_AsnEncodeCert;
3021 break;
3022 case (WORD)X509_CERT_TO_BE_SIGNED:
3023 encodeFunc = CRYPT_AsnEncodeCertInfo;
3024 break;
3025 case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
3026 encodeFunc = CRYPT_AsnEncodeCRLInfo;
3027 break;
3028 case (WORD)X509_EXTENSIONS:
3029 encodeFunc = CRYPT_AsnEncodeExtensions;
3030 break;
3031 case (WORD)X509_NAME_VALUE:
3032 encodeFunc = CRYPT_AsnEncodeNameValue;
3033 break;
3034 case (WORD)X509_NAME:
3035 encodeFunc = CRYPT_AsnEncodeName;
3036 break;
3037 case (WORD)X509_PUBLIC_KEY_INFO:
3038 encodeFunc = CRYPT_AsnEncodePubKeyInfo;
3039 break;
3040 case (WORD)X509_AUTHORITY_KEY_ID:
3041 encodeFunc = CRYPT_AsnEncodeAuthorityKeyId;
3042 break;
3043 case (WORD)X509_ALTERNATE_NAME:
3044 encodeFunc = CRYPT_AsnEncodeAltName;
3045 break;
3046 case (WORD)X509_BASIC_CONSTRAINTS:
3047 encodeFunc = CRYPT_AsnEncodeBasicConstraints;
3048 break;
3049 case (WORD)X509_BASIC_CONSTRAINTS2:
3050 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
3051 break;
3052 case (WORD)RSA_CSP_PUBLICKEYBLOB:
3053 encodeFunc = CRYPT_AsnEncodeRsaPubKey;
3054 break;
3055 case (WORD)X509_UNICODE_NAME:
3056 encodeFunc = CRYPT_AsnEncodeUnicodeName;
3057 break;
3058 case (WORD)PKCS_CONTENT_INFO:
3059 encodeFunc = CRYPT_AsnEncodePKCSContentInfo;
3060 break;
3061 case (WORD)X509_UNICODE_NAME_VALUE:
3062 encodeFunc = CRYPT_AsnEncodeUnicodeNameValue;
3063 break;
3064 case (WORD)X509_OCTET_STRING:
3065 encodeFunc = CRYPT_AsnEncodeOctets;
3066 break;
3067 case (WORD)X509_BITS:
3068 case (WORD)X509_KEY_USAGE:
3069 encodeFunc = CRYPT_AsnEncodeBits;
3070 break;
3071 case (WORD)X509_INTEGER:
3072 encodeFunc = CRYPT_AsnEncodeInt;
3073 break;
3074 case (WORD)X509_MULTI_BYTE_INTEGER:
3075 encodeFunc = CRYPT_AsnEncodeInteger;
3076 break;
3077 case (WORD)X509_MULTI_BYTE_UINT:
3078 encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
3079 break;
3080 case (WORD)X509_ENUMERATED:
3081 encodeFunc = CRYPT_AsnEncodeEnumerated;
3082 break;
3083 case (WORD)X509_CHOICE_OF_TIME:
3084 encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
3085 break;
3086 case (WORD)X509_AUTHORITY_KEY_ID2:
3087 encodeFunc = CRYPT_AsnEncodeAuthorityKeyId2;
3088 break;
3089 case (WORD)X509_SEQUENCE_OF_ANY:
3090 encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
3091 break;
3092 case (WORD)PKCS_UTC_TIME:
3093 encodeFunc = CRYPT_AsnEncodeUtcTime;
3094 break;
3095 case (WORD)X509_CRL_DIST_POINTS:
3096 encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
3097 break;
3098 case (WORD)X509_ENHANCED_KEY_USAGE:
3099 encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
3100 break;
3101 case (WORD)X509_ISSUING_DIST_POINT:
3102 encodeFunc = CRYPT_AsnEncodeIssuingDistPoint;
3103 break;
3104 default:
3105 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
3108 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
3109 encodeFunc = CRYPT_AsnEncodeExtensions;
3110 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
3111 encodeFunc = CRYPT_AsnEncodeUtcTime;
3112 else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER))
3113 encodeFunc = CRYPT_AsnEncodeAuthorityKeyId;
3114 else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2))
3115 encodeFunc = CRYPT_AsnEncodeAuthorityKeyId2;
3116 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
3117 encodeFunc = CRYPT_AsnEncodeEnumerated;
3118 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
3119 encodeFunc = CRYPT_AsnEncodeBits;
3120 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
3121 encodeFunc = CRYPT_AsnEncodeOctets;
3122 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS))
3123 encodeFunc = CRYPT_AsnEncodeBasicConstraints;
3124 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
3125 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
3126 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
3127 encodeFunc = CRYPT_AsnEncodeAltName;
3128 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
3129 encodeFunc = CRYPT_AsnEncodeAltName;
3130 else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
3131 encodeFunc = CRYPT_AsnEncodeAltName;
3132 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
3133 encodeFunc = CRYPT_AsnEncodeAltName;
3134 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
3135 encodeFunc = CRYPT_AsnEncodeAltName;
3136 else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
3137 encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
3138 else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
3139 encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
3140 else if (!strcmp(lpszStructType, szOID_ISSUING_DIST_POINT))
3141 encodeFunc = CRYPT_AsnEncodeIssuingDistPoint;
3142 else
3143 TRACE("OID %s not found or unimplemented, looking for DLL\n",
3144 debugstr_a(lpszStructType));
3145 if (!encodeFunc)
3147 if (!set)
3148 set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_EX_FUNC, 0);
3149 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
3150 (void **)&encodeFunc, &hFunc);
3152 if (encodeFunc)
3153 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
3154 dwFlags, pEncodePara, pvEncoded, pcbEncoded);
3155 else
3156 SetLastError(ERROR_FILE_NOT_FOUND);
3157 if (hFunc)
3158 CryptFreeOIDFunctionAddress(hFunc, 0);
3159 return ret;
3162 BOOL WINAPI CryptExportPublicKeyInfo(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
3163 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3165 return CryptExportPublicKeyInfoEx(hCryptProv, dwKeySpec, dwCertEncodingType,
3166 NULL, 0, NULL, pInfo, pcbInfo);
3169 static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3170 DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
3171 DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3173 BOOL ret;
3174 HCRYPTKEY key;
3175 static CHAR oid[] = szOID_RSA_RSA;
3177 TRACE("(%08lx, %d, %08x, %s, %08x, %p, %p, %p)\n", hCryptProv, dwKeySpec,
3178 dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
3179 pInfo, pcbInfo);
3181 if (!pszPublicKeyObjId)
3182 pszPublicKeyObjId = oid;
3183 if ((ret = CryptGetUserKey(hCryptProv, dwKeySpec, &key)))
3185 DWORD keySize = 0;
3187 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &keySize);
3188 if (ret)
3190 LPBYTE pubKey = CryptMemAlloc(keySize);
3192 if (pubKey)
3194 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, pubKey,
3195 &keySize);
3196 if (ret)
3198 DWORD encodedLen = 0;
3200 ret = CryptEncodeObject(dwCertEncodingType,
3201 RSA_CSP_PUBLICKEYBLOB, pubKey, NULL, &encodedLen);
3202 if (ret)
3204 DWORD sizeNeeded = sizeof(CERT_PUBLIC_KEY_INFO) +
3205 strlen(pszPublicKeyObjId) + 1 + encodedLen;
3207 if (!pInfo)
3208 *pcbInfo = sizeNeeded;
3209 else if (*pcbInfo < sizeNeeded)
3211 SetLastError(ERROR_MORE_DATA);
3212 *pcbInfo = sizeNeeded;
3213 ret = FALSE;
3215 else
3217 pInfo->Algorithm.pszObjId = (char *)pInfo +
3218 sizeof(CERT_PUBLIC_KEY_INFO);
3219 lstrcpyA(pInfo->Algorithm.pszObjId,
3220 pszPublicKeyObjId);
3221 pInfo->Algorithm.Parameters.cbData = 0;
3222 pInfo->Algorithm.Parameters.pbData = NULL;
3223 pInfo->PublicKey.pbData =
3224 (BYTE *)pInfo->Algorithm.pszObjId
3225 + lstrlenA(pInfo->Algorithm.pszObjId) + 1;
3226 pInfo->PublicKey.cbData = encodedLen;
3227 pInfo->PublicKey.cUnusedBits = 0;
3228 ret = CryptEncodeObject(dwCertEncodingType,
3229 RSA_CSP_PUBLICKEYBLOB, pubKey,
3230 pInfo->PublicKey.pbData, &pInfo->PublicKey.cbData);
3234 CryptMemFree(pubKey);
3236 else
3237 ret = FALSE;
3239 CryptDestroyKey(key);
3241 return ret;
3244 typedef BOOL (WINAPI *ExportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
3245 DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
3246 DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo);
3248 BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
3249 DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId, DWORD dwFlags,
3250 void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3252 static HCRYPTOIDFUNCSET set = NULL;
3253 BOOL ret;
3254 ExportPublicKeyInfoExFunc exportFunc = NULL;
3255 HCRYPTOIDFUNCADDR hFunc = NULL;
3257 TRACE("(%08lx, %d, %08x, %s, %08x, %p, %p, %p)\n", hCryptProv, dwKeySpec,
3258 dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
3259 pInfo, pcbInfo);
3261 if (!hCryptProv)
3263 SetLastError(ERROR_INVALID_PARAMETER);
3264 return FALSE;
3267 if (pszPublicKeyObjId)
3269 if (!set)
3270 set = CryptInitOIDFunctionSet(CRYPT_OID_EXPORT_PUBLIC_KEY_INFO_FUNC,
3272 CryptGetOIDFunctionAddress(set, dwCertEncodingType, pszPublicKeyObjId,
3273 0, (void **)&exportFunc, &hFunc);
3275 if (!exportFunc)
3276 exportFunc = CRYPT_ExportRsaPublicKeyInfoEx;
3277 ret = exportFunc(hCryptProv, dwKeySpec, dwCertEncodingType,
3278 pszPublicKeyObjId, dwFlags, pvAuxInfo, pInfo, pcbInfo);
3279 if (hFunc)
3280 CryptFreeOIDFunctionAddress(hFunc, 0);
3281 return ret;
3284 BOOL WINAPI CryptImportPublicKeyInfo(HCRYPTPROV hCryptProv,
3285 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
3287 return CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType, pInfo,
3288 0, 0, NULL, phKey);
3291 static BOOL WINAPI CRYPT_ImportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3292 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3293 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
3295 BOOL ret;
3296 DWORD pubKeySize = 0;
3298 TRACE("(%08lx, %d, %p, %d, %08x, %p, %p)\n", hCryptProv,
3299 dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
3301 ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
3302 pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, NULL, &pubKeySize);
3303 if (ret)
3305 LPBYTE pubKey = CryptMemAlloc(pubKeySize);
3307 if (pubKey)
3309 ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
3310 pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, pubKey,
3311 &pubKeySize);
3312 if (ret)
3313 ret = CryptImportKey(hCryptProv, pubKey, pubKeySize, 0, 0,
3314 phKey);
3315 CryptMemFree(pubKey);
3317 else
3318 ret = FALSE;
3320 return ret;
3323 typedef BOOL (WINAPI *ImportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
3324 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3325 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey);
3327 BOOL WINAPI CryptImportPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3328 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3329 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
3331 static HCRYPTOIDFUNCSET set = NULL;
3332 BOOL ret;
3333 ImportPublicKeyInfoExFunc importFunc = NULL;
3334 HCRYPTOIDFUNCADDR hFunc = NULL;
3336 TRACE("(%08lx, %d, %p, %d, %08x, %p, %p)\n", hCryptProv,
3337 dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
3339 if (!set)
3340 set = CryptInitOIDFunctionSet(CRYPT_OID_IMPORT_PUBLIC_KEY_INFO_FUNC, 0);
3341 CryptGetOIDFunctionAddress(set, dwCertEncodingType,
3342 pInfo->Algorithm.pszObjId, 0, (void **)&importFunc, &hFunc);
3343 if (!importFunc)
3344 importFunc = CRYPT_ImportRsaPublicKeyInfoEx;
3345 ret = importFunc(hCryptProv, dwCertEncodingType, pInfo, aiKeyAlg, dwFlags,
3346 pvAuxInfo, phKey);
3347 if (hFunc)
3348 CryptFreeOIDFunctionAddress(hFunc, 0);
3349 return ret;