1d9e397b599b13d642138480a28c14db7a136bf0Adam Langley/* Copyright (c) 2014, Google Inc.
2d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
3d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * Permission to use, copy, modify, and/or distribute this software for any
4d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * purpose with or without fee is hereby granted, provided that the above
5d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * copyright notice and this permission notice appear in all copies.
6d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
7d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
15d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/x509.h>
16d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
1746ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley#include <assert.h>
1846ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
19d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/bytestring.h>
20d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/err.h>
21e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley#include <openssl/mem.h>
22d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/obj.h>
2313a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley#include <openssl/pem.h>
24d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/stack.h>
25d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
26d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include "../bytestring/internal.h"
27d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
28d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
2946ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley/* pkcs7_parse_header reads the non-certificate/non-CRL prefix of a PKCS#7
3046ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley * SignedData blob from |cbs| and sets |*out| to point to the rest of the
3146ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley * input. If the input is in BER format, then |*der_bytes| will be set to a
3246ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley * pointer that needs to be freed by the caller once they have finished
3346ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley * processing |*out| (which will be pointing into |*der_bytes|).
3446ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley *
3546ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley * It returns one on success or zero on error. On error, |*der_bytes| is
3646ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley * NULL. */
3746ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langleystatic int pkcs7_parse_header(uint8_t **der_bytes, CBS *out, CBS *cbs) {
38d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  size_t der_len;
3946ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  CBS in, content_info, content_type, wrapped_signed_data, signed_data;
40d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  uint64_t version;
41d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
42d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  /* The input may be in BER format. */
4346ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  *der_bytes = NULL;
4446ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  if (!CBS_asn1_ber_to_der(cbs, der_bytes, &der_len)) {
45d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return 0;
46d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
4746ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  if (*der_bytes != NULL) {
4846ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    CBS_init(&in, *der_bytes, der_len);
49d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  } else {
50d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    CBS_init(&in, CBS_data(cbs), CBS_len(cbs));
51d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
52d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
53d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  /* See https://tools.ietf.org/html/rfc2315#section-7 */
54d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (!CBS_get_asn1(&in, &content_info, CBS_ASN1_SEQUENCE) ||
55d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      !CBS_get_asn1(&content_info, &content_type, CBS_ASN1_OBJECT)) {
56d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    goto err;
57d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
58d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
59d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (OBJ_cbs2nid(&content_type) != NID_pkcs7_signed) {
6046ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    OPENSSL_PUT_ERROR(X509, pkcs7_parse_header,
61d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                      X509_R_NOT_PKCS7_SIGNED_DATA);
62d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    goto err;
63d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
64d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
65d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  /* See https://tools.ietf.org/html/rfc2315#section-9.1 */
66d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (!CBS_get_asn1(&content_info, &wrapped_signed_data,
67d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                    CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
68d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      !CBS_get_asn1(&wrapped_signed_data, &signed_data, CBS_ASN1_SEQUENCE) ||
69d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      !CBS_get_asn1_uint64(&signed_data, &version) ||
70d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      !CBS_get_asn1(&signed_data, NULL /* digests */, CBS_ASN1_SET) ||
71d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      !CBS_get_asn1(&signed_data, NULL /* content */, CBS_ASN1_SEQUENCE)) {
72d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    goto err;
73d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
74d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
75d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (version < 1) {
7646ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    OPENSSL_PUT_ERROR(X509, pkcs7_parse_header,
77d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                      X509_R_BAD_PKCS7_VERSION);
78d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    goto err;
79d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
80d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
8146ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  CBS_init(out, CBS_data(&signed_data), CBS_len(&signed_data));
8246ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  return 1;
8346ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
8446ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langleyerr:
8546ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  if (*der_bytes) {
8646ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    OPENSSL_free(*der_bytes);
8746ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    *der_bytes = NULL;
8846ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  }
8946ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
9046ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  return 0;
9146ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley}
9246ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
9346ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langleyint PKCS7_get_certificates(STACK_OF(X509) *out_certs, CBS *cbs) {
9446ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  CBS signed_data, certificates;
9546ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  uint8_t *der_bytes = NULL;
9646ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  int ret = 0;
9746ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  const size_t initial_certs_len = sk_X509_num(out_certs);
9846ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
9946ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  if (!pkcs7_parse_header(&der_bytes, &signed_data, cbs)) {
10046ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    return 0;
10146ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  }
10246ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
10346ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  /* See https://tools.ietf.org/html/rfc2315#section-9.1 */
104d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (!CBS_get_asn1(&signed_data, &certificates,
105d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                    CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) {
106d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    OPENSSL_PUT_ERROR(X509, PKCS7_get_certificates,
107d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                      X509_R_NO_CERTIFICATES_INCLUDED);
108d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    goto err;
109d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
110d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
111d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  while (CBS_len(&certificates) > 0) {
112d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    CBS cert;
113d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    X509 *x509;
114d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    const uint8_t *inp;
115d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
116d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (!CBS_get_asn1_element(&certificates, &cert, CBS_ASN1_SEQUENCE)) {
117d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      goto err;
118d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
119d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
120d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    inp = CBS_data(&cert);
121d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    x509 = d2i_X509(NULL, &inp, CBS_len(&cert));
122d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (!x509) {
123d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      goto err;
124d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
125d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
12646ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    assert(inp == CBS_data(&cert) + CBS_len(&cert));
12746ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
12846ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    if (sk_X509_push(out_certs, x509) == 0) {
12946ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley      X509_free(x509);
130d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      goto err;
131d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
132d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
133d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
134d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  ret = 1;
135d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
136d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyerr:
137d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (der_bytes) {
138d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    OPENSSL_free(der_bytes);
139d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
140d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
141d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (!ret) {
142d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    while (sk_X509_num(out_certs) != initial_certs_len) {
143d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      X509 *x509 = sk_X509_pop(out_certs);
144d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      X509_free(x509);
145d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
146d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
147d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
148d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return ret;
149d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
150d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
15146ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langleyint PKCS7_get_CRLs(STACK_OF(X509_CRL) *out_crls, CBS *cbs) {
15246ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  CBS signed_data, crls;
15346ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  uint8_t *der_bytes = NULL;
15446ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  int ret = 0;
15546ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  const size_t initial_crls_len = sk_X509_CRL_num(out_crls);
15646ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
15746ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  if (!pkcs7_parse_header(&der_bytes, &signed_data, cbs)) {
15846ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    return 0;
15946ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  }
16046ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
16146ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  /* See https://tools.ietf.org/html/rfc2315#section-9.1 */
16246ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
16346ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  /* Even if only CRLs are included, there may be an empty certificates block.
16446ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley   * OpenSSL does this, for example. */
16546ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  if (CBS_peek_asn1_tag(&signed_data,
16646ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley                        CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) &&
16746ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley      !CBS_get_asn1(&signed_data, NULL /* certificates */,
16846ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley                    CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) {
16946ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    goto err;
17046ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  }
17146ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
17246ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  if (!CBS_get_asn1(&signed_data, &crls,
17346ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley                    CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1)) {
17446ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    OPENSSL_PUT_ERROR(X509, PKCS7_get_CRLs,
17546ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley                      X509_R_NO_CRLS_INCLUDED);
17646ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    goto err;
17746ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  }
17846ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
17946ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  while (CBS_len(&crls) > 0) {
18046ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    CBS crl_data;
18146ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    X509_CRL *crl;
18246ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    const uint8_t *inp;
18346ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
18446ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    if (!CBS_get_asn1_element(&crls, &crl_data, CBS_ASN1_SEQUENCE)) {
18546ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley      goto err;
18646ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    }
18746ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
18846ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    inp = CBS_data(&crl_data);
18946ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    crl = d2i_X509_CRL(NULL, &inp, CBS_len(&crl_data));
19046ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    if (!crl) {
19146ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley      goto err;
19246ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    }
19346ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
19446ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    assert(inp == CBS_data(&crl_data) + CBS_len(&crl_data));
19546ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
19646ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    if (sk_X509_CRL_push(out_crls, crl) == 0) {
19746ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley      X509_CRL_free(crl);
19846ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley      goto err;
19946ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    }
20046ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  }
20146ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
20246ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  ret = 1;
20346ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
20446ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langleyerr:
20546ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  if (der_bytes) {
20646ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    OPENSSL_free(der_bytes);
20746ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  }
20846ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
20946ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  if (!ret) {
21046ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    while (sk_X509_CRL_num(out_crls) != initial_crls_len) {
21146ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley      X509_CRL_free(sk_X509_CRL_pop(out_crls));
21246ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    }
21346ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  }
21446ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
21546ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  return ret;
21646ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley}
21746ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
21813a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langleyint PKCS7_get_PEM_certificates(STACK_OF(X509) *out_certs, BIO *pem_bio) {
21913a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley  uint8_t *data;
22013a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley  long len;
22113a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley  int ret;
22213a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley
22313a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley  /* Even though we pass PEM_STRING_PKCS7 as the expected PEM type here, PEM
22413a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley   * internally will actually allow several other values too, including
22513a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley   * "CERTIFICATE". */
22613a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley  if (!PEM_bytes_read_bio(&data, &len, NULL /* PEM type output */,
22713a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley                          PEM_STRING_PKCS7, pem_bio,
22813a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley                          NULL /* password callback */,
22913a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley                          NULL /* password callback argument */)) {
23013a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley    return 0;
23113a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley  }
23213a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley
23313a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley  CBS cbs;
23413a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley  CBS_init(&cbs, data, len);
23513a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley  ret = PKCS7_get_certificates(out_certs, &cbs);
23613a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley  OPENSSL_free(data);
23713a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley  return ret;
23813a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley}
23913a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley
24013a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langleyint PKCS7_get_PEM_CRLs(STACK_OF(X509_CRL) *out_crls, BIO *pem_bio) {
24113a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley  uint8_t *data;
24213a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley  long len;
24313a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley  int ret;
24413a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley
24513a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley  /* Even though we pass PEM_STRING_PKCS7 as the expected PEM type here, PEM
24613a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley   * internally will actually allow several other values too, including
24713a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley   * "CERTIFICATE". */
24813a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley  if (!PEM_bytes_read_bio(&data, &len, NULL /* PEM type output */,
24913a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley                          PEM_STRING_PKCS7, pem_bio,
25013a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley                          NULL /* password callback */,
25113a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley                          NULL /* password callback argument */)) {
25213a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley    return 0;
25313a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley  }
25413a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley
25513a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley  CBS cbs;
25613a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley  CBS_init(&cbs, data, len);
25713a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley  ret = PKCS7_get_CRLs(out_crls, &cbs);
25813a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley  OPENSSL_free(data);
25913a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley  return ret;
26013a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley}
26113a2c994a655cbabc53ccaae76c83d6ece01e183Adam Langley
26246ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley/* pkcs7_bundle writes a PKCS#7, SignedData structure to |out| and then calls
26346ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley * |cb| with a CBB to which certificate or CRL data can be written, and the
26446ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley * opaque context pointer, |arg|. The callback can return zero to indicate an
26546ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley * error.
26646ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley *
26746ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley * pkcs7_bundle returns one on success or zero on error. */
26846ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langleystatic int pkcs7_bundle(CBB *out, int (*cb)(CBB *out, const void *arg),
26946ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley                        const void *arg) {
270d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  CBB outer_seq, wrapped_seq, seq, version_bytes, digest_algos_set,
27146ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley      content_info;
272d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
273d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  /* See https://tools.ietf.org/html/rfc2315#section-7 */
274d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (!CBB_add_asn1(out, &outer_seq, CBS_ASN1_SEQUENCE) ||
275d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      !OBJ_nid2cbb(&outer_seq, NID_pkcs7_signed) ||
276d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      !CBB_add_asn1(&outer_seq, &wrapped_seq,
277d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                    CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
278d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      /* See https://tools.ietf.org/html/rfc2315#section-9.1 */
279d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      !CBB_add_asn1(&wrapped_seq, &seq, CBS_ASN1_SEQUENCE) ||
280d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      !CBB_add_asn1(&seq, &version_bytes, CBS_ASN1_INTEGER) ||
281d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      !CBB_add_u8(&version_bytes, 1) ||
282d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      !CBB_add_asn1(&seq, &digest_algos_set, CBS_ASN1_SET) ||
283d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      !CBB_add_asn1(&seq, &content_info, CBS_ASN1_SEQUENCE) ||
284d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      !OBJ_nid2cbb(&content_info, NID_pkcs7_data) ||
28546ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley      !cb(&seq, arg)) {
28646ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    return 0;
28746ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  }
28846ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
28946ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  return CBB_flush(out);
29046ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley}
29146ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
29246ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langleystatic int pkcs7_bundle_certificates_cb(CBB *out, const void *arg) {
29346ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  const STACK_OF(X509) *certs = arg;
29446ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  size_t i;
29546ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  CBB certificates;
29646ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
29746ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  /* See https://tools.ietf.org/html/rfc2315#section-9.1 */
29846ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  if (!CBB_add_asn1(out, &certificates,
299d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                    CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) {
300d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return 0;
301d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
302d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
303d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  for (i = 0; i < sk_X509_num(certs); i++) {
304d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    X509 *x509 = sk_X509_value(certs, i);
305d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    uint8_t *buf;
306d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    int len = i2d_X509(x509, NULL);
307d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
308d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (len < 0 ||
309d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        !CBB_add_space(&certificates, &buf, len) ||
310d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        i2d_X509(x509, &buf) < 0) {
311d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      return 0;
312d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
313d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
314d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
315d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return CBB_flush(out);
316d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
31746ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
31846ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langleyint PKCS7_bundle_certificates(CBB *out, const STACK_OF(X509) *certs) {
31946ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  return pkcs7_bundle(out, pkcs7_bundle_certificates_cb, certs);
32046ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley}
32146ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
32246ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langleystatic int pkcs7_bundle_crls_cb(CBB *out, const void *arg) {
32346ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  const STACK_OF(X509_CRL) *crls = arg;
32446ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  size_t i;
32546ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  CBB crl_data;
32646ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
32746ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  /* See https://tools.ietf.org/html/rfc2315#section-9.1 */
32846ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  if (!CBB_add_asn1(out, &crl_data,
32946ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley                    CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1)) {
33046ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    return 0;
33146ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  }
33246ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
33346ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  for (i = 0; i < sk_X509_CRL_num(crls); i++) {
33446ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    X509_CRL *crl = sk_X509_CRL_value(crls, i);
33546ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    uint8_t *buf;
33646ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    int len = i2d_X509_CRL(crl, NULL);
33746ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
33846ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    if (len < 0 ||
33946ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley        !CBB_add_space(&crl_data, &buf, len) ||
34046ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley        i2d_X509_CRL(crl, &buf) < 0) {
34146ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley      return 0;
34246ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley    }
34346ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  }
34446ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
34546ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  return CBB_flush(out);
34646ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley}
34746ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley
34846ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langleyint PKCS7_bundle_CRLs(CBB *out, const STACK_OF(X509_CRL) *crls) {
34946ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley  return pkcs7_bundle(out, pkcs7_bundle_crls_cb, crls);
35046ba7161f20f8b1e6729384a98e1b9973ed3c908Adam Langley}
351