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 /* | 5 /* |
6 * PKCS7 decoding, verification. | 6 * PKCS7 decoding, verification. |
7 */ | 7 */ |
8 | 8 |
9 #include "p7local.h" | 9 #include "p7local.h" |
10 | 10 |
11 #include "cert.h" | 11 #include "cert.h" |
12 » » » » /* XXX do not want to have to include */ | 12 /* XXX do not want to have to include */ |
13 #include "certdb.h"» » /* certdb.h -- the trust stuff needed by */ | 13 #include "certdb.h" /* certdb.h -- the trust stuff needed by */ |
14 » » » » /* the add certificate code needs to get */ | 14 /* the add certificate code needs to get */ |
15 » /* rewritten/abstracted and then this */ | 15 /* rewritten/abstracted and then this */ |
16 » » » » /* include should be removed! */ | 16 /* include should be removed! */ |
17 /*#include "cdbhdl.h" */ | 17 /*#include "cdbhdl.h" */ |
18 #include "cryptohi.h" | 18 #include "cryptohi.h" |
19 #include "key.h" | 19 #include "key.h" |
20 #include "secasn1.h" | 20 #include "secasn1.h" |
21 #include "secitem.h" | 21 #include "secitem.h" |
22 #include "secoid.h" | 22 #include "secoid.h" |
23 #include "pk11func.h" | 23 #include "pk11func.h" |
24 #include "prtime.h" | 24 #include "prtime.h" |
25 #include "secerr.h" | 25 #include "secerr.h" |
26 #include "sechash.h"» /* for HASH_GetHashObject() */ | 26 #include "sechash.h" /* for HASH_GetHashObject() */ |
27 #include "secder.h" | 27 #include "secder.h" |
28 #include "secpkcs5.h" | 28 #include "secpkcs5.h" |
29 | 29 |
30 struct sec_pkcs7_decoder_worker { | 30 struct sec_pkcs7_decoder_worker { |
31 int depth; | 31 int depth; |
32 int digcnt; | 32 int digcnt; |
33 void **digcxs; | 33 void **digcxs; |
34 const SECHashObject **digobjs; | 34 const SECHashObject **digobjs; |
35 sec_PKCS7CipherObject *decryptobj; | 35 sec_PKCS7CipherObject *decryptobj; |
36 PRBool saw_contents; | 36 PRBool saw_contents; |
37 }; | 37 }; |
38 | 38 |
39 struct SEC_PKCS7DecoderContextStr { | 39 struct SEC_PKCS7DecoderContextStr { |
40 SEC_ASN1DecoderContext *dcx; | 40 SEC_ASN1DecoderContext *dcx; |
41 SEC_PKCS7ContentInfo *cinfo; | 41 SEC_PKCS7ContentInfo *cinfo; |
42 SEC_PKCS7DecoderContentCallback cb; | 42 SEC_PKCS7DecoderContentCallback cb; |
43 void *cb_arg; | 43 void *cb_arg; |
44 SECKEYGetPasswordKey pwfn; | 44 SECKEYGetPasswordKey pwfn; |
45 void *pwfn_arg; | 45 void *pwfn_arg; |
46 struct sec_pkcs7_decoder_worker worker; | 46 struct sec_pkcs7_decoder_worker worker; |
47 PLArenaPool *tmp_poolp; | 47 PLArenaPool *tmp_poolp; |
48 int error; | 48 int error; |
49 SEC_PKCS7GetDecryptKeyCallback dkcb; | 49 SEC_PKCS7GetDecryptKeyCallback dkcb; |
50 void *dkcb_arg; | 50 void *dkcb_arg; |
51 SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb; | 51 SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb; |
52 }; | 52 }; |
53 | 53 |
54 /* | 54 /* |
55 * Handle one worker, decrypting and digesting the data as necessary. | 55 * Handle one worker, decrypting and digesting the data as necessary. |
56 * | 56 * |
57 * XXX If/when we support nested contents, this probably needs to be | 57 * XXX If/when we support nested contents, this probably needs to be |
58 * revised somewhat to get passed the content-info (which unfortunately | 58 * revised somewhat to get passed the content-info (which unfortunately |
59 * can be two different types depending on whether it is encrypted or not) | 59 * can be two different types depending on whether it is encrypted or not) |
60 * corresponding to the given worker. | 60 * corresponding to the given worker. |
61 */ | 61 */ |
62 static void | 62 static void sec_pkcs7_decoder_work_data(SEC_PKCS7DecoderContext *p7dcx, |
63 sec_pkcs7_decoder_work_data (SEC_PKCS7DecoderContext *p7dcx, | 63 struct sec_pkcs7_decoder_worker *worker, |
64 » » » struct sec_pkcs7_decoder_worker *worker, | 64 const unsigned char *data, |
65 » » » const unsigned char *data, unsigned long len, | 65 unsigned long len, PRBool final) { |
66 » » » PRBool final) | 66 unsigned char *buf = NULL; |
67 { | 67 SECStatus rv; |
68 unsigned char *buf = NULL; | 68 int i; |
69 SECStatus rv; | 69 |
70 int i; | 70 /* |
71 | 71 * We should really have data to process, or we should be trying |
72 /* | 72 * to finish/flush the last block. (This is an overly paranoid |
73 * We should really have data to process, or we should be trying | 73 * check since all callers are in this file and simple inspection |
74 * to finish/flush the last block. (This is an overly paranoid | 74 * proves they do it right. But it could find a bug in future |
75 * check since all callers are in this file and simple inspection | 75 * modifications/development, that is why it is here.) |
76 * proves they do it right. But it could find a bug in future | 76 */ |
77 * modifications/development, that is why it is here.) | 77 PORT_Assert((data != NULL && len) || final); |
78 */ | 78 |
79 PORT_Assert ((data != NULL && len) || final); | 79 /* |
80 | 80 * Decrypt this chunk. |
81 /* | 81 * |
82 * Decrypt this chunk. | 82 * XXX If we get an error, we do not want to do the digest or callback, |
83 * | 83 * but we want to keep decoding. Or maybe we want to stop decoding |
84 * XXX If we get an error, we do not want to do the digest or callback, | 84 * altogether if there is a callback, because obviously we are not |
85 * but we want to keep decoding. Or maybe we want to stop decoding | 85 * sending the data back and they want to know that. |
86 * altogether if there is a callback, because obviously we are not | 86 */ |
87 * sending the data back and they want to know that. | 87 if (worker->decryptobj != NULL) { |
88 */ | 88 /* XXX the following lengths should all be longs? */ |
| 89 unsigned int inlen; /* length of data being decrypted */ |
| 90 unsigned int outlen; /* length of decrypted data */ |
| 91 unsigned int buflen; /* length available for decrypted data */ |
| 92 SECItem *plain; |
| 93 |
| 94 inlen = len; |
| 95 buflen = sec_PKCS7DecryptLength(worker->decryptobj, inlen, final); |
| 96 if (buflen == 0) { |
| 97 if (inlen == 0) /* no input and no output */ |
| 98 return; |
| 99 /* |
| 100 * No output is expected, but the input data may be buffered |
| 101 * so we still have to call Decrypt. |
| 102 */ |
| 103 rv = sec_PKCS7Decrypt(worker->decryptobj, NULL, NULL, 0, data, inlen, |
| 104 final); |
| 105 if (rv != SECSuccess) { |
| 106 p7dcx->error = PORT_GetError(); |
| 107 return; /* XXX indicate error? */ |
| 108 } |
| 109 return; |
| 110 } |
| 111 |
| 112 if (p7dcx->cb != NULL) { |
| 113 buf = (unsigned char *)PORT_Alloc(buflen); |
| 114 plain = NULL; |
| 115 } else { |
| 116 unsigned long oldlen; |
| 117 |
| 118 /* |
| 119 * XXX This assumes one level of content only. |
| 120 * See comment above about nested content types. |
| 121 * XXX Also, it should work for signedAndEnvelopedData, too! |
| 122 */ |
| 123 plain = |
| 124 &(p7dcx->cinfo->content.envelopedData->encContentInfo.plainContent); |
| 125 |
| 126 oldlen = plain->len; |
| 127 if (oldlen == 0) { |
| 128 buf = (unsigned char *)PORT_ArenaAlloc(p7dcx->cinfo->poolp, buflen); |
| 129 } else { |
| 130 buf = (unsigned char *)PORT_ArenaGrow(p7dcx->cinfo->poolp, plain->data, |
| 131 oldlen, oldlen + buflen); |
| 132 if (buf != NULL) buf += oldlen; |
| 133 } |
| 134 plain->data = buf; |
| 135 } |
| 136 if (buf == NULL) { |
| 137 p7dcx->error = SEC_ERROR_NO_MEMORY; |
| 138 return; /* XXX indicate error? */ |
| 139 } |
| 140 rv = sec_PKCS7Decrypt(worker->decryptobj, buf, &outlen, buflen, data, inlen, |
| 141 final); |
| 142 if (rv != SECSuccess) { |
| 143 p7dcx->error = PORT_GetError(); |
| 144 return; /* XXX indicate error? */ |
| 145 } |
| 146 if (plain != NULL) { |
| 147 PORT_Assert(final || outlen == buflen); |
| 148 plain->len += outlen; |
| 149 } |
| 150 data = buf; |
| 151 len = outlen; |
| 152 } |
| 153 |
| 154 /* |
| 155 * Update the running digests. |
| 156 */ |
| 157 if (len) { |
| 158 for (i = 0; i < worker->digcnt; i++) { |
| 159 (*worker->digobjs[i]->update)(worker->digcxs[i], data, len); |
| 160 } |
| 161 } |
| 162 |
| 163 /* |
| 164 * Pass back the contents bytes, and free the temporary buffer. |
| 165 */ |
| 166 if (p7dcx->cb != NULL) { |
| 167 if (len) (*p7dcx->cb)(p7dcx->cb_arg, (const char *)data, len); |
89 if (worker->decryptobj != NULL) { | 168 if (worker->decryptobj != NULL) { |
90 » /* XXX the following lengths should all be longs? */ | 169 PORT_Assert(buf != NULL); |
91 » unsigned int inlen;» /* length of data being decrypted */ | 170 PORT_Free(buf); |
92 » unsigned int outlen;» /* length of decrypted data */ | 171 } |
93 » unsigned int buflen;» /* length available for decrypted data */ | 172 } |
94 » SECItem *plain; | 173 } |
95 | 174 |
96 » inlen = len; | 175 static void sec_pkcs7_decoder_filter(void *arg, const char *data, |
97 » buflen = sec_PKCS7DecryptLength (worker->decryptobj, inlen, final); | 176 unsigned long len, int depth, |
98 » if (buflen == 0) { | 177 SEC_ASN1EncodingPart data_kind) { |
99 » if (inlen == 0)» /* no input and no output */ | 178 SEC_PKCS7DecoderContext *p7dcx; |
100 » » return; | 179 struct sec_pkcs7_decoder_worker *worker; |
101 » /* | 180 |
102 » * No output is expected, but the input data may be buffered | 181 /* |
103 » * so we still have to call Decrypt. | 182 * Since we do not handle any nested contents, the only bytes we |
104 » */ | 183 * are really interested in are the actual contents bytes (not |
105 » rv = sec_PKCS7Decrypt (worker->decryptobj, NULL, NULL, 0, | 184 * the identifier, length, or end-of-contents bytes). If we were |
106 » » » » data, inlen, final); | 185 * handling nested types we would probably need to do something |
107 » if (rv != SECSuccess) { | 186 * smarter based on depth and data_kind. |
108 » » p7dcx->error = PORT_GetError(); | 187 */ |
109 » » return;»» /* XXX indicate error? */ | 188 if (data_kind != SEC_ASN1_Contents) return; |
110 » } | 189 |
111 » return; | 190 /* |
112 » } | 191 * The ASN.1 decoder should not even call us with a length of 0. |
113 | 192 * Just being paranoid. |
114 » if (p7dcx->cb != NULL) { | 193 */ |
115 » buf = (unsigned char *) PORT_Alloc (buflen); | 194 PORT_Assert(len); |
116 » plain = NULL; | 195 if (len == 0) return; |
117 » } else { | 196 |
118 » unsigned long oldlen; | 197 p7dcx = (SEC_PKCS7DecoderContext *)arg; |
119 | 198 |
120 » /* | 199 /* |
121 » * XXX This assumes one level of content only. | 200 * Handling nested contents would mean that there is a chain |
122 » * See comment above about nested content types. | 201 * of workers -- one per each level of content. The following |
123 » * XXX Also, it should work for signedAndEnvelopedData, too! | 202 * would start with the first worker and loop over them. |
124 » */ | 203 */ |
125 » plain = &(p7dcx->cinfo-> | 204 worker = &(p7dcx->worker); |
126 » » » content.envelopedData->encContentInfo.plainContent); | 205 |
127 | 206 worker->saw_contents = PR_TRUE; |
128 » oldlen = plain->len; | 207 |
129 » if (oldlen == 0) { | 208 sec_pkcs7_decoder_work_data(p7dcx, worker, (const unsigned char *)data, len, |
130 » » buf = (unsigned char*)PORT_ArenaAlloc (p7dcx->cinfo->poolp,· | 209 PR_FALSE); |
131 » » » » » » buflen); | 210 } |
132 » } else { | |
133 » » buf = (unsigned char*)PORT_ArenaGrow (p7dcx->cinfo->poolp,· | |
134 » » » » plain->data, | |
135 » » » » oldlen, oldlen + buflen); | |
136 » » if (buf != NULL) | |
137 » » buf += oldlen; | |
138 » } | |
139 » plain->data = buf; | |
140 » } | |
141 » if (buf == NULL) { | |
142 » p7dcx->error = SEC_ERROR_NO_MEMORY; | |
143 » return;» » /* XXX indicate error? */ | |
144 » } | |
145 » rv = sec_PKCS7Decrypt (worker->decryptobj, buf, &outlen, buflen, | |
146 » » » data, inlen, final); | |
147 » if (rv != SECSuccess) { | |
148 » p7dcx->error = PORT_GetError(); | |
149 » return;» » /* XXX indicate error? */ | |
150 » } | |
151 » if (plain != NULL) { | |
152 » PORT_Assert (final || outlen == buflen); | |
153 » plain->len += outlen; | |
154 » } | |
155 » data = buf; | |
156 » len = outlen; | |
157 } | |
158 | |
159 /* | |
160 * Update the running digests. | |
161 */ | |
162 if (len) { | |
163 » for (i = 0; i < worker->digcnt; i++) { | |
164 » (* worker->digobjs[i]->update) (worker->digcxs[i], data, len); | |
165 » } | |
166 } | |
167 | |
168 /* | |
169 * Pass back the contents bytes, and free the temporary buffer. | |
170 */ | |
171 if (p7dcx->cb != NULL) { | |
172 » if (len) | |
173 » (* p7dcx->cb) (p7dcx->cb_arg, (const char *)data, len); | |
174 » if (worker->decryptobj != NULL) { | |
175 » PORT_Assert (buf != NULL); | |
176 » PORT_Free (buf); | |
177 » } | |
178 } | |
179 } | |
180 | |
181 static void | |
182 sec_pkcs7_decoder_filter (void *arg, const char *data, unsigned long len, | |
183 » » » int depth, SEC_ASN1EncodingPart data_kind) | |
184 { | |
185 SEC_PKCS7DecoderContext *p7dcx; | |
186 struct sec_pkcs7_decoder_worker *worker; | |
187 | |
188 /* | |
189 * Since we do not handle any nested contents, the only bytes we | |
190 * are really interested in are the actual contents bytes (not | |
191 * the identifier, length, or end-of-contents bytes). If we were | |
192 * handling nested types we would probably need to do something | |
193 * smarter based on depth and data_kind. | |
194 */ | |
195 if (data_kind != SEC_ASN1_Contents) | |
196 » return; | |
197 | |
198 /* | |
199 * The ASN.1 decoder should not even call us with a length of 0. | |
200 * Just being paranoid. | |
201 */ | |
202 PORT_Assert (len); | |
203 if (len == 0) | |
204 » return; | |
205 | |
206 p7dcx = (SEC_PKCS7DecoderContext*)arg; | |
207 | |
208 /* | |
209 * Handling nested contents would mean that there is a chain | |
210 * of workers -- one per each level of content. The following | |
211 * would start with the first worker and loop over them. | |
212 */ | |
213 worker = &(p7dcx->worker); | |
214 | |
215 worker->saw_contents = PR_TRUE; | |
216 | |
217 sec_pkcs7_decoder_work_data (p7dcx, worker, | |
218 » » » » (const unsigned char *) data, len, PR_FALSE); | |
219 } | |
220 | |
221 | 211 |
222 /* | 212 /* |
223 * Create digest contexts for each algorithm in "digestalgs". | 213 * Create digest contexts for each algorithm in "digestalgs". |
224 * No algorithms is not an error, we just do not do anything. | 214 * No algorithms is not an error, we just do not do anything. |
225 * An error (like trouble allocating memory), marks the error | 215 * An error (like trouble allocating memory), marks the error |
226 * in "p7dcx" and returns SECFailure, which means that our caller | 216 * in "p7dcx" and returns SECFailure, which means that our caller |
227 * should just give up altogether. | 217 * should just give up altogether. |
228 */ | 218 */ |
229 static SECStatus | 219 static SECStatus sec_pkcs7_decoder_start_digests(SEC_PKCS7DecoderContext *p7dcx, |
230 sec_pkcs7_decoder_start_digests (SEC_PKCS7DecoderContext *p7dcx, int depth, | 220 int depth, |
231 » » » » SECAlgorithmID **digestalgs) | 221 SECAlgorithmID **digestalgs) { |
232 { | 222 int i, digcnt; |
233 int i, digcnt; | 223 |
234 | 224 if (digestalgs == NULL) return SECSuccess; |
235 if (digestalgs == NULL) | 225 |
236 » return SECSuccess; | 226 /* |
| 227 * Count the algorithms. |
| 228 */ |
| 229 digcnt = 0; |
| 230 while (digestalgs[digcnt] != NULL) digcnt++; |
| 231 |
| 232 /* |
| 233 * No algorithms means no work to do. |
| 234 * Just act as if there were no algorithms specified. |
| 235 */ |
| 236 if (digcnt == 0) return SECSuccess; |
| 237 |
| 238 p7dcx->worker.digcxs = |
| 239 (void **)PORT_ArenaAlloc(p7dcx->tmp_poolp, digcnt * sizeof(void *)); |
| 240 p7dcx->worker.digobjs = (const SECHashObject **)PORT_ArenaAlloc( |
| 241 p7dcx->tmp_poolp, digcnt * sizeof(SECHashObject *)); |
| 242 if (p7dcx->worker.digcxs == NULL || p7dcx->worker.digobjs == NULL) { |
| 243 p7dcx->error = SEC_ERROR_NO_MEMORY; |
| 244 return SECFailure; |
| 245 } |
| 246 |
| 247 p7dcx->worker.depth = depth; |
| 248 p7dcx->worker.digcnt = 0; |
| 249 |
| 250 /* |
| 251 * Create a digest context for each algorithm. |
| 252 */ |
| 253 for (i = 0; i < digcnt; i++) { |
| 254 SECAlgorithmID *algid = digestalgs[i]; |
| 255 SECOidTag oidTag = SECOID_FindOIDTag(&(algid->algorithm)); |
| 256 const SECHashObject *digobj = HASH_GetHashObjectByOidTag(oidTag); |
| 257 void *digcx; |
237 | 258 |
238 /* | 259 /* |
239 * Count the algorithms. | 260 * Skip any algorithm we do not even recognize; obviously, |
| 261 * this could be a problem, but if it is critical then the |
| 262 * result will just be that the signature does not verify. |
| 263 * We do not necessarily want to error out here, because |
| 264 * the particular algorithm may not actually be important, |
| 265 * but we cannot know that until later. |
240 */ | 266 */ |
241 digcnt = 0; | 267 if (digobj == NULL) { |
242 while (digestalgs[digcnt] != NULL) | 268 p7dcx->worker.digcnt--; |
243 » digcnt++; | 269 continue; |
244 | 270 } |
245 /* | 271 |
246 * No algorithms means no work to do. | 272 digcx = (*digobj->create)(); |
247 * Just act as if there were no algorithms specified. | 273 if (digcx != NULL) { |
248 */ | 274 (*digobj->begin)(digcx); |
249 if (digcnt == 0) | 275 p7dcx->worker.digobjs[p7dcx->worker.digcnt] = digobj; |
250 » return SECSuccess; | 276 p7dcx->worker.digcxs[p7dcx->worker.digcnt] = digcx; |
251 | 277 p7dcx->worker.digcnt++; |
252 p7dcx->worker.digcxs = (void**)PORT_ArenaAlloc (p7dcx->tmp_poolp, | 278 } |
253 » » » » » digcnt * sizeof (void *)); | 279 } |
254 p7dcx->worker.digobjs = (const SECHashObject**)PORT_ArenaAlloc (p7dcx->tmp_p
oolp, | 280 |
255 » » » » » digcnt * sizeof (SECHashObject *)); | 281 if (p7dcx->worker.digcnt != 0) |
256 if (p7dcx->worker.digcxs == NULL || p7dcx->worker.digobjs == NULL) { | 282 SEC_ASN1DecoderSetFilterProc(p7dcx->dcx, sec_pkcs7_decoder_filter, p7dcx, |
257 » p7dcx->error = SEC_ERROR_NO_MEMORY; | 283 (PRBool)(p7dcx->cb != NULL)); |
258 » return SECFailure; | 284 return SECSuccess; |
259 } | 285 } |
260 | |
261 p7dcx->worker.depth = depth; | |
262 p7dcx->worker.digcnt = 0; | |
263 | |
264 /* | |
265 * Create a digest context for each algorithm. | |
266 */ | |
267 for (i = 0; i < digcnt; i++) { | |
268 » SECAlgorithmID * algid = digestalgs[i]; | |
269 » SECOidTag oidTag = SECOID_FindOIDTag(&(algid->algorithm)); | |
270 » const SECHashObject *digobj = HASH_GetHashObjectByOidTag(oidTag); | |
271 » void *digcx; | |
272 | |
273 » /* | |
274 » * Skip any algorithm we do not even recognize; obviously, | |
275 » * this could be a problem, but if it is critical then the | |
276 » * result will just be that the signature does not verify. | |
277 » * We do not necessarily want to error out here, because | |
278 » * the particular algorithm may not actually be important, | |
279 » * but we cannot know that until later. | |
280 » */ | |
281 » if (digobj == NULL) { | |
282 » p7dcx->worker.digcnt--; | |
283 » continue; | |
284 » } | |
285 | |
286 » digcx = (* digobj->create)(); | |
287 » if (digcx != NULL) { | |
288 » (* digobj->begin) (digcx); | |
289 » p7dcx->worker.digobjs[p7dcx->worker.digcnt] = digobj; | |
290 » p7dcx->worker.digcxs[p7dcx->worker.digcnt] = digcx; | |
291 » p7dcx->worker.digcnt++; | |
292 » } | |
293 } | |
294 | |
295 if (p7dcx->worker.digcnt != 0) | |
296 » SEC_ASN1DecoderSetFilterProc (p7dcx->dcx, | |
297 » » » » sec_pkcs7_decoder_filter, | |
298 » » » » p7dcx, | |
299 » » » » (PRBool)(p7dcx->cb != NULL)); | |
300 return SECSuccess; | |
301 } | |
302 | |
303 | 286 |
304 /* | 287 /* |
305 * Close out all of the digest contexts, storing the results in "digestsp". | 288 * Close out all of the digest contexts, storing the results in "digestsp". |
306 */ | 289 */ |
307 static SECStatus | 290 static SECStatus sec_pkcs7_decoder_finish_digests( |
308 sec_pkcs7_decoder_finish_digests (SEC_PKCS7DecoderContext *p7dcx, | 291 SEC_PKCS7DecoderContext *p7dcx, PLArenaPool *poolp, SECItem ***digestsp) { |
309 » » » » PLArenaPool *poolp, | 292 struct sec_pkcs7_decoder_worker *worker; |
310 » » » » SECItem ***digestsp) | 293 const SECHashObject *digobj; |
311 { | 294 void *digcx; |
312 struct sec_pkcs7_decoder_worker *worker; | 295 SECItem **digests, *digest; |
313 const SECHashObject *digobj; | 296 int i; |
314 void *digcx; | 297 void *mark; |
315 SECItem **digests, *digest; | 298 |
316 int i; | 299 /* |
317 void *mark; | 300 * XXX Handling nested contents would mean that there is a chain |
318 | 301 * of workers -- one per each level of content. The following |
319 /* | 302 * would want to find the last worker in the chain. |
320 * XXX Handling nested contents would mean that there is a chain | 303 */ |
321 * of workers -- one per each level of content. The following | 304 worker = &(p7dcx->worker); |
322 * would want to find the last worker in the chain. | 305 |
323 */ | 306 /* |
324 worker = &(p7dcx->worker); | 307 * If no digests, then we have nothing to do. |
325 | 308 */ |
326 /* | 309 if (worker->digcnt == 0) return SECSuccess; |
327 * If no digests, then we have nothing to do. | 310 |
328 */ | 311 /* |
329 if (worker->digcnt == 0) | 312 * No matter what happens after this, we want to stop filtering. |
330 » return SECSuccess; | 313 * XXX If we handle nested contents, we only want to stop filtering |
331 | 314 * if we are finishing off the *last* worker. |
332 /* | 315 */ |
333 * No matter what happens after this, we want to stop filtering. | 316 SEC_ASN1DecoderClearFilterProc(p7dcx->dcx); |
334 * XXX If we handle nested contents, we only want to stop filtering | 317 |
335 * if we are finishing off the *last* worker. | 318 /* |
336 */ | 319 * If we ended up with no contents, just destroy each |
337 SEC_ASN1DecoderClearFilterProc (p7dcx->dcx); | 320 * digest context -- they are meaningless and potentially |
338 | 321 * confusing, because their presence would imply some content |
339 /* | 322 * was digested. |
340 * If we ended up with no contents, just destroy each | 323 */ |
341 * digest context -- they are meaningless and potentially | 324 if (!worker->saw_contents) { |
342 * confusing, because their presence would imply some content | 325 for (i = 0; i < worker->digcnt; i++) { |
343 * was digested. | 326 digcx = worker->digcxs[i]; |
344 */ | 327 digobj = worker->digobjs[i]; |
345 if (! worker->saw_contents) { | 328 (*digobj->destroy)(digcx, PR_TRUE); |
346 » for (i = 0; i < worker->digcnt; i++) { | 329 } |
347 » digcx = worker->digcxs[i]; | |
348 » digobj = worker->digobjs[i]; | |
349 » (* digobj->destroy) (digcx, PR_TRUE); | |
350 » } | |
351 » return SECSuccess; | |
352 } | |
353 | |
354 mark = PORT_ArenaMark (poolp); | |
355 | |
356 /* | |
357 * Close out each digest context, saving digest away. | |
358 */ | |
359 digests =· | |
360 (SECItem**)PORT_ArenaAlloc (poolp,(worker->digcnt+1)*sizeof(SECItem *)); | |
361 digest = (SECItem*)PORT_ArenaAlloc (poolp, worker->digcnt*sizeof(SECItem)); | |
362 if (digests == NULL || digest == NULL) { | |
363 » p7dcx->error = PORT_GetError(); | |
364 » PORT_ArenaRelease (poolp, mark); | |
365 » return SECFailure; | |
366 } | |
367 | |
368 for (i = 0; i < worker->digcnt; i++, digest++) { | |
369 » digcx = worker->digcxs[i]; | |
370 » digobj = worker->digobjs[i]; | |
371 | |
372 » digest->data = (unsigned char*)PORT_ArenaAlloc (poolp, digobj->length); | |
373 » if (digest->data == NULL) { | |
374 » p7dcx->error = PORT_GetError(); | |
375 » PORT_ArenaRelease (poolp, mark); | |
376 » return SECFailure; | |
377 » } | |
378 | |
379 » digest->len = digobj->length; | |
380 » (* digobj->end) (digcx, digest->data, &(digest->len), digest->len); | |
381 » (* digobj->destroy) (digcx, PR_TRUE); | |
382 | |
383 » digests[i] = digest; | |
384 } | |
385 digests[i] = NULL; | |
386 *digestsp = digests; | |
387 | |
388 PORT_ArenaUnmark (poolp, mark); | |
389 return SECSuccess; | 330 return SECSuccess; |
| 331 } |
| 332 |
| 333 mark = PORT_ArenaMark(poolp); |
| 334 |
| 335 /* |
| 336 * Close out each digest context, saving digest away. |
| 337 */ |
| 338 digests = (SECItem **)PORT_ArenaAlloc( |
| 339 poolp, (worker->digcnt + 1) * sizeof(SECItem *)); |
| 340 digest = (SECItem *)PORT_ArenaAlloc(poolp, worker->digcnt * sizeof(SECItem)); |
| 341 if (digests == NULL || digest == NULL) { |
| 342 p7dcx->error = PORT_GetError(); |
| 343 PORT_ArenaRelease(poolp, mark); |
| 344 return SECFailure; |
| 345 } |
| 346 |
| 347 for (i = 0; i < worker->digcnt; i++, digest++) { |
| 348 digcx = worker->digcxs[i]; |
| 349 digobj = worker->digobjs[i]; |
| 350 |
| 351 digest->data = (unsigned char *)PORT_ArenaAlloc(poolp, digobj->length); |
| 352 if (digest->data == NULL) { |
| 353 p7dcx->error = PORT_GetError(); |
| 354 PORT_ArenaRelease(poolp, mark); |
| 355 return SECFailure; |
| 356 } |
| 357 |
| 358 digest->len = digobj->length; |
| 359 (*digobj->end)(digcx, digest->data, &(digest->len), digest->len); |
| 360 (*digobj->destroy)(digcx, PR_TRUE); |
| 361 |
| 362 digests[i] = digest; |
| 363 } |
| 364 digests[i] = NULL; |
| 365 *digestsp = digests; |
| 366 |
| 367 PORT_ArenaUnmark(poolp, mark); |
| 368 return SECSuccess; |
390 } | 369 } |
391 | 370 |
392 /* | 371 /* |
393 * XXX Need comment explaining following helper function (which is used | 372 * XXX Need comment explaining following helper function (which is used |
394 * by sec_pkcs7_decoder_start_decrypt). | 373 * by sec_pkcs7_decoder_start_decrypt). |
395 */ | 374 */ |
396 | 375 |
397 static PK11SymKey * | 376 static PK11SymKey *sec_pkcs7_decoder_get_recipient_key( |
398 sec_pkcs7_decoder_get_recipient_key (SEC_PKCS7DecoderContext *p7dcx, | 377 SEC_PKCS7DecoderContext *p7dcx, SEC_PKCS7RecipientInfo **recipientinfos, |
399 » » » » SEC_PKCS7RecipientInfo **recipientinfos, | 378 SEC_PKCS7EncryptedContentInfo *enccinfo) { |
400 » » » » SEC_PKCS7EncryptedContentInfo *enccinfo) | 379 SEC_PKCS7RecipientInfo *ri; |
401 { | 380 CERTCertificate *cert = NULL; |
402 SEC_PKCS7RecipientInfo *ri; | 381 SECKEYPrivateKey *privkey = NULL; |
403 CERTCertificate *cert = NULL; | 382 PK11SymKey *bulkkey = NULL; |
404 SECKEYPrivateKey *privkey = NULL; | 383 SECOidTag keyalgtag, bulkalgtag, encalgtag; |
405 PK11SymKey *bulkkey = NULL; | 384 PK11SlotInfo *slot = NULL; |
406 SECOidTag keyalgtag, bulkalgtag, encalgtag; | 385 |
407 PK11SlotInfo *slot = NULL; | 386 if (recipientinfos == NULL || recipientinfos[0] == NULL) { |
408 | 387 p7dcx->error = SEC_ERROR_NOT_A_RECIPIENT; |
409 if (recipientinfos == NULL || recipientinfos[0] == NULL) { | 388 goto no_key_found; |
410 » p7dcx->error = SEC_ERROR_NOT_A_RECIPIENT; | 389 } |
411 » goto no_key_found; | 390 |
412 } | 391 cert = PK11_FindCertAndKeyByRecipientList(&slot, recipientinfos, &ri, |
413 | 392 &privkey, p7dcx->pwfn_arg); |
414 cert = PK11_FindCertAndKeyByRecipientList(&slot,recipientinfos,&ri, | 393 if (cert == NULL) { |
415 » » » » » » &privkey, p7dcx->pwfn_arg); | 394 p7dcx->error = SEC_ERROR_NOT_A_RECIPIENT; |
416 if (cert == NULL) { | 395 goto no_key_found; |
417 » p7dcx->error = SEC_ERROR_NOT_A_RECIPIENT; | 396 } |
418 » goto no_key_found; | 397 |
419 } | 398 ri->cert = cert; /* so we can find it later */ |
420 | 399 PORT_Assert(privkey != NULL); |
421 ri->cert = cert;» » /* so we can find it later */ | 400 |
422 PORT_Assert(privkey != NULL); | 401 keyalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm)); |
423 | 402 encalgtag = SECOID_GetAlgorithmTag(&(ri->keyEncAlg)); |
424 keyalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm)); | 403 if (keyalgtag != encalgtag) { |
425 encalgtag = SECOID_GetAlgorithmTag (&(ri->keyEncAlg)); | 404 p7dcx->error = SEC_ERROR_PKCS7_KEYALG_MISMATCH; |
426 if (keyalgtag != encalgtag) { | 405 goto no_key_found; |
427 » p7dcx->error = SEC_ERROR_PKCS7_KEYALG_MISMATCH; | 406 } |
428 » goto no_key_found; | 407 bulkalgtag = SECOID_GetAlgorithmTag(&(enccinfo->contentEncAlg)); |
429 } | 408 |
430 bulkalgtag = SECOID_GetAlgorithmTag (&(enccinfo->contentEncAlg)); | 409 switch (encalgtag) { |
431 | 410 case SEC_OID_PKCS1_RSA_ENCRYPTION: |
432 switch (encalgtag) { | 411 bulkkey = PK11_PubUnwrapSymKey(privkey, &ri->encKey, |
433 case SEC_OID_PKCS1_RSA_ENCRYPTION: | 412 PK11_AlgtagToMechanism(bulkalgtag), |
434 » bulkkey = PK11_PubUnwrapSymKey (privkey, &ri->encKey, | 413 CKA_DECRYPT, 0); |
435 » » » » » PK11_AlgtagToMechanism (bulkalgtag), | 414 if (bulkkey == NULL) { |
436 » » » » » CKA_DECRYPT, 0); | 415 p7dcx->error = PORT_GetError(); |
437 » if (bulkkey == NULL) { | 416 PORT_SetError(0); |
438 » p7dcx->error = PORT_GetError(); | 417 goto no_key_found; |
439 » PORT_SetError(0); | 418 } |
440 » goto no_key_found; | 419 break; |
441 » } | 420 default: |
442 » break; | 421 p7dcx->error = SEC_ERROR_UNSUPPORTED_KEYALG; |
443 default: | 422 break; |
444 » p7dcx->error = SEC_ERROR_UNSUPPORTED_KEYALG; | 423 } |
445 » break; | |
446 } | |
447 | 424 |
448 no_key_found: | 425 no_key_found: |
449 if (privkey != NULL) | 426 if (privkey != NULL) SECKEY_DestroyPrivateKey(privkey); |
450 » SECKEY_DestroyPrivateKey (privkey); | 427 if (slot != NULL) PK11_FreeSlot(slot); |
451 if (slot != NULL) | 428 |
452 » PK11_FreeSlot(slot); | 429 return bulkkey; |
453 | 430 } |
454 return bulkkey; | 431 |
455 } | |
456 | |
457 /* | 432 /* |
458 * XXX The following comment is old -- the function used to only handle | 433 * XXX The following comment is old -- the function used to only handle |
459 * EnvelopedData or SignedAndEnvelopedData but now handles EncryptedData | 434 * EnvelopedData or SignedAndEnvelopedData but now handles EncryptedData |
460 * as well (and it had all of the code of the helper function above | 435 * as well (and it had all of the code of the helper function above |
461 * built into it), though the comment was left as is. Fix it... | 436 * built into it), though the comment was left as is. Fix it... |
462 * | 437 * |
463 * We are just about to decode the content of an EnvelopedData. | 438 * We are just about to decode the content of an EnvelopedData. |
464 * Set up a decryption context so we can decrypt as we go. | 439 * Set up a decryption context so we can decrypt as we go. |
465 * Presumably we are one of the recipients listed in "recipientinfos". | 440 * Presumably we are one of the recipients listed in "recipientinfos". |
466 * (XXX And if we are not, or if we have trouble, what should we do? | 441 * (XXX And if we are not, or if we have trouble, what should we do? |
467 * It would be nice to let the decoding still work. Maybe it should | 442 * It would be nice to let the decoding still work. Maybe it should |
468 * be an error if there is a content callback, but not an error otherwise?) | 443 * be an error if there is a content callback, but not an error otherwise?) |
469 * The encryption key and related information can be found in "enccinfo". | 444 * The encryption key and related information can be found in "enccinfo". |
470 */ | 445 */ |
471 static SECStatus | 446 static SECStatus sec_pkcs7_decoder_start_decrypt( |
472 sec_pkcs7_decoder_start_decrypt (SEC_PKCS7DecoderContext *p7dcx, int depth, | 447 SEC_PKCS7DecoderContext *p7dcx, int depth, |
473 » » » » SEC_PKCS7RecipientInfo **recipientinfos, | 448 SEC_PKCS7RecipientInfo **recipientinfos, |
474 » » » » SEC_PKCS7EncryptedContentInfo *enccinfo, | 449 SEC_PKCS7EncryptedContentInfo *enccinfo, |
475 » » » » PK11SymKey **copy_key_for_signature) | 450 PK11SymKey **copy_key_for_signature) { |
476 { | 451 PK11SymKey *bulkkey = NULL; |
477 PK11SymKey *bulkkey = NULL; | 452 sec_PKCS7CipherObject *decryptobj; |
478 sec_PKCS7CipherObject *decryptobj; | 453 |
479 | 454 /* |
480 /* | 455 * If a callback is supplied to retrieve the encryption key, |
481 * If a callback is supplied to retrieve the encryption key,· | 456 * for instance, for Encrypted Content infos, then retrieve |
482 * for instance, for Encrypted Content infos, then retrieve | 457 * the bulkkey from the callback. Otherwise, assume that |
483 * the bulkkey from the callback. Otherwise, assume that | 458 * we are processing Enveloped or SignedAndEnveloped data |
484 * we are processing Enveloped or SignedAndEnveloped data | 459 * content infos. |
485 * content infos. | 460 * |
486 * | 461 * XXX Put an assert here? |
487 * XXX Put an assert here? | 462 */ |
488 */ | 463 if (SEC_PKCS7ContentType(p7dcx->cinfo) == SEC_OID_PKCS7_ENCRYPTED_DATA) { |
489 if (SEC_PKCS7ContentType(p7dcx->cinfo) == SEC_OID_PKCS7_ENCRYPTED_DATA) { | 464 if (p7dcx->dkcb != NULL) { |
490 » if (p7dcx->dkcb != NULL) { | 465 bulkkey = (*p7dcx->dkcb)(p7dcx->dkcb_arg, &(enccinfo->contentEncAlg)); |
491 » bulkkey = (*p7dcx->dkcb)(p7dcx->dkcb_arg, | 466 } |
492 » » » » &(enccinfo->contentEncAlg)); | 467 enccinfo->keysize = 0; |
493 » } | 468 } else { |
494 » enccinfo->keysize = 0; | 469 bulkkey = |
495 } else { | 470 sec_pkcs7_decoder_get_recipient_key(p7dcx, recipientinfos, enccinfo); |
496 » bulkkey = sec_pkcs7_decoder_get_recipient_key (p7dcx, recipientinfos, | 471 if (bulkkey == NULL) goto no_decryption; |
497 » » » » » » enccinfo); | 472 enccinfo->keysize = |
498 » if (bulkkey == NULL) goto no_decryption; | 473 PK11_GetKeyStrength(bulkkey, &(enccinfo->contentEncAlg)); |
499 » enccinfo->keysize = PK11_GetKeyStrength(bulkkey, | 474 } |
500 » » » » » » &(enccinfo->contentEncAlg)); | 475 |
501 | 476 /* |
502 } | 477 * XXX I think following should set error in p7dcx and clear set error |
503 | 478 * (as used to be done here, or as is done in get_receipient_key above. |
504 /* | 479 */ |
505 * XXX I think following should set error in p7dcx and clear set error | 480 if (bulkkey == NULL) { |
506 * (as used to be done here, or as is done in get_receipient_key above. | 481 goto no_decryption; |
507 */ | 482 } |
508 if(bulkkey == NULL) { | 483 |
509 » goto no_decryption; | 484 /* |
510 } | 485 * We want to make sure decryption is allowed. This is done via |
511 ···· | 486 * a callback specified in SEC_PKCS7DecoderStart(). |
512 /*· | 487 */ |
513 * We want to make sure decryption is allowed. This is done via | 488 if (p7dcx->decrypt_allowed_cb) { |
514 * a callback specified in SEC_PKCS7DecoderStart(). | 489 if ((*p7dcx->decrypt_allowed_cb)(&(enccinfo->contentEncAlg), bulkkey) == |
515 */ | 490 PR_FALSE) { |
516 if (p7dcx->decrypt_allowed_cb) { | 491 p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED; |
517 » if ((*p7dcx->decrypt_allowed_cb) (&(enccinfo->contentEncAlg), | 492 goto no_decryption; |
518 » » » » » bulkkey) == PR_FALSE) { | 493 } |
519 » p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED; | 494 } else { |
520 » goto no_decryption; | 495 p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED; |
521 » } | 496 goto no_decryption; |
522 } else { | 497 } |
523 » p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED; | 498 |
524 » goto no_decryption; | 499 /* |
525 } | 500 * When decrypting a signedAndEnvelopedData, the signature also has |
526 | 501 * to be decrypted with the bulk encryption key; to avoid having to |
527 /* | 502 * get it all over again later (and do another potentially expensive |
528 * When decrypting a signedAndEnvelopedData, the signature also has | 503 * RSA operation), copy it for later signature verification to use. |
529 * to be decrypted with the bulk encryption key; to avoid having to | 504 */ |
530 * get it all over again later (and do another potentially expensive | 505 if (copy_key_for_signature != NULL) |
531 * RSA operation), copy it for later signature verification to use. | 506 *copy_key_for_signature = PK11_ReferenceSymKey(bulkkey); |
532 */ | 507 |
533 if (copy_key_for_signature != NULL) | 508 /* |
534 » *copy_key_for_signature = PK11_ReferenceSymKey (bulkkey); | 509 * Now we have the bulk encryption key (in bulkkey) and the |
535 | 510 * the algorithm (in enccinfo->contentEncAlg). Using those, |
536 /* | 511 * create a decryption context. |
537 * Now we have the bulk encryption key (in bulkkey) and the | 512 */ |
538 * the algorithm (in enccinfo->contentEncAlg). Using those, | 513 decryptobj = |
539 * create a decryption context. | 514 sec_PKCS7CreateDecryptObject(bulkkey, &(enccinfo->contentEncAlg)); |
540 */ | 515 |
541 decryptobj = sec_PKCS7CreateDecryptObject (bulkkey, | 516 /* |
542 » » » » » &(enccinfo->contentEncAlg)); | 517 * We are done with (this) bulkkey now. |
543 | 518 */ |
544 /* | 519 PK11_FreeSymKey(bulkkey); |
545 * We are done with (this) bulkkey now. | 520 |
546 */ | 521 if (decryptobj == NULL) { |
547 PK11_FreeSymKey (bulkkey); | 522 p7dcx->error = PORT_GetError(); |
548 | 523 PORT_SetError(0); |
549 if (decryptobj == NULL) { | 524 goto no_decryption; |
550 » p7dcx->error = PORT_GetError(); | 525 } |
551 » PORT_SetError(0); | 526 |
552 » goto no_decryption; | 527 SEC_ASN1DecoderSetFilterProc(p7dcx->dcx, sec_pkcs7_decoder_filter, p7dcx, |
553 } | 528 (PRBool)(p7dcx->cb != NULL)); |
554 | 529 |
555 SEC_ASN1DecoderSetFilterProc (p7dcx->dcx, | 530 p7dcx->worker.depth = depth; |
556 » » » » sec_pkcs7_decoder_filter, | 531 p7dcx->worker.decryptobj = decryptobj; |
557 » » » » p7dcx, | 532 |
558 » » » » (PRBool)(p7dcx->cb != NULL)); | 533 return SECSuccess; |
559 | |
560 p7dcx->worker.depth = depth; | |
561 p7dcx->worker.decryptobj = decryptobj; | |
562 | |
563 return SECSuccess; | |
564 | 534 |
565 no_decryption: | 535 no_decryption: |
566 /* | 536 /* |
567 * For some reason (error set already, if appropriate), we cannot | 537 * For some reason (error set already, if appropriate), we cannot |
568 * decrypt the content. I am not sure what exactly is the right | 538 * decrypt the content. I am not sure what exactly is the right |
569 * thing to do here; in some cases we want to just stop, and in | 539 * thing to do here; in some cases we want to just stop, and in |
570 * others we want to let the decoding finish even though we cannot | 540 * others we want to let the decoding finish even though we cannot |
571 * decrypt the content. My current thinking is that if the caller | 541 * decrypt the content. My current thinking is that if the caller |
572 * set up a content callback, then they are really interested in | 542 * set up a content callback, then they are really interested in |
573 * getting (decrypted) content, and if they cannot they will want | 543 * getting (decrypted) content, and if they cannot they will want |
574 * to know about it. However, if no callback was specified, then | 544 * to know about it. However, if no callback was specified, then |
575 * maybe it is not important that the decryption failed. | 545 * maybe it is not important that the decryption failed. |
576 */ | 546 */ |
577 if (p7dcx->cb != NULL) | 547 if (p7dcx->cb != NULL) |
578 return SECFailure; | 548 return SECFailure; |
579 else | 549 else |
580 return SECSuccess; /* Let the decoding continue. */ | 550 return SECSuccess; /* Let the decoding continue. */ |
581 } | 551 } |
582 | 552 |
583 | 553 static SECStatus sec_pkcs7_decoder_finish_decrypt( |
584 static SECStatus | 554 SEC_PKCS7DecoderContext *p7dcx, PLArenaPool *poolp, |
585 sec_pkcs7_decoder_finish_decrypt (SEC_PKCS7DecoderContext *p7dcx, | 555 SEC_PKCS7EncryptedContentInfo *enccinfo) { |
586 PLArenaPool *poolp, | 556 struct sec_pkcs7_decoder_worker *worker; |
587 SEC_PKCS7EncryptedContentInfo *enccinfo) | 557 |
588 { | 558 /* |
589 struct sec_pkcs7_decoder_worker *worker; | 559 * XXX Handling nested contents would mean that there is a chain |
590 | 560 * of workers -- one per each level of content. The following |
591 /* | 561 * would want to find the last worker in the chain. |
592 * XXX Handling nested contents would mean that there is a chain | 562 */ |
593 * of workers -- one per each level of content. The following | 563 worker = &(p7dcx->worker); |
594 * would want to find the last worker in the chain. | 564 |
595 */ | 565 /* |
596 worker = &(p7dcx->worker); | 566 * If no decryption context, then we have nothing to do. |
597 | 567 */ |
598 /* | 568 if (worker->decryptobj == NULL) return SECSuccess; |
599 * If no decryption context, then we have nothing to do. | 569 |
600 */ | 570 /* |
601 if (worker->decryptobj == NULL) | 571 * No matter what happens after this, we want to stop filtering. |
602 return SECSuccess; | 572 * XXX If we handle nested contents, we only want to stop filtering |
603 | 573 * if we are finishing off the *last* worker. |
604 /* | 574 */ |
605 * No matter what happens after this, we want to stop filtering. | 575 SEC_ASN1DecoderClearFilterProc(p7dcx->dcx); |
606 * XXX If we handle nested contents, we only want to stop filtering | 576 |
607 * if we are finishing off the *last* worker. | 577 /* |
608 */ | 578 * Handle the last block. |
609 SEC_ASN1DecoderClearFilterProc (p7dcx->dcx); | 579 */ |
610 | 580 sec_pkcs7_decoder_work_data(p7dcx, worker, NULL, 0, PR_TRUE); |
611 /* | 581 |
612 * Handle the last block. | 582 /* |
613 */ | 583 * All done, destroy it. |
614 sec_pkcs7_decoder_work_data (p7dcx, worker, NULL, 0, PR_TRUE); | 584 */ |
615 | 585 sec_PKCS7DestroyDecryptObject(worker->decryptobj); |
616 /* | 586 worker->decryptobj = NULL; |
617 * All done, destroy it. | 587 |
618 */ | 588 return SECSuccess; |
619 sec_PKCS7DestroyDecryptObject (worker->decryptobj); | 589 } |
620 worker->decryptobj = NULL; | 590 |
621 | 591 static void sec_pkcs7_decoder_notify(void *arg, PRBool before, void *dest, |
622 return SECSuccess; | 592 int depth) { |
623 } | 593 SEC_PKCS7DecoderContext *p7dcx; |
624 | 594 SEC_PKCS7ContentInfo *cinfo; |
625 | 595 SEC_PKCS7SignedData *sigd; |
626 static void | 596 SEC_PKCS7EnvelopedData *envd; |
627 sec_pkcs7_decoder_notify (void *arg, PRBool before, void *dest, int depth) | 597 SEC_PKCS7SignedAndEnvelopedData *saed; |
628 { | 598 SEC_PKCS7EncryptedData *encd; |
629 SEC_PKCS7DecoderContext *p7dcx; | 599 SEC_PKCS7DigestedData *digd; |
630 SEC_PKCS7ContentInfo *cinfo; | 600 PRBool after; |
631 SEC_PKCS7SignedData *sigd; | 601 SECStatus rv; |
632 SEC_PKCS7EnvelopedData *envd; | 602 |
633 SEC_PKCS7SignedAndEnvelopedData *saed; | 603 /* |
634 SEC_PKCS7EncryptedData *encd; | 604 * Just to make the code easier to read, create an "after" variable |
635 SEC_PKCS7DigestedData *digd; | 605 * that is equivalent to "not before". |
636 PRBool after; | 606 * (This used to be just the statement "after = !before", but that |
637 SECStatus rv; | 607 * causes a warning on the mac; to avoid that, we do it the long way.) |
638 | 608 */ |
639 /* | 609 if (before) |
640 * Just to make the code easier to read, create an "after" variable | 610 after = PR_FALSE; |
641 * that is equivalent to "not before". | 611 else |
642 * (This used to be just the statement "after = !before", but that | 612 after = PR_TRUE; |
643 * causes a warning on the mac; to avoid that, we do it the long way.) | 613 |
644 */ | 614 p7dcx = (SEC_PKCS7DecoderContext *)arg; |
645 if (before) | 615 cinfo = p7dcx->cinfo; |
646 after = PR_FALSE; | 616 |
647 else | 617 if (cinfo->contentTypeTag == NULL) { |
648 after = PR_TRUE; | 618 if (after && dest == &(cinfo->contentType)) |
649 | 619 cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType)); |
650 p7dcx = (SEC_PKCS7DecoderContext*)arg; | 620 return; |
651 cinfo = p7dcx->cinfo; | 621 } |
652 | 622 |
653 if (cinfo->contentTypeTag == NULL) { | 623 switch (cinfo->contentTypeTag->offset) { |
654 if (after && dest == &(cinfo->contentType)) | 624 case SEC_OID_PKCS7_SIGNED_DATA: |
655 cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType)); | 625 sigd = cinfo->content.signedData; |
656 return; | 626 if (sigd == NULL) break; |
657 } | 627 |
658 | 628 if (sigd->contentInfo.contentTypeTag == NULL) { |
659 switch (cinfo->contentTypeTag->offset) { | 629 if (after && dest == &(sigd->contentInfo.contentType)) |
660 case SEC_OID_PKCS7_SIGNED_DATA: | 630 sigd->contentInfo.contentTypeTag = |
661 sigd = cinfo->content.signedData; | 631 SECOID_FindOID(&(sigd->contentInfo.contentType)); |
662 if (sigd == NULL) | 632 break; |
663 break; | 633 } |
664 | 634 |
665 if (sigd->contentInfo.contentTypeTag == NULL) { | 635 /* |
666 if (after && dest == &(sigd->contentInfo.contentType)) | 636 * We only set up a filtering digest if the content is |
667 sigd->contentInfo.contentTypeTag = | 637 * plain DATA; anything else needs more work because a |
668 SECOID_FindOID(&(sigd->contentInfo.contentType)); | 638 * second pass is required to produce a DER encoding from |
669 break; | 639 * an input that can be BER encoded. (This is a requirement |
670 } | 640 * of PKCS7 that is unfortunate, but there you have it.) |
671 | 641 * |
672 /* | 642 * XXX Also, since we stop here if this is not DATA, the |
673 * We only set up a filtering digest if the content is | 643 * inner content is not getting processed at all. Someday |
674 * plain DATA; anything else needs more work because a | 644 * we may want to fix that. |
675 * second pass is required to produce a DER encoding from | 645 */ |
676 * an input that can be BER encoded. (This is a requirement | 646 if (sigd->contentInfo.contentTypeTag->offset != SEC_OID_PKCS7_DATA) { |
677 * of PKCS7 that is unfortunate, but there you have it.) | 647 /* XXX Set an error in p7dcx->error */ |
678 * | 648 SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx); |
679 * XXX Also, since we stop here if this is not DATA, the | 649 break; |
680 * inner content is not getting processed at all. Someday | 650 } |
681 * we may want to fix that. | 651 |
682 */ | 652 /* |
683 if (sigd->contentInfo.contentTypeTag->offset != SEC_OID_PKCS7_DATA) { | 653 * Just before the content, we want to set up a digest context |
684 /* XXX Set an error in p7dcx->error */ | 654 * for each digest algorithm listed, and start a filter which |
685 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); | 655 * will run all of the contents bytes through that digest. |
686 break; | 656 */ |
687 } | 657 if (before && dest == &(sigd->contentInfo.content)) { |
688 | 658 rv = sec_pkcs7_decoder_start_digests(p7dcx, depth, |
689 /* | 659 sigd->digestAlgorithms); |
690 * Just before the content, we want to set up a digest context | 660 if (rv != SECSuccess) SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx); |
691 * for each digest algorithm listed, and start a filter which | 661 |
692 * will run all of the contents bytes through that digest. | 662 break; |
693 */ | 663 } |
694 if (before && dest == &(sigd->contentInfo.content)) { | 664 |
695 rv = sec_pkcs7_decoder_start_digests (p7dcx, depth, | 665 /* |
696 sigd->digestAlgorithms); | 666 * XXX To handle nested types, here is where we would want |
697 if (rv != SECSuccess) | 667 * to check for inner boundaries that need handling. |
698 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); | 668 */ |
699 | 669 |
700 break; | 670 /* |
701 } | 671 * Are we done? |
702 | 672 */ |
703 /* | 673 if (after && dest == &(sigd->contentInfo.content)) { |
704 * XXX To handle nested types, here is where we would want | 674 /* |
705 * to check for inner boundaries that need handling. | 675 * Close out the digest contexts. We ignore any error |
706 */ | 676 * because we are stopping anyway; the error status left |
707 | 677 * behind in p7dcx will be seen by outer functions. |
708 /* | 678 */ |
709 * Are we done? | 679 (void)sec_pkcs7_decoder_finish_digests(p7dcx, cinfo->poolp, |
710 */ | 680 &(sigd->digests)); |
711 if (after && dest == &(sigd->contentInfo.content)) { | 681 |
712 /* | 682 /* |
713 * Close out the digest contexts. We ignore any error | 683 * XXX To handle nested contents, we would need to remove |
714 * because we are stopping anyway; the error status left | 684 * the worker from the chain (and free it). |
715 * behind in p7dcx will be seen by outer functions. | 685 */ |
716 */ | 686 |
717 (void) sec_pkcs7_decoder_finish_digests (p7dcx, cinfo->poolp, | 687 /* |
718 &(sigd->digests)); | 688 * Stop notify. |
719 | 689 */ |
720 /* | 690 SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx); |
721 * XXX To handle nested contents, we would need to remove | 691 } |
722 * the worker from the chain (and free it). | 692 break; |
723 */ | 693 |
724 | 694 case SEC_OID_PKCS7_ENVELOPED_DATA: |
725 /* | 695 envd = cinfo->content.envelopedData; |
726 * Stop notify. | 696 if (envd == NULL) break; |
727 */ | 697 |
728 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); | 698 if (envd->encContentInfo.contentTypeTag == NULL) { |
729 } | 699 if (after && dest == &(envd->encContentInfo.contentType)) |
730 break; | 700 envd->encContentInfo.contentTypeTag = |
731 | 701 SECOID_FindOID(&(envd->encContentInfo.contentType)); |
732 case SEC_OID_PKCS7_ENVELOPED_DATA: | 702 break; |
733 envd = cinfo->content.envelopedData; | 703 } |
734 if (envd == NULL) | 704 |
735 break; | 705 /* |
736 | 706 * Just before the content, we want to set up a decryption |
737 if (envd->encContentInfo.contentTypeTag == NULL) { | 707 * context, and start a filter which will run all of the |
738 if (after && dest == &(envd->encContentInfo.contentType)) | 708 * contents bytes through it to determine the plain content. |
739 envd->encContentInfo.contentTypeTag = | 709 */ |
740 SECOID_FindOID(&(envd->encContentInfo.contentType)); | 710 if (before && dest == &(envd->encContentInfo.encContent)) { |
741 break; | 711 rv = sec_pkcs7_decoder_start_decrypt(p7dcx, depth, envd->recipientInfos, |
742 } | 712 &(envd->encContentInfo), NULL); |
743 | 713 if (rv != SECSuccess) SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx); |
744 /* | 714 |
745 * Just before the content, we want to set up a decryption | 715 break; |
746 * context, and start a filter which will run all of the | 716 } |
747 * contents bytes through it to determine the plain content. | 717 |
748 */ | 718 /* |
749 if (before && dest == &(envd->encContentInfo.encContent)) { | 719 * Are we done? |
750 rv = sec_pkcs7_decoder_start_decrypt (p7dcx, depth, | 720 */ |
751 envd->recipientInfos, | 721 if (after && dest == &(envd->encContentInfo.encContent)) { |
752 &(envd->encContentInfo), | 722 /* |
753 NULL); | 723 * Close out the decryption context. We ignore any error |
754 if (rv != SECSuccess) | 724 * because we are stopping anyway; the error status left |
755 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); | 725 * behind in p7dcx will be seen by outer functions. |
756 | 726 */ |
757 break; | 727 (void)sec_pkcs7_decoder_finish_decrypt(p7dcx, cinfo->poolp, |
758 } | 728 &(envd->encContentInfo)); |
759 | 729 |
760 /* | 730 /* |
761 * Are we done? | 731 * XXX To handle nested contents, we would need to remove |
762 */ | 732 * the worker from the chain (and free it). |
763 if (after && dest == &(envd->encContentInfo.encContent)) { | 733 */ |
764 /* | 734 |
765 * Close out the decryption context. We ignore any error | 735 /* |
766 * because we are stopping anyway; the error status left | 736 * Stop notify. |
767 * behind in p7dcx will be seen by outer functions. | 737 */ |
768 */ | 738 SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx); |
769 (void) sec_pkcs7_decoder_finish_decrypt (p7dcx, cinfo->poolp, | 739 } |
770 &(envd->encContentInfo)); | 740 break; |
771 | 741 |
772 /* | 742 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: |
773 * XXX To handle nested contents, we would need to remove | 743 saed = cinfo->content.signedAndEnvelopedData; |
774 * the worker from the chain (and free it). | 744 if (saed == NULL) break; |
775 */ | 745 |
776 | 746 if (saed->encContentInfo.contentTypeTag == NULL) { |
777 /* | 747 if (after && dest == &(saed->encContentInfo.contentType)) |
778 * Stop notify. | 748 saed->encContentInfo.contentTypeTag = |
779 */ | 749 SECOID_FindOID(&(saed->encContentInfo.contentType)); |
780 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); | 750 break; |
781 } | 751 } |
782 break; | 752 |
783 | 753 /* |
784 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | 754 * Just before the content, we want to set up a decryption |
785 saed = cinfo->content.signedAndEnvelopedData; | 755 * context *and* digest contexts, and start a filter which |
786 if (saed == NULL) | 756 * will run all of the contents bytes through both. |
787 break; | 757 */ |
788 | 758 if (before && dest == &(saed->encContentInfo.encContent)) { |
789 if (saed->encContentInfo.contentTypeTag == NULL) { | 759 rv = sec_pkcs7_decoder_start_decrypt(p7dcx, depth, saed->recipientInfos, |
790 if (after && dest == &(saed->encContentInfo.contentType)) | 760 &(saed->encContentInfo), |
791 saed->encContentInfo.contentTypeTag = | 761 &(saed->sigKey)); |
792 SECOID_FindOID(&(saed->encContentInfo.contentType)); | 762 if (rv == SECSuccess) |
793 break; | 763 rv = sec_pkcs7_decoder_start_digests(p7dcx, depth, |
794 } | 764 saed->digestAlgorithms); |
795 | 765 if (rv != SECSuccess) SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx); |
796 /* | 766 |
797 * Just before the content, we want to set up a decryption | 767 break; |
798 * context *and* digest contexts, and start a filter which | 768 } |
799 * will run all of the contents bytes through both. | 769 |
800 */ | 770 /* |
801 if (before && dest == &(saed->encContentInfo.encContent)) { | 771 * Are we done? |
802 rv = sec_pkcs7_decoder_start_decrypt (p7dcx, depth, | 772 */ |
803 saed->recipientInfos, | 773 if (after && dest == &(saed->encContentInfo.encContent)) { |
804 &(saed->encContentInfo), | 774 /* |
805 &(saed->sigKey)); | 775 * Close out the decryption and digests contexts. |
806 if (rv == SECSuccess) | 776 * We ignore any errors because we are stopping anyway; |
807 rv = sec_pkcs7_decoder_start_digests (p7dcx, depth, | 777 * the error status left behind in p7dcx will be seen by |
808 saed->digestAlgorithms); | 778 * outer functions. |
809 if (rv != SECSuccess) | 779 * |
810 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); | 780 * Note that the decrypt stuff must be called first; |
811 | 781 * it may have a last buffer to do which in turn has |
812 break; | 782 * to be added to the digest. |
813 } | 783 */ |
814 | 784 (void)sec_pkcs7_decoder_finish_decrypt(p7dcx, cinfo->poolp, |
815 /* | 785 &(saed->encContentInfo)); |
816 * Are we done? | 786 (void)sec_pkcs7_decoder_finish_digests(p7dcx, cinfo->poolp, |
817 */ | 787 &(saed->digests)); |
818 if (after && dest == &(saed->encContentInfo.encContent)) { | 788 |
819 /* | 789 /* |
820 * Close out the decryption and digests contexts. | 790 * XXX To handle nested contents, we would need to remove |
821 * We ignore any errors because we are stopping anyway; | 791 * the worker from the chain (and free it). |
822 * the error status left behind in p7dcx will be seen by | 792 */ |
823 * outer functions. | 793 |
824 * | 794 /* |
825 * Note that the decrypt stuff must be called first; | 795 * Stop notify. |
826 * it may have a last buffer to do which in turn has | 796 */ |
827 * to be added to the digest. | 797 SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx); |
828 */ | 798 } |
829 (void) sec_pkcs7_decoder_finish_decrypt (p7dcx, cinfo->poolp, | 799 break; |
830 &(saed->encContentInfo)); | 800 |
831 (void) sec_pkcs7_decoder_finish_digests (p7dcx, cinfo->poolp, | 801 case SEC_OID_PKCS7_DIGESTED_DATA: |
832 &(saed->digests)); | 802 digd = cinfo->content.digestedData; |
833 | 803 |
834 /* | 804 /* |
835 * XXX To handle nested contents, we would need to remove | 805 * XXX Want to do the digest or not? Maybe future enhancement... |
836 * the worker from the chain (and free it). | 806 */ |
837 */ | 807 if (before && dest == &(digd->contentInfo.content.data)) { |
838 | 808 SEC_ASN1DecoderSetFilterProc(p7dcx->dcx, sec_pkcs7_decoder_filter, |
839 /* | 809 p7dcx, (PRBool)(p7dcx->cb != NULL)); |
840 * Stop notify. | 810 break; |
841 */ | 811 } |
842 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); | 812 |
843 } | 813 /* |
844 break; | 814 * Are we done? |
845 | 815 */ |
846 case SEC_OID_PKCS7_DIGESTED_DATA: | 816 if (after && dest == &(digd->contentInfo.content.data)) { |
847 digd = cinfo->content.digestedData; | 817 SEC_ASN1DecoderClearFilterProc(p7dcx->dcx); |
848 ········ | 818 } |
849 /*· | 819 break; |
850 * XXX Want to do the digest or not? Maybe future enhancement... | 820 |
851 */ | 821 case SEC_OID_PKCS7_ENCRYPTED_DATA: |
852 if (before && dest == &(digd->contentInfo.content.data)) { | 822 encd = cinfo->content.encryptedData; |
853 SEC_ASN1DecoderSetFilterProc (p7dcx->dcx, sec_pkcs7_decoder_filter, | 823 |
854 p7dcx, | 824 /* |
855 (PRBool)(p7dcx->cb != NULL)); | 825 * XXX If the decryption key callback is set, we want to start |
856 break; | 826 * the decryption. If the callback is not set, we will treat the |
857 } | 827 * content as plain data, since we do not have the key. |
858 | 828 * |
859 /* | 829 * Is this the proper thing to do? |
860 * Are we done? | 830 */ |
861 */ | 831 if (before && dest == &(encd->encContentInfo.encContent)) { |
862 if (after && dest == &(digd->contentInfo.content.data)) { | 832 /* |
863 SEC_ASN1DecoderClearFilterProc (p7dcx->dcx); | 833 * Start the encryption process if the decryption key callback |
864 } | 834 * is present. Otherwise, treat the content like plain data. |
865 break; | 835 */ |
866 | 836 rv = SECSuccess; |
867 case SEC_OID_PKCS7_ENCRYPTED_DATA: | 837 if (p7dcx->dkcb != NULL) { |
868 encd = cinfo->content.encryptedData; | 838 rv = sec_pkcs7_decoder_start_decrypt(p7dcx, depth, NULL, |
869 | 839 &(encd->encContentInfo), NULL); |
870 /* | 840 } |
871 * XXX If the decryption key callback is set, we want to start | 841 |
872 * the decryption. If the callback is not set, we will treat the | 842 if (rv != SECSuccess) SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx); |
873 * content as plain data, since we do not have the key. | 843 |
874 * | 844 break; |
875 * Is this the proper thing to do? | 845 } |
876 */ | 846 |
877 if (before && dest == &(encd->encContentInfo.encContent)) { | 847 /* |
878 /* | 848 * Are we done? |
879 * Start the encryption process if the decryption key callback | 849 */ |
880 * is present. Otherwise, treat the content like plain data. | 850 if (after && dest == &(encd->encContentInfo.encContent)) { |
881 */ | 851 /* |
882 rv = SECSuccess; | 852 * Close out the decryption context. We ignore any error |
883 if (p7dcx->dkcb != NULL) { | 853 * because we are stopping anyway; the error status left |
884 rv = sec_pkcs7_decoder_start_decrypt (p7dcx, depth, NULL, | 854 * behind in p7dcx will be seen by outer functions. |
885 &(encd->encContentInfo), | 855 */ |
886 NULL); | 856 (void)sec_pkcs7_decoder_finish_decrypt(p7dcx, cinfo->poolp, |
887 } | 857 &(encd->encContentInfo)); |
888 | 858 |
889 if (rv != SECSuccess) | 859 /* |
890 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); | 860 * Stop notify. |
891 ················ | 861 */ |
892 break; | 862 SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx); |
893 } | 863 } |
894 | 864 break; |
895 /* | 865 |
896 * Are we done? | 866 case SEC_OID_PKCS7_DATA: |
897 */ | 867 /* |
898 if (after && dest == &(encd->encContentInfo.encContent)) { | 868 * If a output callback has been specified, we want to set the filter |
899 /* | 869 * to call the callback. This is taken care of in |
900 * Close out the decryption context. We ignore any error | 870 * sec_pkcs7_decoder_start_decrypt() or |
901 * because we are stopping anyway; the error status left | 871 * sec_pkcs7_decoder_start_digests() for the other content types. |
902 * behind in p7dcx will be seen by outer functions. | 872 */ |
903 */ | 873 |
904 (void) sec_pkcs7_decoder_finish_decrypt (p7dcx, cinfo->poolp, | 874 if (before && dest == &(cinfo->content.data)) { |
905 &(encd->encContentInfo)); | 875 |
906 | 876 /* |
907 /* | 877 * Set the filter proc up. |
908 * Stop notify. | 878 */ |
909 */ | 879 SEC_ASN1DecoderSetFilterProc(p7dcx->dcx, sec_pkcs7_decoder_filter, |
910 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); | 880 p7dcx, (PRBool)(p7dcx->cb != NULL)); |
911 } | 881 break; |
912 break; | 882 } |
913 | 883 |
914 case SEC_OID_PKCS7_DATA: | 884 if (after && dest == &(cinfo->content.data)) { |
915 /* | 885 /* |
916 * If a output callback has been specified, we want to set the filter | 886 * Time to clean up after ourself, stop the Notify and Filter |
917 * to call the callback. This is taken care of in· | 887 * procedures. |
918 * sec_pkcs7_decoder_start_decrypt() or· | 888 */ |
919 * sec_pkcs7_decoder_start_digests() for the other content types. | 889 SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx); |
920 */· | 890 SEC_ASN1DecoderClearFilterProc(p7dcx->dcx); |
921 ········ | 891 } |
922 if (before && dest == &(cinfo->content.data)) { | 892 break; |
923 | 893 |
924 /*· | 894 default: |
925 * Set the filter proc up. | 895 SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx); |
926 */ | 896 break; |
927 SEC_ASN1DecoderSetFilterProc (p7dcx->dcx, | 897 } |
928 sec_pkcs7_decoder_filter, | 898 } |
929 p7dcx, | 899 |
930 (PRBool)(p7dcx->cb != NULL)); | 900 SEC_PKCS7DecoderContext *SEC_PKCS7DecoderStart( |
931 break; | 901 SEC_PKCS7DecoderContentCallback cb, void *cb_arg, SECKEYGetPasswordKey pwfn, |
932 } | 902 void *pwfn_arg, SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb, |
933 | 903 void *decrypt_key_cb_arg, |
934 if (after && dest == &(cinfo->content.data)) { | 904 SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb) { |
935 /* | 905 SEC_PKCS7DecoderContext *p7dcx; |
936 * Time to clean up after ourself, stop the Notify and Filter | 906 SEC_ASN1DecoderContext *dcx; |
937 * procedures. | 907 SEC_PKCS7ContentInfo *cinfo; |
938 */ | 908 PLArenaPool *poolp; |
939 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); | 909 |
940 SEC_ASN1DecoderClearFilterProc (p7dcx->dcx); | 910 poolp = PORT_NewArena(1024); /* XXX what is right value? */ |
941 } | 911 if (poolp == NULL) return NULL; |
942 break; | 912 |
943 | 913 cinfo = (SEC_PKCS7ContentInfo *)PORT_ArenaZAlloc(poolp, sizeof(*cinfo)); |
944 default: | 914 if (cinfo == NULL) { |
945 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); | 915 PORT_FreeArena(poolp, PR_FALSE); |
946 break; | 916 return NULL; |
947 } | 917 } |
948 } | 918 |
949 | 919 cinfo->poolp = poolp; |
950 | 920 cinfo->pwfn = pwfn; |
951 SEC_PKCS7DecoderContext * | 921 cinfo->pwfn_arg = pwfn_arg; |
952 SEC_PKCS7DecoderStart(SEC_PKCS7DecoderContentCallback cb, void *cb_arg, | 922 cinfo->created = PR_FALSE; |
953 SECKEYGetPasswordKey pwfn, void *pwfn_arg, | 923 cinfo->refCount = 1; |
954 SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb,· | 924 |
955 void *decrypt_key_cb_arg, | 925 p7dcx = |
956 SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb) | 926 (SEC_PKCS7DecoderContext *)PORT_ZAlloc(sizeof(SEC_PKCS7DecoderContext)); |
957 { | 927 if (p7dcx == NULL) { |
958 SEC_PKCS7DecoderContext *p7dcx; | 928 PORT_FreeArena(poolp, PR_FALSE); |
959 SEC_ASN1DecoderContext *dcx; | 929 return NULL; |
960 SEC_PKCS7ContentInfo *cinfo; | 930 } |
961 PLArenaPool *poolp; | 931 |
962 | 932 p7dcx->tmp_poolp = PORT_NewArena(1024); /* XXX what is right value? */ |
963 poolp = PORT_NewArena (1024); /* XXX what is right value? */ | 933 if (p7dcx->tmp_poolp == NULL) { |
964 if (poolp == NULL) | 934 PORT_Free(p7dcx); |
965 return NULL; | 935 PORT_FreeArena(poolp, PR_FALSE); |
966 | 936 return NULL; |
967 cinfo = (SEC_PKCS7ContentInfo*)PORT_ArenaZAlloc (poolp, sizeof(*cinfo)); | 937 } |
968 if (cinfo == NULL) { | 938 |
969 PORT_FreeArena (poolp, PR_FALSE); | 939 dcx = SEC_ASN1DecoderStart(poolp, cinfo, sec_PKCS7ContentInfoTemplate); |
970 return NULL; | 940 if (dcx == NULL) { |
971 } | 941 PORT_FreeArena(p7dcx->tmp_poolp, PR_FALSE); |
972 | 942 PORT_Free(p7dcx); |
973 cinfo->poolp = poolp; | 943 PORT_FreeArena(poolp, PR_FALSE); |
974 cinfo->pwfn = pwfn; | 944 return NULL; |
975 cinfo->pwfn_arg = pwfn_arg; | 945 } |
976 cinfo->created = PR_FALSE; | 946 |
977 cinfo->refCount = 1; | 947 SEC_ASN1DecoderSetNotifyProc(dcx, sec_pkcs7_decoder_notify, p7dcx); |
978 | 948 |
979 p7dcx =· | 949 p7dcx->dcx = dcx; |
980 (SEC_PKCS7DecoderContext*)PORT_ZAlloc (sizeof(SEC_PKCS7DecoderContext)); | 950 p7dcx->cinfo = cinfo; |
981 if (p7dcx == NULL) { | 951 p7dcx->cb = cb; |
982 PORT_FreeArena (poolp, PR_FALSE); | 952 p7dcx->cb_arg = cb_arg; |
983 return NULL; | 953 p7dcx->pwfn = pwfn; |
984 } | 954 p7dcx->pwfn_arg = pwfn_arg; |
985 | 955 p7dcx->dkcb = decrypt_key_cb; |
986 p7dcx->tmp_poolp = PORT_NewArena (1024); /* XXX what is right value? */ | 956 p7dcx->dkcb_arg = decrypt_key_cb_arg; |
987 if (p7dcx->tmp_poolp == NULL) { | 957 p7dcx->decrypt_allowed_cb = decrypt_allowed_cb; |
988 PORT_Free (p7dcx); | 958 |
989 PORT_FreeArena (poolp, PR_FALSE); | 959 return p7dcx; |
990 return NULL; | 960 } |
991 } | |
992 | |
993 dcx = SEC_ASN1DecoderStart (poolp, cinfo, sec_PKCS7ContentInfoTemplate); | |
994 if (dcx == NULL) { | |
995 PORT_FreeArena (p7dcx->tmp_poolp, PR_FALSE); | |
996 PORT_Free (p7dcx); | |
997 PORT_FreeArena (poolp, PR_FALSE); | |
998 return NULL; | |
999 } | |
1000 | |
1001 SEC_ASN1DecoderSetNotifyProc (dcx, sec_pkcs7_decoder_notify, p7dcx); | |
1002 | |
1003 p7dcx->dcx = dcx; | |
1004 p7dcx->cinfo = cinfo; | |
1005 p7dcx->cb = cb; | |
1006 p7dcx->cb_arg = cb_arg; | |
1007 p7dcx->pwfn = pwfn; | |
1008 p7dcx->pwfn_arg = pwfn_arg; | |
1009 p7dcx->dkcb = decrypt_key_cb; | |
1010 p7dcx->dkcb_arg = decrypt_key_cb_arg; | |
1011 p7dcx->decrypt_allowed_cb = decrypt_allowed_cb; | |
1012 | |
1013 return p7dcx; | |
1014 } | |
1015 | |
1016 | 961 |
1017 /* | 962 /* |
1018 * Do the next chunk of PKCS7 decoding. If there is a problem, set | 963 * Do the next chunk of PKCS7 decoding. If there is a problem, set |
1019 * an error and return a failure status. Note that in the case of | 964 * an error and return a failure status. Note that in the case of |
1020 * an error, this routine is still prepared to be called again and | 965 * an error, this routine is still prepared to be called again and |
1021 * again in case that is the easiest route for our caller to take. | 966 * again in case that is the easiest route for our caller to take. |
1022 * We simply detect it and do not do anything except keep setting | 967 * We simply detect it and do not do anything except keep setting |
1023 * that error in case our caller has not noticed it yet... | 968 * that error in case our caller has not noticed it yet... |
1024 */ | 969 */ |
1025 SECStatus | 970 SECStatus SEC_PKCS7DecoderUpdate(SEC_PKCS7DecoderContext *p7dcx, |
1026 SEC_PKCS7DecoderUpdate(SEC_PKCS7DecoderContext *p7dcx, | 971 const char *buf, unsigned long len) { |
1027 » » const char *buf, unsigned long len) | 972 if (p7dcx->cinfo != NULL && p7dcx->dcx != NULL) { |
1028 { | 973 PORT_Assert(p7dcx->error == 0); |
1029 if (p7dcx->cinfo != NULL && p7dcx->dcx != NULL) {· | 974 if (p7dcx->error == 0) { |
1030 » PORT_Assert (p7dcx->error == 0); | 975 if (SEC_ASN1DecoderUpdate(p7dcx->dcx, buf, len) != SECSuccess) { |
1031 » if (p7dcx->error == 0) { | 976 p7dcx->error = PORT_GetError(); |
1032 » if (SEC_ASN1DecoderUpdate (p7dcx->dcx, buf, len) != SECSuccess) { | 977 PORT_Assert(p7dcx->error); |
1033 » » p7dcx->error = PORT_GetError(); | 978 if (p7dcx->error == 0) p7dcx->error = -1; |
1034 » » PORT_Assert (p7dcx->error); | 979 } |
1035 » » if (p7dcx->error == 0) | 980 } |
1036 » » p7dcx->error = -1; | 981 } |
1037 » } | 982 |
1038 » } | 983 if (p7dcx->error) { |
1039 } | |
1040 | |
1041 if (p7dcx->error) { | |
1042 » if (p7dcx->dcx != NULL) { | |
1043 » (void) SEC_ASN1DecoderFinish (p7dcx->dcx); | |
1044 » p7dcx->dcx = NULL; | |
1045 » } | |
1046 » if (p7dcx->cinfo != NULL) { | |
1047 » SEC_PKCS7DestroyContentInfo (p7dcx->cinfo); | |
1048 » p7dcx->cinfo = NULL; | |
1049 » } | |
1050 » PORT_SetError (p7dcx->error); | |
1051 » return SECFailure; | |
1052 } | |
1053 | |
1054 return SECSuccess; | |
1055 } | |
1056 | |
1057 | |
1058 SEC_PKCS7ContentInfo * | |
1059 SEC_PKCS7DecoderFinish(SEC_PKCS7DecoderContext *p7dcx) | |
1060 { | |
1061 SEC_PKCS7ContentInfo *cinfo; | |
1062 | |
1063 cinfo = p7dcx->cinfo; | |
1064 if (p7dcx->dcx != NULL) { | 984 if (p7dcx->dcx != NULL) { |
1065 » if (SEC_ASN1DecoderFinish (p7dcx->dcx) != SECSuccess) { | 985 (void)SEC_ASN1DecoderFinish(p7dcx->dcx); |
1066 » SEC_PKCS7DestroyContentInfo (cinfo); | 986 p7dcx->dcx = NULL; |
1067 » cinfo = NULL; | 987 } |
1068 » } | 988 if (p7dcx->cinfo != NULL) { |
1069 } | 989 SEC_PKCS7DestroyContentInfo(p7dcx->cinfo); |
1070 /* free any NSS data structures */ | 990 p7dcx->cinfo = NULL; |
1071 if (p7dcx->worker.decryptobj) { | 991 } |
1072 sec_PKCS7DestroyDecryptObject (p7dcx->worker.decryptobj); | 992 PORT_SetError(p7dcx->error); |
1073 } | 993 return SECFailure; |
1074 PORT_FreeArena (p7dcx->tmp_poolp, PR_FALSE); | 994 } |
1075 PORT_Free (p7dcx); | 995 |
1076 return cinfo; | 996 return SECSuccess; |
1077 } | 997 } |
1078 | 998 |
1079 | 999 SEC_PKCS7ContentInfo *SEC_PKCS7DecoderFinish(SEC_PKCS7DecoderContext *p7dcx) { |
1080 SEC_PKCS7ContentInfo * | 1000 SEC_PKCS7ContentInfo *cinfo; |
1081 SEC_PKCS7DecodeItem(SECItem *p7item, | 1001 |
1082 » » SEC_PKCS7DecoderContentCallback cb, void *cb_arg, | 1002 cinfo = p7dcx->cinfo; |
1083 » » SECKEYGetPasswordKey pwfn, void *pwfn_arg, | 1003 if (p7dcx->dcx != NULL) { |
1084 » » SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb, | 1004 if (SEC_ASN1DecoderFinish(p7dcx->dcx) != SECSuccess) { |
1085 » » void *decrypt_key_cb_arg, | 1005 SEC_PKCS7DestroyContentInfo(cinfo); |
1086 » » SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb) | 1006 cinfo = NULL; |
1087 { | 1007 } |
1088 SEC_PKCS7DecoderContext *p7dcx; | 1008 } |
1089 | 1009 /* free any NSS data structures */ |
1090 p7dcx = SEC_PKCS7DecoderStart(cb, cb_arg, pwfn, pwfn_arg, decrypt_key_cb, | 1010 if (p7dcx->worker.decryptobj) { |
1091 » » » » decrypt_key_cb_arg, decrypt_allowed_cb); | 1011 sec_PKCS7DestroyDecryptObject(p7dcx->worker.decryptobj); |
1092 if (!p7dcx) { | 1012 } |
1093 /* error code is set */ | 1013 PORT_FreeArena(p7dcx->tmp_poolp, PR_FALSE); |
1094 return NULL; | 1014 PORT_Free(p7dcx); |
1095 } | 1015 return cinfo; |
1096 (void) SEC_PKCS7DecoderUpdate(p7dcx, (char *) p7item->data, p7item->len); | 1016 } |
1097 return SEC_PKCS7DecoderFinish(p7dcx); | 1017 |
| 1018 SEC_PKCS7ContentInfo *SEC_PKCS7DecodeItem( |
| 1019 SECItem *p7item, SEC_PKCS7DecoderContentCallback cb, void *cb_arg, |
| 1020 SECKEYGetPasswordKey pwfn, void *pwfn_arg, |
| 1021 SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg, |
| 1022 SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb) { |
| 1023 SEC_PKCS7DecoderContext *p7dcx; |
| 1024 |
| 1025 p7dcx = SEC_PKCS7DecoderStart(cb, cb_arg, pwfn, pwfn_arg, decrypt_key_cb, |
| 1026 decrypt_key_cb_arg, decrypt_allowed_cb); |
| 1027 if (!p7dcx) { |
| 1028 /* error code is set */ |
| 1029 return NULL; |
| 1030 } |
| 1031 (void)SEC_PKCS7DecoderUpdate(p7dcx, (char *)p7item->data, p7item->len); |
| 1032 return SEC_PKCS7DecoderFinish(p7dcx); |
1098 } | 1033 } |
1099 | 1034 |
1100 /* | 1035 /* |
1101 * Abort the ASN.1 stream. Used by pkcs 12 | 1036 * Abort the ASN.1 stream. Used by pkcs 12 |
1102 */ | 1037 */ |
1103 void | 1038 void SEC_PKCS7DecoderAbort(SEC_PKCS7DecoderContext *p7dcx, int error) { |
1104 SEC_PKCS7DecoderAbort(SEC_PKCS7DecoderContext *p7dcx, int error) | 1039 PORT_Assert(p7dcx); |
1105 { | 1040 SEC_ASN1DecoderAbort(p7dcx->dcx, error); |
1106 PORT_Assert(p7dcx); | 1041 } |
1107 SEC_ASN1DecoderAbort(p7dcx->dcx, error); | |
1108 } | |
1109 | |
1110 | 1042 |
1111 /* | 1043 /* |
1112 * If the thing contains any certs or crls return true; false otherwise. | 1044 * If the thing contains any certs or crls return true; false otherwise. |
1113 */ | 1045 */ |
1114 PRBool | 1046 PRBool SEC_PKCS7ContainsCertsOrCrls(SEC_PKCS7ContentInfo *cinfo) { |
1115 SEC_PKCS7ContainsCertsOrCrls(SEC_PKCS7ContentInfo *cinfo) | 1047 SECOidTag kind; |
1116 { | 1048 SECItem **certs; |
1117 SECOidTag kind; | 1049 CERTSignedCrl **crls; |
1118 SECItem **certs; | 1050 |
1119 CERTSignedCrl **crls; | 1051 kind = SEC_PKCS7ContentType(cinfo); |
1120 | 1052 switch (kind) { |
1121 kind = SEC_PKCS7ContentType (cinfo); | 1053 default: |
1122 switch (kind) { | 1054 case SEC_OID_PKCS7_DATA: |
1123 default: | 1055 case SEC_OID_PKCS7_DIGESTED_DATA: |
1124 case SEC_OID_PKCS7_DATA: | 1056 case SEC_OID_PKCS7_ENVELOPED_DATA: |
1125 case SEC_OID_PKCS7_DIGESTED_DATA: | 1057 case SEC_OID_PKCS7_ENCRYPTED_DATA: |
1126 case SEC_OID_PKCS7_ENVELOPED_DATA: | 1058 return PR_FALSE; |
1127 case SEC_OID_PKCS7_ENCRYPTED_DATA: | 1059 case SEC_OID_PKCS7_SIGNED_DATA: |
1128 » return PR_FALSE; | 1060 certs = cinfo->content.signedData->rawCerts; |
1129 case SEC_OID_PKCS7_SIGNED_DATA: | 1061 crls = cinfo->content.signedData->crls; |
1130 » certs = cinfo->content.signedData->rawCerts; | 1062 break; |
1131 » crls = cinfo->content.signedData->crls; | 1063 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: |
1132 » break; | 1064 certs = cinfo->content.signedAndEnvelopedData->rawCerts; |
1133 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | 1065 crls = cinfo->content.signedAndEnvelopedData->crls; |
1134 » certs = cinfo->content.signedAndEnvelopedData->rawCerts; | 1066 break; |
1135 » crls = cinfo->content.signedAndEnvelopedData->crls; | 1067 } |
1136 » break; | 1068 |
1137 } | 1069 /* |
1138 | 1070 * I know this could be collapsed, but I was in a mood to be explicit. |
1139 /* | 1071 */ |
1140 * I know this could be collapsed, but I was in a mood to be explicit. | 1072 if (certs != NULL && certs[0] != NULL) |
1141 */ | 1073 return PR_TRUE; |
1142 if (certs != NULL && certs[0] != NULL) | 1074 else if (crls != NULL && crls[0] != NULL) |
1143 » return PR_TRUE; | 1075 return PR_TRUE; |
1144 else if (crls != NULL && crls[0] != NULL) | 1076 else |
1145 » return PR_TRUE; | 1077 return PR_FALSE; |
1146 else | |
1147 » return PR_FALSE; | |
1148 } | 1078 } |
1149 | 1079 |
1150 /* return the content length...could use GetContent, however we | 1080 /* return the content length...could use GetContent, however we |
1151 * need the encrypted content length | 1081 * need the encrypted content length |
1152 */ | 1082 */ |
1153 PRBool | 1083 PRBool SEC_PKCS7IsContentEmpty(SEC_PKCS7ContentInfo *cinfo, |
1154 SEC_PKCS7IsContentEmpty(SEC_PKCS7ContentInfo *cinfo, unsigned int minLen) | 1084 unsigned int minLen) { |
1155 { | 1085 SECItem *item = NULL; |
1156 SECItem *item = NULL; | 1086 |
1157 | 1087 if (cinfo == NULL) { |
1158 if(cinfo == NULL) { | 1088 return PR_TRUE; |
1159 » return PR_TRUE; | 1089 } |
1160 } | 1090 |
1161 | 1091 switch (SEC_PKCS7ContentType(cinfo)) { |
1162 switch(SEC_PKCS7ContentType(cinfo)) | 1092 case SEC_OID_PKCS7_DATA: |
1163 { | 1093 item = cinfo->content.data; |
1164 » case SEC_OID_PKCS7_DATA: | 1094 break; |
1165 » item = cinfo->content.data; | 1095 case SEC_OID_PKCS7_ENCRYPTED_DATA: |
1166 » break; | 1096 item = &cinfo->content.encryptedData->encContentInfo.encContent; |
1167 » case SEC_OID_PKCS7_ENCRYPTED_DATA: | 1097 break; |
1168 » item = &cinfo->content.encryptedData->encContentInfo.encContent; | 1098 default: |
1169 » break; | 1099 /* add other types */ |
1170 » default: | 1100 return PR_FALSE; |
1171 » /* add other types */ | 1101 } |
1172 » return PR_FALSE; | 1102 |
1173 } | 1103 if (!item) { |
1174 | 1104 return PR_TRUE; |
1175 if(!item) { | 1105 } else if (item->len <= minLen) { |
1176 » return PR_TRUE; | 1106 return PR_TRUE; |
1177 } else if(item->len <= minLen) { | 1107 } |
1178 » return PR_TRUE; | 1108 |
1179 } | 1109 return PR_FALSE; |
1180 | 1110 } |
1181 return PR_FALSE; | 1111 |
1182 } | 1112 PRBool SEC_PKCS7ContentIsEncrypted(SEC_PKCS7ContentInfo *cinfo) { |
1183 | 1113 SECOidTag kind; |
1184 | 1114 |
1185 PRBool | 1115 kind = SEC_PKCS7ContentType(cinfo); |
1186 SEC_PKCS7ContentIsEncrypted(SEC_PKCS7ContentInfo *cinfo) | 1116 switch (kind) { |
1187 { | 1117 default: |
1188 SECOidTag kind; | 1118 case SEC_OID_PKCS7_DATA: |
1189 | 1119 case SEC_OID_PKCS7_DIGESTED_DATA: |
1190 kind = SEC_PKCS7ContentType (cinfo); | 1120 case SEC_OID_PKCS7_SIGNED_DATA: |
1191 switch (kind) { | 1121 return PR_FALSE; |
1192 default: | 1122 case SEC_OID_PKCS7_ENCRYPTED_DATA: |
1193 case SEC_OID_PKCS7_DATA: | 1123 case SEC_OID_PKCS7_ENVELOPED_DATA: |
1194 case SEC_OID_PKCS7_DIGESTED_DATA: | 1124 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: |
1195 case SEC_OID_PKCS7_SIGNED_DATA: | 1125 return PR_TRUE; |
1196 » return PR_FALSE; | 1126 } |
1197 case SEC_OID_PKCS7_ENCRYPTED_DATA: | 1127 } |
1198 case SEC_OID_PKCS7_ENVELOPED_DATA: | |
1199 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | |
1200 » return PR_TRUE; | |
1201 } | |
1202 } | |
1203 | |
1204 | 1128 |
1205 /* | 1129 /* |
1206 * If the PKCS7 content has a signature (not just *could* have a signature) | 1130 * If the PKCS7 content has a signature (not just *could* have a signature) |
1207 * return true; false otherwise. This can/should be called before calling | 1131 * return true; false otherwise. This can/should be called before calling |
1208 * VerifySignature, which will always indicate failure if no signature is | 1132 * VerifySignature, which will always indicate failure if no signature is |
1209 * present, but that does not mean there even was a signature! | 1133 * present, but that does not mean there even was a signature! |
1210 * Note that the content itself can be empty (detached content was sent | 1134 * Note that the content itself can be empty (detached content was sent |
1211 * another way); it is the presence of the signature that matters. | 1135 * another way); it is the presence of the signature that matters. |
1212 */ | 1136 */ |
1213 PRBool | 1137 PRBool SEC_PKCS7ContentIsSigned(SEC_PKCS7ContentInfo *cinfo) { |
1214 SEC_PKCS7ContentIsSigned(SEC_PKCS7ContentInfo *cinfo) | 1138 SECOidTag kind; |
1215 { | 1139 SEC_PKCS7SignerInfo **signerinfos; |
1216 SECOidTag kind; | 1140 |
1217 SEC_PKCS7SignerInfo **signerinfos; | 1141 kind = SEC_PKCS7ContentType(cinfo); |
1218 | 1142 switch (kind) { |
1219 kind = SEC_PKCS7ContentType (cinfo); | 1143 default: |
1220 switch (kind) { | 1144 case SEC_OID_PKCS7_DATA: |
1221 default: | 1145 case SEC_OID_PKCS7_DIGESTED_DATA: |
1222 case SEC_OID_PKCS7_DATA: | 1146 case SEC_OID_PKCS7_ENVELOPED_DATA: |
1223 case SEC_OID_PKCS7_DIGESTED_DATA: | 1147 case SEC_OID_PKCS7_ENCRYPTED_DATA: |
1224 case SEC_OID_PKCS7_ENVELOPED_DATA: | 1148 return PR_FALSE; |
1225 case SEC_OID_PKCS7_ENCRYPTED_DATA: | 1149 case SEC_OID_PKCS7_SIGNED_DATA: |
1226 » return PR_FALSE; | 1150 signerinfos = cinfo->content.signedData->signerInfos; |
1227 case SEC_OID_PKCS7_SIGNED_DATA: | 1151 break; |
1228 » signerinfos = cinfo->content.signedData->signerInfos; | 1152 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: |
1229 » break; | 1153 signerinfos = cinfo->content.signedAndEnvelopedData->signerInfos; |
1230 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | 1154 break; |
1231 » signerinfos = cinfo->content.signedAndEnvelopedData->signerInfos; | 1155 } |
1232 » break; | 1156 |
1233 } | 1157 /* |
1234 | 1158 * I know this could be collapsed; but I kind of think it will get |
1235 /* | 1159 * more complicated before I am finished, so... |
1236 * I know this could be collapsed; but I kind of think it will get | 1160 */ |
1237 * more complicated before I am finished, so... | 1161 if (signerinfos != NULL && signerinfos[0] != NULL) |
1238 */ | 1162 return PR_TRUE; |
1239 if (signerinfos != NULL && signerinfos[0] != NULL) | 1163 else |
1240 » return PR_TRUE; | 1164 return PR_FALSE; |
1241 else | 1165 } |
1242 » return PR_FALSE; | |
1243 } | |
1244 | |
1245 | 1166 |
1246 /* | 1167 /* |
1247 * sec_pkcs7_verify_signature | 1168 * sec_pkcs7_verify_signature |
1248 * | 1169 * |
1249 * Look at a PKCS7 contentInfo and check if the signature is good. | 1170 * Look at a PKCS7 contentInfo and check if the signature is good. |
1250 * The digest was either calculated earlier (and is stored in the | 1171 * The digest was either calculated earlier (and is stored in the |
1251 * contentInfo itself) or is passed in via "detached_digest". | 1172 * contentInfo itself) or is passed in via "detached_digest". |
1252 * | 1173 * |
1253 * The verification checks that the signing cert is valid and trusted | 1174 * The verification checks that the signing cert is valid and trusted |
1254 * for the purpose specified by "certusage" at | 1175 * for the purpose specified by "certusage" at |
(...skipping 16 matching lines...) Expand all Loading... |
1271 * if/when that changes, review and change these as needed. | 1192 * if/when that changes, review and change these as needed. |
1272 * | 1193 * |
1273 * XXX This is broken wrt signedAndEnvelopedData. In that case, the | 1194 * XXX This is broken wrt signedAndEnvelopedData. In that case, the |
1274 * message digest is doubly encrypted -- first encrypted with the signer | 1195 * message digest is doubly encrypted -- first encrypted with the signer |
1275 * private key but then again encrypted with the bulk encryption key used | 1196 * private key but then again encrypted with the bulk encryption key used |
1276 * to encrypt the content. So before we can pass the digest to VerifyDigest, | 1197 * to encrypt the content. So before we can pass the digest to VerifyDigest, |
1277 * we need to decrypt it with the bulk encryption key. Also, in this case, | 1198 * we need to decrypt it with the bulk encryption key. Also, in this case, |
1278 * there should be NO authenticatedAttributes (signerinfo->authAttr should | 1199 * there should be NO authenticatedAttributes (signerinfo->authAttr should |
1279 * be NULL). | 1200 * be NULL). |
1280 */ | 1201 */ |
1281 static PRBool | 1202 static PRBool sec_pkcs7_verify_signature(SEC_PKCS7ContentInfo *cinfo, |
1282 sec_pkcs7_verify_signature(SEC_PKCS7ContentInfo *cinfo, | 1203 SECCertUsage certusage, |
1283 SECCertUsage certusage, | 1204 const SECItem *detached_digest, |
1284 const SECItem *detached_digest, | 1205 HASH_HashType digest_type, |
1285 HASH_HashType digest_type, | 1206 PRBool keepcerts, |
1286 PRBool keepcerts, | 1207 const PRTime *atTime) { |
1287 const PRTime *atTime) | 1208 SECAlgorithmID **digestalgs, *bulkid; |
1288 { | 1209 const SECItem *digest; |
1289 SECAlgorithmID **digestalgs, *bulkid; | 1210 SECItem **digests; |
1290 const SECItem *digest; | 1211 SECItem **rawcerts; |
1291 SECItem **digests; | 1212 CERTSignedCrl **crls; |
1292 SECItem **rawcerts; | 1213 SEC_PKCS7SignerInfo **signerinfos, *signerinfo; |
1293 CERTSignedCrl **crls; | 1214 CERTCertificate *cert, **certs; |
1294 SEC_PKCS7SignerInfo **signerinfos, *signerinfo; | 1215 PRBool goodsig; |
1295 CERTCertificate *cert, **certs; | 1216 CERTCertDBHandle *certdb, *defaultdb; |
1296 PRBool goodsig; | 1217 SECOidTag encTag, digestTag; |
1297 CERTCertDBHandle *certdb, *defaultdb;· | 1218 HASH_HashType found_type; |
1298 SECOidTag encTag,digestTag; | 1219 int i, certcount; |
1299 HASH_HashType found_type; | 1220 SECKEYPublicKey *publickey; |
1300 int i, certcount; | 1221 SECItem *content_type; |
1301 SECKEYPublicKey *publickey; | 1222 PK11SymKey *sigkey; |
1302 SECItem *content_type; | 1223 SECItem *encoded_stime; |
1303 PK11SymKey *sigkey; | 1224 PRTime stime; |
1304 SECItem *encoded_stime; | 1225 PRTime verificationTime; |
1305 PRTime stime; | 1226 SECStatus rv; |
1306 PRTime verificationTime; | 1227 |
| 1228 /* |
| 1229 * Everything needed in order to "goto done" safely. |
| 1230 */ |
| 1231 goodsig = PR_FALSE; |
| 1232 certcount = 0; |
| 1233 cert = NULL; |
| 1234 certs = NULL; |
| 1235 certdb = NULL; |
| 1236 defaultdb = CERT_GetDefaultCertDB(); |
| 1237 publickey = NULL; |
| 1238 |
| 1239 if (!SEC_PKCS7ContentIsSigned(cinfo)) { |
| 1240 PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); |
| 1241 goto done; |
| 1242 } |
| 1243 |
| 1244 PORT_Assert(cinfo->contentTypeTag != NULL); |
| 1245 |
| 1246 switch (cinfo->contentTypeTag->offset) { |
| 1247 default: |
| 1248 case SEC_OID_PKCS7_DATA: |
| 1249 case SEC_OID_PKCS7_DIGESTED_DATA: |
| 1250 case SEC_OID_PKCS7_ENVELOPED_DATA: |
| 1251 case SEC_OID_PKCS7_ENCRYPTED_DATA: |
| 1252 /* Could only get here if SEC_PKCS7ContentIsSigned is broken. */ |
| 1253 PORT_Assert(0); |
| 1254 case SEC_OID_PKCS7_SIGNED_DATA: { |
| 1255 SEC_PKCS7SignedData *sdp; |
| 1256 |
| 1257 sdp = cinfo->content.signedData; |
| 1258 digestalgs = sdp->digestAlgorithms; |
| 1259 digests = sdp->digests; |
| 1260 rawcerts = sdp->rawCerts; |
| 1261 crls = sdp->crls; |
| 1262 signerinfos = sdp->signerInfos; |
| 1263 content_type = &(sdp->contentInfo.contentType); |
| 1264 sigkey = NULL; |
| 1265 bulkid = NULL; |
| 1266 } break; |
| 1267 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: { |
| 1268 SEC_PKCS7SignedAndEnvelopedData *saedp; |
| 1269 |
| 1270 saedp = cinfo->content.signedAndEnvelopedData; |
| 1271 digestalgs = saedp->digestAlgorithms; |
| 1272 digests = saedp->digests; |
| 1273 rawcerts = saedp->rawCerts; |
| 1274 crls = saedp->crls; |
| 1275 signerinfos = saedp->signerInfos; |
| 1276 content_type = &(saedp->encContentInfo.contentType); |
| 1277 sigkey = saedp->sigKey; |
| 1278 bulkid = &(saedp->encContentInfo.contentEncAlg); |
| 1279 } break; |
| 1280 } |
| 1281 |
| 1282 if ((signerinfos == NULL) || (signerinfos[0] == NULL)) { |
| 1283 PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); |
| 1284 goto done; |
| 1285 } |
| 1286 |
| 1287 /* |
| 1288 * XXX Need to handle multiple signatures; checking them is easy, |
| 1289 * but what should be the semantics here (like, return value)? |
| 1290 */ |
| 1291 if (signerinfos[1] != NULL) { |
| 1292 PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); |
| 1293 goto done; |
| 1294 } |
| 1295 |
| 1296 signerinfo = signerinfos[0]; |
| 1297 |
| 1298 /* |
| 1299 * XXX I would like to just pass the issuerAndSN, along with the rawcerts |
| 1300 * and crls, to some function that did all of this certificate stuff |
| 1301 * (open/close the database if necessary, verifying the certs, etc.) |
| 1302 * and gave me back a cert pointer if all was good. |
| 1303 */ |
| 1304 certdb = defaultdb; |
| 1305 if (certdb == NULL) { |
| 1306 goto done; |
| 1307 } |
| 1308 |
| 1309 certcount = 0; |
| 1310 if (rawcerts != NULL) { |
| 1311 for (; rawcerts[certcount] != NULL; certcount++) { |
| 1312 /* just counting */ |
| 1313 } |
| 1314 } |
| 1315 |
| 1316 /* |
| 1317 * Note that the result of this is that each cert in "certs" |
| 1318 * needs to be destroyed. |
| 1319 */ |
| 1320 rv = CERT_ImportCerts(certdb, certusage, certcount, rawcerts, &certs, |
| 1321 keepcerts, PR_FALSE, NULL); |
| 1322 if (rv != SECSuccess) { |
| 1323 goto done; |
| 1324 } |
| 1325 |
| 1326 /* |
| 1327 * This cert will also need to be freed, but since we save it |
| 1328 * in signerinfo for later, we do not want to destroy it when |
| 1329 * we leave this function -- we let the clean-up of the entire |
| 1330 * cinfo structure later do the destroy of this cert. |
| 1331 */ |
| 1332 cert = CERT_FindCertByIssuerAndSN(certdb, signerinfo->issuerAndSN); |
| 1333 if (cert == NULL) { |
| 1334 goto done; |
| 1335 } |
| 1336 |
| 1337 signerinfo->cert = cert; |
| 1338 |
| 1339 /* |
| 1340 * Get and convert the signing time; if available, it will be used |
| 1341 * both on the cert verification and for importing the sender |
| 1342 * email profile. |
| 1343 */ |
| 1344 encoded_stime = SEC_PKCS7GetSigningTime(cinfo); |
| 1345 if (encoded_stime != NULL) { |
| 1346 if (DER_DecodeTimeChoice(&stime, encoded_stime) != SECSuccess) |
| 1347 encoded_stime = NULL; /* conversion failed, so pretend none */ |
| 1348 } |
| 1349 |
| 1350 /* |
| 1351 * XXX This uses the signing time, if available. Additionally, we |
| 1352 * might want to, if there is no signing time, get the message time |
| 1353 * from the mail header itself, and use that. That would require |
| 1354 * a change to our interface though, and for S/MIME callers to pass |
| 1355 * in a time (and for non-S/MIME callers to pass in nothing, or |
| 1356 * maybe make them pass in the current time, always?). |
| 1357 */ |
| 1358 if (atTime) { |
| 1359 verificationTime = *atTime; |
| 1360 } else if (encoded_stime != NULL) { |
| 1361 verificationTime = stime; |
| 1362 } else { |
| 1363 verificationTime = PR_Now(); |
| 1364 } |
| 1365 if (CERT_VerifyCert(certdb, cert, PR_TRUE, certusage, verificationTime, |
| 1366 cinfo->pwfn_arg, NULL) != SECSuccess) { |
| 1367 /* |
| 1368 * XXX Give the user an option to check the signature anyway? |
| 1369 * If we want to do this, need to give a way to leave and display |
| 1370 * some dialog and get the answer and come back through (or do |
| 1371 * the rest of what we do below elsewhere, maybe by putting it |
| 1372 * in a function that we call below and could call from a dialog |
| 1373 * finish handler). |
| 1374 */ |
| 1375 goto savecert; |
| 1376 } |
| 1377 |
| 1378 publickey = CERT_ExtractPublicKey(cert); |
| 1379 if (publickey == NULL) goto done; |
| 1380 |
| 1381 /* |
| 1382 * XXX No! If digests is empty, see if we can create it now by |
| 1383 * digesting the contents. This is necessary if we want to allow |
| 1384 * somebody to do a simple decode (without filtering, etc.) and |
| 1385 * then later call us here to do the verification. |
| 1386 * OR, we can just specify that the interface to this routine |
| 1387 * *requires* that the digest(s) be done before calling and either |
| 1388 * stashed in the struct itself or passed in explicitly (as would |
| 1389 * be done for detached contents). |
| 1390 */ |
| 1391 if ((digests == NULL || digests[0] == NULL) && |
| 1392 (detached_digest == NULL || detached_digest->data == NULL)) |
| 1393 goto done; |
| 1394 |
| 1395 /* |
| 1396 * Find and confirm digest algorithm. |
| 1397 */ |
| 1398 digestTag = SECOID_FindOIDTag(&(signerinfo->digestAlg.algorithm)); |
| 1399 |
| 1400 /* make sure we understand the digest type first */ |
| 1401 found_type = HASH_GetHashTypeByOidTag(digestTag); |
| 1402 if ((digestTag == SEC_OID_UNKNOWN) || (found_type == HASH_AlgNULL)) { |
| 1403 PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); |
| 1404 goto done; |
| 1405 } |
| 1406 |
| 1407 if (detached_digest != NULL) { |
| 1408 unsigned int hashLen = HASH_ResultLen(found_type); |
| 1409 |
| 1410 if (digest_type != found_type || detached_digest->len != hashLen) { |
| 1411 PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); |
| 1412 goto done; |
| 1413 } |
| 1414 digest = detached_digest; |
| 1415 } else { |
| 1416 PORT_Assert(digestalgs != NULL && digestalgs[0] != NULL); |
| 1417 if (digestalgs == NULL || digestalgs[0] == NULL) { |
| 1418 PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); |
| 1419 goto done; |
| 1420 } |
| 1421 |
| 1422 /* |
| 1423 * pick digest matching signerinfo->digestAlg from digests |
| 1424 */ |
| 1425 for (i = 0; digestalgs[i] != NULL; i++) { |
| 1426 if (SECOID_FindOIDTag(&(digestalgs[i]->algorithm)) == digestTag) break; |
| 1427 } |
| 1428 if (digestalgs[i] == NULL) { |
| 1429 PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); |
| 1430 goto done; |
| 1431 } |
| 1432 |
| 1433 digest = digests[i]; |
| 1434 } |
| 1435 |
| 1436 encTag = SECOID_FindOIDTag(&(signerinfo->digestEncAlg.algorithm)); |
| 1437 if (encTag == SEC_OID_UNKNOWN) { |
| 1438 PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); |
| 1439 goto done; |
| 1440 } |
| 1441 |
| 1442 if (signerinfo->authAttr != NULL) { |
| 1443 SEC_PKCS7Attribute *attr; |
| 1444 SECItem *value; |
| 1445 SECItem encoded_attrs; |
| 1446 |
| 1447 /* |
| 1448 * We have a sigkey only for signedAndEnvelopedData, which is |
| 1449 * not supposed to have any authenticated attributes. |
| 1450 */ |
| 1451 if (sigkey != NULL) { |
| 1452 PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); |
| 1453 goto done; |
| 1454 } |
| 1455 |
| 1456 /* |
| 1457 * PKCS #7 says that if there are any authenticated attributes, |
| 1458 * then there must be one for content type which matches the |
| 1459 * content type of the content being signed, and there must |
| 1460 * be one for message digest which matches our message digest. |
| 1461 * So check these things first. |
| 1462 * XXX Might be nice to have a compare-attribute-value function |
| 1463 * which could collapse the following nicely. |
| 1464 */ |
| 1465 attr = sec_PKCS7FindAttribute(signerinfo->authAttr, |
| 1466 SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE); |
| 1467 value = sec_PKCS7AttributeValue(attr); |
| 1468 if (value == NULL || value->len != content_type->len) { |
| 1469 PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); |
| 1470 goto done; |
| 1471 } |
| 1472 if (PORT_Memcmp(value->data, content_type->data, value->len) != 0) { |
| 1473 PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); |
| 1474 goto done; |
| 1475 } |
| 1476 |
| 1477 attr = sec_PKCS7FindAttribute(signerinfo->authAttr, |
| 1478 SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE); |
| 1479 value = sec_PKCS7AttributeValue(attr); |
| 1480 if (value == NULL || value->len != digest->len) { |
| 1481 PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); |
| 1482 goto done; |
| 1483 } |
| 1484 if (PORT_Memcmp(value->data, digest->data, value->len) != 0) { |
| 1485 PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); |
| 1486 goto done; |
| 1487 } |
| 1488 |
| 1489 /* |
| 1490 * Okay, we met the constraints of the basic attributes. |
| 1491 * Now check the signature, which is based on a digest of |
| 1492 * the DER-encoded authenticated attributes. So, first we |
| 1493 * encode and then we digest/verify. |
| 1494 */ |
| 1495 encoded_attrs.data = NULL; |
| 1496 encoded_attrs.len = 0; |
| 1497 if (sec_PKCS7EncodeAttributes(NULL, &encoded_attrs, |
| 1498 &(signerinfo->authAttr)) == NULL) |
| 1499 goto done; |
| 1500 |
| 1501 if (encoded_attrs.data == NULL || encoded_attrs.len == 0) { |
| 1502 PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); |
| 1503 goto done; |
| 1504 } |
| 1505 |
| 1506 goodsig = (PRBool)( |
| 1507 VFY_VerifyDataDirect(encoded_attrs.data, encoded_attrs.len, publickey, |
| 1508 &(signerinfo->encDigest), encTag, digestTag, NULL, |
| 1509 cinfo->pwfn_arg) == SECSuccess); |
| 1510 PORT_Free(encoded_attrs.data); |
| 1511 } else { |
| 1512 SECItem *sig; |
| 1513 SECItem holder; |
1307 SECStatus rv; | 1514 SECStatus rv; |
1308 | 1515 |
1309 /* | 1516 /* |
1310 * Everything needed in order to "goto done" safely. | 1517 * No authenticated attributes. |
1311 */ | 1518 * The signature is based on the plain message digest. |
1312 goodsig = PR_FALSE; | 1519 */ |
1313 certcount = 0; | 1520 |
1314 cert = NULL; | 1521 sig = &(signerinfo->encDigest); |
1315 certs = NULL; | 1522 if (sig->len == 0) {/* bad signature */ |
1316 certdb = NULL; | 1523 PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); |
1317 defaultdb = CERT_GetDefaultCertDB(); | 1524 goto done; |
1318 publickey = NULL; | 1525 } |
1319 | 1526 |
1320 if (! SEC_PKCS7ContentIsSigned(cinfo)) { | 1527 if (sigkey != NULL) { |
1321 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | 1528 sec_PKCS7CipherObject *decryptobj; |
1322 goto done; | 1529 unsigned int buflen; |
1323 } | 1530 |
1324 | 1531 /* |
1325 PORT_Assert (cinfo->contentTypeTag != NULL); | 1532 * For signedAndEnvelopedData, we first must decrypt the encrypted |
1326 | 1533 * digest with the bulk encryption key. The result is the normal |
1327 switch (cinfo->contentTypeTag->offset) { | 1534 * encrypted digest (aka the signature). |
1328 default: | 1535 */ |
1329 case SEC_OID_PKCS7_DATA: | 1536 decryptobj = sec_PKCS7CreateDecryptObject(sigkey, bulkid); |
1330 case SEC_OID_PKCS7_DIGESTED_DATA: | 1537 if (decryptobj == NULL) goto done; |
1331 case SEC_OID_PKCS7_ENVELOPED_DATA: | 1538 |
1332 case SEC_OID_PKCS7_ENCRYPTED_DATA: | 1539 buflen = sec_PKCS7DecryptLength(decryptobj, sig->len, PR_TRUE); |
1333 /* Could only get here if SEC_PKCS7ContentIsSigned is broken. */ | 1540 PORT_Assert(buflen); |
1334 PORT_Assert (0); | 1541 if (buflen == 0) {/* something is wrong */ |
1335 case SEC_OID_PKCS7_SIGNED_DATA: | 1542 sec_PKCS7DestroyDecryptObject(decryptobj); |
1336 { | 1543 goto done; |
1337 SEC_PKCS7SignedData *sdp; | 1544 } |
1338 | 1545 |
1339 sdp = cinfo->content.signedData; | 1546 holder.data = (unsigned char *)PORT_Alloc(buflen); |
1340 digestalgs = sdp->digestAlgorithms; | 1547 if (holder.data == NULL) { |
1341 digests = sdp->digests; | 1548 sec_PKCS7DestroyDecryptObject(decryptobj); |
1342 rawcerts = sdp->rawCerts; | 1549 goto done; |
1343 crls = sdp->crls; | 1550 } |
1344 signerinfos = sdp->signerInfos; | 1551 |
1345 content_type = &(sdp->contentInfo.contentType); | 1552 rv = sec_PKCS7Decrypt(decryptobj, holder.data, &holder.len, buflen, |
1346 sigkey = NULL; | 1553 sig->data, sig->len, PR_TRUE); |
1347 bulkid = NULL; | 1554 sec_PKCS7DestroyDecryptObject(decryptobj); |
1348 } | 1555 if (rv != SECSuccess) { |
1349 break; | 1556 goto done; |
1350 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | 1557 } |
1351 { | 1558 |
1352 SEC_PKCS7SignedAndEnvelopedData *saedp; | 1559 sig = &holder; |
1353 | 1560 } |
1354 saedp = cinfo->content.signedAndEnvelopedData; | 1561 |
1355 digestalgs = saedp->digestAlgorithms; | 1562 goodsig = (PRBool)(VFY_VerifyDigestDirect(digest, publickey, sig, encTag, |
1356 digests = saedp->digests; | 1563 digestTag, |
1357 rawcerts = saedp->rawCerts; | 1564 cinfo->pwfn_arg) == SECSuccess); |
1358 crls = saedp->crls; | 1565 |
1359 signerinfos = saedp->signerInfos; | 1566 if (sigkey != NULL) { |
1360 content_type = &(saedp->encContentInfo.contentType); | 1567 PORT_Assert(sig == &holder); |
1361 sigkey = saedp->sigKey; | 1568 PORT_ZFree(holder.data, holder.len); |
1362 bulkid = &(saedp->encContentInfo.contentEncAlg); | 1569 } |
1363 } | 1570 } |
1364 break; | 1571 |
1365 } | 1572 if (!goodsig) { |
1366 | 1573 /* |
1367 if ((signerinfos == NULL) || (signerinfos[0] == NULL)) { | 1574 * XXX Change the generic error into our specific one, because |
1368 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | 1575 * in that case we get a better explanation out of the Security |
1369 goto done; | 1576 * Advisor. This is really a bug in our error strings (the |
1370 } | 1577 * "generic" error has a lousy/wrong message associated with it |
1371 | 1578 * which assumes the signature verification was done for the |
1372 /* | 1579 * purposes of checking the issuer signature on a certificate) |
1373 * XXX Need to handle multiple signatures; checking them is easy, | 1580 * but this is at least an easy workaround and/or in the |
1374 * but what should be the semantics here (like, return value)? | 1581 * Security Advisor, which specifically checks for the error |
1375 */ | 1582 * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation |
1376 if (signerinfos[1] != NULL) { | 1583 * in that case but does not similarly check for |
1377 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | 1584 * SEC_ERROR_BAD_SIGNATURE. It probably should, but then would |
1378 goto done; | 1585 * probably say the wrong thing in the case that it *was* the |
1379 } | 1586 * certificate signature check that failed during the cert |
1380 | 1587 * verification done above. Our error handling is really a mess. |
1381 signerinfo = signerinfos[0]; | 1588 */ |
1382 | 1589 if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE) |
1383 /* | 1590 PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); |
1384 * XXX I would like to just pass the issuerAndSN, along with the rawcerts | 1591 } |
1385 * and crls, to some function that did all of this certificate stuff | |
1386 * (open/close the database if necessary, verifying the certs, etc.) | |
1387 * and gave me back a cert pointer if all was good. | |
1388 */ | |
1389 certdb = defaultdb; | |
1390 if (certdb == NULL) { | |
1391 goto done; | |
1392 } | |
1393 | |
1394 certcount = 0; | |
1395 if (rawcerts != NULL) { | |
1396 for (; rawcerts[certcount] != NULL; certcount++) { | |
1397 /* just counting */ | |
1398 } | |
1399 } | |
1400 | |
1401 /* | |
1402 * Note that the result of this is that each cert in "certs" | |
1403 * needs to be destroyed. | |
1404 */ | |
1405 rv = CERT_ImportCerts(certdb, certusage, certcount, rawcerts, &certs, | |
1406 keepcerts, PR_FALSE, NULL); | |
1407 if ( rv != SECSuccess ) { | |
1408 goto done; | |
1409 } | |
1410 | |
1411 /* | |
1412 * This cert will also need to be freed, but since we save it | |
1413 * in signerinfo for later, we do not want to destroy it when | |
1414 * we leave this function -- we let the clean-up of the entire | |
1415 * cinfo structure later do the destroy of this cert. | |
1416 */ | |
1417 cert = CERT_FindCertByIssuerAndSN(certdb, signerinfo->issuerAndSN); | |
1418 if (cert == NULL) { | |
1419 goto done; | |
1420 } | |
1421 | |
1422 signerinfo->cert = cert; | |
1423 | |
1424 /* | |
1425 * Get and convert the signing time; if available, it will be used | |
1426 * both on the cert verification and for importing the sender | |
1427 * email profile. | |
1428 */ | |
1429 encoded_stime = SEC_PKCS7GetSigningTime (cinfo); | |
1430 if (encoded_stime != NULL) { | |
1431 if (DER_DecodeTimeChoice (&stime, encoded_stime) != SECSuccess) | |
1432 encoded_stime = NULL; /* conversion failed, so pretend none */ | |
1433 } | |
1434 | |
1435 /* | |
1436 * XXX This uses the signing time, if available. Additionally, we | |
1437 * might want to, if there is no signing time, get the message time | |
1438 * from the mail header itself, and use that. That would require | |
1439 * a change to our interface though, and for S/MIME callers to pass | |
1440 * in a time (and for non-S/MIME callers to pass in nothing, or | |
1441 * maybe make them pass in the current time, always?). | |
1442 */ | |
1443 if (atTime) { | |
1444 verificationTime = *atTime; | |
1445 } else if (encoded_stime != NULL) { | |
1446 verificationTime = stime; | |
1447 } else { | |
1448 verificationTime = PR_Now(); | |
1449 } | |
1450 if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage, verificationTime, | |
1451 cinfo->pwfn_arg, NULL) != SECSuccess) | |
1452 { | |
1453 /* | |
1454 * XXX Give the user an option to check the signature anyway? | |
1455 * If we want to do this, need to give a way to leave and display | |
1456 * some dialog and get the answer and come back through (or do | |
1457 * the rest of what we do below elsewhere, maybe by putting it | |
1458 * in a function that we call below and could call from a dialog | |
1459 * finish handler). | |
1460 */ | |
1461 goto savecert; | |
1462 } | |
1463 | |
1464 publickey = CERT_ExtractPublicKey (cert); | |
1465 if (publickey == NULL) | |
1466 goto done; | |
1467 | |
1468 /* | |
1469 * XXX No! If digests is empty, see if we can create it now by | |
1470 * digesting the contents. This is necessary if we want to allow | |
1471 * somebody to do a simple decode (without filtering, etc.) and | |
1472 * then later call us here to do the verification. | |
1473 * OR, we can just specify that the interface to this routine | |
1474 * *requires* that the digest(s) be done before calling and either | |
1475 * stashed in the struct itself or passed in explicitly (as would | |
1476 * be done for detached contents). | |
1477 */ | |
1478 if ((digests == NULL || digests[0] == NULL) | |
1479 && (detached_digest == NULL || detached_digest->data == NULL)) | |
1480 goto done; | |
1481 | |
1482 /* | |
1483 * Find and confirm digest algorithm. | |
1484 */ | |
1485 digestTag = SECOID_FindOIDTag(&(signerinfo->digestAlg.algorithm)); | |
1486 | |
1487 /* make sure we understand the digest type first */ | |
1488 found_type = HASH_GetHashTypeByOidTag(digestTag); | |
1489 if ((digestTag == SEC_OID_UNKNOWN) || (found_type == HASH_AlgNULL)) { | |
1490 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1491 goto done; | |
1492 } | |
1493 | |
1494 if (detached_digest != NULL) { | |
1495 unsigned int hashLen = HASH_ResultLen(found_type); | |
1496 | |
1497 if (digest_type != found_type ||· | |
1498 detached_digest->len != hashLen) { | |
1499 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1500 goto done; | |
1501 } | |
1502 digest = detached_digest; | |
1503 } else { | |
1504 PORT_Assert (digestalgs != NULL && digestalgs[0] != NULL); | |
1505 if (digestalgs == NULL || digestalgs[0] == NULL) { | |
1506 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1507 goto done; | |
1508 } | |
1509 | |
1510 /* | |
1511 * pick digest matching signerinfo->digestAlg from digests | |
1512 */ | |
1513 for (i = 0; digestalgs[i] != NULL; i++) { | |
1514 if (SECOID_FindOIDTag(&(digestalgs[i]->algorithm)) == digestTag) | |
1515 break; | |
1516 } | |
1517 if (digestalgs[i] == NULL) { | |
1518 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1519 goto done; | |
1520 } | |
1521 | |
1522 digest = digests[i]; | |
1523 } | |
1524 | |
1525 encTag = SECOID_FindOIDTag(&(signerinfo->digestEncAlg.algorithm)); | |
1526 if (encTag == SEC_OID_UNKNOWN) { | |
1527 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1528 goto done; | |
1529 } | |
1530 | |
1531 if (signerinfo->authAttr != NULL) { | |
1532 SEC_PKCS7Attribute *attr; | |
1533 SECItem *value; | |
1534 SECItem encoded_attrs; | |
1535 | |
1536 /* | |
1537 * We have a sigkey only for signedAndEnvelopedData, which is | |
1538 * not supposed to have any authenticated attributes. | |
1539 */ | |
1540 if (sigkey != NULL) { | |
1541 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1542 goto done; | |
1543 } | |
1544 | |
1545 /* | |
1546 * PKCS #7 says that if there are any authenticated attributes, | |
1547 * then there must be one for content type which matches the | |
1548 * content type of the content being signed, and there must | |
1549 * be one for message digest which matches our message digest. | |
1550 * So check these things first. | |
1551 * XXX Might be nice to have a compare-attribute-value function | |
1552 * which could collapse the following nicely. | |
1553 */ | |
1554 attr = sec_PKCS7FindAttribute (signerinfo->authAttr, | |
1555 SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE); | |
1556 value = sec_PKCS7AttributeValue (attr); | |
1557 if (value == NULL || value->len != content_type->len) { | |
1558 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1559 goto done; | |
1560 } | |
1561 if (PORT_Memcmp (value->data, content_type->data, value->len) != 0) { | |
1562 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1563 goto done; | |
1564 } | |
1565 | |
1566 attr = sec_PKCS7FindAttribute (signerinfo->authAttr, | |
1567 SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE); | |
1568 value = sec_PKCS7AttributeValue (attr); | |
1569 if (value == NULL || value->len != digest->len) { | |
1570 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1571 goto done; | |
1572 } | |
1573 if (PORT_Memcmp (value->data, digest->data, value->len) != 0) { | |
1574 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1575 goto done; | |
1576 } | |
1577 | |
1578 /* | |
1579 * Okay, we met the constraints of the basic attributes. | |
1580 * Now check the signature, which is based on a digest of | |
1581 * the DER-encoded authenticated attributes. So, first we | |
1582 * encode and then we digest/verify. | |
1583 */ | |
1584 encoded_attrs.data = NULL; | |
1585 encoded_attrs.len = 0; | |
1586 if (sec_PKCS7EncodeAttributes (NULL, &encoded_attrs, | |
1587 &(signerinfo->authAttr)) == NULL) | |
1588 goto done; | |
1589 | |
1590 if (encoded_attrs.data == NULL || encoded_attrs.len == 0) { | |
1591 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1592 goto done; | |
1593 } | |
1594 | |
1595 goodsig = (PRBool)(VFY_VerifyDataDirect(encoded_attrs.data,· | |
1596 encoded_attrs.len, | |
1597 publickey, &(signerinfo->encDigest), | |
1598 encTag, digestTag, NULL, | |
1599 cinfo->pwfn_arg) == SECSuccess); | |
1600 PORT_Free (encoded_attrs.data); | |
1601 } else { | |
1602 SECItem *sig; | |
1603 SECItem holder; | |
1604 SECStatus rv; | |
1605 | |
1606 /* | |
1607 * No authenticated attributes. | |
1608 * The signature is based on the plain message digest. | |
1609 */ | |
1610 | |
1611 sig = &(signerinfo->encDigest); | |
1612 if (sig->len == 0) { /* bad signature */ | |
1613 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1614 goto done; | |
1615 } | |
1616 | |
1617 if (sigkey != NULL) { | |
1618 sec_PKCS7CipherObject *decryptobj; | |
1619 unsigned int buflen; | |
1620 | |
1621 /* | |
1622 * For signedAndEnvelopedData, we first must decrypt the encrypted | |
1623 * digest with the bulk encryption key. The result is the normal | |
1624 * encrypted digest (aka the signature). | |
1625 */ | |
1626 decryptobj = sec_PKCS7CreateDecryptObject (sigkey, bulkid); | |
1627 if (decryptobj == NULL) | |
1628 goto done; | |
1629 | |
1630 buflen = sec_PKCS7DecryptLength (decryptobj, sig->len, PR_TRUE); | |
1631 PORT_Assert (buflen); | |
1632 if (buflen == 0) { /* something is wrong */ | |
1633 sec_PKCS7DestroyDecryptObject (decryptobj); | |
1634 goto done; | |
1635 } | |
1636 | |
1637 holder.data = (unsigned char*)PORT_Alloc (buflen); | |
1638 if (holder.data == NULL) { | |
1639 sec_PKCS7DestroyDecryptObject (decryptobj); | |
1640 goto done; | |
1641 } | |
1642 | |
1643 rv = sec_PKCS7Decrypt (decryptobj, holder.data, &holder.len, buflen, | |
1644 sig->data, sig->len, PR_TRUE); | |
1645 sec_PKCS7DestroyDecryptObject (decryptobj); | |
1646 if (rv != SECSuccess) { | |
1647 goto done; | |
1648 } | |
1649 | |
1650 sig = &holder; | |
1651 } | |
1652 | |
1653 goodsig = (PRBool)(VFY_VerifyDigestDirect(digest, publickey, sig, | |
1654 encTag, digestTag, cinfo->pwfn_arg) | |
1655 == SECSuccess); | |
1656 | |
1657 if (sigkey != NULL) { | |
1658 PORT_Assert (sig == &holder); | |
1659 PORT_ZFree (holder.data, holder.len); | |
1660 } | |
1661 } | |
1662 | |
1663 if (! goodsig) { | |
1664 /* | |
1665 * XXX Change the generic error into our specific one, because | |
1666 * in that case we get a better explanation out of the Security | |
1667 * Advisor. This is really a bug in our error strings (the | |
1668 * "generic" error has a lousy/wrong message associated with it | |
1669 * which assumes the signature verification was done for the | |
1670 * purposes of checking the issuer signature on a certificate) | |
1671 * but this is at least an easy workaround and/or in the | |
1672 * Security Advisor, which specifically checks for the error | |
1673 * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation | |
1674 * in that case but does not similarly check for | |
1675 * SEC_ERROR_BAD_SIGNATURE. It probably should, but then would | |
1676 * probably say the wrong thing in the case that it *was* the | |
1677 * certificate signature check that failed during the cert | |
1678 * verification done above. Our error handling is really a mess. | |
1679 */ | |
1680 if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE) | |
1681 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1682 } | |
1683 | 1592 |
1684 savecert: | 1593 savecert: |
1685 /* | 1594 /* |
1686 * Only save the smime profile if we are checking an email message and | 1595 * Only save the smime profile if we are checking an email message and |
1687 * the cert has an email address in it. | 1596 * the cert has an email address in it. |
1688 */ | 1597 */ |
1689 if ( cert->emailAddr && cert->emailAddr[0] && | 1598 if (cert->emailAddr && cert->emailAddr[0] && |
1690 » ( ( certusage == certUsageEmailSigner ) || | 1599 ((certusage == certUsageEmailSigner) || |
1691 » ( certusage == certUsageEmailRecipient ) ) ) { | 1600 (certusage == certUsageEmailRecipient))) { |
1692 » SECItem *profile = NULL; | 1601 SECItem *profile = NULL; |
1693 » int save_error; | 1602 int save_error; |
1694 | 1603 |
1695 » /* | 1604 /* |
1696 » * Remember the current error set because we do not care about | 1605 * Remember the current error set because we do not care about |
1697 » * anything set by the functions we are about to call. | 1606 * anything set by the functions we are about to call. |
1698 » */ | 1607 */ |
1699 » save_error = PORT_GetError(); | 1608 save_error = PORT_GetError(); |
1700 | 1609 |
1701 » if (goodsig && (signerinfo->authAttr != NULL)) { | 1610 if (goodsig && (signerinfo->authAttr != NULL)) { |
1702 » /* | 1611 /* |
1703 » * If the signature is good, then we can save the S/MIME profile, | 1612 * If the signature is good, then we can save the S/MIME profile, |
1704 » * if we have one. | 1613 * if we have one. |
1705 » */ | 1614 */ |
1706 » SEC_PKCS7Attribute *attr; | 1615 SEC_PKCS7Attribute *attr; |
1707 | 1616 |
1708 » attr = sec_PKCS7FindAttribute (signerinfo->authAttr, | 1617 attr = sec_PKCS7FindAttribute(signerinfo->authAttr, |
1709 » » » » » SEC_OID_PKCS9_SMIME_CAPABILITIES, | 1618 SEC_OID_PKCS9_SMIME_CAPABILITIES, PR_TRUE); |
1710 » » » » » PR_TRUE); | 1619 profile = sec_PKCS7AttributeValue(attr); |
1711 » profile = sec_PKCS7AttributeValue (attr); | 1620 } |
1712 » } | 1621 |
1713 | 1622 rv = CERT_SaveSMimeProfile(cert, profile, encoded_stime); |
1714 » rv = CERT_SaveSMimeProfile (cert, profile, encoded_stime); | 1623 |
1715 | 1624 /* |
1716 » /* | 1625 * Restore the saved error in case the calls above set a new |
1717 » * Restore the saved error in case the calls above set a new | 1626 * one that we do not actually care about. |
1718 » * one that we do not actually care about. | 1627 */ |
1719 » */ | 1628 PORT_SetError(save_error); |
1720 » PORT_SetError (save_error); | 1629 |
1721 | 1630 /* |
1722 » /* | 1631 * XXX Failure is not indicated anywhere -- the signature |
1723 » * XXX Failure is not indicated anywhere -- the signature | 1632 * verification itself is unaffected by whether or not the |
1724 » * verification itself is unaffected by whether or not the | 1633 * profile was successfully saved. |
1725 » * profile was successfully saved. | 1634 */ |
1726 » */ | 1635 } |
1727 } | |
1728 »······· | |
1729 | 1636 |
1730 done: | 1637 done: |
1731 | 1638 |
1732 /* | 1639 /* |
1733 * See comment above about why we do not want to destroy cert | 1640 * See comment above about why we do not want to destroy cert |
1734 * itself here. | 1641 * itself here. |
1735 */ | 1642 */ |
1736 | 1643 |
1737 if (certs != NULL) | 1644 if (certs != NULL) CERT_DestroyCertArray(certs, certcount); |
1738 » CERT_DestroyCertArray (certs, certcount); | 1645 |
1739 | 1646 if (publickey != NULL) SECKEY_DestroyPublicKey(publickey); |
1740 if (publickey != NULL) | 1647 |
1741 » SECKEY_DestroyPublicKey (publickey); | 1648 return goodsig; |
1742 | |
1743 return goodsig; | |
1744 } | 1649 } |
1745 | 1650 |
1746 /* | 1651 /* |
1747 * SEC_PKCS7VerifySignature | 1652 * SEC_PKCS7VerifySignature |
1748 * Look at a PKCS7 contentInfo and check if the signature is good. | 1653 * Look at a PKCS7 contentInfo and check if the signature is good. |
1749 * The verification checks that the signing cert is valid and trusted | 1654 * The verification checks that the signing cert is valid and trusted |
1750 * for the purpose specified by "certusage". | 1655 * for the purpose specified by "certusage". |
1751 * | 1656 * |
1752 * In addition, if "keepcerts" is true, add any new certificates found | 1657 * In addition, if "keepcerts" is true, add any new certificates found |
1753 * into our local database. | 1658 * into our local database. |
1754 */ | 1659 */ |
1755 PRBool | 1660 PRBool SEC_PKCS7VerifySignature(SEC_PKCS7ContentInfo *cinfo, |
1756 SEC_PKCS7VerifySignature(SEC_PKCS7ContentInfo *cinfo, | 1661 SECCertUsage certusage, PRBool keepcerts) { |
1757 » » » SECCertUsage certusage, | 1662 return sec_pkcs7_verify_signature(cinfo, certusage, NULL, HASH_AlgNULL, |
1758 » » » PRBool keepcerts) | 1663 keepcerts, NULL); |
1759 { | |
1760 return sec_pkcs7_verify_signature (cinfo, certusage, | |
1761 » » » » NULL, HASH_AlgNULL, keepcerts, NULL); | |
1762 } | 1664 } |
1763 | 1665 |
1764 /* | 1666 /* |
1765 * SEC_PKCS7VerifyDetachedSignature | 1667 * SEC_PKCS7VerifyDetachedSignature |
1766 * Look at a PKCS7 contentInfo and check if the signature matches | 1668 * Look at a PKCS7 contentInfo and check if the signature matches |
1767 * a passed-in digest (calculated, supposedly, from detached contents). | 1669 * a passed-in digest (calculated, supposedly, from detached contents). |
1768 * The verification checks that the signing cert is valid and trusted | 1670 * The verification checks that the signing cert is valid and trusted |
1769 * for the purpose specified by "certusage". | 1671 * for the purpose specified by "certusage". |
1770 * | 1672 * |
1771 * In addition, if "keepcerts" is true, add any new certificates found | 1673 * In addition, if "keepcerts" is true, add any new certificates found |
1772 * into our local database. | 1674 * into our local database. |
1773 */ | 1675 */ |
1774 PRBool | 1676 PRBool SEC_PKCS7VerifyDetachedSignature(SEC_PKCS7ContentInfo *cinfo, |
1775 SEC_PKCS7VerifyDetachedSignature(SEC_PKCS7ContentInfo *cinfo, | 1677 SECCertUsage certusage, |
1776 » » » » SECCertUsage certusage, | 1678 const SECItem *detached_digest, |
1777 » » » » const SECItem *detached_digest, | 1679 HASH_HashType digest_type, |
1778 » » » » HASH_HashType digest_type, | 1680 PRBool keepcerts) { |
1779 » » » » PRBool keepcerts) | 1681 return sec_pkcs7_verify_signature(cinfo, certusage, detached_digest, |
1780 { | 1682 digest_type, keepcerts, NULL); |
1781 return sec_pkcs7_verify_signature (cinfo, certusage, | |
1782 » » » » detached_digest, digest_type, | |
1783 » » » » keepcerts, NULL); | |
1784 } | 1683 } |
1785 | 1684 |
1786 /* | 1685 /* |
1787 * SEC_PKCS7VerifyDetachedSignatureAtTime | 1686 * SEC_PKCS7VerifyDetachedSignatureAtTime |
1788 * Look at a PKCS7 contentInfo and check if the signature matches | 1687 * Look at a PKCS7 contentInfo and check if the signature matches |
1789 * a passed-in digest (calculated, supposedly, from detached contents). | 1688 * a passed-in digest (calculated, supposedly, from detached contents). |
1790 * The verification checks that the signing cert is valid and trusted | 1689 * The verification checks that the signing cert is valid and trusted |
1791 * for the purpose specified by "certusage" at time "atTime". | 1690 * for the purpose specified by "certusage" at time "atTime". |
1792 * | 1691 * |
1793 * In addition, if "keepcerts" is true, add any new certificates found | 1692 * In addition, if "keepcerts" is true, add any new certificates found |
1794 * into our local database. | 1693 * into our local database. |
1795 */ | 1694 */ |
1796 PRBool | 1695 PRBool SEC_PKCS7VerifyDetachedSignatureAtTime(SEC_PKCS7ContentInfo *cinfo, |
1797 SEC_PKCS7VerifyDetachedSignatureAtTime(SEC_PKCS7ContentInfo *cinfo, | 1696 SECCertUsage certusage, |
1798 » » » » SECCertUsage certusage, | 1697 const SECItem *detached_digest, |
1799 » » » » const SECItem *detached_digest, | 1698 HASH_HashType digest_type, |
1800 » » » » HASH_HashType digest_type, | 1699 PRBool keepcerts, PRTime atTime) { |
1801 » » » » PRBool keepcerts, | 1700 return sec_pkcs7_verify_signature(cinfo, certusage, detached_digest, |
1802 » » » » PRTime atTime) | 1701 digest_type, keepcerts, &atTime); |
1803 { | |
1804 return sec_pkcs7_verify_signature (cinfo, certusage, | |
1805 » » » » detached_digest, digest_type, | |
1806 » » » » keepcerts, &atTime); | |
1807 } | 1702 } |
1808 | 1703 |
1809 /* | 1704 /* |
1810 * Return the asked-for portion of the name of the signer of a PKCS7 | 1705 * Return the asked-for portion of the name of the signer of a PKCS7 |
1811 * signed object. | 1706 * signed object. |
1812 * | 1707 * |
1813 * Returns a pointer to allocated memory, which must be freed. | 1708 * Returns a pointer to allocated memory, which must be freed. |
1814 * A NULL return value is an error. | 1709 * A NULL return value is an error. |
1815 */ | 1710 */ |
1816 | 1711 |
1817 #define sec_common_name 1 | 1712 #define sec_common_name 1 |
1818 #define sec_email_address 2 | 1713 #define sec_email_address 2 |
1819 | 1714 |
1820 static char * | 1715 static char *sec_pkcs7_get_signer_cert_info(SEC_PKCS7ContentInfo *cinfo, |
1821 sec_pkcs7_get_signer_cert_info(SEC_PKCS7ContentInfo *cinfo, int selector) | 1716 int selector) { |
1822 { | 1717 SECOidTag kind; |
1823 SECOidTag kind; | 1718 SEC_PKCS7SignerInfo **signerinfos; |
1824 SEC_PKCS7SignerInfo **signerinfos; | 1719 CERTCertificate *signercert; |
1825 CERTCertificate *signercert; | 1720 char *container; |
1826 char *container; | 1721 |
1827 | 1722 kind = SEC_PKCS7ContentType(cinfo); |
1828 kind = SEC_PKCS7ContentType (cinfo); | 1723 switch (kind) { |
1829 switch (kind) { | 1724 default: |
1830 default: | 1725 case SEC_OID_PKCS7_DATA: |
1831 case SEC_OID_PKCS7_DATA: | 1726 case SEC_OID_PKCS7_DIGESTED_DATA: |
1832 case SEC_OID_PKCS7_DIGESTED_DATA: | 1727 case SEC_OID_PKCS7_ENVELOPED_DATA: |
1833 case SEC_OID_PKCS7_ENVELOPED_DATA: | 1728 case SEC_OID_PKCS7_ENCRYPTED_DATA: |
1834 case SEC_OID_PKCS7_ENCRYPTED_DATA: | 1729 PORT_Assert(0); |
1835 » PORT_Assert (0); | 1730 return NULL; |
1836 » return NULL; | 1731 case SEC_OID_PKCS7_SIGNED_DATA: { |
1837 case SEC_OID_PKCS7_SIGNED_DATA: | 1732 SEC_PKCS7SignedData *sdp; |
1838 » { | 1733 |
1839 » SEC_PKCS7SignedData *sdp; | 1734 sdp = cinfo->content.signedData; |
1840 | 1735 signerinfos = sdp->signerInfos; |
1841 » sdp = cinfo->content.signedData; | 1736 } break; |
1842 » signerinfos = sdp->signerInfos; | 1737 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: { |
1843 » } | 1738 SEC_PKCS7SignedAndEnvelopedData *saedp; |
1844 » break; | 1739 |
1845 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | 1740 saedp = cinfo->content.signedAndEnvelopedData; |
1846 » { | 1741 signerinfos = saedp->signerInfos; |
1847 » SEC_PKCS7SignedAndEnvelopedData *saedp; | 1742 } break; |
1848 | 1743 } |
1849 » saedp = cinfo->content.signedAndEnvelopedData; | 1744 |
1850 » signerinfos = saedp->signerInfos; | 1745 if (signerinfos == NULL || signerinfos[0] == NULL) return NULL; |
1851 » } | 1746 |
1852 » break; | 1747 signercert = signerinfos[0]->cert; |
1853 } | 1748 |
1854 | 1749 /* |
1855 if (signerinfos == NULL || signerinfos[0] == NULL) | 1750 * No cert there; see if we can find one by calling verify ourselves. |
1856 » return NULL; | 1751 */ |
1857 | 1752 if (signercert == NULL) { |
| 1753 /* |
| 1754 * The cert usage does not matter in this case, because we do not |
| 1755 * actually care about the verification itself, but we have to pick |
| 1756 * some valid usage to pass in. |
| 1757 */ |
| 1758 (void)sec_pkcs7_verify_signature(cinfo, certUsageEmailSigner, NULL, |
| 1759 HASH_AlgNULL, PR_FALSE, NULL); |
1858 signercert = signerinfos[0]->cert; | 1760 signercert = signerinfos[0]->cert; |
1859 | 1761 if (signercert == NULL) return NULL; |
1860 /* | 1762 } |
1861 * No cert there; see if we can find one by calling verify ourselves. | 1763 |
1862 */ | 1764 switch (selector) { |
1863 if (signercert == NULL) { | 1765 case sec_common_name: |
1864 » /* | 1766 container = CERT_GetCommonName(&signercert->subject); |
1865 » * The cert usage does not matter in this case, because we do not | 1767 break; |
1866 » * actually care about the verification itself, but we have to pick | 1768 case sec_email_address: |
1867 » * some valid usage to pass in. | 1769 if (signercert->emailAddr && signercert->emailAddr[0]) { |
1868 » */ | 1770 container = PORT_Strdup(signercert->emailAddr); |
1869 » (void) sec_pkcs7_verify_signature (cinfo, certUsageEmailSigner, | 1771 } else { |
1870 » » » » » NULL, HASH_AlgNULL, PR_FALSE, NULL); | 1772 container = NULL; |
1871 » signercert = signerinfos[0]->cert; | 1773 } |
1872 » if (signercert == NULL) | 1774 break; |
1873 » return NULL; | 1775 default: |
1874 } | 1776 PORT_Assert(0); |
1875 | 1777 container = NULL; |
1876 switch (selector) { | 1778 break; |
1877 case sec_common_name: | 1779 } |
1878 » container = CERT_GetCommonName (&signercert->subject); | 1780 |
1879 » break; | 1781 return container; |
1880 case sec_email_address: | 1782 } |
1881 » if(signercert->emailAddr && signercert->emailAddr[0]) { | 1783 |
1882 » container = PORT_Strdup(signercert->emailAddr); | 1784 char *SEC_PKCS7GetSignerCommonName(SEC_PKCS7ContentInfo *cinfo) { |
1883 » } else { | 1785 return sec_pkcs7_get_signer_cert_info(cinfo, sec_common_name); |
1884 » container = NULL; | 1786 } |
1885 » } | 1787 |
1886 » break; | 1788 char *SEC_PKCS7GetSignerEmailAddress(SEC_PKCS7ContentInfo *cinfo) { |
1887 default: | 1789 return sec_pkcs7_get_signer_cert_info(cinfo, sec_email_address); |
1888 » PORT_Assert (0); | 1790 } |
1889 » container = NULL; | |
1890 » break; | |
1891 } | |
1892 | |
1893 return container; | |
1894 } | |
1895 | |
1896 char * | |
1897 SEC_PKCS7GetSignerCommonName(SEC_PKCS7ContentInfo *cinfo) | |
1898 { | |
1899 return sec_pkcs7_get_signer_cert_info(cinfo, sec_common_name); | |
1900 } | |
1901 | |
1902 char * | |
1903 SEC_PKCS7GetSignerEmailAddress(SEC_PKCS7ContentInfo *cinfo) | |
1904 { | |
1905 return sec_pkcs7_get_signer_cert_info(cinfo, sec_email_address); | |
1906 } | |
1907 | |
1908 | 1791 |
1909 /* | 1792 /* |
1910 * Return the signing time, in UTCTime format, of a PKCS7 contentInfo. | 1793 * Return the signing time, in UTCTime format, of a PKCS7 contentInfo. |
1911 */ | 1794 */ |
1912 SECItem * | 1795 SECItem *SEC_PKCS7GetSigningTime(SEC_PKCS7ContentInfo *cinfo) { |
1913 SEC_PKCS7GetSigningTime(SEC_PKCS7ContentInfo *cinfo) | 1796 SEC_PKCS7SignerInfo **signerinfos; |
1914 { | 1797 SEC_PKCS7Attribute *attr; |
1915 SEC_PKCS7SignerInfo **signerinfos; | 1798 |
1916 SEC_PKCS7Attribute *attr; | 1799 if (SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_SIGNED_DATA) return NULL; |
1917 | 1800 |
1918 if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA) | 1801 signerinfos = cinfo->content.signedData->signerInfos; |
1919 » return NULL; | 1802 |
1920 | 1803 /* |
1921 signerinfos = cinfo->content.signedData->signerInfos; | 1804 * No signature, or more than one, means no deal. |
1922 | 1805 */ |
1923 /* | 1806 if (signerinfos == NULL || signerinfos[0] == NULL || signerinfos[1] != NULL) |
1924 * No signature, or more than one, means no deal. | 1807 return NULL; |
1925 */ | 1808 |
1926 if (signerinfos == NULL || signerinfos[0] == NULL || signerinfos[1] != NULL) | 1809 attr = sec_PKCS7FindAttribute(signerinfos[0]->authAttr, |
1927 » return NULL; | 1810 SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE); |
1928 | 1811 return sec_PKCS7AttributeValue(attr); |
1929 attr = sec_PKCS7FindAttribute (signerinfos[0]->authAttr, | 1812 } |
1930 » » » » SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE); | |
1931 return sec_PKCS7AttributeValue (attr); | |
1932 } | |
OLD | NEW |