195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley/* Copyright (c) 2014, Google Inc. 295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * Permission to use, copy, modify, and/or distribute this software for any 495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * purpose with or without fee is hereby granted, provided that the above 595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * copyright notice and this permission notice appear in all copies. 695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 1095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 1295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 1395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 1495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley 1595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/x509.h> 1695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley 1795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/bytestring.h> 1895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/err.h> 1995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/obj.h> 2095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/stack.h> 2195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley 229c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley#include "../bytestring/internal.h" 239c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley 2495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley 2595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyint PKCS7_get_certificates(STACK_OF(X509) *out_certs, CBS *cbs) { 269c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley uint8_t *der_bytes = NULL; 279c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley size_t der_len; 289c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley CBS in, content_info, content_type, wrapped_signed_data, signed_data, 299c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley certificates; 3095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley const size_t initial_certs_len = sk_X509_num(out_certs); 319c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley uint64_t version; 329c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley int ret = 0; 339c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley 349c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley /* The input may be in BER format. */ 359c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley if (!CBS_asn1_ber_to_der(cbs, &der_bytes, &der_len)) { 369c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley return 0; 379c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley } 389c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley if (der_bytes != NULL) { 399c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley CBS_init(&in, der_bytes, der_len); 409c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley } else { 419c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley CBS_init(&in, CBS_data(cbs), CBS_len(cbs)); 429c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley } 4395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley 44eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley /* See https://tools.ietf.org/html/rfc2315#section-7 */ 459c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley if (!CBS_get_asn1(&in, &content_info, CBS_ASN1_SEQUENCE) || 4695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley !CBS_get_asn1(&content_info, &content_type, CBS_ASN1_OBJECT)) { 479c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley goto err; 4895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley } 4995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley 509c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley if (OBJ_cbs2nid(&content_type) != NID_pkcs7_signed) { 5195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley OPENSSL_PUT_ERROR(X509, PKCS7_get_certificates, 5295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley X509_R_NOT_PKCS7_SIGNED_DATA); 539c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley goto err; 5495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley } 5595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley 56eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley /* See https://tools.ietf.org/html/rfc2315#section-9.1 */ 579c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley if (!CBS_get_asn1(&content_info, &wrapped_signed_data, 589c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) || 599c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley !CBS_get_asn1(&wrapped_signed_data, &signed_data, CBS_ASN1_SEQUENCE) || 609c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley !CBS_get_asn1_uint64(&signed_data, &version) || 619c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley !CBS_get_asn1(&signed_data, NULL /* digests */, CBS_ASN1_SET) || 629c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley !CBS_get_asn1(&signed_data, NULL /* content */, CBS_ASN1_SEQUENCE)) { 639c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley goto err; 6495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley } 6595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley 669c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley if (version < 1) { 6795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley OPENSSL_PUT_ERROR(X509, PKCS7_get_certificates, 6895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley X509_R_BAD_PKCS7_VERSION); 699c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley goto err; 7095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley } 7195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley 729c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley if (!CBS_get_asn1(&signed_data, &certificates, 739c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) { 7495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley OPENSSL_PUT_ERROR(X509, PKCS7_get_certificates, 7595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley X509_R_NO_CERTIFICATES_INCLUDED); 769c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley goto err; 7795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley } 7895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley 7995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley while (CBS_len(&certificates) > 0) { 8095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley CBS cert; 8195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley X509 *x509; 8295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley const uint8_t *inp; 8395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley 8495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley if (!CBS_get_asn1_element(&certificates, &cert, CBS_ASN1_SEQUENCE)) { 8595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley goto err; 8695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley } 8795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley 8895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley inp = CBS_data(&cert); 8995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley x509 = d2i_X509(NULL, &inp, CBS_len(&cert)); 9095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley if (!x509) { 9195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley goto err; 9295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley } 9395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley 9495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley if (inp != CBS_data(&cert) + CBS_len(&cert)) { 9595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley /* This suggests a disconnect between the two ASN.1 parsers. */ 9695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley goto err; 9795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley } 9895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley 9995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley sk_X509_push(out_certs, x509); 10095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley } 10195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley 1029c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley ret = 1; 10395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley 10495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyerr: 1059c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley if (der_bytes) { 1069c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley OPENSSL_free(der_bytes); 1079c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley } 1089c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley 1099c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley if (!ret) { 1109c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley while (sk_X509_num(out_certs) != initial_certs_len) { 1119c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley X509 *x509 = sk_X509_pop(out_certs); 1129c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley X509_free(x509); 1139c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley } 11495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley } 11595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley 1169c01e00c2e5bb8087c27203c0adccd9738beb64dAdam Langley return ret; 11795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley} 118eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley 119eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langleyint PKCS7_bundle_certificates(CBB *out, const STACK_OF(X509) *certs) { 120eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley CBB outer_seq, wrapped_seq, seq, version_bytes, digest_algos_set, 121eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley content_info, certificates; 122eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley size_t i; 123eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley 124eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley /* See https://tools.ietf.org/html/rfc2315#section-7 */ 125eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley if (!CBB_add_asn1(out, &outer_seq, CBS_ASN1_SEQUENCE) || 126eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley !OBJ_nid2cbb(&outer_seq, NID_pkcs7_signed) || 127eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley !CBB_add_asn1(&outer_seq, &wrapped_seq, 128eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) || 129eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley /* See https://tools.ietf.org/html/rfc2315#section-9.1 */ 130eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley !CBB_add_asn1(&wrapped_seq, &seq, CBS_ASN1_SEQUENCE) || 131eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley !CBB_add_asn1(&seq, &version_bytes, CBS_ASN1_INTEGER) || 132eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley !CBB_add_u8(&version_bytes, 1) || 133eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley !CBB_add_asn1(&seq, &digest_algos_set, CBS_ASN1_SET) || 134eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley !CBB_add_asn1(&seq, &content_info, CBS_ASN1_SEQUENCE) || 135eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley !OBJ_nid2cbb(&content_info, NID_pkcs7_data) || 136eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley !CBB_add_asn1(&seq, &certificates, 137eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) { 138eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley return 0; 139eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley } 140eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley 141eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley for (i = 0; i < sk_X509_num(certs); i++) { 142eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley X509 *x509 = sk_X509_value(certs, i); 143eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley uint8_t *buf; 144eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley int len = i2d_X509(x509, NULL); 145eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley 146eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley if (len < 0 || 147eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley !CBB_add_space(&certificates, &buf, len) || 148eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley i2d_X509(x509, &buf) < 0) { 149eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley return 0; 150eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley } 151eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley } 152eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley 153eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley return CBB_flush(out); 154eeb9f491e8f07a3160df6c586a5bde42ebceb672Adam Langley} 155