xref: /openbsd-src/lib/libcrypto/cms/cms_lib.c (revision 2777ee89d0e541ec819d05abee114837837abbec)
1 /* $OpenBSD: cms_lib.c,v 1.4 2014/07/25 06:05:32 doug Exp $ */
2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3  * project.
4  */
5 /* ====================================================================
6  * Copyright (c) 2008 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 
54 #include <openssl/asn1t.h>
55 #include <openssl/x509.h>
56 #include <openssl/err.h>
57 #include <openssl/pem.h>
58 #include <openssl/bio.h>
59 #include <openssl/asn1.h>
60 #include "cms.h"
61 #include "cms_lcl.h"
62 
63 IMPLEMENT_ASN1_FUNCTIONS(CMS_ContentInfo)
64 IMPLEMENT_ASN1_PRINT_FUNCTION(CMS_ContentInfo)
65 
66 DECLARE_ASN1_ITEM(CMS_CertificateChoices)
67 DECLARE_ASN1_ITEM(CMS_RevocationInfoChoice)
68 DECLARE_STACK_OF(CMS_CertificateChoices)
69 DECLARE_STACK_OF(CMS_RevocationInfoChoice)
70 
71 const ASN1_OBJECT *
72 CMS_get0_type(CMS_ContentInfo *cms)
73 {
74 	return cms->contentType;
75 }
76 
77 CMS_ContentInfo *
78 cms_Data_create(void)
79 {
80 	CMS_ContentInfo *cms;
81 
82 	cms = CMS_ContentInfo_new();
83 	if (cms) {
84 		cms->contentType = OBJ_nid2obj(NID_pkcs7_data);
85 		/* Never detached */
86 		CMS_set_detached(cms, 0);
87 	}
88 	return cms;
89 }
90 
91 BIO *
92 cms_content_bio(CMS_ContentInfo *cms)
93 {
94 	ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
95 
96 	if (!pos)
97 		return NULL;
98 	/* If content detached data goes nowhere: create NULL BIO */
99 	if (!*pos)
100 		return BIO_new(BIO_s_null());
101 	/* If content not detached and created return memory BIO
102 	 */
103 	if (!*pos || ((*pos)->flags == ASN1_STRING_FLAG_CONT))
104 		return BIO_new(BIO_s_mem());
105 	/* Else content was read in: return read only BIO for it */
106 	return BIO_new_mem_buf((*pos)->data, (*pos)->length);
107 }
108 
109 BIO *
110 CMS_dataInit(CMS_ContentInfo *cms, BIO *icont)
111 {
112 	BIO *cmsbio, *cont;
113 
114 	if (icont)
115 		cont = icont;
116 	else
117 		cont = cms_content_bio(cms);
118 	if (!cont) {
119 		CMSerr(CMS_F_CMS_DATAINIT, CMS_R_NO_CONTENT);
120 		return NULL;
121 	}
122 	switch (OBJ_obj2nid(cms->contentType)) {
123 	case NID_pkcs7_data:
124 		return cont;
125 	case NID_pkcs7_signed:
126 		cmsbio = cms_SignedData_init_bio(cms);
127 		break;
128 	case NID_pkcs7_digest:
129 		cmsbio = cms_DigestedData_init_bio(cms);
130 		break;
131 #ifdef ZLIB
132 	case NID_id_smime_ct_compressedData:
133 		cmsbio = cms_CompressedData_init_bio(cms);
134 		break;
135 #endif
136 	case NID_pkcs7_encrypted:
137 		cmsbio = cms_EncryptedData_init_bio(cms);
138 		break;
139 	case NID_pkcs7_enveloped:
140 		cmsbio = cms_EnvelopedData_init_bio(cms);
141 		break;
142 	default:
143 		CMSerr(CMS_F_CMS_DATAINIT, CMS_R_UNSUPPORTED_TYPE);
144 		return NULL;
145 	}
146 
147 	if (cmsbio)
148 		return BIO_push(cmsbio, cont);
149 
150 	if (!icont)
151 		BIO_free(cont);
152 	return NULL;
153 }
154 
155 int
156 CMS_dataFinal(CMS_ContentInfo *cms, BIO *cmsbio)
157 {
158 	ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
159 
160 	if (!pos)
161 		return 0;
162 	/* If ebmedded content find memory BIO and set content */
163 	if (*pos && ((*pos)->flags & ASN1_STRING_FLAG_CONT)) {
164 		BIO *mbio;
165 		unsigned char *cont;
166 		long contlen;
167 		mbio = BIO_find_type(cmsbio, BIO_TYPE_MEM);
168 		if (!mbio) {
169 			CMSerr(CMS_F_CMS_DATAFINAL, CMS_R_CONTENT_NOT_FOUND);
170 			return 0;
171 		}
172 		contlen = BIO_get_mem_data(mbio, &cont);
173 		/* Set bio as read only so its content can't be clobbered */
174 		BIO_set_flags(mbio, BIO_FLAGS_MEM_RDONLY);
175 		BIO_set_mem_eof_return(mbio, 0);
176 		ASN1_STRING_set0(*pos, cont, contlen);
177 		(*pos)->flags &= ~ASN1_STRING_FLAG_CONT;
178 	}
179 
180 	switch (OBJ_obj2nid(cms->contentType)) {
181 	case NID_pkcs7_data:
182 	case NID_pkcs7_enveloped:
183 	case NID_pkcs7_encrypted:
184 	case NID_id_smime_ct_compressedData:
185 		/* Nothing to do */
186 		return 1;
187 	case NID_pkcs7_signed:
188 		return cms_SignedData_final(cms, cmsbio);
189 	case NID_pkcs7_digest:
190 		return cms_DigestedData_do_final(cms, cmsbio, 0);
191 	default:
192 		CMSerr(CMS_F_CMS_DATAFINAL, CMS_R_UNSUPPORTED_TYPE);
193 		return 0;
194 	}
195 }
196 
197 /* Return an OCTET STRING pointer to content. This allows it to
198  * be accessed or set later.
199  */
200 
201 ASN1_OCTET_STRING **CMS_get0_content(CMS_ContentInfo *cms)
202 {
203 	switch (OBJ_obj2nid(cms->contentType)) {
204 	case NID_pkcs7_data:
205 		return &cms->d.data;
206 	case NID_pkcs7_signed:
207 		return &cms->d.signedData->encapContentInfo->eContent;
208 	case NID_pkcs7_enveloped:
209 		return &cms->d.envelopedData->encryptedContentInfo->encryptedContent;
210 	case NID_pkcs7_digest:
211 		return &cms->d.digestedData->encapContentInfo->eContent;
212 	case NID_pkcs7_encrypted:
213 		return &cms->d.encryptedData->encryptedContentInfo->encryptedContent;
214 	case NID_id_smime_ct_authData:
215 		return &cms->d.authenticatedData->encapContentInfo->eContent;
216 	case NID_id_smime_ct_compressedData:
217 		return &cms->d.compressedData->encapContentInfo->eContent;
218 	default:
219 		if (cms->d.other->type == V_ASN1_OCTET_STRING)
220 			return &cms->d.other->value.octet_string;
221 		CMSerr(CMS_F_CMS_GET0_CONTENT, CMS_R_UNSUPPORTED_CONTENT_TYPE);
222 		return NULL;
223 	}
224 }
225 
226 /* Return an ASN1_OBJECT pointer to content type. This allows it to
227  * be accessed or set later.
228  */
229 
230 static ASN1_OBJECT **cms_get0_econtent_type(CMS_ContentInfo *cms)
231 {
232 	switch (OBJ_obj2nid(cms->contentType)) {
233 	case NID_pkcs7_signed:
234 		return &cms->d.signedData->encapContentInfo->eContentType;
235 	case NID_pkcs7_enveloped:
236 		return &cms->d.envelopedData->encryptedContentInfo->contentType;
237 	case NID_pkcs7_digest:
238 		return &cms->d.digestedData->encapContentInfo->eContentType;
239 	case NID_pkcs7_encrypted:
240 		return &cms->d.encryptedData->encryptedContentInfo->contentType;
241 	case NID_id_smime_ct_authData:
242 		return &cms->d.authenticatedData->encapContentInfo->eContentType;
243 	case NID_id_smime_ct_compressedData:
244 		return &cms->d.compressedData->encapContentInfo->eContentType;
245 	default:
246 		CMSerr(CMS_F_CMS_GET0_ECONTENT_TYPE,
247 		    CMS_R_UNSUPPORTED_CONTENT_TYPE);
248 		return NULL;
249 	}
250 }
251 
252 const ASN1_OBJECT *
253 CMS_get0_eContentType(CMS_ContentInfo *cms)
254 {
255 	ASN1_OBJECT **petype;
256 
257 	petype = cms_get0_econtent_type(cms);
258 	if (petype)
259 		return *petype;
260 	return NULL;
261 }
262 
263 int
264 CMS_set1_eContentType(CMS_ContentInfo *cms, const ASN1_OBJECT *oid)
265 {
266 	ASN1_OBJECT **petype, *etype;
267 
268 	petype = cms_get0_econtent_type(cms);
269 	if (!petype)
270 		return 0;
271 	if (!oid)
272 		return 1;
273 	etype = OBJ_dup(oid);
274 	if (!etype)
275 		return 0;
276 	ASN1_OBJECT_free(*petype);
277 	*petype = etype;
278 	return 1;
279 }
280 
281 int
282 CMS_is_detached(CMS_ContentInfo *cms)
283 {
284 	ASN1_OCTET_STRING **pos;
285 
286 	pos = CMS_get0_content(cms);
287 	if (!pos)
288 		return -1;
289 	if (*pos)
290 		return 0;
291 	return 1;
292 }
293 
294 int
295 CMS_set_detached(CMS_ContentInfo *cms, int detached)
296 {
297 	ASN1_OCTET_STRING **pos;
298 
299 	pos = CMS_get0_content(cms);
300 	if (!pos)
301 		return 0;
302 	if (detached) {
303 		if (*pos) {
304 			ASN1_OCTET_STRING_free(*pos);
305 			*pos = NULL;
306 		}
307 		return 1;
308 	}
309 	if (!*pos)
310 		*pos = ASN1_OCTET_STRING_new();
311 	if (*pos) {
312 		/* NB: special flag to show content is created and not
313 		 * read in.
314 		 */
315 		(*pos)->flags |= ASN1_STRING_FLAG_CONT;
316 		return 1;
317 	}
318 	CMSerr(CMS_F_CMS_SET_DETACHED, ERR_R_MALLOC_FAILURE);
319 	return 0;
320 }
321 
322 /* Set up an X509_ALGOR DigestAlgorithmIdentifier from an EVP_MD */
323 
324 void
325 cms_DigestAlgorithm_set(X509_ALGOR *alg, const EVP_MD *md)
326 {
327 	int param_type;
328 
329 	if (md->flags & EVP_MD_FLAG_DIGALGID_ABSENT)
330 		param_type = V_ASN1_UNDEF;
331 	else
332 		param_type = V_ASN1_NULL;
333 
334 	X509_ALGOR_set0(alg, OBJ_nid2obj(EVP_MD_type(md)), param_type, NULL);
335 
336 }
337 
338 /* Create a digest BIO from an X509_ALGOR structure */
339 
340 BIO *
341 cms_DigestAlgorithm_init_bio(X509_ALGOR *digestAlgorithm)
342 {
343 	BIO *mdbio = NULL;
344 	ASN1_OBJECT *digestoid;
345 	const EVP_MD *digest;
346 
347 	X509_ALGOR_get0(&digestoid, NULL, NULL, digestAlgorithm);
348 	digest = EVP_get_digestbyobj(digestoid);
349 	if (!digest) {
350 		CMSerr(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO,
351 		    CMS_R_UNKNOWN_DIGEST_ALGORIHM);
352 		goto err;
353 	}
354 	mdbio = BIO_new(BIO_f_md());
355 	if (!mdbio || !BIO_set_md(mdbio, digest)) {
356 		CMSerr(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO,
357 		    CMS_R_MD_BIO_INIT_ERROR);
358 		goto err;
359 	}
360 	return mdbio;
361 
362 err:
363 	BIO_free(mdbio);
364 	return NULL;
365 }
366 
367 /* Locate a message digest content from a BIO chain based on SignerInfo */
368 
369 int
370 cms_DigestAlgorithm_find_ctx(EVP_MD_CTX *mctx, BIO *chain, X509_ALGOR *mdalg)
371 {
372 	int nid;
373 	ASN1_OBJECT *mdoid;
374 
375 	X509_ALGOR_get0(&mdoid, NULL, NULL, mdalg);
376 	nid = OBJ_obj2nid(mdoid);
377 
378 	/* Look for digest type to match signature */
379 	for (;;) {
380 		EVP_MD_CTX *mtmp;
381 		chain = BIO_find_type(chain, BIO_TYPE_MD);
382 		if (chain == NULL) {
383 			CMSerr(CMS_F_CMS_DIGESTALGORITHM_FIND_CTX,
384 			    CMS_R_NO_MATCHING_DIGEST);
385 			return 0;
386 		}
387 		BIO_get_md_ctx(chain, &mtmp);
388 		if (EVP_MD_CTX_type(mtmp) == nid
389 		/* Workaround for broken implementations that use signature
390 		 * algorithm  OID instead of digest.
391 		 */ ||
392 		    EVP_MD_pkey_type(EVP_MD_CTX_md(mtmp)) == nid)
393 			return EVP_MD_CTX_copy_ex(mctx, mtmp);
394 		chain = BIO_next(chain);
395 	}
396 }
397 
398 static STACK_OF(CMS_CertificateChoices) **
399 cms_get0_certificate_choices(CMS_ContentInfo *cms)
400 {
401 	switch (OBJ_obj2nid(cms->contentType)) {
402 	case NID_pkcs7_signed:
403 		return &cms->d.signedData->certificates;
404 	case NID_pkcs7_enveloped:
405 		return &cms->d.envelopedData->originatorInfo->certificates;
406 	default:
407 		CMSerr(CMS_F_CMS_GET0_CERTIFICATE_CHOICES,
408 		    CMS_R_UNSUPPORTED_CONTENT_TYPE);
409 		return NULL;
410 	}
411 }
412 
413 CMS_CertificateChoices *
414 CMS_add0_CertificateChoices(CMS_ContentInfo *cms)
415 {
416 	STACK_OF(CMS_CertificateChoices) **pcerts;
417 	CMS_CertificateChoices *cch;
418 
419 	pcerts = cms_get0_certificate_choices(cms);
420 	if (!pcerts)
421 		return NULL;
422 	if (!*pcerts)
423 		*pcerts = sk_CMS_CertificateChoices_new_null();
424 	if (!*pcerts)
425 		return NULL;
426 	cch = M_ASN1_new_of(CMS_CertificateChoices);
427 	if (!cch)
428 		return NULL;
429 	if (!sk_CMS_CertificateChoices_push(*pcerts, cch)) {
430 		M_ASN1_free_of(cch, CMS_CertificateChoices);
431 		return NULL;
432 	}
433 	return cch;
434 }
435 
436 int
437 CMS_add0_cert(CMS_ContentInfo *cms, X509 *cert)
438 {
439 	CMS_CertificateChoices *cch;
440 	STACK_OF(CMS_CertificateChoices) **pcerts;
441 	int i;
442 
443 	pcerts = cms_get0_certificate_choices(cms);
444 	if (!pcerts)
445 		return 0;
446 	for (i = 0; i < sk_CMS_CertificateChoices_num(*pcerts); i++) {
447 		cch = sk_CMS_CertificateChoices_value(*pcerts, i);
448 		if (cch->type == CMS_CERTCHOICE_CERT) {
449 			if (!X509_cmp(cch->d.certificate, cert)) {
450 				CMSerr(CMS_F_CMS_ADD0_CERT,
451 				    CMS_R_CERTIFICATE_ALREADY_PRESENT);
452 				return 0;
453 			}
454 		}
455 	}
456 	cch = CMS_add0_CertificateChoices(cms);
457 	if (!cch)
458 		return 0;
459 	cch->type = CMS_CERTCHOICE_CERT;
460 	cch->d.certificate = cert;
461 	return 1;
462 }
463 
464 int
465 CMS_add1_cert(CMS_ContentInfo *cms, X509 *cert)
466 {
467 	int r;
468 
469 	r = CMS_add0_cert(cms, cert);
470 	if (r > 0)
471 		CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509);
472 	return r;
473 }
474 
475 static STACK_OF(CMS_RevocationInfoChoice) **
476 cms_get0_revocation_choices(CMS_ContentInfo *cms)
477 {
478 	switch (OBJ_obj2nid(cms->contentType)) {
479 	case NID_pkcs7_signed:
480 		return &cms->d.signedData->crls;
481 	case NID_pkcs7_enveloped:
482 		return &cms->d.envelopedData->originatorInfo->crls;
483 	default:
484 		CMSerr(CMS_F_CMS_GET0_REVOCATION_CHOICES,
485 		    CMS_R_UNSUPPORTED_CONTENT_TYPE);
486 		return NULL;
487 	}
488 }
489 
490 CMS_RevocationInfoChoice *
491 CMS_add0_RevocationInfoChoice(CMS_ContentInfo *cms)
492 {
493 	STACK_OF(CMS_RevocationInfoChoice) **pcrls;
494 	CMS_RevocationInfoChoice *rch;
495 
496 	pcrls = cms_get0_revocation_choices(cms);
497 	if (!pcrls)
498 		return NULL;
499 	if (!*pcrls)
500 		*pcrls = sk_CMS_RevocationInfoChoice_new_null();
501 	if (!*pcrls)
502 		return NULL;
503 	rch = M_ASN1_new_of(CMS_RevocationInfoChoice);
504 	if (!rch)
505 		return NULL;
506 	if (!sk_CMS_RevocationInfoChoice_push(*pcrls, rch)) {
507 		M_ASN1_free_of(rch, CMS_RevocationInfoChoice);
508 		return NULL;
509 	}
510 	return rch;
511 }
512 
513 int
514 CMS_add0_crl(CMS_ContentInfo *cms, X509_CRL *crl)
515 {
516 	CMS_RevocationInfoChoice *rch;
517 
518 	rch = CMS_add0_RevocationInfoChoice(cms);
519 	if (!rch)
520 		return 0;
521 	rch->type = CMS_REVCHOICE_CRL;
522 	rch->d.crl = crl;
523 	return 1;
524 }
525 
526 int
527 CMS_add1_crl(CMS_ContentInfo *cms, X509_CRL *crl)
528 {
529 	int r;
530 
531 	r = CMS_add0_crl(cms, crl);
532 	if (r > 0)
533 		CRYPTO_add(&crl->references, 1, CRYPTO_LOCK_X509_CRL);
534 	return r;
535 }
536 
537 STACK_OF(X509) *CMS_get1_certs(CMS_ContentInfo *cms)
538 {
539 	STACK_OF(X509) *certs = NULL;
540 	CMS_CertificateChoices *cch;
541 	STACK_OF(CMS_CertificateChoices) **pcerts;
542 	int i;
543 
544 	pcerts = cms_get0_certificate_choices(cms);
545 	if (!pcerts)
546 		return NULL;
547 	for (i = 0; i < sk_CMS_CertificateChoices_num(*pcerts); i++) {
548 		cch = sk_CMS_CertificateChoices_value(*pcerts, i);
549 		if (cch->type == 0) {
550 			if (!certs) {
551 				certs = sk_X509_new_null();
552 				if (!certs)
553 					return NULL;
554 			}
555 			if (!sk_X509_push(certs, cch->d.certificate)) {
556 				sk_X509_pop_free(certs, X509_free);
557 				return NULL;
558 			}
559 			CRYPTO_add(&cch->d.certificate->references,
560 			    1, CRYPTO_LOCK_X509);
561 		}
562 	}
563 	return certs;
564 
565 }
566 
567 STACK_OF(X509_CRL) *CMS_get1_crls(CMS_ContentInfo *cms)
568 {
569 	STACK_OF(X509_CRL) *crls = NULL;
570 	STACK_OF(CMS_RevocationInfoChoice) **pcrls;
571 	CMS_RevocationInfoChoice *rch;
572 	int i;
573 
574 	pcrls = cms_get0_revocation_choices(cms);
575 	if (!pcrls)
576 		return NULL;
577 	for (i = 0; i < sk_CMS_RevocationInfoChoice_num(*pcrls); i++) {
578 		rch = sk_CMS_RevocationInfoChoice_value(*pcrls, i);
579 		if (rch->type == 0) {
580 			if (!crls) {
581 				crls = sk_X509_CRL_new_null();
582 				if (!crls)
583 					return NULL;
584 			}
585 			if (!sk_X509_CRL_push(crls, rch->d.crl)) {
586 				sk_X509_CRL_pop_free(crls, X509_CRL_free);
587 				return NULL;
588 			}
589 			CRYPTO_add(&rch->d.crl->references,
590 			    1, CRYPTO_LOCK_X509_CRL);
591 		}
592 	}
593 	return crls;
594 }
595