]>
Commit | Line | Data |
---|---|---|
d02b48c6 | 1 | /* crypto/pkcs7/pk7_doit.c */ |
58964a49 | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
d02b48c6 RE |
3 | * All rights reserved. |
4 | * | |
5 | * This package is an SSL implementation written | |
6 | * by Eric Young (eay@cryptsoft.com). | |
7 | * The implementation was written so as to conform with Netscapes SSL. | |
8 | * | |
9 | * This library is free for commercial and non-commercial use as long as | |
10 | * the following conditions are aheared to. The following conditions | |
11 | * apply to all code found in this distribution, be it the RC4, RSA, | |
12 | * lhash, DES, etc., code; not just the SSL code. The SSL documentation | |
13 | * included with this distribution is covered by the same copyright terms | |
14 | * except that the holder is Tim Hudson (tjh@cryptsoft.com). | |
15 | * | |
16 | * Copyright remains Eric Young's, and as such any Copyright notices in | |
17 | * the code are not to be removed. | |
18 | * If this package is used in a product, Eric Young should be given attribution | |
19 | * as the author of the parts of the library used. | |
20 | * This can be in the form of a textual message at program startup or | |
21 | * in documentation (online or textual) provided with the package. | |
22 | * | |
23 | * Redistribution and use in source and binary forms, with or without | |
24 | * modification, are permitted provided that the following conditions | |
25 | * are met: | |
26 | * 1. Redistributions of source code must retain the copyright | |
27 | * notice, this list of conditions and the following disclaimer. | |
28 | * 2. Redistributions in binary form must reproduce the above copyright | |
29 | * notice, this list of conditions and the following disclaimer in the | |
30 | * documentation and/or other materials provided with the distribution. | |
31 | * 3. All advertising materials mentioning features or use of this software | |
32 | * must display the following acknowledgement: | |
33 | * "This product includes cryptographic software written by | |
34 | * Eric Young (eay@cryptsoft.com)" | |
35 | * The word 'cryptographic' can be left out if the rouines from the library | |
36 | * being used are not cryptographic related :-). | |
37 | * 4. If you include any Windows specific code (or a derivative thereof) from | |
38 | * the apps directory (application code) you must include an acknowledgement: | |
39 | * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" | |
40 | * | |
41 | * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND | |
42 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
43 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
44 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
45 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
46 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
47 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
48 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
49 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
50 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
51 | * SUCH DAMAGE. | |
52 | * | |
53 | * The licence and distribution terms for any publically available version or | |
54 | * derivative of this code cannot be changed. i.e. this code cannot simply be | |
55 | * copied and put under another distribution licence | |
56 | * [including the GNU Public Licence.] | |
57 | */ | |
58 | ||
59 | #include <stdio.h> | |
60 | #include "cryptlib.h" | |
ec577822 BM |
61 | #include <openssl/rand.h> |
62 | #include <openssl/objects.h> | |
63 | #include <openssl/x509.h> | |
5a9a4b29 | 64 | #include <openssl/x509v3.h> |
8f2e4fdf | 65 | #include <openssl/err.h> |
d02b48c6 | 66 | |
b6436ff2 BL |
67 | static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype, |
68 | void *value); | |
69 | static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid); | |
dfeab068 | 70 | |
67fec850 RL |
71 | static int PKCS7_type_is_other(PKCS7* p7) |
72 | { | |
73 | int isOther=1; | |
74 | ||
75 | int nid=OBJ_obj2nid(p7->type); | |
76 | ||
77 | switch( nid ) | |
78 | { | |
79 | case NID_pkcs7_data: | |
80 | case NID_pkcs7_signed: | |
81 | case NID_pkcs7_enveloped: | |
82 | case NID_pkcs7_signedAndEnveloped: | |
83 | case NID_pkcs7_digest: | |
84 | case NID_pkcs7_encrypted: | |
85 | isOther=0; | |
86 | break; | |
87 | default: | |
88 | isOther=1; | |
89 | } | |
90 | ||
91 | return isOther; | |
92 | ||
93 | } | |
94 | ||
caf044cb | 95 | static ASN1_OCTET_STRING *PKCS7_get_octet_string(PKCS7 *p7) |
67fec850 | 96 | { |
caf044cb DSH |
97 | if ( PKCS7_type_is_data(p7)) |
98 | return p7->d.data; | |
99 | if ( PKCS7_type_is_other(p7) && p7->d.other | |
100 | && (p7->d.other->type == V_ASN1_OCTET_STRING)) | |
101 | return p7->d.other->value.octet_string; | |
102 | return NULL; | |
67fec850 RL |
103 | } |
104 | ||
c5a55463 DSH |
105 | static int PKCS7_bio_add_digest(BIO **pbio, X509_ALGOR *alg) |
106 | { | |
107 | BIO *btmp; | |
108 | const EVP_MD *md; | |
109 | if ((btmp=BIO_new(BIO_f_md())) == NULL) | |
110 | { | |
111 | PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST,ERR_R_BIO_LIB); | |
112 | goto err; | |
113 | } | |
114 | ||
115 | md=EVP_get_digestbyobj(alg->algorithm); | |
116 | if (md == NULL) | |
117 | { | |
118 | PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST,PKCS7_R_UNKNOWN_DIGEST_TYPE); | |
119 | goto err; | |
120 | } | |
121 | ||
122 | BIO_set_md(btmp,md); | |
123 | if (*pbio == NULL) | |
124 | *pbio=btmp; | |
125 | else if (!BIO_push(*pbio,btmp)) | |
126 | { | |
127 | PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST,ERR_R_BIO_LIB); | |
128 | goto err; | |
129 | } | |
130 | btmp=NULL; | |
131 | ||
132 | return 1; | |
133 | ||
134 | err: | |
135 | if (btmp) | |
136 | BIO_free(btmp); | |
137 | return 0; | |
138 | ||
139 | } | |
140 | ||
399a6f0b DSH |
141 | static int pkcs7_encode_rinfo(PKCS7_RECIP_INFO *ri, |
142 | unsigned char *key, int keylen) | |
143 | { | |
144 | EVP_PKEY_CTX *pctx = NULL; | |
145 | EVP_PKEY *pkey = NULL; | |
146 | unsigned char *ek = NULL; | |
147 | int ret = 0; | |
0e345353 | 148 | size_t eklen; |
399a6f0b DSH |
149 | |
150 | pkey = X509_get_pubkey(ri->cert); | |
151 | ||
152 | if (!pkey) | |
153 | return 0; | |
154 | ||
155 | pctx = EVP_PKEY_CTX_new(pkey, NULL); | |
156 | if (!pctx) | |
157 | return 0; | |
158 | ||
159 | if (EVP_PKEY_encrypt_init(pctx) <= 0) | |
160 | goto err; | |
161 | ||
162 | if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_ENCRYPT, | |
163 | EVP_PKEY_CTRL_PKCS7_ENCRYPT, 0, ri) <= 0) | |
164 | { | |
165 | PKCS7err(PKCS7_F_PKCS7_ENCODE_RINFO, PKCS7_R_CTRL_ERROR); | |
166 | goto err; | |
167 | } | |
168 | ||
169 | if (EVP_PKEY_encrypt(pctx, NULL, &eklen, key, keylen) <= 0) | |
170 | goto err; | |
171 | ||
172 | ek = OPENSSL_malloc(eklen); | |
173 | ||
174 | if (ek == NULL) | |
175 | { | |
176 | PKCS7err(PKCS7_F_PKCS7_ENCODE_RINFO, ERR_R_MALLOC_FAILURE); | |
177 | goto err; | |
178 | } | |
179 | ||
180 | if (EVP_PKEY_encrypt(pctx, ek, &eklen, key, keylen) <= 0) | |
181 | goto err; | |
182 | ||
183 | ASN1_STRING_set0(ri->enc_key, ek, eklen); | |
184 | ek = NULL; | |
185 | ||
186 | ret = 1; | |
187 | ||
188 | err: | |
189 | if (pkey) | |
190 | EVP_PKEY_free(pkey); | |
191 | if (pctx) | |
192 | EVP_PKEY_CTX_free(pctx); | |
193 | if (ek) | |
194 | OPENSSL_free(ek); | |
195 | return ret; | |
196 | ||
197 | } | |
198 | ||
199 | ||
777c47ac BL |
200 | static int pkcs7_decrypt_rinfo(unsigned char **pek, int *peklen, |
201 | PKCS7_RECIP_INFO *ri, EVP_PKEY *pkey) | |
7144c421 DSH |
202 | { |
203 | EVP_PKEY_CTX *pctx = NULL; | |
204 | unsigned char *ek = NULL; | |
0e345353 | 205 | size_t eklen; |
7144c421 DSH |
206 | |
207 | int ret = 0; | |
208 | ||
209 | pctx = EVP_PKEY_CTX_new(pkey, NULL); | |
210 | if (!pctx) | |
211 | return 0; | |
212 | ||
213 | if (EVP_PKEY_decrypt_init(pctx) <= 0) | |
214 | goto err; | |
215 | ||
216 | if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DECRYPT, | |
217 | EVP_PKEY_CTRL_PKCS7_DECRYPT, 0, ri) <= 0) | |
218 | { | |
219 | PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, PKCS7_R_CTRL_ERROR); | |
220 | goto err; | |
221 | } | |
222 | ||
223 | if (EVP_PKEY_decrypt(pctx, NULL, &eklen, | |
224 | ri->enc_key->data, ri->enc_key->length) <= 0) | |
225 | goto err; | |
226 | ||
227 | ek = OPENSSL_malloc(eklen); | |
228 | ||
229 | if (ek == NULL) | |
230 | { | |
231 | PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, ERR_R_MALLOC_FAILURE); | |
232 | goto err; | |
233 | } | |
234 | ||
235 | if (EVP_PKEY_decrypt(pctx, ek, &eklen, | |
236 | ri->enc_key->data, ri->enc_key->length) <= 0) | |
237 | { | |
238 | PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, ERR_R_EVP_LIB); | |
239 | goto err; | |
240 | } | |
241 | ||
242 | ret = 1; | |
243 | ||
244 | *pek = ek; | |
245 | *peklen = eklen; | |
246 | ||
247 | err: | |
248 | if (pctx) | |
249 | EVP_PKEY_CTX_free(pctx); | |
250 | if (!ret && ek) | |
251 | OPENSSL_free(ek); | |
252 | ||
253 | return ret; | |
254 | } | |
399a6f0b | 255 | |
6b691a5c | 256 | BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) |
d02b48c6 | 257 | { |
77fe058c | 258 | int i; |
dfeab068 | 259 | BIO *out=NULL,*btmp=NULL; |
c5a55463 | 260 | X509_ALGOR *xa = NULL; |
e778802f | 261 | const EVP_CIPHER *evp_cipher=NULL; |
426edadf | 262 | STACK_OF(X509_ALGOR) *md_sk=NULL; |
8f0edcd1 | 263 | STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL; |
58964a49 RE |
264 | X509_ALGOR *xalg=NULL; |
265 | PKCS7_RECIP_INFO *ri=NULL; | |
c5a55463 | 266 | ASN1_OCTET_STRING *os=NULL; |
d02b48c6 RE |
267 | |
268 | i=OBJ_obj2nid(p7->type); | |
269 | p7->state=PKCS7_S_HEADER; | |
270 | ||
271 | switch (i) | |
272 | { | |
273 | case NID_pkcs7_signed: | |
58964a49 | 274 | md_sk=p7->d.sign->md_algs; |
c5a55463 | 275 | os = PKCS7_get_octet_string(p7->d.sign->contents); |
58964a49 RE |
276 | break; |
277 | case NID_pkcs7_signedAndEnveloped: | |
278 | rsk=p7->d.signed_and_enveloped->recipientinfo; | |
279 | md_sk=p7->d.signed_and_enveloped->md_algs; | |
84fa704c DSH |
280 | xalg=p7->d.signed_and_enveloped->enc_data->algorithm; |
281 | evp_cipher=p7->d.signed_and_enveloped->enc_data->cipher; | |
58964a49 | 282 | if (evp_cipher == NULL) |
d02b48c6 | 283 | { |
84fa704c DSH |
284 | PKCS7err(PKCS7_F_PKCS7_DATAINIT, |
285 | PKCS7_R_CIPHER_NOT_INITIALIZED); | |
58964a49 RE |
286 | goto err; |
287 | } | |
58964a49 | 288 | break; |
dfeab068 RE |
289 | case NID_pkcs7_enveloped: |
290 | rsk=p7->d.enveloped->recipientinfo; | |
84fa704c DSH |
291 | xalg=p7->d.enveloped->enc_data->algorithm; |
292 | evp_cipher=p7->d.enveloped->enc_data->cipher; | |
dfeab068 RE |
293 | if (evp_cipher == NULL) |
294 | { | |
84fa704c DSH |
295 | PKCS7err(PKCS7_F_PKCS7_DATAINIT, |
296 | PKCS7_R_CIPHER_NOT_INITIALIZED); | |
dfeab068 RE |
297 | goto err; |
298 | } | |
dfeab068 | 299 | break; |
c5a55463 DSH |
300 | case NID_pkcs7_digest: |
301 | xa = p7->d.digest->md; | |
302 | os = PKCS7_get_octet_string(p7->d.digest->contents); | |
303 | break; | |
559d5013 DSH |
304 | case NID_pkcs7_data: |
305 | break; | |
58964a49 RE |
306 | default: |
307 | PKCS7err(PKCS7_F_PKCS7_DATAINIT,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); | |
308 | goto err; | |
309 | } | |
310 | ||
c5a55463 DSH |
311 | for (i=0; i<sk_X509_ALGOR_num(md_sk); i++) |
312 | if (!PKCS7_bio_add_digest(&out, sk_X509_ALGOR_value(md_sk, i))) | |
313 | goto err; | |
d02b48c6 | 314 | |
c5a55463 DSH |
315 | if (xa && !PKCS7_bio_add_digest(&out, xa)) |
316 | goto err; | |
58964a49 RE |
317 | |
318 | if (evp_cipher != NULL) | |
319 | { | |
320 | unsigned char key[EVP_MAX_KEY_LENGTH]; | |
321 | unsigned char iv[EVP_MAX_IV_LENGTH]; | |
322 | int keylen,ivlen; | |
84fa704c | 323 | EVP_CIPHER_CTX *ctx; |
58964a49 | 324 | |
dfeab068 RE |
325 | if ((btmp=BIO_new(BIO_f_cipher())) == NULL) |
326 | { | |
327 | PKCS7err(PKCS7_F_PKCS7_DATAINIT,ERR_R_BIO_LIB); | |
328 | goto err; | |
329 | } | |
84fa704c | 330 | BIO_get_cipher_ctx(btmp, &ctx); |
58964a49 RE |
331 | keylen=EVP_CIPHER_key_length(evp_cipher); |
332 | ivlen=EVP_CIPHER_iv_length(evp_cipher); | |
84fa704c | 333 | xalg->algorithm = OBJ_nid2obj(EVP_CIPHER_type(evp_cipher)); |
689f9fab NL |
334 | if (ivlen > 0) |
335 | if (RAND_pseudo_bytes(iv,ivlen) <= 0) | |
336 | goto err; | |
216659eb DSH |
337 | if (EVP_CipherInit_ex(ctx, evp_cipher, NULL, NULL, NULL, 1)<=0) |
338 | goto err; | |
339 | if (EVP_CIPHER_CTX_rand_key(ctx, key) <= 0) | |
340 | goto err; | |
341 | if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1) <= 0) | |
342 | goto err; | |
58964a49 | 343 | |
884e8ec6 | 344 | if (ivlen > 0) { |
689f9fab NL |
345 | if (xalg->parameter == NULL) { |
346 | xalg->parameter = ASN1_TYPE_new(); | |
347 | if (xalg->parameter == NULL) | |
348 | goto err; | |
349 | } | |
884e8ec6 | 350 | if(EVP_CIPHER_param_to_asn1(ctx, xalg->parameter) < 0) |
689f9fab | 351 | goto err; |
884e8ec6 | 352 | } |
58964a49 RE |
353 | |
354 | /* Lets do the pub key stuff :-) */ | |
8f0edcd1 | 355 | for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) |
58964a49 | 356 | { |
8f0edcd1 | 357 | ri=sk_PKCS7_RECIP_INFO_value(rsk,i); |
399a6f0b | 358 | if (pkcs7_encode_rinfo(ri, key, keylen) <= 0) |
a0e7c8ee | 359 | goto err; |
58964a49 | 360 | } |
4579924b | 361 | OPENSSL_cleanse(key, keylen); |
58964a49 | 362 | |
58964a49 RE |
363 | if (out == NULL) |
364 | out=btmp; | |
365 | else | |
366 | BIO_push(out,btmp); | |
dfeab068 | 367 | btmp=NULL; |
58964a49 RE |
368 | } |
369 | ||
caf044cb DSH |
370 | if (bio == NULL) |
371 | { | |
9d6b1ce6 | 372 | if (PKCS7_is_detached(p7)) |
d02b48c6 | 373 | bio=BIO_new(BIO_s_null()); |
c5a55463 DSH |
374 | else if (os && os->length > 0) |
375 | bio = BIO_new_mem_buf(os->data, os->length); | |
376 | if(bio == NULL) | |
caf044cb | 377 | { |
c5a55463 | 378 | bio=BIO_new(BIO_s_mem()); |
689f9fab NL |
379 | if (bio == NULL) |
380 | goto err; | |
c5a55463 | 381 | BIO_set_mem_eof_return(bio,0); |
d02b48c6 | 382 | } |
c5a55463 | 383 | } |
559d5013 DSH |
384 | if (out) |
385 | BIO_push(out,bio); | |
386 | else | |
387 | out = bio; | |
dfeab068 RE |
388 | bio=NULL; |
389 | if (0) | |
390 | { | |
391 | err: | |
392 | if (out != NULL) | |
393 | BIO_free_all(out); | |
394 | if (btmp != NULL) | |
395 | BIO_free_all(btmp); | |
396 | out=NULL; | |
397 | } | |
d02b48c6 | 398 | return(out); |
dfeab068 RE |
399 | } |
400 | ||
8f2e4fdf DSH |
401 | static int pkcs7_cmp_ri(PKCS7_RECIP_INFO *ri, X509 *pcert) |
402 | { | |
403 | int ret; | |
404 | ret = X509_NAME_cmp(ri->issuer_and_serial->issuer, | |
405 | pcert->cert_info->issuer); | |
406 | if (ret) | |
407 | return ret; | |
408 | return M_ASN1_INTEGER_cmp(pcert->cert_info->serialNumber, | |
409 | ri->issuer_and_serial->serial); | |
410 | } | |
411 | ||
dfeab068 | 412 | /* int */ |
84fa704c | 413 | BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) |
dfeab068 RE |
414 | { |
415 | int i,j; | |
416 | BIO *out=NULL,*btmp=NULL,*etmp=NULL,*bio=NULL; | |
dfeab068 RE |
417 | X509_ALGOR *xa; |
418 | ASN1_OCTET_STRING *data_body=NULL; | |
e778802f BL |
419 | const EVP_MD *evp_md; |
420 | const EVP_CIPHER *evp_cipher=NULL; | |
dfeab068 RE |
421 | EVP_CIPHER_CTX *evp_ctx=NULL; |
422 | X509_ALGOR *enc_alg=NULL; | |
426edadf | 423 | STACK_OF(X509_ALGOR) *md_sk=NULL; |
8f0edcd1 | 424 | STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL; |
dfeab068 | 425 | PKCS7_RECIP_INFO *ri=NULL; |
dfeab068 RE |
426 | |
427 | i=OBJ_obj2nid(p7->type); | |
428 | p7->state=PKCS7_S_HEADER; | |
429 | ||
430 | switch (i) | |
431 | { | |
432 | case NID_pkcs7_signed: | |
caf044cb | 433 | data_body=PKCS7_get_octet_string(p7->d.sign->contents); |
dfeab068 RE |
434 | md_sk=p7->d.sign->md_algs; |
435 | break; | |
436 | case NID_pkcs7_signedAndEnveloped: | |
437 | rsk=p7->d.signed_and_enveloped->recipientinfo; | |
438 | md_sk=p7->d.signed_and_enveloped->md_algs; | |
439 | data_body=p7->d.signed_and_enveloped->enc_data->enc_data; | |
440 | enc_alg=p7->d.signed_and_enveloped->enc_data->algorithm; | |
77fe058c | 441 | evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm); |
dfeab068 RE |
442 | if (evp_cipher == NULL) |
443 | { | |
84fa704c | 444 | PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE); |
dfeab068 RE |
445 | goto err; |
446 | } | |
dfeab068 RE |
447 | break; |
448 | case NID_pkcs7_enveloped: | |
449 | rsk=p7->d.enveloped->recipientinfo; | |
450 | enc_alg=p7->d.enveloped->enc_data->algorithm; | |
451 | data_body=p7->d.enveloped->enc_data->enc_data; | |
77fe058c | 452 | evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm); |
dfeab068 RE |
453 | if (evp_cipher == NULL) |
454 | { | |
84fa704c | 455 | PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE); |
dfeab068 RE |
456 | goto err; |
457 | } | |
dfeab068 RE |
458 | break; |
459 | default: | |
84fa704c | 460 | PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); |
dfeab068 RE |
461 | goto err; |
462 | } | |
463 | ||
464 | /* We will be checking the signature */ | |
465 | if (md_sk != NULL) | |
466 | { | |
426edadf | 467 | for (i=0; i<sk_X509_ALGOR_num(md_sk); i++) |
dfeab068 | 468 | { |
426edadf | 469 | xa=sk_X509_ALGOR_value(md_sk,i); |
dfeab068 RE |
470 | if ((btmp=BIO_new(BIO_f_md())) == NULL) |
471 | { | |
84fa704c | 472 | PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB); |
dfeab068 RE |
473 | goto err; |
474 | } | |
475 | ||
476 | j=OBJ_obj2nid(xa->algorithm); | |
77fe058c | 477 | evp_md=EVP_get_digestbynid(j); |
dfeab068 RE |
478 | if (evp_md == NULL) |
479 | { | |
84fa704c | 480 | PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNKNOWN_DIGEST_TYPE); |
dfeab068 RE |
481 | goto err; |
482 | } | |
483 | ||
484 | BIO_set_md(btmp,evp_md); | |
485 | if (out == NULL) | |
486 | out=btmp; | |
487 | else | |
488 | BIO_push(out,btmp); | |
489 | btmp=NULL; | |
490 | } | |
491 | } | |
492 | ||
493 | if (evp_cipher != NULL) | |
494 | { | |
495 | #if 0 | |
496 | unsigned char key[EVP_MAX_KEY_LENGTH]; | |
497 | unsigned char iv[EVP_MAX_IV_LENGTH]; | |
498 | unsigned char *p; | |
499 | int keylen,ivlen; | |
500 | int max; | |
501 | X509_OBJECT ret; | |
502 | #endif | |
7144c421 DSH |
503 | unsigned char *ek = NULL; |
504 | int eklen; | |
dfeab068 RE |
505 | |
506 | if ((etmp=BIO_new(BIO_f_cipher())) == NULL) | |
507 | { | |
84fa704c | 508 | PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB); |
dfeab068 RE |
509 | goto err; |
510 | } | |
511 | ||
512 | /* It was encrypted, we need to decrypt the secret key | |
513 | * with the private key */ | |
514 | ||
84fa704c DSH |
515 | /* Find the recipientInfo which matches the passed certificate |
516 | * (if any) | |
10243d97 DSH |
517 | */ |
518 | ||
7144c421 DSH |
519 | if (pcert) |
520 | { | |
521 | for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) | |
522 | { | |
8f2e4fdf DSH |
523 | ri=sk_PKCS7_RECIP_INFO_value(rsk,i); |
524 | if (!pkcs7_cmp_ri(ri, pcert)) | |
525 | break; | |
526 | ri=NULL; | |
7144c421 DSH |
527 | } |
528 | if (ri == NULL) | |
529 | { | |
8f2e4fdf DSH |
530 | PKCS7err(PKCS7_F_PKCS7_DATADECODE, |
531 | PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE); | |
532 | goto err; | |
7144c421 | 533 | } |
dfeab068 RE |
534 | } |
535 | ||
8f2e4fdf DSH |
536 | /* If we haven't got a certificate try each ri in turn */ |
537 | ||
538 | if (pcert == NULL) | |
dfeab068 | 539 | { |
8f2e4fdf DSH |
540 | for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) |
541 | { | |
542 | ri=sk_PKCS7_RECIP_INFO_value(rsk,i); | |
7144c421 DSH |
543 | if (pkcs7_decrypt_rinfo(&ek, &eklen, |
544 | ri, pkey) > 0) | |
8f2e4fdf DSH |
545 | break; |
546 | ERR_clear_error(); | |
547 | ri = NULL; | |
548 | } | |
549 | if (ri == NULL) | |
550 | { | |
551 | PKCS7err(PKCS7_F_PKCS7_DATADECODE, | |
552 | PKCS7_R_NO_RECIPIENT_MATCHES_KEY); | |
553 | goto err; | |
554 | } | |
555 | } | |
556 | else | |
557 | { | |
7144c421 | 558 | if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey) <= 0) |
8f2e4fdf | 559 | goto err; |
dfeab068 RE |
560 | } |
561 | ||
562 | evp_ctx=NULL; | |
563 | BIO_get_cipher_ctx(etmp,&evp_ctx); | |
216659eb DSH |
564 | if (EVP_CipherInit_ex(evp_ctx,evp_cipher,NULL,NULL,NULL,0) <= 0) |
565 | goto err; | |
dfeab068 | 566 | if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0) |
4ac881ed | 567 | goto err; |
dfeab068 | 568 | |
7144c421 | 569 | if (eklen != EVP_CIPHER_CTX_key_length(evp_ctx)) { |
7f060601 | 570 | /* Some S/MIME clients don't use the same key |
9716a8f9 DSH |
571 | * and effective key length. The key length is |
572 | * determined by the size of the decrypted RSA key. | |
9716a8f9 | 573 | */ |
7144c421 | 574 | if(!EVP_CIPHER_CTX_set_key_length(evp_ctx, eklen)) |
63da21c0 | 575 | { |
9716a8f9 | 576 | PKCS7err(PKCS7_F_PKCS7_DATADECODE, |
84fa704c | 577 | PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH); |
9716a8f9 | 578 | goto err; |
63da21c0 | 579 | } |
7f060601 | 580 | } |
7144c421 | 581 | if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,ek,NULL,0) <= 0) |
216659eb | 582 | goto err; |
dfeab068 | 583 | |
7144c421 DSH |
584 | if (ek) |
585 | { | |
586 | OPENSSL_cleanse(ek,eklen); | |
587 | OPENSSL_free(ek); | |
588 | } | |
dfeab068 RE |
589 | |
590 | if (out == NULL) | |
591 | out=etmp; | |
592 | else | |
593 | BIO_push(out,etmp); | |
594 | etmp=NULL; | |
595 | } | |
596 | ||
597 | #if 1 | |
9d6b1ce6 | 598 | if (PKCS7_is_detached(p7) || (in_bio != NULL)) |
dfeab068 RE |
599 | { |
600 | bio=in_bio; | |
601 | } | |
602 | else | |
603 | { | |
8484721a | 604 | #if 0 |
dfeab068 RE |
605 | bio=BIO_new(BIO_s_mem()); |
606 | /* We need to set this so that when we have read all | |
607 | * the data, the encrypt BIO, if present, will read | |
608 | * EOF and encode the last few bytes */ | |
609 | BIO_set_mem_eof_return(bio,0); | |
610 | ||
611 | if (data_body->length > 0) | |
612 | BIO_write(bio,(char *)data_body->data,data_body->length); | |
8484721a DSH |
613 | #else |
614 | if (data_body->length > 0) | |
615 | bio = BIO_new_mem_buf(data_body->data,data_body->length); | |
616 | else { | |
617 | bio=BIO_new(BIO_s_mem()); | |
618 | BIO_set_mem_eof_return(bio,0); | |
619 | } | |
689f9fab NL |
620 | if (bio == NULL) |
621 | goto err; | |
8484721a | 622 | #endif |
dfeab068 RE |
623 | } |
624 | BIO_push(out,bio); | |
625 | bio=NULL; | |
626 | #endif | |
627 | if (0) | |
628 | { | |
d02b48c6 | 629 | err: |
dfeab068 RE |
630 | if (out != NULL) BIO_free_all(out); |
631 | if (btmp != NULL) BIO_free_all(btmp); | |
632 | if (etmp != NULL) BIO_free_all(etmp); | |
633 | if (bio != NULL) BIO_free_all(bio); | |
634 | out=NULL; | |
635 | } | |
dfeab068 | 636 | return(out); |
d02b48c6 RE |
637 | } |
638 | ||
c5a55463 DSH |
639 | static BIO *PKCS7_find_digest(EVP_MD_CTX **pmd, BIO *bio, int nid) |
640 | { | |
641 | for (;;) | |
642 | { | |
643 | bio=BIO_find_type(bio,BIO_TYPE_MD); | |
644 | if (bio == NULL) | |
645 | { | |
8afca8d9 | 646 | PKCS7err(PKCS7_F_PKCS7_FIND_DIGEST,PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); |
c5a55463 DSH |
647 | return NULL; |
648 | } | |
649 | BIO_get_md_ctx(bio,pmd); | |
650 | if (*pmd == NULL) | |
651 | { | |
8afca8d9 | 652 | PKCS7err(PKCS7_F_PKCS7_FIND_DIGEST,ERR_R_INTERNAL_ERROR); |
c5a55463 DSH |
653 | return NULL; |
654 | } | |
655 | if (EVP_MD_CTX_type(*pmd) == nid) | |
656 | return bio; | |
657 | bio=BIO_next(bio); | |
658 | } | |
659 | return NULL; | |
660 | } | |
661 | ||
76fa8f18 DSH |
662 | static int do_pkcs7_signed_attrib(PKCS7_SIGNER_INFO *si, EVP_MD_CTX *mctx) |
663 | { | |
664 | unsigned char md_data[EVP_MAX_MD_SIZE]; | |
665 | unsigned int md_len; | |
666 | ||
667 | /* Add signing time if not already present */ | |
668 | if (!PKCS7_get_signed_attribute(si, NID_pkcs9_signingTime)) | |
669 | { | |
670 | if (!PKCS7_add0_attrib_signing_time(si, NULL)) | |
671 | { | |
672 | PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB, | |
673 | ERR_R_MALLOC_FAILURE); | |
674 | return 0; | |
675 | } | |
676 | } | |
677 | ||
678 | /* Add digest */ | |
b6dcdbfc DSH |
679 | if (!EVP_DigestFinal_ex(mctx, md_data,&md_len)) |
680 | { | |
681 | PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB, ERR_R_EVP_LIB); | |
682 | return 0; | |
683 | } | |
76fa8f18 DSH |
684 | if (!PKCS7_add1_attrib_digest(si, md_data, md_len)) |
685 | { | |
686 | PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB, ERR_R_MALLOC_FAILURE); | |
687 | return 0; | |
688 | } | |
689 | ||
690 | /* Now sign the attributes */ | |
691 | if (!PKCS7_SIGNER_INFO_sign(si)) | |
692 | return 0; | |
693 | ||
694 | return 1; | |
695 | } | |
696 | ||
697 | ||
6b691a5c | 698 | int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) |
d02b48c6 RE |
699 | { |
700 | int ret=0; | |
701 | int i,j; | |
702 | BIO *btmp; | |
d02b48c6 RE |
703 | PKCS7_SIGNER_INFO *si; |
704 | EVP_MD_CTX *mdc,ctx_tmp; | |
b6436ff2 | 705 | STACK_OF(X509_ATTRIBUTE) *sk; |
b05b50e6 | 706 | STACK_OF(PKCS7_SIGNER_INFO) *si_sk=NULL; |
58964a49 | 707 | ASN1_OCTET_STRING *os=NULL; |
d02b48c6 | 708 | |
b1254052 | 709 | EVP_MD_CTX_init(&ctx_tmp); |
d02b48c6 RE |
710 | i=OBJ_obj2nid(p7->type); |
711 | p7->state=PKCS7_S_HEADER; | |
712 | ||
713 | switch (i) | |
714 | { | |
559d5013 DSH |
715 | case NID_pkcs7_data: |
716 | os = p7->d.data; | |
717 | break; | |
58964a49 RE |
718 | case NID_pkcs7_signedAndEnveloped: |
719 | /* XXXXXXXXXXXXXXXX */ | |
720 | si_sk=p7->d.signed_and_enveloped->signer_info; | |
559d5013 DSH |
721 | os = p7->d.signed_and_enveloped->enc_data->enc_data; |
722 | if (!os) | |
a0e7c8ee | 723 | { |
559d5013 DSH |
724 | os=M_ASN1_OCTET_STRING_new(); |
725 | if (!os) | |
726 | { | |
727 | PKCS7err(PKCS7_F_PKCS7_DATAFINAL,ERR_R_MALLOC_FAILURE); | |
728 | goto err; | |
729 | } | |
730 | p7->d.signed_and_enveloped->enc_data->enc_data=os; | |
a0e7c8ee | 731 | } |
58964a49 | 732 | break; |
dfeab068 RE |
733 | case NID_pkcs7_enveloped: |
734 | /* XXXXXXXXXXXXXXXX */ | |
559d5013 DSH |
735 | os = p7->d.enveloped->enc_data->enc_data; |
736 | if (!os) | |
a0e7c8ee | 737 | { |
559d5013 DSH |
738 | os=M_ASN1_OCTET_STRING_new(); |
739 | if (!os) | |
740 | { | |
741 | PKCS7err(PKCS7_F_PKCS7_DATAFINAL,ERR_R_MALLOC_FAILURE); | |
742 | goto err; | |
743 | } | |
744 | p7->d.enveloped->enc_data->enc_data=os; | |
a0e7c8ee | 745 | } |
dfeab068 | 746 | break; |
d02b48c6 | 747 | case NID_pkcs7_signed: |
58964a49 | 748 | si_sk=p7->d.sign->signer_info; |
caf044cb | 749 | os=PKCS7_get_octet_string(p7->d.sign->contents); |
924acc54 | 750 | /* If detached data then the content is excluded */ |
caf044cb | 751 | if(PKCS7_type_is_data(p7->d.sign->contents) && p7->detached) { |
08e9c1af | 752 | M_ASN1_OCTET_STRING_free(os); |
924acc54 DSH |
753 | p7->d.sign->contents->d.data = NULL; |
754 | } | |
58964a49 | 755 | break; |
c5a55463 DSH |
756 | |
757 | case NID_pkcs7_digest: | |
758 | os=PKCS7_get_octet_string(p7->d.digest->contents); | |
759 | /* If detached data then the content is excluded */ | |
760 | if(PKCS7_type_is_data(p7->d.digest->contents) && p7->detached) | |
761 | { | |
762 | M_ASN1_OCTET_STRING_free(os); | |
763 | p7->d.digest->contents->d.data = NULL; | |
764 | } | |
765 | break; | |
766 | ||
4f1a0b2c BL |
767 | default: |
768 | PKCS7err(PKCS7_F_PKCS7_DATAFINAL,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); | |
769 | goto err; | |
58964a49 | 770 | } |
d02b48c6 | 771 | |
58964a49 RE |
772 | if (si_sk != NULL) |
773 | { | |
b05b50e6 | 774 | for (i=0; i<sk_PKCS7_SIGNER_INFO_num(si_sk); i++) |
d02b48c6 | 775 | { |
b05b50e6 | 776 | si=sk_PKCS7_SIGNER_INFO_value(si_sk,i); |
76fa8f18 DSH |
777 | if (si->pkey == NULL) |
778 | continue; | |
dfeab068 | 779 | |
76fa8f18 | 780 | j = OBJ_obj2nid(si->digest_alg->algorithm); |
d02b48c6 RE |
781 | |
782 | btmp=bio; | |
c5a55463 DSH |
783 | |
784 | btmp = PKCS7_find_digest(&mdc, btmp, j); | |
785 | ||
786 | if (btmp == NULL) | |
787 | goto err; | |
788 | ||
d02b48c6 RE |
789 | /* We now have the EVP_MD_CTX, lets do the |
790 | * signing. */ | |
b6dcdbfc DSH |
791 | if (!EVP_MD_CTX_copy_ex(&ctx_tmp,mdc)) |
792 | goto err; | |
d02b48c6 RE |
793 | |
794 | sk=si->auth_attr; | |
dfeab068 RE |
795 | |
796 | /* If there are attributes, we add the digest | |
797 | * attribute and only sign the attributes */ | |
76fa8f18 | 798 | if (sk_X509_ATTRIBUTE_num(sk) > 0) |
d02b48c6 | 799 | { |
76fa8f18 | 800 | if (!do_pkcs7_signed_attrib(si, &ctx_tmp)) |
a0e7c8ee | 801 | goto err; |
76fa8f18 DSH |
802 | } |
803 | else | |
804 | { | |
805 | unsigned char *abuf = NULL; | |
806 | unsigned int abuflen; | |
807 | abuflen = EVP_PKEY_size(si->pkey); | |
808 | abuf = OPENSSL_malloc(abuflen); | |
809 | if (!abuf) | |
810 | goto err; | |
811 | ||
812 | if (!EVP_SignFinal(&ctx_tmp, abuf, &abuflen, | |
813 | si->pkey)) | |
a0e7c8ee | 814 | { |
8afca8d9 | 815 | PKCS7err(PKCS7_F_PKCS7_DATAFINAL, |
76fa8f18 | 816 | ERR_R_EVP_LIB); |
a0e7c8ee DSH |
817 | goto err; |
818 | } | |
76fa8f18 | 819 | ASN1_STRING_set0(si->enc_digest, abuf, abuflen); |
d02b48c6 | 820 | } |
d02b48c6 | 821 | } |
d02b48c6 | 822 | } |
c5a55463 DSH |
823 | else if (i == NID_pkcs7_digest) |
824 | { | |
825 | unsigned char md_data[EVP_MAX_MD_SIZE]; | |
826 | unsigned int md_len; | |
827 | if (!PKCS7_find_digest(&mdc, bio, | |
828 | OBJ_obj2nid(p7->d.digest->md->algorithm))) | |
829 | goto err; | |
b6dcdbfc DSH |
830 | if (!EVP_DigestFinal_ex(mdc,md_data,&md_len)) |
831 | goto err; | |
c5a55463 DSH |
832 | M_ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len); |
833 | } | |
d02b48c6 | 834 | |
559d5013 | 835 | if (!PKCS7_is_detached(p7) && !(os->flags & ASN1_STRING_FLAG_NDEF)) |
dfeab068 | 836 | { |
76fa8f18 DSH |
837 | char *cont; |
838 | long contlen; | |
dfeab068 RE |
839 | btmp=BIO_find_type(bio,BIO_TYPE_MEM); |
840 | if (btmp == NULL) | |
841 | { | |
8afca8d9 | 842 | PKCS7err(PKCS7_F_PKCS7_DATAFINAL,PKCS7_R_UNABLE_TO_FIND_MEM_BIO); |
dfeab068 RE |
843 | goto err; |
844 | } | |
76fa8f18 | 845 | contlen = BIO_get_mem_data(btmp, &cont); |
8484721a DSH |
846 | /* Mark the BIO read only then we can use its copy of the data |
847 | * instead of making an extra copy. | |
848 | */ | |
849 | BIO_set_flags(btmp, BIO_FLAGS_MEM_RDONLY); | |
850 | BIO_set_mem_eof_return(btmp, 0); | |
76fa8f18 | 851 | ASN1_STRING_set0(os, (unsigned char *)cont, contlen); |
dfeab068 | 852 | } |
d02b48c6 RE |
853 | ret=1; |
854 | err: | |
dbad1690 | 855 | EVP_MD_CTX_cleanup(&ctx_tmp); |
d02b48c6 RE |
856 | return(ret); |
857 | } | |
858 | ||
76fa8f18 DSH |
859 | int PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si) |
860 | { | |
861 | EVP_MD_CTX mctx; | |
b7683e3a | 862 | EVP_PKEY_CTX *pctx; |
76fa8f18 DSH |
863 | unsigned char *abuf = NULL; |
864 | int alen; | |
786aa98d | 865 | size_t siglen; |
76fa8f18 DSH |
866 | const EVP_MD *md = NULL; |
867 | ||
868 | md = EVP_get_digestbyobj(si->digest_alg->algorithm); | |
869 | if (md == NULL) | |
870 | return 0; | |
871 | ||
872 | EVP_MD_CTX_init(&mctx); | |
b7683e3a | 873 | if (EVP_DigestSignInit(&mctx, &pctx, md,NULL, si->pkey) <= 0) |
76fa8f18 | 874 | goto err; |
b7683e3a DSH |
875 | |
876 | if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN, | |
877 | EVP_PKEY_CTRL_PKCS7_SIGN, 0, si) <= 0) | |
878 | { | |
879 | PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SIGN, PKCS7_R_CTRL_ERROR); | |
880 | goto err; | |
881 | } | |
882 | ||
76fa8f18 DSH |
883 | alen = ASN1_item_i2d((ASN1_VALUE *)si->auth_attr,&abuf, |
884 | ASN1_ITEM_rptr(PKCS7_ATTR_SIGN)); | |
885 | if(!abuf) | |
886 | goto err; | |
b7683e3a | 887 | if (EVP_DigestSignUpdate(&mctx,abuf,alen) <= 0) |
76fa8f18 DSH |
888 | goto err; |
889 | OPENSSL_free(abuf); | |
b7683e3a DSH |
890 | if (EVP_DigestSignFinal(&mctx, NULL, &siglen) <= 0) |
891 | goto err; | |
892 | abuf = OPENSSL_malloc(siglen); | |
76fa8f18 DSH |
893 | if(!abuf) |
894 | goto err; | |
b7683e3a DSH |
895 | if (EVP_DigestSignFinal(&mctx, abuf, &siglen) <= 0) |
896 | goto err; | |
897 | ||
898 | if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN, | |
899 | EVP_PKEY_CTRL_PKCS7_SIGN, 1, si) <= 0) | |
900 | { | |
901 | PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SIGN, PKCS7_R_CTRL_ERROR); | |
76fa8f18 | 902 | goto err; |
b7683e3a | 903 | } |
76fa8f18 DSH |
904 | |
905 | EVP_MD_CTX_cleanup(&mctx); | |
906 | ||
907 | ASN1_STRING_set0(si->enc_digest, abuf, siglen); | |
76fa8f18 DSH |
908 | |
909 | return 1; | |
910 | ||
911 | err: | |
912 | if (abuf) | |
913 | OPENSSL_free(abuf); | |
914 | EVP_MD_CTX_cleanup(&mctx); | |
915 | return 0; | |
916 | ||
917 | } | |
76fa8f18 | 918 | |
6b691a5c UM |
919 | int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx, BIO *bio, |
920 | PKCS7 *p7, PKCS7_SIGNER_INFO *si) | |
d02b48c6 | 921 | { |
d02b48c6 | 922 | PKCS7_ISSUER_AND_SERIAL *ias; |
dfeab068 | 923 | int ret=0,i; |
f73e07cf | 924 | STACK_OF(X509) *cert; |
d02b48c6 RE |
925 | X509 *x509; |
926 | ||
dfeab068 RE |
927 | if (PKCS7_type_is_signed(p7)) |
928 | { | |
929 | cert=p7->d.sign->cert; | |
930 | } | |
931 | else if (PKCS7_type_is_signedAndEnveloped(p7)) | |
932 | { | |
933 | cert=p7->d.signed_and_enveloped->cert; | |
934 | } | |
935 | else | |
936 | { | |
937 | PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,PKCS7_R_WRONG_PKCS7_TYPE); | |
938 | goto err; | |
939 | } | |
58964a49 | 940 | /* XXXXXXXXXXXXXXXXXXXXXXX */ |
d02b48c6 | 941 | ias=si->issuer_and_serial; |
d02b48c6 | 942 | |
dfeab068 | 943 | x509=X509_find_by_issuer_and_serial(cert,ias->issuer,ias->serial); |
d02b48c6 RE |
944 | |
945 | /* were we able to find the cert in passed to us */ | |
946 | if (x509 == NULL) | |
947 | { | |
948 | PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,PKCS7_R_UNABLE_TO_FIND_CERTIFICATE); | |
949 | goto err; | |
950 | } | |
951 | ||
952 | /* Lets verify */ | |
79aa04ef GT |
953 | if(!X509_STORE_CTX_init(ctx,cert_store,x509,cert)) |
954 | { | |
955 | PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,ERR_R_X509_LIB); | |
956 | goto err; | |
957 | } | |
5a9a4b29 | 958 | X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_SMIME_SIGN); |
d02b48c6 | 959 | i=X509_verify_cert(ctx); |
dfeab068 RE |
960 | if (i <= 0) |
961 | { | |
962 | PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,ERR_R_X509_LIB); | |
0fa197d8 | 963 | X509_STORE_CTX_cleanup(ctx); |
dfeab068 RE |
964 | goto err; |
965 | } | |
d02b48c6 RE |
966 | X509_STORE_CTX_cleanup(ctx); |
967 | ||
170afce5 DSH |
968 | return PKCS7_signatureVerify(bio, p7, si, x509); |
969 | err: | |
970 | return ret; | |
971 | } | |
972 | ||
973 | int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si, | |
974 | X509 *x509) | |
975 | { | |
976 | ASN1_OCTET_STRING *os; | |
977 | EVP_MD_CTX mdc_tmp,*mdc; | |
170afce5 DSH |
978 | int ret=0,i; |
979 | int md_type; | |
980 | STACK_OF(X509_ATTRIBUTE) *sk; | |
981 | BIO *btmp; | |
982 | EVP_PKEY *pkey; | |
983 | ||
dbad1690 BL |
984 | EVP_MD_CTX_init(&mdc_tmp); |
985 | ||
170afce5 DSH |
986 | if (!PKCS7_type_is_signed(p7) && |
987 | !PKCS7_type_is_signedAndEnveloped(p7)) { | |
988 | PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, | |
989 | PKCS7_R_WRONG_PKCS7_TYPE); | |
990 | goto err; | |
991 | } | |
992 | ||
d02b48c6 RE |
993 | md_type=OBJ_obj2nid(si->digest_alg->algorithm); |
994 | ||
995 | btmp=bio; | |
996 | for (;;) | |
997 | { | |
998 | if ((btmp == NULL) || | |
999 | ((btmp=BIO_find_type(btmp,BIO_TYPE_MD)) == NULL)) | |
1000 | { | |
170afce5 DSH |
1001 | PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, |
1002 | PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); | |
d02b48c6 RE |
1003 | goto err; |
1004 | } | |
1005 | BIO_get_md_ctx(btmp,&mdc); | |
1006 | if (mdc == NULL) | |
1007 | { | |
170afce5 | 1008 | PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, |
5277d7cb | 1009 | ERR_R_INTERNAL_ERROR); |
d02b48c6 RE |
1010 | goto err; |
1011 | } | |
72b60351 | 1012 | if (EVP_MD_CTX_type(mdc) == md_type) |
d02b48c6 | 1013 | break; |
beab098d DSH |
1014 | /* Workaround for some broken clients that put the signature |
1015 | * OID instead of the digest OID in digest_alg->algorithm | |
1016 | */ | |
1017 | if (EVP_MD_pkey_type(EVP_MD_CTX_md(mdc)) == md_type) | |
1018 | break; | |
cfd3bb17 | 1019 | btmp=BIO_next(btmp); |
d02b48c6 RE |
1020 | } |
1021 | ||
dfeab068 RE |
1022 | /* mdc is the digest ctx that we want, unless there are attributes, |
1023 | * in which case the digest is the signed attributes */ | |
b6dcdbfc DSH |
1024 | if (!EVP_MD_CTX_copy_ex(&mdc_tmp,mdc)) |
1025 | goto err; | |
d02b48c6 RE |
1026 | |
1027 | sk=si->auth_attr; | |
b6436ff2 | 1028 | if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0)) |
d02b48c6 | 1029 | { |
ec5add87 | 1030 | unsigned char md_dat[EVP_MAX_MD_SIZE], *abuf = NULL; |
48bd505c BL |
1031 | unsigned int md_len; |
1032 | int alen; | |
dfeab068 RE |
1033 | ASN1_OCTET_STRING *message_digest; |
1034 | ||
b6dcdbfc DSH |
1035 | if (!EVP_DigestFinal_ex(&mdc_tmp,md_dat,&md_len)) |
1036 | goto err; | |
dfeab068 RE |
1037 | message_digest=PKCS7_digest_from_attributes(sk); |
1038 | if (!message_digest) | |
1039 | { | |
170afce5 DSH |
1040 | PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, |
1041 | PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); | |
dfeab068 RE |
1042 | goto err; |
1043 | } | |
0b415fb0 | 1044 | if ((message_digest->length != (int)md_len) || |
dfeab068 RE |
1045 | (memcmp(message_digest->data,md_dat,md_len))) |
1046 | { | |
1047 | #if 0 | |
1048 | { | |
1049 | int ii; | |
1050 | for (ii=0; ii<message_digest->length; ii++) | |
1051 | printf("%02X",message_digest->data[ii]); printf(" sent\n"); | |
1052 | for (ii=0; ii<md_len; ii++) printf("%02X",md_dat[ii]); printf(" calc\n"); | |
1053 | } | |
1054 | #endif | |
170afce5 DSH |
1055 | PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, |
1056 | PKCS7_R_DIGEST_FAILURE); | |
dfeab068 RE |
1057 | ret= -1; |
1058 | goto err; | |
1059 | } | |
1060 | ||
b6dcdbfc DSH |
1061 | if (!EVP_VerifyInit_ex(&mdc_tmp,EVP_get_digestbynid(md_type), NULL)) |
1062 | goto err; | |
ec5add87 DSH |
1063 | |
1064 | alen = ASN1_item_i2d((ASN1_VALUE *)sk, &abuf, | |
bb5ea36b | 1065 | ASN1_ITEM_rptr(PKCS7_ATTR_VERIFY)); |
907e9962 NL |
1066 | if (alen <= 0) |
1067 | { | |
1068 | PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY,ERR_R_ASN1_LIB); | |
1069 | ret = -1; | |
1070 | goto err; | |
1071 | } | |
b6dcdbfc DSH |
1072 | if (!EVP_VerifyUpdate(&mdc_tmp, abuf, alen)) |
1073 | goto err; | |
ec5add87 DSH |
1074 | |
1075 | OPENSSL_free(abuf); | |
d02b48c6 RE |
1076 | } |
1077 | ||
1078 | os=si->enc_digest; | |
924acc54 | 1079 | pkey = X509_get_pubkey(x509); |
db4a4659 DSH |
1080 | if (!pkey) |
1081 | { | |
1082 | ret = -1; | |
1083 | goto err; | |
1084 | } | |
dfeab068 | 1085 | |
924acc54 DSH |
1086 | i=EVP_VerifyFinal(&mdc_tmp,os->data,os->length, pkey); |
1087 | EVP_PKEY_free(pkey); | |
d02b48c6 RE |
1088 | if (i <= 0) |
1089 | { | |
170afce5 DSH |
1090 | PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, |
1091 | PKCS7_R_SIGNATURE_FAILURE); | |
d02b48c6 RE |
1092 | ret= -1; |
1093 | goto err; | |
1094 | } | |
1095 | else | |
1096 | ret=1; | |
1097 | err: | |
dbad1690 | 1098 | EVP_MD_CTX_cleanup(&mdc_tmp); |
d02b48c6 RE |
1099 | return(ret); |
1100 | } | |
1101 | ||
6b691a5c | 1102 | PKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx) |
dfeab068 | 1103 | { |
8f0edcd1 | 1104 | STACK_OF(PKCS7_RECIP_INFO) *rsk; |
dfeab068 RE |
1105 | PKCS7_RECIP_INFO *ri; |
1106 | int i; | |
1107 | ||
1108 | i=OBJ_obj2nid(p7->type); | |
689f9fab NL |
1109 | if (i != NID_pkcs7_signedAndEnveloped) |
1110 | return NULL; | |
1111 | if (p7->d.signed_and_enveloped == NULL) | |
1112 | return NULL; | |
dfeab068 | 1113 | rsk=p7->d.signed_and_enveloped->recipientinfo; |
689f9fab NL |
1114 | if (rsk == NULL) |
1115 | return NULL; | |
8f0edcd1 BL |
1116 | ri=sk_PKCS7_RECIP_INFO_value(rsk,0); |
1117 | if (sk_PKCS7_RECIP_INFO_num(rsk) <= idx) return(NULL); | |
1118 | ri=sk_PKCS7_RECIP_INFO_value(rsk,idx); | |
dfeab068 RE |
1119 | return(ri->issuer_and_serial); |
1120 | } | |
1121 | ||
6b691a5c | 1122 | ASN1_TYPE *PKCS7_get_signed_attribute(PKCS7_SIGNER_INFO *si, int nid) |
dfeab068 RE |
1123 | { |
1124 | return(get_attribute(si->auth_attr,nid)); | |
1125 | } | |
1126 | ||
6b691a5c | 1127 | ASN1_TYPE *PKCS7_get_attribute(PKCS7_SIGNER_INFO *si, int nid) |
dfeab068 RE |
1128 | { |
1129 | return(get_attribute(si->unauth_attr,nid)); | |
1130 | } | |
1131 | ||
b6436ff2 | 1132 | static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid) |
dfeab068 RE |
1133 | { |
1134 | int i; | |
1135 | X509_ATTRIBUTE *xa; | |
1136 | ASN1_OBJECT *o; | |
1137 | ||
1138 | o=OBJ_nid2obj(nid); | |
10243d97 | 1139 | if (!o || !sk) return(NULL); |
b6436ff2 | 1140 | for (i=0; i<sk_X509_ATTRIBUTE_num(sk); i++) |
dfeab068 | 1141 | { |
b6436ff2 | 1142 | xa=sk_X509_ATTRIBUTE_value(sk,i); |
dfeab068 RE |
1143 | if (OBJ_cmp(xa->object,o) == 0) |
1144 | { | |
9d6b1ce6 | 1145 | if (!xa->single && sk_ASN1_TYPE_num(xa->value.set)) |
d35ea5b0 | 1146 | return(sk_ASN1_TYPE_value(xa->value.set,0)); |
dfeab068 RE |
1147 | else |
1148 | return(NULL); | |
1149 | } | |
1150 | } | |
1151 | return(NULL); | |
1152 | } | |
1153 | ||
b6436ff2 | 1154 | ASN1_OCTET_STRING *PKCS7_digest_from_attributes(STACK_OF(X509_ATTRIBUTE) *sk) |
10243d97 | 1155 | { |
dfeab068 | 1156 | ASN1_TYPE *astype; |
10243d97 DSH |
1157 | if(!(astype = get_attribute(sk, NID_pkcs9_messageDigest))) return NULL; |
1158 | return astype->value.octet_string; | |
1159 | } | |
dfeab068 | 1160 | |
b6436ff2 BL |
1161 | int PKCS7_set_signed_attributes(PKCS7_SIGNER_INFO *p7si, |
1162 | STACK_OF(X509_ATTRIBUTE) *sk) | |
dfeab068 RE |
1163 | { |
1164 | int i; | |
1165 | ||
1166 | if (p7si->auth_attr != NULL) | |
b6436ff2 BL |
1167 | sk_X509_ATTRIBUTE_pop_free(p7si->auth_attr,X509_ATTRIBUTE_free); |
1168 | p7si->auth_attr=sk_X509_ATTRIBUTE_dup(sk); | |
689f9fab NL |
1169 | if (p7si->auth_attr == NULL) |
1170 | return 0; | |
b6436ff2 | 1171 | for (i=0; i<sk_X509_ATTRIBUTE_num(sk); i++) |
dfeab068 | 1172 | { |
b6436ff2 BL |
1173 | if ((sk_X509_ATTRIBUTE_set(p7si->auth_attr,i, |
1174 | X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value(sk,i)))) | |
1175 | == NULL) | |
dfeab068 RE |
1176 | return(0); |
1177 | } | |
1178 | return(1); | |
1179 | } | |
1180 | ||
b6436ff2 | 1181 | int PKCS7_set_attributes(PKCS7_SIGNER_INFO *p7si, STACK_OF(X509_ATTRIBUTE) *sk) |
dfeab068 RE |
1182 | { |
1183 | int i; | |
1184 | ||
1185 | if (p7si->unauth_attr != NULL) | |
b6436ff2 BL |
1186 | sk_X509_ATTRIBUTE_pop_free(p7si->unauth_attr, |
1187 | X509_ATTRIBUTE_free); | |
1188 | p7si->unauth_attr=sk_X509_ATTRIBUTE_dup(sk); | |
689f9fab NL |
1189 | if (p7si->unauth_attr == NULL) |
1190 | return 0; | |
b6436ff2 | 1191 | for (i=0; i<sk_X509_ATTRIBUTE_num(sk); i++) |
dfeab068 | 1192 | { |
b6436ff2 BL |
1193 | if ((sk_X509_ATTRIBUTE_set(p7si->unauth_attr,i, |
1194 | X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value(sk,i)))) | |
1195 | == NULL) | |
dfeab068 RE |
1196 | return(0); |
1197 | } | |
1198 | return(1); | |
1199 | } | |
1200 | ||
6b691a5c | 1201 | int PKCS7_add_signed_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype, |
c8b41850 | 1202 | void *value) |
dfeab068 RE |
1203 | { |
1204 | return(add_attribute(&(p7si->auth_attr),nid,atrtype,value)); | |
1205 | } | |
1206 | ||
6b691a5c | 1207 | int PKCS7_add_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype, |
c8b41850 | 1208 | void *value) |
dfeab068 RE |
1209 | { |
1210 | return(add_attribute(&(p7si->unauth_attr),nid,atrtype,value)); | |
1211 | } | |
1212 | ||
b6436ff2 BL |
1213 | static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype, |
1214 | void *value) | |
dfeab068 RE |
1215 | { |
1216 | X509_ATTRIBUTE *attr=NULL; | |
dfeab068 RE |
1217 | |
1218 | if (*sk == NULL) | |
1219 | { | |
62324627 | 1220 | *sk = sk_X509_ATTRIBUTE_new_null(); |
689f9fab NL |
1221 | if (*sk == NULL) |
1222 | return 0; | |
dfeab068 | 1223 | new_attrib: |
689f9fab NL |
1224 | if (!(attr=X509_ATTRIBUTE_create(nid,atrtype,value))) |
1225 | return 0; | |
1226 | if (!sk_X509_ATTRIBUTE_push(*sk,attr)) | |
1227 | { | |
1228 | X509_ATTRIBUTE_free(attr); | |
1229 | return 0; | |
1230 | } | |
dfeab068 RE |
1231 | } |
1232 | else | |
1233 | { | |
1234 | int i; | |
1235 | ||
b6436ff2 | 1236 | for (i=0; i<sk_X509_ATTRIBUTE_num(*sk); i++) |
dfeab068 | 1237 | { |
b6436ff2 | 1238 | attr=sk_X509_ATTRIBUTE_value(*sk,i); |
dfeab068 RE |
1239 | if (OBJ_obj2nid(attr->object) == nid) |
1240 | { | |
1241 | X509_ATTRIBUTE_free(attr); | |
1242 | attr=X509_ATTRIBUTE_create(nid,atrtype,value); | |
689f9fab NL |
1243 | if (attr == NULL) |
1244 | return 0; | |
1245 | if (!sk_X509_ATTRIBUTE_set(*sk,i,attr)) | |
1246 | { | |
1247 | X509_ATTRIBUTE_free(attr); | |
1248 | return 0; | |
1249 | } | |
dfeab068 RE |
1250 | goto end; |
1251 | } | |
1252 | } | |
1253 | goto new_attrib; | |
1254 | } | |
1255 | end: | |
1256 | return(1); | |
1257 | } | |
1258 |