comparison nss/lib/pkcs7/certread.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1e5118fa0cb1
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include "cert.h"
6 #include "base64.h"
7 #include "secitem.h"
8 #include "secder.h"
9 #include "secasn1.h"
10 #include "secoid.h"
11 #include "secerr.h"
12
13 SEC_ASN1_MKSUB(SEC_AnyTemplate)
14 SEC_ASN1_MKSUB(SEC_SetOfAnyTemplate)
15
16 typedef struct ContentInfoStr ContentInfo;
17 typedef struct DegenerateSignedDataStr DegenerateSignedData;
18
19 struct ContentInfoStr {
20 SECOidTag contentTypeTag; /* local; not part of encoding */
21 SECItem contentType;
22 union {
23 SECItem *data;
24 DegenerateSignedData *signedData;
25 } content;
26 };
27
28 struct DegenerateSignedDataStr {
29 SECItem version;
30 SECItem **digestAlgorithms;
31 ContentInfo contentInfo;
32 SECItem **certificates;
33 SECItem **crls;
34 SECItem **signerInfos;
35 };
36
37 static const SEC_ASN1Template *
38 choose_content_template(void *src_or_dest, PRBool encoding);
39
40 static const SEC_ASN1TemplateChooserPtr template_chooser
41 = choose_content_template;
42
43 static const SEC_ASN1Template ContentInfoTemplate[] = {
44 { SEC_ASN1_SEQUENCE,
45 0, NULL, sizeof(ContentInfo) },
46 { SEC_ASN1_OBJECT_ID,
47 offsetof(ContentInfo,contentType) },
48 { SEC_ASN1_OPTIONAL | SEC_ASN1_DYNAMIC |
49 SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
50 offsetof(ContentInfo,content),
51 &template_chooser },
52 { 0 }
53 };
54
55 static const SEC_ASN1Template DegenerateSignedDataTemplate[] = {
56 { SEC_ASN1_SEQUENCE,
57 0, NULL, sizeof(DegenerateSignedData) },
58 { SEC_ASN1_INTEGER,
59 offsetof(DegenerateSignedData,version) },
60 { SEC_ASN1_SET_OF | SEC_ASN1_XTRN,
61 offsetof(DegenerateSignedData,digestAlgorithms),
62 SEC_ASN1_SUB(SEC_AnyTemplate) },
63 { SEC_ASN1_INLINE,
64 offsetof(DegenerateSignedData,contentInfo),
65 ContentInfoTemplate },
66 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
67 SEC_ASN1_XTRN | 0,
68 offsetof(DegenerateSignedData,certificates),
69 SEC_ASN1_SUB(SEC_SetOfAnyTemplate) },
70 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
71 SEC_ASN1_XTRN | 1,
72 offsetof(DegenerateSignedData,crls),
73 SEC_ASN1_SUB(SEC_SetOfAnyTemplate) },
74 { SEC_ASN1_SET_OF | SEC_ASN1_XTRN,
75 offsetof(DegenerateSignedData,signerInfos),
76 SEC_ASN1_SUB(SEC_AnyTemplate) },
77 { 0 }
78 };
79
80 static const SEC_ASN1Template PointerToDegenerateSignedDataTemplate[] = {
81 { SEC_ASN1_POINTER, 0, DegenerateSignedDataTemplate }
82 };
83
84 static SECOidTag
85 GetContentTypeTag(ContentInfo *cinfo)
86 {
87 if (cinfo->contentTypeTag == SEC_OID_UNKNOWN)
88 cinfo->contentTypeTag = SECOID_FindOIDTag(&cinfo->contentType);
89 return cinfo->contentTypeTag;
90 }
91
92 static const SEC_ASN1Template *
93 choose_content_template(void *src_or_dest, PRBool encoding)
94 {
95 const SEC_ASN1Template *theTemplate;
96 ContentInfo *cinfo;
97 SECOidTag kind;
98
99 PORT_Assert(src_or_dest != NULL);
100 if (src_or_dest == NULL)
101 return NULL;
102
103 cinfo = (ContentInfo*)src_or_dest;
104 kind = GetContentTypeTag(cinfo);
105 switch (kind) {
106 default:
107 theTemplate = SEC_ASN1_GET(SEC_PointerToAnyTemplate);
108 break;
109 case SEC_OID_PKCS7_DATA:
110 theTemplate = SEC_ASN1_GET(SEC_PointerToOctetStringTemplate);
111 break;
112 case SEC_OID_PKCS7_SIGNED_DATA:
113 theTemplate = PointerToDegenerateSignedDataTemplate;
114 break;
115 }
116 return theTemplate;
117 }
118
119 static SECStatus
120 SEC_ReadPKCS7Certs(SECItem *pkcs7Item, CERTImportCertificateFunc f, void *arg)
121 {
122 ContentInfo contentInfo;
123 SECStatus rv;
124 SECItem **certs;
125 int count;
126 PLArenaPool *arena;
127
128 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
129 if ( arena == NULL ) {
130 return SECFailure;
131 }
132
133 PORT_Memset(&contentInfo, 0, sizeof(contentInfo));
134 rv = SEC_ASN1DecodeItem(arena, &contentInfo, ContentInfoTemplate,
135 pkcs7Item);
136 if ( rv != SECSuccess ) {
137 goto loser;
138 }
139
140 if ( GetContentTypeTag(&contentInfo) != SEC_OID_PKCS7_SIGNED_DATA ) {
141 goto loser;
142 }
143
144 certs = contentInfo.content.signedData->certificates;
145 if ( certs ) {
146 count = 0;
147
148 while ( *certs ) {
149 count++;
150 certs++;
151 }
152 rv = (* f)(arg, contentInfo.content.signedData->certificates, count);
153 }
154
155 rv = SECSuccess;
156
157 goto done;
158 loser:
159 rv = SECFailure;
160
161 done:
162 if ( arena ) {
163 PORT_FreeArena(arena, PR_FALSE);
164 }
165
166 return(rv);
167 }
168
169 const SEC_ASN1Template SEC_CertSequenceTemplate[] = {
170 { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, 0, SEC_ASN1_SUB(SEC_AnyTemplate) }
171 };
172
173 static SECStatus
174 SEC_ReadCertSequence(SECItem *certsItem, CERTImportCertificateFunc f, void *arg)
175 {
176 SECStatus rv;
177 SECItem **certs;
178 int count;
179 SECItem **rawCerts = NULL;
180 PLArenaPool *arena;
181 ContentInfo contentInfo;
182
183 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
184 if ( arena == NULL ) {
185 return SECFailure;
186 }
187
188 PORT_Memset(&contentInfo, 0, sizeof(contentInfo));
189 rv = SEC_ASN1DecodeItem(arena, &contentInfo, ContentInfoTemplate,
190 certsItem);
191 if ( rv != SECSuccess ) {
192 goto loser;
193 }
194
195 if ( GetContentTypeTag(&contentInfo) != SEC_OID_NS_TYPE_CERT_SEQUENCE ) {
196 goto loser;
197 }
198
199 rv = SEC_QuickDERDecodeItem(arena, &rawCerts, SEC_CertSequenceTemplate,
200 contentInfo.content.data);
201
202 if (rv != SECSuccess) {
203 goto loser;
204 }
205
206 certs = rawCerts;
207 if ( certs ) {
208 count = 0;
209
210 while ( *certs ) {
211 count++;
212 certs++;
213 }
214 rv = (* f)(arg, rawCerts, count);
215 }
216
217 rv = SECSuccess;
218
219 goto done;
220 loser:
221 rv = SECFailure;
222
223 done:
224 if ( arena ) {
225 PORT_FreeArena(arena, PR_FALSE);
226 }
227
228 return(rv);
229 }
230
231 CERTCertificate *
232 CERT_ConvertAndDecodeCertificate(char *certstr)
233 {
234 CERTCertificate *cert;
235 SECStatus rv;
236 SECItem der;
237
238 rv = ATOB_ConvertAsciiToItem(&der, certstr);
239 if (rv != SECSuccess)
240 return NULL;
241
242 cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
243 &der, NULL, PR_FALSE, PR_TRUE);
244
245 PORT_Free(der.data);
246 return cert;
247 }
248
249 static const char NS_CERT_HEADER[] = "-----BEGIN CERTIFICATE-----";
250 static const char NS_CERT_TRAILER[] = "-----END CERTIFICATE-----";
251 #define NS_CERT_HEADER_LEN ((sizeof NS_CERT_HEADER) - 1)
252 #define NS_CERT_TRAILER_LEN ((sizeof NS_CERT_TRAILER) - 1)
253
254 /*
255 * read an old style ascii or binary certificate chain
256 */
257 SECStatus
258 CERT_DecodeCertPackage(char *certbuf,
259 int certlen,
260 CERTImportCertificateFunc f,
261 void *arg)
262 {
263 unsigned char *cp;
264 unsigned char *bincert = NULL;
265 char * ascCert = NULL;
266 SECStatus rv;
267
268 if ( certbuf == NULL ) {
269 PORT_SetError(SEC_ERROR_INVALID_ARGS);
270 return(SECFailure);
271 }
272 /*
273 * Make sure certlen is long enough to handle the longest possible
274 * reference in the code below:
275 * 0x30 0x84 l1 l2 l3 l4 +
276 * tag 9 o1 o2 o3 o4 o5 o6 o7 o8 o9
277 * where 9 is the longest length of the expected oids we are testing.
278 * 6 + 11 = 17. 17 bytes is clearly too small to code any kind of
279 * certificate (a 128 bit ECC certificate contains at least an 8 byte
280 * key and a 16 byte signature, plus coding overhead). Typically a cert
281 * is much larger. So it's safe to require certlen to be at least 17
282 * bytes.
283 */
284 if (certlen < 17) {
285 PORT_SetError(SEC_ERROR_INPUT_LEN);
286 return(SECFailure);
287 }
288
289 cp = (unsigned char *)certbuf;
290
291 /* is a DER encoded certificate of some type? */
292 if ( ( *cp & 0x1f ) == SEC_ASN1_SEQUENCE ) {
293 SECItem certitem;
294 SECItem *pcertitem = &certitem;
295 int seqLen, seqLenLen;
296
297 cp++;
298
299 if ( *cp & 0x80) {
300 /* Multibyte length */
301 seqLenLen = cp[0] & 0x7f;
302
303 switch (seqLenLen) {
304 case 4:
305 seqLen = ((unsigned long)cp[1]<<24) |
306 ((unsigned long)cp[2]<<16) | (cp[3]<<8) | cp[4];
307 break;
308 case 3:
309 seqLen = ((unsigned long)cp[1]<<16) | (cp[2]<<8) | cp[3];
310 break;
311 case 2:
312 seqLen = (cp[1]<<8) | cp[2];
313 break;
314 case 1:
315 seqLen = cp[1];
316 break;
317 case 0:
318 /* indefinite length */
319 seqLen = 0;
320 break;
321 default:
322 goto notder;
323 }
324 cp += ( seqLenLen + 1 );
325
326 } else {
327 seqLenLen = 0;
328 seqLen = *cp;
329 cp++;
330 }
331
332 /* check entire length if definite length */
333 if ( seqLen || seqLenLen ) {
334 if ( certlen != ( seqLen + seqLenLen + 2 ) ) {
335 if (certlen > ( seqLen + seqLenLen + 2 ))
336 PORT_SetError(SEC_ERROR_EXTRA_INPUT);
337 else
338 PORT_SetError(SEC_ERROR_INPUT_LEN);
339 goto notder;
340 }
341 }
342
343 /* check the type oid */
344 if ( cp[0] == SEC_ASN1_OBJECT_ID ) {
345 SECOidData *oiddata;
346 SECItem oiditem;
347 /* XXX - assume DER encoding of OID len!! */
348 oiditem.len = cp[1];
349 /* if we add an oid below that is longer than 9 bytes, then we
350 * need to change the certlen check at the top of the function
351 * to prevent a buffer overflow
352 */
353 if ( oiditem.len > 9 ) {
354 PORT_SetError(SEC_ERROR_UNRECOGNIZED_OID);
355 return(SECFailure);
356 }
357 oiditem.data = (unsigned char *)&cp[2];
358 oiddata = SECOID_FindOID(&oiditem);
359 if ( oiddata == NULL ) {
360 return(SECFailure);
361 }
362
363 certitem.data = (unsigned char*)certbuf;
364 certitem.len = certlen;
365
366 switch ( oiddata->offset ) {
367 case SEC_OID_PKCS7_SIGNED_DATA:
368 /* oid: 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02 */
369 return(SEC_ReadPKCS7Certs(&certitem, f, arg));
370 break;
371 case SEC_OID_NS_TYPE_CERT_SEQUENCE:
372 /* oid: 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x02, 0x05 */
373 return(SEC_ReadCertSequence(&certitem, f, arg));
374 break;
375 default:
376 break;
377 }
378
379 } else {
380 /* it had better be a certificate by now!! */
381 certitem.data = (unsigned char*)certbuf;
382 certitem.len = certlen;
383
384 rv = (* f)(arg, &pcertitem, 1);
385 return(rv);
386 }
387 }
388
389 /* now look for a netscape base64 ascii encoded cert */
390 notder:
391 {
392 unsigned char *certbegin = NULL;
393 unsigned char *certend = NULL;
394 char *pc;
395 int cl;
396
397 /* Convert the ASCII data into a nul-terminated string */
398 ascCert = (char *)PORT_Alloc(certlen + 1);
399 if (!ascCert) {
400 rv = SECFailure;
401 goto loser;
402 }
403
404 PORT_Memcpy(ascCert, certbuf, certlen);
405 ascCert[certlen] = '\0';
406
407 pc = PORT_Strchr(ascCert, '\n'); /* find an EOL */
408 if (!pc) { /* maybe this is a MAC file */
409 pc = ascCert;
410 while (*pc && NULL != (pc = PORT_Strchr(pc, '\r'))) {
411 *pc++ = '\n';
412 }
413 }
414
415 cp = (unsigned char *)ascCert;
416 cl = certlen;
417
418 /* find the beginning marker */
419 while ( cl > NS_CERT_HEADER_LEN ) {
420 int found = 0;
421 if ( !PORT_Strncasecmp((char *)cp, NS_CERT_HEADER,
422 NS_CERT_HEADER_LEN) ) {
423 cl -= NS_CERT_HEADER_LEN;
424 cp += NS_CERT_HEADER_LEN;
425 found = 1;
426 }
427
428 /* skip to next eol */
429 while ( cl && ( *cp != '\n' )) {
430 cp++;
431 cl--;
432 }
433
434 /* skip all blank lines */
435 while ( cl && ( *cp == '\n' || *cp == '\r' )) {
436 cp++;
437 cl--;
438 }
439 if (cl && found) {
440 certbegin = cp;
441 break;
442 }
443 }
444
445 if ( certbegin ) {
446 /* find the ending marker */
447 while ( cl >= NS_CERT_TRAILER_LEN ) {
448 if ( !PORT_Strncasecmp((char *)cp, NS_CERT_TRAILER,
449 NS_CERT_TRAILER_LEN) ) {
450 certend = cp;
451 break;
452 }
453
454 /* skip to next eol */
455 while ( cl && ( *cp != '\n' )) {
456 cp++;
457 cl--;
458 }
459
460 /* skip all blank lines */
461 while ( cl && ( *cp == '\n' || *cp == '\r' )) {
462 cp++;
463 cl--;
464 }
465 }
466 }
467
468 if ( certbegin && certend ) {
469 unsigned int binLen;
470
471 *certend = 0;
472 /* convert to binary */
473 bincert = ATOB_AsciiToData((char *)certbegin, &binLen);
474 if (!bincert) {
475 rv = SECFailure;
476 goto loser;
477 }
478
479 /* now recurse to decode the binary */
480 rv = CERT_DecodeCertPackage((char *)bincert, binLen, f, arg);
481
482 } else {
483 PORT_SetError(SEC_ERROR_BAD_DER);
484 rv = SECFailure;
485 }
486 }
487
488 loser:
489
490 if ( bincert ) {
491 PORT_Free(bincert);
492 }
493
494 if ( ascCert ) {
495 PORT_Free(ascCert);
496 }
497
498 return(rv);
499 }
500
501 typedef struct {
502 PLArenaPool *arena;
503 SECItem cert;
504 } collect_args;
505
506 static SECStatus
507 collect_certs(void *arg, SECItem **certs, int numcerts)
508 {
509 SECStatus rv;
510 collect_args *collectArgs;
511
512 collectArgs = (collect_args *)arg;
513
514 rv = SECITEM_CopyItem(collectArgs->arena, &collectArgs->cert, *certs);
515
516 return(rv);
517 }
518
519
520 /*
521 * read an old style ascii or binary certificate
522 */
523 CERTCertificate *
524 CERT_DecodeCertFromPackage(char *certbuf, int certlen)
525 {
526 collect_args collectArgs;
527 SECStatus rv;
528 CERTCertificate *cert = NULL;
529
530 collectArgs.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
531
532 rv = CERT_DecodeCertPackage(certbuf, certlen, collect_certs,
533 (void *)&collectArgs);
534 if ( rv == SECSuccess ) {
535 cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
536 &collectArgs.cert, NULL,
537 PR_FALSE, PR_TRUE);
538 }
539
540 PORT_FreeArena(collectArgs.arena, PR_FALSE);
541
542 return(cert);
543 }
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)