1/* Copyright (c) 2014, Google Inc. 2 * 3 * Permission to use, copy, modify, and/or distribute this software for any 4 * purpose with or without fee is hereby granted, provided that the above 5 * copyright notice and this permission notice appear in all copies. 6 * 7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 14 15#include <openssl/x509.h> 16 17#include <openssl/bytestring.h> 18#include <openssl/err.h> 19#include <openssl/obj.h> 20#include <openssl/stack.h> 21 22#include "../bytestring/internal.h" 23 24 25int PKCS7_get_certificates(STACK_OF(X509) *out_certs, CBS *cbs) { 26 uint8_t *der_bytes = NULL; 27 size_t der_len; 28 CBS in, content_info, content_type, wrapped_signed_data, signed_data, 29 certificates; 30 const size_t initial_certs_len = sk_X509_num(out_certs); 31 uint64_t version; 32 int ret = 0; 33 34 /* The input may be in BER format. */ 35 if (!CBS_asn1_ber_to_der(cbs, &der_bytes, &der_len)) { 36 return 0; 37 } 38 if (der_bytes != NULL) { 39 CBS_init(&in, der_bytes, der_len); 40 } else { 41 CBS_init(&in, CBS_data(cbs), CBS_len(cbs)); 42 } 43 44 /* See https://tools.ietf.org/html/rfc2315#section-7 */ 45 if (!CBS_get_asn1(&in, &content_info, CBS_ASN1_SEQUENCE) || 46 !CBS_get_asn1(&content_info, &content_type, CBS_ASN1_OBJECT)) { 47 goto err; 48 } 49 50 if (OBJ_cbs2nid(&content_type) != NID_pkcs7_signed) { 51 OPENSSL_PUT_ERROR(X509, PKCS7_get_certificates, 52 X509_R_NOT_PKCS7_SIGNED_DATA); 53 goto err; 54 } 55 56 /* See https://tools.ietf.org/html/rfc2315#section-9.1 */ 57 if (!CBS_get_asn1(&content_info, &wrapped_signed_data, 58 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) || 59 !CBS_get_asn1(&wrapped_signed_data, &signed_data, CBS_ASN1_SEQUENCE) || 60 !CBS_get_asn1_uint64(&signed_data, &version) || 61 !CBS_get_asn1(&signed_data, NULL /* digests */, CBS_ASN1_SET) || 62 !CBS_get_asn1(&signed_data, NULL /* content */, CBS_ASN1_SEQUENCE)) { 63 goto err; 64 } 65 66 if (version < 1) { 67 OPENSSL_PUT_ERROR(X509, PKCS7_get_certificates, 68 X509_R_BAD_PKCS7_VERSION); 69 goto err; 70 } 71 72 if (!CBS_get_asn1(&signed_data, &certificates, 73 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) { 74 OPENSSL_PUT_ERROR(X509, PKCS7_get_certificates, 75 X509_R_NO_CERTIFICATES_INCLUDED); 76 goto err; 77 } 78 79 while (CBS_len(&certificates) > 0) { 80 CBS cert; 81 X509 *x509; 82 const uint8_t *inp; 83 84 if (!CBS_get_asn1_element(&certificates, &cert, CBS_ASN1_SEQUENCE)) { 85 goto err; 86 } 87 88 inp = CBS_data(&cert); 89 x509 = d2i_X509(NULL, &inp, CBS_len(&cert)); 90 if (!x509) { 91 goto err; 92 } 93 94 if (inp != CBS_data(&cert) + CBS_len(&cert)) { 95 /* This suggests a disconnect between the two ASN.1 parsers. */ 96 goto err; 97 } 98 99 sk_X509_push(out_certs, x509); 100 } 101 102 ret = 1; 103 104err: 105 if (der_bytes) { 106 OPENSSL_free(der_bytes); 107 } 108 109 if (!ret) { 110 while (sk_X509_num(out_certs) != initial_certs_len) { 111 X509 *x509 = sk_X509_pop(out_certs); 112 X509_free(x509); 113 } 114 } 115 116 return ret; 117} 118 119int PKCS7_bundle_certificates(CBB *out, const STACK_OF(X509) *certs) { 120 CBB outer_seq, wrapped_seq, seq, version_bytes, digest_algos_set, 121 content_info, certificates; 122 size_t i; 123 124 /* See https://tools.ietf.org/html/rfc2315#section-7 */ 125 if (!CBB_add_asn1(out, &outer_seq, CBS_ASN1_SEQUENCE) || 126 !OBJ_nid2cbb(&outer_seq, NID_pkcs7_signed) || 127 !CBB_add_asn1(&outer_seq, &wrapped_seq, 128 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) || 129 /* See https://tools.ietf.org/html/rfc2315#section-9.1 */ 130 !CBB_add_asn1(&wrapped_seq, &seq, CBS_ASN1_SEQUENCE) || 131 !CBB_add_asn1(&seq, &version_bytes, CBS_ASN1_INTEGER) || 132 !CBB_add_u8(&version_bytes, 1) || 133 !CBB_add_asn1(&seq, &digest_algos_set, CBS_ASN1_SET) || 134 !CBB_add_asn1(&seq, &content_info, CBS_ASN1_SEQUENCE) || 135 !OBJ_nid2cbb(&content_info, NID_pkcs7_data) || 136 !CBB_add_asn1(&seq, &certificates, 137 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) { 138 return 0; 139 } 140 141 for (i = 0; i < sk_X509_num(certs); i++) { 142 X509 *x509 = sk_X509_value(certs, i); 143 uint8_t *buf; 144 int len = i2d_X509(x509, NULL); 145 146 if (len < 0 || 147 !CBB_add_space(&certificates, &buf, len) || 148 i2d_X509(x509, &buf) < 0) { 149 return 0; 150 } 151 } 152 153 return CBB_flush(out); 154} 155