msi: Test transforms removing a row in a table.
[wine/multimedia.git] / dlls / crypt32 / encode.c
blob81ce22442d9b0f8fbe57fa570d7c1da71a74bd2c
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 "excpt.h"
44 #include "wincrypt.h"
45 #include "winreg.h"
46 #include "snmp.h"
47 #include "wine/debug.h"
48 #include "wine/exception.h"
49 #include "wine/unicode.h"
50 #include "crypt32_private.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
54 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
55 BYTE *, DWORD *);
56 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
57 DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
59 /* Prototypes for built-in encoders. They follow the Ex style prototypes.
60 * The dwCertEncodingType and lpszStructType are ignored by the built-in
61 * functions, but the parameters are retained to simplify CryptEncodeObjectEx,
62 * since it must call functions in external DLLs that follow these signatures.
64 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
65 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
66 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
67 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
68 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
69 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
70 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
71 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
72 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
73 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
74 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
75 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
76 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
77 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
78 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
79 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
80 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
81 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
82 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
83 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
84 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
85 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
86 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
87 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
88 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
89 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
90 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
91 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
92 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
93 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
94 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
95 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
96 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
97 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
98 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
99 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
101 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
102 const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
104 static HCRYPTOIDFUNCSET set = NULL;
105 BOOL ret = FALSE;
106 HCRYPTOIDFUNCADDR hFunc;
107 CryptEncodeObjectFunc pCryptEncodeObject;
109 TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
110 debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
111 pcbEncoded);
113 if (!pbEncoded && !pcbEncoded)
115 SetLastError(ERROR_INVALID_PARAMETER);
116 return FALSE;
119 /* Try registered DLL first.. */
120 if (!set)
121 set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_FUNC, 0);
122 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
123 (void **)&pCryptEncodeObject, &hFunc);
124 if (pCryptEncodeObject)
126 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
127 pvStructInfo, pbEncoded, pcbEncoded);
128 CryptFreeOIDFunctionAddress(hFunc, 0);
130 else
132 /* If not, use CryptEncodeObjectEx */
133 ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
134 pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
136 return ret;
139 /* Helper function to check *pcbEncoded, set it to the required size, and
140 * optionally to allocate memory. Assumes pbEncoded is not NULL.
141 * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
142 * pointer to the newly allocated memory.
144 static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
145 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
146 DWORD bytesNeeded)
148 BOOL ret = TRUE;
150 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
152 if (pEncodePara && pEncodePara->pfnAlloc)
153 *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
154 else
155 *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
156 if (!*(BYTE **)pbEncoded)
157 ret = FALSE;
158 else
159 *pcbEncoded = bytesNeeded;
161 else if (bytesNeeded > *pcbEncoded)
163 *pcbEncoded = bytesNeeded;
164 SetLastError(ERROR_MORE_DATA);
165 ret = FALSE;
167 else
168 *pcbEncoded = bytesNeeded;
169 return ret;
172 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
174 DWORD bytesNeeded, significantBytes = 0;
176 if (len <= 0x7f)
177 bytesNeeded = 1;
178 else
180 DWORD temp;
182 for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
183 temp <<= 8, significantBytes--)
185 bytesNeeded = significantBytes + 1;
187 if (!pbEncoded)
189 *pcbEncoded = bytesNeeded;
190 return TRUE;
192 if (*pcbEncoded < bytesNeeded)
194 SetLastError(ERROR_MORE_DATA);
195 return FALSE;
197 if (len <= 0x7f)
198 *pbEncoded = (BYTE)len;
199 else
201 DWORD i;
203 *pbEncoded++ = significantBytes | 0x80;
204 for (i = 0; i < significantBytes; i++)
206 *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
207 len >>= 8;
210 *pcbEncoded = bytesNeeded;
211 return TRUE;
214 struct AsnEncodeSequenceItem
216 const void *pvStructInfo;
217 CryptEncodeObjectExFunc encodeFunc;
218 DWORD size; /* used during encoding, not for your use */
221 static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
222 struct AsnEncodeSequenceItem items[], DWORD cItem, DWORD dwFlags,
223 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
225 BOOL ret;
226 DWORD i, dataLen = 0;
228 TRACE("%p, %d, %08x, %p, %p, %d\n", items, cItem, dwFlags, pEncodePara,
229 pbEncoded, *pcbEncoded);
230 for (i = 0, ret = TRUE; ret && i < cItem; i++)
232 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
233 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
234 NULL, &items[i].size);
235 /* Some functions propagate their errors through the size */
236 if (!ret)
237 *pcbEncoded = items[i].size;
238 dataLen += items[i].size;
240 if (ret)
242 DWORD lenBytes, bytesNeeded;
244 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
245 bytesNeeded = 1 + lenBytes + dataLen;
246 if (!pbEncoded)
247 *pcbEncoded = bytesNeeded;
248 else
250 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
251 pcbEncoded, bytesNeeded)))
253 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
254 pbEncoded = *(BYTE **)pbEncoded;
255 *pbEncoded++ = ASN_SEQUENCE;
256 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
257 pbEncoded += lenBytes;
258 for (i = 0; ret && i < cItem; i++)
260 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
261 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG,
262 NULL, pbEncoded, &items[i].size);
263 /* Some functions propagate their errors through the size */
264 if (!ret)
265 *pcbEncoded = items[i].size;
266 pbEncoded += items[i].size;
271 TRACE("returning %d (%08x)\n", ret, GetLastError());
272 return ret;
275 struct AsnConstructedItem
277 BYTE tag;
278 const void *pvStructInfo;
279 CryptEncodeObjectExFunc encodeFunc;
282 static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
283 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
284 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
286 BOOL ret;
287 const struct AsnConstructedItem *item =
288 (const struct AsnConstructedItem *)pvStructInfo;
289 DWORD len;
291 if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
292 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &len)))
294 DWORD dataLen, bytesNeeded;
296 CRYPT_EncodeLen(len, NULL, &dataLen);
297 bytesNeeded = 1 + dataLen + len;
298 if (!pbEncoded)
299 *pcbEncoded = bytesNeeded;
300 else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
301 pbEncoded, pcbEncoded, bytesNeeded)))
303 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
304 pbEncoded = *(BYTE **)pbEncoded;
305 *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
306 CRYPT_EncodeLen(len, pbEncoded, &dataLen);
307 pbEncoded += dataLen;
308 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
309 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
310 pbEncoded, &len);
311 if (!ret)
313 /* Some functions propagate their errors through the size */
314 *pcbEncoded = len;
318 else
320 /* Some functions propagate their errors through the size */
321 *pcbEncoded = len;
323 return ret;
326 struct AsnEncodeTagSwappedItem
328 BYTE tag;
329 const void *pvStructInfo;
330 CryptEncodeObjectExFunc encodeFunc;
333 /* Sort of a wacky hack, it encodes something using the struct
334 * AsnEncodeTagSwappedItem's encodeFunc, then replaces the tag byte with the tag
335 * given in the struct AsnEncodeTagSwappedItem.
337 static BOOL WINAPI CRYPT_AsnEncodeSwapTag(DWORD dwCertEncodingType,
338 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
339 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
341 BOOL ret;
342 const struct AsnEncodeTagSwappedItem *item =
343 (const struct AsnEncodeTagSwappedItem *)pvStructInfo;
345 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
346 item->pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
347 if (ret && pbEncoded)
348 *pbEncoded = item->tag;
349 return ret;
352 static BOOL WINAPI CRYPT_AsnEncodeCertVersion(DWORD dwCertEncodingType,
353 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
354 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
356 const DWORD *ver = (const DWORD *)pvStructInfo;
357 BOOL ret;
359 /* CERT_V1 is not encoded */
360 if (*ver == CERT_V1)
362 *pcbEncoded = 0;
363 ret = TRUE;
365 else
367 struct AsnConstructedItem item = { 0, ver, CRYPT_AsnEncodeInt };
369 ret = CRYPT_AsnEncodeConstructed(dwCertEncodingType, X509_INTEGER,
370 &item, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
372 return ret;
375 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
376 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
377 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
379 const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
380 BOOL ret;
382 if (!pbEncoded)
384 *pcbEncoded = blob->cbData;
385 ret = TRUE;
387 else
389 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
390 pcbEncoded, blob->cbData)))
392 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
393 pbEncoded = *(BYTE **)pbEncoded;
394 if (blob->cbData)
395 memcpy(pbEncoded, blob->pbData, blob->cbData);
396 *pcbEncoded = blob->cbData;
397 ret = TRUE;
400 return ret;
403 static BOOL WINAPI CRYPT_AsnEncodeValidity(DWORD dwCertEncodingType,
404 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
405 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
407 BOOL ret;
408 /* This has two filetimes in a row, a NotBefore and a NotAfter */
409 const FILETIME *timePtr = (const FILETIME *)pvStructInfo;
410 struct AsnEncodeSequenceItem items[] = {
411 { timePtr++, CRYPT_AsnEncodeChoiceOfTime, 0 },
412 { timePtr, CRYPT_AsnEncodeChoiceOfTime, 0 },
415 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
416 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
417 pcbEncoded);
418 return ret;
421 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmId(
422 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
423 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
424 DWORD *pcbEncoded)
426 const CRYPT_ALGORITHM_IDENTIFIER *algo =
427 (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
428 BOOL ret;
429 struct AsnEncodeSequenceItem items[] = {
430 { algo->pszObjId, CRYPT_AsnEncodeOid, 0 },
431 { &algo->Parameters, CRYPT_CopyEncodedBlob, 0 },
434 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
435 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
436 pcbEncoded);
437 return ret;
440 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
441 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
442 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
444 BOOL ret;
446 __TRY
448 const CERT_PUBLIC_KEY_INFO *info =
449 (const CERT_PUBLIC_KEY_INFO *)pvStructInfo;
450 struct AsnEncodeSequenceItem items[] = {
451 { &info->Algorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
452 { &info->PublicKey, CRYPT_AsnEncodeBits, 0 },
455 TRACE("Encoding public key with OID %s\n",
456 debugstr_a(info->Algorithm.pszObjId));
457 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
458 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
459 pcbEncoded);
461 __EXCEPT_PAGE_FAULT
463 SetLastError(STATUS_ACCESS_VIOLATION);
464 ret = FALSE;
466 __ENDTRY
467 return ret;
470 static BOOL WINAPI CRYPT_AsnEncodeCert(DWORD dwCertEncodingType,
471 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
472 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
474 BOOL ret;
476 __TRY
478 const CERT_SIGNED_CONTENT_INFO *info =
479 (const CERT_SIGNED_CONTENT_INFO *)pvStructInfo;
480 struct AsnEncodeSequenceItem items[] = {
481 { &info->ToBeSigned, CRYPT_CopyEncodedBlob, 0 },
482 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
483 { &info->Signature, CRYPT_AsnEncodeBitsSwapBytes, 0 },
486 if (dwFlags & CRYPT_ENCODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
487 items[2].encodeFunc = CRYPT_AsnEncodeBits;
488 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
489 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
490 pcbEncoded);
492 __EXCEPT_PAGE_FAULT
494 SetLastError(STATUS_ACCESS_VIOLATION);
495 ret = FALSE;
497 __ENDTRY
498 return ret;
501 /* Like in Windows, this blithely ignores the validity of the passed-in
502 * CERT_INFO, and just encodes it as-is. The resulting encoded data may not
503 * decode properly, see CRYPT_AsnDecodeCertInfo.
505 static BOOL WINAPI CRYPT_AsnEncodeCertInfo(DWORD dwCertEncodingType,
506 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
507 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
509 BOOL ret;
511 __TRY
513 const CERT_INFO *info = (const CERT_INFO *)pvStructInfo;
514 struct AsnEncodeSequenceItem items[10] = {
515 { &info->dwVersion, CRYPT_AsnEncodeCertVersion, 0 },
516 { &info->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
517 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
518 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
519 { &info->NotBefore, CRYPT_AsnEncodeValidity, 0 },
520 { &info->Subject, CRYPT_CopyEncodedBlob, 0 },
521 { &info->SubjectPublicKeyInfo, CRYPT_AsnEncodePubKeyInfo, 0 },
522 { 0 }
524 struct AsnConstructedItem constructed[3] = { { 0 } };
525 DWORD cItem = 7, cConstructed = 0;
527 if (info->IssuerUniqueId.cbData)
529 constructed[cConstructed].tag = 1;
530 constructed[cConstructed].pvStructInfo = &info->IssuerUniqueId;
531 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
532 items[cItem].pvStructInfo = &constructed[cConstructed];
533 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
534 cConstructed++;
535 cItem++;
537 if (info->SubjectUniqueId.cbData)
539 constructed[cConstructed].tag = 2;
540 constructed[cConstructed].pvStructInfo = &info->SubjectUniqueId;
541 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
542 items[cItem].pvStructInfo = &constructed[cConstructed];
543 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
544 cConstructed++;
545 cItem++;
547 if (info->cExtension)
549 constructed[cConstructed].tag = 3;
550 constructed[cConstructed].pvStructInfo = &info->cExtension;
551 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions;
552 items[cItem].pvStructInfo = &constructed[cConstructed];
553 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
554 cConstructed++;
555 cItem++;
558 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
559 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
561 __EXCEPT_PAGE_FAULT
563 SetLastError(STATUS_ACCESS_VIOLATION);
564 ret = FALSE;
566 __ENDTRY
567 return ret;
570 static BOOL WINAPI CRYPT_AsnEncodeCRLEntry(const CRL_ENTRY *entry,
571 BYTE *pbEncoded, DWORD *pcbEncoded)
573 struct AsnEncodeSequenceItem items[3] = {
574 { &entry->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
575 { &entry->RevocationDate, CRYPT_AsnEncodeChoiceOfTime, 0 },
576 { 0 }
578 DWORD cItem = 2;
579 BOOL ret;
581 TRACE("%p, %p, %p\n", entry, pbEncoded, pcbEncoded);
583 if (entry->cExtension)
585 items[cItem].pvStructInfo = &entry->cExtension;
586 items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
587 cItem++;
590 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
591 pbEncoded, pcbEncoded);
593 TRACE("returning %d (%08x)\n", ret, GetLastError());
594 return ret;
597 static BOOL WINAPI CRYPT_AsnEncodeCRLEntries(DWORD dwCertEncodingType,
598 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
599 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
601 DWORD cCRLEntry = *(const DWORD *)pvStructInfo;
602 DWORD bytesNeeded, dataLen, lenBytes, i;
603 const CRL_ENTRY *rgCRLEntry = *(const CRL_ENTRY **)
604 ((const BYTE *)pvStructInfo + sizeof(DWORD));
605 BOOL ret = TRUE;
607 for (i = 0, dataLen = 0; ret && i < cCRLEntry; i++)
609 DWORD size;
611 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], NULL, &size);
612 if (ret)
613 dataLen += size;
615 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
616 bytesNeeded = 1 + lenBytes + dataLen;
617 if (!pbEncoded)
618 *pcbEncoded = bytesNeeded;
619 else
621 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
622 pcbEncoded, bytesNeeded)))
624 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
625 pbEncoded = *(BYTE **)pbEncoded;
626 *pbEncoded++ = ASN_SEQUENCEOF;
627 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
628 pbEncoded += lenBytes;
629 for (i = 0; i < cCRLEntry; i++)
631 DWORD size = dataLen;
633 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], pbEncoded, &size);
634 pbEncoded += size;
635 dataLen -= size;
639 return ret;
642 static BOOL WINAPI CRYPT_AsnEncodeCRLVersion(DWORD dwCertEncodingType,
643 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
644 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
646 const DWORD *ver = (const DWORD *)pvStructInfo;
647 BOOL ret;
649 /* CRL_V1 is not encoded */
650 if (*ver == CRL_V1)
652 *pcbEncoded = 0;
653 ret = TRUE;
655 else
656 ret = CRYPT_AsnEncodeInt(dwCertEncodingType, X509_INTEGER, ver,
657 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
658 return ret;
661 /* Like in Windows, this blithely ignores the validity of the passed-in
662 * CRL_INFO, and just encodes it as-is. The resulting encoded data may not
663 * decode properly, see CRYPT_AsnDecodeCRLInfo.
665 static BOOL WINAPI CRYPT_AsnEncodeCRLInfo(DWORD dwCertEncodingType,
666 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
667 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
669 BOOL ret;
671 __TRY
673 const CRL_INFO *info = (const CRL_INFO *)pvStructInfo;
674 struct AsnEncodeSequenceItem items[7] = {
675 { &info->dwVersion, CRYPT_AsnEncodeCRLVersion, 0 },
676 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
677 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
678 { &info->ThisUpdate, CRYPT_AsnEncodeChoiceOfTime, 0 },
679 { 0 }
681 struct AsnConstructedItem constructed[1] = { { 0 } };
682 DWORD cItem = 4, cConstructed = 0;
684 if (info->NextUpdate.dwLowDateTime || info->NextUpdate.dwHighDateTime)
686 items[cItem].pvStructInfo = &info->NextUpdate;
687 items[cItem].encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
688 cItem++;
690 if (info->cCRLEntry)
692 items[cItem].pvStructInfo = &info->cCRLEntry;
693 items[cItem].encodeFunc = CRYPT_AsnEncodeCRLEntries;
694 cItem++;
696 if (info->cExtension)
698 constructed[cConstructed].tag = 0;
699 constructed[cConstructed].pvStructInfo = &info->cExtension;
700 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions;
701 items[cItem].pvStructInfo = &constructed[cConstructed];
702 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
703 cConstructed++;
704 cItem++;
707 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
708 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
710 __EXCEPT_PAGE_FAULT
712 SetLastError(STATUS_ACCESS_VIOLATION);
713 ret = FALSE;
715 __ENDTRY
716 return ret;
719 static BOOL CRYPT_AsnEncodeExtension(CERT_EXTENSION *ext, BYTE *pbEncoded,
720 DWORD *pcbEncoded)
722 BOOL ret;
723 struct AsnEncodeSequenceItem items[3] = {
724 { ext->pszObjId, CRYPT_AsnEncodeOid, 0 },
725 { NULL, NULL, 0 },
726 { NULL, NULL, 0 },
728 DWORD cItem = 1;
730 TRACE("%p, %p, %d\n", ext, pbEncoded, *pcbEncoded);
732 if (ext->fCritical)
734 items[cItem].pvStructInfo = &ext->fCritical;
735 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
736 cItem++;
738 items[cItem].pvStructInfo = &ext->Value;
739 items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
740 cItem++;
742 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
743 pbEncoded, pcbEncoded);
744 TRACE("returning %d (%08x)\n", ret, GetLastError());
745 return ret;
748 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
749 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
750 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
752 BOOL ret;
754 __TRY
756 DWORD bytesNeeded, dataLen, lenBytes, i;
757 const CERT_EXTENSIONS *exts = (const CERT_EXTENSIONS *)pvStructInfo;
759 ret = TRUE;
760 for (i = 0, dataLen = 0; ret && i < exts->cExtension; i++)
762 DWORD size;
764 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i], NULL, &size);
765 if (ret)
766 dataLen += size;
768 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
769 bytesNeeded = 1 + lenBytes + dataLen;
770 if (!pbEncoded)
771 *pcbEncoded = bytesNeeded;
772 else
774 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
775 pcbEncoded, bytesNeeded)))
777 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
778 pbEncoded = *(BYTE **)pbEncoded;
779 *pbEncoded++ = ASN_SEQUENCEOF;
780 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
781 pbEncoded += lenBytes;
782 for (i = 0; i < exts->cExtension; i++)
784 DWORD size = dataLen;
786 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i],
787 pbEncoded, &size);
788 pbEncoded += size;
789 dataLen -= size;
794 __EXCEPT_PAGE_FAULT
796 SetLastError(STATUS_ACCESS_VIOLATION);
797 ret = FALSE;
799 __ENDTRY
800 return ret;
803 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
804 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
805 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
807 LPCSTR pszObjId = (LPCSTR)pvStructInfo;
808 DWORD bytesNeeded = 0, lenBytes;
809 BOOL ret = TRUE;
810 int firstPos = 0;
811 BYTE firstByte = 0;
813 TRACE("%s\n", debugstr_a(pszObjId));
815 if (pszObjId)
817 const char *ptr;
818 int val1, val2;
820 if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
822 SetLastError(CRYPT_E_ASN1_ERROR);
823 return FALSE;
825 bytesNeeded++;
826 firstByte = val1 * 40 + val2;
827 ptr = pszObjId + firstPos;
828 while (ret && *ptr)
830 int pos;
832 /* note I assume each component is at most 32-bits long in base 2 */
833 if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
835 if (val1 >= 0x10000000)
836 bytesNeeded += 5;
837 else if (val1 >= 0x200000)
838 bytesNeeded += 4;
839 else if (val1 >= 0x4000)
840 bytesNeeded += 3;
841 else if (val1 >= 0x80)
842 bytesNeeded += 2;
843 else
844 bytesNeeded += 1;
845 ptr += pos;
846 if (*ptr == '.')
847 ptr++;
849 else
851 SetLastError(CRYPT_E_ASN1_ERROR);
852 return FALSE;
855 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
857 else
858 lenBytes = 1;
859 bytesNeeded += 1 + lenBytes;
860 if (pbEncoded)
862 if (*pcbEncoded < bytesNeeded)
864 SetLastError(ERROR_MORE_DATA);
865 ret = FALSE;
867 else
869 *pbEncoded++ = ASN_OBJECTIDENTIFIER;
870 CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
871 pbEncoded += lenBytes;
872 if (pszObjId)
874 const char *ptr;
875 int val, pos;
877 *pbEncoded++ = firstByte;
878 ptr = pszObjId + firstPos;
879 while (ret && *ptr)
881 sscanf(ptr, "%d%n", &val, &pos);
883 unsigned char outBytes[5];
884 int numBytes, i;
886 if (val >= 0x10000000)
887 numBytes = 5;
888 else if (val >= 0x200000)
889 numBytes = 4;
890 else if (val >= 0x4000)
891 numBytes = 3;
892 else if (val >= 0x80)
893 numBytes = 2;
894 else
895 numBytes = 1;
896 for (i = numBytes; i > 0; i--)
898 outBytes[i - 1] = val & 0x7f;
899 val >>= 7;
901 for (i = 0; i < numBytes - 1; i++)
902 *pbEncoded++ = outBytes[i] | 0x80;
903 *pbEncoded++ = outBytes[i];
904 ptr += pos;
905 if (*ptr == '.')
906 ptr++;
912 *pcbEncoded = bytesNeeded;
913 return ret;
916 static BOOL CRYPT_AsnEncodeStringCoerce(const CERT_NAME_VALUE *value,
917 BYTE tag, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
918 DWORD *pcbEncoded)
920 BOOL ret = TRUE;
921 LPCSTR str = (LPCSTR)value->Value.pbData;
922 DWORD bytesNeeded, lenBytes, encodedLen;
924 encodedLen = value->Value.cbData ? value->Value.cbData : lstrlenA(str);
925 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
926 bytesNeeded = 1 + lenBytes + encodedLen;
927 if (!pbEncoded)
928 *pcbEncoded = bytesNeeded;
929 else
931 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
932 pbEncoded, pcbEncoded, bytesNeeded)))
934 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
935 pbEncoded = *(BYTE **)pbEncoded;
936 *pbEncoded++ = tag;
937 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
938 pbEncoded += lenBytes;
939 memcpy(pbEncoded, str, encodedLen);
942 return ret;
945 static BOOL CRYPT_AsnEncodeBMPString(const CERT_NAME_VALUE *value,
946 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
947 DWORD *pcbEncoded)
949 BOOL ret = TRUE;
950 LPCWSTR str = (LPCWSTR)value->Value.pbData;
951 DWORD bytesNeeded, lenBytes, strLen;
953 strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
954 lstrlenW(str);
955 CRYPT_EncodeLen(strLen * 2, NULL, &lenBytes);
956 bytesNeeded = 1 + lenBytes + strLen * 2;
957 if (!pbEncoded)
958 *pcbEncoded = bytesNeeded;
959 else
961 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
962 pbEncoded, pcbEncoded, bytesNeeded)))
964 DWORD i;
966 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
967 pbEncoded = *(BYTE **)pbEncoded;
968 *pbEncoded++ = ASN_BMPSTRING;
969 CRYPT_EncodeLen(strLen * 2, pbEncoded, &lenBytes);
970 pbEncoded += lenBytes;
971 for (i = 0; i < strLen; i++)
973 *pbEncoded++ = (str[i] & 0xff00) >> 8;
974 *pbEncoded++ = str[i] & 0x00ff;
978 return ret;
981 static BOOL CRYPT_AsnEncodeUTF8String(const CERT_NAME_VALUE *value,
982 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
983 DWORD *pcbEncoded)
985 BOOL ret = TRUE;
986 LPCWSTR str = (LPCWSTR)value->Value.pbData;
987 DWORD bytesNeeded, lenBytes, encodedLen, strLen;
989 strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
990 lstrlenW(str);
991 encodedLen = WideCharToMultiByte(CP_UTF8, 0, str, strLen, NULL, 0, NULL,
992 NULL);
993 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
994 bytesNeeded = 1 + lenBytes + encodedLen;
995 if (!pbEncoded)
996 *pcbEncoded = bytesNeeded;
997 else
999 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1000 pbEncoded, pcbEncoded, bytesNeeded)))
1002 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1003 pbEncoded = *(BYTE **)pbEncoded;
1004 *pbEncoded++ = ASN_UTF8STRING;
1005 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1006 pbEncoded += lenBytes;
1007 WideCharToMultiByte(CP_UTF8, 0, str, strLen, (LPSTR)pbEncoded,
1008 bytesNeeded - lenBytes - 1, NULL, NULL);
1011 return ret;
1014 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
1015 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1016 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1018 BOOL ret = TRUE;
1020 __TRY
1022 const CERT_NAME_VALUE *value = (const CERT_NAME_VALUE *)pvStructInfo;
1024 switch (value->dwValueType)
1026 case CERT_RDN_ANY_TYPE:
1027 /* explicitly disallowed */
1028 SetLastError(E_INVALIDARG);
1029 ret = FALSE;
1030 break;
1031 case CERT_RDN_ENCODED_BLOB:
1032 ret = CRYPT_CopyEncodedBlob(dwCertEncodingType, NULL,
1033 &value->Value, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1034 break;
1035 case CERT_RDN_OCTET_STRING:
1036 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_OCTETSTRING,
1037 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1038 break;
1039 case CERT_RDN_NUMERIC_STRING:
1040 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_NUMERICSTRING,
1041 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1042 break;
1043 case CERT_RDN_PRINTABLE_STRING:
1044 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_PRINTABLESTRING,
1045 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1046 break;
1047 case CERT_RDN_TELETEX_STRING:
1048 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_T61STRING,
1049 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1050 break;
1051 case CERT_RDN_VIDEOTEX_STRING:
1052 ret = CRYPT_AsnEncodeStringCoerce(value,
1053 ASN_VIDEOTEXSTRING, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1054 break;
1055 case CERT_RDN_IA5_STRING:
1056 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_IA5STRING,
1057 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1058 break;
1059 case CERT_RDN_GRAPHIC_STRING:
1060 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_GRAPHICSTRING,
1061 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1062 break;
1063 case CERT_RDN_VISIBLE_STRING:
1064 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_VISIBLESTRING,
1065 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1066 break;
1067 case CERT_RDN_GENERAL_STRING:
1068 ret = CRYPT_AsnEncodeStringCoerce(value, ASN_GENERALSTRING,
1069 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1070 break;
1071 case CERT_RDN_UNIVERSAL_STRING:
1072 FIXME("CERT_RDN_UNIVERSAL_STRING: unimplemented\n");
1073 SetLastError(CRYPT_E_ASN1_CHOICE);
1074 ret = FALSE;
1075 break;
1076 case CERT_RDN_BMP_STRING:
1077 ret = CRYPT_AsnEncodeBMPString(value, dwFlags, pEncodePara,
1078 pbEncoded, pcbEncoded);
1079 break;
1080 case CERT_RDN_UTF8_STRING:
1081 ret = CRYPT_AsnEncodeUTF8String(value, dwFlags, pEncodePara,
1082 pbEncoded, pcbEncoded);
1083 break;
1084 default:
1085 SetLastError(CRYPT_E_ASN1_CHOICE);
1086 ret = FALSE;
1089 __EXCEPT_PAGE_FAULT
1091 SetLastError(STATUS_ACCESS_VIOLATION);
1092 ret = FALSE;
1094 __ENDTRY
1095 return ret;
1098 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
1099 CERT_RDN_ATTR *attr, CryptEncodeObjectExFunc nameValueEncodeFunc,
1100 BYTE *pbEncoded, DWORD *pcbEncoded)
1102 DWORD bytesNeeded = 0, lenBytes, size;
1103 BOOL ret;
1105 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL, attr->pszObjId,
1106 0, NULL, NULL, &size);
1107 if (ret)
1109 bytesNeeded += size;
1110 /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
1111 * with dwValueType, so "cast" it to get its encoded size
1113 ret = nameValueEncodeFunc(dwCertEncodingType, NULL,
1114 (CERT_NAME_VALUE *)&attr->dwValueType, 0, NULL, NULL, &size);
1115 if (ret)
1117 bytesNeeded += size;
1118 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1119 bytesNeeded += 1 + lenBytes;
1120 if (pbEncoded)
1122 if (*pcbEncoded < bytesNeeded)
1124 SetLastError(ERROR_MORE_DATA);
1125 ret = FALSE;
1127 else
1129 *pbEncoded++ = ASN_SEQUENCE;
1130 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1131 &lenBytes);
1132 pbEncoded += lenBytes;
1133 size = bytesNeeded - 1 - lenBytes;
1134 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
1135 attr->pszObjId, 0, NULL, pbEncoded, &size);
1136 if (ret)
1138 pbEncoded += size;
1139 size = bytesNeeded - 1 - lenBytes - size;
1140 ret = nameValueEncodeFunc(dwCertEncodingType,
1141 NULL, (CERT_NAME_VALUE *)&attr->dwValueType,
1142 0, NULL, pbEncoded, &size);
1143 if (!ret)
1144 *pcbEncoded = size;
1148 if (ret)
1149 *pcbEncoded = bytesNeeded;
1151 else
1153 /* Have to propagate index of failing character */
1154 *pcbEncoded = size;
1157 return ret;
1160 static int BLOBComp(const void *l, const void *r)
1162 const CRYPT_DER_BLOB *a = (const CRYPT_DER_BLOB *)l, *b = (const CRYPT_DER_BLOB *)r;
1163 int ret;
1165 if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
1166 ret = a->cbData - b->cbData;
1167 return ret;
1170 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
1172 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
1173 CryptEncodeObjectExFunc nameValueEncodeFunc, BYTE *pbEncoded,
1174 DWORD *pcbEncoded)
1176 BOOL ret;
1177 CRYPT_DER_BLOB *blobs = NULL;
1179 __TRY
1181 DWORD bytesNeeded = 0, lenBytes, i;
1183 blobs = NULL;
1184 ret = TRUE;
1185 if (rdn->cRDNAttr)
1187 blobs = CryptMemAlloc(rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1188 if (!blobs)
1189 ret = FALSE;
1190 else
1191 memset(blobs, 0, rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1193 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1195 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
1196 nameValueEncodeFunc, NULL, &blobs[i].cbData);
1197 if (ret)
1198 bytesNeeded += blobs[i].cbData;
1199 else
1201 /* Have to propagate index of failing character */
1202 *pcbEncoded = blobs[i].cbData;
1205 if (ret)
1207 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1208 bytesNeeded += 1 + lenBytes;
1209 if (pbEncoded)
1211 if (*pcbEncoded < bytesNeeded)
1213 SetLastError(ERROR_MORE_DATA);
1214 ret = FALSE;
1216 else
1218 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1220 blobs[i].pbData = CryptMemAlloc(blobs[i].cbData);
1221 if (!blobs[i].pbData)
1222 ret = FALSE;
1223 else
1225 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
1226 &rdn->rgRDNAttr[i], nameValueEncodeFunc,
1227 blobs[i].pbData, &blobs[i].cbData);
1228 if (!ret)
1229 *pcbEncoded = blobs[i].cbData;
1232 if (ret)
1234 qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
1235 BLOBComp);
1236 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
1237 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1238 &lenBytes);
1239 pbEncoded += lenBytes;
1240 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1242 memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
1243 pbEncoded += blobs[i].cbData;
1248 if (ret)
1249 *pcbEncoded = bytesNeeded;
1251 if (blobs)
1253 for (i = 0; i < rdn->cRDNAttr; i++)
1254 CryptMemFree(blobs[i].pbData);
1257 __EXCEPT_PAGE_FAULT
1259 SetLastError(STATUS_ACCESS_VIOLATION);
1260 ret = FALSE;
1262 __ENDTRY
1263 CryptMemFree(blobs);
1264 return ret;
1267 static BOOL WINAPI CRYPT_AsnEncodeUnicodeNameValue(DWORD dwCertEncodingType,
1268 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1269 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
1271 static BOOL WINAPI CRYPT_AsnEncodeOrCopyUnicodeNameValue(
1272 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
1273 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1274 DWORD *pcbEncoded)
1276 const CERT_NAME_VALUE *value = (const CERT_NAME_VALUE *)pvStructInfo;
1277 BOOL ret;
1279 if (value->dwValueType == CERT_RDN_ENCODED_BLOB)
1280 ret = CRYPT_CopyEncodedBlob(dwCertEncodingType, NULL, &value->Value,
1281 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1282 else
1283 ret = CRYPT_AsnEncodeUnicodeNameValue(dwCertEncodingType, NULL, value,
1284 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1285 return ret;
1288 static BOOL WINAPI CRYPT_AsnEncodeUnicodeName(DWORD dwCertEncodingType,
1289 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1290 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1292 BOOL ret = TRUE;
1294 __TRY
1296 const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1297 DWORD bytesNeeded = 0, lenBytes, size, i;
1299 TRACE("encoding name with %d RDNs\n", info->cRDN);
1300 ret = TRUE;
1301 for (i = 0; ret && i < info->cRDN; i++)
1303 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i],
1304 CRYPT_AsnEncodeOrCopyUnicodeNameValue, NULL, &size);
1305 if (ret)
1306 bytesNeeded += size;
1307 else
1308 *pcbEncoded = size;
1310 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1311 bytesNeeded += 1 + lenBytes;
1312 if (ret)
1314 if (!pbEncoded)
1315 *pcbEncoded = bytesNeeded;
1316 else
1318 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1319 pbEncoded, pcbEncoded, bytesNeeded)))
1321 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1322 pbEncoded = *(BYTE **)pbEncoded;
1323 *pbEncoded++ = ASN_SEQUENCEOF;
1324 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1325 &lenBytes);
1326 pbEncoded += lenBytes;
1327 for (i = 0; ret && i < info->cRDN; i++)
1329 size = bytesNeeded;
1330 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1331 &info->rgRDN[i], CRYPT_AsnEncodeOrCopyUnicodeNameValue,
1332 pbEncoded, &size);
1333 if (ret)
1335 pbEncoded += size;
1336 bytesNeeded -= size;
1338 else
1339 *pcbEncoded = size;
1345 __EXCEPT_PAGE_FAULT
1347 SetLastError(STATUS_ACCESS_VIOLATION);
1348 ret = FALSE;
1350 __ENDTRY
1351 return ret;
1354 static BOOL CRYPT_AsnEncodeUnicodeStringCoerce(const CERT_NAME_VALUE *value,
1355 BYTE tag, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1356 DWORD *pcbEncoded)
1358 BOOL ret = TRUE;
1359 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1360 DWORD bytesNeeded, lenBytes, encodedLen;
1362 encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1363 lstrlenW(str);
1364 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1365 bytesNeeded = 1 + lenBytes + encodedLen;
1366 if (!pbEncoded)
1367 *pcbEncoded = bytesNeeded;
1368 else
1370 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1371 pbEncoded, pcbEncoded, bytesNeeded)))
1373 DWORD i;
1375 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1376 pbEncoded = *(BYTE **)pbEncoded;
1377 *pbEncoded++ = tag;
1378 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1379 pbEncoded += lenBytes;
1380 for (i = 0; i < encodedLen; i++)
1381 *pbEncoded++ = (BYTE)str[i];
1384 return ret;
1387 static BOOL CRYPT_AsnEncodeNumericString(const CERT_NAME_VALUE *value,
1388 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1389 DWORD *pcbEncoded)
1391 BOOL ret = TRUE;
1392 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1393 DWORD bytesNeeded, lenBytes, encodedLen;
1395 encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1396 lstrlenW(str);
1397 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1398 bytesNeeded = 1 + lenBytes + encodedLen;
1399 if (!pbEncoded)
1400 *pcbEncoded = bytesNeeded;
1401 else
1403 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1404 pbEncoded, pcbEncoded, bytesNeeded)))
1406 DWORD i;
1408 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1409 pbEncoded = *(BYTE **)pbEncoded;
1410 *pbEncoded++ = ASN_NUMERICSTRING;
1411 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1412 pbEncoded += lenBytes;
1413 for (i = 0; ret && i < encodedLen; i++)
1415 if (isdigitW(str[i]))
1416 *pbEncoded++ = (BYTE)str[i];
1417 else
1419 *pcbEncoded = i;
1420 SetLastError(CRYPT_E_INVALID_NUMERIC_STRING);
1421 ret = FALSE;
1426 return ret;
1429 static inline int isprintableW(WCHAR wc)
1431 return isalnumW(wc) || isspaceW(wc) || wc == '\'' || wc == '(' ||
1432 wc == ')' || wc == '+' || wc == ',' || wc == '-' || wc == '.' ||
1433 wc == '/' || wc == ':' || wc == '=' || wc == '?';
1436 static BOOL CRYPT_AsnEncodePrintableString(const CERT_NAME_VALUE *value,
1437 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1438 DWORD *pcbEncoded)
1440 BOOL ret = TRUE;
1441 LPCWSTR str = (LPCWSTR)value->Value.pbData;
1442 DWORD bytesNeeded, lenBytes, encodedLen;
1444 encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1445 lstrlenW(str);
1446 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1447 bytesNeeded = 1 + lenBytes + encodedLen;
1448 if (!pbEncoded)
1449 *pcbEncoded = bytesNeeded;
1450 else
1452 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1453 pbEncoded, pcbEncoded, bytesNeeded)))
1455 DWORD i;
1457 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1458 pbEncoded = *(BYTE **)pbEncoded;
1459 *pbEncoded++ = ASN_PRINTABLESTRING;
1460 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1461 pbEncoded += lenBytes;
1462 for (i = 0; ret && i < encodedLen; i++)
1464 if (isprintableW(str[i]))
1465 *pbEncoded++ = (BYTE)str[i];
1466 else
1468 *pcbEncoded = i;
1469 SetLastError(CRYPT_E_INVALID_PRINTABLE_STRING);
1470 ret = FALSE;
1475 return ret;
1478 static BOOL CRYPT_AsnEncodeIA5String(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_IA5STRING;
1502 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1503 pbEncoded += lenBytes;
1504 for (i = 0; ret && i < encodedLen; i++)
1506 if (str[i] <= 0x7f)
1507 *pbEncoded++ = (BYTE)str[i];
1508 else
1510 *pcbEncoded = i;
1511 SetLastError(CRYPT_E_INVALID_IA5_STRING);
1512 ret = FALSE;
1517 return ret;
1520 static BOOL CRYPT_AsnEncodeUniversalString(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, strLen;
1528 /* FIXME: doesn't handle composite characters */
1529 strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1530 lstrlenW(str);
1531 CRYPT_EncodeLen(strLen * 4, NULL, &lenBytes);
1532 bytesNeeded = 1 + lenBytes + strLen * 4;
1533 if (!pbEncoded)
1534 *pcbEncoded = bytesNeeded;
1535 else
1537 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1538 pbEncoded, pcbEncoded, bytesNeeded)))
1540 DWORD i;
1542 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1543 pbEncoded = *(BYTE **)pbEncoded;
1544 *pbEncoded++ = ASN_UNIVERSALSTRING;
1545 CRYPT_EncodeLen(strLen * 4, pbEncoded, &lenBytes);
1546 pbEncoded += lenBytes;
1547 for (i = 0; i < strLen; i++)
1549 *pbEncoded++ = 0;
1550 *pbEncoded++ = 0;
1551 *pbEncoded++ = (BYTE)((str[i] & 0xff00) >> 8);
1552 *pbEncoded++ = (BYTE)(str[i] & 0x00ff);
1556 return ret;
1559 static BOOL WINAPI CRYPT_AsnEncodeUnicodeNameValue(DWORD dwCertEncodingType,
1560 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1561 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1563 BOOL ret = FALSE;
1565 __TRY
1567 const CERT_NAME_VALUE *value = (const CERT_NAME_VALUE *)pvStructInfo;
1569 switch (value->dwValueType)
1571 case CERT_RDN_ANY_TYPE:
1572 case CERT_RDN_ENCODED_BLOB:
1573 case CERT_RDN_OCTET_STRING:
1574 SetLastError(CRYPT_E_NOT_CHAR_STRING);
1575 break;
1576 case CERT_RDN_NUMERIC_STRING:
1577 ret = CRYPT_AsnEncodeNumericString(value, dwFlags, pEncodePara,
1578 pbEncoded, pcbEncoded);
1579 break;
1580 case CERT_RDN_PRINTABLE_STRING:
1581 ret = CRYPT_AsnEncodePrintableString(value, dwFlags, pEncodePara,
1582 pbEncoded, pcbEncoded);
1583 break;
1584 case CERT_RDN_TELETEX_STRING:
1585 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_T61STRING,
1586 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1587 break;
1588 case CERT_RDN_VIDEOTEX_STRING:
1589 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value,
1590 ASN_VIDEOTEXSTRING, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1591 break;
1592 case CERT_RDN_IA5_STRING:
1593 ret = CRYPT_AsnEncodeIA5String(value, dwFlags, pEncodePara,
1594 pbEncoded, pcbEncoded);
1595 break;
1596 case CERT_RDN_GRAPHIC_STRING:
1597 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_GRAPHICSTRING,
1598 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1599 break;
1600 case CERT_RDN_VISIBLE_STRING:
1601 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_VISIBLESTRING,
1602 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1603 break;
1604 case CERT_RDN_GENERAL_STRING:
1605 ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_GENERALSTRING,
1606 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1607 break;
1608 case CERT_RDN_UNIVERSAL_STRING:
1609 ret = CRYPT_AsnEncodeUniversalString(value, dwFlags, pEncodePara,
1610 pbEncoded, pcbEncoded);
1611 break;
1612 case CERT_RDN_BMP_STRING:
1613 ret = CRYPT_AsnEncodeBMPString(value, dwFlags, pEncodePara,
1614 pbEncoded, pcbEncoded);
1615 break;
1616 case CERT_RDN_UTF8_STRING:
1617 ret = CRYPT_AsnEncodeUTF8String(value, dwFlags, pEncodePara,
1618 pbEncoded, pcbEncoded);
1619 break;
1620 default:
1621 SetLastError(CRYPT_E_ASN1_CHOICE);
1624 __EXCEPT_PAGE_FAULT
1626 SetLastError(STATUS_ACCESS_VIOLATION);
1628 __ENDTRY
1629 return ret;
1632 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
1633 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1634 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1636 BOOL ret;
1638 __TRY
1640 const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1641 DWORD bytesNeeded = 0, lenBytes, size, i;
1643 TRACE("encoding name with %d RDNs\n", info->cRDN);
1644 ret = TRUE;
1645 for (i = 0; ret && i < info->cRDN; i++)
1647 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i],
1648 CRYPT_AsnEncodeNameValue, NULL, &size);
1649 if (ret)
1650 bytesNeeded += size;
1652 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1653 bytesNeeded += 1 + lenBytes;
1654 if (ret)
1656 if (!pbEncoded)
1657 *pcbEncoded = bytesNeeded;
1658 else
1660 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1661 pbEncoded, pcbEncoded, bytesNeeded)))
1663 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1664 pbEncoded = *(BYTE **)pbEncoded;
1665 *pbEncoded++ = ASN_SEQUENCEOF;
1666 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1667 &lenBytes);
1668 pbEncoded += lenBytes;
1669 for (i = 0; ret && i < info->cRDN; i++)
1671 size = bytesNeeded;
1672 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1673 &info->rgRDN[i], CRYPT_AsnEncodeNameValue, pbEncoded,
1674 &size);
1675 if (ret)
1677 pbEncoded += size;
1678 bytesNeeded -= size;
1685 __EXCEPT_PAGE_FAULT
1687 SetLastError(STATUS_ACCESS_VIOLATION);
1688 ret = FALSE;
1690 __ENDTRY
1691 return ret;
1694 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1695 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1696 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1698 BOOL val = *(const BOOL *)pvStructInfo, ret;
1700 TRACE("%d\n", val);
1702 if (!pbEncoded)
1704 *pcbEncoded = 3;
1705 ret = TRUE;
1707 else if (*pcbEncoded < 3)
1709 *pcbEncoded = 3;
1710 SetLastError(ERROR_MORE_DATA);
1711 ret = FALSE;
1713 else
1715 *pcbEncoded = 3;
1716 *pbEncoded++ = ASN_BOOL;
1717 *pbEncoded++ = 1;
1718 *pbEncoded++ = val ? 0xff : 0;
1719 ret = TRUE;
1721 TRACE("returning %d (%08x)\n", ret, GetLastError());
1722 return ret;
1725 static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry,
1726 BYTE *pbEncoded, DWORD *pcbEncoded)
1728 BOOL ret;
1729 DWORD dataLen;
1731 ret = TRUE;
1732 switch (entry->dwAltNameChoice)
1734 case CERT_ALT_NAME_RFC822_NAME:
1735 case CERT_ALT_NAME_DNS_NAME:
1736 case CERT_ALT_NAME_URL:
1737 if (entry->u.pwszURL)
1739 DWORD i;
1741 /* Not + 1: don't encode the NULL-terminator */
1742 dataLen = lstrlenW(entry->u.pwszURL);
1743 for (i = 0; ret && i < dataLen; i++)
1745 if (entry->u.pwszURL[i] > 0x7f)
1747 SetLastError(CRYPT_E_INVALID_IA5_STRING);
1748 ret = FALSE;
1749 *pcbEncoded = i;
1753 else
1754 dataLen = 0;
1755 break;
1756 case CERT_ALT_NAME_IP_ADDRESS:
1757 dataLen = entry->u.IPAddress.cbData;
1758 break;
1759 case CERT_ALT_NAME_REGISTERED_ID:
1760 /* FIXME: encode OID */
1761 case CERT_ALT_NAME_OTHER_NAME:
1762 case CERT_ALT_NAME_DIRECTORY_NAME:
1763 FIXME("name type %d unimplemented\n", entry->dwAltNameChoice);
1764 return FALSE;
1765 default:
1766 SetLastError(E_INVALIDARG);
1767 return FALSE;
1769 if (ret)
1771 DWORD bytesNeeded, lenBytes;
1773 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1774 bytesNeeded = 1 + dataLen + lenBytes;
1775 if (!pbEncoded)
1776 *pcbEncoded = bytesNeeded;
1777 else if (*pcbEncoded < bytesNeeded)
1779 SetLastError(ERROR_MORE_DATA);
1780 *pcbEncoded = bytesNeeded;
1781 ret = FALSE;
1783 else
1785 *pbEncoded++ = ASN_CONTEXT | (entry->dwAltNameChoice - 1);
1786 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1787 pbEncoded += lenBytes;
1788 switch (entry->dwAltNameChoice)
1790 case CERT_ALT_NAME_RFC822_NAME:
1791 case CERT_ALT_NAME_DNS_NAME:
1792 case CERT_ALT_NAME_URL:
1794 DWORD i;
1796 for (i = 0; i < dataLen; i++)
1797 *pbEncoded++ = (BYTE)entry->u.pwszURL[i];
1798 break;
1800 case CERT_ALT_NAME_IP_ADDRESS:
1801 memcpy(pbEncoded, entry->u.IPAddress.pbData, dataLen);
1802 break;
1804 if (ret)
1805 *pcbEncoded = bytesNeeded;
1808 TRACE("returning %d (%08x)\n", ret, GetLastError());
1809 return ret;
1812 static BOOL WINAPI CRYPT_AsnEncodeAuthorityKeyId(DWORD dwCertEncodingType,
1813 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1814 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1816 BOOL ret;
1818 __TRY
1820 const CERT_AUTHORITY_KEY_ID_INFO *info =
1821 (const CERT_AUTHORITY_KEY_ID_INFO *)pvStructInfo;
1822 struct AsnEncodeSequenceItem items[3] = { { 0 } };
1823 struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
1824 struct AsnConstructedItem constructed = { 0 };
1825 DWORD cItem = 0, cSwapped = 0;
1827 if (info->KeyId.cbData)
1829 swapped[cSwapped].tag = ASN_CONTEXT | 0;
1830 swapped[cSwapped].pvStructInfo = &info->KeyId;
1831 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
1832 items[cItem].pvStructInfo = &swapped[cSwapped];
1833 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
1834 cSwapped++;
1835 cItem++;
1837 if (info->CertIssuer.cbData)
1839 constructed.tag = 1;
1840 constructed.pvStructInfo = &info->CertIssuer;
1841 constructed.encodeFunc = CRYPT_CopyEncodedBlob;
1842 items[cItem].pvStructInfo = &constructed;
1843 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
1844 cItem++;
1846 if (info->CertSerialNumber.cbData)
1848 swapped[cSwapped].tag = ASN_CONTEXT | 2;
1849 swapped[cSwapped].pvStructInfo = &info->CertSerialNumber;
1850 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
1851 items[cItem].pvStructInfo = &swapped[cSwapped];
1852 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
1853 cSwapped++;
1854 cItem++;
1856 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, dwFlags,
1857 pEncodePara, pbEncoded, pcbEncoded);
1859 __EXCEPT_PAGE_FAULT
1861 SetLastError(STATUS_ACCESS_VIOLATION);
1862 ret = FALSE;
1864 __ENDTRY
1865 return ret;
1868 static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
1869 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1870 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1872 BOOL ret;
1874 __TRY
1876 const CERT_ALT_NAME_INFO *info =
1877 (const CERT_ALT_NAME_INFO *)pvStructInfo;
1878 DWORD bytesNeeded, dataLen, lenBytes, i;
1880 ret = TRUE;
1881 /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
1882 * can't encode an erroneous entry index if it's bigger than this.
1884 for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
1886 DWORD len;
1888 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i], NULL,
1889 &len);
1890 if (ret)
1891 dataLen += len;
1892 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
1894 /* CRYPT_AsnEncodeAltNameEntry encoded the index of
1895 * the bad character, now set the index of the bad
1896 * entry
1898 *pcbEncoded = (BYTE)i <<
1899 CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT | len;
1902 if (ret)
1904 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1905 bytesNeeded = 1 + lenBytes + dataLen;
1906 if (!pbEncoded)
1908 *pcbEncoded = bytesNeeded;
1909 ret = TRUE;
1911 else
1913 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1914 pbEncoded, pcbEncoded, bytesNeeded)))
1916 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1917 pbEncoded = *(BYTE **)pbEncoded;
1918 *pbEncoded++ = ASN_SEQUENCEOF;
1919 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1920 pbEncoded += lenBytes;
1921 for (i = 0; ret && i < info->cAltEntry; i++)
1923 DWORD len = dataLen;
1925 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i],
1926 pbEncoded, &len);
1927 if (ret)
1929 pbEncoded += len;
1930 dataLen -= len;
1937 __EXCEPT_PAGE_FAULT
1939 SetLastError(STATUS_ACCESS_VIOLATION);
1940 ret = FALSE;
1942 __ENDTRY
1943 return ret;
1946 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints(DWORD dwCertEncodingType,
1947 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1948 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1950 BOOL ret;
1952 __TRY
1954 const CERT_BASIC_CONSTRAINTS_INFO *info =
1955 (const CERT_BASIC_CONSTRAINTS_INFO *)pvStructInfo;
1956 struct AsnEncodeSequenceItem items[3] = {
1957 { &info->SubjectType, CRYPT_AsnEncodeBits, 0 },
1958 { 0 }
1960 DWORD cItem = 1;
1962 if (info->fPathLenConstraint)
1964 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1965 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1966 cItem++;
1968 if (info->cSubtreesConstraint)
1970 items[cItem].pvStructInfo = &info->cSubtreesConstraint;
1971 items[cItem].encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
1972 cItem++;
1974 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1975 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1977 __EXCEPT_PAGE_FAULT
1979 SetLastError(STATUS_ACCESS_VIOLATION);
1980 ret = FALSE;
1982 __ENDTRY
1983 return ret;
1986 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
1987 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1988 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1990 BOOL ret;
1992 __TRY
1994 const CERT_BASIC_CONSTRAINTS2_INFO *info =
1995 (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
1996 struct AsnEncodeSequenceItem items[2] = { { 0 } };
1997 DWORD cItem = 0;
1999 if (info->fCA)
2001 items[cItem].pvStructInfo = &info->fCA;
2002 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
2003 cItem++;
2005 if (info->fPathLenConstraint)
2007 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
2008 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
2009 cItem++;
2011 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
2012 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2014 __EXCEPT_PAGE_FAULT
2016 SetLastError(STATUS_ACCESS_VIOLATION);
2017 ret = FALSE;
2019 __ENDTRY
2020 return ret;
2023 static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
2024 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2025 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2027 BOOL ret;
2029 __TRY
2031 const BLOBHEADER *hdr =
2032 (const BLOBHEADER *)pvStructInfo;
2034 if (hdr->bType != PUBLICKEYBLOB)
2036 SetLastError(E_INVALIDARG);
2037 ret = FALSE;
2039 else
2041 const RSAPUBKEY *rsaPubKey = (const RSAPUBKEY *)
2042 ((const BYTE *)pvStructInfo + sizeof(BLOBHEADER));
2043 CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8,
2044 (BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) };
2045 struct AsnEncodeSequenceItem items[] = {
2046 { &blob, CRYPT_AsnEncodeUnsignedInteger, 0 },
2047 { &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 },
2050 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
2051 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
2052 pcbEncoded);
2055 __EXCEPT_PAGE_FAULT
2057 SetLastError(STATUS_ACCESS_VIOLATION);
2058 ret = FALSE;
2060 __ENDTRY
2061 return ret;
2064 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
2065 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2066 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2068 BOOL ret;
2070 __TRY
2072 const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
2073 DWORD bytesNeeded, lenBytes;
2075 TRACE("(%d, %p), %08x, %p, %p, %d\n", blob->cbData, blob->pbData,
2076 dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
2078 CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
2079 bytesNeeded = 1 + lenBytes + blob->cbData;
2080 if (!pbEncoded)
2082 *pcbEncoded = bytesNeeded;
2083 ret = TRUE;
2085 else
2087 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2088 pcbEncoded, bytesNeeded)))
2090 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2091 pbEncoded = *(BYTE **)pbEncoded;
2092 *pbEncoded++ = ASN_OCTETSTRING;
2093 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
2094 pbEncoded += lenBytes;
2095 if (blob->cbData)
2096 memcpy(pbEncoded, blob->pbData, blob->cbData);
2100 __EXCEPT_PAGE_FAULT
2102 SetLastError(STATUS_ACCESS_VIOLATION);
2103 ret = FALSE;
2105 __ENDTRY
2106 TRACE("returning %d (%08x)\n", ret, GetLastError());
2107 return ret;
2110 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
2111 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2112 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2114 BOOL ret;
2116 __TRY
2118 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
2119 DWORD bytesNeeded, lenBytes, dataBytes;
2120 BYTE unusedBits;
2122 /* yep, MS allows cUnusedBits to be >= 8 */
2123 if (!blob->cUnusedBits)
2125 dataBytes = blob->cbData;
2126 unusedBits = 0;
2128 else if (blob->cbData * 8 > blob->cUnusedBits)
2130 dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
2131 unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
2132 blob->cUnusedBits;
2134 else
2136 dataBytes = 0;
2137 unusedBits = 0;
2139 CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
2140 bytesNeeded = 1 + lenBytes + dataBytes + 1;
2141 if (!pbEncoded)
2143 *pcbEncoded = bytesNeeded;
2144 ret = TRUE;
2146 else
2148 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2149 pcbEncoded, bytesNeeded)))
2151 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2152 pbEncoded = *(BYTE **)pbEncoded;
2153 *pbEncoded++ = ASN_BITSTRING;
2154 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
2155 pbEncoded += lenBytes;
2156 *pbEncoded++ = unusedBits;
2157 if (dataBytes)
2159 BYTE mask = 0xff << unusedBits;
2161 if (dataBytes > 1)
2163 memcpy(pbEncoded, blob->pbData, dataBytes - 1);
2164 pbEncoded += dataBytes - 1;
2166 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
2171 __EXCEPT_PAGE_FAULT
2173 SetLastError(STATUS_ACCESS_VIOLATION);
2174 ret = FALSE;
2176 __ENDTRY
2177 return ret;
2180 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
2181 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2182 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2184 BOOL ret;
2186 __TRY
2188 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
2189 CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
2191 ret = TRUE;
2192 if (newBlob.cbData)
2194 newBlob.pbData = CryptMemAlloc(newBlob.cbData);
2195 if (newBlob.pbData)
2197 DWORD i;
2199 for (i = 0; i < newBlob.cbData; i++)
2200 newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
2202 else
2203 ret = FALSE;
2205 if (ret)
2206 ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
2207 &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2208 CryptMemFree(newBlob.pbData);
2210 __EXCEPT_PAGE_FAULT
2212 SetLastError(STATUS_ACCESS_VIOLATION);
2213 ret = FALSE;
2215 __ENDTRY
2216 return ret;
2219 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
2220 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2221 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2223 CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
2225 return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
2226 &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2229 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
2230 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2231 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2233 BOOL ret;
2235 __TRY
2237 DWORD significantBytes, lenBytes;
2238 BYTE padByte = 0, bytesNeeded;
2239 BOOL pad = FALSE;
2240 const CRYPT_INTEGER_BLOB *blob =
2241 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
2243 significantBytes = blob->cbData;
2244 if (significantBytes)
2246 if (blob->pbData[significantBytes - 1] & 0x80)
2248 /* negative, lop off leading (little-endian) 0xffs */
2249 for (; significantBytes > 0 &&
2250 blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
2252 if (blob->pbData[significantBytes - 1] < 0x80)
2254 padByte = 0xff;
2255 pad = TRUE;
2258 else
2260 /* positive, lop off leading (little-endian) zeroes */
2261 for (; significantBytes > 0 &&
2262 !blob->pbData[significantBytes - 1]; significantBytes--)
2264 if (significantBytes == 0)
2265 significantBytes = 1;
2266 if (blob->pbData[significantBytes - 1] > 0x7f)
2268 padByte = 0;
2269 pad = TRUE;
2273 if (pad)
2274 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2275 else
2276 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2277 bytesNeeded = 1 + lenBytes + significantBytes;
2278 if (pad)
2279 bytesNeeded++;
2280 if (!pbEncoded)
2282 *pcbEncoded = bytesNeeded;
2283 ret = TRUE;
2285 else
2287 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2288 pcbEncoded, bytesNeeded)))
2290 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2291 pbEncoded = *(BYTE **)pbEncoded;
2292 *pbEncoded++ = ASN_INTEGER;
2293 if (pad)
2295 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2296 pbEncoded += lenBytes;
2297 *pbEncoded++ = padByte;
2299 else
2301 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2302 pbEncoded += lenBytes;
2304 for (; significantBytes > 0; significantBytes--)
2305 *(pbEncoded++) = blob->pbData[significantBytes - 1];
2309 __EXCEPT_PAGE_FAULT
2311 SetLastError(STATUS_ACCESS_VIOLATION);
2312 ret = FALSE;
2314 __ENDTRY
2315 return ret;
2318 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
2319 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2320 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2322 BOOL ret;
2324 __TRY
2326 DWORD significantBytes, lenBytes;
2327 BYTE bytesNeeded;
2328 BOOL pad = FALSE;
2329 const CRYPT_INTEGER_BLOB *blob =
2330 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
2332 significantBytes = blob->cbData;
2333 if (significantBytes)
2335 /* positive, lop off leading (little-endian) zeroes */
2336 for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
2337 significantBytes--)
2339 if (significantBytes == 0)
2340 significantBytes = 1;
2341 if (blob->pbData[significantBytes - 1] > 0x7f)
2342 pad = TRUE;
2344 if (pad)
2345 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2346 else
2347 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2348 bytesNeeded = 1 + lenBytes + significantBytes;
2349 if (pad)
2350 bytesNeeded++;
2351 if (!pbEncoded)
2353 *pcbEncoded = bytesNeeded;
2354 ret = TRUE;
2356 else
2358 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2359 pcbEncoded, bytesNeeded)))
2361 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2362 pbEncoded = *(BYTE **)pbEncoded;
2363 *pbEncoded++ = ASN_INTEGER;
2364 if (pad)
2366 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2367 pbEncoded += lenBytes;
2368 *pbEncoded++ = 0;
2370 else
2372 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2373 pbEncoded += lenBytes;
2375 for (; significantBytes > 0; significantBytes--)
2376 *(pbEncoded++) = blob->pbData[significantBytes - 1];
2380 __EXCEPT_PAGE_FAULT
2382 SetLastError(STATUS_ACCESS_VIOLATION);
2383 ret = FALSE;
2385 __ENDTRY
2386 return ret;
2389 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
2390 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2391 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2393 CRYPT_INTEGER_BLOB blob;
2394 BOOL ret;
2396 /* Encode as an unsigned integer, then change the tag to enumerated */
2397 blob.cbData = sizeof(DWORD);
2398 blob.pbData = (BYTE *)pvStructInfo;
2399 ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
2400 X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2401 if (ret && pbEncoded)
2403 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2404 pbEncoded = *(BYTE **)pbEncoded;
2405 pbEncoded[0] = ASN_ENUMERATED;
2407 return ret;
2410 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
2411 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2412 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2414 BOOL ret;
2416 __TRY
2418 SYSTEMTIME sysTime;
2419 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
2420 * temporary buffer because the output buffer is not NULL-terminated.
2422 char buf[16];
2423 static const DWORD bytesNeeded = sizeof(buf) - 1;
2425 if (!pbEncoded)
2427 *pcbEncoded = bytesNeeded;
2428 ret = TRUE;
2430 else
2432 /* Sanity check the year, this is a two-digit year format */
2433 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2434 &sysTime);
2435 if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
2437 SetLastError(CRYPT_E_BAD_ENCODE);
2438 ret = FALSE;
2440 if (ret)
2442 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2443 pbEncoded, pcbEncoded, bytesNeeded)))
2445 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2446 pbEncoded = *(BYTE **)pbEncoded;
2447 buf[0] = ASN_UTCTIME;
2448 buf[1] = bytesNeeded - 2;
2449 snprintf(buf + 2, sizeof(buf) - 2,
2450 "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
2451 sysTime.wYear - 2000 : sysTime.wYear - 1900,
2452 sysTime.wMonth, sysTime.wDay, sysTime.wHour,
2453 sysTime.wMinute, sysTime.wSecond);
2454 memcpy(pbEncoded, buf, bytesNeeded);
2459 __EXCEPT_PAGE_FAULT
2461 SetLastError(STATUS_ACCESS_VIOLATION);
2462 ret = FALSE;
2464 __ENDTRY
2465 return ret;
2468 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
2469 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2470 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2472 BOOL ret;
2474 __TRY
2476 SYSTEMTIME sysTime;
2477 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
2478 * temporary buffer because the output buffer is not NULL-terminated.
2480 char buf[18];
2481 static const DWORD bytesNeeded = sizeof(buf) - 1;
2483 if (!pbEncoded)
2485 *pcbEncoded = bytesNeeded;
2486 ret = TRUE;
2488 else
2490 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2491 &sysTime);
2492 if (ret)
2493 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2494 pcbEncoded, bytesNeeded);
2495 if (ret)
2497 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2498 pbEncoded = *(BYTE **)pbEncoded;
2499 buf[0] = ASN_GENERALTIME;
2500 buf[1] = bytesNeeded - 2;
2501 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
2502 sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour,
2503 sysTime.wMinute, sysTime.wSecond);
2504 memcpy(pbEncoded, buf, bytesNeeded);
2508 __EXCEPT_PAGE_FAULT
2510 SetLastError(STATUS_ACCESS_VIOLATION);
2511 ret = FALSE;
2513 __ENDTRY
2514 return ret;
2517 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
2518 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2519 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2521 BOOL ret;
2523 __TRY
2525 SYSTEMTIME sysTime;
2527 /* Check the year, if it's in the UTCTime range call that encode func */
2528 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
2529 return FALSE;
2530 if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
2531 ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
2532 pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2533 else
2534 ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
2535 lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
2536 pcbEncoded);
2538 __EXCEPT_PAGE_FAULT
2540 SetLastError(STATUS_ACCESS_VIOLATION);
2541 ret = FALSE;
2543 __ENDTRY
2544 return ret;
2547 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
2548 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2549 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2551 BOOL ret;
2553 __TRY
2555 DWORD bytesNeeded, dataLen, lenBytes, i;
2556 const CRYPT_SEQUENCE_OF_ANY *seq =
2557 (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
2559 for (i = 0, dataLen = 0; i < seq->cValue; i++)
2560 dataLen += seq->rgValue[i].cbData;
2561 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2562 bytesNeeded = 1 + lenBytes + dataLen;
2563 if (!pbEncoded)
2565 *pcbEncoded = bytesNeeded;
2566 ret = TRUE;
2568 else
2570 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2571 pcbEncoded, bytesNeeded)))
2573 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2574 pbEncoded = *(BYTE **)pbEncoded;
2575 *pbEncoded++ = ASN_SEQUENCEOF;
2576 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2577 pbEncoded += lenBytes;
2578 for (i = 0; i < seq->cValue; i++)
2580 memcpy(pbEncoded, seq->rgValue[i].pbData,
2581 seq->rgValue[i].cbData);
2582 pbEncoded += seq->rgValue[i].cbData;
2587 __EXCEPT_PAGE_FAULT
2589 SetLastError(STATUS_ACCESS_VIOLATION);
2590 ret = FALSE;
2592 __ENDTRY
2593 return ret;
2596 static BOOL CRYPT_AsnEncodeDistPoint(const CRL_DIST_POINT *distPoint,
2597 BYTE *pbEncoded, DWORD *pcbEncoded)
2599 BOOL ret = TRUE;
2600 struct AsnEncodeSequenceItem items[3] = { { 0 } };
2601 struct AsnConstructedItem constructed = { 0 };
2602 struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2603 DWORD cItem = 0, cSwapped = 0;
2605 switch (distPoint->DistPointName.dwDistPointNameChoice)
2607 case CRL_DIST_POINT_NO_NAME:
2608 /* do nothing */
2609 break;
2610 case CRL_DIST_POINT_FULL_NAME:
2611 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
2612 swapped[cSwapped].pvStructInfo = &distPoint->DistPointName.u.FullName;
2613 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2614 constructed.tag = 0;
2615 constructed.pvStructInfo = &swapped[cSwapped];
2616 constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
2617 items[cItem].pvStructInfo = &constructed;
2618 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2619 cSwapped++;
2620 cItem++;
2621 break;
2622 case CRL_DIST_POINT_ISSUER_RDN_NAME:
2623 FIXME("unimplemented for CRL_DIST_POINT_ISSUER_RDN_NAME\n");
2624 ret = FALSE;
2625 break;
2626 default:
2627 ret = FALSE;
2629 if (ret && distPoint->ReasonFlags.cbData)
2631 swapped[cSwapped].tag = ASN_CONTEXT | 1;
2632 swapped[cSwapped].pvStructInfo = &distPoint->ReasonFlags;
2633 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
2634 items[cItem].pvStructInfo = &swapped[cSwapped];
2635 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2636 cSwapped++;
2637 cItem++;
2639 if (ret && distPoint->CRLIssuer.cAltEntry)
2641 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 2;
2642 swapped[cSwapped].pvStructInfo = &distPoint->CRLIssuer;
2643 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2644 items[cItem].pvStructInfo = &swapped[cSwapped];
2645 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2646 cSwapped++;
2647 cItem++;
2649 if (ret)
2650 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
2651 pbEncoded, pcbEncoded);
2652 return ret;
2655 static BOOL WINAPI CRYPT_AsnEncodeCRLDistPoints(DWORD dwCertEncodingType,
2656 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2657 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2659 BOOL ret;
2661 __TRY
2663 const CRL_DIST_POINTS_INFO *info =
2664 (const CRL_DIST_POINTS_INFO *)pvStructInfo;
2666 if (!info->cDistPoint)
2668 SetLastError(E_INVALIDARG);
2669 ret = FALSE;
2671 else
2673 DWORD bytesNeeded, dataLen, lenBytes, i;
2675 ret = TRUE;
2676 for (i = 0, dataLen = 0; ret && i < info->cDistPoint; i++)
2678 DWORD len;
2680 ret = CRYPT_AsnEncodeDistPoint(&info->rgDistPoint[i], NULL,
2681 &len);
2682 if (ret)
2683 dataLen += len;
2684 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
2686 /* Have to propagate index of failing character */
2687 *pcbEncoded = len;
2690 if (ret)
2692 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2693 bytesNeeded = 1 + lenBytes + dataLen;
2694 if (!pbEncoded)
2696 *pcbEncoded = bytesNeeded;
2697 ret = TRUE;
2699 else
2701 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2702 pbEncoded, pcbEncoded, bytesNeeded)))
2704 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2705 pbEncoded = *(BYTE **)pbEncoded;
2706 *pbEncoded++ = ASN_SEQUENCEOF;
2707 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2708 pbEncoded += lenBytes;
2709 for (i = 0; ret && i < info->cDistPoint; i++)
2711 DWORD len = dataLen;
2713 ret = CRYPT_AsnEncodeDistPoint(
2714 &info->rgDistPoint[i], pbEncoded, &len);
2715 if (ret)
2717 pbEncoded += len;
2718 dataLen -= len;
2726 __EXCEPT_PAGE_FAULT
2728 SetLastError(STATUS_ACCESS_VIOLATION);
2729 ret = FALSE;
2731 __ENDTRY
2732 return ret;
2735 static BOOL WINAPI CRYPT_AsnEncodeEnhancedKeyUsage(DWORD dwCertEncodingType,
2736 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2737 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2739 BOOL ret;
2741 __TRY
2743 const CERT_ENHKEY_USAGE *usage =
2744 (const CERT_ENHKEY_USAGE *)pvStructInfo;
2745 DWORD bytesNeeded = 0, lenBytes, size, i;
2747 ret = TRUE;
2748 for (i = 0; ret && i < usage->cUsageIdentifier; i++)
2750 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
2751 usage->rgpszUsageIdentifier[i],
2752 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &size);
2753 if (ret)
2754 bytesNeeded += size;
2756 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
2757 bytesNeeded += 1 + lenBytes;
2758 if (ret)
2760 if (!pbEncoded)
2761 *pcbEncoded = bytesNeeded;
2762 else
2764 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2765 pbEncoded, pcbEncoded, bytesNeeded)))
2767 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2768 pbEncoded = *(BYTE **)pbEncoded;
2769 *pbEncoded++ = ASN_SEQUENCEOF;
2770 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
2771 &lenBytes);
2772 pbEncoded += lenBytes;
2773 for (i = 0; ret && i < usage->cUsageIdentifier; i++)
2775 size = bytesNeeded;
2776 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
2777 usage->rgpszUsageIdentifier[i],
2778 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pbEncoded,
2779 &size);
2780 if (ret)
2782 pbEncoded += size;
2783 bytesNeeded -= size;
2790 __EXCEPT_PAGE_FAULT
2792 SetLastError(STATUS_ACCESS_VIOLATION);
2793 ret = FALSE;
2795 __ENDTRY
2796 return ret;
2799 static BOOL WINAPI CRYPT_AsnEncodeIssuingDistPoint(DWORD dwCertEncodingType,
2800 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2801 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2803 BOOL ret;
2805 __TRY
2807 const CRL_ISSUING_DIST_POINT *point =
2808 (const CRL_ISSUING_DIST_POINT *)pvStructInfo;
2809 struct AsnEncodeSequenceItem items[6] = { { 0 } };
2810 struct AsnConstructedItem constructed = { 0 };
2811 struct AsnEncodeTagSwappedItem swapped[5] = { { 0 } };
2812 DWORD cItem = 0, cSwapped = 0;
2814 ret = TRUE;
2815 switch (point->DistPointName.dwDistPointNameChoice)
2817 case CRL_DIST_POINT_NO_NAME:
2818 /* do nothing */
2819 break;
2820 case CRL_DIST_POINT_FULL_NAME:
2821 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
2822 swapped[cSwapped].pvStructInfo = &point->DistPointName.u.FullName;
2823 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2824 constructed.tag = 0;
2825 constructed.pvStructInfo = &swapped[cSwapped];
2826 constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
2827 items[cItem].pvStructInfo = &constructed;
2828 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2829 cSwapped++;
2830 cItem++;
2831 break;
2832 default:
2833 SetLastError(E_INVALIDARG);
2834 ret = FALSE;
2836 if (ret && point->fOnlyContainsUserCerts)
2838 swapped[cSwapped].tag = ASN_CONTEXT | 1;
2839 swapped[cSwapped].pvStructInfo = &point->fOnlyContainsUserCerts;
2840 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
2841 items[cItem].pvStructInfo = &swapped[cSwapped];
2842 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2843 cSwapped++;
2844 cItem++;
2846 if (ret && point->fOnlyContainsCACerts)
2848 swapped[cSwapped].tag = ASN_CONTEXT | 2;
2849 swapped[cSwapped].pvStructInfo = &point->fOnlyContainsCACerts;
2850 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
2851 items[cItem].pvStructInfo = &swapped[cSwapped];
2852 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2853 cSwapped++;
2854 cItem++;
2856 if (ret && point->OnlySomeReasonFlags.cbData)
2858 swapped[cSwapped].tag = ASN_CONTEXT | 3;
2859 swapped[cSwapped].pvStructInfo = &point->OnlySomeReasonFlags;
2860 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
2861 items[cItem].pvStructInfo = &swapped[cSwapped];
2862 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2863 cSwapped++;
2864 cItem++;
2866 if (ret && point->fIndirectCRL)
2868 swapped[cSwapped].tag = ASN_CONTEXT | 4;
2869 swapped[cSwapped].pvStructInfo = &point->fIndirectCRL;
2870 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
2871 items[cItem].pvStructInfo = &swapped[cSwapped];
2872 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2873 cSwapped++;
2874 cItem++;
2876 if (ret)
2877 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
2878 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2880 __EXCEPT_PAGE_FAULT
2882 SetLastError(STATUS_ACCESS_VIOLATION);
2883 ret = FALSE;
2885 __ENDTRY
2886 return ret;
2889 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2890 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
2891 void *pvEncoded, DWORD *pcbEncoded)
2893 static HCRYPTOIDFUNCSET set = NULL;
2894 BOOL ret = FALSE;
2895 CryptEncodeObjectExFunc encodeFunc = NULL;
2896 HCRYPTOIDFUNCADDR hFunc = NULL;
2898 TRACE("(0x%08x, %s, %p, 0x%08x, %p, %p, %p)\n", dwCertEncodingType,
2899 debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
2900 pvEncoded, pcbEncoded);
2902 if (!pvEncoded && !pcbEncoded)
2904 SetLastError(ERROR_INVALID_PARAMETER);
2905 return FALSE;
2907 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
2908 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
2910 SetLastError(ERROR_FILE_NOT_FOUND);
2911 return FALSE;
2914 SetLastError(NOERROR);
2915 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
2916 *(BYTE **)pvEncoded = NULL;
2917 if (!HIWORD(lpszStructType))
2919 switch (LOWORD(lpszStructType))
2921 case (WORD)X509_CERT:
2922 encodeFunc = CRYPT_AsnEncodeCert;
2923 break;
2924 case (WORD)X509_CERT_TO_BE_SIGNED:
2925 encodeFunc = CRYPT_AsnEncodeCertInfo;
2926 break;
2927 case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
2928 encodeFunc = CRYPT_AsnEncodeCRLInfo;
2929 break;
2930 case (WORD)X509_EXTENSIONS:
2931 encodeFunc = CRYPT_AsnEncodeExtensions;
2932 break;
2933 case (WORD)X509_NAME_VALUE:
2934 encodeFunc = CRYPT_AsnEncodeNameValue;
2935 break;
2936 case (WORD)X509_NAME:
2937 encodeFunc = CRYPT_AsnEncodeName;
2938 break;
2939 case (WORD)X509_PUBLIC_KEY_INFO:
2940 encodeFunc = CRYPT_AsnEncodePubKeyInfo;
2941 break;
2942 case (WORD)X509_AUTHORITY_KEY_ID:
2943 encodeFunc = CRYPT_AsnEncodeAuthorityKeyId;
2944 break;
2945 case (WORD)X509_ALTERNATE_NAME:
2946 encodeFunc = CRYPT_AsnEncodeAltName;
2947 break;
2948 case (WORD)X509_BASIC_CONSTRAINTS:
2949 encodeFunc = CRYPT_AsnEncodeBasicConstraints;
2950 break;
2951 case (WORD)X509_BASIC_CONSTRAINTS2:
2952 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2953 break;
2954 case (WORD)RSA_CSP_PUBLICKEYBLOB:
2955 encodeFunc = CRYPT_AsnEncodeRsaPubKey;
2956 break;
2957 case (WORD)X509_UNICODE_NAME:
2958 encodeFunc = CRYPT_AsnEncodeUnicodeName;
2959 break;
2960 case (WORD)X509_UNICODE_NAME_VALUE:
2961 encodeFunc = CRYPT_AsnEncodeUnicodeNameValue;
2962 break;
2963 case (WORD)X509_OCTET_STRING:
2964 encodeFunc = CRYPT_AsnEncodeOctets;
2965 break;
2966 case (WORD)X509_BITS:
2967 case (WORD)X509_KEY_USAGE:
2968 encodeFunc = CRYPT_AsnEncodeBits;
2969 break;
2970 case (WORD)X509_INTEGER:
2971 encodeFunc = CRYPT_AsnEncodeInt;
2972 break;
2973 case (WORD)X509_MULTI_BYTE_INTEGER:
2974 encodeFunc = CRYPT_AsnEncodeInteger;
2975 break;
2976 case (WORD)X509_MULTI_BYTE_UINT:
2977 encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
2978 break;
2979 case (WORD)X509_ENUMERATED:
2980 encodeFunc = CRYPT_AsnEncodeEnumerated;
2981 break;
2982 case (WORD)X509_CHOICE_OF_TIME:
2983 encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
2984 break;
2985 case (WORD)X509_SEQUENCE_OF_ANY:
2986 encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
2987 break;
2988 case (WORD)PKCS_UTC_TIME:
2989 encodeFunc = CRYPT_AsnEncodeUtcTime;
2990 break;
2991 case (WORD)X509_CRL_DIST_POINTS:
2992 encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
2993 break;
2994 case (WORD)X509_ENHANCED_KEY_USAGE:
2995 encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
2996 break;
2997 case (WORD)X509_ISSUING_DIST_POINT:
2998 encodeFunc = CRYPT_AsnEncodeIssuingDistPoint;
2999 break;
3000 default:
3001 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
3004 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
3005 encodeFunc = CRYPT_AsnEncodeExtensions;
3006 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
3007 encodeFunc = CRYPT_AsnEncodeUtcTime;
3008 else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER))
3009 encodeFunc = CRYPT_AsnEncodeAuthorityKeyId;
3010 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
3011 encodeFunc = CRYPT_AsnEncodeEnumerated;
3012 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
3013 encodeFunc = CRYPT_AsnEncodeBits;
3014 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
3015 encodeFunc = CRYPT_AsnEncodeOctets;
3016 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS))
3017 encodeFunc = CRYPT_AsnEncodeBasicConstraints;
3018 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
3019 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
3020 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
3021 encodeFunc = CRYPT_AsnEncodeAltName;
3022 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
3023 encodeFunc = CRYPT_AsnEncodeAltName;
3024 else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
3025 encodeFunc = CRYPT_AsnEncodeAltName;
3026 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
3027 encodeFunc = CRYPT_AsnEncodeAltName;
3028 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
3029 encodeFunc = CRYPT_AsnEncodeAltName;
3030 else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
3031 encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
3032 else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
3033 encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
3034 else if (!strcmp(lpszStructType, szOID_ISSUING_DIST_POINT))
3035 encodeFunc = CRYPT_AsnEncodeIssuingDistPoint;
3036 else
3037 TRACE("OID %s not found or unimplemented, looking for DLL\n",
3038 debugstr_a(lpszStructType));
3039 if (!encodeFunc)
3041 if (!set)
3042 set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_EX_FUNC, 0);
3043 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
3044 (void **)&encodeFunc, &hFunc);
3046 if (encodeFunc)
3047 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
3048 dwFlags, pEncodePara, pvEncoded, pcbEncoded);
3049 else
3050 SetLastError(ERROR_FILE_NOT_FOUND);
3051 if (hFunc)
3052 CryptFreeOIDFunctionAddress(hFunc, 0);
3053 return ret;
3056 BOOL WINAPI CryptExportPublicKeyInfo(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
3057 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3059 return CryptExportPublicKeyInfoEx(hCryptProv, dwKeySpec, dwCertEncodingType,
3060 NULL, 0, NULL, pInfo, pcbInfo);
3063 static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3064 DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
3065 DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3067 BOOL ret;
3068 HCRYPTKEY key;
3069 static CHAR oid[] = szOID_RSA_RSA;
3071 TRACE("(%08lx, %d, %08x, %s, %08x, %p, %p, %p)\n", hCryptProv, dwKeySpec,
3072 dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
3073 pInfo, pcbInfo);
3075 if (!pszPublicKeyObjId)
3076 pszPublicKeyObjId = oid;
3077 if ((ret = CryptGetUserKey(hCryptProv, dwKeySpec, &key)))
3079 DWORD keySize = 0;
3081 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &keySize);
3082 if (ret)
3084 LPBYTE pubKey = CryptMemAlloc(keySize);
3086 if (pubKey)
3088 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, pubKey,
3089 &keySize);
3090 if (ret)
3092 DWORD encodedLen = 0;
3094 ret = CryptEncodeObject(dwCertEncodingType,
3095 RSA_CSP_PUBLICKEYBLOB, pubKey, NULL, &encodedLen);
3096 if (ret)
3098 DWORD sizeNeeded = sizeof(CERT_PUBLIC_KEY_INFO) +
3099 strlen(pszPublicKeyObjId) + 1 + encodedLen;
3101 if (!pInfo)
3102 *pcbInfo = sizeNeeded;
3103 else if (*pcbInfo < sizeNeeded)
3105 SetLastError(ERROR_MORE_DATA);
3106 *pcbInfo = sizeNeeded;
3107 ret = FALSE;
3109 else
3111 pInfo->Algorithm.pszObjId = (char *)pInfo +
3112 sizeof(CERT_PUBLIC_KEY_INFO);
3113 lstrcpyA(pInfo->Algorithm.pszObjId,
3114 pszPublicKeyObjId);
3115 pInfo->Algorithm.Parameters.cbData = 0;
3116 pInfo->Algorithm.Parameters.pbData = NULL;
3117 pInfo->PublicKey.pbData =
3118 (BYTE *)pInfo->Algorithm.pszObjId
3119 + lstrlenA(pInfo->Algorithm.pszObjId) + 1;
3120 pInfo->PublicKey.cbData = encodedLen;
3121 pInfo->PublicKey.cUnusedBits = 0;
3122 ret = CryptEncodeObject(dwCertEncodingType,
3123 RSA_CSP_PUBLICKEYBLOB, pubKey,
3124 pInfo->PublicKey.pbData, &pInfo->PublicKey.cbData);
3128 CryptMemFree(pubKey);
3130 else
3131 ret = FALSE;
3133 CryptDestroyKey(key);
3135 return ret;
3138 typedef BOOL (WINAPI *ExportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
3139 DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
3140 DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo);
3142 BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
3143 DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId, DWORD dwFlags,
3144 void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3146 static HCRYPTOIDFUNCSET set = NULL;
3147 BOOL ret;
3148 ExportPublicKeyInfoExFunc exportFunc = NULL;
3149 HCRYPTOIDFUNCADDR hFunc = NULL;
3151 TRACE("(%08lx, %d, %08x, %s, %08x, %p, %p, %p)\n", hCryptProv, dwKeySpec,
3152 dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
3153 pInfo, pcbInfo);
3155 if (!hCryptProv)
3157 SetLastError(ERROR_INVALID_PARAMETER);
3158 return FALSE;
3161 if (pszPublicKeyObjId)
3163 if (!set)
3164 set = CryptInitOIDFunctionSet(CRYPT_OID_EXPORT_PUBLIC_KEY_INFO_FUNC,
3166 CryptGetOIDFunctionAddress(set, dwCertEncodingType, pszPublicKeyObjId,
3167 0, (void **)&exportFunc, &hFunc);
3169 if (!exportFunc)
3170 exportFunc = CRYPT_ExportRsaPublicKeyInfoEx;
3171 ret = exportFunc(hCryptProv, dwKeySpec, dwCertEncodingType,
3172 pszPublicKeyObjId, dwFlags, pvAuxInfo, pInfo, pcbInfo);
3173 if (hFunc)
3174 CryptFreeOIDFunctionAddress(hFunc, 0);
3175 return ret;
3178 BOOL WINAPI CryptImportPublicKeyInfo(HCRYPTPROV hCryptProv,
3179 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
3181 return CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType, pInfo,
3182 0, 0, NULL, phKey);
3185 static BOOL WINAPI CRYPT_ImportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3186 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3187 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
3189 BOOL ret;
3190 DWORD pubKeySize = 0;
3192 TRACE("(%08lx, %d, %p, %d, %08x, %p, %p)\n", hCryptProv,
3193 dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
3195 ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
3196 pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, NULL, &pubKeySize);
3197 if (ret)
3199 LPBYTE pubKey = CryptMemAlloc(pubKeySize);
3201 if (pubKey)
3203 ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
3204 pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, pubKey,
3205 &pubKeySize);
3206 if (ret)
3207 ret = CryptImportKey(hCryptProv, pubKey, pubKeySize, 0, 0,
3208 phKey);
3209 CryptMemFree(pubKey);
3211 else
3212 ret = FALSE;
3214 return ret;
3217 typedef BOOL (WINAPI *ImportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
3218 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3219 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey);
3221 BOOL WINAPI CryptImportPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3222 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3223 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
3225 static HCRYPTOIDFUNCSET set = NULL;
3226 BOOL ret;
3227 ImportPublicKeyInfoExFunc importFunc = NULL;
3228 HCRYPTOIDFUNCADDR hFunc = NULL;
3230 TRACE("(%08lx, %d, %p, %d, %08x, %p, %p)\n", hCryptProv,
3231 dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
3233 if (!set)
3234 set = CryptInitOIDFunctionSet(CRYPT_OID_IMPORT_PUBLIC_KEY_INFO_FUNC, 0);
3235 CryptGetOIDFunctionAddress(set, dwCertEncodingType,
3236 pInfo->Algorithm.pszObjId, 0, (void **)&importFunc, &hFunc);
3237 if (!importFunc)
3238 importFunc = CRYPT_ImportRsaPublicKeyInfoEx;
3239 ret = importFunc(hCryptProv, dwCertEncodingType, pInfo, aiKeyAlg, dwFlags,
3240 pvAuxInfo, phKey);
3241 if (hFunc)
3242 CryptFreeOIDFunctionAddress(hFunc, 0);
3243 return ret;