summaryrefslogtreecommitdiff
path: root/src/lib/libcrypto/cms/cms_lib.c
diff options
context:
space:
mode:
authorjsing <>2019-08-10 15:55:20 +0000
committerjsing <>2019-08-10 15:55:20 +0000
commita0845ead6d459f388701fe3fe8fa27635f4885f1 (patch)
treecfa2d4e7280cbfe7b7007556c8dcab6691e87b83 /src/lib/libcrypto/cms/cms_lib.c
parent38e170324f2dafb68786e79022ddafab241aad3d (diff)
downloadopenbsd-a0845ead6d459f388701fe3fe8fa27635f4885f1.tar.gz
openbsd-a0845ead6d459f388701fe3fe8fa27635f4885f1.tar.bz2
openbsd-a0845ead6d459f388701fe3fe8fa27635f4885f1.zip
Work towards supporting Cryptographic Message Syntax (CMS) in libcrypto.
Cryptographic Message Syntax (CMS) is a standard for cryptographically protecting messages, as defined in RFC 5652. It is derived from PKCS #7 version 1.5 and utilises various ASN.1 structures, making it complex and fairly heavyweight. Various protocols - including RPKI (RFC 6480) - have been built on top of it, which means it is necessary to support CMS, in order to support RPKI. This imports around 6,000 lines of code from OpenSSL 1.1.1, which is still under the original OpenSSL license. Further work will occur in tree. Requested by and discussed with many. ok deraadt@ tb@
Diffstat (limited to 'src/lib/libcrypto/cms/cms_lib.c')
-rw-r--r--src/lib/libcrypto/cms/cms_lib.c587
1 files changed, 587 insertions, 0 deletions
diff --git a/src/lib/libcrypto/cms/cms_lib.c b/src/lib/libcrypto/cms/cms_lib.c
new file mode 100644
index 0000000000..c2cac26010
--- /dev/null
+++ b/src/lib/libcrypto/cms/cms_lib.c
@@ -0,0 +1,587 @@
1/*
2 * Copyright 2008-2016 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the OpenSSL license (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10#include <openssl/asn1t.h>
11#include <openssl/x509v3.h>
12#include <openssl/err.h>
13#include <openssl/pem.h>
14#include <openssl/bio.h>
15#include <openssl/asn1.h>
16#include <openssl/cms.h>
17#include "cms_lcl.h"
18
19IMPLEMENT_ASN1_FUNCTIONS(CMS_ContentInfo)
20IMPLEMENT_ASN1_PRINT_FUNCTION(CMS_ContentInfo)
21
22const ASN1_OBJECT *CMS_get0_type(const CMS_ContentInfo *cms)
23{
24 return cms->contentType;
25}
26
27CMS_ContentInfo *cms_Data_create(void)
28{
29 CMS_ContentInfo *cms;
30 cms = CMS_ContentInfo_new();
31 if (cms != NULL) {
32 cms->contentType = OBJ_nid2obj(NID_pkcs7_data);
33 /* Never detached */
34 CMS_set_detached(cms, 0);
35 }
36 return cms;
37}
38
39BIO *cms_content_bio(CMS_ContentInfo *cms)
40{
41 ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
42 if (!pos)
43 return NULL;
44 /* If content detached data goes nowhere: create NULL BIO */
45 if (!*pos)
46 return BIO_new(BIO_s_null());
47 /*
48 * If content not detached and created return memory BIO
49 */
50 if (!*pos || ((*pos)->flags == ASN1_STRING_FLAG_CONT))
51 return BIO_new(BIO_s_mem());
52 /* Else content was read in: return read only BIO for it */
53 return BIO_new_mem_buf((*pos)->data, (*pos)->length);
54}
55
56BIO *CMS_dataInit(CMS_ContentInfo *cms, BIO *icont)
57{
58 BIO *cmsbio, *cont;
59 if (icont)
60 cont = icont;
61 else
62 cont = cms_content_bio(cms);
63 if (!cont) {
64 CMSerr(CMS_F_CMS_DATAINIT, CMS_R_NO_CONTENT);
65 return NULL;
66 }
67 switch (OBJ_obj2nid(cms->contentType)) {
68
69 case NID_pkcs7_data:
70 return cont;
71
72 case NID_pkcs7_signed:
73 cmsbio = cms_SignedData_init_bio(cms);
74 break;
75
76 case NID_pkcs7_digest:
77 cmsbio = cms_DigestedData_init_bio(cms);
78 break;
79#ifdef ZLIB
80 case NID_id_smime_ct_compressedData:
81 cmsbio = cms_CompressedData_init_bio(cms);
82 break;
83#endif
84
85 case NID_pkcs7_encrypted:
86 cmsbio = cms_EncryptedData_init_bio(cms);
87 break;
88
89 case NID_pkcs7_enveloped:
90 cmsbio = cms_EnvelopedData_init_bio(cms);
91 break;
92
93 default:
94 CMSerr(CMS_F_CMS_DATAINIT, CMS_R_UNSUPPORTED_TYPE);
95 return NULL;
96 }
97
98 if (cmsbio)
99 return BIO_push(cmsbio, cont);
100
101 if (!icont)
102 BIO_free(cont);
103 return NULL;
104
105}
106
107int CMS_dataFinal(CMS_ContentInfo *cms, BIO *cmsbio)
108{
109 ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
110 if (!pos)
111 return 0;
112 /* If embedded content find memory BIO and set content */
113 if (*pos && ((*pos)->flags & ASN1_STRING_FLAG_CONT)) {
114 BIO *mbio;
115 unsigned char *cont;
116 long contlen;
117 mbio = BIO_find_type(cmsbio, BIO_TYPE_MEM);
118 if (!mbio) {
119 CMSerr(CMS_F_CMS_DATAFINAL, CMS_R_CONTENT_NOT_FOUND);
120 return 0;
121 }
122 contlen = BIO_get_mem_data(mbio, &cont);
123 /* Set bio as read only so its content can't be clobbered */
124 BIO_set_flags(mbio, BIO_FLAGS_MEM_RDONLY);
125 BIO_set_mem_eof_return(mbio, 0);
126 ASN1_STRING_set0(*pos, cont, contlen);
127 (*pos)->flags &= ~ASN1_STRING_FLAG_CONT;
128 }
129
130 switch (OBJ_obj2nid(cms->contentType)) {
131
132 case NID_pkcs7_data:
133 case NID_pkcs7_enveloped:
134 case NID_pkcs7_encrypted:
135 case NID_id_smime_ct_compressedData:
136 /* Nothing to do */
137 return 1;
138
139 case NID_pkcs7_signed:
140 return cms_SignedData_final(cms, cmsbio);
141
142 case NID_pkcs7_digest:
143 return cms_DigestedData_do_final(cms, cmsbio, 0);
144
145 default:
146 CMSerr(CMS_F_CMS_DATAFINAL, CMS_R_UNSUPPORTED_TYPE);
147 return 0;
148 }
149}
150
151/*
152 * Return an OCTET STRING pointer to content. This allows it to be accessed
153 * or set later.
154 */
155
156ASN1_OCTET_STRING **CMS_get0_content(CMS_ContentInfo *cms)
157{
158 switch (OBJ_obj2nid(cms->contentType)) {
159
160 case NID_pkcs7_data:
161 return &cms->d.data;
162
163 case NID_pkcs7_signed:
164 return &cms->d.signedData->encapContentInfo->eContent;
165
166 case NID_pkcs7_enveloped:
167 return &cms->d.envelopedData->encryptedContentInfo->encryptedContent;
168
169 case NID_pkcs7_digest:
170 return &cms->d.digestedData->encapContentInfo->eContent;
171
172 case NID_pkcs7_encrypted:
173 return &cms->d.encryptedData->encryptedContentInfo->encryptedContent;
174
175 case NID_id_smime_ct_authData:
176 return &cms->d.authenticatedData->encapContentInfo->eContent;
177
178 case NID_id_smime_ct_compressedData:
179 return &cms->d.compressedData->encapContentInfo->eContent;
180
181 default:
182 if (cms->d.other->type == V_ASN1_OCTET_STRING)
183 return &cms->d.other->value.octet_string;
184 CMSerr(CMS_F_CMS_GET0_CONTENT, CMS_R_UNSUPPORTED_CONTENT_TYPE);
185 return NULL;
186
187 }
188}
189
190/*
191 * Return an ASN1_OBJECT pointer to content type. This allows it to be
192 * accessed or set later.
193 */
194
195static ASN1_OBJECT **cms_get0_econtent_type(CMS_ContentInfo *cms)
196{
197 switch (OBJ_obj2nid(cms->contentType)) {
198
199 case NID_pkcs7_signed:
200 return &cms->d.signedData->encapContentInfo->eContentType;
201
202 case NID_pkcs7_enveloped:
203 return &cms->d.envelopedData->encryptedContentInfo->contentType;
204
205 case NID_pkcs7_digest:
206 return &cms->d.digestedData->encapContentInfo->eContentType;
207
208 case NID_pkcs7_encrypted:
209 return &cms->d.encryptedData->encryptedContentInfo->contentType;
210
211 case NID_id_smime_ct_authData:
212 return &cms->d.authenticatedData->encapContentInfo->eContentType;
213
214 case NID_id_smime_ct_compressedData:
215 return &cms->d.compressedData->encapContentInfo->eContentType;
216
217 default:
218 CMSerr(CMS_F_CMS_GET0_ECONTENT_TYPE, CMS_R_UNSUPPORTED_CONTENT_TYPE);
219 return NULL;
220
221 }
222}
223
224const ASN1_OBJECT *CMS_get0_eContentType(CMS_ContentInfo *cms)
225{
226 ASN1_OBJECT **petype;
227 petype = cms_get0_econtent_type(cms);
228 if (petype)
229 return *petype;
230 return NULL;
231}
232
233int CMS_set1_eContentType(CMS_ContentInfo *cms, const ASN1_OBJECT *oid)
234{
235 ASN1_OBJECT **petype, *etype;
236 petype = cms_get0_econtent_type(cms);
237 if (!petype)
238 return 0;
239 if (!oid)
240 return 1;
241 etype = OBJ_dup(oid);
242 if (!etype)
243 return 0;
244 ASN1_OBJECT_free(*petype);
245 *petype = etype;
246 return 1;
247}
248
249int CMS_is_detached(CMS_ContentInfo *cms)
250{
251 ASN1_OCTET_STRING **pos;
252 pos = CMS_get0_content(cms);
253 if (!pos)
254 return -1;
255 if (*pos)
256 return 0;
257 return 1;
258}
259
260int CMS_set_detached(CMS_ContentInfo *cms, int detached)
261{
262 ASN1_OCTET_STRING **pos;
263 pos = CMS_get0_content(cms);
264 if (!pos)
265 return 0;
266 if (detached) {
267 ASN1_OCTET_STRING_free(*pos);
268 *pos = NULL;
269 return 1;
270 }
271 if (*pos == NULL)
272 *pos = ASN1_OCTET_STRING_new();
273 if (*pos != NULL) {
274 /*
275 * NB: special flag to show content is created and not read in.
276 */
277 (*pos)->flags |= ASN1_STRING_FLAG_CONT;
278 return 1;
279 }
280 CMSerr(CMS_F_CMS_SET_DETACHED, ERR_R_MALLOC_FAILURE);
281 return 0;
282}
283
284/* Create a digest BIO from an X509_ALGOR structure */
285
286BIO *cms_DigestAlgorithm_init_bio(X509_ALGOR *digestAlgorithm)
287{
288 BIO *mdbio = NULL;
289 const ASN1_OBJECT *digestoid;
290 const EVP_MD *digest;
291 X509_ALGOR_get0(&digestoid, NULL, NULL, digestAlgorithm);
292 digest = EVP_get_digestbyobj(digestoid);
293 if (!digest) {
294 CMSerr(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO,
295 CMS_R_UNKNOWN_DIGEST_ALGORITHM);
296 goto err;
297 }
298 mdbio = BIO_new(BIO_f_md());
299 if (mdbio == NULL || !BIO_set_md(mdbio, digest)) {
300 CMSerr(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO, CMS_R_MD_BIO_INIT_ERROR);
301 goto err;
302 }
303 return mdbio;
304 err:
305 BIO_free(mdbio);
306 return NULL;
307}
308
309/* Locate a message digest content from a BIO chain based on SignerInfo */
310
311int cms_DigestAlgorithm_find_ctx(EVP_MD_CTX *mctx, BIO *chain,
312 X509_ALGOR *mdalg)
313{
314 int nid;
315 const ASN1_OBJECT *mdoid;
316 X509_ALGOR_get0(&mdoid, NULL, NULL, mdalg);
317 nid = OBJ_obj2nid(mdoid);
318 /* Look for digest type to match signature */
319 for (;;) {
320 EVP_MD_CTX *mtmp;
321 chain = BIO_find_type(chain, BIO_TYPE_MD);
322 if (chain == NULL) {
323 CMSerr(CMS_F_CMS_DIGESTALGORITHM_FIND_CTX,
324 CMS_R_NO_MATCHING_DIGEST);
325 return 0;
326 }
327 BIO_get_md_ctx(chain, &mtmp);
328 if (EVP_MD_CTX_type(mtmp) == nid
329 /*
330 * Workaround for broken implementations that use signature
331 * algorithm OID instead of digest.
332 */
333 || EVP_MD_pkey_type(EVP_MD_CTX_md(mtmp)) == nid)
334 return EVP_MD_CTX_copy_ex(mctx, mtmp);
335 chain = BIO_next(chain);
336 }
337}
338
339static STACK_OF(CMS_CertificateChoices)
340**cms_get0_certificate_choices(CMS_ContentInfo *cms)
341{
342 switch (OBJ_obj2nid(cms->contentType)) {
343
344 case NID_pkcs7_signed:
345 return &cms->d.signedData->certificates;
346
347 case NID_pkcs7_enveloped:
348 if (cms->d.envelopedData->originatorInfo == NULL)
349 return NULL;
350 return &cms->d.envelopedData->originatorInfo->certificates;
351
352 default:
353 CMSerr(CMS_F_CMS_GET0_CERTIFICATE_CHOICES,
354 CMS_R_UNSUPPORTED_CONTENT_TYPE);
355 return NULL;
356
357 }
358}
359
360CMS_CertificateChoices *CMS_add0_CertificateChoices(CMS_ContentInfo *cms)
361{
362 STACK_OF(CMS_CertificateChoices) **pcerts;
363 CMS_CertificateChoices *cch;
364 pcerts = cms_get0_certificate_choices(cms);
365 if (!pcerts)
366 return NULL;
367 if (!*pcerts)
368 *pcerts = sk_CMS_CertificateChoices_new_null();
369 if (!*pcerts)
370 return NULL;
371 cch = M_ASN1_new_of(CMS_CertificateChoices);
372 if (!cch)
373 return NULL;
374 if (!sk_CMS_CertificateChoices_push(*pcerts, cch)) {
375 M_ASN1_free_of(cch, CMS_CertificateChoices);
376 return NULL;
377 }
378 return cch;
379}
380
381int CMS_add0_cert(CMS_ContentInfo *cms, X509 *cert)
382{
383 CMS_CertificateChoices *cch;
384 STACK_OF(CMS_CertificateChoices) **pcerts;
385 int i;
386 pcerts = cms_get0_certificate_choices(cms);
387 if (!pcerts)
388 return 0;
389 for (i = 0; i < sk_CMS_CertificateChoices_num(*pcerts); i++) {
390 cch = sk_CMS_CertificateChoices_value(*pcerts, i);
391 if (cch->type == CMS_CERTCHOICE_CERT) {
392 if (!X509_cmp(cch->d.certificate, cert)) {
393 CMSerr(CMS_F_CMS_ADD0_CERT,
394 CMS_R_CERTIFICATE_ALREADY_PRESENT);
395 return 0;
396 }
397 }
398 }
399 cch = CMS_add0_CertificateChoices(cms);
400 if (!cch)
401 return 0;
402 cch->type = CMS_CERTCHOICE_CERT;
403 cch->d.certificate = cert;
404 return 1;
405}
406
407int CMS_add1_cert(CMS_ContentInfo *cms, X509 *cert)
408{
409 int r;
410 r = CMS_add0_cert(cms, cert);
411 if (r > 0)
412 X509_up_ref(cert);
413 return r;
414}
415
416static STACK_OF(CMS_RevocationInfoChoice)
417**cms_get0_revocation_choices(CMS_ContentInfo *cms)
418{
419 switch (OBJ_obj2nid(cms->contentType)) {
420
421 case NID_pkcs7_signed:
422 return &cms->d.signedData->crls;
423
424 case NID_pkcs7_enveloped:
425 if (cms->d.envelopedData->originatorInfo == NULL)
426 return NULL;
427 return &cms->d.envelopedData->originatorInfo->crls;
428
429 default:
430 CMSerr(CMS_F_CMS_GET0_REVOCATION_CHOICES,
431 CMS_R_UNSUPPORTED_CONTENT_TYPE);
432 return NULL;
433
434 }
435}
436
437CMS_RevocationInfoChoice *CMS_add0_RevocationInfoChoice(CMS_ContentInfo *cms)
438{
439 STACK_OF(CMS_RevocationInfoChoice) **pcrls;
440 CMS_RevocationInfoChoice *rch;
441 pcrls = cms_get0_revocation_choices(cms);
442 if (!pcrls)
443 return NULL;
444 if (!*pcrls)
445 *pcrls = sk_CMS_RevocationInfoChoice_new_null();
446 if (!*pcrls)
447 return NULL;
448 rch = M_ASN1_new_of(CMS_RevocationInfoChoice);
449 if (!rch)
450 return NULL;
451 if (!sk_CMS_RevocationInfoChoice_push(*pcrls, rch)) {
452 M_ASN1_free_of(rch, CMS_RevocationInfoChoice);
453 return NULL;
454 }
455 return rch;
456}
457
458int CMS_add0_crl(CMS_ContentInfo *cms, X509_CRL *crl)
459{
460 CMS_RevocationInfoChoice *rch;
461 rch = CMS_add0_RevocationInfoChoice(cms);
462 if (!rch)
463 return 0;
464 rch->type = CMS_REVCHOICE_CRL;
465 rch->d.crl = crl;
466 return 1;
467}
468
469int CMS_add1_crl(CMS_ContentInfo *cms, X509_CRL *crl)
470{
471 int r;
472 r = CMS_add0_crl(cms, crl);
473 if (r > 0)
474 X509_CRL_up_ref(crl);
475 return r;
476}
477
478STACK_OF(X509) *CMS_get1_certs(CMS_ContentInfo *cms)
479{
480 STACK_OF(X509) *certs = NULL;
481 CMS_CertificateChoices *cch;
482 STACK_OF(CMS_CertificateChoices) **pcerts;
483 int i;
484 pcerts = cms_get0_certificate_choices(cms);
485 if (!pcerts)
486 return NULL;
487 for (i = 0; i < sk_CMS_CertificateChoices_num(*pcerts); i++) {
488 cch = sk_CMS_CertificateChoices_value(*pcerts, i);
489 if (cch->type == 0) {
490 if (!certs) {
491 certs = sk_X509_new_null();
492 if (!certs)
493 return NULL;
494 }
495 if (!sk_X509_push(certs, cch->d.certificate)) {
496 sk_X509_pop_free(certs, X509_free);
497 return NULL;
498 }
499 X509_up_ref(cch->d.certificate);
500 }
501 }
502 return certs;
503
504}
505
506STACK_OF(X509_CRL) *CMS_get1_crls(CMS_ContentInfo *cms)
507{
508 STACK_OF(X509_CRL) *crls = NULL;
509 STACK_OF(CMS_RevocationInfoChoice) **pcrls;
510 CMS_RevocationInfoChoice *rch;
511 int i;
512 pcrls = cms_get0_revocation_choices(cms);
513 if (!pcrls)
514 return NULL;
515 for (i = 0; i < sk_CMS_RevocationInfoChoice_num(*pcrls); i++) {
516 rch = sk_CMS_RevocationInfoChoice_value(*pcrls, i);
517 if (rch->type == 0) {
518 if (!crls) {
519 crls = sk_X509_CRL_new_null();
520 if (!crls)
521 return NULL;
522 }
523 if (!sk_X509_CRL_push(crls, rch->d.crl)) {
524 sk_X509_CRL_pop_free(crls, X509_CRL_free);
525 return NULL;
526 }
527 X509_CRL_up_ref(rch->d.crl);
528 }
529 }
530 return crls;
531}
532
533int cms_ias_cert_cmp(CMS_IssuerAndSerialNumber *ias, X509 *cert)
534{
535 int ret;
536 ret = X509_NAME_cmp(ias->issuer, X509_get_issuer_name(cert));
537 if (ret)
538 return ret;
539 return ASN1_INTEGER_cmp(ias->serialNumber, X509_get_serialNumber(cert));
540}
541
542int cms_keyid_cert_cmp(ASN1_OCTET_STRING *keyid, X509 *cert)
543{
544 const ASN1_OCTET_STRING *cert_keyid = X509_get0_subject_key_id(cert);
545
546 if (cert_keyid == NULL)
547 return -1;
548 return ASN1_OCTET_STRING_cmp(keyid, cert_keyid);
549}
550
551int cms_set1_ias(CMS_IssuerAndSerialNumber **pias, X509 *cert)
552{
553 CMS_IssuerAndSerialNumber *ias;
554 ias = M_ASN1_new_of(CMS_IssuerAndSerialNumber);
555 if (!ias)
556 goto err;
557 if (!X509_NAME_set(&ias->issuer, X509_get_issuer_name(cert)))
558 goto err;
559 if (!ASN1_STRING_copy(ias->serialNumber, X509_get_serialNumber(cert)))
560 goto err;
561 M_ASN1_free_of(*pias, CMS_IssuerAndSerialNumber);
562 *pias = ias;
563 return 1;
564 err:
565 M_ASN1_free_of(ias, CMS_IssuerAndSerialNumber);
566 CMSerr(CMS_F_CMS_SET1_IAS, ERR_R_MALLOC_FAILURE);
567 return 0;
568}
569
570int cms_set1_keyid(ASN1_OCTET_STRING **pkeyid, X509 *cert)
571{
572 ASN1_OCTET_STRING *keyid = NULL;
573 const ASN1_OCTET_STRING *cert_keyid;
574 cert_keyid = X509_get0_subject_key_id(cert);
575 if (cert_keyid == NULL) {
576 CMSerr(CMS_F_CMS_SET1_KEYID, CMS_R_CERTIFICATE_HAS_NO_KEYID);
577 return 0;
578 }
579 keyid = ASN1_STRING_dup(cert_keyid);
580 if (!keyid) {
581 CMSerr(CMS_F_CMS_SET1_KEYID, ERR_R_MALLOC_FAILURE);
582 return 0;
583 }
584 ASN1_OCTET_STRING_free(*pkeyid);
585 *pkeyid = keyid;
586 return 1;
587}