OLD | NEW |
1 /* This Source Code Form is subject to the terms of the Mozilla Public | 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 | 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/. */ | 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | 4 |
5 #include "cert.h" | 5 #include "cert.h" |
6 #include "secpkcs7.h" | |
7 #include "base64.h" | 6 #include "base64.h" |
8 #include "secitem.h" | 7 #include "secitem.h" |
9 #include "secder.h" | 8 #include "secder.h" |
10 #include "secasn1.h" | 9 #include "secasn1.h" |
11 #include "secoid.h" | 10 #include "secoid.h" |
12 #include "secerr.h" | 11 #include "secerr.h" |
13 | 12 |
14 SEC_ASN1_MKSUB(SEC_AnyTemplate) | 13 SEC_ASN1_MKSUB(SEC_AnyTemplate) |
| 14 SEC_ASN1_MKSUB(SEC_SetOfAnyTemplate) |
15 | 15 |
16 SECStatus | 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 |
17 SEC_ReadPKCS7Certs(SECItem *pkcs7Item, CERTImportCertificateFunc f, void *arg) | 120 SEC_ReadPKCS7Certs(SECItem *pkcs7Item, CERTImportCertificateFunc f, void *arg) |
18 { | 121 { |
19 SEC_PKCS7ContentInfo *contentInfo = NULL; | 122 ContentInfo contentInfo; |
20 SECStatus rv; | 123 SECStatus rv; |
21 SECItem **certs; | 124 SECItem **certs; |
22 int count; | 125 int count; |
| 126 PRArenaPool *arena; |
23 | 127 |
24 contentInfo = SEC_PKCS7DecodeItem(pkcs7Item, NULL, NULL, NULL, NULL, NULL, | 128 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
25 » » » » NULL, NULL); | 129 if ( arena == NULL ) { |
26 if ( contentInfo == 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 ) { |
27 goto loser; | 137 goto loser; |
28 } | 138 } |
29 | 139 |
30 if ( SEC_PKCS7ContentType (contentInfo) != SEC_OID_PKCS7_SIGNED_DATA ) { | 140 if ( GetContentTypeTag(&contentInfo) != SEC_OID_PKCS7_SIGNED_DATA ) { |
31 goto loser; | 141 goto loser; |
32 } | 142 } |
33 | 143 |
34 certs = contentInfo->content.signedData->rawCerts; | 144 certs = contentInfo.content.signedData->certificates; |
35 if ( certs ) { | 145 if ( certs ) { |
36 count = 0; | 146 count = 0; |
37 | 147 |
38 while ( *certs ) { | 148 while ( *certs ) { |
39 count++; | 149 count++; |
40 certs++; | 150 certs++; |
41 } | 151 } |
42 » rv = (* f)(arg, contentInfo->content.signedData->rawCerts, count); | 152 » rv = (* f)(arg, contentInfo.content.signedData->certificates, count); |
43 } | 153 } |
44 | 154 |
45 rv = SECSuccess; | 155 rv = SECSuccess; |
46 | 156 |
47 goto done; | 157 goto done; |
48 loser: | 158 loser: |
49 rv = SECFailure; | 159 rv = SECFailure; |
50 | 160 |
51 done: | 161 done: |
52 if ( contentInfo ) { | 162 if ( arena ) { |
53 » SEC_PKCS7DestroyContentInfo(contentInfo); | 163 » PORT_FreeArena(arena, PR_FALSE); |
54 } | 164 } |
55 | 165 |
56 return(rv); | 166 return(rv); |
57 } | 167 } |
58 | 168 |
59 const SEC_ASN1Template SEC_CertSequenceTemplate[] = { | 169 const SEC_ASN1Template SEC_CertSequenceTemplate[] = { |
60 { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, 0, SEC_ASN1_SUB(SEC_AnyTemplate) } | 170 { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, 0, SEC_ASN1_SUB(SEC_AnyTemplate) } |
61 }; | 171 }; |
62 | 172 |
63 SECStatus | 173 static SECStatus |
64 SEC_ReadCertSequence(SECItem *certsItem, CERTImportCertificateFunc f, void *arg) | 174 SEC_ReadCertSequence(SECItem *certsItem, CERTImportCertificateFunc f, void *arg) |
65 { | 175 { |
66 SECStatus rv; | 176 SECStatus rv; |
67 SECItem **certs; | 177 SECItem **certs; |
68 int count; | 178 int count; |
69 SECItem **rawCerts = NULL; | 179 SECItem **rawCerts = NULL; |
70 PRArenaPool *arena; | 180 PRArenaPool *arena; |
71 SEC_PKCS7ContentInfo *contentInfo = NULL; | 181 ContentInfo contentInfo; |
72 | 182 |
73 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | 183 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
74 if (arena == NULL) { | 184 if ( arena == NULL ) { |
75 return SECFailure; | 185 return SECFailure; |
76 } | 186 } |
77 | 187 |
78 contentInfo = SEC_PKCS7DecodeItem(certsItem, NULL, NULL, NULL, NULL, NULL, | 188 PORT_Memset(&contentInfo, 0, sizeof(contentInfo)); |
79 » » » » NULL, NULL); | 189 rv = SEC_ASN1DecodeItem(arena, &contentInfo, ContentInfoTemplate, |
80 if ( contentInfo == NULL ) { | 190 » » » certsItem); |
| 191 if ( rv != SECSuccess ) { |
81 goto loser; | 192 goto loser; |
82 } | 193 } |
83 | 194 |
84 if ( SEC_PKCS7ContentType (contentInfo) != SEC_OID_NS_TYPE_CERT_SEQUENCE ) { | 195 if ( GetContentTypeTag(&contentInfo) != SEC_OID_NS_TYPE_CERT_SEQUENCE ) { |
85 goto loser; | 196 goto loser; |
86 } | 197 } |
87 | 198 |
88 | |
89 rv = SEC_QuickDERDecodeItem(arena, &rawCerts, SEC_CertSequenceTemplate, | 199 rv = SEC_QuickDERDecodeItem(arena, &rawCerts, SEC_CertSequenceTemplate, |
90 » » contentInfo->content.data); | 200 » » contentInfo.content.data); |
91 | 201 |
92 if (rv != SECSuccess) { | 202 if (rv != SECSuccess) { |
93 goto loser; | 203 goto loser; |
94 } | 204 } |
95 | 205 |
96 certs = rawCerts; | 206 certs = rawCerts; |
97 if ( certs ) { | 207 if ( certs ) { |
98 count = 0; | 208 count = 0; |
99 | 209 |
100 while ( *certs ) { | 210 while ( *certs ) { |
101 count++; | 211 count++; |
102 certs++; | 212 certs++; |
103 } | 213 } |
104 rv = (* f)(arg, rawCerts, count); | 214 rv = (* f)(arg, rawCerts, count); |
105 } | 215 } |
106 | 216 |
107 rv = SECSuccess; | 217 rv = SECSuccess; |
108 | 218 |
109 goto done; | 219 goto done; |
110 loser: | 220 loser: |
111 rv = SECFailure; | 221 rv = SECFailure; |
112 | 222 |
113 done: | 223 done: |
114 if ( contentInfo ) { | |
115 SEC_PKCS7DestroyContentInfo(contentInfo); | |
116 } | |
117 | |
118 if ( arena ) { | 224 if ( arena ) { |
119 PORT_FreeArena(arena, PR_FALSE); | 225 PORT_FreeArena(arena, PR_FALSE); |
120 } | 226 } |
121 | 227 |
122 return(rv); | 228 return(rv); |
123 } | 229 } |
124 | 230 |
125 CERTCertificate * | 231 CERTCertificate * |
126 CERT_ConvertAndDecodeCertificate(char *certstr) | 232 CERT_ConvertAndDecodeCertificate(char *certstr) |
127 { | 233 { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 | 267 |
162 if ( certbuf == NULL ) { | 268 if ( certbuf == NULL ) { |
163 PORT_SetError(SEC_ERROR_INVALID_ARGS); | 269 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
164 return(SECFailure); | 270 return(SECFailure); |
165 } | 271 } |
166 /* | 272 /* |
167 * Make sure certlen is long enough to handle the longest possible | 273 * Make sure certlen is long enough to handle the longest possible |
168 * reference in the code below: | 274 * reference in the code below: |
169 * 0x30 0x84 l1 l2 l3 l4 + | 275 * 0x30 0x84 l1 l2 l3 l4 + |
170 * tag 9 o1 o2 o3 o4 o5 o6 o7 o8 o9 | 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. |
171 * 6 + 11 = 17. 17 bytes is clearly too small to code any kind of | 278 * 6 + 11 = 17. 17 bytes is clearly too small to code any kind of |
172 * certificate (a 128 bit ECC certificate contains at least an 8 byte | 279 * certificate (a 128 bit ECC certificate contains at least an 8 byte |
173 * key and a 16 byte signature, plus coding overhead). Typically a cert | 280 * key and a 16 byte signature, plus coding overhead). Typically a cert |
174 * is much larger. So it's safe to require certlen to be at least 17 | 281 * is much larger. So it's safe to require certlen to be at least 17 |
175 * bytes. | 282 * bytes. |
176 */ | 283 */ |
177 if (certlen < 17) { | 284 if (certlen < 17) { |
178 PORT_SetError(SEC_ERROR_INPUT_LEN); | 285 PORT_SetError(SEC_ERROR_INPUT_LEN); |
179 return(SECFailure); | 286 return(SECFailure); |
180 } | 287 } |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
251 oiddata = SECOID_FindOID(&oiditem); | 358 oiddata = SECOID_FindOID(&oiditem); |
252 if ( oiddata == NULL ) { | 359 if ( oiddata == NULL ) { |
253 return(SECFailure); | 360 return(SECFailure); |
254 } | 361 } |
255 | 362 |
256 certitem.data = (unsigned char*)certbuf; | 363 certitem.data = (unsigned char*)certbuf; |
257 certitem.len = certlen; | 364 certitem.len = certlen; |
258 | 365 |
259 switch ( oiddata->offset ) { | 366 switch ( oiddata->offset ) { |
260 case SEC_OID_PKCS7_SIGNED_DATA: | 367 case SEC_OID_PKCS7_SIGNED_DATA: |
| 368 /* oid: 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02 */ |
261 return(SEC_ReadPKCS7Certs(&certitem, f, arg)); | 369 return(SEC_ReadPKCS7Certs(&certitem, f, arg)); |
262 break; | 370 break; |
263 case SEC_OID_NS_TYPE_CERT_SEQUENCE: | 371 case SEC_OID_NS_TYPE_CERT_SEQUENCE: |
| 372 /* oid: 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x02, 0x05 */ |
264 return(SEC_ReadCertSequence(&certitem, f, arg)); | 373 return(SEC_ReadCertSequence(&certitem, f, arg)); |
265 break; | 374 break; |
266 default: | 375 default: |
267 break; | 376 break; |
268 } | 377 } |
269 | 378 |
270 } else { | 379 } else { |
271 /* it had better be a certificate by now!! */ | 380 /* it had better be a certificate by now!! */ |
272 certitem.data = (unsigned char*)certbuf; | 381 certitem.data = (unsigned char*)certbuf; |
273 certitem.len = certlen; | 382 certitem.len = certlen; |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
425 if ( rv == SECSuccess ) { | 534 if ( rv == SECSuccess ) { |
426 cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), | 535 cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), |
427 &collectArgs.cert, NULL, | 536 &collectArgs.cert, NULL, |
428 PR_FALSE, PR_TRUE); | 537 PR_FALSE, PR_TRUE); |
429 } | 538 } |
430 | 539 |
431 PORT_FreeArena(collectArgs.arena, PR_FALSE); | 540 PORT_FreeArena(collectArgs.arena, PR_FALSE); |
432 | 541 |
433 return(cert); | 542 return(cert); |
434 } | 543 } |
OLD | NEW |