wine.inf: We should not override existing associations.
[wine/hacks.git] / dlls / crypt32 / encode.c
blob9d9aca4ce82c5db779e99ce618c214dcec4f5397
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%08lx, %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, %ld, %08lx, %p, %p, %ld\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 (%08lx)\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 (%08lx)\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, %ld\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 (%08lx)\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 = (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 CRYPT_DER_BLOB *a = (CRYPT_DER_BLOB *)l, *b = (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 %ld 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 = (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 %ld 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 (%08lx)\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 %ld 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 (%08lx)\n", ret, GetLastError());
1809 return ret;
1812 static BOOL WINAPI CRYPT_AsnEncodeAltName(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_ALT_NAME_INFO *info =
1821 (const CERT_ALT_NAME_INFO *)pvStructInfo;
1822 DWORD bytesNeeded, dataLen, lenBytes, i;
1824 ret = TRUE;
1825 /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
1826 * can't encode an erroneous entry index if it's bigger than this.
1828 for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
1830 DWORD len;
1832 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i], NULL,
1833 &len);
1834 if (ret)
1835 dataLen += len;
1836 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
1838 /* CRYPT_AsnEncodeAltNameEntry encoded the index of
1839 * the bad character, now set the index of the bad
1840 * entry
1842 *pcbEncoded = (BYTE)i <<
1843 CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT | len;
1846 if (ret)
1848 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1849 bytesNeeded = 1 + lenBytes + dataLen;
1850 if (!pbEncoded)
1852 *pcbEncoded = bytesNeeded;
1853 ret = TRUE;
1855 else
1857 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1858 pbEncoded, pcbEncoded, bytesNeeded)))
1860 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1861 pbEncoded = *(BYTE **)pbEncoded;
1862 *pbEncoded++ = ASN_SEQUENCEOF;
1863 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1864 pbEncoded += lenBytes;
1865 for (i = 0; ret && i < info->cAltEntry; i++)
1867 DWORD len = dataLen;
1869 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i],
1870 pbEncoded, &len);
1871 if (ret)
1873 pbEncoded += len;
1874 dataLen -= len;
1881 __EXCEPT_PAGE_FAULT
1883 SetLastError(STATUS_ACCESS_VIOLATION);
1884 ret = FALSE;
1886 __ENDTRY
1887 return ret;
1890 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints(DWORD dwCertEncodingType,
1891 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1892 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1894 BOOL ret;
1896 __TRY
1898 const CERT_BASIC_CONSTRAINTS_INFO *info =
1899 (const CERT_BASIC_CONSTRAINTS_INFO *)pvStructInfo;
1900 struct AsnEncodeSequenceItem items[3] = {
1901 { &info->SubjectType, CRYPT_AsnEncodeBits, 0 },
1902 { 0 }
1904 DWORD cItem = 1;
1906 if (info->fPathLenConstraint)
1908 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1909 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1910 cItem++;
1912 if (info->cSubtreesConstraint)
1914 items[cItem].pvStructInfo = &info->cSubtreesConstraint;
1915 items[cItem].encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
1916 cItem++;
1918 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1919 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1921 __EXCEPT_PAGE_FAULT
1923 SetLastError(STATUS_ACCESS_VIOLATION);
1924 ret = FALSE;
1926 __ENDTRY
1927 return ret;
1930 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
1931 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1932 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1934 BOOL ret;
1936 __TRY
1938 const CERT_BASIC_CONSTRAINTS2_INFO *info =
1939 (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
1940 struct AsnEncodeSequenceItem items[2] = { { 0 } };
1941 DWORD cItem = 0;
1943 if (info->fCA)
1945 items[cItem].pvStructInfo = &info->fCA;
1946 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
1947 cItem++;
1949 if (info->fPathLenConstraint)
1951 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1952 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1953 cItem++;
1955 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1956 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1958 __EXCEPT_PAGE_FAULT
1960 SetLastError(STATUS_ACCESS_VIOLATION);
1961 ret = FALSE;
1963 __ENDTRY
1964 return ret;
1967 static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
1968 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1969 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1971 BOOL ret;
1973 __TRY
1975 const BLOBHEADER *hdr =
1976 (const BLOBHEADER *)pvStructInfo;
1978 if (hdr->bType != PUBLICKEYBLOB)
1980 SetLastError(E_INVALIDARG);
1981 ret = FALSE;
1983 else
1985 const RSAPUBKEY *rsaPubKey = (const RSAPUBKEY *)
1986 ((const BYTE *)pvStructInfo + sizeof(BLOBHEADER));
1987 CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8,
1988 (BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) };
1989 struct AsnEncodeSequenceItem items[] = {
1990 { &blob, CRYPT_AsnEncodeUnsignedInteger, 0 },
1991 { &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 },
1994 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
1995 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
1996 pcbEncoded);
1999 __EXCEPT_PAGE_FAULT
2001 SetLastError(STATUS_ACCESS_VIOLATION);
2002 ret = FALSE;
2004 __ENDTRY
2005 return ret;
2008 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
2009 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2010 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2012 BOOL ret;
2014 __TRY
2016 const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
2017 DWORD bytesNeeded, lenBytes;
2019 TRACE("(%ld, %p), %08lx, %p, %p, %ld\n", blob->cbData, blob->pbData,
2020 dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
2022 CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
2023 bytesNeeded = 1 + lenBytes + blob->cbData;
2024 if (!pbEncoded)
2026 *pcbEncoded = bytesNeeded;
2027 ret = TRUE;
2029 else
2031 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2032 pcbEncoded, bytesNeeded)))
2034 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2035 pbEncoded = *(BYTE **)pbEncoded;
2036 *pbEncoded++ = ASN_OCTETSTRING;
2037 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
2038 pbEncoded += lenBytes;
2039 if (blob->cbData)
2040 memcpy(pbEncoded, blob->pbData, blob->cbData);
2044 __EXCEPT_PAGE_FAULT
2046 SetLastError(STATUS_ACCESS_VIOLATION);
2047 ret = FALSE;
2049 __ENDTRY
2050 TRACE("returning %d (%08lx)\n", ret, GetLastError());
2051 return ret;
2054 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
2055 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2056 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2058 BOOL ret;
2060 __TRY
2062 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
2063 DWORD bytesNeeded, lenBytes, dataBytes;
2064 BYTE unusedBits;
2066 /* yep, MS allows cUnusedBits to be >= 8 */
2067 if (!blob->cUnusedBits)
2069 dataBytes = blob->cbData;
2070 unusedBits = 0;
2072 else if (blob->cbData * 8 > blob->cUnusedBits)
2074 dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
2075 unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
2076 blob->cUnusedBits;
2078 else
2080 dataBytes = 0;
2081 unusedBits = 0;
2083 CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
2084 bytesNeeded = 1 + lenBytes + dataBytes + 1;
2085 if (!pbEncoded)
2087 *pcbEncoded = bytesNeeded;
2088 ret = TRUE;
2090 else
2092 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2093 pcbEncoded, bytesNeeded)))
2095 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2096 pbEncoded = *(BYTE **)pbEncoded;
2097 *pbEncoded++ = ASN_BITSTRING;
2098 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
2099 pbEncoded += lenBytes;
2100 *pbEncoded++ = unusedBits;
2101 if (dataBytes)
2103 BYTE mask = 0xff << unusedBits;
2105 if (dataBytes > 1)
2107 memcpy(pbEncoded, blob->pbData, dataBytes - 1);
2108 pbEncoded += dataBytes - 1;
2110 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
2115 __EXCEPT_PAGE_FAULT
2117 SetLastError(STATUS_ACCESS_VIOLATION);
2118 ret = FALSE;
2120 __ENDTRY
2121 return ret;
2124 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
2125 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2126 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2128 BOOL ret;
2130 __TRY
2132 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
2133 CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
2135 ret = TRUE;
2136 if (newBlob.cbData)
2138 newBlob.pbData = CryptMemAlloc(newBlob.cbData);
2139 if (newBlob.pbData)
2141 DWORD i;
2143 for (i = 0; i < newBlob.cbData; i++)
2144 newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
2146 else
2147 ret = FALSE;
2149 if (ret)
2150 ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
2151 &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2152 CryptMemFree(newBlob.pbData);
2154 __EXCEPT_PAGE_FAULT
2156 SetLastError(STATUS_ACCESS_VIOLATION);
2157 ret = FALSE;
2159 __ENDTRY
2160 return ret;
2163 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
2164 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2165 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2167 CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
2169 return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
2170 &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2173 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
2174 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2175 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2177 BOOL ret;
2179 __TRY
2181 DWORD significantBytes, lenBytes;
2182 BYTE padByte = 0, bytesNeeded;
2183 BOOL pad = FALSE;
2184 const CRYPT_INTEGER_BLOB *blob =
2185 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
2187 significantBytes = blob->cbData;
2188 if (significantBytes)
2190 if (blob->pbData[significantBytes - 1] & 0x80)
2192 /* negative, lop off leading (little-endian) 0xffs */
2193 for (; significantBytes > 0 &&
2194 blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
2196 if (blob->pbData[significantBytes - 1] < 0x80)
2198 padByte = 0xff;
2199 pad = TRUE;
2202 else
2204 /* positive, lop off leading (little-endian) zeroes */
2205 for (; significantBytes > 0 &&
2206 !blob->pbData[significantBytes - 1]; significantBytes--)
2208 if (significantBytes == 0)
2209 significantBytes = 1;
2210 if (blob->pbData[significantBytes - 1] > 0x7f)
2212 padByte = 0;
2213 pad = TRUE;
2217 if (pad)
2218 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2219 else
2220 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2221 bytesNeeded = 1 + lenBytes + significantBytes;
2222 if (pad)
2223 bytesNeeded++;
2224 if (!pbEncoded)
2226 *pcbEncoded = bytesNeeded;
2227 ret = TRUE;
2229 else
2231 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2232 pcbEncoded, bytesNeeded)))
2234 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2235 pbEncoded = *(BYTE **)pbEncoded;
2236 *pbEncoded++ = ASN_INTEGER;
2237 if (pad)
2239 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2240 pbEncoded += lenBytes;
2241 *pbEncoded++ = padByte;
2243 else
2245 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2246 pbEncoded += lenBytes;
2248 for (; significantBytes > 0; significantBytes--)
2249 *(pbEncoded++) = blob->pbData[significantBytes - 1];
2253 __EXCEPT_PAGE_FAULT
2255 SetLastError(STATUS_ACCESS_VIOLATION);
2256 ret = FALSE;
2258 __ENDTRY
2259 return ret;
2262 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
2263 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2264 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2266 BOOL ret;
2268 __TRY
2270 DWORD significantBytes, lenBytes;
2271 BYTE bytesNeeded;
2272 BOOL pad = FALSE;
2273 const CRYPT_INTEGER_BLOB *blob =
2274 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
2276 significantBytes = blob->cbData;
2277 if (significantBytes)
2279 /* positive, lop off leading (little-endian) zeroes */
2280 for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
2281 significantBytes--)
2283 if (significantBytes == 0)
2284 significantBytes = 1;
2285 if (blob->pbData[significantBytes - 1] > 0x7f)
2286 pad = TRUE;
2288 if (pad)
2289 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2290 else
2291 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2292 bytesNeeded = 1 + lenBytes + significantBytes;
2293 if (pad)
2294 bytesNeeded++;
2295 if (!pbEncoded)
2297 *pcbEncoded = bytesNeeded;
2298 ret = TRUE;
2300 else
2302 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2303 pcbEncoded, bytesNeeded)))
2305 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2306 pbEncoded = *(BYTE **)pbEncoded;
2307 *pbEncoded++ = ASN_INTEGER;
2308 if (pad)
2310 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2311 pbEncoded += lenBytes;
2312 *pbEncoded++ = 0;
2314 else
2316 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2317 pbEncoded += lenBytes;
2319 for (; significantBytes > 0; significantBytes--)
2320 *(pbEncoded++) = blob->pbData[significantBytes - 1];
2324 __EXCEPT_PAGE_FAULT
2326 SetLastError(STATUS_ACCESS_VIOLATION);
2327 ret = FALSE;
2329 __ENDTRY
2330 return ret;
2333 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
2334 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2335 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2337 CRYPT_INTEGER_BLOB blob;
2338 BOOL ret;
2340 /* Encode as an unsigned integer, then change the tag to enumerated */
2341 blob.cbData = sizeof(DWORD);
2342 blob.pbData = (BYTE *)pvStructInfo;
2343 ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
2344 X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2345 if (ret && pbEncoded)
2347 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2348 pbEncoded = *(BYTE **)pbEncoded;
2349 pbEncoded[0] = ASN_ENUMERATED;
2351 return ret;
2354 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
2355 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2356 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2358 BOOL ret;
2360 __TRY
2362 SYSTEMTIME sysTime;
2363 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
2364 * temporary buffer because the output buffer is not NULL-terminated.
2366 char buf[16];
2367 static const DWORD bytesNeeded = sizeof(buf) - 1;
2369 if (!pbEncoded)
2371 *pcbEncoded = bytesNeeded;
2372 ret = TRUE;
2374 else
2376 /* Sanity check the year, this is a two-digit year format */
2377 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2378 &sysTime);
2379 if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
2381 SetLastError(CRYPT_E_BAD_ENCODE);
2382 ret = FALSE;
2384 if (ret)
2386 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2387 pbEncoded, pcbEncoded, bytesNeeded)))
2389 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2390 pbEncoded = *(BYTE **)pbEncoded;
2391 buf[0] = ASN_UTCTIME;
2392 buf[1] = bytesNeeded - 2;
2393 snprintf(buf + 2, sizeof(buf) - 2,
2394 "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
2395 sysTime.wYear - 2000 : sysTime.wYear - 1900,
2396 sysTime.wMonth, sysTime.wDay, sysTime.wHour,
2397 sysTime.wMinute, sysTime.wSecond);
2398 memcpy(pbEncoded, buf, bytesNeeded);
2403 __EXCEPT_PAGE_FAULT
2405 SetLastError(STATUS_ACCESS_VIOLATION);
2406 ret = FALSE;
2408 __ENDTRY
2409 return ret;
2412 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
2413 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2414 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2416 BOOL ret;
2418 __TRY
2420 SYSTEMTIME sysTime;
2421 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
2422 * temporary buffer because the output buffer is not NULL-terminated.
2424 char buf[18];
2425 static const DWORD bytesNeeded = sizeof(buf) - 1;
2427 if (!pbEncoded)
2429 *pcbEncoded = bytesNeeded;
2430 ret = TRUE;
2432 else
2434 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2435 &sysTime);
2436 if (ret)
2437 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2438 pcbEncoded, bytesNeeded);
2439 if (ret)
2441 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2442 pbEncoded = *(BYTE **)pbEncoded;
2443 buf[0] = ASN_GENERALTIME;
2444 buf[1] = bytesNeeded - 2;
2445 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
2446 sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour,
2447 sysTime.wMinute, sysTime.wSecond);
2448 memcpy(pbEncoded, buf, bytesNeeded);
2452 __EXCEPT_PAGE_FAULT
2454 SetLastError(STATUS_ACCESS_VIOLATION);
2455 ret = FALSE;
2457 __ENDTRY
2458 return ret;
2461 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
2462 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2463 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2465 BOOL ret;
2467 __TRY
2469 SYSTEMTIME sysTime;
2471 /* Check the year, if it's in the UTCTime range call that encode func */
2472 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
2473 return FALSE;
2474 if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
2475 ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
2476 pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2477 else
2478 ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
2479 lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
2480 pcbEncoded);
2482 __EXCEPT_PAGE_FAULT
2484 SetLastError(STATUS_ACCESS_VIOLATION);
2485 ret = FALSE;
2487 __ENDTRY
2488 return ret;
2491 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
2492 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2493 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2495 BOOL ret;
2497 __TRY
2499 DWORD bytesNeeded, dataLen, lenBytes, i;
2500 const CRYPT_SEQUENCE_OF_ANY *seq =
2501 (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
2503 for (i = 0, dataLen = 0; i < seq->cValue; i++)
2504 dataLen += seq->rgValue[i].cbData;
2505 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2506 bytesNeeded = 1 + lenBytes + dataLen;
2507 if (!pbEncoded)
2509 *pcbEncoded = bytesNeeded;
2510 ret = TRUE;
2512 else
2514 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2515 pcbEncoded, bytesNeeded)))
2517 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2518 pbEncoded = *(BYTE **)pbEncoded;
2519 *pbEncoded++ = ASN_SEQUENCEOF;
2520 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2521 pbEncoded += lenBytes;
2522 for (i = 0; i < seq->cValue; i++)
2524 memcpy(pbEncoded, seq->rgValue[i].pbData,
2525 seq->rgValue[i].cbData);
2526 pbEncoded += seq->rgValue[i].cbData;
2531 __EXCEPT_PAGE_FAULT
2533 SetLastError(STATUS_ACCESS_VIOLATION);
2534 ret = FALSE;
2536 __ENDTRY
2537 return ret;
2540 static BOOL CRYPT_AsnEncodeDistPoint(const CRL_DIST_POINT *distPoint,
2541 BYTE *pbEncoded, DWORD *pcbEncoded)
2543 BOOL ret = TRUE;
2544 struct AsnEncodeSequenceItem items[3] = { { 0 } };
2545 struct AsnConstructedItem constructed = { 0 };
2546 struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2547 DWORD cItem = 0, cSwapped = 0;
2549 switch (distPoint->DistPointName.dwDistPointNameChoice)
2551 case CRL_DIST_POINT_NO_NAME:
2552 /* do nothing */
2553 break;
2554 case CRL_DIST_POINT_FULL_NAME:
2555 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
2556 swapped[cSwapped].pvStructInfo = &distPoint->DistPointName.u.FullName;
2557 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2558 constructed.tag = 0;
2559 constructed.pvStructInfo = &swapped[cSwapped];
2560 constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
2561 items[cItem].pvStructInfo = &constructed;
2562 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2563 cSwapped++;
2564 cItem++;
2565 break;
2566 case CRL_DIST_POINT_ISSUER_RDN_NAME:
2567 FIXME("unimplemented for CRL_DIST_POINT_ISSUER_RDN_NAME\n");
2568 ret = FALSE;
2569 break;
2570 default:
2571 ret = FALSE;
2573 if (ret && distPoint->ReasonFlags.cbData)
2575 swapped[cSwapped].tag = ASN_CONTEXT | 1;
2576 swapped[cSwapped].pvStructInfo = &distPoint->ReasonFlags;
2577 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
2578 items[cItem].pvStructInfo = &swapped[cSwapped];
2579 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2580 cSwapped++;
2581 cItem++;
2583 if (ret && distPoint->CRLIssuer.cAltEntry)
2585 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 2;
2586 swapped[cSwapped].pvStructInfo = &distPoint->CRLIssuer;
2587 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2588 items[cItem].pvStructInfo = &swapped[cSwapped];
2589 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2590 cSwapped++;
2591 cItem++;
2593 if (ret)
2594 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
2595 pbEncoded, pcbEncoded);
2596 return ret;
2599 static BOOL WINAPI CRYPT_AsnEncodeCRLDistPoints(DWORD dwCertEncodingType,
2600 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2601 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2603 BOOL ret;
2605 __TRY
2607 const CRL_DIST_POINTS_INFO *info =
2608 (const CRL_DIST_POINTS_INFO *)pvStructInfo;
2610 if (!info->cDistPoint)
2612 SetLastError(E_INVALIDARG);
2613 ret = FALSE;
2615 else
2617 DWORD bytesNeeded, dataLen, lenBytes, i;
2619 ret = TRUE;
2620 for (i = 0, dataLen = 0; ret && i < info->cDistPoint; i++)
2622 DWORD len;
2624 ret = CRYPT_AsnEncodeDistPoint(&info->rgDistPoint[i], NULL,
2625 &len);
2626 if (ret)
2627 dataLen += len;
2628 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
2630 /* Have to propagate index of failing character */
2631 *pcbEncoded = len;
2634 if (ret)
2636 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2637 bytesNeeded = 1 + lenBytes + dataLen;
2638 if (!pbEncoded)
2640 *pcbEncoded = bytesNeeded;
2641 ret = TRUE;
2643 else
2645 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2646 pbEncoded, pcbEncoded, bytesNeeded)))
2648 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2649 pbEncoded = *(BYTE **)pbEncoded;
2650 *pbEncoded++ = ASN_SEQUENCEOF;
2651 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2652 pbEncoded += lenBytes;
2653 for (i = 0; ret && i < info->cDistPoint; i++)
2655 DWORD len = dataLen;
2657 ret = CRYPT_AsnEncodeDistPoint(
2658 &info->rgDistPoint[i], pbEncoded, &len);
2659 if (ret)
2661 pbEncoded += len;
2662 dataLen -= len;
2670 __EXCEPT_PAGE_FAULT
2672 SetLastError(STATUS_ACCESS_VIOLATION);
2673 ret = FALSE;
2675 __ENDTRY
2676 return ret;
2679 static BOOL WINAPI CRYPT_AsnEncodeEnhancedKeyUsage(DWORD dwCertEncodingType,
2680 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2681 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2683 BOOL ret;
2685 __TRY
2687 const CERT_ENHKEY_USAGE *usage =
2688 (const CERT_ENHKEY_USAGE *)pvStructInfo;
2689 DWORD bytesNeeded = 0, lenBytes, size, i;
2691 ret = TRUE;
2692 for (i = 0; ret && i < usage->cUsageIdentifier; i++)
2694 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
2695 usage->rgpszUsageIdentifier[i],
2696 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &size);
2697 if (ret)
2698 bytesNeeded += size;
2700 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
2701 bytesNeeded += 1 + lenBytes;
2702 if (ret)
2704 if (!pbEncoded)
2705 *pcbEncoded = bytesNeeded;
2706 else
2708 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2709 pbEncoded, pcbEncoded, bytesNeeded)))
2711 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2712 pbEncoded = *(BYTE **)pbEncoded;
2713 *pbEncoded++ = ASN_SEQUENCEOF;
2714 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
2715 &lenBytes);
2716 pbEncoded += lenBytes;
2717 for (i = 0; ret && i < usage->cUsageIdentifier; i++)
2719 size = bytesNeeded;
2720 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
2721 usage->rgpszUsageIdentifier[i],
2722 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pbEncoded,
2723 &size);
2724 if (ret)
2726 pbEncoded += size;
2727 bytesNeeded -= size;
2734 __EXCEPT_PAGE_FAULT
2736 SetLastError(STATUS_ACCESS_VIOLATION);
2737 ret = FALSE;
2739 __ENDTRY
2740 return ret;
2743 static BOOL WINAPI CRYPT_AsnEncodeIssuingDistPoint(DWORD dwCertEncodingType,
2744 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2745 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2747 BOOL ret;
2749 __TRY
2751 const CRL_ISSUING_DIST_POINT *point =
2752 (const CRL_ISSUING_DIST_POINT *)pvStructInfo;
2753 struct AsnEncodeSequenceItem items[6] = { { 0 } };
2754 struct AsnConstructedItem constructed = { 0 };
2755 struct AsnEncodeTagSwappedItem swapped[5] = { { 0 } };
2756 DWORD cItem = 0, cSwapped = 0;
2758 ret = TRUE;
2759 switch (point->DistPointName.dwDistPointNameChoice)
2761 case CRL_DIST_POINT_NO_NAME:
2762 /* do nothing */
2763 break;
2764 case CRL_DIST_POINT_FULL_NAME:
2765 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
2766 swapped[cSwapped].pvStructInfo = &point->DistPointName.u.FullName;
2767 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2768 constructed.tag = 0;
2769 constructed.pvStructInfo = &swapped[cSwapped];
2770 constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
2771 items[cItem].pvStructInfo = &constructed;
2772 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2773 cSwapped++;
2774 cItem++;
2775 break;
2776 default:
2777 SetLastError(E_INVALIDARG);
2778 ret = FALSE;
2780 if (ret && point->fOnlyContainsUserCerts)
2782 swapped[cSwapped].tag = ASN_CONTEXT | 1;
2783 swapped[cSwapped].pvStructInfo = &point->fOnlyContainsUserCerts;
2784 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
2785 items[cItem].pvStructInfo = &swapped[cSwapped];
2786 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2787 cSwapped++;
2788 cItem++;
2790 if (ret && point->fOnlyContainsCACerts)
2792 swapped[cSwapped].tag = ASN_CONTEXT | 2;
2793 swapped[cSwapped].pvStructInfo = &point->fOnlyContainsCACerts;
2794 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
2795 items[cItem].pvStructInfo = &swapped[cSwapped];
2796 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2797 cSwapped++;
2798 cItem++;
2800 if (ret && point->OnlySomeReasonFlags.cbData)
2802 swapped[cSwapped].tag = ASN_CONTEXT | 3;
2803 swapped[cSwapped].pvStructInfo = &point->OnlySomeReasonFlags;
2804 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
2805 items[cItem].pvStructInfo = &swapped[cSwapped];
2806 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2807 cSwapped++;
2808 cItem++;
2810 if (ret && point->fIndirectCRL)
2812 swapped[cSwapped].tag = ASN_CONTEXT | 4;
2813 swapped[cSwapped].pvStructInfo = &point->fIndirectCRL;
2814 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
2815 items[cItem].pvStructInfo = &swapped[cSwapped];
2816 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2817 cSwapped++;
2818 cItem++;
2820 if (ret)
2821 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
2822 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2824 __EXCEPT_PAGE_FAULT
2826 SetLastError(STATUS_ACCESS_VIOLATION);
2827 ret = FALSE;
2829 __ENDTRY
2830 return ret;
2833 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2834 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
2835 void *pvEncoded, DWORD *pcbEncoded)
2837 static HCRYPTOIDFUNCSET set = NULL;
2838 BOOL ret = FALSE;
2839 CryptEncodeObjectExFunc encodeFunc = NULL;
2840 HCRYPTOIDFUNCADDR hFunc = NULL;
2842 TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p)\n", dwCertEncodingType,
2843 debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
2844 pvEncoded, pcbEncoded);
2846 if (!pvEncoded && !pcbEncoded)
2848 SetLastError(ERROR_INVALID_PARAMETER);
2849 return FALSE;
2851 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
2852 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
2854 SetLastError(ERROR_FILE_NOT_FOUND);
2855 return FALSE;
2858 SetLastError(NOERROR);
2859 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
2860 *(BYTE **)pvEncoded = NULL;
2861 if (!HIWORD(lpszStructType))
2863 switch (LOWORD(lpszStructType))
2865 case (WORD)X509_CERT:
2866 encodeFunc = CRYPT_AsnEncodeCert;
2867 break;
2868 case (WORD)X509_CERT_TO_BE_SIGNED:
2869 encodeFunc = CRYPT_AsnEncodeCertInfo;
2870 break;
2871 case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
2872 encodeFunc = CRYPT_AsnEncodeCRLInfo;
2873 break;
2874 case (WORD)X509_EXTENSIONS:
2875 encodeFunc = CRYPT_AsnEncodeExtensions;
2876 break;
2877 case (WORD)X509_NAME_VALUE:
2878 encodeFunc = CRYPT_AsnEncodeNameValue;
2879 break;
2880 case (WORD)X509_NAME:
2881 encodeFunc = CRYPT_AsnEncodeName;
2882 break;
2883 case (WORD)X509_PUBLIC_KEY_INFO:
2884 encodeFunc = CRYPT_AsnEncodePubKeyInfo;
2885 break;
2886 case (WORD)X509_ALTERNATE_NAME:
2887 encodeFunc = CRYPT_AsnEncodeAltName;
2888 break;
2889 case (WORD)X509_BASIC_CONSTRAINTS:
2890 encodeFunc = CRYPT_AsnEncodeBasicConstraints;
2891 break;
2892 case (WORD)X509_BASIC_CONSTRAINTS2:
2893 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2894 break;
2895 case (WORD)RSA_CSP_PUBLICKEYBLOB:
2896 encodeFunc = CRYPT_AsnEncodeRsaPubKey;
2897 break;
2898 case (WORD)X509_UNICODE_NAME:
2899 encodeFunc = CRYPT_AsnEncodeUnicodeName;
2900 break;
2901 case (WORD)X509_UNICODE_NAME_VALUE:
2902 encodeFunc = CRYPT_AsnEncodeUnicodeNameValue;
2903 break;
2904 case (WORD)X509_OCTET_STRING:
2905 encodeFunc = CRYPT_AsnEncodeOctets;
2906 break;
2907 case (WORD)X509_BITS:
2908 case (WORD)X509_KEY_USAGE:
2909 encodeFunc = CRYPT_AsnEncodeBits;
2910 break;
2911 case (WORD)X509_INTEGER:
2912 encodeFunc = CRYPT_AsnEncodeInt;
2913 break;
2914 case (WORD)X509_MULTI_BYTE_INTEGER:
2915 encodeFunc = CRYPT_AsnEncodeInteger;
2916 break;
2917 case (WORD)X509_MULTI_BYTE_UINT:
2918 encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
2919 break;
2920 case (WORD)X509_ENUMERATED:
2921 encodeFunc = CRYPT_AsnEncodeEnumerated;
2922 break;
2923 case (WORD)X509_CHOICE_OF_TIME:
2924 encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
2925 break;
2926 case (WORD)X509_SEQUENCE_OF_ANY:
2927 encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
2928 break;
2929 case (WORD)PKCS_UTC_TIME:
2930 encodeFunc = CRYPT_AsnEncodeUtcTime;
2931 break;
2932 case (WORD)X509_CRL_DIST_POINTS:
2933 encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
2934 break;
2935 case (WORD)X509_ENHANCED_KEY_USAGE:
2936 encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
2937 break;
2938 case (WORD)X509_ISSUING_DIST_POINT:
2939 encodeFunc = CRYPT_AsnEncodeIssuingDistPoint;
2940 break;
2941 default:
2942 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
2945 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
2946 encodeFunc = CRYPT_AsnEncodeExtensions;
2947 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
2948 encodeFunc = CRYPT_AsnEncodeUtcTime;
2949 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
2950 encodeFunc = CRYPT_AsnEncodeEnumerated;
2951 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2952 encodeFunc = CRYPT_AsnEncodeBits;
2953 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
2954 encodeFunc = CRYPT_AsnEncodeOctets;
2955 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS))
2956 encodeFunc = CRYPT_AsnEncodeBasicConstraints;
2957 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
2958 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2959 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
2960 encodeFunc = CRYPT_AsnEncodeAltName;
2961 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
2962 encodeFunc = CRYPT_AsnEncodeAltName;
2963 else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
2964 encodeFunc = CRYPT_AsnEncodeAltName;
2965 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
2966 encodeFunc = CRYPT_AsnEncodeAltName;
2967 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
2968 encodeFunc = CRYPT_AsnEncodeAltName;
2969 else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
2970 encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
2971 else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
2972 encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
2973 else if (!strcmp(lpszStructType, szOID_ISSUING_DIST_POINT))
2974 encodeFunc = CRYPT_AsnEncodeIssuingDistPoint;
2975 else
2976 TRACE("OID %s not found or unimplemented, looking for DLL\n",
2977 debugstr_a(lpszStructType));
2978 if (!encodeFunc)
2980 if (!set)
2981 set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_EX_FUNC, 0);
2982 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
2983 (void **)&encodeFunc, &hFunc);
2985 if (encodeFunc)
2986 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
2987 dwFlags, pEncodePara, pvEncoded, pcbEncoded);
2988 else
2989 SetLastError(ERROR_FILE_NOT_FOUND);
2990 if (hFunc)
2991 CryptFreeOIDFunctionAddress(hFunc, 0);
2992 return ret;
2995 BOOL WINAPI CryptExportPublicKeyInfo(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
2996 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
2998 return CryptExportPublicKeyInfoEx(hCryptProv, dwKeySpec, dwCertEncodingType,
2999 NULL, 0, NULL, pInfo, pcbInfo);
3002 static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3003 DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
3004 DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3006 BOOL ret;
3007 HCRYPTKEY key;
3008 static CHAR oid[] = szOID_RSA_RSA;
3010 TRACE("(%08lx, %ld, %08lx, %s, %08lx, %p, %p, %p)\n", hCryptProv, dwKeySpec,
3011 dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
3012 pInfo, pcbInfo);
3014 if (!pszPublicKeyObjId)
3015 pszPublicKeyObjId = oid;
3016 if ((ret = CryptGetUserKey(hCryptProv, dwKeySpec, &key)))
3018 DWORD keySize = 0;
3020 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &keySize);
3021 if (ret)
3023 LPBYTE pubKey = CryptMemAlloc(keySize);
3025 if (pubKey)
3027 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, pubKey,
3028 &keySize);
3029 if (ret)
3031 DWORD encodedLen = 0;
3033 ret = CryptEncodeObject(dwCertEncodingType,
3034 RSA_CSP_PUBLICKEYBLOB, pubKey, NULL, &encodedLen);
3035 if (ret)
3037 DWORD sizeNeeded = sizeof(CERT_PUBLIC_KEY_INFO) +
3038 strlen(pszPublicKeyObjId) + 1 + encodedLen;
3040 if (!pInfo)
3041 *pcbInfo = sizeNeeded;
3042 else if (*pcbInfo < sizeNeeded)
3044 SetLastError(ERROR_MORE_DATA);
3045 *pcbInfo = sizeNeeded;
3046 ret = FALSE;
3048 else
3050 pInfo->Algorithm.pszObjId = (char *)pInfo +
3051 sizeof(CERT_PUBLIC_KEY_INFO);
3052 lstrcpyA(pInfo->Algorithm.pszObjId,
3053 pszPublicKeyObjId);
3054 pInfo->Algorithm.Parameters.cbData = 0;
3055 pInfo->Algorithm.Parameters.pbData = NULL;
3056 pInfo->PublicKey.pbData =
3057 (BYTE *)pInfo->Algorithm.pszObjId
3058 + lstrlenA(pInfo->Algorithm.pszObjId) + 1;
3059 pInfo->PublicKey.cbData = encodedLen;
3060 pInfo->PublicKey.cUnusedBits = 0;
3061 ret = CryptEncodeObject(dwCertEncodingType,
3062 RSA_CSP_PUBLICKEYBLOB, pubKey,
3063 pInfo->PublicKey.pbData, &pInfo->PublicKey.cbData);
3067 CryptMemFree(pubKey);
3069 else
3070 ret = FALSE;
3072 CryptDestroyKey(key);
3074 return ret;
3077 typedef BOOL (WINAPI *ExportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
3078 DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
3079 DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo);
3081 BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
3082 DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId, DWORD dwFlags,
3083 void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3085 static HCRYPTOIDFUNCSET set = NULL;
3086 BOOL ret;
3087 ExportPublicKeyInfoExFunc exportFunc = NULL;
3088 HCRYPTOIDFUNCADDR hFunc = NULL;
3090 TRACE("(%08lx, %ld, %08lx, %s, %08lx, %p, %p, %p)\n", hCryptProv, dwKeySpec,
3091 dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
3092 pInfo, pcbInfo);
3094 if (!hCryptProv)
3096 SetLastError(ERROR_INVALID_PARAMETER);
3097 return FALSE;
3100 if (pszPublicKeyObjId)
3102 if (!set)
3103 set = CryptInitOIDFunctionSet(CRYPT_OID_EXPORT_PUBLIC_KEY_INFO_FUNC,
3105 CryptGetOIDFunctionAddress(set, dwCertEncodingType, pszPublicKeyObjId,
3106 0, (void **)&exportFunc, &hFunc);
3108 if (!exportFunc)
3109 exportFunc = CRYPT_ExportRsaPublicKeyInfoEx;
3110 ret = exportFunc(hCryptProv, dwKeySpec, dwCertEncodingType,
3111 pszPublicKeyObjId, dwFlags, pvAuxInfo, pInfo, pcbInfo);
3112 if (hFunc)
3113 CryptFreeOIDFunctionAddress(hFunc, 0);
3114 return ret;
3117 BOOL WINAPI CryptImportPublicKeyInfo(HCRYPTPROV hCryptProv,
3118 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
3120 return CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType, pInfo,
3121 0, 0, NULL, phKey);
3124 static BOOL WINAPI CRYPT_ImportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3125 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3126 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
3128 BOOL ret;
3129 DWORD pubKeySize = 0;
3131 TRACE("(%ld, %ld, %p, %d, %08lx, %p, %p)\n", hCryptProv,
3132 dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
3134 ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
3135 pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, NULL, &pubKeySize);
3136 if (ret)
3138 LPBYTE pubKey = CryptMemAlloc(pubKeySize);
3140 if (pubKey)
3142 ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
3143 pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, pubKey,
3144 &pubKeySize);
3145 if (ret)
3146 ret = CryptImportKey(hCryptProv, pubKey, pubKeySize, 0, 0,
3147 phKey);
3148 CryptMemFree(pubKey);
3150 else
3151 ret = FALSE;
3153 return ret;
3156 typedef BOOL (WINAPI *ImportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
3157 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3158 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey);
3160 BOOL WINAPI CryptImportPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3161 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3162 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
3164 static HCRYPTOIDFUNCSET set = NULL;
3165 BOOL ret;
3166 ImportPublicKeyInfoExFunc importFunc = NULL;
3167 HCRYPTOIDFUNCADDR hFunc = NULL;
3169 TRACE("(%ld, %ld, %p, %d, %08lx, %p, %p)\n", hCryptProv,
3170 dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
3172 if (!set)
3173 set = CryptInitOIDFunctionSet(CRYPT_OID_IMPORT_PUBLIC_KEY_INFO_FUNC, 0);
3174 CryptGetOIDFunctionAddress(set, dwCertEncodingType,
3175 pInfo->Algorithm.pszObjId, 0, (void **)&importFunc, &hFunc);
3176 if (!importFunc)
3177 importFunc = CRYPT_ImportRsaPublicKeyInfoEx;
3178 ret = importFunc(hCryptProv, dwCertEncodingType, pInfo, aiKeyAlg, dwFlags,
3179 pvAuxInfo, phKey);
3180 if (hFunc)
3181 CryptFreeOIDFunctionAddress(hFunc, 0);
3182 return ret;