summaryrefslogtreecommitdiff
path: root/src/crypto/pkcs7
diff options
context:
space:
mode:
authorAdam Vartanian <flooey@google.com>2018-08-10 14:55:24 +0100
committerAdam Vartanian <flooey@google.com>2018-08-10 15:32:39 +0100
commitbfcf3a72c0bcb62cfde80e932db0668a7f96c0f8 (patch)
tree3ab110046e45c25f8f69df137f8a9d4a52bf60b5 /src/crypto/pkcs7
parent6120b2b9dfbe5b19fe2d0f69a4b8418ad5f7fe08 (diff)
downloadboringssl-bfcf3a72c0bcb62cfde80e932db0668a7f96c0f8.tar.gz
external/boringssl: Sync to 8625ec4b436ccb4098ed4aac10891eff8372be41.
This includes the following changes: https://boringssl.googlesource.com/boringssl/+log/c596415ec62b501523d80f9afa26b135406da6bf..8625ec4b436ccb4098ed4aac10891eff8372be41 Test: cts -m CtsLibcoreTestCases Change-Id: I47a45e6b6f46b19fcbcb6c917895867d56dcd2ca
Diffstat (limited to 'src/crypto/pkcs7')
-rw-r--r--src/crypto/pkcs7/pkcs7.c32
-rw-r--r--src/crypto/pkcs7/pkcs7_test.cc79
-rw-r--r--src/crypto/pkcs7/pkcs7_x509.c194
3 files changed, 267 insertions, 38 deletions
diff --git a/src/crypto/pkcs7/pkcs7.c b/src/crypto/pkcs7/pkcs7.c
index fc175a94..c04bffde 100644
--- a/src/crypto/pkcs7/pkcs7.c
+++ b/src/crypto/pkcs7/pkcs7.c
@@ -41,23 +41,14 @@ static const uint8_t kPKCS7SignedData[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
// It returns one on success or zero on error. On error, |*der_bytes| is
// NULL.
int pkcs7_parse_header(uint8_t **der_bytes, CBS *out, CBS *cbs) {
- size_t der_len;
CBS in, content_info, content_type, wrapped_signed_data, signed_data;
uint64_t version;
// The input may be in BER format.
*der_bytes = NULL;
- if (!CBS_asn1_ber_to_der(cbs, der_bytes, &der_len)) {
- return 0;
- }
- if (*der_bytes != NULL) {
- CBS_init(&in, *der_bytes, der_len);
- } else {
- CBS_init(&in, CBS_data(cbs), CBS_len(cbs));
- }
-
- // See https://tools.ietf.org/html/rfc2315#section-7
- if (!CBS_get_asn1(&in, &content_info, CBS_ASN1_SEQUENCE) ||
+ if (!CBS_asn1_ber_to_der(cbs, &in, der_bytes) ||
+ // See https://tools.ietf.org/html/rfc2315#section-7
+ !CBS_get_asn1(&in, &content_info, CBS_ASN1_SEQUENCE) ||
!CBS_get_asn1(&content_info, &content_type, CBS_ASN1_OBJECT)) {
goto err;
}
@@ -96,20 +87,21 @@ int PKCS7_get_raw_certificates(STACK_OF(CRYPTO_BUFFER) *out_certs, CBS *cbs,
CRYPTO_BUFFER_POOL *pool) {
CBS signed_data, certificates;
uint8_t *der_bytes = NULL;
- int ret = 0;
+ int ret = 0, has_certificates;
const size_t initial_certs_len = sk_CRYPTO_BUFFER_num(out_certs);
- if (!pkcs7_parse_header(&der_bytes, &signed_data, cbs)) {
- return 0;
- }
-
// See https://tools.ietf.org/html/rfc2315#section-9.1
- if (!CBS_get_asn1(&signed_data, &certificates,
- CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) {
- OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_NO_CERTIFICATES_INCLUDED);
+ if (!pkcs7_parse_header(&der_bytes, &signed_data, cbs) ||
+ !CBS_get_optional_asn1(
+ &signed_data, &certificates, &has_certificates,
+ CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) {
goto err;
}
+ if (!has_certificates) {
+ CBS_init(&certificates, NULL, 0);
+ }
+
while (CBS_len(&certificates) > 0) {
CBS cert;
if (!CBS_get_asn1_element(&certificates, &cert, CBS_ASN1_SEQUENCE)) {
diff --git a/src/crypto/pkcs7/pkcs7_test.cc b/src/crypto/pkcs7/pkcs7_test.cc
index 54f7e8aa..1ac9af2b 100644
--- a/src/crypto/pkcs7/pkcs7_test.cc
+++ b/src/crypto/pkcs7/pkcs7_test.cc
@@ -480,6 +480,7 @@ static void TestCertRepase(const uint8_t *der_bytes, size_t der_len) {
CBS pkcs7;
CBS_init(&pkcs7, der_bytes, der_len);
ASSERT_TRUE(PKCS7_get_certificates(certs.get(), &pkcs7));
+ EXPECT_EQ(0u, CBS_len(&pkcs7));
bssl::ScopedCBB cbb;
ASSERT_TRUE(CBB_init(cbb.get(), der_len));
@@ -489,9 +490,9 @@ static void TestCertRepase(const uint8_t *der_bytes, size_t der_len) {
CBS_init(&pkcs7, result_data, result_len);
ASSERT_TRUE(PKCS7_get_certificates(certs2.get(), &pkcs7));
+ EXPECT_EQ(0u, CBS_len(&pkcs7));
ASSERT_EQ(sk_X509_num(certs.get()), sk_X509_num(certs2.get()));
-
for (size_t i = 0; i < sk_X509_num(certs.get()); i++) {
X509 *a = sk_X509_value(certs.get(), i);
X509 *b = sk_X509_value(certs2.get(), i);
@@ -504,6 +505,50 @@ static void TestCertRepase(const uint8_t *der_bytes, size_t der_len) {
bssl::UniquePtr<uint8_t> free_result2_data(result2_data);
EXPECT_EQ(Bytes(result_data, result_len), Bytes(result2_data, result2_len));
+
+ // Parse with the legacy API instead.
+ const uint8_t *ptr = der_bytes;
+ bssl::UniquePtr<PKCS7> pkcs7_obj(d2i_PKCS7(nullptr, &ptr, der_len));
+ ASSERT_TRUE(pkcs7_obj);
+ EXPECT_EQ(ptr, der_bytes + der_len);
+
+ ASSERT_TRUE(PKCS7_type_is_signed(pkcs7_obj.get()));
+ const STACK_OF(X509) *certs3 = pkcs7_obj->d.sign->cert;
+ ASSERT_EQ(sk_X509_num(certs.get()), sk_X509_num(certs3));
+ for (size_t i = 0; i < sk_X509_num(certs.get()); i++) {
+ X509 *a = sk_X509_value(certs.get(), i);
+ X509 *b = sk_X509_value(certs3, i);
+ ASSERT_EQ(0, X509_cmp(a, b));
+ }
+
+ // Serialize the original object. This should echo back the original saved
+ // bytes.
+ uint8_t *result3_data = nullptr;
+ int result3_len = i2d_PKCS7(pkcs7_obj.get(), &result3_data);
+ ASSERT_GT(result3_len, 0);
+ bssl::UniquePtr<uint8_t> free_result3_data(result3_data);
+ EXPECT_EQ(Bytes(der_bytes, der_len), Bytes(result3_data, result3_len));
+
+ // Make a new object with the legacy API.
+ pkcs7_obj.reset(
+ PKCS7_sign(nullptr, nullptr, certs.get(), nullptr, PKCS7_DETACHED));
+ ASSERT_TRUE(pkcs7_obj);
+
+ ASSERT_TRUE(PKCS7_type_is_signed(pkcs7_obj.get()));
+ const STACK_OF(X509) *certs4 = pkcs7_obj->d.sign->cert;
+ ASSERT_EQ(sk_X509_num(certs.get()), sk_X509_num(certs4));
+ for (size_t i = 0; i < sk_X509_num(certs.get()); i++) {
+ X509 *a = sk_X509_value(certs.get(), i);
+ X509 *b = sk_X509_value(certs4, i);
+ ASSERT_EQ(0, X509_cmp(a, b));
+ }
+
+ // This new object should serialize canonically.
+ uint8_t *result4_data = nullptr;
+ int result4_len = i2d_PKCS7(pkcs7_obj.get(), &result4_data);
+ ASSERT_GT(result4_len, 0);
+ bssl::UniquePtr<uint8_t> free_result4_data(result4_data);
+ EXPECT_EQ(Bytes(result_data, result_len), Bytes(result4_data, result4_len));
}
static void TestCRLReparse(const uint8_t *der_bytes, size_t der_len) {
@@ -517,6 +562,7 @@ static void TestCRLReparse(const uint8_t *der_bytes, size_t der_len) {
CBS pkcs7;
CBS_init(&pkcs7, der_bytes, der_len);
ASSERT_TRUE(PKCS7_get_CRLs(crls.get(), &pkcs7));
+ EXPECT_EQ(0u, CBS_len(&pkcs7));
bssl::ScopedCBB cbb;
ASSERT_TRUE(CBB_init(cbb.get(), der_len));
@@ -526,9 +572,9 @@ static void TestCRLReparse(const uint8_t *der_bytes, size_t der_len) {
CBS_init(&pkcs7, result_data, result_len);
ASSERT_TRUE(PKCS7_get_CRLs(crls2.get(), &pkcs7));
+ EXPECT_EQ(0u, CBS_len(&pkcs7));
ASSERT_EQ(sk_X509_CRL_num(crls.get()), sk_X509_CRL_num(crls.get()));
-
for (size_t i = 0; i < sk_X509_CRL_num(crls.get()); i++) {
X509_CRL *a = sk_X509_CRL_value(crls.get(), i);
X509_CRL *b = sk_X509_CRL_value(crls2.get(), i);
@@ -541,6 +587,35 @@ static void TestCRLReparse(const uint8_t *der_bytes, size_t der_len) {
bssl::UniquePtr<uint8_t> free_result2_data(result2_data);
EXPECT_EQ(Bytes(result_data, result_len), Bytes(result2_data, result2_len));
+
+ // Parse with the legacy API instead.
+ const uint8_t *ptr = der_bytes;
+ bssl::UniquePtr<PKCS7> pkcs7_obj(d2i_PKCS7(nullptr, &ptr, der_len));
+ ASSERT_TRUE(pkcs7_obj);
+ EXPECT_EQ(ptr, der_bytes + der_len);
+
+ ASSERT_TRUE(PKCS7_type_is_signed(pkcs7_obj.get()));
+ const STACK_OF(X509_CRL) *crls3 = pkcs7_obj->d.sign->crl;
+ ASSERT_EQ(sk_X509_CRL_num(crls.get()), sk_X509_CRL_num(crls3));
+ for (size_t i = 0; i < sk_X509_CRL_num(crls.get()); i++) {
+ X509_CRL *a = sk_X509_CRL_value(crls.get(), i);
+ X509_CRL *b = sk_X509_CRL_value(crls3, i);
+ ASSERT_EQ(0, X509_CRL_cmp(a, b));
+ }
+
+ ptr = result_data;
+ pkcs7_obj.reset(d2i_PKCS7(nullptr, &ptr, result_len));
+ ASSERT_TRUE(pkcs7_obj);
+ EXPECT_EQ(ptr, result_data + result_len);
+
+ ASSERT_TRUE(PKCS7_type_is_signed(pkcs7_obj.get()));
+ const STACK_OF(X509_CRL) *crls4 = pkcs7_obj->d.sign->crl;
+ ASSERT_EQ(sk_X509_CRL_num(crls.get()), sk_X509_CRL_num(crls4));
+ for (size_t i = 0; i < sk_X509_CRL_num(crls.get()); i++) {
+ X509_CRL *a = sk_X509_CRL_value(crls.get(), i);
+ X509_CRL *b = sk_X509_CRL_value(crls4, i);
+ ASSERT_EQ(0, X509_CRL_cmp(a, b));
+ }
}
static void TestPEMCerts(const char *pem) {
diff --git a/src/crypto/pkcs7/pkcs7_x509.c b/src/crypto/pkcs7/pkcs7_x509.c
index 7bc39d27..a2a6b46a 100644
--- a/src/crypto/pkcs7/pkcs7_x509.c
+++ b/src/crypto/pkcs7/pkcs7_x509.c
@@ -26,6 +26,7 @@
#include <openssl/x509.h>
#include "internal.h"
+#include "../internal.h"
int PKCS7_get_certificates(STACK_OF(X509) *out_certs, CBS *cbs) {
@@ -64,28 +65,24 @@ err:
int PKCS7_get_CRLs(STACK_OF(X509_CRL) *out_crls, CBS *cbs) {
CBS signed_data, crls;
uint8_t *der_bytes = NULL;
- int ret = 0;
+ int ret = 0, has_crls;
const size_t initial_crls_len = sk_X509_CRL_num(out_crls);
- if (!pkcs7_parse_header(&der_bytes, &signed_data, cbs)) {
- return 0;
- }
-
// See https://tools.ietf.org/html/rfc2315#section-9.1
-
- // Even if only CRLs are included, there may be an empty certificates block.
- // OpenSSL does this, for example.
- if (CBS_peek_asn1_tag(&signed_data,
- CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) &&
- !CBS_get_asn1(&signed_data, NULL /* certificates */,
- CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) {
+ if (!pkcs7_parse_header(&der_bytes, &signed_data, cbs) ||
+ // Even if only CRLs are included, there may be an empty certificates
+ // block. OpenSSL does this, for example.
+ !CBS_get_optional_asn1(
+ &signed_data, NULL, NULL,
+ CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
+ !CBS_get_optional_asn1(
+ &signed_data, &crls, &has_crls,
+ CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1)) {
goto err;
}
- if (!CBS_get_asn1(&signed_data, &crls,
- CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1)) {
- OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_NO_CRLS_INCLUDED);
- goto err;
+ if (!has_crls) {
+ CBS_init(&crls, NULL, 0);
}
while (CBS_len(&crls) > 0) {
@@ -231,3 +228,168 @@ static int pkcs7_bundle_crls_cb(CBB *out, const void *arg) {
int PKCS7_bundle_CRLs(CBB *out, const STACK_OF(X509_CRL) *crls) {
return pkcs7_bundle(out, pkcs7_bundle_crls_cb, crls);
}
+
+static PKCS7 *pkcs7_new(CBS *cbs) {
+ PKCS7 *ret = OPENSSL_malloc(sizeof(PKCS7));
+ if (ret == NULL) {
+ return NULL;
+ }
+ OPENSSL_memset(ret, 0, sizeof(PKCS7));
+ ret->type = (ASN1_OBJECT *)OBJ_nid2obj(NID_pkcs7_signed);
+ ret->d.sign = OPENSSL_malloc(sizeof(PKCS7_SIGNED));
+ if (ret->d.sign == NULL) {
+ goto err;
+ }
+ ret->d.sign->cert = sk_X509_new_null();
+ ret->d.sign->crl = sk_X509_CRL_new_null();
+ CBS copy = *cbs, copy2 = *cbs;
+ if (ret->d.sign->cert == NULL || ret->d.sign->crl == NULL ||
+ !PKCS7_get_certificates(ret->d.sign->cert, &copy) ||
+ !PKCS7_get_CRLs(ret->d.sign->crl, cbs)) {
+ goto err;
+ }
+
+ if (sk_X509_num(ret->d.sign->cert) == 0) {
+ sk_X509_free(ret->d.sign->cert);
+ ret->d.sign->cert = NULL;
+ }
+
+ if (sk_X509_CRL_num(ret->d.sign->crl) == 0) {
+ sk_X509_CRL_free(ret->d.sign->crl);
+ ret->d.sign->crl = NULL;
+ }
+
+ ret->ber_len = CBS_len(&copy2) - CBS_len(cbs);
+ ret->ber_bytes = BUF_memdup(CBS_data(&copy2), ret->ber_len);
+ if (ret->ber_bytes == NULL) {
+ goto err;
+ }
+
+ return ret;
+
+err:
+ PKCS7_free(ret);
+ return NULL;
+}
+
+PKCS7 *d2i_PKCS7(PKCS7 **out, const uint8_t **inp,
+ size_t len) {
+ CBS cbs;
+ CBS_init(&cbs, *inp, len);
+ PKCS7 *ret = pkcs7_new(&cbs);
+ if (ret == NULL) {
+ return NULL;
+ }
+ *inp = CBS_data(&cbs);
+ if (out != NULL) {
+ PKCS7_free(*out);
+ *out = ret;
+ }
+ return ret;
+}
+
+PKCS7 *d2i_PKCS7_bio(BIO *bio, PKCS7 **out) {
+ // Use a generous bound, to allow for PKCS#7 files containing large root sets.
+ static const size_t kMaxSize = 4 * 1024 * 1024;
+ uint8_t *data;
+ size_t len;
+ if (!BIO_read_asn1(bio, &data, &len, kMaxSize)) {
+ return NULL;
+ }
+
+ CBS cbs;
+ CBS_init(&cbs, data, len);
+ PKCS7 *ret = pkcs7_new(&cbs);
+ OPENSSL_free(data);
+ if (out != NULL && ret != NULL) {
+ PKCS7_free(*out);
+ *out = ret;
+ }
+ return ret;
+}
+
+int i2d_PKCS7(const PKCS7 *p7, uint8_t **out) {
+ if (p7->ber_len > INT_MAX) {
+ OPENSSL_PUT_ERROR(PKCS8, ERR_R_OVERFLOW);
+ return -1;
+ }
+
+ if (out == NULL) {
+ return (int)p7->ber_len;
+ }
+
+ if (*out == NULL) {
+ *out = OPENSSL_malloc(p7->ber_len);
+ if (*out == NULL) {
+ OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ OPENSSL_memcpy(*out, p7->ber_bytes, p7->ber_len);
+ } else {
+ OPENSSL_memcpy(*out, p7->ber_bytes, p7->ber_len);
+ *out += p7->ber_len;
+ }
+ return (int)p7->ber_len;
+}
+
+int i2d_PKCS7_bio(BIO *bio, const PKCS7 *p7) {
+ size_t written = 0;
+ while (written < p7->ber_len) {
+ size_t todo = p7->ber_len - written;
+ int len = todo > INT_MAX ? INT_MAX : (int)todo;
+ int ret = BIO_write(bio, p7->ber_bytes + written, len);
+ if (ret <= 0) {
+ return 0;
+ }
+ written += (size_t)ret;
+ }
+ return 1;
+}
+
+void PKCS7_free(PKCS7 *p7) {
+ if (p7 == NULL) {
+ return;
+ }
+
+ OPENSSL_free(p7->ber_bytes);
+ ASN1_OBJECT_free(p7->type);
+ // We only supported signed data.
+ if (p7->d.sign != NULL) {
+ sk_X509_pop_free(p7->d.sign->cert, X509_free);
+ sk_X509_CRL_pop_free(p7->d.sign->crl, X509_CRL_free);
+ OPENSSL_free(p7->d.sign);
+ }
+ OPENSSL_free(p7);
+}
+
+// We only support signed data, so these getters are no-ops.
+int PKCS7_type_is_data(const PKCS7 *p7) { return 0; }
+int PKCS7_type_is_digest(const PKCS7 *p7) { return 0; }
+int PKCS7_type_is_encrypted(const PKCS7 *p7) { return 0; }
+int PKCS7_type_is_enveloped(const PKCS7 *p7) { return 0; }
+int PKCS7_type_is_signed(const PKCS7 *p7) { return 1; }
+int PKCS7_type_is_signedAndEnveloped(const PKCS7 *p7) { return 0; }
+
+PKCS7 *PKCS7_sign(X509 *sign_cert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
+ BIO *data, int flags) {
+ if (sign_cert != NULL || pkey != NULL || flags != PKCS7_DETACHED) {
+ OPENSSL_PUT_ERROR(PKCS7, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return NULL;
+ }
+
+ uint8_t *der;
+ size_t len;
+ CBB cbb;
+ if (!CBB_init(&cbb, 2048) ||
+ !PKCS7_bundle_certificates(&cbb, certs) ||
+ !CBB_finish(&cbb, &der, &len)) {
+ CBB_cleanup(&cbb);
+ return NULL;
+ }
+
+ CBS cbs;
+ CBS_init(&cbs, der, len);
+ PKCS7 *ret = pkcs7_new(&cbs);
+ OPENSSL_free(der);
+ return ret;
+}