GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libcrypto/pkcs7/pk7_smime.c Lines: 146 268 54.5 %
Date: 2017-11-07 Branches: 106 218 48.6 %

Line Branch Exec Source
1
/* $OpenBSD: pk7_smime.c,v 1.22 2017/01/29 17:49:23 beck Exp $ */
2
/* Written by Dr Stephen N Henson (steve@openssl.org) 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
63
#include <openssl/err.h>
64
#include <openssl/x509.h>
65
#include <openssl/x509v3.h>
66
67
static int pkcs7_copy_existing_digest(PKCS7 *p7, PKCS7_SIGNER_INFO *si);
68
69
PKCS7 *
70
PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs, BIO *data,
71
    int flags)
72
{
73
	PKCS7 *p7;
74
	int i;
75
76
28
	if (!(p7 = PKCS7_new())) {
77
		PKCS7error(ERR_R_MALLOC_FAILURE);
78
		return NULL;
79
	}
80
81
14
	if (!PKCS7_set_type(p7, NID_pkcs7_signed))
82
		goto err;
83
84
14
	if (!PKCS7_content_new(p7, NID_pkcs7_data))
85
		goto err;
86
87

20
	if (pkey && !PKCS7_sign_add_signer(p7, signcert, pkey, NULL, flags)) {
88
		PKCS7error(PKCS7_R_PKCS7_ADD_SIGNER_ERROR);
89
		goto err;
90
	}
91
92
14
	if (!(flags & PKCS7_NOCERTS)) {
93
40
		for (i = 0; i < sk_X509_num(certs); i++) {
94
6
			if (!PKCS7_add_certificate(p7, sk_X509_value(certs, i)))
95
				goto err;
96
		}
97
	}
98
99
14
	if (flags & PKCS7_DETACHED)
100
8
		PKCS7_set_detached(p7, 1);
101
102
14
	if (flags & (PKCS7_STREAM|PKCS7_PARTIAL))
103
8
		return p7;
104
105
6
	if (PKCS7_final(p7, data, flags))
106
6
		return p7;
107
108
err:
109
	PKCS7_free(p7);
110
	return NULL;
111
14
}
112
113
int
114
PKCS7_final(PKCS7 *p7, BIO *data, int flags)
115
{
116
	BIO *p7bio;
117
	int ret = 0;
118
119
36
	if (!(p7bio = PKCS7_dataInit(p7, NULL))) {
120
		PKCS7error(ERR_R_MALLOC_FAILURE);
121
		return 0;
122
	}
123
124
18
	SMIME_crlf_copy(data, p7bio, flags);
125
126
18
	(void)BIO_flush(p7bio);
127
128
18
	if (!PKCS7_dataFinal(p7, p7bio)) {
129
		PKCS7error(PKCS7_R_PKCS7_DATASIGN);
130
		goto err;
131
	}
132
133
18
	ret = 1;
134
135
err:
136
18
	BIO_free_all(p7bio);
137
138
18
	return ret;
139
18
}
140
141
/* Check to see if a cipher exists and if so add S/MIME capabilities */
142
143
static int
144
add_cipher_smcap(STACK_OF(X509_ALGOR) *sk, int nid, int arg)
145
{
146
252
	if (EVP_get_cipherbynid(nid))
147
126
		return PKCS7_simple_smimecap(sk, nid, arg);
148
	return 1;
149
126
}
150
151
static int
152
add_digest_smcap(STACK_OF(X509_ALGOR) *sk, int nid, int arg)
153
{
154
84
	if (EVP_get_digestbynid(nid))
155
42
		return PKCS7_simple_smimecap(sk, nid, arg);
156
	return 1;
157
42
}
158
159
PKCS7_SIGNER_INFO *
160
PKCS7_sign_add_signer(PKCS7 *p7, X509 *signcert, EVP_PKEY *pkey,
161
    const EVP_MD *md, int flags)
162
{
163
	PKCS7_SIGNER_INFO *si = NULL;
164
	STACK_OF(X509_ALGOR) *smcap = NULL;
165
166
28
	if (!X509_check_private_key(signcert, pkey)) {
167
		PKCS7error(PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE);
168
		return NULL;
169
	}
170
171
14
	if (!(si = PKCS7_add_signature(p7, signcert, pkey, md))) {
172
		PKCS7error(PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR);
173
		return NULL;
174
	}
175
176
14
	if (!(flags & PKCS7_NOCERTS)) {
177
14
		if (!PKCS7_add_certificate(p7, signcert))
178
			goto err;
179
	}
180
181
14
	if (!(flags & PKCS7_NOATTR)) {
182
14
		if (!PKCS7_add_attrib_content_type(si, NULL))
183
			goto err;
184
		/* Add SMIMECapabilities */
185
14
		if (!(flags & PKCS7_NOSMIMECAP)) {
186
14
			if (!(smcap = sk_X509_ALGOR_new_null())) {
187
				PKCS7error(ERR_R_MALLOC_FAILURE);
188
				goto err;
189
			}
190

28
			if (!add_cipher_smcap(smcap, NID_aes_256_cbc, -1) ||
191
14
			    !add_digest_smcap(smcap, NID_id_GostR3411_94, -1) ||
192
14
			    !add_digest_smcap(smcap, NID_id_tc26_gost3411_2012_256, -1) ||
193
14
			    !add_digest_smcap(smcap, NID_id_tc26_gost3411_2012_512, -1) ||
194
14
			    !add_cipher_smcap(smcap, NID_id_Gost28147_89, -1) ||
195
14
			    !add_cipher_smcap(smcap, NID_aes_192_cbc, -1) ||
196
14
			    !add_cipher_smcap(smcap, NID_aes_128_cbc, -1) ||
197
14
			    !add_cipher_smcap(smcap, NID_des_ede3_cbc, -1) ||
198
14
			    !add_cipher_smcap(smcap, NID_rc2_cbc, 128) ||
199
14
			    !add_cipher_smcap(smcap, NID_rc2_cbc, 64) ||
200
14
			    !add_cipher_smcap(smcap, NID_des_cbc, -1) ||
201
14
			    !add_cipher_smcap(smcap, NID_rc2_cbc, 40) ||
202
14
			    !PKCS7_add_attrib_smimecap(si, smcap))
203
				goto err;
204
14
			sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free);
205
			smcap = NULL;
206
14
		}
207
14
		if (flags & PKCS7_REUSE_DIGEST) {
208
			if (!pkcs7_copy_existing_digest(p7, si))
209
				goto err;
210
			if (!(flags & PKCS7_PARTIAL) &&
211
			    !PKCS7_SIGNER_INFO_sign(si))
212
				goto err;
213
		}
214
	}
215
14
	return si;
216
217
err:
218
	if (smcap)
219
		sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free);
220
	return NULL;
221
14
}
222
223
/* Search for a digest matching SignerInfo digest type and if found
224
 * copy across.
225
 */
226
227
static int
228
pkcs7_copy_existing_digest(PKCS7 *p7, PKCS7_SIGNER_INFO *si)
229
{
230
	int i;
231
	STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
232
	PKCS7_SIGNER_INFO *sitmp;
233
	ASN1_OCTET_STRING *osdig = NULL;
234
235
	sinfos = PKCS7_get_signer_info(p7);
236
	for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++) {
237
		sitmp = sk_PKCS7_SIGNER_INFO_value(sinfos, i);
238
		if (si == sitmp)
239
			break;
240
		if (sk_X509_ATTRIBUTE_num(sitmp->auth_attr) <= 0)
241
			continue;
242
		if (!OBJ_cmp(si->digest_alg->algorithm,
243
		    sitmp->digest_alg->algorithm)) {
244
			osdig = PKCS7_digest_from_attributes(sitmp->auth_attr);
245
			break;
246
		}
247
248
	}
249
250
	if (osdig)
251
		return PKCS7_add1_attrib_digest(si, osdig->data, osdig->length);
252
253
	PKCS7error(PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND);
254
	return 0;
255
}
256
257
int
258
PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store, BIO *indata,
259
    BIO *out, int flags)
260
{
261
	STACK_OF(X509) *signers;
262
	X509 *signer;
263
	STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
264
	PKCS7_SIGNER_INFO *si;
265
28
	X509_STORE_CTX cert_ctx;
266
14
	char buf[4096];
267
	int i, j = 0, k, ret = 0;
268
	BIO *p7bio;
269
	BIO *tmpin, *tmpout;
270
271
14
	if (!p7) {
272
		PKCS7error(PKCS7_R_INVALID_NULL_POINTER);
273
		return 0;
274
	}
275
276
14
	if (!PKCS7_type_is_signed(p7)) {
277
		PKCS7error(PKCS7_R_WRONG_CONTENT_TYPE);
278
		return 0;
279
	}
280
281
	/* Check for no data and no content: no data to verify signature */
282
14
	if (PKCS7_get_detached(p7) && !indata) {
283
		PKCS7error(PKCS7_R_NO_CONTENT);
284
		return 0;
285
	}
286
287
	/*
288
	 * Very old Netscape illegally included empty content with
289
	 * a detached signature.  Very old users should upgrade.
290
	 */
291
	/* Check for data and content: two sets of data */
292
14
	if (!PKCS7_get_detached(p7) && indata) {
293
		PKCS7error(PKCS7_R_CONTENT_AND_DATA_PRESENT);
294
		return 0;
295
	}
296
297
14
	sinfos = PKCS7_get_signer_info(p7);
298
299

28
	if (!sinfos || !sk_PKCS7_SIGNER_INFO_num(sinfos)) {
300
		PKCS7error(PKCS7_R_NO_SIGNATURES_ON_DATA);
301
		return 0;
302
	}
303
304
305
14
	signers = PKCS7_get0_signers(p7, certs, flags);
306
307
14
	if (!signers)
308
		return 0;
309
310
	/* Now verify the certificates */
311
312
14
	if (!(flags & PKCS7_NOVERIFY))
313
56
		for (k = 0; k < sk_X509_num(signers); k++) {
314
14
			signer = sk_X509_value (signers, k);
315
14
			if  (!(flags & PKCS7_NOCHAIN)) {
316
14
				if (!X509_STORE_CTX_init(&cert_ctx, store,
317
14
				    signer, p7->d.sign->cert)) {
318
					PKCS7error(ERR_R_X509_LIB);
319
					sk_X509_free(signers);
320
					return 0;
321
				}
322
28
				if (X509_STORE_CTX_set_default(&cert_ctx,
323
14
				    "smime_sign") == 0) {
324
					sk_X509_free(signers);
325
					return 0;
326
				}
327
			} else if (!X509_STORE_CTX_init(&cert_ctx, store,
328
			    signer, NULL)) {
329
				PKCS7error(ERR_R_X509_LIB);
330
				sk_X509_free(signers);
331
				return 0;
332
			}
333
14
			if (!(flags & PKCS7_NOCRL))
334
14
				X509_STORE_CTX_set0_crls(&cert_ctx, p7->d.sign->crl);
335
14
			i = X509_verify_cert(&cert_ctx);
336
14
			if (i <= 0)
337
				j = X509_STORE_CTX_get_error(&cert_ctx);
338
14
			X509_STORE_CTX_cleanup(&cert_ctx);
339
14
			if (i <= 0) {
340
				PKCS7error(PKCS7_R_CERTIFICATE_VERIFY_ERROR);
341
				ERR_asprintf_error_data("Verify error:%s",
342
				    X509_verify_cert_error_string(j));
343
				sk_X509_free(signers);
344
				return 0;
345
			}
346
			/* Check for revocation status here */
347
		}
348
349
	/*
350
	 * Performance optimization: if the content is a memory BIO then
351
	 * store its contents in a temporary read only memory BIO. This
352
	 * avoids potentially large numbers of slow copies of data which will
353
	 * occur when reading from a read write memory BIO when signatures
354
	 * are calculated.
355
	 */
356

22
	if (indata && (BIO_method_type(indata) == BIO_TYPE_MEM)) {
357
8
		char *ptr;
358
		long len;
359
360
8
		len = BIO_get_mem_data(indata, &ptr);
361
8
		tmpin = BIO_new_mem_buf(ptr, len);
362
8
		if (tmpin == NULL) {
363
			PKCS7error(ERR_R_MALLOC_FAILURE);
364
			return 0;
365
		}
366
16
	} else
367
		tmpin = indata;
368
369
370
14
	if (!(p7bio = PKCS7_dataInit(p7, tmpin)))
371
		goto err;
372
373
14
	if (flags & PKCS7_TEXT) {
374
		if (!(tmpout = BIO_new(BIO_s_mem()))) {
375
			PKCS7error(ERR_R_MALLOC_FAILURE);
376
			goto err;
377
		}
378
		BIO_set_mem_eof_return(tmpout, 0);
379
	} else
380
		tmpout = out;
381
382
	/* We now have to 'read' from p7bio to calculate digests etc. */
383
	for (;;) {
384
28
		i = BIO_read(p7bio, buf, sizeof(buf));
385
28
		if (i <= 0)
386
			break;
387
14
		if (tmpout)
388
14
			BIO_write(tmpout, buf, i);
389
	}
390
391
14
	if (flags & PKCS7_TEXT) {
392
		if (!SMIME_text(tmpout, out)) {
393
			PKCS7error(PKCS7_R_SMIME_TEXT_ERROR);
394
			BIO_free(tmpout);
395
			goto err;
396
		}
397
		BIO_free(tmpout);
398
	}
399
400
	/* Now Verify All Signatures */
401
14
	if (!(flags & PKCS7_NOSIGS))
402
56
		for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++) {
403
14
			si = sk_PKCS7_SIGNER_INFO_value(sinfos, i);
404
14
			signer = sk_X509_value (signers, i);
405
14
			j = PKCS7_signatureVerify(p7bio, p7, si, signer);
406
14
			if (j <= 0) {
407
				PKCS7error(PKCS7_R_SIGNATURE_FAILURE);
408
				goto err;
409
			}
410
		}
411
412
14
	ret = 1;
413
414
err:
415
14
	if (tmpin == indata) {
416
		if (indata)
417
			BIO_pop(p7bio);
418
	}
419
14
	BIO_free_all(p7bio);
420
14
	sk_X509_free(signers);
421
422
14
	return ret;
423
14
}
424
425
STACK_OF(X509) *
426
PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs, int flags)
427
{
428
	STACK_OF(X509) *signers;
429
	STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
430
	PKCS7_SIGNER_INFO *si;
431
	PKCS7_ISSUER_AND_SERIAL *ias;
432
	X509 *signer;
433
	int i;
434
435
36
	if (!p7) {
436
		PKCS7error(PKCS7_R_INVALID_NULL_POINTER);
437
		return NULL;
438
	}
439
440
18
	if (!PKCS7_type_is_signed(p7)) {
441
		PKCS7error(PKCS7_R_WRONG_CONTENT_TYPE);
442
		return NULL;
443
	}
444
445
	/* Collect all the signers together */
446
18
	sinfos = PKCS7_get_signer_info(p7);
447
18
	if (sk_PKCS7_SIGNER_INFO_num(sinfos) <= 0) {
448
		PKCS7error(PKCS7_R_NO_SIGNERS);
449
		return 0;
450
	}
451
452
18
	if (!(signers = sk_X509_new_null())) {
453
		PKCS7error(ERR_R_MALLOC_FAILURE);
454
		return NULL;
455
	}
456
457
72
	for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++) {
458
18
		si = sk_PKCS7_SIGNER_INFO_value(sinfos, i);
459
18
		ias = si->issuer_and_serial;
460
		signer = NULL;
461
		/* If any certificates passed they take priority */
462
18
		if (certs)
463
14
			signer = X509_find_by_issuer_and_serial (certs,
464
14
			    ias->issuer, ias->serial);
465

26
		if (!signer && !(flags & PKCS7_NOINTERN) && p7->d.sign->cert)
466
4
			signer =
467
4
			    X509_find_by_issuer_and_serial(p7->d.sign->cert,
468
4
			      ias->issuer, ias->serial);
469
18
		if (!signer) {
470
			PKCS7error(PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND);
471
			sk_X509_free(signers);
472
			return 0;
473
		}
474
475
18
		if (!sk_X509_push(signers, signer)) {
476
			sk_X509_free(signers);
477
			return NULL;
478
		}
479
	}
480
18
	return signers;
481
18
}
482
483
/* Build a complete PKCS#7 enveloped data */
484
485
PKCS7 *
486
PKCS7_encrypt(STACK_OF(X509) *certs, BIO *in, const EVP_CIPHER *cipher,
487
    int flags)
488
{
489
	PKCS7 *p7;
490
	BIO *p7bio = NULL;
491
	int i;
492
	X509 *x509;
493
494
12
	if (!(p7 = PKCS7_new())) {
495
		PKCS7error(ERR_R_MALLOC_FAILURE);
496
		return NULL;
497
	}
498
499
6
	if (!PKCS7_set_type(p7, NID_pkcs7_enveloped))
500
		goto err;
501
6
	if (!PKCS7_set_cipher(p7, cipher)) {
502
		PKCS7error(PKCS7_R_ERROR_SETTING_CIPHER);
503
		goto err;
504
	}
505
506
24
	for (i = 0; i < sk_X509_num(certs); i++) {
507
6
		x509 = sk_X509_value(certs, i);
508
6
		if (!PKCS7_add_recipient(p7, x509)) {
509
			PKCS7error(PKCS7_R_ERROR_ADDING_RECIPIENT);
510
			goto err;
511
		}
512
	}
513
514
6
	if (flags & PKCS7_STREAM)
515
		return p7;
516
517
6
	if (PKCS7_final(p7, in, flags))
518
6
		return p7;
519
520
err:
521
	BIO_free_all(p7bio);
522
	PKCS7_free(p7);
523
	return NULL;
524
6
}
525
526
int
527
PKCS7_decrypt(PKCS7 *p7, EVP_PKEY *pkey, X509 *cert, BIO *data, int flags)
528
{
529
	BIO *tmpmem;
530
	int ret, i;
531
12
	char buf[4096];
532
533
6
	if (!p7) {
534
		PKCS7error(PKCS7_R_INVALID_NULL_POINTER);
535
		return 0;
536
	}
537
538
6
	if (!PKCS7_type_is_enveloped(p7)) {
539
		PKCS7error(PKCS7_R_WRONG_CONTENT_TYPE);
540
		return 0;
541
	}
542
543

12
	if (cert && !X509_check_private_key(cert, pkey)) {
544
		PKCS7error(PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE);
545
		return 0;
546
	}
547
548
6
	if (!(tmpmem = PKCS7_dataDecode(p7, pkey, NULL, cert))) {
549
		PKCS7error(PKCS7_R_DECRYPT_ERROR);
550
		return 0;
551
	}
552
553
6
	if (flags & PKCS7_TEXT) {
554
		BIO *tmpbuf;
555
556
		/* Encrypt BIOs can't do BIO_gets() so add a buffer BIO */
557
		if (!(tmpbuf = BIO_new(BIO_f_buffer()))) {
558
			PKCS7error(ERR_R_MALLOC_FAILURE);
559
			BIO_free_all(tmpmem);
560
			return 0;
561
		}
562
		BIO_push(tmpbuf, tmpmem);
563
		ret = SMIME_text(tmpbuf, data);
564
		if (ret > 0 && BIO_method_type(tmpmem) == BIO_TYPE_CIPHER) {
565
			if (!BIO_get_cipher_status(tmpmem))
566
				ret = 0;
567
		}
568
		BIO_free_all(tmpbuf);
569
		return ret;
570
	} else {
571
		for (;;) {
572
12
			i = BIO_read(tmpmem, buf, sizeof(buf));
573
12
			if (i <= 0) {
574
				ret = 1;
575
6
				if (BIO_method_type(tmpmem) ==
576
				    BIO_TYPE_CIPHER) {
577
6
					if (!BIO_get_cipher_status(tmpmem))
578
						ret = 0;
579
				}
580
				break;
581
			}
582
6
			if (BIO_write(data, buf, i) != i) {
583
				ret = 0;
584
				break;
585
			}
586
		}
587
6
		BIO_free_all(tmpmem);
588
6
		return ret;
589
	}
590
6
}