]> git.ipfire.org Git - people/ms/strongswan.git/blob - src/libstrongswan/plugins/openssl/openssl_pkcs7.c
Fixed some typos, courtesy of codespell
[people/ms/strongswan.git] / src / libstrongswan / plugins / openssl / openssl_pkcs7.c
1 /*
2 * Copyright (C) 2012 Martin Willi
3 * Copyright (C) 2012 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include <openssl/opensslv.h>
17 #include <openssl/opensslconf.h>
18
19 #if OPENSSL_VERSION_NUMBER >= 0x0090807fL
20 #ifndef OPENSSL_NO_CMS
21
22 #include "openssl_pkcs7.h"
23 #include "openssl_util.h"
24
25 #include <library.h>
26 #include <utils/debug.h>
27 #include <asn1/oid.h>
28 #include <credentials/sets/mem_cred.h>
29
30 #include <openssl/cms.h>
31
32 #if OPENSSL_VERSION_NUMBER < 0x10100000L
33 #define X509_ATTRIBUTE_get0_object(attr) ({ (attr)->object; })
34 #endif
35
36 typedef struct private_openssl_pkcs7_t private_openssl_pkcs7_t;
37
38 /**
39 * Private data of an openssl_pkcs7_t object.
40 */
41 struct private_openssl_pkcs7_t {
42
43 /**
44 * Public pkcs7_t interface.
45 */
46 pkcs7_t public;
47
48 /**
49 * Type of this container
50 */
51 container_type_t type;
52
53 /**
54 * OpenSSL CMS structure
55 */
56 CMS_ContentInfo *cms;
57 };
58
59 /**
60 * OpenSSL does not allow us to read the signature to verify it with our own
61 * crypto API. We define the internal CMS_SignerInfo structure here to get it.
62 */
63 struct CMS_SignerInfo_st {
64 long version;
65 void *sid;
66 X509_ALGOR *digestAlgorithm;
67 STACK_OF(X509_ATTRIBUTE) *signedAttrs;
68 X509_ALGOR *signatureAlgorithm;
69 ASN1_OCTET_STRING *signature;
70 /* and more... */
71 };
72
73 /**
74 * And we also need access to the wrappend CMS_KeyTransRecipientInfo to
75 * read the encrypted key
76 */
77 struct CMS_KeyTransRecipientInfo_st {
78 long version;
79 void *rid;
80 X509_ALGOR *keyEncryptionAlgorithm;
81 ASN1_OCTET_STRING *encryptedKey;
82 };
83
84 struct CMS_RecipientInfo_st {
85 int type;
86 struct CMS_KeyTransRecipientInfo_st *ktri;
87 /* and more in union... */
88 };
89
90 struct CMS_EncryptedContentInfo_st {
91 ASN1_OBJECT *contentType;
92 X509_ALGOR *contentEncryptionAlgorithm;
93 ASN1_OCTET_STRING *encryptedContent;
94 /* and more... */
95 };
96
97 struct CMS_EnvelopedData_st {
98 long version;
99 void *originatorInfo;
100 STACK_OF(CMS_RecipientInfo) *recipientInfos;
101 struct CMS_EncryptedContentInfo_st *encryptedContentInfo;
102 /* and more... */
103 };
104
105 struct CMS_ContentInfo_st {
106 ASN1_OBJECT *contentType;
107 struct CMS_EnvelopedData_st *envelopedData;
108 /* and more in union... */
109 };
110
111 /**
112 * We can't include asn1.h, declare function prototypes directly
113 */
114 chunk_t asn1_wrap(int, const char *mode, ...);
115 int asn1_unwrap(chunk_t*, chunk_t*);
116
117 /**
118 * Enumerator over certificates
119 */
120 typedef struct {
121 /** implements enumerator_t */
122 enumerator_t public;
123 /** Stack of X509 certificates */
124 STACK_OF(X509) *certs;
125 /** current enumerator position in certificates */
126 int i;
127 /** currently enumerating certificate_t */
128 certificate_t *cert;
129 } cert_enumerator_t;
130
131 METHOD(enumerator_t, cert_destroy, void,
132 cert_enumerator_t *this)
133 {
134 DESTROY_IF(this->cert);
135 free(this);
136 }
137
138 METHOD(enumerator_t, cert_enumerate, bool,
139 cert_enumerator_t *this, va_list args)
140 {
141 certificate_t **out;
142
143 VA_ARGS_VGET(args, out);
144
145 if (!this->certs)
146 {
147 return FALSE;
148 }
149 while (this->i < sk_X509_num(this->certs))
150 {
151 chunk_t encoding;
152 X509 *x509;
153
154 /* clean up previous round */
155 DESTROY_IF(this->cert);
156 this->cert = NULL;
157
158 x509 = sk_X509_value(this->certs, this->i++);
159 encoding = openssl_i2chunk(X509, x509);
160 this->cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
161 BUILD_BLOB_ASN1_DER, encoding,
162 BUILD_END);
163 free(encoding.ptr);
164 if (!this->cert)
165 {
166 continue;
167 }
168 *out = this->cert;
169 return TRUE;
170 }
171 return FALSE;
172 }
173
174 METHOD(pkcs7_t, create_cert_enumerator, enumerator_t*,
175 private_openssl_pkcs7_t *this)
176 {
177 cert_enumerator_t *enumerator;
178
179 if (this->type == CONTAINER_PKCS7_SIGNED_DATA)
180 {
181 INIT(enumerator,
182 .public = {
183 .enumerate = enumerator_enumerate_default,
184 .venumerate = _cert_enumerate,
185 .destroy = _cert_destroy,
186 },
187 .certs = CMS_get1_certs(this->cms),
188 );
189 return &enumerator->public;
190 }
191 return enumerator_create_empty();
192 }
193
194 /**
195 * Enumerator for signatures
196 */
197 typedef struct {
198 /** implements enumerator_t */
199 enumerator_t public;
200 /** Stack of signerinfos */
201 STACK_OF(CMS_SignerInfo) *signers;
202 /** current enumerator position in signers */
203 int i;
204 /** currently enumerating auth config */
205 auth_cfg_t *auth;
206 /** full CMS */
207 CMS_ContentInfo *cms;
208 /** credential set containing wrapped certificates */
209 mem_cred_t *creds;
210 } signature_enumerator_t;
211
212 /**
213 * Verify signerInfo signature
214 */
215 static auth_cfg_t *verify_signature(CMS_SignerInfo *si, int hash_oid)
216 {
217 enumerator_t *enumerator;
218 public_key_t *key;
219 certificate_t *cert;
220 auth_cfg_t *auth, *found = NULL;
221 identification_t *issuer, *serial;
222 chunk_t attrs = chunk_empty, sig, attr;
223 X509_NAME *name;
224 ASN1_INTEGER *snr;
225 int i;
226
227 if (CMS_SignerInfo_get0_signer_id(si, NULL, &name, &snr) != 1)
228 {
229 return NULL;
230 }
231 issuer = openssl_x509_name2id(name);
232 if (!issuer)
233 {
234 return NULL;
235 }
236 serial = identification_create_from_encoding(
237 ID_KEY_ID, openssl_asn1_str2chunk(snr));
238
239 /* reconstruct DER encoded attributes to verify signature */
240 for (i = 0; i < CMS_signed_get_attr_count(si); i++)
241 {
242 attr = openssl_i2chunk(X509_ATTRIBUTE, CMS_signed_get_attr(si, i));
243 attrs = chunk_cat("mm", attrs, attr);
244 }
245 /* wrap in a ASN1_SET */
246 attrs = asn1_wrap(0x31, "m", attrs);
247
248 /* TODO: find a better way to access and verify the signature */
249 sig = openssl_asn1_str2chunk(si->signature);
250 enumerator = lib->credmgr->create_trusted_enumerator(lib->credmgr,
251 KEY_RSA, serial, FALSE);
252 while (enumerator->enumerate(enumerator, &cert, &auth))
253 {
254 if (issuer->equals(issuer, cert->get_issuer(cert)))
255 {
256 key = cert->get_public_key(cert);
257 if (key)
258 {
259 if (key->verify(key, signature_scheme_from_oid(hash_oid), NULL,
260 attrs, sig))
261 {
262 found = auth->clone(auth);
263 key->destroy(key);
264 break;
265 }
266 key->destroy(key);
267 }
268 }
269 }
270 enumerator->destroy(enumerator);
271 issuer->destroy(issuer);
272 serial->destroy(serial);
273 free(attrs.ptr);
274
275 return found;
276 }
277
278 /**
279 * Verify the message digest in the signerInfo attributes
280 */
281 static bool verify_digest(CMS_ContentInfo *cms, CMS_SignerInfo *si, int hash_oid)
282 {
283 ASN1_OCTET_STRING *os, **osp;
284 hash_algorithm_t hash_alg;
285 chunk_t digest, content, hash;
286 hasher_t *hasher;
287
288 os = CMS_signed_get0_data_by_OBJ(si,
289 OBJ_nid2obj(NID_pkcs9_messageDigest), -3, V_ASN1_OCTET_STRING);
290 if (!os)
291 {
292 return FALSE;
293 }
294 digest = openssl_asn1_str2chunk(os);
295 osp = CMS_get0_content(cms);
296 if (!osp)
297 {
298 return FALSE;
299 }
300 content = openssl_asn1_str2chunk(*osp);
301
302 hash_alg = hasher_algorithm_from_oid(hash_oid);
303 hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
304 if (!hasher)
305 {
306 DBG1(DBG_LIB, "hash algorithm %N not supported",
307 hash_algorithm_names, hash_alg);
308 return FALSE;
309 }
310 if (!hasher->allocate_hash(hasher, content, &hash))
311 {
312 hasher->destroy(hasher);
313 return FALSE;
314 }
315 hasher->destroy(hasher);
316
317 if (!chunk_equals_const(digest, hash))
318 {
319 free(hash.ptr);
320 DBG1(DBG_LIB, "invalid messageDigest");
321 return FALSE;
322 }
323 free(hash.ptr);
324 return TRUE;
325 }
326
327 METHOD(enumerator_t, signature_enumerate, bool,
328 signature_enumerator_t *this, va_list args)
329 {
330 auth_cfg_t **out;
331
332 VA_ARGS_VGET(args, out);
333
334 if (!this->signers)
335 {
336 return FALSE;
337 }
338 while (this->i < sk_CMS_SignerInfo_num(this->signers))
339 {
340 CMS_SignerInfo *si;
341 X509_ALGOR *digest, *sig;
342 int hash_oid;
343
344 /* clean up previous round */
345 DESTROY_IF(this->auth);
346 this->auth = NULL;
347
348 si = sk_CMS_SignerInfo_value(this->signers, this->i++);
349
350 CMS_SignerInfo_get0_algs(si, NULL, NULL, &digest, &sig);
351 hash_oid = openssl_asn1_known_oid(digest->algorithm);
352 if (openssl_asn1_known_oid(sig->algorithm) != OID_RSA_ENCRYPTION)
353 {
354 DBG1(DBG_LIB, "only RSA digest encryption supported");
355 continue;
356 }
357 this->auth = verify_signature(si, hash_oid);
358 if (!this->auth)
359 {
360 DBG1(DBG_LIB, "unable to verify pkcs7 attributes signature");
361 continue;
362 }
363 if (!verify_digest(this->cms, si, hash_oid))
364 {
365 continue;
366 }
367 *out = this->auth;
368 return TRUE;
369 }
370 return FALSE;
371 }
372
373 METHOD(enumerator_t, signature_destroy, void,
374 signature_enumerator_t *this)
375 {
376 lib->credmgr->remove_local_set(lib->credmgr, &this->creds->set);
377 this->creds->destroy(this->creds);
378 DESTROY_IF(this->auth);
379 free(this);
380 }
381
382 METHOD(container_t, create_signature_enumerator, enumerator_t*,
383 private_openssl_pkcs7_t *this)
384 {
385 signature_enumerator_t *enumerator;
386
387 if (this->type == CONTAINER_PKCS7_SIGNED_DATA)
388 {
389 enumerator_t *certs;
390 certificate_t *cert;
391
392 INIT(enumerator,
393 .public = {
394 .enumerate = enumerator_enumerate_default,
395 .venumerate = _signature_enumerate,
396 .destroy = _signature_destroy,
397 },
398 .cms = this->cms,
399 .signers = CMS_get0_SignerInfos(this->cms),
400 .creds = mem_cred_create(),
401 );
402
403 /* make available wrapped certs during signature checking */
404 certs = create_cert_enumerator(this);
405 while (certs->enumerate(certs, &cert))
406 {
407 enumerator->creds->add_cert(enumerator->creds, FALSE,
408 cert->get_ref(cert));
409 }
410 certs->destroy(certs);
411
412 lib->credmgr->add_local_set(lib->credmgr, &enumerator->creds->set,
413 FALSE);
414
415 return &enumerator->public;
416 }
417 return enumerator_create_empty();
418 }
419
420
421 METHOD(container_t, get_type, container_type_t,
422 private_openssl_pkcs7_t *this)
423 {
424 return this->type;
425 }
426
427 METHOD(pkcs7_t, get_attribute, bool,
428 private_openssl_pkcs7_t *this, int oid,
429 enumerator_t *enumerator, chunk_t *value)
430 {
431 signature_enumerator_t *e;
432 CMS_SignerInfo *si;
433 X509_ATTRIBUTE *attr;
434 ASN1_TYPE *type;
435 chunk_t chunk, wrapped;
436 int i;
437
438 e = (signature_enumerator_t*)enumerator;
439 if (e->i <= 0)
440 {
441 return FALSE;
442 }
443
444 /* "i" gets incremented after enumerate(), hence read from previous */
445 si = sk_CMS_SignerInfo_value(e->signers, e->i - 1);
446 for (i = 0; i < CMS_signed_get_attr_count(si); i++)
447 {
448 attr = CMS_signed_get_attr(si, i);
449 if (X509_ATTRIBUTE_count(attr) == 1 &&
450 openssl_asn1_known_oid(X509_ATTRIBUTE_get0_object(attr)) == oid)
451 {
452 /* get first value in SET */
453 type = X509_ATTRIBUTE_get0_type(attr, 0);
454 chunk = wrapped = openssl_i2chunk(ASN1_TYPE, type);
455 if (asn1_unwrap(&chunk, &chunk) != 0x100 /* ASN1_INVALID */)
456 {
457 *value = chunk_clone(chunk);
458 free(wrapped.ptr);
459 return TRUE;
460 }
461 free(wrapped.ptr);
462 }
463 }
464 return FALSE;
465 }
466
467 /**
468 * Find a private key for issuerAndSerialNumber
469 */
470 static private_key_t *find_private(identification_t *issuer,
471 identification_t *serial)
472 {
473 enumerator_t *enumerator;
474 certificate_t *cert;
475 public_key_t *public;
476 private_key_t *private = NULL;
477 identification_t *id;
478 chunk_t fp;
479
480 enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
481 CERT_X509, KEY_RSA, serial, FALSE);
482 while (enumerator->enumerate(enumerator, &cert))
483 {
484 if (issuer->equals(issuer, cert->get_issuer(cert)))
485 {
486 public = cert->get_public_key(cert);
487 if (public)
488 {
489 if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &fp))
490 {
491 id = identification_create_from_encoding(ID_KEY_ID, fp);
492 private = lib->credmgr->get_private(lib->credmgr,
493 KEY_ANY, id, NULL);
494 id->destroy(id);
495 }
496 public->destroy(public);
497 }
498 }
499 if (private)
500 {
501 break;
502 }
503 }
504 enumerator->destroy(enumerator);
505 return private;
506 }
507
508 /**
509 * Decrypt enveloped-data with a decrypted symmetric key
510 */
511 static bool decrypt_symmetric(private_openssl_pkcs7_t *this, chunk_t key,
512 chunk_t encrypted, chunk_t *plain)
513 {
514 encryption_algorithm_t encr;
515 X509_ALGOR *alg;
516 crypter_t *crypter;
517 chunk_t iv;
518 size_t key_size;
519
520 /* read encryption algorithm from internal structures; TODO fixup */
521 alg = this->cms->envelopedData->encryptedContentInfo->
522 contentEncryptionAlgorithm;
523 encr = encryption_algorithm_from_oid(openssl_asn1_known_oid(alg->algorithm),
524 &key_size);
525 if (alg->parameter->type != V_ASN1_OCTET_STRING)
526 {
527 return FALSE;
528 }
529 iv = openssl_asn1_str2chunk(alg->parameter->value.octet_string);
530
531 crypter = lib->crypto->create_crypter(lib->crypto, encr, key_size / 8);
532 if (!crypter)
533 {
534 DBG1(DBG_LIB, "crypter %N-%d not available",
535 encryption_algorithm_names, alg, key_size);
536 return FALSE;
537 }
538 if (key.len != crypter->get_key_size(crypter))
539 {
540 DBG1(DBG_LIB, "symmetric key length is wrong");
541 crypter->destroy(crypter);
542 return FALSE;
543 }
544 if (iv.len != crypter->get_iv_size(crypter))
545 {
546 DBG1(DBG_LIB, "IV length is wrong");
547 crypter->destroy(crypter);
548 return FALSE;
549 }
550 if (!crypter->set_key(crypter, key) ||
551 !crypter->decrypt(crypter, encrypted, iv, plain))
552 {
553 crypter->destroy(crypter);
554 return FALSE;
555 }
556 crypter->destroy(crypter);
557 return TRUE;
558 }
559
560 /**
561 * Remove enveloped-data PKCS#7 padding from plain data
562 */
563 static bool remove_padding(chunk_t *data)
564 {
565 u_char *pos;
566 u_char pattern;
567 size_t padding;
568
569 if (!data->len)
570 {
571 return FALSE;
572 }
573 pos = data->ptr + data->len - 1;
574 padding = pattern = *pos;
575
576 if (padding > data->len)
577 {
578 DBG1(DBG_LIB, "padding greater than data length");
579 return FALSE;
580 }
581 data->len -= padding;
582
583 while (padding-- > 0)
584 {
585 if (*pos-- != pattern)
586 {
587 DBG1(DBG_LIB, "wrong padding pattern");
588 return FALSE;
589 }
590 }
591 return TRUE;
592 }
593
594 /**
595 * Decrypt PKCS#7 enveloped-data
596 */
597 static bool decrypt(private_openssl_pkcs7_t *this,
598 chunk_t encrypted, chunk_t *plain)
599 {
600 STACK_OF(CMS_RecipientInfo) *ris;
601 CMS_RecipientInfo *ri;
602 chunk_t chunk, key = chunk_empty;
603 int i;
604
605 ris = CMS_get0_RecipientInfos(this->cms);
606 for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++)
607 {
608 ri = sk_CMS_RecipientInfo_value(ris, i);
609 if (CMS_RecipientInfo_type(ri) == CMS_RECIPINFO_TRANS)
610 {
611 identification_t *serial, *issuer;
612 private_key_t *private;
613 X509_ALGOR *alg;
614 X509_NAME *name;
615 ASN1_INTEGER *sn;
616 u_char zero = 0;
617 int oid;
618
619 if (CMS_RecipientInfo_ktri_get0_algs(ri, NULL, NULL, &alg) == 1 &&
620 CMS_RecipientInfo_ktri_get0_signer_id(ri, NULL, &name, &sn) == 1)
621 {
622 oid = openssl_asn1_known_oid(alg->algorithm);
623 if (oid != OID_RSA_ENCRYPTION)
624 {
625 DBG1(DBG_LIB, "only RSA encryption supported in PKCS#7");
626 continue;
627 }
628 issuer = openssl_x509_name2id(name);
629 if (!issuer)
630 {
631 continue;
632 }
633 chunk = openssl_asn1_str2chunk(sn);
634 if (chunk.len && chunk.ptr[0] & 0x80)
635 { /* if MSB is set, append a zero to make it non-negative */
636 chunk = chunk_cata("cc", chunk_from_thing(zero), chunk);
637 }
638 serial = identification_create_from_encoding(ID_KEY_ID, chunk);
639 private = find_private(issuer, serial);
640 issuer->destroy(issuer);
641 serial->destroy(serial);
642
643 if (private)
644 {
645 /* get encryptedKey from internal structure; TODO fixup */
646 chunk = openssl_asn1_str2chunk(ri->ktri->encryptedKey);
647 if (private->decrypt(private, ENCRYPT_RSA_PKCS1,
648 chunk, &key))
649 {
650 private->destroy(private);
651 break;
652 }
653 private->destroy(private);
654 }
655 }
656 }
657 }
658 if (!key.len)
659 {
660 DBG1(DBG_LIB, "no private key found to decrypt PKCS#7");
661 return FALSE;
662 }
663 if (!decrypt_symmetric(this, key, encrypted, plain))
664 {
665 chunk_clear(&key);
666 return FALSE;
667 }
668 chunk_clear(&key);
669 if (!remove_padding(plain))
670 {
671 free(plain->ptr);
672 return FALSE;
673 }
674 return TRUE;
675 }
676
677 METHOD(container_t, get_data, bool,
678 private_openssl_pkcs7_t *this, chunk_t *data)
679 {
680 ASN1_OCTET_STRING **os;
681 chunk_t chunk;
682
683 os = CMS_get0_content(this->cms);
684 if (os)
685 {
686 chunk = openssl_asn1_str2chunk(*os);
687 switch (this->type)
688 {
689 case CONTAINER_PKCS7_DATA:
690 case CONTAINER_PKCS7_SIGNED_DATA:
691 *data = chunk_clone(chunk);
692 return TRUE;
693 case CONTAINER_PKCS7_ENVELOPED_DATA:
694 return decrypt(this, chunk, data);
695 default:
696 break;
697 }
698 }
699 return FALSE;
700 }
701
702 METHOD(container_t, get_encoding, bool,
703 private_openssl_pkcs7_t *this, chunk_t *data)
704 {
705 return FALSE;
706 }
707
708 METHOD(container_t, destroy, void,
709 private_openssl_pkcs7_t *this)
710 {
711 CMS_ContentInfo_free(this->cms);
712 free(this);
713 }
714
715 /**
716 * Generic constructor
717 */
718 static private_openssl_pkcs7_t* create_empty()
719 {
720 private_openssl_pkcs7_t *this;
721
722 INIT(this,
723 .public = {
724 .container = {
725 .get_type = _get_type,
726 .create_signature_enumerator = _create_signature_enumerator,
727 .get_data = _get_data,
728 .get_encoding = _get_encoding,
729 .destroy = _destroy,
730 },
731 .get_attribute = _get_attribute,
732 .create_cert_enumerator = _create_cert_enumerator,
733 },
734 );
735
736 return this;
737 }
738
739 /**
740 * Parse a PKCS#7 container
741 */
742 static bool parse(private_openssl_pkcs7_t *this, chunk_t blob)
743 {
744 BIO *bio;
745
746 bio = BIO_new_mem_buf(blob.ptr, blob.len);
747 this->cms = d2i_CMS_bio(bio, NULL);
748 BIO_free(bio);
749
750 if (!this->cms)
751 {
752 return FALSE;
753 }
754 switch (openssl_asn1_known_oid((ASN1_OBJECT*)CMS_get0_type(this->cms)))
755 {
756 case OID_PKCS7_DATA:
757 this->type = CONTAINER_PKCS7_DATA;
758 break;
759 case OID_PKCS7_SIGNED_DATA:
760 this->type = CONTAINER_PKCS7_SIGNED_DATA;
761 break;
762 case OID_PKCS7_ENVELOPED_DATA:
763 this->type = CONTAINER_PKCS7_ENVELOPED_DATA;
764 break;
765 default:
766 return FALSE;
767 }
768
769 return TRUE;
770 }
771
772 /**
773 * See header
774 */
775 pkcs7_t *openssl_pkcs7_load(container_type_t type, va_list args)
776 {
777 chunk_t blob = chunk_empty;
778 private_openssl_pkcs7_t *this;
779
780 while (TRUE)
781 {
782 switch (va_arg(args, builder_part_t))
783 {
784 case BUILD_BLOB_ASN1_DER:
785 blob = va_arg(args, chunk_t);
786 continue;
787 case BUILD_END:
788 break;
789 default:
790 return NULL;
791 }
792 break;
793 }
794 if (blob.len)
795 {
796 this = create_empty();
797 if (parse(this, blob))
798 {
799 return &this->public;
800 }
801 destroy(this);
802 }
803 return NULL;
804 }
805
806 #endif /* OPENSSL_NO_CMS */
807 #endif /* OPENSSL_VERSION_NUMBER */