1 /*
2 * Copyright 2005-2007 Juan Lang
3 *
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.
8 *
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.
13 *
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
17 *
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 isn't
21 * implemented, so I implement them here.
22 *
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.)
27 *
28 * RFC3280, http://www.faqs.org/rfcs/rfc3280.html
29 *
30 * MSDN, especially "Constants for CryptEncodeObject and CryptDecodeObject"
31 */
32
33 #include "config.h"
34 #include "wine/port.h"
35
36 #include <assert.h>
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40
41 #define NONAMELESSUNION
42
43 #include "windef.h"
44 #include "winbase.h"
45 #include "wincrypt.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"
51
52 WINE_DEFAULT_DEBUG_CHANNEL(cryptasn);
53 WINE_DECLARE_DEBUG_CHANNEL(crypt);
54
55 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
56 BYTE *, DWORD *);
57
58 /* Prototypes for built-in encoders. They follow the Ex style prototypes.
59 * The dwCertEncodingType and lpszStructType are ignored by the built-in
60 * functions, but the parameters are retained to simplify CryptEncodeObjectEx,
61 * since it must call functions in external DLLs that follow these signatures.
62 */
63 BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
64 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
65 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
66 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
67 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
68 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
69 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
70 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
71 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
72 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
73 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
74 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
75 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
76 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
77 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
78 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
79 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
80 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
81 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
82 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
83 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
84 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
85 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
86 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
87 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
88 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
89 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
90 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
91 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
92 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
93 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
94 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
95 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
96
97 BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
98 BYTE *pbEncoded, DWORD *pcbEncoded, DWORD bytesNeeded)
99 {
100 BOOL ret = TRUE;
101
102 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
103 {
104 if (pEncodePara && pEncodePara->pfnAlloc)
105 *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
106 else
107 *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
108 if (!*(BYTE **)pbEncoded)
109 ret = FALSE;
110 else
111 *pcbEncoded = bytesNeeded;
112 }
113 else if (bytesNeeded > *pcbEncoded)
114 {
115 *pcbEncoded = bytesNeeded;
116 SetLastError(ERROR_MORE_DATA);
117 ret = FALSE;
118 }
119 else
120 *pcbEncoded = bytesNeeded;
121 return ret;
122 }
123
124 BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
125 {
126 DWORD bytesNeeded, significantBytes = 0;
127
128 if (len <= 0x7f)
129 bytesNeeded = 1;
130 else
131 {
132 DWORD temp;
133
134 for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
135 temp <<= 8, significantBytes--)
136 ;
137 bytesNeeded = significantBytes + 1;
138 }
139 if (!pbEncoded)
140 {
141 *pcbEncoded = bytesNeeded;
142 return TRUE;
143 }
144 if (*pcbEncoded < bytesNeeded)
145 {
146 SetLastError(ERROR_MORE_DATA);
147 return FALSE;
148 }
149 if (len <= 0x7f)
150 *pbEncoded = (BYTE)len;
151 else
152 {
153 DWORD i;
154
155 *pbEncoded++ = significantBytes | 0x80;
156 for (i = 0; i < significantBytes; i++)
157 {
158 *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
159 len >>= 8;
160 }
161 }
162 *pcbEncoded = bytesNeeded;
163 return TRUE;
164 }
165
166 BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
167 struct AsnEncodeSequenceItem items[], DWORD cItem, DWORD dwFlags,
168 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
169 {
170 BOOL ret;
171 DWORD i, dataLen = 0;
172
173 TRACE("%p, %d, %08x, %p, %p, %d\n", items, cItem, dwFlags, pEncodePara,
174 pbEncoded, *pcbEncoded);
175 for (i = 0, ret = TRUE; ret && i < cItem; i++)
176 {
177 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
178 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
179 NULL, &items[i].size);
180 /* Some functions propagate their errors through the size */
181 if (!ret)
182 *pcbEncoded = items[i].size;
183 dataLen += items[i].size;
184 }
185 if (ret)
186 {
187 DWORD lenBytes, bytesNeeded;
188
189 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
190 bytesNeeded = 1 + lenBytes + dataLen;
191 if (!pbEncoded)
192 *pcbEncoded = bytesNeeded;
193 else
194 {
195 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
196 pcbEncoded, bytesNeeded)))
197 {
198 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
199 pbEncoded = *(BYTE **)pbEncoded;
200 *pbEncoded++ = ASN_SEQUENCE;
201 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
202 pbEncoded += lenBytes;
203 for (i = 0; ret && i < cItem; i++)
204 {
205 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
206 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG,
207 NULL, pbEncoded, &items[i].size);
208 /* Some functions propagate their errors through the size */
209 if (!ret)
210 *pcbEncoded = items[i].size;
211 pbEncoded += items[i].size;
212 }
213 }
214 }
215 }
216 TRACE("returning %d (%08x)\n", ret, GetLastError());
217 return ret;
218 }
219
220 BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
221 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
222 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
223 {
224 BOOL ret;
225 const struct AsnConstructedItem *item =
226 (const struct AsnConstructedItem *)pvStructInfo;
227 DWORD len;
228
229 if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
230 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &len)))
231 {
232 DWORD dataLen, bytesNeeded;
233
234 CRYPT_EncodeLen(len, NULL, &dataLen);
235 bytesNeeded = 1 + dataLen + len;
236 if (!pbEncoded)
237 *pcbEncoded = bytesNeeded;
238 else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
239 pbEncoded, pcbEncoded, bytesNeeded)))
240 {
241 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
242 pbEncoded = *(BYTE **)pbEncoded;
243 *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
244 CRYPT_EncodeLen(len, pbEncoded, &dataLen);
245 pbEncoded += dataLen;
246 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
247 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
248 pbEncoded, &len);
249 if (!ret)
250 {
251 /* Some functions propagate their errors through the size */
252 *pcbEncoded = len;
253 }
254 }
255 }
256 else
257 {
258 /* Some functions propagate their errors through the size */
259 *pcbEncoded = len;
260 }
261 return ret;
262 }
263
264 struct AsnEncodeTagSwappedItem
265 {
266 BYTE tag;
267 const void *pvStructInfo;
268 CryptEncodeObjectExFunc encodeFunc;
269 };
270
271 /* Sort of a wacky hack, it encodes something using the struct
272 * AsnEncodeTagSwappedItem's encodeFunc, then replaces the tag byte with the tag
273 * given in the struct AsnEncodeTagSwappedItem.
274 */
275 static BOOL WINAPI CRYPT_AsnEncodeSwapTag(DWORD dwCertEncodingType,
276 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
277 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
278 {
279 BOOL ret;
280 const struct AsnEncodeTagSwappedItem *item =
281 (const struct AsnEncodeTagSwappedItem *)pvStructInfo;
282
283 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
284 item->pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
285 if (ret && pbEncoded)
286 *pbEncoded = item->tag;
287 return ret;
288 }
289
290 static BOOL WINAPI CRYPT_AsnEncodeCertVersion(DWORD dwCertEncodingType,
291 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
292 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
293 {
294 const DWORD *ver = (const DWORD *)pvStructInfo;
295 BOOL ret;
296
297 /* CERT_V1 is not encoded */
298 if (*ver == CERT_V1)
299 {
300 *pcbEncoded = 0;
301 ret = TRUE;
302 }
303 else
304 {
305 struct AsnConstructedItem item = { 0, ver, CRYPT_AsnEncodeInt };
306
307 ret = CRYPT_AsnEncodeConstructed(dwCertEncodingType, X509_INTEGER,
308 &item, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
309 }
310 return ret;
311 }
312
313 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
314 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
315 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
316 {
317 const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
318 BOOL ret;
319
320 if (!pbEncoded)
321 {
322 *pcbEncoded = blob->cbData;
323 ret = TRUE;
324 }
325 else
326 {
327 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
328 pcbEncoded, blob->cbData)))
329 {
330 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
331 pbEncoded = *(BYTE **)pbEncoded;
332 if (blob->cbData)
333 memcpy(pbEncoded, blob->pbData, blob->cbData);
334 *pcbEncoded = blob->cbData;
335 ret = TRUE;
336 }
337 }
338 return ret;
339 }
340
341 static BOOL WINAPI CRYPT_AsnEncodeValidity(DWORD dwCertEncodingType,
342 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
343 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
344 {
345 BOOL ret;
346 /* This has two filetimes in a row, a NotBefore and a NotAfter */
347 const FILETIME *timePtr = (const FILETIME *)pvStructInfo;
348 struct AsnEncodeSequenceItem items[] = {
349 { timePtr, CRYPT_AsnEncodeChoiceOfTime, 0 },
350 { timePtr + 1, CRYPT_AsnEncodeChoiceOfTime, 0 },
351 };
352
353 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
354 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
355 pcbEncoded);
356 return ret;
357 }
358
359 /* Like CRYPT_AsnEncodeAlgorithmId, but encodes parameters as an asn.1 NULL
360 * if they are empty.
361 */
362 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmIdWithNullParams(
363 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
364 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
365 DWORD *pcbEncoded)
366 {
367 const CRYPT_ALGORITHM_IDENTIFIER *algo =
368 (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
369 static const BYTE asn1Null[] = { ASN_NULL, 0 };
370 static const CRYPT_DATA_BLOB nullBlob = { sizeof(asn1Null),
371 (LPBYTE)asn1Null };
372 BOOL ret;
373 struct AsnEncodeSequenceItem items[2] = {
374 { algo->pszObjId, CRYPT_AsnEncodeOid, 0 },
375 { NULL, CRYPT_CopyEncodedBlob, 0 },
376 };
377
378 if (algo->Parameters.cbData)
379 items[1].pvStructInfo = &algo->Parameters;
380 else
381 items[1].pvStructInfo = &nullBlob;
382 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
383 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
384 pcbEncoded);
385 return ret;
386 }
387
388 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmId(DWORD dwCertEncodingType,
389 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
390 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
391 {
392 const CRYPT_ALGORITHM_IDENTIFIER *algo =
393 (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
394 BOOL ret;
395 struct AsnEncodeSequenceItem items[] = {
396 { algo->pszObjId, CRYPT_AsnEncodeOid, 0 },
397 { &algo->Parameters, CRYPT_CopyEncodedBlob, 0 },
398 };
399
400 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
401 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
402 pcbEncoded);
403 return ret;
404 }
405
406 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
407 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
408 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
409 {
410 BOOL ret;
411
412 __TRY
413 {
414 const CERT_PUBLIC_KEY_INFO *info =
415 (const CERT_PUBLIC_KEY_INFO *)pvStructInfo;
416 struct AsnEncodeSequenceItem items[] = {
417 { &info->Algorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
418 { &info->PublicKey, CRYPT_AsnEncodeBits, 0 },
419 };
420
421 TRACE("Encoding public key with OID %s\n",
422 debugstr_a(info->Algorithm.pszObjId));
423 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
424 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
425 pcbEncoded);
426 }
427 __EXCEPT_PAGE_FAULT
428 {
429 SetLastError(STATUS_ACCESS_VIOLATION);
430 ret = FALSE;
431 }
432 __ENDTRY
433 return ret;
434 }
435
436 static BOOL WINAPI CRYPT_AsnEncodeCert(DWORD dwCertEncodingType,
437 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
438 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
439 {
440 BOOL ret;
441
442 __TRY
443 {
444 const CERT_SIGNED_CONTENT_INFO *info =
445 (const CERT_SIGNED_CONTENT_INFO *)pvStructInfo;
446 struct AsnEncodeSequenceItem items[] = {
447 { &info->ToBeSigned, CRYPT_CopyEncodedBlob, 0 },
448 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
449 { &info->Signature, CRYPT_AsnEncodeBitsSwapBytes, 0 },
450 };
451
452 if (dwFlags & CRYPT_ENCODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
453 items[2].encodeFunc = CRYPT_AsnEncodeBits;
454 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
455 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
456 pcbEncoded);
457 }
458 __EXCEPT_PAGE_FAULT
459 {
460 SetLastError(STATUS_ACCESS_VIOLATION);
461 ret = FALSE;
462 }
463 __ENDTRY
464 return ret;
465 }
466
467 /* Like in Windows, this blithely ignores the validity of the passed-in
468 * CERT_INFO, and just encodes it as-is. The resulting encoded data may not
469 * decode properly, see CRYPT_AsnDecodeCertInfo.
470 */
471 static BOOL WINAPI CRYPT_AsnEncodeCertInfo(DWORD dwCertEncodingType,
472 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
473 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
474 {
475 BOOL ret;
476
477 __TRY
478 {
479 const CERT_INFO *info = (const CERT_INFO *)pvStructInfo;
480 struct AsnEncodeSequenceItem items[10] = {
481 { &info->dwVersion, CRYPT_AsnEncodeCertVersion, 0 },
482 { &info->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
483 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
484 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
485 { &info->NotBefore, CRYPT_AsnEncodeValidity, 0 },
486 { &info->Subject, CRYPT_CopyEncodedBlob, 0 },
487 { &info->SubjectPublicKeyInfo, CRYPT_AsnEncodePubKeyInfo, 0 },
488 { 0 }
489 };
490 struct AsnConstructedItem constructed[3] = { { 0 } };
491 DWORD cItem = 7, cConstructed = 0;
492
493 if (info->IssuerUniqueId.cbData)
494 {
495 constructed[cConstructed].tag = 1;
496 constructed[cConstructed].pvStructInfo = &info->IssuerUniqueId;
497 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
498 items[cItem].pvStructInfo = &constructed[cConstructed];
499 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
500 cConstructed++;
501 cItem++;
502 }
503 if (info->SubjectUniqueId.cbData)
504 {
505 constructed[cConstructed].tag = 2;
506 constructed[cConstructed].pvStructInfo = &info->SubjectUniqueId;
507 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
508 items[cItem].pvStructInfo = &constructed[cConstructed];
509 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
510 cConstructed++;
511 cItem++;
512 }
513 if (info->cExtension)
514 {
515 constructed[cConstructed].tag = 3;
516 constructed[cConstructed].pvStructInfo = &info->cExtension;
517 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions;
518 items[cItem].pvStructInfo = &constructed[cConstructed];
519 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
520 cConstructed++;
521 cItem++;
522 }
523
524 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
525 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
526 }
527 __EXCEPT_PAGE_FAULT
528 {
529 SetLastError(STATUS_ACCESS_VIOLATION);
530 ret = FALSE;
531 }
532 __ENDTRY
533 return ret;
534 }
535
536 static BOOL WINAPI CRYPT_AsnEncodeCRLEntry(const CRL_ENTRY *entry,
537 BYTE *pbEncoded, DWORD *pcbEncoded)
538 {
539 struct AsnEncodeSequenceItem items[3] = {
540 { &entry->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
541 { &entry->RevocationDate, CRYPT_AsnEncodeChoiceOfTime, 0 },
542 { 0 }
543 };
544 DWORD cItem = 2;
545 BOOL ret;
546
547 TRACE("%p, %p, %p\n", entry, pbEncoded, pcbEncoded);
548
549 if (entry->cExtension)
550 {
551 items[cItem].pvStructInfo = &entry->cExtension;
552 items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
553 cItem++;
554 }
555
556 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
557 pbEncoded, pcbEncoded);
558
559 TRACE("returning %d (%08x)\n", ret, GetLastError());
560 return ret;
561 }
562
563 static BOOL WINAPI CRYPT_AsnEncodeCRLEntries(DWORD dwCertEncodingType,
564 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
565 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
566 {
567 DWORD cCRLEntry = *(const DWORD *)pvStructInfo;
568 DWORD bytesNeeded, dataLen, lenBytes, i;
569 const CRL_ENTRY *rgCRLEntry = *(const CRL_ENTRY *const *)
570 ((const BYTE *)pvStructInfo + sizeof(DWORD));
571 BOOL ret = TRUE;
572
573 for (i = 0, dataLen = 0; ret && i < cCRLEntry; i++)
574 {
575 DWORD size;
576
577 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], NULL, &size);
578 if (ret)
579 dataLen += size;
580 }
581 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
582 bytesNeeded = 1 + lenBytes + dataLen;
583 if (!pbEncoded)
584 *pcbEncoded = bytesNeeded;
585 else
586 {
587 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
588 pcbEncoded, bytesNeeded)))
589 {
590 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
591 pbEncoded = *(BYTE **)pbEncoded;
592 *pbEncoded++ = ASN_SEQUENCEOF;
593 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
594 pbEncoded += lenBytes;
595 for (i = 0; i < cCRLEntry; i++)
596 {
597 DWORD size = dataLen;
598
599 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], pbEncoded, &size);
600 pbEncoded += size;
601 dataLen -= size;
602 }
603 }
604 }
605 return ret;
606 }
607
608 static BOOL WINAPI CRYPT_AsnEncodeCRLVersion(DWORD dwCertEncodingType,
609 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
610 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
611 {
612 const DWORD *ver = (const DWORD *)pvStructInfo;
613 BOOL ret;
614
615 /* CRL_V1 is not encoded */
616 if (*ver == CRL_V1)
617 {
618 *pcbEncoded = 0;
619 ret = TRUE;
620 }
621 else
622 ret = CRYPT_AsnEncodeInt(dwCertEncodingType, X509_INTEGER, ver,
623 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
624 return ret;
625 }
626
627 /* Like in Windows, this blithely ignores the validity of the passed-in
628 * CRL_INFO, and just encodes it as-is. The resulting encoded data may not
629 * decode properly, see CRYPT_AsnDecodeCRLInfo.
630 */
631 static BOOL WINAPI CRYPT_AsnEncodeCRLInfo(DWORD dwCertEncodingType,
632 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
633 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
634 {
635 BOOL ret;
636
637 __TRY
638 {
639 const CRL_INFO *info = (const CRL_INFO *)pvStructInfo;
640 struct AsnEncodeSequenceItem items[7] = {
641 { &info->dwVersion, CRYPT_AsnEncodeCRLVersion, 0 },
642 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
643 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
644 { &info->ThisUpdate, CRYPT_AsnEncodeChoiceOfTime, 0 },
645 { 0 }
646 };
647 struct AsnConstructedItem constructed[1] = { { 0 } };
648 DWORD cItem = 4, cConstructed = 0;
649
650 if (info->NextUpdate.dwLowDateTime || info->NextUpdate.dwHighDateTime)
651 {
652 items[cItem].pvStructInfo = &info->NextUpdate;
653 items[cItem].encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
654 cItem++;
655 }
656 if (info->cCRLEntry)
657 {
658 items[cItem].pvStructInfo = &info->cCRLEntry;
659 items[cItem].encodeFunc = CRYPT_AsnEncodeCRLEntries;
660 cItem++;
661 }
662 if (info->cExtension)
663 {
664 constructed[cConstructed].tag = 0;
665 constructed[cConstructed].pvStructInfo = &info->cExtension;
666 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions;
667 items[cItem].pvStructInfo = &constructed[cConstructed];
668 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
669 cConstructed++;
670 cItem++;
671 }
672
673 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
674 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
675 }
676 __EXCEPT_PAGE_FAULT
677 {
678 SetLastError(STATUS_ACCESS_VIOLATION);
679 ret = FALSE;
680 }
681 __ENDTRY
682 return ret;
683 }
684
685 static BOOL CRYPT_AsnEncodeExtension(CERT_EXTENSION *ext, BYTE *pbEncoded,
686 DWORD *pcbEncoded)
687 {
688 BOOL ret;
689 struct AsnEncodeSequenceItem items[3] = {
690 { ext->pszObjId, CRYPT_AsnEncodeOid, 0 },
691 { NULL, NULL, 0 },
692 { NULL, NULL, 0 },
693 };
694 DWORD cItem = 1;
695
696 TRACE("%p, %p, %d\n", ext, pbEncoded, *pcbEncoded);
697
698 if (ext->fCritical)
699 {
700 items[cItem].pvStructInfo = &ext->fCritical;
701 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
702 cItem++;
703 }
704 items[cItem].pvStructInfo = &ext->Value;
705 items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
706 cItem++;
707
708 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
709 pbEncoded, pcbEncoded);
710 TRACE("returning %d (%08x)\n", ret, GetLastError());
711 return ret;
712 }
713
714 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
715 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
716 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
717 {
718 BOOL ret;
719
720 __TRY
721 {
722 DWORD bytesNeeded, dataLen, lenBytes, i;
723 const CERT_EXTENSIONS *exts = (const CERT_EXTENSIONS *)pvStructInfo;
724
725 ret = TRUE;
726 for (i = 0, dataLen = 0; ret && i < exts->cExtension; i++)
727 {
728 DWORD size;
729
730 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i], NULL, &size);
731 if (ret)
732 dataLen += size;
733 }
734 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
735 bytesNeeded = 1 + lenBytes + dataLen;
736 if (!pbEncoded)
737 *pcbEncoded = bytesNeeded;
738 else
739 {
740 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
741 pcbEncoded, bytesNeeded)))
742 {
743 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
744 pbEncoded = *(BYTE **)pbEncoded;
745 *pbEncoded++ = ASN_SEQUENCEOF;
746 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
747 pbEncoded += lenBytes;
748 for (i = 0; i < exts->cExtension; i++)
749 {
750 DWORD size = dataLen;
751
752 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i],
753 pbEncoded, &size);
754 pbEncoded += size;
755 dataLen -= size;
756 }
757 }
758 }
759 }
760 __EXCEPT_PAGE_FAULT
761 {
762 SetLastError(STATUS_ACCESS_VIOLATION);
763 ret = FALSE;
764 }
765 __ENDTRY
766 return ret;
767 }
768
769 BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
770 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
771 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
772 {
773 LPCSTR pszObjId = (LPCSTR)pvStructInfo;
774 DWORD bytesNeeded = 0, lenBytes;
775 BOOL ret = TRUE;
776 int firstPos = 0;
777 BYTE firstByte = 0;
778
779 TRACE("%s\n", debugstr_a(pszObjId));
780
781 if (pszObjId)
782 {
783 const char *ptr;
784 int val1, val2;
785
786 if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
787 {
788 SetLastError(CRYPT_E_ASN1_ERROR);
789 return FALSE;
790 }
791 bytesNeeded++;
792 firstByte = val1 * 40 + val2;
793 ptr = pszObjId + firstPos;
794 while (ret && *ptr)
795 {
796 int pos;
797
798 /* note I assume each component is at most 32-bits long in base 2 */
799 if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
800 {
801 if (val1 >= 0x10000000)
802 bytesNeeded += 5;
803 else if (val1 >= 0x200000)
804 bytesNeeded += 4;
805 else if (val1 >= 0x4000)
806 bytesNeeded += 3;
807 else if (val1 >= 0x80)
808 bytesNeeded += 2;
809 else
810 bytesNeeded += 1;
811 ptr += pos;
812 if (*ptr == '.')
813 ptr++;
814 }
815 else
816 {
817 SetLastError(CRYPT_E_ASN1_ERROR);
818 return FALSE;
819 }
820 }
821 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
822 }
823 else
824 lenBytes = 1;
825 bytesNeeded += 1 + lenBytes;
826 if (pbEncoded)
827 {
828 if (*pcbEncoded < bytesNeeded)
829 {
830 SetLastError(ERROR_MORE_DATA);
831 ret = FALSE;
832 }
833 else
834 {
835 *pbEncoded++ = ASN_OBJECTIDENTIFIER;
836 CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
837 pbEncoded += lenBytes;
838 if (pszObjId)
839 {
840 const char *ptr;
841 int val, pos;
842
843 *pbEncoded++ = firstByte;
844 ptr = pszObjId + firstPos;
845 while (ret && *ptr)
846 {
847 sscanf(ptr, "%d%n", &val, &pos);
848 {
849 unsigned char outBytes[5];
850 int numBytes, i;
851
852 if (val >= 0x10000000)
853 numBytes = 5;
854 else if (val >= 0x200000)
855 numBytes = 4;
856 else if (val >= 0x4000)
857 numBytes = 3;
858 else if (val >= 0x80)
859 numBytes = 2;
860 else
861 numBytes = 1;
862 for (i = numBytes; i > 0; i--)
863 {
864 outBytes[i - 1] = val & 0x7f;
865 val >>= 7;
866 }
867 for (i = 0; i < numBytes - 1; i++)
868 *pbEncoded++ = outBytes[i] | 0x80;
869 *pbEncoded++ = outBytes[i];
870 ptr += pos;
871 if (*ptr == '.')
872 ptr++;
873 }
874 }
875 }
876 }
877 }
878 *pcbEncoded = bytesNeeded;
879 return ret;
880 }
881
882 static BOOL CRYPT_AsnEncodeStringCoerce(const CERT_NAME_VALUE *value,
883 BYTE tag, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
884 DWORD *pcbEncoded)
885 {
886 BOOL ret = TRUE;
887 LPCSTR str = (LPCSTR)value->Value.pbData;
888 DWORD bytesNeeded, lenBytes, encodedLen;
889
890 encodedLen = value->Value.cbData ? value->Value.cbData : lstrlenA(str);
891 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
892 bytesNeeded = 1 + lenBytes + encodedLen;
893 if (!pbEncoded)
894 *pcbEncoded = bytesNeeded;
895 else
896 {
897 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
898 pbEncoded, pcbEncoded, bytesNeeded)))
899 {
900 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
901 pbEncoded = *(BYTE **)pbEncoded;
902 *pbEncoded++ = tag;
903 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
904 pbEncoded += lenBytes;
905 memcpy(pbEncoded, str, encodedLen);
906 }
907 }
908 return ret;
909 }
910
911 static BOOL CRYPT_AsnEncodeBMPString(const CERT_NAME_VALUE *value,
912 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
913 DWORD *pcbEncoded)
914 {
915 BOOL ret = TRUE;
916 LPCWSTR str = (LPCWSTR)value->Value.pbData;
917 DWORD bytesNeeded, lenBytes, strLen;
918
919 if (value->Value.cbData)
920 strLen = value->Value.cbData / sizeof(WCHAR);
921 else if (value->Value.pbData)
922 strLen = lstrlenW(str);
923 else
924 strLen = 0;
925 CRYPT_EncodeLen(strLen * 2, NULL, &lenBytes);
926 bytesNeeded = 1 + lenBytes + strLen * 2;