]>
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; | |
58964a49 RE |
304 | default: |
305 | PKCS7err(PKCS7_F_PKCS7_DATAINIT,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); | |
306 | goto err; | |
307 | } | |
308 | ||
c5a55463 DSH |
309 | for (i=0; i<sk_X509_ALGOR_num(md_sk); i++) |
310 | if (!PKCS7_bio_add_digest(&out, sk_X509_ALGOR_value(md_sk, i))) | |
311 | goto err; | |
d02b48c6 | 312 | |
c5a55463 DSH |
313 | if (xa && !PKCS7_bio_add_digest(&out, xa)) |
314 | goto err; | |
58964a49 RE |
315 | |
316 | if (evp_cipher != NULL) | |
317 | { | |
318 | unsigned char key[EVP_MAX_KEY_LENGTH]; | |
319 | unsigned char iv[EVP_MAX_IV_LENGTH]; | |
320 | int keylen,ivlen; | |
84fa704c | 321 | EVP_CIPHER_CTX *ctx; |
58964a49 | 322 | |
dfeab068 RE |
323 | if ((btmp=BIO_new(BIO_f_cipher())) == NULL) |
324 | { | |
325 | PKCS7err(PKCS7_F_PKCS7_DATAINIT,ERR_R_BIO_LIB); | |
326 | goto err; | |
327 | } | |
84fa704c | 328 | BIO_get_cipher_ctx(btmp, &ctx); |
58964a49 RE |
329 | keylen=EVP_CIPHER_key_length(evp_cipher); |
330 | ivlen=EVP_CIPHER_iv_length(evp_cipher); | |
84fa704c | 331 | xalg->algorithm = OBJ_nid2obj(EVP_CIPHER_type(evp_cipher)); |
e7f97e2d | 332 | if (ivlen > 0) RAND_pseudo_bytes(iv,ivlen); |
216659eb DSH |
333 | if (EVP_CipherInit_ex(ctx, evp_cipher, NULL, NULL, NULL, 1)<=0) |
334 | goto err; | |
335 | if (EVP_CIPHER_CTX_rand_key(ctx, key) <= 0) | |
336 | goto err; | |
337 | if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1) <= 0) | |
338 | goto err; | |
58964a49 | 339 | |
884e8ec6 | 340 | if (ivlen > 0) { |
884e8ec6 DSH |
341 | if (xalg->parameter == NULL) |
342 | xalg->parameter=ASN1_TYPE_new(); | |
343 | if(EVP_CIPHER_param_to_asn1(ctx, xalg->parameter) < 0) | |
344 | goto err; | |
345 | } | |
58964a49 RE |
346 | |
347 | /* Lets do the pub key stuff :-) */ | |
8f0edcd1 | 348 | for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) |
58964a49 | 349 | { |
8f0edcd1 | 350 | ri=sk_PKCS7_RECIP_INFO_value(rsk,i); |
399a6f0b | 351 | if (pkcs7_encode_rinfo(ri, key, keylen) <= 0) |
a0e7c8ee | 352 | goto err; |
58964a49 | 353 | } |
4579924b | 354 | OPENSSL_cleanse(key, keylen); |
58964a49 | 355 | |
58964a49 RE |
356 | if (out == NULL) |
357 | out=btmp; | |
358 | else | |
359 | BIO_push(out,btmp); | |
dfeab068 | 360 | btmp=NULL; |
58964a49 RE |
361 | } |
362 | ||
caf044cb DSH |
363 | if (bio == NULL) |
364 | { | |
9d6b1ce6 | 365 | if (PKCS7_is_detached(p7)) |
d02b48c6 | 366 | bio=BIO_new(BIO_s_null()); |
c5a55463 DSH |
367 | else if (os && os->length > 0) |
368 | bio = BIO_new_mem_buf(os->data, os->length); | |
369 | if(bio == NULL) | |
caf044cb | 370 | { |
c5a55463 DSH |
371 | bio=BIO_new(BIO_s_mem()); |
372 | BIO_set_mem_eof_return(bio,0); | |
d02b48c6 | 373 | } |
c5a55463 | 374 | } |
d02b48c6 | 375 | BIO_push(out,bio); |
dfeab068 RE |
376 | bio=NULL; |
377 | if (0) | |
378 | { | |
379 | err: | |
380 | if (out != NULL) | |
381 | BIO_free_all(out); | |
382 | if (btmp != NULL) | |
383 | BIO_free_all(btmp); | |
384 | out=NULL; | |
385 | } | |
d02b48c6 | 386 | return(out); |
dfeab068 RE |
387 | } |
388 | ||
8f2e4fdf DSH |
389 | static int pkcs7_cmp_ri(PKCS7_RECIP_INFO *ri, X509 *pcert) |
390 | { | |
391 | int ret; | |
392 | ret = X509_NAME_cmp(ri->issuer_and_serial->issuer, | |
393 | pcert->cert_info->issuer); | |
394 | if (ret) | |
395 | return ret; | |
396 | return M_ASN1_INTEGER_cmp(pcert->cert_info->serialNumber, | |
397 | ri->issuer_and_serial->serial); | |
398 | } | |
399 | ||
dfeab068 | 400 | /* int */ |
84fa704c | 401 | BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) |
dfeab068 RE |
402 | { |
403 | int i,j; | |
404 | BIO *out=NULL,*btmp=NULL,*etmp=NULL,*bio=NULL; | |
dfeab068 RE |
405 | X509_ALGOR *xa; |
406 | ASN1_OCTET_STRING *data_body=NULL; | |
e778802f BL |
407 | const EVP_MD *evp_md; |
408 | const EVP_CIPHER *evp_cipher=NULL; | |
dfeab068 RE |
409 | EVP_CIPHER_CTX *evp_ctx=NULL; |
410 | X509_ALGOR *enc_alg=NULL; | |
426edadf | 411 | STACK_OF(X509_ALGOR) *md_sk=NULL; |
8f0edcd1 | 412 | STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL; |
dfeab068 RE |
413 | X509_ALGOR *xalg=NULL; |
414 | PKCS7_RECIP_INFO *ri=NULL; | |
dfeab068 RE |
415 | |
416 | i=OBJ_obj2nid(p7->type); | |
417 | p7->state=PKCS7_S_HEADER; | |
418 | ||
419 | switch (i) | |
420 | { | |
421 | case NID_pkcs7_signed: | |
caf044cb | 422 | data_body=PKCS7_get_octet_string(p7->d.sign->contents); |
dfeab068 RE |
423 | md_sk=p7->d.sign->md_algs; |
424 | break; | |
425 | case NID_pkcs7_signedAndEnveloped: | |
426 | rsk=p7->d.signed_and_enveloped->recipientinfo; | |
427 | md_sk=p7->d.signed_and_enveloped->md_algs; | |
428 | data_body=p7->d.signed_and_enveloped->enc_data->enc_data; | |
429 | enc_alg=p7->d.signed_and_enveloped->enc_data->algorithm; | |
77fe058c | 430 | evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm); |
dfeab068 RE |
431 | if (evp_cipher == NULL) |
432 | { | |
84fa704c | 433 | PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE); |
dfeab068 RE |
434 | goto err; |
435 | } | |
436 | xalg=p7->d.signed_and_enveloped->enc_data->algorithm; | |
437 | break; | |
438 | case NID_pkcs7_enveloped: | |
439 | rsk=p7->d.enveloped->recipientinfo; | |
440 | enc_alg=p7->d.enveloped->enc_data->algorithm; | |
441 | data_body=p7->d.enveloped->enc_data->enc_data; | |
77fe058c | 442 | evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm); |
dfeab068 RE |
443 | if (evp_cipher == NULL) |
444 | { | |
84fa704c | 445 | PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE); |
dfeab068 RE |
446 | goto err; |
447 | } | |
448 | xalg=p7->d.enveloped->enc_data->algorithm; | |
449 | break; | |
450 | default: | |
84fa704c | 451 | PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CONTENT_TYPE); |
dfeab068 RE |
452 | goto err; |
453 | } | |
454 | ||
455 | /* We will be checking the signature */ | |
456 | if (md_sk != NULL) | |
457 | { | |
426edadf | 458 | for (i=0; i<sk_X509_ALGOR_num(md_sk); i++) |
dfeab068 | 459 | { |
426edadf | 460 | xa=sk_X509_ALGOR_value(md_sk,i); |
dfeab068 RE |
461 | if ((btmp=BIO_new(BIO_f_md())) == NULL) |
462 | { | |
84fa704c | 463 | PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB); |
dfeab068 RE |
464 | goto err; |
465 | } | |
466 | ||
467 | j=OBJ_obj2nid(xa->algorithm); | |
77fe058c | 468 | evp_md=EVP_get_digestbynid(j); |
dfeab068 RE |
469 | if (evp_md == NULL) |
470 | { | |
84fa704c | 471 | PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNKNOWN_DIGEST_TYPE); |
dfeab068 RE |
472 | goto err; |
473 | } | |
474 | ||
475 | BIO_set_md(btmp,evp_md); | |
476 | if (out == NULL) | |
477 | out=btmp; | |
478 | else | |
479 | BIO_push(out,btmp); | |
480 | btmp=NULL; | |
481 | } | |
482 | } | |
483 | ||
484 | if (evp_cipher != NULL) | |
485 | { | |
486 | #if 0 | |
487 | unsigned char key[EVP_MAX_KEY_LENGTH]; | |
488 | unsigned char iv[EVP_MAX_IV_LENGTH]; | |
489 | unsigned char *p; | |
490 | int keylen,ivlen; | |
491 | int max; | |
492 | X509_OBJECT ret; | |
493 | #endif | |
7144c421 DSH |
494 | unsigned char *ek = NULL; |
495 | int eklen; | |
dfeab068 RE |
496 | |
497 | if ((etmp=BIO_new(BIO_f_cipher())) == NULL) | |
498 | { | |
84fa704c | 499 | PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB); |
dfeab068 RE |
500 | goto err; |
501 | } | |
502 | ||
503 | /* It was encrypted, we need to decrypt the secret key | |
504 | * with the private key */ | |
505 | ||
84fa704c DSH |
506 | /* Find the recipientInfo which matches the passed certificate |
507 | * (if any) | |
10243d97 DSH |
508 | */ |
509 | ||
7144c421 DSH |
510 | if (pcert) |
511 | { | |
512 | for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) | |
513 | { | |
8f2e4fdf DSH |
514 | ri=sk_PKCS7_RECIP_INFO_value(rsk,i); |
515 | if (!pkcs7_cmp_ri(ri, pcert)) | |
516 | break; | |
517 | ri=NULL; | |
7144c421 DSH |
518 | } |
519 | if (ri == NULL) | |
520 | { | |
8f2e4fdf DSH |
521 | PKCS7err(PKCS7_F_PKCS7_DATADECODE, |
522 | PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE); | |
523 | goto err; | |
7144c421 | 524 | } |
dfeab068 RE |
525 | } |
526 | ||
8f2e4fdf DSH |
527 | /* If we haven't got a certificate try each ri in turn */ |
528 | ||
529 | if (pcert == NULL) | |
dfeab068 | 530 | { |
8f2e4fdf DSH |
531 | for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) |
532 | { | |
533 | ri=sk_PKCS7_RECIP_INFO_value(rsk,i); | |
7144c421 DSH |
534 | if (pkcs7_decrypt_rinfo(&ek, &eklen, |
535 | ri, pkey) > 0) | |
8f2e4fdf DSH |
536 | break; |
537 | ERR_clear_error(); | |
538 | ri = NULL; | |
539 | } | |
540 | if (ri == NULL) | |
541 | { | |
542 | PKCS7err(PKCS7_F_PKCS7_DATADECODE, | |
543 | PKCS7_R_NO_RECIPIENT_MATCHES_KEY); | |
544 | goto err; | |
545 | } | |
546 | } | |
547 | else | |
548 | { | |
7144c421 | 549 | if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey) <= 0) |
8f2e4fdf | 550 | goto err; |
dfeab068 RE |
551 | } |
552 | ||
553 | evp_ctx=NULL; | |
554 | BIO_get_cipher_ctx(etmp,&evp_ctx); | |
216659eb DSH |
555 | if (EVP_CipherInit_ex(evp_ctx,evp_cipher,NULL,NULL,NULL,0) <= 0) |
556 | goto err; | |
dfeab068 | 557 | if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0) |
4ac881ed | 558 | goto err; |
dfeab068 | 559 | |
7144c421 | 560 | if (eklen != EVP_CIPHER_CTX_key_length(evp_ctx)) { |
7f060601 | 561 | /* Some S/MIME clients don't use the same key |
9716a8f9 DSH |
562 | * and effective key length. The key length is |
563 | * determined by the size of the decrypted RSA key. | |
9716a8f9 | 564 | */ |
7144c421 | 565 | if(!EVP_CIPHER_CTX_set_key_length(evp_ctx, eklen)) |
63da21c0 | 566 | { |
9716a8f9 | 567 | PKCS7err(PKCS7_F_PKCS7_DATADECODE, |
84fa704c | 568 | PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH); |
9716a8f9 | 569 | goto err; |
63da21c0 | 570 | } |
7f060601 | 571 | } |
7144c421 | 572 | if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,ek,NULL,0) <= 0) |
216659eb | 573 | goto err; |
dfeab068 | 574 | |
7144c421 DSH |
575 | if (ek) |
576 | { | |
577 | OPENSSL_cleanse(ek,eklen); | |
578 | OPENSSL_free(ek); | |
579 | } | |
dfeab068 RE |
580 | |
581 | if (out == NULL) | |
582 | out=etmp; | |
583 | else | |
584 | BIO_push(out,etmp); | |
585 | etmp=NULL; | |
586 | } | |
587 | ||
588 | #if 1 | |
9d6b1ce6 | 589 | if (PKCS7_is_detached(p7) || (in_bio != NULL)) |
dfeab068 RE |
590 | { |
591 | bio=in_bio; | |
592 | } | |
593 | else | |
594 | { | |
8484721a | 595 | #if 0 |
dfeab068 RE |
596 | bio=BIO_new(BIO_s_mem()); |
597 | /* We need to set this so that when we have read all | |
598 | * the data, the encrypt BIO, if present, will read | |
599 | * EOF and encode the last few bytes */ | |
600 | BIO_set_mem_eof_return(bio,0); | |
601 | ||
602 | if (data_body->length > 0) | |
603 | BIO_write(bio,(char *)data_body->data,data_body->length); | |
8484721a DSH |
604 | #else |
605 | if (data_body->length > 0) | |
606 | bio = BIO_new_mem_buf(data_body->data,data_body->length); | |
607 | else { | |
608 | bio=BIO_new(BIO_s_mem()); | |
609 | BIO_set_mem_eof_return(bio,0); | |
610 | } | |
611 | #endif | |
dfeab068 RE |
612 | } |
613 | BIO_push(out,bio); | |
614 | bio=NULL; | |
615 | #endif | |
616 | if (0) | |
617 | { | |
d02b48c6 | 618 | err: |
dfeab068 RE |
619 | if (out != NULL) BIO_free_all(out); |
620 | if (btmp != NULL) BIO_free_all(btmp); | |
621 | if (etmp != NULL) BIO_free_all(etmp); | |
622 | if (bio != NULL) BIO_free_all(bio); | |
623 | out=NULL; | |
624 | } | |
dfeab068 | 625 | return(out); |
d02b48c6 RE |
626 | } |
627 | ||
c5a55463 DSH |
628 | static BIO *PKCS7_find_digest(EVP_MD_CTX **pmd, BIO *bio, int nid) |
629 | { | |
630 | for (;;) | |
631 | { | |
632 | bio=BIO_find_type(bio,BIO_TYPE_MD); | |
633 | if (bio == NULL) | |
634 | { | |
8afca8d9 | 635 | PKCS7err(PKCS7_F_PKCS7_FIND_DIGEST,PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); |
c5a55463 DSH |
636 | return NULL; |
637 | } | |
638 | BIO_get_md_ctx(bio,pmd); | |
639 | if (*pmd == NULL) | |
640 | { | |
8afca8d9 | 641 | PKCS7err(PKCS7_F_PKCS7_FIND_DIGEST,ERR_R_INTERNAL_ERROR); |
c5a55463 DSH |
642 | return NULL; |
643 | } | |
644 | if (EVP_MD_CTX_type(*pmd) == nid) | |
645 | return bio; | |
646 | bio=BIO_next(bio); | |
647 | } | |
648 | return NULL; | |
649 | } | |
650 | ||
76fa8f18 DSH |
651 | static int do_pkcs7_signed_attrib(PKCS7_SIGNER_INFO *si, EVP_MD_CTX *mctx) |
652 | { | |
653 | unsigned char md_data[EVP_MAX_MD_SIZE]; | |
654 | unsigned int md_len; | |
655 | ||
656 | /* Add signing time if not already present */ | |
657 | if (!PKCS7_get_signed_attribute(si, NID_pkcs9_signingTime)) | |
658 | { | |
659 | if (!PKCS7_add0_attrib_signing_time(si, NULL)) | |
660 | { | |
661 | PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB, | |
662 | ERR_R_MALLOC_FAILURE); | |
663 | return 0; | |
664 | } | |
665 | } | |
666 | ||
667 | /* Add digest */ | |
668 | EVP_DigestFinal_ex(mctx, md_data,&md_len); | |
669 | if (!PKCS7_add1_attrib_digest(si, md_data, md_len)) | |
670 | { | |
671 | PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB, ERR_R_MALLOC_FAILURE); | |
672 | return 0; | |
673 | } | |
674 | ||
675 | /* Now sign the attributes */ | |
676 | if (!PKCS7_SIGNER_INFO_sign(si)) | |
677 | return 0; | |
678 | ||
679 | return 1; | |
680 | } | |
681 | ||
682 | ||
6b691a5c | 683 | int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) |
d02b48c6 RE |
684 | { |
685 | int ret=0; | |
686 | int i,j; | |
687 | BIO *btmp; | |
d02b48c6 RE |
688 | PKCS7_SIGNER_INFO *si; |
689 | EVP_MD_CTX *mdc,ctx_tmp; | |
b6436ff2 | 690 | STACK_OF(X509_ATTRIBUTE) *sk; |
b05b50e6 | 691 | STACK_OF(PKCS7_SIGNER_INFO) *si_sk=NULL; |
58964a49 | 692 | ASN1_OCTET_STRING *os=NULL; |
d02b48c6 | 693 | |
b1254052 | 694 | EVP_MD_CTX_init(&ctx_tmp); |
d02b48c6 RE |
695 | i=OBJ_obj2nid(p7->type); |
696 | p7->state=PKCS7_S_HEADER; | |
697 | ||
698 | switch (i) | |
699 | { | |
58964a49 RE |
700 | case NID_pkcs7_signedAndEnveloped: |
701 | /* XXXXXXXXXXXXXXXX */ | |
702 | si_sk=p7->d.signed_and_enveloped->signer_info; | |
a0e7c8ee DSH |
703 | if (!(os=M_ASN1_OCTET_STRING_new())) |
704 | { | |
8afca8d9 | 705 | PKCS7err(PKCS7_F_PKCS7_DATAFINAL,ERR_R_MALLOC_FAILURE); |
a0e7c8ee DSH |
706 | goto err; |
707 | } | |
58964a49 RE |
708 | p7->d.signed_and_enveloped->enc_data->enc_data=os; |
709 | break; | |
dfeab068 RE |
710 | case NID_pkcs7_enveloped: |
711 | /* XXXXXXXXXXXXXXXX */ | |
a0e7c8ee DSH |
712 | if (!(os=M_ASN1_OCTET_STRING_new())) |
713 | { | |
8afca8d9 | 714 | PKCS7err(PKCS7_F_PKCS7_DATAFINAL,ERR_R_MALLOC_FAILURE); |
a0e7c8ee DSH |
715 | goto err; |
716 | } | |
dfeab068 RE |
717 | p7->d.enveloped->enc_data->enc_data=os; |
718 | break; | |
d02b48c6 | 719 | case NID_pkcs7_signed: |
58964a49 | 720 | si_sk=p7->d.sign->signer_info; |
caf044cb | 721 | os=PKCS7_get_octet_string(p7->d.sign->contents); |
924acc54 | 722 | /* If detached data then the content is excluded */ |
caf044cb | 723 | if(PKCS7_type_is_data(p7->d.sign->contents) && p7->detached) { |
08e9c1af | 724 | M_ASN1_OCTET_STRING_free(os); |
924acc54 DSH |
725 | p7->d.sign->contents->d.data = NULL; |
726 | } | |
58964a49 | 727 | break; |
c5a55463 DSH |
728 | |
729 | case NID_pkcs7_digest: | |
730 | os=PKCS7_get_octet_string(p7->d.digest->contents); | |
731 | /* If detached data then the content is excluded */ | |
732 | if(PKCS7_type_is_data(p7->d.digest->contents) && p7->detached) | |
733 | { | |
734 | M_ASN1_OCTET_STRING_free(os); | |
735 | p7->d.digest->contents->d.data = NULL; | |
736 | } | |
737 | break; | |
738 | ||
58964a49 | 739 | } |
d02b48c6 | 740 | |
58964a49 RE |
741 | if (si_sk != NULL) |
742 | { | |
b05b50e6 | 743 | for (i=0; i<sk_PKCS7_SIGNER_INFO_num(si_sk); i++) |
d02b48c6 | 744 | { |
b05b50e6 | 745 | si=sk_PKCS7_SIGNER_INFO_value(si_sk,i); |
76fa8f18 DSH |
746 | if (si->pkey == NULL) |
747 | continue; | |
dfeab068 | 748 | |
76fa8f18 | 749 | j = OBJ_obj2nid(si->digest_alg->algorithm); |
d02b48c6 RE |
750 | |
751 | btmp=bio; | |
c5a55463 DSH |
752 | |
753 | btmp = PKCS7_find_digest(&mdc, btmp, j); | |
754 | ||
755 | if (btmp == NULL) | |
756 | goto err; | |
757 | ||
d02b48c6 RE |
758 | /* We now have the EVP_MD_CTX, lets do the |
759 | * signing. */ | |
20d2186c | 760 | EVP_MD_CTX_copy_ex(&ctx_tmp,mdc); |
d02b48c6 RE |
761 | |
762 | sk=si->auth_attr; | |
dfeab068 RE |
763 | |
764 | /* If there are attributes, we add the digest | |
765 | * attribute and only sign the attributes */ | |
76fa8f18 | 766 | if (sk_X509_ATTRIBUTE_num(sk) > 0) |
d02b48c6 | 767 | { |
76fa8f18 | 768 | if (!do_pkcs7_signed_attrib(si, &ctx_tmp)) |
a0e7c8ee | 769 | goto err; |
76fa8f18 DSH |
770 | } |
771 | else | |
772 | { | |
773 | unsigned char *abuf = NULL; | |
774 | unsigned int abuflen; | |
775 | abuflen = EVP_PKEY_size(si->pkey); | |
776 | abuf = OPENSSL_malloc(abuflen); | |
777 | if (!abuf) | |
778 | goto err; | |
779 | ||
780 | if (!EVP_SignFinal(&ctx_tmp, abuf, &abuflen, | |
781 | si->pkey)) | |
a0e7c8ee | 782 | { |
8afca8d9 | 783 | PKCS7err(PKCS7_F_PKCS7_DATAFINAL, |
76fa8f18 | 784 | ERR_R_EVP_LIB); |
a0e7c8ee DSH |
785 | goto err; |
786 | } | |
76fa8f18 | 787 | ASN1_STRING_set0(si->enc_digest, abuf, abuflen); |
d02b48c6 | 788 | } |
d02b48c6 | 789 | } |
d02b48c6 | 790 | } |
c5a55463 DSH |
791 | else if (i == NID_pkcs7_digest) |
792 | { | |
793 | unsigned char md_data[EVP_MAX_MD_SIZE]; | |
794 | unsigned int md_len; | |
795 | if (!PKCS7_find_digest(&mdc, bio, | |
796 | OBJ_obj2nid(p7->d.digest->md->algorithm))) | |
797 | goto err; | |
798 | EVP_DigestFinal_ex(mdc,md_data,&md_len); | |
799 | M_ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len); | |
800 | } | |
d02b48c6 | 801 | |
9d6b1ce6 | 802 | if (!PKCS7_is_detached(p7)) |
dfeab068 | 803 | { |
76fa8f18 DSH |
804 | char *cont; |
805 | long contlen; | |
dfeab068 RE |
806 | btmp=BIO_find_type(bio,BIO_TYPE_MEM); |
807 | if (btmp == NULL) | |
808 | { | |
8afca8d9 | 809 | PKCS7err(PKCS7_F_PKCS7_DATAFINAL,PKCS7_R_UNABLE_TO_FIND_MEM_BIO); |
dfeab068 RE |
810 | goto err; |
811 | } | |
76fa8f18 | 812 | contlen = BIO_get_mem_data(btmp, &cont); |
8484721a DSH |
813 | /* Mark the BIO read only then we can use its copy of the data |
814 | * instead of making an extra copy. | |
815 | */ | |
816 | BIO_set_flags(btmp, BIO_FLAGS_MEM_RDONLY); | |
817 | BIO_set_mem_eof_return(btmp, 0); | |
76fa8f18 | 818 | ASN1_STRING_set0(os, (unsigned char *)cont, contlen); |
dfeab068 | 819 | } |
d02b48c6 RE |
820 | ret=1; |
821 | err: | |
dbad1690 | 822 | EVP_MD_CTX_cleanup(&ctx_tmp); |
d02b48c6 RE |
823 | return(ret); |
824 | } | |
825 | ||
76fa8f18 DSH |
826 | int PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si) |
827 | { | |
828 | EVP_MD_CTX mctx; | |
b7683e3a | 829 | EVP_PKEY_CTX *pctx; |
76fa8f18 DSH |
830 | unsigned char *abuf = NULL; |
831 | int alen; | |
786aa98d | 832 | size_t siglen; |
76fa8f18 DSH |
833 | const EVP_MD *md = NULL; |
834 | ||
835 | md = EVP_get_digestbyobj(si->digest_alg->algorithm); | |
836 | if (md == NULL) | |
837 | return 0; | |
838 | ||
839 | EVP_MD_CTX_init(&mctx); | |
b7683e3a | 840 | if (EVP_DigestSignInit(&mctx, &pctx, md,NULL, si->pkey) <= 0) |
76fa8f18 | 841 | goto err; |
b7683e3a DSH |
842 | |
843 | if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN, | |
844 | EVP_PKEY_CTRL_PKCS7_SIGN, 0, si) <= 0) | |
845 | { | |
846 | PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SIGN, PKCS7_R_CTRL_ERROR); | |
847 | goto err; | |
848 | } | |
849 | ||
76fa8f18 DSH |
850 | alen = ASN1_item_i2d((ASN1_VALUE *)si->auth_attr,&abuf, |
851 | ASN1_ITEM_rptr(PKCS7_ATTR_SIGN)); | |
852 | if(!abuf) | |
853 | goto err; | |
b7683e3a | 854 | if (EVP_DigestSignUpdate(&mctx,abuf,alen) <= 0) |
76fa8f18 DSH |
855 | goto err; |
856 | OPENSSL_free(abuf); | |
b7683e3a DSH |
857 | if (EVP_DigestSignFinal(&mctx, NULL, &siglen) <= 0) |
858 | goto err; | |
859 | abuf = OPENSSL_malloc(siglen); | |
76fa8f18 DSH |
860 | if(!abuf) |
861 | goto err; | |
b7683e3a DSH |
862 | if (EVP_DigestSignFinal(&mctx, abuf, &siglen) <= 0) |
863 | goto err; | |
864 | ||
865 | if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN, | |
866 | EVP_PKEY_CTRL_PKCS7_SIGN, 1, si) <= 0) | |
867 | { | |
868 | PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SIGN, PKCS7_R_CTRL_ERROR); | |
76fa8f18 | 869 | goto err; |
b7683e3a | 870 | } |
76fa8f18 DSH |
871 | |
872 | EVP_MD_CTX_cleanup(&mctx); | |
873 | ||
874 | ASN1_STRING_set0(si->enc_digest, abuf, siglen); | |
76fa8f18 DSH |
875 | |
876 | return 1; | |
877 | ||
878 | err: | |
879 | if (abuf) | |
880 | OPENSSL_free(abuf); | |
881 | EVP_MD_CTX_cleanup(&mctx); | |
882 | return 0; | |
883 | ||
884 | } | |
76fa8f18 | 885 | |
6b691a5c UM |
886 | int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx, BIO *bio, |
887 | PKCS7 *p7, PKCS7_SIGNER_INFO *si) | |
d02b48c6 | 888 | { |
d02b48c6 | 889 | PKCS7_ISSUER_AND_SERIAL *ias; |
dfeab068 | 890 | int ret=0,i; |
f73e07cf | 891 | STACK_OF(X509) *cert; |
d02b48c6 RE |
892 | X509 *x509; |
893 | ||
dfeab068 RE |
894 | if (PKCS7_type_is_signed(p7)) |
895 | { | |
896 | cert=p7->d.sign->cert; | |
897 | } | |
898 | else if (PKCS7_type_is_signedAndEnveloped(p7)) | |
899 | { | |
900 | cert=p7->d.signed_and_enveloped->cert; | |
901 | } | |
902 | else | |
903 | { | |
904 | PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,PKCS7_R_WRONG_PKCS7_TYPE); | |
905 | goto err; | |
906 | } | |
58964a49 | 907 | /* XXXXXXXXXXXXXXXXXXXXXXX */ |
d02b48c6 | 908 | ias=si->issuer_and_serial; |
d02b48c6 | 909 | |
dfeab068 | 910 | x509=X509_find_by_issuer_and_serial(cert,ias->issuer,ias->serial); |
d02b48c6 RE |
911 | |
912 | /* were we able to find the cert in passed to us */ | |
913 | if (x509 == NULL) | |
914 | { | |
915 | PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,PKCS7_R_UNABLE_TO_FIND_CERTIFICATE); | |
916 | goto err; | |
917 | } | |
918 | ||
919 | /* Lets verify */ | |
79aa04ef GT |
920 | if(!X509_STORE_CTX_init(ctx,cert_store,x509,cert)) |
921 | { | |
922 | PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,ERR_R_X509_LIB); | |
923 | goto err; | |
924 | } | |
5a9a4b29 | 925 | X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_SMIME_SIGN); |
d02b48c6 | 926 | i=X509_verify_cert(ctx); |
dfeab068 RE |
927 | if (i <= 0) |
928 | { | |
929 | PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,ERR_R_X509_LIB); | |
0fa197d8 | 930 | X509_STORE_CTX_cleanup(ctx); |
dfeab068 RE |
931 | goto err; |
932 | } | |
d02b48c6 RE |
933 | X509_STORE_CTX_cleanup(ctx); |
934 | ||
170afce5 DSH |
935 | return PKCS7_signatureVerify(bio, p7, si, x509); |
936 | err: | |
937 | return ret; | |
938 | } | |
939 | ||
940 | int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si, | |
941 | X509 *x509) | |
942 | { | |
943 | ASN1_OCTET_STRING *os; | |
944 | EVP_MD_CTX mdc_tmp,*mdc; | |
170afce5 DSH |
945 | int ret=0,i; |
946 | int md_type; | |
947 | STACK_OF(X509_ATTRIBUTE) *sk; | |
948 | BIO *btmp; | |
949 | EVP_PKEY *pkey; | |
950 | ||
dbad1690 BL |
951 | EVP_MD_CTX_init(&mdc_tmp); |
952 | ||
170afce5 DSH |
953 | if (!PKCS7_type_is_signed(p7) && |
954 | !PKCS7_type_is_signedAndEnveloped(p7)) { | |
955 | PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, | |
956 | PKCS7_R_WRONG_PKCS7_TYPE); | |
957 | goto err; | |
958 | } | |
959 | ||
d02b48c6 RE |
960 | md_type=OBJ_obj2nid(si->digest_alg->algorithm); |
961 | ||
962 | btmp=bio; | |
963 | for (;;) | |
964 | { | |
965 | if ((btmp == NULL) || | |
966 | ((btmp=BIO_find_type(btmp,BIO_TYPE_MD)) == NULL)) | |
967 | { | |
170afce5 DSH |
968 | PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, |
969 | PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); | |
d02b48c6 RE |
970 | goto err; |
971 | } | |
972 | BIO_get_md_ctx(btmp,&mdc); | |
973 | if (mdc == NULL) | |
974 | { | |
170afce5 | 975 | PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, |
5277d7cb | 976 | ERR_R_INTERNAL_ERROR); |
d02b48c6 RE |
977 | goto err; |
978 | } | |
72b60351 | 979 | if (EVP_MD_CTX_type(mdc) == md_type) |
d02b48c6 | 980 | break; |
beab098d DSH |
981 | /* Workaround for some broken clients that put the signature |
982 | * OID instead of the digest OID in digest_alg->algorithm | |
983 | */ | |
984 | if (EVP_MD_pkey_type(EVP_MD_CTX_md(mdc)) == md_type) | |
985 | break; | |
cfd3bb17 | 986 | btmp=BIO_next(btmp); |
d02b48c6 RE |
987 | } |
988 | ||
dfeab068 RE |
989 | /* mdc is the digest ctx that we want, unless there are attributes, |
990 | * in which case the digest is the signed attributes */ | |
20d2186c | 991 | EVP_MD_CTX_copy_ex(&mdc_tmp,mdc); |
d02b48c6 RE |
992 | |
993 | sk=si->auth_attr; | |
b6436ff2 | 994 | if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0)) |
d02b48c6 | 995 | { |
ec5add87 DSH |
996 | unsigned char md_dat[EVP_MAX_MD_SIZE], *abuf = NULL; |
997 | unsigned int md_len, alen; | |
dfeab068 RE |
998 | ASN1_OCTET_STRING *message_digest; |
999 | ||
20d2186c | 1000 | EVP_DigestFinal_ex(&mdc_tmp,md_dat,&md_len); |
dfeab068 RE |
1001 | message_digest=PKCS7_digest_from_attributes(sk); |
1002 | if (!message_digest) | |
1003 | { | |
170afce5 DSH |
1004 | PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, |
1005 | PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST); | |
dfeab068 RE |
1006 | goto err; |
1007 | } | |
0b415fb0 | 1008 | if ((message_digest->length != (int)md_len) || |
dfeab068 RE |
1009 | (memcmp(message_digest->data,md_dat,md_len))) |
1010 | { | |
1011 | #if 0 | |
1012 | { | |
1013 | int ii; | |
1014 | for (ii=0; ii<message_digest->length; ii++) | |
1015 | printf("%02X",message_digest->data[ii]); printf(" sent\n"); | |
1016 | for (ii=0; ii<md_len; ii++) printf("%02X",md_dat[ii]); printf(" calc\n"); | |
1017 | } | |
1018 | #endif | |
170afce5 DSH |
1019 | PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, |
1020 | PKCS7_R_DIGEST_FAILURE); | |
dfeab068 RE |
1021 | ret= -1; |
1022 | goto err; | |
1023 | } | |
1024 | ||
20d2186c | 1025 | EVP_VerifyInit_ex(&mdc_tmp,EVP_get_digestbynid(md_type), NULL); |
ec5add87 DSH |
1026 | |
1027 | alen = ASN1_item_i2d((ASN1_VALUE *)sk, &abuf, | |
bb5ea36b | 1028 | ASN1_ITEM_rptr(PKCS7_ATTR_VERIFY)); |
ec5add87 DSH |
1029 | EVP_VerifyUpdate(&mdc_tmp, abuf, alen); |
1030 | ||
1031 | OPENSSL_free(abuf); | |
d02b48c6 RE |
1032 | } |
1033 | ||
1034 | os=si->enc_digest; | |
924acc54 | 1035 | pkey = X509_get_pubkey(x509); |
db4a4659 DSH |
1036 | if (!pkey) |
1037 | { | |
1038 | ret = -1; | |
1039 | goto err; | |
1040 | } | |
dfeab068 | 1041 | |
924acc54 DSH |
1042 | i=EVP_VerifyFinal(&mdc_tmp,os->data,os->length, pkey); |
1043 | EVP_PKEY_free(pkey); | |
d02b48c6 RE |
1044 | if (i <= 0) |
1045 | { | |
170afce5 DSH |
1046 | PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, |
1047 | PKCS7_R_SIGNATURE_FAILURE); | |
d02b48c6 RE |
1048 | ret= -1; |
1049 | goto err; | |
1050 | } | |
1051 | else | |
1052 | ret=1; | |
1053 | err: | |
dbad1690 | 1054 | EVP_MD_CTX_cleanup(&mdc_tmp); |
d02b48c6 RE |
1055 | return(ret); |
1056 | } | |
1057 | ||
6b691a5c | 1058 | PKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx) |
dfeab068 | 1059 | { |
8f0edcd1 | 1060 | STACK_OF(PKCS7_RECIP_INFO) *rsk; |
dfeab068 RE |
1061 | PKCS7_RECIP_INFO *ri; |
1062 | int i; | |
1063 | ||
1064 | i=OBJ_obj2nid(p7->type); | |
1065 | if (i != NID_pkcs7_signedAndEnveloped) return(NULL); | |
1066 | rsk=p7->d.signed_and_enveloped->recipientinfo; | |
8f0edcd1 BL |
1067 | ri=sk_PKCS7_RECIP_INFO_value(rsk,0); |
1068 | if (sk_PKCS7_RECIP_INFO_num(rsk) <= idx) return(NULL); | |
1069 | ri=sk_PKCS7_RECIP_INFO_value(rsk,idx); | |
dfeab068 RE |
1070 | return(ri->issuer_and_serial); |
1071 | } | |
1072 | ||
6b691a5c | 1073 | ASN1_TYPE *PKCS7_get_signed_attribute(PKCS7_SIGNER_INFO *si, int nid) |
dfeab068 RE |
1074 | { |
1075 | return(get_attribute(si->auth_attr,nid)); | |
1076 | } | |
1077 | ||
6b691a5c | 1078 | ASN1_TYPE *PKCS7_get_attribute(PKCS7_SIGNER_INFO *si, int nid) |
dfeab068 RE |
1079 | { |
1080 | return(get_attribute(si->unauth_attr,nid)); | |
1081 | } | |
1082 | ||
b6436ff2 | 1083 | static ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid) |
dfeab068 RE |
1084 | { |
1085 | int i; | |
1086 | X509_ATTRIBUTE *xa; | |
1087 | ASN1_OBJECT *o; | |
1088 | ||
1089 | o=OBJ_nid2obj(nid); | |
10243d97 | 1090 | if (!o || !sk) return(NULL); |
b6436ff2 | 1091 | for (i=0; i<sk_X509_ATTRIBUTE_num(sk); i++) |
dfeab068 | 1092 | { |
b6436ff2 | 1093 | xa=sk_X509_ATTRIBUTE_value(sk,i); |
dfeab068 RE |
1094 | if (OBJ_cmp(xa->object,o) == 0) |
1095 | { | |
9d6b1ce6 | 1096 | if (!xa->single && sk_ASN1_TYPE_num(xa->value.set)) |
d35ea5b0 | 1097 | return(sk_ASN1_TYPE_value(xa->value.set,0)); |
dfeab068 RE |
1098 | else |
1099 | return(NULL); | |
1100 | } | |
1101 | } | |
1102 | return(NULL); | |
1103 | } | |
1104 | ||
b6436ff2 | 1105 | ASN1_OCTET_STRING *PKCS7_digest_from_attributes(STACK_OF(X509_ATTRIBUTE) *sk) |
10243d97 | 1106 | { |
dfeab068 | 1107 | ASN1_TYPE *astype; |
10243d97 DSH |
1108 | if(!(astype = get_attribute(sk, NID_pkcs9_messageDigest))) return NULL; |
1109 | return astype->value.octet_string; | |
1110 | } | |
dfeab068 | 1111 | |
b6436ff2 BL |
1112 | int PKCS7_set_signed_attributes(PKCS7_SIGNER_INFO *p7si, |
1113 | STACK_OF(X509_ATTRIBUTE) *sk) | |
dfeab068 RE |
1114 | { |
1115 | int i; | |
1116 | ||
1117 | if (p7si->auth_attr != NULL) | |
b6436ff2 BL |
1118 | sk_X509_ATTRIBUTE_pop_free(p7si->auth_attr,X509_ATTRIBUTE_free); |
1119 | p7si->auth_attr=sk_X509_ATTRIBUTE_dup(sk); | |
1120 | for (i=0; i<sk_X509_ATTRIBUTE_num(sk); i++) | |
dfeab068 | 1121 | { |
b6436ff2 BL |
1122 | if ((sk_X509_ATTRIBUTE_set(p7si->auth_attr,i, |
1123 | X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value(sk,i)))) | |
1124 | == NULL) | |
dfeab068 RE |
1125 | return(0); |
1126 | } | |
1127 | return(1); | |
1128 | } | |
1129 | ||
b6436ff2 | 1130 | int PKCS7_set_attributes(PKCS7_SIGNER_INFO *p7si, STACK_OF(X509_ATTRIBUTE) *sk) |
dfeab068 RE |
1131 | { |
1132 | int i; | |
1133 | ||
1134 | if (p7si->unauth_attr != NULL) | |
b6436ff2 BL |
1135 | sk_X509_ATTRIBUTE_pop_free(p7si->unauth_attr, |
1136 | X509_ATTRIBUTE_free); | |
1137 | p7si->unauth_attr=sk_X509_ATTRIBUTE_dup(sk); | |
1138 | for (i=0; i<sk_X509_ATTRIBUTE_num(sk); i++) | |
dfeab068 | 1139 | { |
b6436ff2 BL |
1140 | if ((sk_X509_ATTRIBUTE_set(p7si->unauth_attr,i, |
1141 | X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value(sk,i)))) | |
1142 | == NULL) | |
dfeab068 RE |
1143 | return(0); |
1144 | } | |
1145 | return(1); | |
1146 | } | |
1147 | ||
6b691a5c | 1148 | int PKCS7_add_signed_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype, |
c8b41850 | 1149 | void *value) |
dfeab068 RE |
1150 | { |
1151 | return(add_attribute(&(p7si->auth_attr),nid,atrtype,value)); | |
1152 | } | |
1153 | ||
6b691a5c | 1154 | int PKCS7_add_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype, |
c8b41850 | 1155 | void *value) |
dfeab068 RE |
1156 | { |
1157 | return(add_attribute(&(p7si->unauth_attr),nid,atrtype,value)); | |
1158 | } | |
1159 | ||
b6436ff2 BL |
1160 | static int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype, |
1161 | void *value) | |
dfeab068 RE |
1162 | { |
1163 | X509_ATTRIBUTE *attr=NULL; | |
dfeab068 RE |
1164 | |
1165 | if (*sk == NULL) | |
1166 | { | |
62324627 | 1167 | *sk = sk_X509_ATTRIBUTE_new_null(); |
dfeab068 RE |
1168 | new_attrib: |
1169 | attr=X509_ATTRIBUTE_create(nid,atrtype,value); | |
b6436ff2 | 1170 | sk_X509_ATTRIBUTE_push(*sk,attr); |
dfeab068 RE |
1171 | } |
1172 | else | |
1173 | { | |
1174 | int i; | |
1175 | ||
b6436ff2 | 1176 | for (i=0; i<sk_X509_ATTRIBUTE_num(*sk); i++) |
dfeab068 | 1177 | { |
b6436ff2 | 1178 | attr=sk_X509_ATTRIBUTE_value(*sk,i); |
dfeab068 RE |
1179 | if (OBJ_obj2nid(attr->object) == nid) |
1180 | { | |
1181 | X509_ATTRIBUTE_free(attr); | |
1182 | attr=X509_ATTRIBUTE_create(nid,atrtype,value); | |
b6436ff2 | 1183 | sk_X509_ATTRIBUTE_set(*sk,i,attr); |
dfeab068 RE |
1184 | goto end; |
1185 | } | |
1186 | } | |
1187 | goto new_attrib; | |
1188 | } | |
1189 | end: | |
1190 | return(1); | |
1191 | } | |
1192 |