d3b55e427387ffacc022ad4dbe5ef1e999567353
[openssl.git] / crypto / pkcs7 / pk7_smime.c
1 /* pk7_smime.c */
2 /* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
3  * project.
4  */
5 /* ====================================================================
6  * Copyright (c) 1999-2004 The OpenSSL Project.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer. 
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. All advertising materials mentioning features or use of this
21  *    software must display the following acknowledgment:
22  *    "This product includes software developed by the OpenSSL Project
23  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24  *
25  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26  *    endorse or promote products derived from this software without
27  *    prior written permission. For written permission, please contact
28  *    licensing@OpenSSL.org.
29  *
30  * 5. Products derived from this software may not be called "OpenSSL"
31  *    nor may "OpenSSL" appear in their names without prior written
32  *    permission of the OpenSSL Project.
33  *
34  * 6. Redistributions of any form whatsoever must retain the following
35  *    acknowledgment:
36  *    "This product includes software developed by the OpenSSL Project
37  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38  *
39  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50  * OF THE POSSIBILITY OF SUCH DAMAGE.
51  * ====================================================================
52  *
53  * This product includes cryptographic software written by Eric Young
54  * (eay@cryptsoft.com).  This product includes software written by Tim
55  * Hudson (tjh@cryptsoft.com).
56  *
57  */
58
59 /* Simple PKCS#7 processing functions */
60
61 #include <stdio.h>
62 #include "cryptlib.h"
63 #include <openssl/x509.h>
64 #include <openssl/x509v3.h>
65
66 static int pkcs7_copy_existing_digest(PKCS7 *p7, PKCS7_SIGNER_INFO *si);
67
68 PKCS7 *PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
69                   BIO *data, int flags)
70 {
71         PKCS7 *p7;
72         int i;
73
74         if(!(p7 = PKCS7_new()))
75                 {
76                 PKCS7err(PKCS7_F_PKCS7_SIGN,ERR_R_MALLOC_FAILURE);
77                 return NULL;
78                 }
79
80         if (!PKCS7_set_type(p7, NID_pkcs7_signed))
81                 goto err;
82
83         if (!PKCS7_content_new(p7, NID_pkcs7_data))
84                 goto err;
85
86         if (pkey && !PKCS7_sign_add_signer(p7, signcert, pkey, NULL, flags))
87                 {
88                 PKCS7err(PKCS7_F_PKCS7_SIGN,PKCS7_R_PKCS7_ADD_SIGNER_ERROR);
89                 goto err;
90                 }
91
92         if(!(flags & PKCS7_NOCERTS))
93                 {
94                 for(i = 0; i < sk_X509_num(certs); i++)
95                         {
96                         if (!PKCS7_add_certificate(p7, sk_X509_value(certs, i)))
97                                 goto err;
98                         }
99                 }
100
101         if (flags & (PKCS7_STREAM|PKCS7_PARTIAL))
102                 return p7;
103
104         if (PKCS7_final(p7, data, flags))
105                 return p7;
106
107         err:
108         PKCS7_free(p7);
109         return NULL;
110 }
111
112 int PKCS7_final(PKCS7 *p7, BIO *data, int flags)
113         {
114         BIO *p7bio;
115         int ret = 0;
116         if (!(p7bio = PKCS7_dataInit(p7, NULL)))
117                 {
118                 PKCS7err(PKCS7_F_PKCS7_FINAL,ERR_R_MALLOC_FAILURE);
119                 return 0;
120                 }
121
122         SMIME_crlf_copy(data, p7bio, flags);
123
124         if(PKCS7_type_is_signed(p7) && (flags & PKCS7_DETACHED))
125                 PKCS7_set_detached(p7, 1);
126
127         if (!PKCS7_dataFinal(p7,p7bio))
128                 {
129                 PKCS7err(PKCS7_F_PKCS7_FINAL,PKCS7_R_PKCS7_DATASIGN);
130                 goto err;
131                 }
132
133         ret = 1;
134
135         err:
136         BIO_free_all(p7bio);
137
138         return ret;
139
140         }
141
142 /* Check to see if a cipher exists and if so add S/MIME capabilities */
143
144 static int add_cipher_smcap(STACK_OF(X509_ALGOR) *sk, int nid, int arg)
145         {
146         if (EVP_get_cipherbynid(nid))
147                 return PKCS7_simple_smimecap(sk, nid, arg);
148         return 1;
149         }
150
151 PKCS7_SIGNER_INFO *PKCS7_sign_add_signer(PKCS7 *p7, X509 *signcert,
152                                         EVP_PKEY *pkey, const EVP_MD *md,
153                                         int flags)
154         {
155         PKCS7_SIGNER_INFO *si = NULL;
156         int si_free = 1;
157         STACK_OF(X509_ALGOR) *smcap = NULL;
158         if(!X509_check_private_key(signcert, pkey))
159                 {
160                 PKCS7err(PKCS7_F_PKCS7_SIGN_ADD_SIGNER,
161                         PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE);
162                 return NULL;
163                 }
164
165         if (!(si = PKCS7_add_signature(p7,signcert,pkey, md)))
166                 {
167                 PKCS7err(PKCS7_F_PKCS7_SIGN_ADD_SIGNER,
168                                 PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR);
169                 return NULL;
170                 }
171
172         /* si is now part of p7 so don't free it on error */
173
174         si_free = 0;
175
176         if(!(flags & PKCS7_NOCERTS))
177                 {
178                 if (!PKCS7_add_certificate(p7, signcert))
179                         goto err;
180                 }
181
182         if(!(flags & PKCS7_NOATTR))
183                 {
184                 if (!PKCS7_add_attrib_content_type(si, NULL))
185                         goto err;
186                 /* Add SMIMECapabilities */
187                 if(!(flags & PKCS7_NOSMIMECAP))
188                         {
189                         if(!(smcap = sk_X509_ALGOR_new_null()))
190                                 {
191                                 PKCS7err(PKCS7_F_PKCS7_SIGN_ADD_SIGNER,
192                                         ERR_R_MALLOC_FAILURE);
193                                 goto err;
194                                 }
195                         if (!add_cipher_smcap(smcap, NID_des_ede3_cbc, -1)
196                                 || !add_cipher_smcap(smcap, NID_rc2_cbc, 128)
197                                 || !add_cipher_smcap(smcap, NID_rc2_cbc, 64)
198                                 || !add_cipher_smcap(smcap, NID_des_cbc, -1)
199                                 || !add_cipher_smcap(smcap, NID_rc2_cbc, 40)
200                                 || !PKCS7_add_attrib_smimecap (si, smcap))
201                                 goto err;
202                         sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free);
203                         smcap = NULL;
204                         }
205                 if (flags & PKCS7_REUSE_DIGEST)
206                         {
207                         if (!pkcs7_copy_existing_digest(p7, si))
208                                 goto err;
209                         if (!PKCS7_SIGNER_INFO_sign(si))
210                                 goto err;
211                         }
212                 }
213         return si;
214         err:
215         if (smcap)
216                 sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free);
217         if (si && si_free)
218                 PKCS7_SIGNER_INFO_free(si);
219         return NULL;
220         }
221
222 /* Search for a digest matching SignerInfo digest type and if found
223  * copy across.
224  */
225
226 static int pkcs7_copy_existing_digest(PKCS7 *p7, PKCS7_SIGNER_INFO *si)
227         {
228         int i;
229         STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
230         PKCS7_SIGNER_INFO *sitmp;
231         ASN1_OCTET_STRING *osdig = NULL;
232         sinfos = PKCS7_get_signer_info(p7);
233         for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++)
234                 {
235                 sitmp = sk_PKCS7_SIGNER_INFO_value(sinfos, i);
236                 if (si == sitmp)
237                         break;
238                 if (sk_X509_ATTRIBUTE_num(sitmp->auth_attr) <= 0)
239                         continue;
240                 if (!OBJ_cmp(si->digest_alg->algorithm,
241                                 sitmp->digest_alg->algorithm))
242                         {
243                         osdig = PKCS7_digest_from_attributes(sitmp->auth_attr);
244                         break;
245                         }
246
247                 }
248
249         if (osdig)
250                 return PKCS7_add1_attrib_digest(si, osdig->data, osdig->length);
251
252         PKCS7err(PKCS7_F_PKCS7_COPY_EXISTING_DIGEST,
253                         PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND);
254         return 0;
255         }
256
257 int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store,
258                                         BIO *indata, BIO *out, int flags)
259 {
260         STACK_OF(X509) *signers;
261         X509 *signer;
262         STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
263         PKCS7_SIGNER_INFO *si;
264         X509_STORE_CTX cert_ctx;
265         char buf[4096];
266         int i, j=0, k, ret = 0;
267         BIO *p7bio;
268         BIO *tmpin, *tmpout;
269
270         if(!p7) {
271                 PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_INVALID_NULL_POINTER);
272                 return 0;
273         }
274
275         if(!PKCS7_type_is_signed(p7)) {
276                 PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_WRONG_CONTENT_TYPE);
277                 return 0;
278         }
279
280         /* Check for no data and no content: no data to verify signature */
281         if(PKCS7_get_detached(p7) && !indata) {
282                 PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_NO_CONTENT);
283                 return 0;
284         }
285 #if 0
286         /* NB: this test commented out because some versions of Netscape
287          * illegally include zero length content when signing data.
288          */
289
290         /* Check for data and content: two sets of data */
291         if(!PKCS7_get_detached(p7) && indata) {
292                                 PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_CONTENT_AND_DATA_PRESENT);
293                 return 0;
294         }
295 #endif
296
297         sinfos = PKCS7_get_signer_info(p7);
298
299         if(!sinfos || !sk_PKCS7_SIGNER_INFO_num(sinfos)) {
300                 PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_NO_SIGNATURES_ON_DATA);
301                 return 0;
302         }
303
304
305         signers = PKCS7_get0_signers(p7, certs, flags);
306
307         if(!signers) return 0;
308
309         /* Now verify the certificates */
310
311         if (!(flags & PKCS7_NOVERIFY)) for (k = 0; k < sk_X509_num(signers); k++) {
312                 signer = sk_X509_value (signers, k);
313                 if (!(flags & PKCS7_NOCHAIN)) {
314                         if(!X509_STORE_CTX_init(&cert_ctx, store, signer,
315                                                         p7->d.sign->cert))
316                                 {
317                                 PKCS7err(PKCS7_F_PKCS7_VERIFY,ERR_R_X509_LIB);
318                                 sk_X509_free(signers);
319                                 return 0;
320                                 }
321                         X509_STORE_CTX_set_purpose(&cert_ctx,
322                                                 X509_PURPOSE_SMIME_SIGN);
323                 } else if(!X509_STORE_CTX_init (&cert_ctx, store, signer, NULL)) {
324                         PKCS7err(PKCS7_F_PKCS7_VERIFY,ERR_R_X509_LIB);
325                         sk_X509_free(signers);
326                         return 0;
327                 }
328                 if (!(flags & PKCS7_NOCRL))
329                         X509_STORE_CTX_set0_crls(&cert_ctx, p7->d.sign->crl);
330                 i = X509_verify_cert(&cert_ctx);
331                 if (i <= 0) j = X509_STORE_CTX_get_error(&cert_ctx);
332                 X509_STORE_CTX_cleanup(&cert_ctx);
333                 if (i <= 0) {
334                         PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_CERTIFICATE_VERIFY_ERROR);
335                         ERR_add_error_data(2, "Verify error:",
336                                          X509_verify_cert_error_string(j));
337                         sk_X509_free(signers);
338                         return 0;
339                 }
340                 /* Check for revocation status here */
341         }
342
343         /* Performance optimization: if the content is a memory BIO then
344          * store its contents in a temporary read only memory BIO. This
345          * avoids potentially large numbers of slow copies of data which will
346          * occur when reading from a read write memory BIO when signatures
347          * are calculated.
348          */
349
350         if (indata && (BIO_method_type(indata) == BIO_TYPE_MEM))
351                 {
352                 char *ptr;
353                 long len;
354                 len = BIO_get_mem_data(indata, &ptr);
355                 tmpin = BIO_new_mem_buf(ptr, len);
356                 if (tmpin == NULL)
357                         {
358                         PKCS7err(PKCS7_F_PKCS7_VERIFY,ERR_R_MALLOC_FAILURE);
359                         return 0;
360                         }
361                 }
362         else
363                 tmpin = indata;
364                 
365
366         p7bio=PKCS7_dataInit(p7,tmpin);
367
368         if(flags & PKCS7_TEXT) {
369                 if(!(tmpout = BIO_new(BIO_s_mem()))) {
370                         PKCS7err(PKCS7_F_PKCS7_VERIFY,ERR_R_MALLOC_FAILURE);
371                         goto err;
372                 }
373         } else tmpout = out;
374
375         /* We now have to 'read' from p7bio to calculate digests etc. */
376         for (;;)
377         {
378                 i=BIO_read(p7bio,buf,sizeof(buf));
379                 if (i <= 0) break;
380                 if (tmpout) BIO_write(tmpout, buf, i);
381         }
382
383         if(flags & PKCS7_TEXT) {
384                 if(!SMIME_text(tmpout, out)) {
385                         PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_SMIME_TEXT_ERROR);
386                         BIO_free(tmpout);
387                         goto err;
388                 }
389                 BIO_free(tmpout);
390         }
391
392         /* Now Verify All Signatures */
393         if (!(flags & PKCS7_NOSIGS))
394             for (i=0; i<sk_PKCS7_SIGNER_INFO_num(sinfos); i++)
395                 {
396                 si=sk_PKCS7_SIGNER_INFO_value(sinfos,i);
397                 signer = sk_X509_value (signers, i);
398                 j=PKCS7_signatureVerify(p7bio,p7,si, signer);
399                 if (j <= 0) {
400                         PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_SIGNATURE_FAILURE);
401                         goto err;
402                 }
403         }
404
405         ret = 1;
406
407         err:
408         
409         if (tmpin == indata)
410                 {
411                 if (indata) BIO_pop(p7bio);
412                 }
413         BIO_free_all(p7bio);
414
415         sk_X509_free(signers);
416
417         return ret;
418 }
419
420 STACK_OF(X509) *PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs, int flags)
421 {
422         STACK_OF(X509) *signers;
423         STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
424         PKCS7_SIGNER_INFO *si;
425         PKCS7_ISSUER_AND_SERIAL *ias;
426         X509 *signer;
427         int i;
428
429         if(!p7) {
430                 PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS,PKCS7_R_INVALID_NULL_POINTER);
431                 return NULL;
432         }
433
434         if(!PKCS7_type_is_signed(p7)) {
435                 PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS,PKCS7_R_WRONG_CONTENT_TYPE);
436                 return NULL;
437         }
438
439         /* Collect all the signers together */
440
441         sinfos = PKCS7_get_signer_info(p7);
442
443         if(sk_PKCS7_SIGNER_INFO_num(sinfos) <= 0) {
444                 PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS,PKCS7_R_NO_SIGNERS);
445                 return 0;
446         }
447
448         if(!(signers = sk_X509_new_null())) {
449                 PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS,ERR_R_MALLOC_FAILURE);
450                 return NULL;
451         }
452
453         for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++)
454         {
455             si = sk_PKCS7_SIGNER_INFO_value(sinfos, i);
456             ias = si->issuer_and_serial;
457             signer = NULL;
458                 /* If any certificates passed they take priority */
459             if (certs) signer = X509_find_by_issuer_and_serial (certs,
460                                                 ias->issuer, ias->serial);
461             if (!signer && !(flags & PKCS7_NOINTERN)
462                         && p7->d.sign->cert) signer =
463                               X509_find_by_issuer_and_serial (p7->d.sign->cert,
464                                                 ias->issuer, ias->serial);
465             if (!signer) {
466                         PKCS7err(PKCS7_F_PKCS7_GET0_SIGNERS,PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND);
467                         sk_X509_free(signers);
468                         return 0;
469             }
470
471             sk_X509_push(signers, signer);
472         }
473         return signers;
474 }
475
476
477 /* Build a complete PKCS#7 enveloped data */
478
479 PKCS7 *PKCS7_encrypt(STACK_OF(X509) *certs, BIO *in, const EVP_CIPHER *cipher,
480                                                                 int flags)
481 {
482         PKCS7 *p7;
483         BIO *p7bio = NULL;
484         int i;
485         X509 *x509;
486         if(!(p7 = PKCS7_new())) {
487                 PKCS7err(PKCS7_F_PKCS7_ENCRYPT,ERR_R_MALLOC_FAILURE);
488                 return NULL;
489         }
490
491         PKCS7_set_type(p7, NID_pkcs7_enveloped);
492         if(!PKCS7_set_cipher(p7, cipher)) {
493                 PKCS7err(PKCS7_F_PKCS7_ENCRYPT,PKCS7_R_ERROR_SETTING_CIPHER);
494                 goto err;
495         }
496
497         for(i = 0; i < sk_X509_num(certs); i++) {
498                 x509 = sk_X509_value(certs, i);
499                 if(!PKCS7_add_recipient(p7, x509)) {
500                         PKCS7err(PKCS7_F_PKCS7_ENCRYPT,
501                                         PKCS7_R_ERROR_ADDING_RECIPIENT);
502                         goto err;
503                 }
504         }
505
506         if (PKCS7_final(p7, in, flags))
507                 return p7;
508
509         err:
510
511         BIO_free(p7bio);
512         PKCS7_free(p7);
513         return NULL;
514
515 }
516
517 int PKCS7_decrypt(PKCS7 *p7, EVP_PKEY *pkey, X509 *cert, BIO *data, int flags)
518 {
519         BIO *tmpmem;
520         int ret, i;
521         char buf[4096];
522
523         if(!p7) {
524                 PKCS7err(PKCS7_F_PKCS7_DECRYPT,PKCS7_R_INVALID_NULL_POINTER);
525                 return 0;
526         }
527
528         if(!PKCS7_type_is_enveloped(p7)) {
529                 PKCS7err(PKCS7_F_PKCS7_DECRYPT,PKCS7_R_WRONG_CONTENT_TYPE);
530                 return 0;
531         }
532
533         if(cert && !X509_check_private_key(cert, pkey)) {
534                 PKCS7err(PKCS7_F_PKCS7_DECRYPT,
535                                 PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE);
536                 return 0;
537         }
538
539         if(!(tmpmem = PKCS7_dataDecode(p7, pkey, NULL, cert))) {
540                 PKCS7err(PKCS7_F_PKCS7_DECRYPT, PKCS7_R_DECRYPT_ERROR);
541                 return 0;
542         }
543
544         if (flags & PKCS7_TEXT) {
545                 BIO *tmpbuf, *bread;
546                 /* Encrypt BIOs can't do BIO_gets() so add a buffer BIO */
547                 if(!(tmpbuf = BIO_new(BIO_f_buffer()))) {
548                         PKCS7err(PKCS7_F_PKCS7_DECRYPT, ERR_R_MALLOC_FAILURE);
549                         return 0;
550                 }
551                 if(!(bread = BIO_push(tmpbuf, tmpmem))) {
552                         PKCS7err(PKCS7_F_PKCS7_DECRYPT, ERR_R_MALLOC_FAILURE);
553                         return 0;
554                 }
555                 ret = SMIME_text(bread, data);
556                 BIO_free_all(bread);
557                 return ret;
558         } else {
559                 for(;;) {
560                         i = BIO_read(tmpmem, buf, sizeof(buf));
561                         if(i <= 0) break;
562                         BIO_write(data, buf, i);
563                 }
564                 BIO_free_all(tmpmem);
565                 return 1;
566         }
567 }