// Copyright (c) 2014, Google Inc.
// SPDX-License-Identifier: ISC

#include <gtest/gtest.h>

#include <openssl/bytestring.h>
#include <openssl/crypto.h>
#include <openssl/mem.h>
#include <openssl/pem.h>
#include <openssl/pkcs7.h>
#include <openssl/stack.h>
#include <openssl/x509.h>

#include "../bytestring/internal.h"
#include "../internal.h"
#include "../test/test_util.h"
#include "internal.h"

std::string GetTestData(const char *path);

// kPKCS7NSS contains the certificate chain of mail.google.com, as saved by NSS
// using the Chrome UI.
static const uint8_t kPKCS7NSS[] = {
    0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
    0x02, 0xa0, 0x80, 0x30, 0x80, 0x02, 0x01, 0x01, 0x31, 0x00, 0x30, 0x80,
    0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x00,
    0x00, 0xa0, 0x82, 0x0b, 0x1e, 0x30, 0x82, 0x03, 0x54, 0x30, 0x82, 0x02,
    0x3c, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x02, 0x34, 0x56, 0x30,
    0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
    0x05, 0x00, 0x30, 0x42, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
    0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55,
    0x04, 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74,
    0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55,
    0x04, 0x03, 0x13, 0x12, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74,
    0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e,
    0x17, 0x0d, 0x30, 0x32, 0x30, 0x35, 0x32, 0x31, 0x30, 0x34, 0x30, 0x30,
    0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x32, 0x30, 0x35, 0x32, 0x31, 0x30,
    0x34, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x42, 0x31, 0x0b, 0x30, 0x09,
    0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30,
    0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54,
    0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1b, 0x30,
    0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47, 0x65, 0x6f, 0x54,
    0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20,
    0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
    0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
    0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xda,
    0xcc, 0x18, 0x63, 0x30, 0xfd, 0xf4, 0x17, 0x23, 0x1a, 0x56, 0x7e, 0x5b,
    0xdf, 0x3c, 0x6c, 0x38, 0xe4, 0x71, 0xb7, 0x78, 0x91, 0xd4, 0xbc, 0xa1,
    0xd8, 0x4c, 0xf8, 0xa8, 0x43, 0xb6, 0x03, 0xe9, 0x4d, 0x21, 0x07, 0x08,
    0x88, 0xda, 0x58, 0x2f, 0x66, 0x39, 0x29, 0xbd, 0x05, 0x78, 0x8b, 0x9d,
    0x38, 0xe8, 0x05, 0xb7, 0x6a, 0x7e, 0x71, 0xa4, 0xe6, 0xc4, 0x60, 0xa6,
    0xb0, 0xef, 0x80, 0xe4, 0x89, 0x28, 0x0f, 0x9e, 0x25, 0xd6, 0xed, 0x83,
    0xf3, 0xad, 0xa6, 0x91, 0xc7, 0x98, 0xc9, 0x42, 0x18, 0x35, 0x14, 0x9d,
    0xad, 0x98, 0x46, 0x92, 0x2e, 0x4f, 0xca, 0xf1, 0x87, 0x43, 0xc1, 0x16,
    0x95, 0x57, 0x2d, 0x50, 0xef, 0x89, 0x2d, 0x80, 0x7a, 0x57, 0xad, 0xf2,
    0xee, 0x5f, 0x6b, 0xd2, 0x00, 0x8d, 0xb9, 0x14, 0xf8, 0x14, 0x15, 0x35,
    0xd9, 0xc0, 0x46, 0xa3, 0x7b, 0x72, 0xc8, 0x91, 0xbf, 0xc9, 0x55, 0x2b,
    0xcd, 0xd0, 0x97, 0x3e, 0x9c, 0x26, 0x64, 0xcc, 0xdf, 0xce, 0x83, 0x19,
    0x71, 0xca, 0x4e, 0xe6, 0xd4, 0xd5, 0x7b, 0xa9, 0x19, 0xcd, 0x55, 0xde,
    0xc8, 0xec, 0xd2, 0x5e, 0x38, 0x53, 0xe5, 0x5c, 0x4f, 0x8c, 0x2d, 0xfe,
    0x50, 0x23, 0x36, 0xfc, 0x66, 0xe6, 0xcb, 0x8e, 0xa4, 0x39, 0x19, 0x00,
    0xb7, 0x95, 0x02, 0x39, 0x91, 0x0b, 0x0e, 0xfe, 0x38, 0x2e, 0xd1, 0x1d,
    0x05, 0x9a, 0xf6, 0x4d, 0x3e, 0x6f, 0x0f, 0x07, 0x1d, 0xaf, 0x2c, 0x1e,
    0x8f, 0x60, 0x39, 0xe2, 0xfa, 0x36, 0x53, 0x13, 0x39, 0xd4, 0x5e, 0x26,
    0x2b, 0xdb, 0x3d, 0xa8, 0x14, 0xbd, 0x32, 0xeb, 0x18, 0x03, 0x28, 0x52,
    0x04, 0x71, 0xe5, 0xab, 0x33, 0x3d, 0xe1, 0x38, 0xbb, 0x07, 0x36, 0x84,
    0x62, 0x9c, 0x79, 0xea, 0x16, 0x30, 0xf4, 0x5f, 0xc0, 0x2b, 0xe8, 0x71,
    0x6b, 0xe4, 0xf9, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x53, 0x30, 0x51,
    0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05,
    0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
    0x04, 0x16, 0x04, 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, 0xab,
    0x05, 0x64, 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, 0x4e,
    0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80,
    0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, 0xab, 0x05, 0x64, 0x0c,
    0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, 0x4e, 0x30, 0x0d, 0x06,
    0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
    0x03, 0x82, 0x01, 0x01, 0x00, 0x35, 0xe3, 0x29, 0x6a, 0xe5, 0x2f, 0x5d,
    0x54, 0x8e, 0x29, 0x50, 0x94, 0x9f, 0x99, 0x1a, 0x14, 0xe4, 0x8f, 0x78,
    0x2a, 0x62, 0x94, 0xa2, 0x27, 0x67, 0x9e, 0xd0, 0xcf, 0x1a, 0x5e, 0x47,
    0xe9, 0xc1, 0xb2, 0xa4, 0xcf, 0xdd, 0x41, 0x1a, 0x05, 0x4e, 0x9b, 0x4b,
    0xee, 0x4a, 0x6f, 0x55, 0x52, 0xb3, 0x24, 0xa1, 0x37, 0x0a, 0xeb, 0x64,
    0x76, 0x2a, 0x2e, 0x2c, 0xf3, 0xfd, 0x3b, 0x75, 0x90, 0xbf, 0xfa, 0x71,
    0xd8, 0xc7, 0x3d, 0x37, 0xd2, 0xb5, 0x05, 0x95, 0x62, 0xb9, 0xa6, 0xde,
    0x89, 0x3d, 0x36, 0x7b, 0x38, 0x77, 0x48, 0x97, 0xac, 0xa6, 0x20, 0x8f,
    0x2e, 0xa6, 0xc9, 0x0c, 0xc2, 0xb2, 0x99, 0x45, 0x00, 0xc7, 0xce, 0x11,
    0x51, 0x22, 0x22, 0xe0, 0xa5, 0xea, 0xb6, 0x15, 0x48, 0x09, 0x64, 0xea,
    0x5e, 0x4f, 0x74, 0xf7, 0x05, 0x3e, 0xc7, 0x8a, 0x52, 0x0c, 0xdb, 0x15,
    0xb4, 0xbd, 0x6d, 0x9b, 0xe5, 0xc6, 0xb1, 0x54, 0x68, 0xa9, 0xe3, 0x69,
    0x90, 0xb6, 0x9a, 0xa5, 0x0f, 0xb8, 0xb9, 0x3f, 0x20, 0x7d, 0xae, 0x4a,
    0xb5, 0xb8, 0x9c, 0xe4, 0x1d, 0xb6, 0xab, 0xe6, 0x94, 0xa5, 0xc1, 0xc7,
    0x83, 0xad, 0xdb, 0xf5, 0x27, 0x87, 0x0e, 0x04, 0x6c, 0xd5, 0xff, 0xdd,
    0xa0, 0x5d, 0xed, 0x87, 0x52, 0xb7, 0x2b, 0x15, 0x02, 0xae, 0x39, 0xa6,
    0x6a, 0x74, 0xe9, 0xda, 0xc4, 0xe7, 0xbc, 0x4d, 0x34, 0x1e, 0xa9, 0x5c,
    0x4d, 0x33, 0x5f, 0x92, 0x09, 0x2f, 0x88, 0x66, 0x5d, 0x77, 0x97, 0xc7,
    0x1d, 0x76, 0x13, 0xa9, 0xd5, 0xe5, 0xf1, 0x16, 0x09, 0x11, 0x35, 0xd5,
    0xac, 0xdb, 0x24, 0x71, 0x70, 0x2c, 0x98, 0x56, 0x0b, 0xd9, 0x17, 0xb4,
    0xd1, 0xe3, 0x51, 0x2b, 0x5e, 0x75, 0xe8, 0xd5, 0xd0, 0xdc, 0x4f, 0x34,
    0xed, 0xc2, 0x05, 0x66, 0x80, 0xa1, 0xcb, 0xe6, 0x33, 0x30, 0x82, 0x03,
    0xba, 0x30, 0x82, 0x02, 0xa2, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08,
    0x3e, 0xa3, 0xe4, 0x78, 0x99, 0x38, 0x13, 0x9d, 0x30, 0x0d, 0x06, 0x09,
    0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
    0x49, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
    0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
    0x0a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x31,
    0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1c, 0x47, 0x6f,
    0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
    0x74, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20,
    0x47, 0x32, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x37, 0x31, 0x36,
    0x31, 0x32, 0x32, 0x31, 0x34, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x31,
    0x30, 0x31, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x69,
    0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
    0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a,
    0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16,
    0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, 0x6f, 0x75,
    0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x69, 0x65, 0x77, 0x31, 0x13,
    0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x47, 0x6f, 0x6f,
    0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x18, 0x30, 0x16, 0x06,
    0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x67,
    0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x59, 0x30,
    0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08,
    0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04,
    0xb2, 0x68, 0x6e, 0x3f, 0x03, 0x9e, 0x43, 0x85, 0x16, 0xb7, 0x89, 0x0b,
    0x16, 0x2a, 0xbe, 0x26, 0x36, 0xdd, 0x68, 0x0a, 0x53, 0x4e, 0x20, 0x40,
    0xf8, 0xd1, 0xdd, 0x63, 0xcb, 0x46, 0x73, 0x09, 0x96, 0x36, 0xde, 0x2c,
    0x45, 0x71, 0x2e, 0x8a, 0x79, 0xeb, 0x40, 0x2f, 0x65, 0x83, 0x81, 0xdb,
    0x37, 0x03, 0x84, 0xa1, 0x9a, 0xd0, 0x22, 0x3b, 0x73, 0x38, 0x45, 0xd3,
    0xd5, 0x91, 0xb2, 0x52, 0xa3, 0x82, 0x01, 0x4f, 0x30, 0x82, 0x01, 0x4b,
    0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06,
    0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b,
    0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x1a, 0x06, 0x03, 0x55,
    0x1d, 0x11, 0x04, 0x13, 0x30, 0x11, 0x82, 0x0f, 0x6d, 0x61, 0x69, 0x6c,
    0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30,
    0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80,
    0x30, 0x68, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01,
    0x04, 0x5c, 0x30, 0x5a, 0x30, 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
    0x05, 0x07, 0x30, 0x02, 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
    0x2f, 0x70, 0x6b, 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
    0x63, 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, 0x2e, 0x63, 0x72,
    0x74, 0x30, 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30,
    0x01, 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x6c,
    0x69, 0x65, 0x6e, 0x74, 0x73, 0x31, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
    0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x30, 0x1d,
    0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x75, 0xc6, 0xb0,
    0x4a, 0x46, 0x61, 0x83, 0xff, 0x91, 0x46, 0x45, 0x35, 0xa7, 0x0f, 0xd0,
    0x5b, 0xe9, 0xdd, 0x94, 0x1b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
    0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1f, 0x06, 0x03, 0x55,
    0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x4a, 0xdd, 0x06, 0x16,
    0x1b, 0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81, 0xb6, 0xbb, 0x62, 0x1a,
    0xba, 0x5a, 0x81, 0x2f, 0x30, 0x17, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04,
    0x10, 0x30, 0x0e, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01,
    0xd6, 0x79, 0x02, 0x05, 0x01, 0x30, 0x30, 0x06, 0x03, 0x55, 0x1d, 0x1f,
    0x04, 0x29, 0x30, 0x27, 0x30, 0x25, 0xa0, 0x23, 0xa0, 0x21, 0x86, 0x1f,
    0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, 0x67,
    0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x47, 0x49,
    0x41, 0x47, 0x32, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, 0x2a,
    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82,
    0x01, 0x01, 0x00, 0x7f, 0x41, 0xf5, 0x57, 0x18, 0x3c, 0x75, 0xf5, 0x23,
    0x66, 0xc3, 0xf0, 0xf2, 0x3e, 0x70, 0x34, 0x56, 0xca, 0x78, 0xec, 0xc7,
    0x81, 0x58, 0x0d, 0xdf, 0xf0, 0xfd, 0x86, 0xe6, 0xe6, 0x50, 0x3d, 0xf6,
    0x09, 0x9a, 0x4d, 0xca, 0x60, 0x37, 0x9a, 0xd4, 0xca, 0x51, 0x7c, 0xf0,
    0x66, 0x23, 0xea, 0x5e, 0x6a, 0x6f, 0x7b, 0xa6, 0x7a, 0x38, 0x97, 0x42,
    0x58, 0x1a, 0x1b, 0x42, 0xae, 0x28, 0xde, 0x18, 0x7f, 0xcc, 0x76, 0x18,
    0x58, 0x05, 0xbf, 0xea, 0xef, 0x14, 0xad, 0x34, 0xe5, 0x5f, 0x25, 0xab,
    0xa1, 0x5f, 0x78, 0x5b, 0x6f, 0xe6, 0x69, 0xd8, 0x74, 0x8c, 0x19, 0x59,
    0xb0, 0x1a, 0xfb, 0x8e, 0xdf, 0x61, 0xac, 0xeb, 0x2b, 0x0a, 0x1c, 0xab,
    0x30, 0x0d, 0x64, 0x25, 0x78, 0xdf, 0x81, 0x71, 0xe3, 0xbd, 0xde, 0x9c,
    0x3f, 0xdd, 0xe9, 0xf8, 0xb6, 0x98, 0x2d, 0x13, 0xa3, 0x7b, 0x14, 0x6f,
    0xe3, 0x8b, 0xfc, 0x4e, 0x31, 0x26, 0xba, 0x10, 0xb4, 0x12, 0xe9, 0xc9,
    0x49, 0x60, 0xf0, 0xaa, 0x1f, 0x44, 0x68, 0x19, 0xd2, 0xb3, 0xc8, 0x46,
    0x22, 0x6b, 0xe1, 0x21, 0x77, 0xfd, 0x72, 0x33, 0x13, 0x21, 0x27, 0x81,
    0xe4, 0x7a, 0xc9, 0xe4, 0x1c, 0x05, 0x04, 0x73, 0x13, 0xda, 0x47, 0xfe,
    0x59, 0x41, 0x9c, 0x11, 0xc5, 0xf6, 0xb5, 0xd0, 0x01, 0xcb, 0x40, 0x19,
    0xf5, 0xfe, 0xb3, 0x3c, 0x1f, 0x61, 0x8f, 0x4d, 0xdb, 0x81, 0x2a, 0x8a,
    0xed, 0xb8, 0x53, 0xc7, 0x19, 0x6b, 0xfa, 0x8b, 0xfc, 0xe3, 0x2e, 0x12,
    0x4e, 0xbd, 0xc5, 0x44, 0x9d, 0x1c, 0x7f, 0x3b, 0x09, 0x51, 0xd7, 0x0a,
    0x0f, 0x22, 0x0a, 0xfd, 0x8c, 0x90, 0x14, 0xed, 0x10, 0xcb, 0x50, 0xcf,
    0xa5, 0x45, 0xce, 0xb0, 0x21, 0x28, 0xcb, 0xd6, 0xf5, 0x6e, 0xb2, 0x3e,
    0xfa, 0x35, 0x0c, 0x3d, 0x09, 0x0d, 0x81, 0x30, 0x82, 0x04, 0x04, 0x30,
    0x82, 0x02, 0xec, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x02, 0x3a,
    0x69, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
    0x01, 0x05, 0x05, 0x00, 0x30, 0x42, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
    0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06,
    0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75,
    0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1b, 0x30, 0x19, 0x06,
    0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75,
    0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x41,
    0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x34, 0x30, 0x35, 0x31, 0x35,
    0x31, 0x35, 0x35, 0x35, 0x5a, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x34, 0x30,
    0x34, 0x31, 0x35, 0x31, 0x35, 0x35, 0x35, 0x5a, 0x30, 0x49, 0x31, 0x0b,
    0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
    0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, 0x6f,
    0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x25, 0x30, 0x23,
    0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1c, 0x47, 0x6f, 0x6f, 0x67, 0x6c,
    0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x41,
    0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x47, 0x32, 0x30,
    0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
    0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30,
    0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0x9c, 0x2a, 0x04, 0x77,
    0x5c, 0xd8, 0x50, 0x91, 0x3a, 0x06, 0xa3, 0x82, 0xe0, 0xd8, 0x50, 0x48,
    0xbc, 0x89, 0x3f, 0xf1, 0x19, 0x70, 0x1a, 0x88, 0x46, 0x7e, 0xe0, 0x8f,
    0xc5, 0xf1, 0x89, 0xce, 0x21, 0xee, 0x5a, 0xfe, 0x61, 0x0d, 0xb7, 0x32,
    0x44, 0x89, 0xa0, 0x74, 0x0b, 0x53, 0x4f, 0x55, 0xa4, 0xce, 0x82, 0x62,
    0x95, 0xee, 0xeb, 0x59, 0x5f, 0xc6, 0xe1, 0x05, 0x80, 0x12, 0xc4, 0x5e,
    0x94, 0x3f, 0xbc, 0x5b, 0x48, 0x38, 0xf4, 0x53, 0xf7, 0x24, 0xe6, 0xfb,
    0x91, 0xe9, 0x15, 0xc4, 0xcf, 0xf4, 0x53, 0x0d, 0xf4, 0x4a, 0xfc, 0x9f,
    0x54, 0xde, 0x7d, 0xbe, 0xa0, 0x6b, 0x6f, 0x87, 0xc0, 0xd0, 0x50, 0x1f,
    0x28, 0x30, 0x03, 0x40, 0xda, 0x08, 0x73, 0x51, 0x6c, 0x7f, 0xff, 0x3a,
    0x3c, 0xa7, 0x37, 0x06, 0x8e, 0xbd, 0x4b, 0x11, 0x04, 0xeb, 0x7d, 0x24,
    0xde, 0xe6, 0xf9, 0xfc, 0x31, 0x71, 0xfb, 0x94, 0xd5, 0x60, 0xf3, 0x2e,
    0x4a, 0xaf, 0x42, 0xd2, 0xcb, 0xea, 0xc4, 0x6a, 0x1a, 0xb2, 0xcc, 0x53,
    0xdd, 0x15, 0x4b, 0x8b, 0x1f, 0xc8, 0x19, 0x61, 0x1f, 0xcd, 0x9d, 0xa8,
    0x3e, 0x63, 0x2b, 0x84, 0x35, 0x69, 0x65, 0x84, 0xc8, 0x19, 0xc5, 0x46,
    0x22, 0xf8, 0x53, 0x95, 0xbe, 0xe3, 0x80, 0x4a, 0x10, 0xc6, 0x2a, 0xec,
    0xba, 0x97, 0x20, 0x11, 0xc7, 0x39, 0x99, 0x10, 0x04, 0xa0, 0xf0, 0x61,
    0x7a, 0x95, 0x25, 0x8c, 0x4e, 0x52, 0x75, 0xe2, 0xb6, 0xed, 0x08, 0xca,
    0x14, 0xfc, 0xce, 0x22, 0x6a, 0xb3, 0x4e, 0xcf, 0x46, 0x03, 0x97, 0x97,
    0x03, 0x7e, 0xc0, 0xb1, 0xde, 0x7b, 0xaf, 0x45, 0x33, 0xcf, 0xba, 0x3e,
    0x71, 0xb7, 0xde, 0xf4, 0x25, 0x25, 0xc2, 0x0d, 0x35, 0x89, 0x9d, 0x9d,
    0xfb, 0x0e, 0x11, 0x79, 0x89, 0x1e, 0x37, 0xc5, 0xaf, 0x8e, 0x72, 0x69,
    0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xfb, 0x30, 0x81, 0xf8, 0x30,
    0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
    0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, 0xab, 0x05, 0x64, 0x0c, 0x11,
    0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, 0x4e, 0x30, 0x1d, 0x06, 0x03,
    0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x4a, 0xdd, 0x06, 0x16, 0x1b,
    0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81, 0xb6, 0xbb, 0x62, 0x1a, 0xba,
    0x5a, 0x81, 0x2f, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
    0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30,
    0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03,
    0x02, 0x01, 0x06, 0x30, 0x3a, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x33,
    0x30, 0x31, 0x30, 0x2f, 0xa0, 0x2d, 0xa0, 0x2b, 0x86, 0x29, 0x68, 0x74,
    0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x67, 0x65, 0x6f,
    0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72,
    0x6c, 0x73, 0x2f, 0x67, 0x74, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e,
    0x63, 0x72, 0x6c, 0x30, 0x3d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
    0x07, 0x01, 0x01, 0x04, 0x31, 0x30, 0x2f, 0x30, 0x2d, 0x06, 0x08, 0x2b,
    0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x21, 0x68, 0x74, 0x74,
    0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x74, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c,
    0x2d, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75,
    0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x17, 0x06, 0x03, 0x55, 0x1d,
    0x20, 0x04, 0x10, 0x30, 0x0e, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01,
    0x04, 0x01, 0xd6, 0x79, 0x02, 0x05, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a,
    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82,
    0x01, 0x01, 0x00, 0x36, 0xd7, 0x06, 0x80, 0x11, 0x27, 0xad, 0x2a, 0x14,
    0x9b, 0x38, 0x77, 0xb3, 0x23, 0xa0, 0x75, 0x58, 0xbb, 0xb1, 0x7e, 0x83,
    0x42, 0xba, 0x72, 0xda, 0x1e, 0xd8, 0x8e, 0x36, 0x06, 0x97, 0xe0, 0xf0,
    0x95, 0x3b, 0x37, 0xfd, 0x1b, 0x42, 0x58, 0xfe, 0x22, 0xc8, 0x6b, 0xbd,
    0x38, 0x5e, 0xd1, 0x3b, 0x25, 0x6e, 0x12, 0xeb, 0x5e, 0x67, 0x76, 0x46,
    0x40, 0x90, 0xda, 0x14, 0xc8, 0x78, 0x0d, 0xed, 0x95, 0x66, 0xda, 0x8e,
    0x86, 0x6f, 0x80, 0xa1, 0xba, 0x56, 0x32, 0x95, 0x86, 0xdc, 0xdc, 0x6a,
    0xca, 0x04, 0x8c, 0x5b, 0x7f, 0xf6, 0xbf, 0xcc, 0x6f, 0x85, 0x03, 0x58,
    0xc3, 0x68, 0x51, 0x13, 0xcd, 0xfd, 0xc8, 0xf7, 0x79, 0x3d, 0x99, 0x35,
    0xf0, 0x56, 0xa3, 0xbd, 0xe0, 0x59, 0xed, 0x4f, 0x44, 0x09, 0xa3, 0x9e,
    0x38, 0x7a, 0xf6, 0x46, 0xd1, 0x1d, 0x12, 0x9d, 0x4f, 0xbe, 0xd0, 0x40,
    0xfc, 0x55, 0xfe, 0x06, 0x5e, 0x3c, 0xda, 0x1c, 0x56, 0xbd, 0x96, 0x51,
    0x7b, 0x6f, 0x57, 0x2a, 0xdb, 0xa2, 0xaa, 0x96, 0xdc, 0x8c, 0x74, 0xc2,
    0x95, 0xbe, 0xf0, 0x6e, 0x95, 0x13, 0xff, 0x17, 0xf0, 0x3c, 0xac, 0xb2,
    0x10, 0x8d, 0xcc, 0x73, 0xfb, 0xe8, 0x8f, 0x02, 0xc6, 0xf0, 0xfb, 0x33,
    0xb3, 0x95, 0x3b, 0xe3, 0xc2, 0xcb, 0x68, 0x58, 0x73, 0xdb, 0xa8, 0x24,
    0x62, 0x3b, 0x06, 0x35, 0x9d, 0x0d, 0xa9, 0x33, 0xbd, 0x78, 0x03, 0x90,
    0x2e, 0x4c, 0x78, 0x5d, 0x50, 0x3a, 0x81, 0xd4, 0xee, 0xa0, 0xc8, 0x70,
    0x38, 0xdc, 0xb2, 0xf9, 0x67, 0xfa, 0x87, 0x40, 0x5d, 0x61, 0xc0, 0x51,
    0x8f, 0x6b, 0x83, 0x6b, 0xcd, 0x05, 0x3a, 0xca, 0xe1, 0xa7, 0x05, 0x78,
    0xfc, 0xca, 0xda, 0x94, 0xd0, 0x2c, 0x08, 0x3d, 0x7e, 0x16, 0x79, 0xc8,
    0xa0, 0x50, 0x20, 0x24, 0x54, 0x33, 0x71, 0x31, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00,
};

// Cribbed from
// https://github.com/bcgit/bc-java/blob/main/pkix/src/test/resources/org/bouncycastle/openssl/test/pkcs7.pem
static const uint8_t kPKCS7EnvelopedData[] = {
    0x30, 0x82, 0x09, 0xA2, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D,
    0x01, 0x07, 0x03, 0xA0, 0x82, 0x09, 0x93, 0x30, 0x82, 0x09, 0x8F, 0x02,
    0x01, 0x00, 0x31, 0x81, 0xF8, 0x30, 0x81, 0xF5, 0x02, 0x01, 0x00, 0x30,
    0x5E, 0x30, 0x59, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
    0x13, 0x02, 0x47, 0x42, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
    0x08, 0x13, 0x09, 0x42, 0x65, 0x72, 0x6B, 0x73, 0x68, 0x69, 0x72, 0x65,
    0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x4E,
    0x65, 0x77, 0x62, 0x75, 0x72, 0x79, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03,
    0x55, 0x04, 0x0A, 0x13, 0x0E, 0x4D, 0x79, 0x20, 0x43, 0x6F, 0x6D, 0x70,
    0x61, 0x6E, 0x79, 0x20, 0x4C, 0x74, 0x64, 0x31, 0x0B, 0x30, 0x09, 0x06,
    0x03, 0x55, 0x04, 0x03, 0x13, 0x02, 0x58, 0x58, 0x02, 0x01, 0x00, 0x30,
    0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
    0x05, 0x00, 0x04, 0x81, 0x80, 0x22, 0x91, 0xBF, 0x5C, 0x0F, 0x7F, 0x68,
    0x0D, 0x8A, 0x4C, 0x1F, 0x32, 0xEE, 0xA8, 0x0E, 0x01, 0xA2, 0x73, 0x69,
    0x3F, 0x1F, 0xA3, 0x62, 0xDA, 0xA5, 0x50, 0x86, 0x89, 0xBF, 0x7D, 0x15,
    0xD3, 0x79, 0xD4, 0xCF, 0x53, 0x0B, 0x9B, 0xB2, 0x07, 0xED, 0x31, 0x6D,
    0x66, 0x12, 0xFA, 0x05, 0x70, 0x1B, 0x74, 0x2D, 0xA2, 0xC2, 0x4E, 0xB6,
    0x29, 0x54, 0xBA, 0xE9, 0x90, 0x8B, 0x04, 0xA7, 0x6C, 0xAA, 0xD0, 0xF7,
    0xC3, 0xD3, 0x76, 0x1E, 0xDC, 0x53, 0x11, 0x6E, 0x80, 0x75, 0xA3, 0x47,
    0x28, 0xD5, 0x1B, 0xEB, 0x3F, 0x37, 0xC9, 0xAA, 0xCD, 0x40, 0x6C, 0xC1,
    0xEB, 0xB9, 0x65, 0x66, 0x37, 0x82, 0x2D, 0xE8, 0xA9, 0x3F, 0xB4, 0x56,
    0x22, 0xF0, 0x59, 0x71, 0x5D, 0x0E, 0xA2, 0xA0, 0xA0, 0x2D, 0xCA, 0x59,
    0x92, 0x96, 0x6A, 0xCE, 0xB9, 0xB3, 0xE4, 0xC8, 0xF1, 0x4C, 0x29, 0x81,
    0xFC, 0x30, 0x82, 0x08, 0x8D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7,
    0x0D, 0x01, 0x07, 0x01, 0x30, 0x14, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86,
    0xF7, 0x0D, 0x03, 0x07, 0x04, 0x08, 0x8D, 0xAF, 0x67, 0x1A, 0x1B, 0x90,
    0x13, 0x51, 0x80, 0x82, 0x08, 0x68, 0x72, 0xCC, 0x21, 0x7B, 0x93, 0x19,
    0x46, 0x8B, 0xFD, 0x66, 0x8D, 0x60, 0x9C, 0x1D, 0xB9, 0x4B, 0x43, 0xFC,
    0x33, 0x0D, 0xF8, 0xEB, 0x75, 0x5A, 0x39, 0xC6, 0xFE, 0x96, 0x35, 0xF5,
    0x99, 0x79, 0x13, 0xDD, 0xF8, 0xAF, 0x90, 0x1B, 0xF4, 0xA6, 0x52, 0xE5,
    0x99, 0x54, 0xFE, 0x9B, 0xE0, 0x91, 0x81, 0xCC, 0xEE, 0xA7, 0xDA, 0x76,
    0xD7, 0xEB, 0x75, 0x3A, 0xAB, 0x1D, 0x68, 0x84, 0xCD, 0x23, 0x2A, 0xC6,
    0x85, 0x84, 0x95, 0x11, 0x35, 0xB2, 0x14, 0x0F, 0xD8, 0x9F, 0xB7, 0x50,
    0xBA, 0x92, 0xBE, 0x71, 0xD0, 0x9A, 0x54, 0xB2, 0x82, 0xDE, 0x54, 0xFC,
    0x7F, 0x5D, 0xE2, 0x3E, 0xB5, 0x38, 0xD3, 0x09, 0xDB, 0x7A, 0x8E, 0x19,
    0x2A, 0x2D, 0xAF, 0x6E, 0xFF, 0xD7, 0xDE, 0xE5, 0x38, 0x7D, 0x13, 0x19,
    0xC1, 0x29, 0x72, 0x73, 0x31, 0x68, 0xCD, 0xCB, 0xE2, 0x51, 0x85, 0x11,
    0xB4, 0x0E, 0x4C, 0x65, 0xA4, 0xB6, 0x7B, 0xAF, 0xF6, 0xAF, 0x57, 0x8B,
    0x65, 0xC5, 0x25, 0x71, 0x9D, 0x01, 0x0D, 0xCB, 0x83, 0xF8, 0x53, 0x5D,
    0xAF, 0x21, 0x9B, 0x2B, 0x3B, 0x52, 0x59, 0xAD, 0xB2, 0x7B, 0x46, 0x26,
    0x52, 0x29, 0x6E, 0xF8, 0x60, 0x19, 0xAF, 0x90, 0x90, 0x8B, 0x72, 0x31,
    0xA5, 0x1C, 0x43, 0xAA, 0xB4, 0xBE, 0x45, 0x44, 0x19, 0x36, 0x59, 0x5C,
    0x83, 0xC9, 0xC6, 0x67, 0x65, 0x0F, 0xE5, 0x6F, 0x05, 0x8C, 0x7F, 0x99,
    0xE7, 0xAF, 0x0D, 0x27, 0xB7, 0x63, 0xA3, 0x38, 0x82, 0x5F, 0x41, 0x07,
    0xC9, 0xDE, 0x2F, 0xA7, 0xE8, 0x34, 0x2D, 0x11, 0xB6, 0x76, 0x48, 0x46,
    0x5C, 0x87, 0xDF, 0xE2, 0xE7, 0xCE, 0xD9, 0x4D, 0xD0, 0x38, 0x08, 0x02,
    0x20, 0xEB, 0x99, 0x98, 0x6E, 0x58, 0x4A, 0x94, 0x4D, 0xD9, 0x4E, 0xC5,
    0xE9, 0x3F, 0x16, 0xFC, 0x5C, 0x12, 0x84, 0x53, 0xB5, 0xBB, 0xE4, 0x07,
    0x61, 0xDB, 0x80, 0xDE, 0x90, 0x3F, 0xE4, 0xAF, 0x88, 0x0D, 0xF0, 0x9B,
    0x11, 0x90, 0xCC, 0x5B, 0x39, 0xDD, 0xD7, 0x79, 0x53, 0x11, 0x94, 0x25,
    0x2D, 0x25, 0xD5, 0xED, 0xD2, 0xCD, 0x0A, 0xAA, 0x51, 0xDF, 0x42, 0x56,
    0xA4, 0x68, 0x3D, 0xE7, 0xAA, 0xC9, 0x47, 0x49, 0x36, 0x6D, 0x3E, 0xC6,
    0x28, 0x54, 0xD7, 0x85, 0x25, 0x0A, 0xFC, 0xFB, 0x9A, 0x73, 0x9C, 0xBA,
    0x21, 0x59, 0x89, 0xC0, 0xFC, 0x6A, 0x02, 0x48, 0xC7, 0xFB, 0x18, 0xD7,
    0xA4, 0x4D, 0xF6, 0xFC, 0x07, 0x11, 0x1E, 0x2E, 0xFB, 0x2D, 0xAD, 0xE7,
    0x2A, 0x9D, 0x5A, 0x40, 0x42, 0xA8, 0xE6, 0xE1, 0xE0, 0xEC, 0x71, 0x20,
    0xC3, 0x5E, 0xB4, 0x4B, 0x52, 0xD4, 0x7A, 0x72, 0x52, 0xA9, 0xC9, 0x8E,
    0xBA, 0x4E, 0x57, 0x5A, 0xF3, 0x35, 0xC1, 0xDB, 0x14, 0x26, 0x5E, 0x50,
    0x93, 0x89, 0xBD, 0x6B, 0x45, 0x72, 0xA2, 0xF2, 0xCF, 0x9B, 0xF4, 0x6B,
    0x9E, 0xE9, 0x4C, 0xB5, 0x48, 0xD1, 0xBA, 0x0C, 0x49, 0x2D, 0xF6, 0x4A,
    0xDB, 0xB3, 0x62, 0xBC, 0xEA, 0xCB, 0x97, 0xD8, 0x7F, 0x5A, 0x6E, 0x81,
    0x5D, 0x8A, 0xB8, 0x3E, 0x88, 0x4C, 0xE5, 0xDF, 0xB9, 0xCC, 0xF6, 0x2A,
    0xBA, 0x99, 0xF9, 0x8A, 0x92, 0x87, 0xB0, 0x0E, 0xBC, 0x3E, 0xCE, 0xEB,
    0x9C, 0x31, 0x06, 0x4B, 0x75, 0x73, 0x39, 0x0D, 0xF6, 0x86, 0xAB, 0xB8,
    0x91, 0xD9, 0xBA, 0xC4, 0x8D, 0xB3, 0x2D, 0x62, 0xB4, 0xFB, 0xA9, 0x90,
    0x9E, 0xEB, 0x01, 0x3C, 0xED, 0x08, 0x03, 0x1B, 0x63, 0x6B, 0xA0, 0x4F,
    0xCF, 0xCB, 0xD3, 0x32, 0x55, 0xA3, 0x66, 0xD5, 0x99, 0x80, 0x42, 0x0C,
    0xA6, 0x94, 0x0C, 0x85, 0x02, 0x4A, 0x04, 0x44, 0x06, 0xE8, 0x74, 0xD5,
    0xCF, 0xEF, 0xE0, 0x90, 0x57, 0x6C, 0xDA, 0x91, 0x4E, 0xD2, 0xFF, 0x29,
    0x2D, 0xC3, 0x01, 0xCB, 0xDF, 0xBC, 0x9E, 0xA8, 0x73, 0xC0, 0x66, 0x9C,
    0xCA, 0x69, 0xEE, 0xA5, 0x72, 0x73, 0x07, 0xA9, 0x77, 0x82, 0x89, 0xF6,
    0xB7, 0xF7, 0xB6, 0xCC, 0x98, 0xC0, 0x3C, 0xA5, 0x12, 0x09, 0xB1, 0xC8,
    0x42, 0x10, 0xA3, 0x5B, 0x62, 0x4A, 0xF6, 0xD1, 0x8A, 0x4D, 0xB1, 0x78,
    0xD2, 0xE6, 0x0C, 0x50, 0x63, 0x08, 0x3E, 0x1C, 0x6B, 0xEE, 0x3D, 0x6E,
    0xE0, 0xB2, 0x8D, 0x12, 0x12, 0x82, 0x36, 0x19, 0x54, 0xCF, 0xCD, 0x8D,
    0x4A, 0xC7, 0x49, 0xD3, 0x46, 0x0D, 0x41, 0xDC, 0x2E, 0x0C, 0xC5, 0x8D,
    0x09, 0x30, 0x04, 0xF7, 0xF4, 0x93, 0x99, 0x11, 0x85, 0xDD, 0x91, 0xD3,
    0xF4, 0xA5, 0xA6, 0xCF, 0x93, 0x10, 0x10, 0x2A, 0x7F, 0xA4, 0x63, 0x91,
    0x0F, 0xB2, 0xED, 0x39, 0x0B, 0x25, 0x6D, 0x46, 0x22, 0x30, 0x7E, 0x68,
    0x09, 0x83, 0xF5, 0x8C, 0x3F, 0x1E, 0x33, 0xE2, 0xB1, 0x0A, 0x58, 0xEF,
    0xD6, 0x91, 0x4F, 0x7F, 0xEB, 0x19, 0x76, 0x96, 0xE8, 0x02, 0x47, 0x5A,
    0x5C, 0xA7, 0x19, 0x56, 0x72, 0xAA, 0x3A, 0xE3, 0xC1, 0x3F, 0x76, 0x35,
    0x8C, 0x19, 0x0B, 0x09, 0x9C, 0xA4, 0x82, 0x75, 0xE4, 0x55, 0xB1, 0x18,
    0x33, 0xB8, 0x12, 0x76, 0xFB, 0x02, 0x18, 0xAE, 0x76, 0x19, 0xCC, 0x47,
    0xCA, 0x2F, 0xE0, 0x3A, 0x17, 0xCE, 0x22, 0x0C, 0xB0, 0x98, 0x50, 0x77,
    0x07, 0x86, 0x24, 0xE2, 0x60, 0xED, 0x53, 0xCE, 0x16, 0xA4, 0xAE, 0x6C,
    0x56, 0x5A, 0xD9, 0xDA, 0xF6, 0x6E, 0x4D, 0xA0, 0x26, 0x38, 0x76, 0x93,
    0x22, 0x45, 0x4C, 0xBE, 0x4A, 0xB7, 0xD0, 0x5F, 0xE3, 0xA5, 0x5C, 0xB7,
    0x38, 0x5E, 0x2F, 0xF7, 0xF1, 0x1B, 0x10, 0x02, 0x46, 0xBF, 0xAA, 0xEA,
    0x1C, 0xC8, 0x4A, 0x9A, 0xE2, 0x07, 0x3F, 0x9D, 0xF4, 0x08, 0xAB, 0x56,
    0x91, 0x45, 0x1F, 0x1A, 0xFE, 0xEA, 0x42, 0x29, 0x59, 0xD5, 0x08, 0xBA,
    0x37, 0x21, 0x49, 0x25, 0x37, 0xDB, 0xD5, 0xB8, 0x72, 0x10, 0xD2, 0x6D,
    0x8F, 0xC0, 0x35, 0x41, 0x01, 0x48, 0x60, 0x70, 0xF3, 0x32, 0x89, 0x66,
    0x52, 0x84, 0x20, 0xA8, 0xE5, 0xC9, 0xFF, 0xAC, 0x5C, 0xF4, 0x0B, 0x42,
    0xBF, 0x47, 0xD4, 0xD8, 0xB8, 0xA3, 0x2D, 0x43, 0x45, 0x8C, 0x1E, 0x2B,
    0x6A, 0x92, 0x60, 0x82, 0x8E, 0x54, 0x9D, 0x91, 0x3D, 0xF3, 0xE2, 0x2A,
    0x50, 0x04, 0xFB, 0xB5, 0x66, 0xA5, 0xA5, 0xB1, 0x62, 0xB0, 0xE7, 0x57,
    0xE4, 0x3C, 0xB9, 0xF3, 0x68, 0x61, 0xBD, 0xC1, 0x67, 0xFF, 0x50, 0xC3,
    0xA4, 0x84, 0x97, 0xA4, 0x5D, 0x24, 0x80, 0x4F, 0x13, 0x57, 0xFB, 0x30,
    0x90, 0x9E, 0xF3, 0xBA, 0xEF, 0xA1, 0x3B, 0xF6, 0x23, 0xD4, 0x73, 0x5D,
    0x73, 0x01, 0xBA, 0x34, 0x2F, 0x7E, 0xC1, 0x40, 0xA3, 0x69, 0x1A, 0x80,
    0xA1, 0xB0, 0x6D, 0xBC, 0xF4, 0x32, 0x2B, 0xAE, 0xBA, 0x23, 0xC0, 0xB5,
    0xDA, 0x99, 0xD6, 0xD0, 0x07, 0xAE, 0xAA, 0xDC, 0xE7, 0x9D, 0x9B, 0xDE,
    0xD8, 0x1D, 0x3F, 0x6B, 0xCD, 0xC4, 0x09, 0x2D, 0x2D, 0x52, 0x6C, 0x42,
    0x3C, 0xEF, 0x73, 0xBF, 0xD4, 0x4D, 0xC1, 0xC6, 0xA4, 0xCA, 0x79, 0x25,
    0xAE, 0xEA, 0x70, 0xEC, 0x1E, 0x0F, 0x71, 0x71, 0x1A, 0x11, 0xBC, 0x69,
    0xBC, 0x71, 0x3E, 0xFF, 0x33, 0x4B, 0x81, 0xFA, 0xCF, 0x46, 0x08, 0x28,
    0x15, 0xDA, 0x92, 0x21, 0x11, 0x52, 0xF7, 0x14, 0x11, 0x3C, 0x4F, 0x53,
    0xB8, 0xEE, 0xE3, 0x12, 0x1F, 0xAD, 0xCA, 0x1E, 0xF4, 0x78, 0xBA, 0x9C,
    0x7B, 0x68, 0xEA, 0x2A, 0x94, 0x70, 0xC4, 0x8B, 0x59, 0xB2, 0xDD, 0xC0,
    0x05, 0x3E, 0x57, 0x6A, 0xB2, 0x7A, 0xBD, 0xF1, 0xB1, 0xC5, 0xCB, 0x39,
    0xE6, 0xC2, 0x46, 0xEF, 0x18, 0xEF, 0xE7, 0x6C, 0x6E, 0x32, 0x29, 0x18,
    0x80, 0xE6, 0xA0, 0x48, 0xAA, 0x44, 0x4D, 0x17, 0x64, 0x78, 0x4D, 0x5A,
    0x02, 0x62, 0xB0, 0xA5, 0xAF, 0xEF, 0x10, 0x5B, 0xB6, 0x27, 0x83, 0xAA,
    0xD4, 0x08, 0xAF, 0xF8, 0x3D, 0x86, 0x73, 0xB1, 0xB4, 0xE1, 0xC3, 0xAC,
    0x75, 0xCF, 0xBA, 0x3F, 0xE3, 0x7D, 0x10, 0x4B, 0xFB, 0xD2, 0xFD, 0x11,
    0xDC, 0xD0, 0x38, 0xBE, 0x0D, 0xE0, 0x4C, 0x17, 0x0E, 0xDF, 0x0C, 0x70,
    0x9C, 0x96, 0x40, 0x4B, 0xB1, 0xB0, 0x50, 0x93, 0x9C, 0xAE, 0xA0, 0xB5,
    0x70, 0x06, 0x90, 0x91, 0xCE, 0x4D, 0x47, 0x49, 0x54, 0xC7, 0x49, 0x4C,
    0xCE, 0x05, 0x96, 0x0C, 0x34, 0xB9, 0xA8, 0xA5, 0xFE, 0x63, 0x02, 0x14,
    0xEC, 0xA1, 0x10, 0x8B, 0x28, 0x6A, 0x43, 0xBE, 0x2B, 0x91, 0xFE, 0xA1,
    0xC5, 0x0C, 0x9F, 0x7A, 0xC6, 0x81, 0xC6, 0xAC, 0x42, 0x65, 0x99, 0x22,
    0x91, 0xBC, 0x01, 0x1E, 0x50, 0xD9, 0xC2, 0x83, 0xDF, 0xC2, 0x77, 0xEB,
    0x57, 0x85, 0xF8, 0xFF, 0x1C, 0xA8, 0xDD, 0xCA, 0x82, 0xA9, 0xB8, 0x5F,
    0x14, 0x59, 0x47, 0x38, 0x05, 0xE2, 0xB2, 0xCC, 0xF5, 0xE3, 0x0B, 0x13,
    0x3E, 0x1E, 0x17, 0x42, 0xE9, 0xA3, 0xE5, 0x16, 0x52, 0x9F, 0x08, 0xFC,
    0x80, 0x62, 0xB6, 0xC6, 0x8B, 0xBD, 0x1F, 0xDC, 0x0C, 0xAF, 0x0B, 0x99,
    0xD9, 0xE0, 0x13, 0xFF, 0x72, 0xF7, 0x3A, 0xD6, 0xC8, 0xAF, 0xF4, 0xB3,
    0x09, 0xBA, 0x7C, 0x63, 0xDE, 0x53, 0xCF, 0xC1, 0x60, 0x9A, 0xB2, 0x57,
    0xBF, 0x28, 0x0C, 0x54, 0xED, 0x71, 0xBF, 0xBE, 0xCF, 0x03, 0x50, 0xF3,
    0x13, 0xD4, 0x8B, 0x88, 0xBC, 0x81, 0xE9, 0x32, 0xFC, 0x96, 0xCC, 0x45,
    0x43, 0x56, 0x45, 0xD8, 0x3F, 0x09, 0x86, 0x90, 0xDE, 0x20, 0xFA, 0x63,
    0x2F, 0x49, 0x36, 0xBD, 0x3A, 0xE6, 0x0A, 0x01, 0x0D, 0x27, 0xEB, 0x42,
    0x73, 0x49, 0xE0, 0x64, 0xEE, 0x79, 0x66, 0x04, 0x5B, 0xA3, 0x57, 0xDB,
    0x07, 0xF4, 0x54, 0x7E, 0x44, 0xD1, 0x80, 0x42, 0x85, 0xF5, 0x69, 0x89,
    0x62, 0x79, 0x57, 0x51, 0x5A, 0x21, 0xEF, 0xB9, 0x19, 0xD1, 0xC7, 0x3D,
    0x63, 0xE2, 0xAC, 0xB9, 0xE1, 0x19, 0xA7, 0x5C, 0x28, 0x49, 0x3C, 0xB0,
    0x25, 0xBD, 0xED, 0x73, 0xF8, 0xD7, 0x79, 0x11, 0x92, 0x99, 0xC6, 0x96,
    0x7B, 0xAA, 0x5A, 0xD0, 0x37, 0x1F, 0x33, 0x9D, 0x1C, 0xA1, 0x5D, 0x32,
    0xE2, 0x5C, 0x35, 0x79, 0xD9, 0xC4, 0x57, 0x7C, 0xE4, 0x03, 0x5A, 0xF8,
    0xCD, 0x5B, 0x54, 0x07, 0x0F, 0x17, 0xBE, 0xBF, 0x46, 0x29, 0xC3, 0x5F,
    0x59, 0xD9, 0xAA, 0x80, 0x82, 0x4A, 0xB1, 0x0A, 0xDA, 0xAB, 0xA5, 0x82,
    0x78, 0x8C, 0x42, 0x3C, 0xF2, 0x70, 0xEF, 0x4F, 0x3E, 0xFD, 0x11, 0x11,
    0x40, 0x1A, 0x14, 0xA1, 0xB5, 0xC8, 0xE3, 0xE2, 0x5A, 0xB7, 0x0F, 0xF3,
    0x5E, 0x25, 0x7D, 0x4A, 0x3A, 0xE3, 0x2B, 0xD9, 0xC9, 0xE0, 0x7D, 0x58,
    0x2B, 0x23, 0xA3, 0xCB, 0x3D, 0xD2, 0x01, 0xB7, 0x98, 0xAE, 0x07, 0x60,
    0xAD, 0x31, 0xAF, 0x90, 0x44, 0xC2, 0x3C, 0x00, 0x0B, 0x6F, 0xEE, 0x11,
    0x83, 0x51, 0x47, 0xCA, 0x64, 0x8C, 0x7C, 0x3A, 0xAE, 0xC0, 0xEB, 0x01,
    0xEB, 0x73, 0x1D, 0x97, 0xAD, 0xC3, 0x22, 0x42, 0x69, 0x89, 0xC0, 0x3A,
    0x09, 0x8E, 0xB2, 0x93, 0xF2, 0xE0, 0x38, 0x00, 0xD0, 0xCC, 0x48, 0xA9,
    0x8D, 0xC7, 0x4A, 0xAB, 0x34, 0x0E, 0x8E, 0x56, 0xF8, 0x86, 0xC4, 0x19,
    0xC4, 0xDF, 0x37, 0x93, 0x31, 0x89, 0x89, 0x60, 0x74, 0xA9, 0x93, 0x8B,
    0x5D, 0x52, 0xEB, 0x19, 0x73, 0xF8, 0xC5, 0x16, 0x12, 0xD9, 0xB5, 0x05,
    0x07, 0x44, 0xFC, 0xA6, 0x89, 0xF4, 0x2B, 0x9A, 0xAC, 0x67, 0xDA, 0x0A,
    0x29, 0xFF, 0x87, 0x65, 0xA1, 0xCC, 0x62, 0x49, 0xE2, 0xE3, 0x71, 0x1F,
    0xF4, 0x84, 0x40, 0xD2, 0xA7, 0x83, 0x97, 0x81, 0x5F, 0x02, 0xEA, 0x40,
    0x90, 0xBD, 0x25, 0x2E, 0x70, 0x63, 0x80, 0x64, 0x47, 0x73, 0xAA, 0xCC,
    0x07, 0x2E, 0x2A, 0x2F, 0x5F, 0x31, 0x46, 0x34, 0xED, 0x47, 0xD8, 0x6C,
    0x9F, 0x86, 0x7F, 0xA5, 0x88, 0x48, 0x82, 0xA3, 0x26, 0xDD, 0x01, 0x15,
    0x90, 0xAF, 0xDA, 0x3A, 0x04, 0xCE, 0x97, 0x05, 0xC7, 0x74, 0x8C, 0x2E,
    0xF8, 0x7B, 0xF3, 0xC7, 0x46, 0x3F, 0x06, 0x03, 0x1D, 0x09, 0x94, 0xA5,
    0xAE, 0xCA, 0x4F, 0x6D, 0x00, 0x43, 0x82, 0xB9, 0x56, 0xCE, 0xBF, 0x8F,
    0x8D, 0xC8, 0xC4, 0xBC, 0x37, 0xF7, 0x2D, 0x88, 0xFD, 0xC2, 0x1B, 0x51,
    0x24, 0xFE, 0x5C, 0x5D, 0x5C, 0x62, 0x62, 0xA8, 0xBF, 0x4A, 0x90, 0xA4,
    0x1A, 0x1C, 0xB8, 0xED, 0x17, 0xCD, 0x61, 0xF9, 0x24, 0x26, 0xCF, 0xE0,
    0x6E, 0x88, 0xE5, 0x3B, 0xF9, 0x43, 0xBC, 0xCF, 0x28, 0xA3, 0xE5, 0xCF,
    0x8B, 0x6D, 0xB3, 0x00, 0xDE, 0xB2, 0x14, 0xBB, 0xB1, 0xAF, 0xAE, 0x65,
    0x25, 0x92, 0xBB, 0x40, 0x8B, 0xDA, 0x6C, 0x7B, 0xD3, 0x90, 0x42, 0x0D,
    0xC2, 0x6A, 0x67, 0x59, 0xC4, 0x47, 0xF8, 0xCC, 0x1C, 0x15, 0x93, 0xB7,
    0xC8, 0xAB, 0x7A, 0x97, 0x16, 0x3B, 0x9C, 0x95, 0xAE, 0x5B, 0x98, 0x61,
    0xF0, 0xEE, 0xE4, 0xE3, 0xFA, 0x0D, 0xD2, 0x93, 0x5D, 0x1A, 0xDB, 0xF5,
    0xFF, 0x65, 0xE0, 0x5C, 0x53, 0x82, 0x44, 0x44, 0x38, 0x09, 0xC3, 0xE7,
    0x66, 0x6F, 0xEF, 0x5D, 0x42, 0xCB, 0x08, 0x28, 0x7B, 0xA0, 0xFF, 0x91,
    0xCA, 0x49, 0x67, 0xC3, 0x27, 0x9D, 0xBD, 0xF7, 0x92, 0x7D, 0x8E, 0x25,
    0xA6, 0x57, 0x70, 0xC8, 0x70, 0x88, 0xB1, 0x8C, 0x98, 0x99, 0xF6, 0x47,
    0x33, 0x0D, 0xF6, 0xCE, 0xA1, 0xF9, 0x8C, 0x29, 0xD2, 0xC5, 0x90, 0x38,
    0x7C, 0x70, 0x6B, 0x6E, 0x5A, 0xF8, 0x32, 0x3F, 0xF9, 0x8F, 0x21, 0xCB,
    0x50, 0x5E, 0x71, 0x1A, 0xC2, 0x5D, 0x9B, 0x94, 0x6D, 0x0D, 0xFC, 0x09,
    0x59, 0xEE, 0x8D, 0x7A, 0x53, 0xBF, 0x90, 0x93, 0x2C, 0xDF, 0x95, 0x23,
    0x03, 0xA7, 0x61, 0x48, 0xE7, 0xC7, 0x12, 0x4C, 0x3B, 0xDC, 0xCE, 0x4F,
    0x8D, 0xC4, 0x68, 0xD4, 0xEB, 0x58, 0x64, 0x6B, 0xB5, 0xF7, 0x1D, 0x90,
    0x82, 0xE8, 0x48, 0x2E, 0x96, 0x71, 0xB8, 0x0B, 0xCD, 0xB4, 0xBA, 0x4E,
    0xB7, 0xCF, 0x33, 0xDC, 0xFB, 0x6C, 0xC4, 0x0E, 0x85, 0x73, 0x40, 0x46,
    0xA5, 0x05, 0xCF, 0x25, 0x36, 0x30, 0xB5, 0x78, 0x8F, 0x7F, 0x59, 0x63,
    0x7D, 0x47, 0x79, 0x28, 0x5B, 0x0F, 0xA2, 0x13, 0xC9, 0x38, 0x81, 0x09,
    0x01, 0xA1, 0x47, 0x2F, 0x71, 0x93, 0xC2, 0x65, 0x85, 0xB4, 0xAD, 0x5D,
    0x1E, 0x87, 0xCF, 0x42, 0xE9, 0x22, 0x39, 0x36, 0xFA, 0xA4, 0x2E, 0xB2,
    0x2A, 0x53, 0x3F, 0xCC, 0x65, 0x8B, 0x3B, 0x2C, 0xD3, 0x33, 0x8A, 0x8F,
    0x52, 0xFB, 0x94, 0x4B, 0x08, 0x35, 0x51, 0x8F, 0x06, 0xA6, 0x50, 0x9E,
    0xAA, 0x10, 0x89, 0x35, 0x38, 0x9E, 0x36, 0x6C, 0x98, 0xEF, 0x4B, 0xF3,
    0x1B, 0x60, 0x96, 0x72, 0x8B, 0x40, 0xC1, 0x13, 0xDE, 0x55, 0xBA, 0x5A,
    0xE0, 0xC1, 0x16, 0x45, 0x71, 0xDF, 0xF5, 0xFB, 0x78, 0x31, 0xAC, 0x1B,
    0xAA, 0x7D, 0x89, 0xE3, 0xC8, 0x96, 0xE1, 0x98, 0x21, 0xF3, 0x6B, 0xC5,
    0x1C, 0xD6, 0x1C, 0x19, 0x18, 0xCA, 0x44, 0x9A, 0x8B, 0xCE, 0x9E, 0x15,
    0x06, 0x7F, 0xEA, 0xA5, 0x16, 0x97, 0xF9, 0xA5, 0x84, 0xB1, 0xD5, 0xEA,
    0xE2, 0xC8, 0x51, 0x80, 0x53, 0x80, 0x38, 0xAC, 0x90, 0x34, 0xC7, 0xB1,
    0x19, 0x9C, 0x9D, 0xF5, 0xA9, 0xA4, 0x6E, 0x5A, 0xA3, 0x10, 0xE3, 0x84,
    0xCF, 0x3C, 0x4F, 0x51, 0xD9, 0xAD, 0xF2, 0x4F, 0x90, 0x12, 0x6F, 0x89,
    0x0B, 0xCD, 0x0D, 0x47, 0x6B, 0x2F, 0xD6, 0x6C, 0x3C, 0xD0, 0xFA, 0x94,
    0xFE, 0x18, 0xAC, 0xE7, 0x35, 0x09, 0xD4, 0x08, 0xF8, 0xB7, 0x39, 0x05,
    0x7E, 0x2E, 0x23, 0xCB, 0x69, 0xCF, 0x36, 0xF5, 0x52, 0xA6, 0x35, 0xA2,
    0x00, 0x8E, 0x9C, 0xA5, 0x9B, 0x1B, 0x76, 0x17, 0x61, 0xF6, 0x26, 0xB2,
    0x8A, 0x3E, 0x18, 0x75, 0x08, 0x37, 0x1C, 0x1D, 0xB4, 0xFB, 0x52, 0xBD,
    0x55, 0xC1, 0x67, 0x4E, 0x60, 0x6A, 0x2C, 0xA8, 0x81, 0x6C, 0x6D, 0xA8,
    0xE2, 0x85, 0xF6, 0xA0, 0xD3, 0xC4, 0xF5, 0x5A, 0xF7, 0x1F, 0xD6, 0x3C,
    0x61, 0xA5, 0x68, 0x79, 0x45, 0x3E, 0x2A, 0x2A, 0xA8, 0xE6,
};

// kPKCS7Windows is the Equifax root certificate, as exported by Windows 7.
static const uint8_t kPKCS7Windows[] = {
    0x30, 0x82, 0x02, 0xb1, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
    0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xa2, 0x30, 0x82, 0x02, 0x9e, 0x02,
    0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
    0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, 0x02, 0x86, 0x30, 0x82, 0x02,
    0x82, 0x30, 0x82, 0x01, 0xeb, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01,
    0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
    0x01, 0x04, 0x05, 0x00, 0x30, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
    0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x1c, 0x30, 0x1a, 0x06,
    0x03, 0x55, 0x04, 0x0a, 0x13, 0x13, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61,
    0x78, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x49, 0x6e, 0x63,
    0x2e, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1d,
    0x45, 0x71, 0x75, 0x69, 0x66, 0x61, 0x78, 0x20, 0x53, 0x65, 0x63, 0x75,
    0x72, 0x65, 0x20, 0x65, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73,
    0x20, 0x43, 0x41, 0x2d, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x39, 0x39, 0x30,
    0x36, 0x32, 0x31, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d,
    0x32, 0x30, 0x30, 0x36, 0x32, 0x31, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30,
    0x5a, 0x30, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
    0x13, 0x02, 0x55, 0x53, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04,
    0x0a, 0x13, 0x13, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61, 0x78, 0x20, 0x53,
    0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x26,
    0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1d, 0x45, 0x71, 0x75,
    0x69, 0x66, 0x61, 0x78, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20,
    0x65, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x20, 0x43, 0x41,
    0x2d, 0x31, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
    0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00,
    0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xce, 0x2f, 0x19, 0xbc, 0x17,
    0xb7, 0x77, 0xde, 0x93, 0xa9, 0x5f, 0x5a, 0x0d, 0x17, 0x4f, 0x34, 0x1a,
    0x0c, 0x98, 0xf4, 0x22, 0xd9, 0x59, 0xd4, 0xc4, 0x68, 0x46, 0xf0, 0xb4,
    0x35, 0xc5, 0x85, 0x03, 0x20, 0xc6, 0xaf, 0x45, 0xa5, 0x21, 0x51, 0x45,
    0x41, 0xeb, 0x16, 0x58, 0x36, 0x32, 0x6f, 0xe2, 0x50, 0x62, 0x64, 0xf9,
    0xfd, 0x51, 0x9c, 0xaa, 0x24, 0xd9, 0xf4, 0x9d, 0x83, 0x2a, 0x87, 0x0a,
    0x21, 0xd3, 0x12, 0x38, 0x34, 0x6c, 0x8d, 0x00, 0x6e, 0x5a, 0xa0, 0xd9,
    0x42, 0xee, 0x1a, 0x21, 0x95, 0xf9, 0x52, 0x4c, 0x55, 0x5a, 0xc5, 0x0f,
    0x38, 0x4f, 0x46, 0xfa, 0x6d, 0xf8, 0x2e, 0x35, 0xd6, 0x1d, 0x7c, 0xeb,
    0xe2, 0xf0, 0xb0, 0x75, 0x80, 0xc8, 0xa9, 0x13, 0xac, 0xbe, 0x88, 0xef,
    0x3a, 0x6e, 0xab, 0x5f, 0x2a, 0x38, 0x62, 0x02, 0xb0, 0x12, 0x7b, 0xfe,
    0x8f, 0xa6, 0x03, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x66, 0x30, 0x64,
    0x30, 0x11, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01,
    0x01, 0x04, 0x04, 0x03, 0x02, 0x00, 0x07, 0x30, 0x0f, 0x06, 0x03, 0x55,
    0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
    0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80,
    0x14, 0x4a, 0x78, 0x32, 0x52, 0x11, 0xdb, 0x59, 0x16, 0x36, 0x5e, 0xdf,
    0xc1, 0x14, 0x36, 0x40, 0x6a, 0x47, 0x7c, 0x4c, 0xa1, 0x30, 0x1d, 0x06,
    0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x4a, 0x78, 0x32, 0x52,
    0x11, 0xdb, 0x59, 0x16, 0x36, 0x5e, 0xdf, 0xc1, 0x14, 0x36, 0x40, 0x6a,
    0x47, 0x7c, 0x4c, 0xa1, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
    0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x75,
    0x5b, 0xa8, 0x9b, 0x03, 0x11, 0xe6, 0xe9, 0x56, 0x4c, 0xcd, 0xf9, 0xa9,
    0x4c, 0xc0, 0x0d, 0x9a, 0xf3, 0xcc, 0x65, 0x69, 0xe6, 0x25, 0x76, 0xcc,
    0x59, 0xb7, 0xd6, 0x54, 0xc3, 0x1d, 0xcd, 0x99, 0xac, 0x19, 0xdd, 0xb4,
    0x85, 0xd5, 0xe0, 0x3d, 0xfc, 0x62, 0x20, 0xa7, 0x84, 0x4b, 0x58, 0x65,
    0xf1, 0xe2, 0xf9, 0x95, 0x21, 0x3f, 0xf5, 0xd4, 0x7e, 0x58, 0x1e, 0x47,
    0x87, 0x54, 0x3e, 0x58, 0xa1, 0xb5, 0xb5, 0xf8, 0x2a, 0xef, 0x71, 0xe7,
    0xbc, 0xc3, 0xf6, 0xb1, 0x49, 0x46, 0xe2, 0xd7, 0xa0, 0x6b, 0xe5, 0x56,
    0x7a, 0x9a, 0x27, 0x98, 0x7c, 0x46, 0x62, 0x14, 0xe7, 0xc9, 0xfc, 0x6e,
    0x03, 0x12, 0x79, 0x80, 0x38, 0x1d, 0x48, 0x82, 0x8d, 0xfc, 0x17, 0xfe,
    0x2a, 0x96, 0x2b, 0xb5, 0x62, 0xa6, 0xa6, 0x3d, 0xbd, 0x7f, 0x92, 0x59,
    0xcd, 0x5a, 0x2a, 0x82, 0xb2, 0x37, 0x79, 0x31, 0x00,
};


// kPKCS7SignedWithSignerInfo has content SignedData, but unlike other test
// objects, it contains SignerInfos as well.
static const uint8_t kPKCS7SignedWithSignerInfo[]{
    0x30, 0x82, 0x03, 0x54, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
    0x01, 0x07, 0x02, 0xa0, 0x82, 0x03, 0x45, 0x30, 0x82, 0x03, 0x41, 0x02,
    0x01, 0x01, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
    0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x30, 0x82, 0x00, 0x25, 0x06,
    0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82,
    0x00, 0x16, 0x04, 0x82, 0x00, 0x12, 0x49, 0x6e, 0x69, 0x7a, 0x69, 0x6f,
    0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x75, 0x74, 0x6f, 0x2e, 0x0a,
    0xa0, 0x82, 0x01, 0x72, 0x30, 0x82, 0x01, 0x6e, 0x30, 0x82, 0x01, 0x14,
    0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x60, 0x5c, 0xd2, 0xd5, 0x26,
    0x75, 0xb3, 0x92, 0xa5, 0xaa, 0x9b, 0x02, 0xb2, 0x6a, 0x55, 0x66, 0x30,
    0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30,
    0x0f, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x04,
    0x54, 0x65, 0x73, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x37,
    0x31, 0x36, 0x31, 0x34, 0x35, 0x36, 0x33, 0x35, 0x5a, 0x17, 0x0d, 0x31,
    0x39, 0x30, 0x37, 0x31, 0x36, 0x31, 0x34, 0x35, 0x36, 0x33, 0x35, 0x5a,
    0x30, 0x0f, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
    0x04, 0x54, 0x65, 0x73, 0x74, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a,
    0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce,
    0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x24, 0x4c, 0xb6, 0xcc,
    0x1c, 0x69, 0x21, 0xff, 0x49, 0xd8, 0xbe, 0x26, 0x3e, 0x0b, 0x7c, 0xd0,
    0x5a, 0x28, 0x65, 0x5a, 0x84, 0x6c, 0x82, 0x5e, 0xca, 0xe6, 0xec, 0xe6,
    0x9a, 0x6a, 0x21, 0xc4, 0xe4, 0xf2, 0x20, 0x24, 0xc0, 0xe9, 0xf4, 0xe4,
    0x74, 0x9c, 0x98, 0xa1, 0xad, 0xf2, 0x5f, 0x90, 0xde, 0x6e, 0xf9, 0x48,
    0x2b, 0x67, 0x18, 0x83, 0xa7, 0x0e, 0xb4, 0xb7, 0xab, 0x9f, 0x06, 0x43,
    0xa3, 0x52, 0x30, 0x50, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
    0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x04, 0xf0, 0x30, 0x1d, 0x06, 0x03,
    0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xc3, 0xc0, 0x84, 0xdf, 0x7b,
    0x04, 0x0d, 0xb0, 0x38, 0xaf, 0x51, 0x8c, 0xe3, 0x97, 0xf6, 0xec, 0x20,
    0xd6, 0x26, 0xe6, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
    0x30, 0x16, 0x80, 0x14, 0xc3, 0xc0, 0x84, 0xdf, 0x7b, 0x04, 0x0d, 0xb0,
    0x38, 0xaf, 0x51, 0x8c, 0xe3, 0x97, 0xf6, 0xec, 0x20, 0xd6, 0x26, 0xe6,
    0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
    0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0xde, 0x60, 0x1e, 0x57,
    0x3d, 0xaf, 0xb5, 0x9b, 0xc5, 0x51, 0xd5, 0x8e, 0x3e, 0x7b, 0x9e, 0xda,
    0x06, 0x12, 0xdd, 0x01, 0x12, 0x80, 0x5a, 0x22, 0x17, 0xb7, 0x34, 0x75,
    0x9b, 0x88, 0x44, 0x17, 0x02, 0x20, 0x67, 0xc3, 0xfd, 0xe6, 0x07, 0x80,
    0xd4, 0x1c, 0x1d, 0x7a, 0x3b, 0x90, 0x29, 0x1f, 0x3d, 0x39, 0xc4, 0xdc,
    0x2f, 0x20, 0x6d, 0xcc, 0xba, 0x2f, 0x98, 0x2c, 0x06, 0xb6, 0x7c, 0x09,
    0xb2, 0x32, 0x31, 0x82, 0x01, 0x8a, 0x30, 0x82, 0x01, 0x86, 0x02, 0x01,
    0x01, 0x30, 0x23, 0x30, 0x0f, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55,
    0x04, 0x03, 0x0c, 0x04, 0x54, 0x65, 0x73, 0x74, 0x02, 0x10, 0x60, 0x5c,
    0xd2, 0xd5, 0x26, 0x75, 0xb3, 0x92, 0xa5, 0xaa, 0x9b, 0x02, 0xb2, 0x6a,
    0x55, 0x66, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
    0x04, 0x02, 0x01, 0x05, 0x00, 0xa0, 0x81, 0xf7, 0x30, 0x18, 0x06, 0x09,
    0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x03, 0x31, 0x0b, 0x06,
    0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x30, 0x1c,
    0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x05, 0x31,
    0x0f, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x37, 0x31, 0x36, 0x31, 0x34, 0x35,
    0x36, 0x33, 0x35, 0x5a, 0x30, 0x2a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
    0xf7, 0x0d, 0x01, 0x09, 0x34, 0x31, 0x1d, 0x30, 0x1b, 0x30, 0x0d, 0x06,
    0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00,
    0xa1, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
    0x30, 0x2f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09,
    0x04, 0x31, 0x22, 0x04, 0x20, 0x72, 0x4c, 0x51, 0xbb, 0xe7, 0x6d, 0xa0,
    0x5a, 0xfb, 0x20, 0xcb, 0xe8, 0xeb, 0x03, 0x7c, 0xda, 0xe1, 0xaf, 0xd7,
    0x13, 0x12, 0x5d, 0x2d, 0xc1, 0x3d, 0x55, 0x2d, 0xa9, 0xf4, 0x42, 0xd2,
    0x4d, 0x30, 0x60, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
    0x09, 0x10, 0x02, 0x2f, 0x31, 0x51, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x4b,
    0x04, 0x20, 0xba, 0xbc, 0x08, 0x43, 0x4c, 0x58, 0x26, 0x73, 0x01, 0xe0,
    0x06, 0x86, 0x1d, 0x27, 0xec, 0xa1, 0x25, 0x67, 0x0e, 0x79, 0x27, 0x97,
    0x24, 0x8e, 0x76, 0xa5, 0x71, 0x7a, 0x5b, 0xf9, 0x93, 0xc2, 0x30, 0x27,
    0x30, 0x13, 0xa4, 0x11, 0x30, 0x0f, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03,
    0x55, 0x04, 0x03, 0x0c, 0x04, 0x54, 0x65, 0x73, 0x74, 0x02, 0x10, 0x60,
    0x5c, 0xd2, 0xd5, 0x26, 0x75, 0xb3, 0x92, 0xa5, 0xaa, 0x9b, 0x02, 0xb2,
    0x6a, 0x55, 0x66, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
    0x04, 0x03, 0x02, 0x04, 0x47, 0x30, 0x45, 0x02, 0x21, 0x00, 0xf1, 0x04,
    0x30, 0x2e, 0xab, 0xb4, 0x28, 0xec, 0xc8, 0xe7, 0x1c, 0xe2, 0xe3, 0x8f,
    0x6c, 0xbe, 0xd8, 0x48, 0xa8, 0xe9, 0xa2, 0xb5, 0xd5, 0xda, 0x19, 0x93,
    0x3e, 0x48, 0x5c, 0x83, 0xcc, 0x71, 0x02, 0x20, 0x0c, 0xbb, 0x40, 0xa0,
    0xb7, 0xb9, 0xb2, 0xe0, 0x48, 0x92, 0x06, 0x22, 0xfb, 0x28, 0x6f, 0xd1,
    0x46, 0x95, 0xf2, 0x4c, 0xf6, 0x50, 0xbd, 0xaa, 0x40, 0xb8, 0x85, 0xf8,
    0x4c, 0x34, 0xbb, 0xb9,
};

// kOpenSSLCRL is the Equifax CRL, converted to PKCS#7 form by:
//   openssl crl2pkcs7 -inform DER -in secureca.crl
static const uint8_t kOpenSSLCRL[] = {
    0x30, 0x82, 0x03, 0x85, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
    0x01, 0x07, 0x02, 0xa0, 0x82, 0x03, 0x76, 0x30, 0x82, 0x03, 0x72, 0x02,
    0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
    0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x00, 0xa1, 0x82, 0x03, 0x58, 0x30,
    0x82, 0x03, 0x54, 0x30, 0x82, 0x02, 0xbd, 0x30, 0x0d, 0x06, 0x09, 0x2a,
    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x4e,
    0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
    0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07,
    0x45, 0x71, 0x75, 0x69, 0x66, 0x61, 0x78, 0x31, 0x2d, 0x30, 0x2b, 0x06,
    0x03, 0x55, 0x04, 0x0b, 0x13, 0x24, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61,
    0x78, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72,
    0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74,
    0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x32,
    0x32, 0x37, 0x30, 0x31, 0x32, 0x33, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31,
    0x35, 0x30, 0x33, 0x30, 0x39, 0x30, 0x31, 0x32, 0x33, 0x30, 0x30, 0x5a,
    0x30, 0x82, 0x02, 0x3c, 0x30, 0x14, 0x02, 0x03, 0x0f, 0x58, 0xe4, 0x17,
    0x0d, 0x31, 0x34, 0x30, 0x34, 0x32, 0x37, 0x30, 0x38, 0x31, 0x39, 0x32,
    0x32, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x14, 0x76, 0x19, 0x17, 0x0d, 0x31,
    0x34, 0x30, 0x36, 0x31, 0x38, 0x31, 0x35, 0x30, 0x30, 0x30, 0x33, 0x5a,
    0x30, 0x14, 0x02, 0x03, 0x0f, 0x9a, 0xfb, 0x17, 0x0d, 0x31, 0x34, 0x30,
    0x34, 0x32, 0x39, 0x31, 0x38, 0x30, 0x39, 0x31, 0x37, 0x5a, 0x30, 0x14,
    0x02, 0x03, 0x14, 0x8b, 0xc0, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x37, 0x30,
    0x39, 0x31, 0x39, 0x34, 0x36, 0x33, 0x33, 0x5a, 0x30, 0x14, 0x02, 0x03,
    0x14, 0xe4, 0x9c, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x34, 0x31, 0x36, 0x32,
    0x33, 0x33, 0x39, 0x33, 0x35, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x0f, 0x86,
    0x07, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x35, 0x32, 0x31, 0x31, 0x35, 0x35,
    0x30, 0x35, 0x33, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x12, 0xe2, 0x29, 0x17,
    0x0d, 0x31, 0x34, 0x30, 0x36, 0x31, 0x37, 0x31, 0x38, 0x35, 0x35, 0x31,
    0x35, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x0d, 0x42, 0x66, 0x17, 0x0d, 0x31,
    0x32, 0x30, 0x36, 0x32, 0x37, 0x31, 0x37, 0x31, 0x30, 0x35, 0x33, 0x5a,
    0x30, 0x14, 0x02, 0x03, 0x03, 0x1e, 0x33, 0x17, 0x0d, 0x30, 0x32, 0x30,
    0x35, 0x31, 0x35, 0x31, 0x33, 0x30, 0x36, 0x31, 0x31, 0x5a, 0x30, 0x14,
    0x02, 0x03, 0x12, 0xe2, 0x23, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x36, 0x30,
    0x36, 0x32, 0x30, 0x34, 0x30, 0x32, 0x31, 0x5a, 0x30, 0x14, 0x02, 0x03,
    0x13, 0x9c, 0xab, 0x17, 0x0d, 0x31, 0x30, 0x30, 0x37, 0x32, 0x39, 0x31,
    0x36, 0x34, 0x34, 0x33, 0x39, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x12, 0xc6,
    0x0a, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x36, 0x30, 0x36, 0x32, 0x32, 0x32,
    0x31, 0x33, 0x39, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x03, 0x25, 0x85, 0x17,
    0x0d, 0x30, 0x32, 0x30, 0x35, 0x31, 0x34, 0x31, 0x38, 0x31, 0x31, 0x35,
    0x37, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x14, 0x86, 0xe6, 0x17, 0x0d, 0x31,
    0x34, 0x30, 0x37, 0x32, 0x35, 0x30, 0x32, 0x30, 0x30, 0x33, 0x38, 0x5a,
    0x30, 0x14, 0x02, 0x03, 0x13, 0x9c, 0xa1, 0x17, 0x0d, 0x31, 0x30, 0x30,
    0x37, 0x32, 0x39, 0x31, 0x36, 0x34, 0x37, 0x33, 0x32, 0x5a, 0x30, 0x14,
    0x02, 0x03, 0x15, 0x4d, 0x5c, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x34, 0x33,
    0x30, 0x30, 0x30, 0x30, 0x34, 0x34, 0x32, 0x5a, 0x30, 0x14, 0x02, 0x03,
    0x0f, 0xfa, 0x2d, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x36, 0x31, 0x37, 0x31,
    0x38, 0x35, 0x30, 0x31, 0x31, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x13, 0x75,
    0x55, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x31, 0x31, 0x38, 0x30, 0x32, 0x32,
    0x31, 0x33, 0x33, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x0f, 0x56, 0x96, 0x17,
    0x0d, 0x31, 0x34, 0x30, 0x36, 0x32, 0x34, 0x31, 0x32, 0x33, 0x31, 0x30,
    0x32, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x0b, 0x80, 0x8a, 0x17, 0x0d, 0x31,
    0x32, 0x30, 0x36, 0x32, 0x37, 0x31, 0x37, 0x31, 0x30, 0x32, 0x35, 0x5a,
    0x30, 0x14, 0x02, 0x03, 0x0f, 0x94, 0x16, 0x17, 0x0d, 0x31, 0x30, 0x30,
    0x33, 0x30, 0x31, 0x31, 0x33, 0x34, 0x35, 0x33, 0x31, 0x5a, 0x30, 0x14,
    0x02, 0x03, 0x14, 0x16, 0xb3, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x36, 0x31,
    0x38, 0x31, 0x34, 0x33, 0x32, 0x35, 0x36, 0x5a, 0x30, 0x14, 0x02, 0x03,
    0x0a, 0xe1, 0x85, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x36, 0x32, 0x37, 0x31,
    0x37, 0x31, 0x30, 0x31, 0x37, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x14, 0xcc,
    0x3e, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x37, 0x31, 0x31, 0x31, 0x32, 0x35,
    0x35, 0x33, 0x31, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x10, 0x5b, 0xcb, 0x17,
    0x0d, 0x31, 0x30, 0x30, 0x37, 0x33, 0x30, 0x32, 0x31, 0x33, 0x31, 0x32,
    0x30, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x15, 0x6a, 0x1f, 0x17, 0x0d, 0x31,
    0x34, 0x30, 0x32, 0x32, 0x36, 0x31, 0x32, 0x33, 0x35, 0x31, 0x39, 0x5a,
    0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
    0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x1d, 0x5c, 0x27, 0x07, 0x11,
    0x03, 0xf2, 0x00, 0xbd, 0xf4, 0x46, 0x3e, 0x71, 0xfd, 0x10, 0x84, 0x83,
    0xd9, 0xd2, 0xd2, 0x19, 0xa0, 0x20, 0xf7, 0x1a, 0x43, 0x3d, 0xac, 0xda,
    0x33, 0xfc, 0xb7, 0x42, 0x60, 0x1a, 0xa4, 0xa8, 0xb2, 0x07, 0x5c, 0x51,
    0x16, 0xc0, 0x42, 0x80, 0x0a, 0x0f, 0xf0, 0x47, 0x5b, 0x4b, 0x78, 0x90,
    0xaf, 0xc7, 0xac, 0x48, 0xf8, 0xca, 0x3c, 0x13, 0x5e, 0xf6, 0xd1, 0x88,
    0xae, 0x55, 0xa3, 0x0c, 0x8a, 0x62, 0x47, 0x29, 0xf8, 0x72, 0xb8, 0x24,
    0x17, 0xaf, 0xb2, 0x06, 0x1e, 0xa7, 0x72, 0x76, 0xab, 0x96, 0x1d, 0xe0,
    0x7c, 0xd4, 0x0c, 0x42, 0x82, 0x3d, 0x4a, 0x8e, 0x15, 0x77, 0x2f, 0x3c,
    0x2a, 0x8c, 0x3a, 0x04, 0x10, 0x55, 0xdc, 0xbb, 0xba, 0xb1, 0x91, 0xee,
    0x7b, 0xe7, 0x23, 0xc5, 0x71, 0x13, 0xae, 0x6b, 0x21, 0x35, 0xd3, 0x64,
    0xf0, 0x00, 0x54, 0x31, 0x00,
};

// kPEMCert is the result of exporting the mail.google.com certificate from
// Chrome and then running it through:
//   openssl pkcs7 -inform DER -in mail.google.com -outform PEM
static const char kPEMCert[] =
    "-----BEGIN PKCS7-----\n"
    "MIID+wYJKoZIhvcNAQcCoIID7DCCA+gCAQExADALBgkqhkiG9w0BBwGgggPQMIID\n"
    "zDCCArSgAwIBAgIIWesoywKxoNQwDQYJKoZIhvcNAQELBQAwSTELMAkGA1UEBhMC\n"
    "VVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRlcm5l\n"
    "dCBBdXRob3JpdHkgRzIwHhcNMTUwMjExMTQxNTA2WhcNMTUwNTEyMDAwMDAwWjBp\n"
    "MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91\n"
    "bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEYMBYGA1UEAwwPbWFpbC5n\n"
    "b29nbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7MdALmCkcRRf/tzQ\n"
    "a8eu3J7S5CTQa5ns0ReF9ktlbB1RL56BVGAu4p7BrT32D6gDpiggXq3gxN81A0TG\n"
    "C2yICKOCAWEwggFdMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAsBgNV\n"
    "HREEJTAjgg9tYWlsLmdvb2dsZS5jb22CEGluYm94Lmdvb2dsZS5jb20wCwYDVR0P\n"
    "BAQDAgeAMGgGCCsGAQUFBwEBBFwwWjArBggrBgEFBQcwAoYfaHR0cDovL3BraS5n\n"
    "b29nbGUuY29tL0dJQUcyLmNydDArBggrBgEFBQcwAYYfaHR0cDovL2NsaWVudHMx\n"
    "Lmdvb2dsZS5jb20vb2NzcDAdBgNVHQ4EFgQUQqsYsRoWLiG6qmV2N1mpYaHawxAw\n"
    "DAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBRK3QYWG7z2aLV29YG2u2IaulqBLzAX\n"
    "BgNVHSAEEDAOMAwGCisGAQQB1nkCBQEwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDov\n"
    "L3BraS5nb29nbGUuY29tL0dJQUcyLmNybDANBgkqhkiG9w0BAQsFAAOCAQEAKNh3\n"
    "isNuGBisPKVlekOsZR6S8oP/fS/xt6Hqvg0EwFXvhxoJ40rxAB2LMykY17e+ln3P\n"
    "MwBBlRkwY1btcDT15JwzgaZb38rq/r+Pkb5Qgmx/InA/pw0QHDtwHQp5uXZuvu6p\n"
    "J/SlCwyq7EOvByWdVQcMU/dhGa3idXEkn/zwfqcG6YjdWKoDmXWZYv3RiP3wJcRB\n"
    "9+3U1wOe3uebnZLRWO6/w0to1XY8TFHklyw5rwIE5sbxOx5N3Ne8+GgPrUDvGAz0\n"
    "rAUKnh3b7GNXL1qlZh2qkhB6rUzvtPpg397Asg3xVtExCHOk4zPqzzicttoEbVVy\n"
    "0T8rIMUNwC4Beh4JVjEA\n"
    "-----END PKCS7-----\n";

// kPEMCRL is the result of downloading the Equifax CRL and running:
//   openssl crl2pkcs7 -inform DER -in secureca.crl  */
static const char kPEMCRL[] =
    "-----BEGIN PKCS7-----\n"
    "MIIDhQYJKoZIhvcNAQcCoIIDdjCCA3ICAQExADALBgkqhkiG9w0BBwGgAKGCA1gw\n"
    "ggNUMIICvTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UEChMH\n"
    "RXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0\n"
    "aG9yaXR5Fw0xNTAyMjcwMTIzMDBaFw0xNTAzMDkwMTIzMDBaMIICPDAUAgMPWOQX\n"
    "DTE0MDQyNzA4MTkyMlowFAIDFHYZFw0xNDA2MTgxNTAwMDNaMBQCAw+a+xcNMTQw\n"
    "NDI5MTgwOTE3WjAUAgMUi8AXDTE0MDcwOTE5NDYzM1owFAIDFOScFw0xNDA0MTYy\n"
    "MzM5MzVaMBQCAw+GBxcNMTQwNTIxMTU1MDUzWjAUAgMS4ikXDTE0MDYxNzE4NTUx\n"
    "NVowFAIDDUJmFw0xMjA2MjcxNzEwNTNaMBQCAwMeMxcNMDIwNTE1MTMwNjExWjAU\n"
    "AgMS4iMXDTE0MDYwNjIwNDAyMVowFAIDE5yrFw0xMDA3MjkxNjQ0MzlaMBQCAxLG\n"
    "ChcNMTQwNjA2MjIyMTM5WjAUAgMDJYUXDTAyMDUxNDE4MTE1N1owFAIDFIbmFw0x\n"
    "NDA3MjUwMjAwMzhaMBQCAxOcoRcNMTAwNzI5MTY0NzMyWjAUAgMVTVwXDTE0MDQz\n"
    "MDAwMDQ0MlowFAIDD/otFw0xNDA2MTcxODUwMTFaMBQCAxN1VRcNMTUwMTE4MDIy\n"
    "MTMzWjAUAgMPVpYXDTE0MDYyNDEyMzEwMlowFAIDC4CKFw0xMjA2MjcxNzEwMjVa\n"
    "MBQCAw+UFhcNMTAwMzAxMTM0NTMxWjAUAgMUFrMXDTE0MDYxODE0MzI1NlowFAID\n"
    "CuGFFw0xMjA2MjcxNzEwMTdaMBQCAxTMPhcNMTQwNzExMTI1NTMxWjAUAgMQW8sX\n"
    "DTEwMDczMDIxMzEyMFowFAIDFWofFw0xNDAyMjYxMjM1MTlaMA0GCSqGSIb3DQEB\n"
    "BQUAA4GBAB1cJwcRA/IAvfRGPnH9EISD2dLSGaAg9xpDPazaM/y3QmAapKiyB1xR\n"
    "FsBCgAoP8EdbS3iQr8esSPjKPBNe9tGIrlWjDIpiRyn4crgkF6+yBh6ncnarlh3g\n"
    "fNQMQoI9So4Vdy88Kow6BBBV3Lu6sZHue+cjxXETrmshNdNk8ABUMQA=\n"
    "-----END PKCS7-----\n";

static void TestCertReparse(const uint8_t *der_bytes, size_t der_len) {
  bssl::UniquePtr<STACK_OF(X509)> certs(sk_X509_new_null());
  ASSERT_TRUE(certs);
  bssl::UniquePtr<STACK_OF(X509)> certs2(sk_X509_new_null());
  ASSERT_TRUE(certs2);
  uint8_t *result_data, *result2_data;
  size_t result_len, result2_len;

  CBS pkcs7;
  CBS_init(&pkcs7, der_bytes, der_len);
  ASSERT_TRUE(PKCS7_get_certificates(certs.get(), &pkcs7));
  EXPECT_EQ(0u, CBS_len(&pkcs7));

  // Some test cases contain indefinite-length BER input
  CBS der_conv_out;
  uint8_t *der_conv = nullptr;
  CBS_init(&pkcs7, der_bytes, der_len);
  ASSERT_TRUE(CBS_asn1_ber_to_der(&pkcs7, &der_conv_out, &der_conv));
  bool is_ber = der_conv != nullptr;
  bssl::UniquePtr<uint8_t> free_der_conv(der_conv);

  bssl::ScopedCBB cbb;
  ASSERT_TRUE(CBB_init(cbb.get(), der_len));
  ASSERT_TRUE(PKCS7_bundle_certificates(cbb.get(), certs.get()));
  ASSERT_TRUE(CBB_finish(cbb.get(), &result_data, &result_len));
  bssl::UniquePtr<uint8_t> free_result_data(result_data);

  CBS_init(&pkcs7, result_data, result_len);
  ASSERT_TRUE(PKCS7_get_certificates(certs2.get(), &pkcs7));
  EXPECT_EQ(0u, CBS_len(&pkcs7));

  // PKCS#7 stores certificates in a SET OF, so |PKCS7_bundle_certificates| may
  // not preserve the original order. All of our test inputs are already sorted,
  // but this check should be relaxed if we add others.
  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);
    ASSERT_EQ(0, X509_cmp(a, b));
  }

  ASSERT_TRUE(CBB_init(cbb.get(), der_len));
  ASSERT_TRUE(PKCS7_bundle_certificates(cbb.get(), certs2.get()));
  ASSERT_TRUE(CBB_finish(cbb.get(), &result2_data, &result2_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);
  // |ASN1_item_d2i| natively handles BER, so the pointer always advances by
  // the full input length regardless of whether the input is BER or DER.
  EXPECT_EQ(ptr, der_bytes + der_len);
  bssl::UniquePtr<PKCS7> pkcs7_dup(PKCS7_dup(pkcs7_obj.get()));
  ASSERT_TRUE(pkcs7_dup);
  EXPECT_EQ(OBJ_obj2nid(pkcs7_obj.get()->type),
            OBJ_obj2nid(pkcs7_dup.get()->type));

  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);
  if (is_ber) {
    EXPECT_EQ(Bytes(der_conv, CBS_len(&der_conv_out)),
              Bytes(result3_data, result3_len));
  } else {
    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) {
  bssl::UniquePtr<STACK_OF(X509_CRL)> crls(sk_X509_CRL_new_null());
  ASSERT_TRUE(crls);
  bssl::UniquePtr<STACK_OF(X509_CRL)> crls2(sk_X509_CRL_new_null());
  ASSERT_TRUE(crls2);
  uint8_t *result_data, *result2_data;
  size_t result_len, result2_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));
  ASSERT_TRUE(PKCS7_bundle_CRLs(cbb.get(), crls.get()));
  ASSERT_TRUE(CBB_finish(cbb.get(), &result_data, &result_len));
  bssl::UniquePtr<uint8_t> free_result_data(result_data);

  CBS_init(&pkcs7, result_data, result_len);
  ASSERT_TRUE(PKCS7_get_CRLs(crls2.get(), &pkcs7));
  EXPECT_EQ(0u, CBS_len(&pkcs7));

  // PKCS#7 stores CRLs in a SET OF, so |PKCS7_bundle_CRLs| may not preserve the
  // original order. All of our test inputs are already sorted, but this check
  // should be relaxed if we add others.
  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);
    ASSERT_EQ(0, X509_CRL_cmp(a, b));
  }

  ASSERT_TRUE(CBB_init(cbb.get(), der_len));
  ASSERT_TRUE(PKCS7_bundle_CRLs(cbb.get(), crls2.get()));
  ASSERT_TRUE(CBB_finish(cbb.get(), &result2_data, &result2_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) {
  bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem, strlen(pem)));
  ASSERT_TRUE(bio);
  bssl::UniquePtr<STACK_OF(X509)> certs(sk_X509_new_null());
  ASSERT_TRUE(certs);

  ASSERT_TRUE(PKCS7_get_PEM_certificates(certs.get(), bio.get()));
  ASSERT_EQ(1u, sk_X509_num(certs.get()));
}

static void TestPEMCRLs(const char *pem) {
  bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem, strlen(pem)));
  ASSERT_TRUE(bio);
  bssl::UniquePtr<STACK_OF(X509_CRL)> crls(sk_X509_CRL_new_null());
  ASSERT_TRUE(crls);

  ASSERT_TRUE(PKCS7_get_PEM_CRLs(crls.get(), bio.get()));
  ASSERT_EQ(1u, sk_X509_CRL_num(crls.get()));
}

TEST(PKCS7Test, CertReparseNSS) {
  TestCertReparse(kPKCS7NSS, sizeof(kPKCS7NSS));
}

TEST(PKCS7Test, CertReparseWindows) {
  TestCertReparse(kPKCS7Windows, sizeof(kPKCS7Windows));
}

TEST(PKCS7Test, CertSignedWithSignerInfos) {
  TestCertReparse(kPKCS7SignedWithSignerInfo,
                  sizeof(kPKCS7SignedWithSignerInfo));
}

TEST(PKCS7Test, CrlReparse) {
  TestCRLReparse(kOpenSSLCRL, sizeof(kOpenSSLCRL));
}

TEST(PKCS7Test, PEMCerts) { TestPEMCerts(kPEMCert); }

TEST(PKCS7Test, PEMCRLs) { TestPEMCRLs(kPEMCRL); }

// Test that we output certificates in the canonical DER order.
TEST(PKCS7Test, SortCerts) {
  // kPKCS7NSS contains three certificates in the canonical DER order.
  CBS pkcs7;
  CBS_init(&pkcs7, kPKCS7NSS, sizeof(kPKCS7NSS));
  bssl::UniquePtr<STACK_OF(X509)> certs(sk_X509_new_null());
  ASSERT_TRUE(certs);
  ASSERT_TRUE(PKCS7_get_certificates(certs.get(), &pkcs7));
  ASSERT_EQ(3u, sk_X509_num(certs.get()));

  X509 *cert1 = sk_X509_value(certs.get(), 0);
  X509 *cert2 = sk_X509_value(certs.get(), 1);
  X509 *cert3 = sk_X509_value(certs.get(), 2);

  auto check_order = [&](X509 *new_cert1, X509 *new_cert2, X509 *new_cert3) {
    // Bundle the certificates in the new order.
    bssl::UniquePtr<STACK_OF(X509)> new_certs(sk_X509_new_null());
    ASSERT_TRUE(new_certs);
    ASSERT_TRUE(bssl::PushToStack(new_certs.get(), bssl::UpRef(new_cert1)));
    ASSERT_TRUE(bssl::PushToStack(new_certs.get(), bssl::UpRef(new_cert2)));
    ASSERT_TRUE(bssl::PushToStack(new_certs.get(), bssl::UpRef(new_cert3)));
    bssl::ScopedCBB cbb;
    ASSERT_TRUE(CBB_init(cbb.get(), sizeof(kPKCS7NSS)));
    ASSERT_TRUE(PKCS7_bundle_certificates(cbb.get(), new_certs.get()));

    // The bundle should be sorted back to the original order.
    CBS cbs;
    CBS_init(&cbs, CBB_data(cbb.get()), CBB_len(cbb.get()));
    bssl::UniquePtr<STACK_OF(X509)> result(sk_X509_new_null());
    ASSERT_TRUE(result);
    ASSERT_TRUE(PKCS7_get_certificates(result.get(), &cbs));
    ASSERT_EQ(sk_X509_num(certs.get()), sk_X509_num(result.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(result.get(), i);
      EXPECT_EQ(0, X509_cmp(a, b));
    }
  };

  check_order(cert1, cert2, cert3);
  check_order(cert3, cert2, cert1);
  check_order(cert2, cert3, cert1);
}

// Test that we output certificates in the canonical DER order, using the
// CRYPTO_BUFFER version of the parse and bundle functions.
TEST(PKCS7Test, SortCertsRaw) {
  // kPKCS7NSS contains three certificates in the canonical DER order.
  CBS pkcs7;
  CBS_init(&pkcs7, kPKCS7NSS, sizeof(kPKCS7NSS));
  bssl::UniquePtr<STACK_OF(CRYPTO_BUFFER)> certs(sk_CRYPTO_BUFFER_new_null());
  ASSERT_TRUE(certs);
  ASSERT_TRUE(PKCS7_get_raw_certificates(certs.get(), &pkcs7, nullptr));
  ASSERT_EQ(3u, sk_CRYPTO_BUFFER_num(certs.get()));

  CRYPTO_BUFFER *cert1 = sk_CRYPTO_BUFFER_value(certs.get(), 0);
  CRYPTO_BUFFER *cert2 = sk_CRYPTO_BUFFER_value(certs.get(), 1);
  CRYPTO_BUFFER *cert3 = sk_CRYPTO_BUFFER_value(certs.get(), 2);

  auto check_order = [&](CRYPTO_BUFFER *new_cert1, CRYPTO_BUFFER *new_cert2,
                         CRYPTO_BUFFER *new_cert3) {
    // Bundle the certificates in the new order.
    bssl::UniquePtr<STACK_OF(CRYPTO_BUFFER)> new_certs(
        sk_CRYPTO_BUFFER_new_null());
    ASSERT_TRUE(new_certs);
    ASSERT_TRUE(bssl::PushToStack(new_certs.get(), bssl::UpRef(new_cert1)));
    ASSERT_TRUE(bssl::PushToStack(new_certs.get(), bssl::UpRef(new_cert2)));
    ASSERT_TRUE(bssl::PushToStack(new_certs.get(), bssl::UpRef(new_cert3)));
    bssl::ScopedCBB cbb;
    ASSERT_TRUE(CBB_init(cbb.get(), sizeof(kPKCS7NSS)));
    ASSERT_TRUE(PKCS7_bundle_raw_certificates(cbb.get(), new_certs.get()));

    // The bundle should be sorted back to the original order.
    CBS cbs;
    CBS_init(&cbs, CBB_data(cbb.get()), CBB_len(cbb.get()));
    bssl::UniquePtr<STACK_OF(CRYPTO_BUFFER)> result(
        sk_CRYPTO_BUFFER_new_null());
    ASSERT_TRUE(result);
    ASSERT_TRUE(PKCS7_get_raw_certificates(result.get(), &cbs, nullptr));
    ASSERT_EQ(sk_CRYPTO_BUFFER_num(certs.get()),
              sk_CRYPTO_BUFFER_num(result.get()));
    for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(certs.get()); i++) {
      CRYPTO_BUFFER *a = sk_CRYPTO_BUFFER_value(certs.get(), i);
      CRYPTO_BUFFER *b = sk_CRYPTO_BUFFER_value(result.get(), i);
      EXPECT_EQ(Bytes(CRYPTO_BUFFER_data(a), CRYPTO_BUFFER_len(a)),
                Bytes(CRYPTO_BUFFER_data(b), CRYPTO_BUFFER_len(b)));
    }
  };

  check_order(cert1, cert2, cert3);
  check_order(cert3, cert2, cert1);
  check_order(cert2, cert3, cert1);
}

// Test that we output CRLs in the canonical DER order.
TEST(PKCS7Test, SortCRLs) {
  static const char kCRL1[] = R"(
-----BEGIN X509 CRL-----
MIIBpzCBkAIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE
CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ
Qm9yaW5nU1NMFw0xNjA5MjYxNTEwNTVaFw0xNjEwMjYxNTEwNTVaoA4wDDAKBgNV
HRQEAwIBATANBgkqhkiG9w0BAQsFAAOCAQEAnrBKKgvd9x9zwK9rtUvVeFeJ7+LN
ZEAc+a5oxpPNEsJx6hXoApYEbzXMxuWBQoCs5iEBycSGudct21L+MVf27M38KrWo
eOkq0a2siqViQZO2Fb/SUFR0k9zb8xl86Zf65lgPplALun0bV/HT7MJcl04Tc4os
dsAReBs5nqTGNEd5AlC1iKHvQZkM//MD51DspKnDpsDiUVi54h9C1SpfZmX8H2Vv
diyu0fZ/bPAM3VAGawatf/SyWfBMyKpoPXEG39oAzmjjOj8en82psn7m474IGaho
/vBbhl1ms5qQiLYPjm4YELtnXQoFyC72tBjbdFd/ZE9k4CNKDbxFUXFbkw==
-----END X509 CRL-----
)";
  static const char kCRL2[] = R"(
-----BEGIN X509 CRL-----
MIIBvjCBpwIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE
CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ
Qm9yaW5nU1NMFw0xNjA5MjYxNTEyNDRaFw0xNjEwMjYxNTEyNDRaMBUwEwICEAAX
DTE2MDkyNjE1MTIyNlqgDjAMMAoGA1UdFAQDAgECMA0GCSqGSIb3DQEBCwUAA4IB
AQCUGaM4DcWzlQKrcZvI8TMeR8BpsvQeo5BoI/XZu2a8h//PyRyMwYeaOM+3zl0d
sjgCT8b3C1FPgT+P2Lkowv7rJ+FHJRNQkogr+RuqCSPTq65ha4WKlRGWkMFybzVH
NloxC+aU3lgp/NlX9yUtfqYmJek1CDrOOGPrAEAwj1l/BUeYKNGqfBWYJQtPJu+5
OaSvIYGpETCZJscUWODmLEb/O3DM438vLvxonwGqXqS0KX37+CHpUlyhnSovxXxp
Pz4aF+L7OtczxL0GYtD2fR9B7TDMqsNmHXgQrixvvOY7MUdLGbd4RfJL3yA53hyO
xzfKY2TzxLiOmctG0hXFkH5J
-----END X509 CRL-----
)";

  bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(kCRL1, strlen(kCRL1)));
  ASSERT_TRUE(bio);
  bssl::UniquePtr<X509_CRL> crl1(
      PEM_read_bio_X509_CRL(bio.get(), nullptr, nullptr, nullptr));
  ASSERT_TRUE(crl1);
  bio.reset(BIO_new_mem_buf(kCRL2, strlen(kCRL2)));
  ASSERT_TRUE(bio);
  bssl::UniquePtr<X509_CRL> crl2(
      PEM_read_bio_X509_CRL(bio.get(), nullptr, nullptr, nullptr));
  ASSERT_TRUE(crl2);

  // DER's SET OF ordering sorts by tag, then length, so |crl1| comes before
  // |crl2|.
  auto check_order = [&](X509_CRL *new_crl1, X509_CRL *new_crl2) {
    // Bundle the CRLs in the new order.
    bssl::UniquePtr<STACK_OF(X509_CRL)> new_crls(sk_X509_CRL_new_null());
    ASSERT_TRUE(new_crls);
    ASSERT_TRUE(bssl::PushToStack(new_crls.get(), bssl::UpRef(new_crl1)));
    ASSERT_TRUE(bssl::PushToStack(new_crls.get(), bssl::UpRef(new_crl2)));
    bssl::ScopedCBB cbb;
    ASSERT_TRUE(CBB_init(cbb.get(), 64));
    ASSERT_TRUE(PKCS7_bundle_CRLs(cbb.get(), new_crls.get()));

    // The bundle should be sorted back to the original order.
    CBS cbs;
    CBS_init(&cbs, CBB_data(cbb.get()), CBB_len(cbb.get()));
    bssl::UniquePtr<STACK_OF(X509_CRL)> result(sk_X509_CRL_new_null());
    ASSERT_TRUE(result);
    ASSERT_TRUE(PKCS7_get_CRLs(result.get(), &cbs));
    ASSERT_EQ(2u, sk_X509_CRL_num(result.get()));
    EXPECT_EQ(0, X509_CRL_cmp(crl1.get(), sk_X509_CRL_value(result.get(), 0)));
    EXPECT_EQ(0, X509_CRL_cmp(crl2.get(), sk_X509_CRL_value(result.get(), 1)));
  };

  check_order(crl1.get(), crl2.get());
  check_order(crl2.get(), crl1.get());
}

TEST(PKCS7Test, KernelModuleSigning) {
  // Sign a message with the same call that the Linux kernel's sign-file.c
  // makes.
  static const char kCert[] = R"(
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIURVkPzF/4dwy7419Qk75uhIuyf0EwDQYJKoZIhvcNAQEL
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMTA5MjExOTIyMTJaFw0yMjA5
MjExOTIyMTJaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQC1+MOn+BopcEVR4QMvjXdAxGkWFllXyQFDToL+qOiP
RU1yN7C8KCtkbOAFttJIO4O/i0iZ7KqYbnmB6YUA/ONAcakocnrdoESgRJcVMeAx
Dk/11OtMF5yIfeOOO/TUeVNmAUaT63gFbKy/adpqhzJtOv9BBl5VcYNGGSE+0wtb
mjpmNsxunEQR1KLDc97fGYHeRfKoSyrCIEE8IaAEpKGR2Sku3v9Jwh7RpjupgiUA
kH6pJk7VMZm5vl2wFjYvfysgjeN5ZtsxFDMaPYZStpxMxpNd5C9DsO2Ljp5NMpGf
NGmG4ZqiaQg8z2cIM6ESmN1zDJdUh5IXed1fOxBZD/poUFH0wDRFWnvzlaPmjJEF
rYLMK8svnE5nEQp9vu93ISFBx7cofs+niMaUXPEqaRSqruifN2M1it3kOf/8YZl1
vurs+VtHD6nOJo6bd11+37aBidIB/BaWnzLrDmSTcPFa1tkTHwoLqc9+jThTq9jZ
6w3lAMPpsoenyD19UmQB589+4kNp2SIO/TtzVQCGgQPXE2jDCl6G9aIPMkfvpPZK
4THVil3WQRCFYnYdDO4HQXo2ZuC4RiqgY5ygfeoL+fa9k383lgxxAHQLS7xsbaVB
40RmfdbdevgPYIwZNNO78ddRmMdSv6IknSW9gydGzY//btY+t1SWcBZWzn1Ewq8g
2QIDAQABo1MwUTAdBgNVHQ4EFgQUotZD9ajEvnQYVezIWzcW4pzvMcUwHwYDVR0j
BBgwFoAUotZD9ajEvnQYVezIWzcW4pzvMcUwDwYDVR0TAQH/BAUwAwEB/zANBgkq
hkiG9w0BAQsFAAOCAgEAqCe42PIWoyLDx9bR+5cSp99N5xo5lLiSLtWx2emDbZB2
AunqKYeEgIV+TWNF2w1SZ/ckFgV7SlL2Yl73N/veSNRfNAnpjLksGDFpdJb7YXrx
cUvxdy1mr8oau6J7PC9JGjBTBrnhqwCQX1FtcAxODKll2Lsfuj6+bdC3rCK7KBEo
ENamMJZIeo8lRP9qFF2xwCEzZjRv2zvB6O5o9045aTUcdCrwUfKE2sqY6EXRzFTC
waK0HRCd1FLv9omhz/Ug5PMHP4d6MZfnAbFm+AzAhnpkrk/9TJYSOoNTNLWsuqhp
dN0rKqiFWv1zIwfknXvTh1P1Ap+G5jffAca0zWUH1oKjE7ZZioSsaZ6gySnD8+WQ
TPbOYtG+n0mhCH1TrU8Dqi3rd8g5IbC8loYLRH94QtodOnevD4Qo9Orfrsr8hGOW
ABespanZArhoQ03DAtpNhtHm2NWJQF2uHNqcTrkq0omqZBTbMD1GKMBujoNooAUu
w51U9r+RycPJTFqEGHb0nd7EjoyXEXtuX1Ld5fTZjQ9SszmQKQ8w3lHqRGNlkSiO
e3IOOq2ruXmq1jykxpmi82IcTRUE8TZBfL/yz0nxpHKAYC1VwMezrkgZDGz4npxf
1z2+qd58xU6/jsf7/+3xdPFubeEJujdbCkWQsQC5Rzm48zDWGq/pyzFji44K3TA=
-----END CERTIFICATE-----
)";

  static const char kKey[] = R"(
-----BEGIN PRIVATE KEY-----
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
hJTbHtjEDJ7BHLC/CNUhXbpyyu1y
-----END PRIVATE KEY-----
)";

  bssl::UniquePtr<BIO> cert_bio(
      BIO_new_mem_buf(const_cast<char *>(kCert), sizeof(kCert) - 1));
  bssl::UniquePtr<X509> cert(
      PEM_read_bio_X509(cert_bio.get(), nullptr, nullptr, nullptr));

  bssl::UniquePtr<BIO> key_bio(
      BIO_new_mem_buf(const_cast<char *>(kKey), sizeof(kKey) - 1));
  bssl::UniquePtr<EVP_PKEY> key(
      PEM_read_bio_PrivateKey(key_bio.get(), nullptr, nullptr, nullptr));

  static const char kSignedData[] = "signed data";
  bssl::UniquePtr<BIO> data_bio(BIO_new_mem_buf(const_cast<char *>(kSignedData),
                                                sizeof(kSignedData) - 1));

  bssl::UniquePtr<PKCS7> pkcs7(
      PKCS7_sign(cert.get(), key.get(), /*certs=*/nullptr, data_bio.get(),
                 PKCS7_NOATTR | PKCS7_BINARY | PKCS7_NOCERTS | PKCS7_DETACHED));
  ASSERT_TRUE(pkcs7);

  uint8_t *pkcs7_bytes = nullptr;
  const int pkcs7_len = i2d_PKCS7(pkcs7.get(), &pkcs7_bytes);
  ASSERT_GE(pkcs7_len, 0);
  bssl::UniquePtr<uint8_t> pkcs7_storage(pkcs7_bytes);

  // RSA signatures are deterministic so the output should not change.
  static const uint8_t kExpectedOutput[] = {
      0x30, 0x82, 0x02, 0xbc, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
      0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xad, 0x30, 0x82, 0x02, 0xa9, 0x02,
      0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
      0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48,
      0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x02, 0x86, 0x30, 0x82,
      0x02, 0x82, 0x02, 0x01, 0x01, 0x30, 0x5d, 0x30, 0x45, 0x31, 0x0b, 0x30,
      0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
      0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d,
      0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
      0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
      0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
      0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x02, 0x14, 0x45, 0x59, 0x0f, 0xcc,
      0x5f, 0xf8, 0x77, 0x0c, 0xbb, 0xe3, 0x5f, 0x50, 0x93, 0xbe, 0x6e, 0x84,
      0x8b, 0xb2, 0x7f, 0x41, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
      0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
      0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x00,
      0x54, 0xd4, 0x7c, 0xdc, 0x19, 0x86, 0xa1, 0xb2, 0xbe, 0xe3, 0xa4, 0x5e,
      0xad, 0x16, 0x6f, 0x7c, 0xf9, 0xa6, 0x40, 0x90, 0xb8, 0x78, 0x85, 0xf1,
      0x02, 0x59, 0xe5, 0x9f, 0x83, 0xfb, 0x20, 0xcf, 0x29, 0x52, 0xb6, 0x35,
      0x5c, 0xf9, 0xef, 0x4e, 0xc5, 0xd3, 0xa6, 0x45, 0x6e, 0xfa, 0x0a, 0xa7,
      0x53, 0xc8, 0xf4, 0xf9, 0xd6, 0xc5, 0xd8, 0xd8, 0x04, 0x3d, 0xb4, 0x15,
      0xa7, 0x7a, 0x53, 0xdd, 0x27, 0xfa, 0x58, 0x2e, 0x5e, 0xc4, 0xcd, 0x45,
      0xaa, 0xc2, 0x7b, 0xf9, 0x3d, 0xd7, 0x22, 0x20, 0x90, 0xbb, 0xa5, 0x62,
      0xd5, 0xaa, 0x39, 0x8f, 0xc1, 0x00, 0xef, 0x4b, 0x03, 0x2c, 0x32, 0xc0,
      0xad, 0x27, 0xb6, 0xfe, 0x86, 0xe5, 0x9d, 0xf0, 0xbe, 0xb1, 0x0d, 0xa4,
      0xa3, 0x40, 0xe0, 0xaa, 0x0a, 0x13, 0x6e, 0x61, 0x9a, 0x3b, 0xae, 0x78,
      0xd4, 0x6f, 0x2d, 0x1d, 0x40, 0x4b, 0xe3, 0x5f, 0xf8, 0xe8, 0x21, 0x89,
      0x35, 0x73, 0x6d, 0x7e, 0x41, 0xc6, 0x0f, 0x0c, 0x01, 0x64, 0x61, 0xa8,
      0x37, 0xef, 0x2b, 0x95, 0xb7, 0x34, 0xac, 0xc7, 0xdb, 0x66, 0x87, 0x45,
      0xb4, 0x0f, 0x60, 0x01, 0x07, 0x29, 0x74, 0x32, 0x0b, 0xae, 0xbc, 0x08,
      0x88, 0x15, 0xc3, 0x79, 0x4a, 0x1c, 0x5a, 0x9c, 0xc2, 0xfb, 0x4f, 0xd3,
      0x17, 0xc2, 0x40, 0x71, 0x37, 0xea, 0xa6, 0x1e, 0xf0, 0x5b, 0xa5, 0xd7,
      0x9b, 0x9e, 0x57, 0x44, 0x74, 0xc5, 0xd5, 0x5f, 0xba, 0xbc, 0xd7, 0xe1,
      0xae, 0xd0, 0xd3, 0xb5, 0x10, 0xc6, 0x8b, 0xb1, 0x83, 0x7c, 0xaa, 0x3a,
      0xbb, 0xe8, 0x7f, 0x56, 0xc4, 0x3b, 0x9d, 0x45, 0x09, 0x9b, 0x34, 0xc9,
      0xfb, 0x5a, 0xa1, 0xab, 0xd0, 0x07, 0x79, 0x43, 0x58, 0x44, 0xd7, 0x40,
      0xc4, 0xa7, 0xd3, 0xe9, 0x18, 0xb9, 0x78, 0x1d, 0x93, 0x0b, 0xc1, 0xdb,
      0xc3, 0xae, 0xc9, 0xe8, 0x2c, 0xa7, 0x8c, 0x7e, 0x31, 0x1e, 0xec, 0x1c,
      0xab, 0x83, 0xa0, 0x5d, 0x0e, 0xc3, 0x6a, 0x7c, 0x97, 0x09, 0xcf, 0x00,
      0xa9, 0x66, 0xda, 0x21, 0x85, 0xaa, 0x47, 0xd8, 0xea, 0x8f, 0x72, 0x54,
      0x03, 0x6c, 0xbc, 0x4b, 0xf9, 0x92, 0xae, 0x82, 0x75, 0x33, 0x10, 0x4d,
      0x65, 0x4d, 0x0e, 0x73, 0x5d, 0x6f, 0x09, 0xee, 0x56, 0x78, 0x87, 0x0b,
      0xa3, 0xaa, 0xc2, 0x5f, 0x49, 0x73, 0x0d, 0x78, 0xfa, 0x40, 0xc1, 0x25,
      0x2f, 0x5d, 0x8a, 0xe1, 0xbf, 0x38, 0x2c, 0xd0, 0x26, 0xbd, 0xf5, 0x6e,
      0x02, 0x01, 0x2e, 0x9e, 0x27, 0x64, 0x4b, 0x61, 0x8c, 0x68, 0x6e, 0x09,
      0xfe, 0x0b, 0xf8, 0x36, 0x4e, 0x84, 0xb7, 0x76, 0xcb, 0x41, 0xf0, 0x40,
      0x72, 0xc9, 0x74, 0x64, 0x5f, 0xbe, 0x9e, 0xfe, 0x9e, 0xce, 0x89, 0x84,
      0x68, 0x81, 0x57, 0x2a, 0xdb, 0xd6, 0x01, 0xa8, 0x1b, 0x6e, 0x5d, 0xc4,
      0x65, 0xbd, 0x0d, 0x98, 0x54, 0xa3, 0x18, 0x23, 0x09, 0x4a, 0x8d, 0x6c,
      0xc6, 0x2e, 0xfe, 0x7a, 0xa9, 0x11, 0x92, 0x8b, 0xd0, 0xc1, 0xe7, 0x76,
      0x71, 0xec, 0x34, 0xfc, 0xc8, 0x2a, 0x5e, 0x38, 0x52, 0xe6, 0xc8, 0xa5,
      0x1d, 0x0b, 0xce, 0xf5, 0xc0, 0xe5, 0x0b, 0x88, 0xa9, 0x55, 0x88, 0x6c,
      0xfa, 0xea, 0xaa, 0x39, 0x66, 0xdd, 0x80, 0x52, 0xe0, 0x7e, 0x45, 0x8e,
      0x51, 0x2c, 0x36, 0x07, 0xd7, 0x2b, 0xf1, 0x46, 0x00, 0x66, 0xb2, 0x5a,
      0x39, 0xbe, 0xf7, 0x26, 0x15, 0xbc, 0x55, 0xdb, 0xe9, 0x01, 0xdd, 0x54,
      0x27, 0x2b, 0xfe, 0x86, 0x52, 0xef, 0xc6, 0x27, 0xa3, 0xf7, 0x55, 0x55,
      0xb8, 0xe2, 0x1f, 0xcb, 0x32, 0xd8, 0xba, 0xd6, 0x69, 0xde, 0x8d, 0xa7,
      0xfa, 0xad, 0xf6, 0x2a, 0xc0, 0x6f, 0x86, 0x50, 0x27, 0x5a, 0xe2, 0xe3,
      0xf6, 0xb9, 0x01, 0xec, 0x01, 0x37, 0x84, 0x01,
  };
  EXPECT_EQ(Bytes(pkcs7_bytes, pkcs7_len),
            Bytes(kExpectedOutput, sizeof(kExpectedOutput)));

  ERR_clear_error();
}

TEST(PKCS7Test, GettersSetters) {
  bssl::UniquePtr<PKCS7> p7;

  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7);
  EXPECT_FALSE(PKCS7_set_type(p7.get(), NID_undef));
  EXPECT_FALSE(PKCS7_content_new(p7.get(), NID_undef));

  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7);
  EXPECT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signed));
  // set type redundantly to ensure we're properly freeing up existing
  // resources on subsequent set.
  EXPECT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signed));
  EXPECT_TRUE(PKCS7_type_is_signed(p7.get()));
  EXPECT_TRUE(PKCS7_content_new(p7.get(), NID_pkcs7_signed));
  EXPECT_FALSE(PKCS7_set_cipher(p7.get(), EVP_aes_128_gcm()));
  EXPECT_FALSE(PKCS7_add_recipient_info(p7.get(), nullptr));
  EXPECT_FALSE(PKCS7_get_signer_info(nullptr));

  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7);
  EXPECT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_digest));
  // set type redundantly to ensure we're properly freeing up existing
  // resources on subsequent set.
  EXPECT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_digest));
  EXPECT_TRUE(PKCS7_type_is_digest(p7.get()));
  EXPECT_TRUE(PKCS7_content_new(p7.get(), NID_pkcs7_digest));
  EXPECT_FALSE(PKCS7_add_certificate(p7.get(), nullptr));
  EXPECT_FALSE(PKCS7_add_crl(p7.get(), nullptr));
  EXPECT_FALSE(PKCS7_add_signer(p7.get(), nullptr));
  EXPECT_FALSE(PKCS7_get_signer_info(p7.get()));

  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7.get());
  EXPECT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_data));
  // set type redundantly to ensure we're properly freeing up existing
  // resources on subsequent set.
  EXPECT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_data));
  EXPECT_TRUE(PKCS7_type_is_data(p7.get()));
  EXPECT_FALSE(PKCS7_set_content(p7.get(), p7.get()));

  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7.get());
  EXPECT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signedAndEnveloped));
  // set type redundantly to ensure we're properly freeing up existing
  // resources on subsequent set.
  EXPECT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signedAndEnveloped));
  EXPECT_TRUE(PKCS7_type_is_signedAndEnveloped(p7.get()));
  EXPECT_TRUE(PKCS7_set_cipher(p7.get(), EVP_aes_128_gcm()));
  EXPECT_FALSE(PKCS7_set_content(p7.get(), p7.get()));

  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7.get());
  EXPECT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_enveloped));
  // set type redundantly to ensure we're properly freeing up existing
  // resources on subsequent set.
  EXPECT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_enveloped));
  EXPECT_TRUE(PKCS7_type_is_enveloped(p7.get()));
  EXPECT_TRUE(PKCS7_set_cipher(p7.get(), EVP_aes_128_gcm()));
  EXPECT_FALSE(PKCS7_set_content(p7.get(), p7.get()));

  // Ruby requires that we can set type NID_pkcs7_encrypted even though we don't
  // really support it for most functions.
  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7.get());
  EXPECT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_encrypted));
  // set type redundantly to ensure we're properly freeing up existing
  // resources on subsequent set.
  EXPECT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_encrypted));
  EXPECT_TRUE(PKCS7_type_is_encrypted(p7.get()));
  EXPECT_FALSE(PKCS7_set_content(p7.get(), p7.get()));

  // |d2i_*| functions advance the input reference by number of bytes parsed,
  // so save off a local reference and reset it for each test case.
  const uint8_t *p7_der = kPKCS7SignedWithSignerInfo;
  const size_t p7_der_len = sizeof(kPKCS7SignedWithSignerInfo);
  p7.reset(d2i_PKCS7(nullptr, &p7_der, p7_der_len));
  ASSERT_TRUE(p7);
  ASSERT_TRUE(PKCS7_type_is_signed(p7.get()));
  STACK_OF(PKCS7_SIGNER_INFO) *sk_p7si_signed = PKCS7_get_signer_info(p7.get());
  ASSERT_TRUE(sk_p7si_signed);
  ASSERT_GT(sk_PKCS7_SIGNER_INFO_num(sk_p7si_signed), 0UL);
  PKCS7_SIGNER_INFO *p7si = sk_PKCS7_SIGNER_INFO_value(sk_p7si_signed, 0);
  ASSERT_TRUE(p7si);
  EXPECT_FALSE(PKCS7_get_signed_attribute(
      p7si, NID_md5));  // hash nid not valid x509 attr
  ASN1_TYPE *signing_time =
      PKCS7_get_signed_attribute(p7si, NID_pkcs9_signingTime);
  ASSERT_TRUE(signing_time);
  EVP_PKEY *pkey;
  X509_ALGOR *pdig;
  X509_ALGOR *psig;
  PKCS7_SIGNER_INFO_get0_algs(p7si, &pkey, &pdig, &psig);
  ASSERT_FALSE(pkey);  // no attached pkey
  ASSERT_TRUE(psig);
  ASSERT_TRUE(pdig);

  // Negative lengths not valid
  EXPECT_FALSE(d2i_PKCS7(nullptr, &p7_der, -1));

  bssl::UniquePtr<PKCS7> p7_dup(PKCS7_dup(p7.get()));
  ASSERT_TRUE(p7_dup);
  EXPECT_TRUE(PKCS7_type_is_signed(p7_dup.get()));

  p7_der = kPKCS7SignedWithSignerInfo;
  bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(p7_der, p7_der_len));
  p7.reset(d2i_PKCS7_bio(bio.get(), nullptr));
  ASSERT_TRUE(p7);
  ASSERT_TRUE(PKCS7_type_is_signed(p7.get()));
  bio.reset(BIO_new(BIO_s_mem()));
  ASSERT_TRUE(i2d_PKCS7_bio(bio.get(), p7.get()));

  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7);
  ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signed));
  bio.reset(BIO_new_mem_buf(kPEMCert, strlen(kPEMCert)));
  ASSERT_TRUE(bio);
  bssl::UniquePtr<STACK_OF(X509)> certs(sk_X509_new_null());
  ASSERT_TRUE(certs);
  ASSERT_TRUE(PKCS7_get_PEM_certificates(certs.get(), bio.get()));
  ASSERT_EQ(1U, sk_X509_num(certs.get()));
  EXPECT_TRUE(PKCS7_add_certificate(p7.get(), sk_X509_value(certs.get(), 0U)));

  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7);
  ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signed));
  bio.reset(BIO_new_mem_buf(kPEMCRL, strlen(kPEMCRL)));
  ASSERT_TRUE(bio);
  bssl::UniquePtr<STACK_OF(X509_CRL)> crls(sk_X509_CRL_new_null());
  ASSERT_TRUE(crls);
  ASSERT_TRUE(PKCS7_get_PEM_CRLs(crls.get(), bio.get()));
  ASSERT_EQ(1U, sk_X509_CRL_num(crls.get()));
  EXPECT_TRUE(PKCS7_add_crl(p7.get(), sk_X509_CRL_value(crls.get(), 0U)));

  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7);
  ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signedAndEnveloped));
  bio.reset(BIO_new_mem_buf(kPEMCert, strlen(kPEMCert)));
  ASSERT_TRUE(bio);
  certs.reset(sk_X509_new_null());
  ASSERT_TRUE(certs);
  ASSERT_TRUE(PKCS7_get_PEM_certificates(certs.get(), bio.get()));
  ASSERT_EQ(1U, sk_X509_num(certs.get()));
  EXPECT_TRUE(PKCS7_add_certificate(p7.get(), sk_X509_value(certs.get(), 0U)));

  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7);
  ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signedAndEnveloped));
  bio.reset(BIO_new_mem_buf(kPEMCRL, strlen(kPEMCRL)));
  ASSERT_TRUE(bio);
  crls.reset(sk_X509_CRL_new_null());
  ASSERT_TRUE(crls);
  ASSERT_TRUE(PKCS7_get_PEM_CRLs(crls.get(), bio.get()));
  ASSERT_EQ(1U, sk_X509_CRL_num(crls.get()));
  EXPECT_TRUE(PKCS7_add_crl(p7.get(), sk_X509_CRL_value(crls.get(), 0U)));

  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7);
  ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signed));
  bssl::UniquePtr<RSA> rsa(RSA_new());
  ASSERT_TRUE(rsa);
  ASSERT_TRUE(RSA_generate_key_fips(rsa.get(), 2048, nullptr));
  bssl::UniquePtr<EVP_PKEY> rsa_pkey(EVP_PKEY_new());
  ASSERT_TRUE(rsa_pkey);
  ASSERT_TRUE(EVP_PKEY_set1_RSA(rsa_pkey.get(), rsa.get()));
  bssl::UniquePtr<X509> rsa_x509(sk_X509_pop(certs.get()));
  ASSERT_EQ(0U, sk_X509_num(certs.get()));
  ASSERT_TRUE(rsa_x509);
  p7si = PKCS7_SIGNER_INFO_new();
  ASSERT_TRUE(p7si);
  EXPECT_TRUE(PKCS7_SIGNER_INFO_set(p7si, rsa_x509.get(), rsa_pkey.get(),
                                    EVP_sha256()));
  EXPECT_FALSE(PKCS7_SIGNER_INFO_set(p7si, nullptr, nullptr, nullptr));
  EXPECT_TRUE(PKCS7_add_signer(p7.get(), p7si));
  EXPECT_TRUE(PKCS7_get_signer_info(p7.get()));

  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7.get());
  ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signedAndEnveloped));
  p7si = PKCS7_SIGNER_INFO_new();
  ASSERT_TRUE(p7si);
  bssl::UniquePtr<X509> ecdsa_x509(X509_new());
  ASSERT_TRUE(ecdsa_x509);
  bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr));
  ASSERT_TRUE(ctx);
  ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get()));
  ASSERT_TRUE(
      EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), NID_X9_62_prime256v1));
  bssl::UniquePtr<EVP_PKEY> ecdsa_pkey(EVP_PKEY_new());
  EVP_PKEY *ecdsa_pkey_ptr = ecdsa_pkey.get();
  ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &ecdsa_pkey_ptr));
  EXPECT_TRUE(PKCS7_SIGNER_INFO_set(p7si, ecdsa_x509.get(), ecdsa_pkey.get(),
                                    EVP_sha256()));
  EXPECT_TRUE(PKCS7_add_signer(p7.get(), p7si));
  EXPECT_TRUE(PKCS7_get_signer_info(p7.get()));

  // Cover overlap between |p7| and signer info message digest algorithms
  p7.reset(PKCS7_new());
  ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signed));
  X509_ALGOR *md_alg1 = X509_ALGOR_new();
  X509_ALGOR_set_md(md_alg1, EVP_sha384());
  sk_X509_ALGOR_push(p7->d.sign->md_algs, md_alg1);
  X509_ALGOR *md_alg2 = X509_ALGOR_new();
  X509_ALGOR_set_md(md_alg2, EVP_sha256());
  sk_X509_ALGOR_push(p7->d.sign->md_algs, md_alg2);

  p7si = PKCS7_SIGNER_INFO_new();
  ASSERT_TRUE(p7si);
  EXPECT_TRUE(PKCS7_SIGNER_INFO_set(p7si, ecdsa_x509.get(), ecdsa_pkey.get(),
                                    EVP_sha256()));
  EXPECT_TRUE(PKCS7_add_signer(p7.get(), p7si));

  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7.get());
  ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signed));
  p7si = PKCS7_SIGNER_INFO_new();
  ASSERT_TRUE(p7si);
  ecdsa_x509.reset(X509_new());
  ASSERT_TRUE(ecdsa_x509);
  ctx.reset(EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519, nullptr));
  ASSERT_TRUE(ctx);
  ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get()));
  ecdsa_pkey.reset(EVP_PKEY_new());
  ecdsa_pkey_ptr = ecdsa_pkey.get();
  ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &ecdsa_pkey_ptr));
  EXPECT_FALSE(PKCS7_SIGNER_INFO_set(p7si, ecdsa_x509.get(), ecdsa_pkey.get(),
                                     EVP_sha256()));
  PKCS7_SIGNER_INFO_free(p7si);

  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7);
  ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signedAndEnveloped));
  ASSERT_TRUE(X509_set_pubkey(rsa_x509.get(), rsa_pkey.get()));
  PKCS7_RECIP_INFO *p7ri = PKCS7_RECIP_INFO_new();
  EXPECT_TRUE(PKCS7_RECIP_INFO_set(p7ri, rsa_x509.get()));
  EXPECT_FALSE(PKCS7_RECIP_INFO_set(p7ri, nullptr));
  X509_ALGOR *penc = NULL;
  PKCS7_RECIP_INFO_get0_alg(p7ri, &penc);
  ASSERT_TRUE(penc);
  EXPECT_TRUE(PKCS7_add_recipient_info(p7.get(), p7ri));

  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7);
  ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_enveloped));
  ASSERT_TRUE(X509_set_pubkey(rsa_x509.get(), rsa_pkey.get()));
  p7ri = PKCS7_RECIP_INFO_new();
  EXPECT_TRUE(PKCS7_RECIP_INFO_set(p7ri, rsa_x509.get()));
  PKCS7_RECIP_INFO_get0_alg(p7ri, &penc);
  ASSERT_TRUE(penc);
  EXPECT_TRUE(PKCS7_add_recipient_info(p7.get(), p7ri));
}

TEST(PKCS7Test, DataInitFinal) {
  bssl::UniquePtr<PKCS7> p7;
  bssl::UniquePtr<BIO> bio, bio_in;
  bssl::UniquePtr<STACK_OF(X509)> certs;
  bssl::UniquePtr<X509> rsa_x509;
  bssl::UniquePtr<uint8_t> p7_der;
  size_t p7_der_len;
  const uint8_t *p7_ptr;

  p7_ptr = kPKCS7SignedWithSignerInfo;
  p7_der_len = sizeof(kPKCS7SignedWithSignerInfo);
  p7.reset(d2i_PKCS7(nullptr, &p7_ptr, p7_der_len));
  ASSERT_TRUE(p7);
  EXPECT_TRUE(PKCS7_type_is_signed(p7.get()));
  bio.reset(PKCS7_dataInit(p7.get(), nullptr));
  ASSERT_TRUE(bio);
  EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get()));

  // parse a cert for use with recipient infos
  bssl::UniquePtr<RSA> rsa(RSA_new());
  ASSERT_TRUE(rsa);
  ASSERT_TRUE(RSA_generate_key_fips(rsa.get(), 2048, nullptr));
  bssl::UniquePtr<EVP_PKEY> rsa_pkey(EVP_PKEY_new());
  ASSERT_TRUE(rsa_pkey);

  ASSERT_TRUE(EVP_PKEY_set1_RSA(rsa_pkey.get(), rsa.get()));
  bio.reset(BIO_new_mem_buf(kPEMCert, strlen(kPEMCert)));
  ASSERT_TRUE(bio);
  certs.reset(sk_X509_new_null());
  ASSERT_TRUE(certs);
  ASSERT_TRUE(PKCS7_get_PEM_certificates(certs.get(), bio.get()));
  ASSERT_EQ(1U, sk_X509_num(certs.get()));
  rsa_x509.reset(sk_X509_pop(certs.get()));
  ASSERT_TRUE(X509_set_pubkey(rsa_x509.get(), rsa_pkey.get()));

  p7_ptr = kPKCS7EnvelopedData;
  p7_der_len = sizeof(kPKCS7EnvelopedData);
  p7.reset(d2i_PKCS7(nullptr, &p7_ptr, p7_der_len));
  ASSERT_TRUE(p7);
  EXPECT_TRUE(PKCS7_type_is_enveloped(p7.get()));
  // need to initialize cipher for enveloped data
  EXPECT_TRUE(PKCS7_set_cipher(p7.get(), EVP_aes_128_ctr()));
  // attach a (non-serialized, unrelated) cert to |p7ri_sk|
  STACK_OF(PKCS7_RECIP_INFO) *p7ri_sk = PKCS7_get_recipient_info(p7.get());
  PKCS7_RECIP_INFO *p7ri = sk_PKCS7_RECIP_INFO_value(p7ri_sk, 0);
  ASSERT_TRUE(p7ri);
  EXPECT_TRUE(PKCS7_RECIP_INFO_set(p7ri, rsa_x509.get()));
  bio.reset(PKCS7_dataInit(p7.get(), nullptr));
  ASSERT_TRUE(bio);
  EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get()));

  bio.reset(nullptr);
  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7);
  ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signedAndEnveloped));
  ASSERT_TRUE(PKCS7_set_cipher(p7.get(), EVP_aes_128_ctr()));
  bio.reset(PKCS7_dataInit(p7.get(), nullptr));
  EXPECT_TRUE(bio);
  EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get()));

  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7);
  ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_digest));
  ASSERT_TRUE(PKCS7_set_digest(p7.get(), EVP_sha256()));
  ASSERT_TRUE(PKCS7_content_new(p7.get(), NID_pkcs7_data));
  bio.reset(PKCS7_dataInit(p7.get(), nullptr));
  EXPECT_TRUE(bio);
  EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get()));

  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7);
  ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_data));
  bio.reset(PKCS7_dataInit(p7.get(), nullptr));
  EXPECT_TRUE(bio);
  EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get()));

  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7);
  ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_enveloped));
  ASSERT_TRUE(PKCS7_set_cipher(p7.get(), EVP_aes_128_ctr()));
  bio.reset(PKCS7_dataInit(p7.get(), nullptr));
  EXPECT_TRUE(bio);
  EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get()));

  // pre-existing BIO?
  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7);
  ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_enveloped));
  ASSERT_TRUE(PKCS7_set_cipher(p7.get(), EVP_aes_128_ctr()));
  bio.reset(PKCS7_dataInit(p7.get(), nullptr));
  EXPECT_TRUE(bio);
  EXPECT_TRUE(PKCS7_dataFinal(p7.get(), bio.get()));

  // Error cases

  // type NID_pkcs7_encrypted is not supported by the BIO functions
  p7.reset(PKCS7_new());
  bio_in.reset(BIO_new(BIO_s_mem()));
  ASSERT_TRUE(p7);
  ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_encrypted));
  bio.reset(PKCS7_dataInit(p7.get(), bio_in.get()));
  EXPECT_FALSE(bio);
  EXPECT_FALSE(PKCS7_dataFinal(p7.get(), bio.get()));

  // NID_pkcs7_enveloped and NID_pkcs7_signedAndEnveloped require a cipher
  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7);
  ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_enveloped));
  bio.reset(PKCS7_dataInit(p7.get(), nullptr));
  EXPECT_FALSE(bio);
  EXPECT_FALSE(PKCS7_dataFinal(p7.get(), bio.get()));
  ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_enveloped));
  bio.reset(PKCS7_dataInit(p7.get(), nullptr));
  EXPECT_FALSE(bio);
  EXPECT_FALSE(PKCS7_dataFinal(p7.get(), bio.get()));
}

TEST(PKCS7Test, TestEnveloped) {
  bssl::UniquePtr<PKCS7> p7;
  bssl::UniquePtr<BIO> bio;
  bssl::UniquePtr<STACK_OF(X509)> certs;
  bssl::UniquePtr<X509> rsa_x509;
  const size_t pt_len = 64;
  // NOTE: we make |buf| larger than |pt_len| in case padding gets added.
  // without the extra room, we sometimes overflow into the next variable on the
  // stack.
  uint8_t buf[pt_len + EVP_MAX_BLOCK_LENGTH];
  uint8_t decrypted[pt_len + EVP_MAX_BLOCK_LENGTH];

  OPENSSL_cleanse(buf, sizeof(buf));
  OPENSSL_memset(buf, 'A', pt_len);

  // parse a cert for use with recipient infos
  bssl::UniquePtr<RSA> rsa(RSA_new());
  ASSERT_TRUE(rsa);
  ASSERT_TRUE(RSA_generate_key_fips(rsa.get(), 2048, nullptr));
  bssl::UniquePtr<EVP_PKEY> rsa_pkey(EVP_PKEY_new());
  ASSERT_TRUE(rsa_pkey);
  ASSERT_TRUE(EVP_PKEY_set1_RSA(rsa_pkey.get(), rsa.get()));
  certs.reset(sk_X509_new_null());
  bio.reset(BIO_new_mem_buf(kPEMCert, strlen(kPEMCert)));
  ASSERT_TRUE(bio);
  certs.reset(sk_X509_new_null());
  ASSERT_TRUE(certs);
  ASSERT_TRUE(PKCS7_get_PEM_certificates(certs.get(), bio.get()));
  ASSERT_EQ(1U, sk_X509_num(certs.get()));
  rsa_x509.reset(sk_X509_value(certs.get(), 0));
  ASSERT_TRUE(X509_set_pubkey(rsa_x509.get(), rsa_pkey.get()));
  X509_up_ref(rsa_x509.get());

  // standard success case
  bio.reset(BIO_new_mem_buf(buf, pt_len));
  p7.reset(
      PKCS7_encrypt(certs.get(), bio.get(), EVP_aes_128_cbc(), /*flags*/ 0));
  EXPECT_TRUE(p7);
  EXPECT_TRUE(PKCS7_type_is_enveloped(p7.get()));
  bio.reset(BIO_new(BIO_s_mem()));
  EXPECT_TRUE(PKCS7_decrypt(p7.get(), rsa_pkey.get(), rsa_x509.get(), bio.get(),
                            /*flags*/ 0));
  EXPECT_EQ(pt_len, BIO_pending(bio.get()));
  OPENSSL_cleanse(decrypted, sizeof(decrypted));
  ASSERT_EQ(pt_len, (size_t)BIO_read(bio.get(), decrypted, sizeof(decrypted)));
  EXPECT_EQ(Bytes(buf, pt_len), Bytes(decrypted, pt_len));

  // no certs provided for decryption
  bio.reset(BIO_new_mem_buf(buf, pt_len));
  p7.reset(
      PKCS7_encrypt(certs.get(), bio.get(), EVP_aes_128_cbc(), /*flags*/ 0));
  EXPECT_TRUE(p7);
  EXPECT_TRUE(PKCS7_type_is_enveloped(p7.get()));
  bio.reset(BIO_new(BIO_s_mem()));
  EXPECT_TRUE(PKCS7_decrypt(p7.get(), rsa_pkey.get(), /*certs*/ nullptr,
                            bio.get(),
                            /*flags*/ 0));
  EXPECT_EQ(pt_len, BIO_pending(bio.get()));
  OPENSSL_cleanse(decrypted, sizeof(decrypted));
  ASSERT_EQ(pt_len, (size_t)BIO_read(bio.get(), decrypted, sizeof(decrypted)));
  EXPECT_EQ(Bytes(buf, pt_len), Bytes(decrypted, pt_len));

  // empty plaintext
  bio.reset(BIO_new(BIO_s_mem()));
  ASSERT_TRUE(BIO_set_mem_eof_return(bio.get(), 0));
  p7.reset(
      PKCS7_encrypt(certs.get(), bio.get(), EVP_aes_128_cbc(), /*flags*/ 0));
  EXPECT_TRUE(p7);
  EXPECT_TRUE(PKCS7_type_is_enveloped(p7.get()));
  bio.reset(BIO_new(BIO_s_mem()));
  ASSERT_TRUE(BIO_set_mem_eof_return(bio.get(), 0));
  EXPECT_TRUE(PKCS7_decrypt(p7.get(), rsa_pkey.get(), rsa_x509.get(), bio.get(),
                            /*flags*/ 0));
  EXPECT_EQ(0UL, BIO_pending(bio.get()));
  EXPECT_EQ(0, BIO_read(bio.get(), decrypted, sizeof(decrypted)));
  EXPECT_FALSE(BIO_should_retry(bio.get()));

  // unsupported content type, with and without content
  p7.reset(PKCS7_new());
  ASSERT_TRUE(p7);
  ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signed));
  EXPECT_FALSE(PKCS7_decrypt(p7.get(), rsa_pkey.get(), nullptr, bio.get(), 0));
  ASSERT_TRUE(PKCS7_content_new(p7.get(), NID_pkcs7_data));
  EXPECT_FALSE(PKCS7_decrypt(p7.get(), rsa_pkey.get(), nullptr, bio.get(), 0));

  // test multiple recipients using the same recipient twice. elide |cert| to
  // exercise iterative decryption attempt behavior with multiple (2) successful
  // decryptions.
  sk_X509_push(certs.get(), rsa_x509.get());
  bio.reset(BIO_new_mem_buf(buf, pt_len));
  p7.reset(
      PKCS7_encrypt(certs.get(), bio.get(), EVP_aes_128_cbc(), /*flags*/ 0));
  ASSERT_TRUE(p7);
  bio.reset(BIO_new(BIO_s_mem()));
  // set |rsa_pkey| back to original RSA key
  ASSERT_TRUE(EVP_PKEY_set1_RSA(rsa_pkey.get(), rsa.get()));
  EXPECT_TRUE(PKCS7_decrypt(p7.get(), rsa_pkey.get(), /*cert*/ nullptr,
                            bio.get(),
                            /*flags*/ 0));
  ASSERT_TRUE(sk_X509_pop(certs.get()));
  ASSERT_EQ(1LU, sk_X509_num(certs.get()));

  // test "MMA" decrypt with mismatched cert pub key/pkey private key and block
  // cipher used for content encryption
  bio.reset(BIO_new_mem_buf(buf, pt_len));
  p7.reset(
      PKCS7_encrypt(certs.get(), bio.get(), EVP_aes_128_cbc(), /*flags*/ 0));
  EXPECT_TRUE(p7);
  EXPECT_TRUE(PKCS7_type_is_enveloped(p7.get()));
  bio.reset(BIO_new(BIO_s_mem()));
  // set new RSA key, cert pub key and PKEY private key now mismatch
  rsa.reset(RSA_new());
  ASSERT_TRUE(RSA_generate_key_fips(rsa.get(), 2048, nullptr));
  ASSERT_TRUE(EVP_PKEY_set1_RSA(rsa_pkey.get(), rsa.get()));
  // attempt decryption with the new, mismatched keypair. content key decryption
  // should "succeed" and produce random, useless content decryption key.
  // The content is "decrypted" with the useless key, so nonsense gets written
  // to the output |bio|. The cipher ends up in an unhealthy state due to bad
  // padding (what should be the final pad block is now just random bytes), so
  // the overall |PKCS7_decrypt| operation fails.
  int decrypt_ok =
      PKCS7_decrypt(p7.get(), rsa_pkey.get(), /*certs*/ nullptr, bio.get(),
                    /*flags*/ 0);
  EXPECT_LE(pt_len, BIO_pending(bio.get()));
  OPENSSL_cleanse(decrypted, sizeof(decrypted));
  // There's a fun edge case here for block ciphers using conventional PKCS#7
  // padding. In this padding scheme, the last byte of the padded plaintext
  // determines how many bytes of padding have been appended and must be
  // stripped, A random MMA-defense-garbled padded plaintext with last byte of
  // 0x01 will trick the EVP API into thinking that byte is a valid padding
  // byte, so it (and only it) will be stripped. This leaves the other
  // block_size-1 bytes of the padding block in place, resulting in a larger
  // "decrypted plaintext" than anticipated. However, this doesn't only apply to
  // one byte of padding. With probability 16^-2, it applies to pad 0x02 0x02
  // and so on with increasingly small probabilities. So, we give slack up to
  // 16^-4 which means this test will erroneously fail 0.001526% of the time in
  // expectation. Ideally we'd find a way to access the padded plaintext and
  // account for this deterministically by checking the random "padding" and
  // adusting accordingly.
  const size_t max_decrypt = pt_len + EVP_CIPHER_block_size(EVP_aes_128_cbc());
  const size_t decrypted_len =
      (size_t)BIO_read(bio.get(), decrypted, sizeof(decrypted));
  ASSERT_LE(decrypted_len, sizeof(decrypted));
  if (decrypted_len > pt_len) {
    EXPECT_LT(max_decrypt - 4, decrypted_len);
    EXPECT_TRUE(decrypt_ok);
    EXPECT_FALSE(ERR_GET_REASON(ERR_peek_error()));
  } else {
    EXPECT_EQ(pt_len, decrypted_len);
    EXPECT_FALSE(decrypt_ok);
    EXPECT_EQ(CIPHER_R_BAD_DECRYPT, ERR_GET_REASON(ERR_peek_error()));
  }
  // Of course, plaintext shouldn't equal decrypted in any case here
  EXPECT_NE(Bytes(buf, pt_len), Bytes(decrypted, sizeof(decrypted)));

  // test "MMA" decrypt as above, but with stream cipher. stream cipher has no
  // padding, so content encryption should "succeed" but return nonsense because
  // the content decryption key is just randomly generated bytes.
  bio.reset(BIO_new_mem_buf(buf, pt_len));
  p7.reset(
      PKCS7_encrypt(certs.get(), bio.get(), EVP_aes_128_ctr(), /*flags*/ 0));
  EXPECT_TRUE(p7);
  EXPECT_TRUE(PKCS7_type_is_enveloped(p7.get()));
  bio.reset(BIO_new(BIO_s_mem()));
  // content decryption "succeeds"...
  EXPECT_TRUE(PKCS7_decrypt(p7.get(), rsa_pkey.get(), /*certs*/ nullptr,
                            bio.get(),
                            /*flags*/ 0));
  EXPECT_EQ(pt_len, BIO_pending(bio.get()));
  OPENSSL_cleanse(decrypted, sizeof(decrypted));
  ASSERT_EQ(pt_len, (size_t)BIO_read(bio.get(), decrypted, sizeof(decrypted)));
  // ...but it produces pseudo-random nonsense
  EXPECT_NE(Bytes(buf, pt_len), Bytes(decrypted, sizeof(decrypted)));
  EXPECT_FALSE(ERR_GET_REASON(ERR_peek_error()));

  // mismatched cert + pkey on decrypt
  bio.reset(BIO_new_mem_buf(buf, pt_len));
  p7.reset(
      PKCS7_encrypt(certs.get(), bio.get(), EVP_aes_128_cbc(), /*flags*/ 0));
  bio.reset(BIO_new(BIO_s_mem()));
  bssl::UniquePtr<RSA> rsa2(RSA_new());
  ASSERT_TRUE(RSA_generate_key_fips(rsa2.get(), 2048, nullptr));
  ASSERT_TRUE(EVP_PKEY_set1_RSA(rsa_pkey.get(), rsa2.get()));
  EXPECT_FALSE(PKCS7_decrypt(p7.get(), rsa_pkey.get(), rsa_x509.get(),
                             bio.get(),
                             /*flags*/ 0));
  EXPECT_EQ(X509_R_KEY_VALUES_MISMATCH, ERR_GET_REASON(ERR_peek_error()));
}

TEST(PKCS7Test, TestSigned) {
  bssl::UniquePtr<PKCS7> p7;
  bssl::UniquePtr<BIO> bio_in, bio_out;
  bssl::UniquePtr<STACK_OF(X509)> certs;
  bssl::UniquePtr<X509_STORE> store;
  bssl::UniquePtr<X509_STORE_CTX> store_ctx;
  bssl::UniquePtr<ASN1_TIME> not_before, not_after;
  bssl::UniquePtr<RSA> root_rsa, leaf_rsa;
  bssl::UniquePtr<EVP_PKEY> root_pkey, leaf_pkey;
  uint8_t buf[64], out_buf[sizeof(buf)];

  OPENSSL_memset(buf, 'A', sizeof(buf));
  OPENSSL_memset(out_buf, '\0', sizeof(out_buf));

  root_rsa.reset(RSA_new());
  ASSERT_TRUE(RSA_generate_key_fips(root_rsa.get(), 2048, nullptr));
  root_pkey.reset(EVP_PKEY_new());
  ASSERT_TRUE(EVP_PKEY_set1_RSA(root_pkey.get(), root_rsa.get()));
  leaf_rsa.reset(RSA_new());
  ASSERT_TRUE(RSA_generate_key_fips(leaf_rsa.get(), 2048, nullptr));
  leaf_pkey.reset(EVP_PKEY_new());
  ASSERT_TRUE(EVP_PKEY_set1_RSA(leaf_pkey.get(), leaf_rsa.get()));

  // |PKCS7_verify| creates its own X509_STORE_CTX internally, so we can't set
  // relative validity time on the store it uses from here (by default
  // X509_STORE_CTX uses std's |time|). So, we set a wide validity gap here.
  // |not_after| won't need to be updated until December 9999 and |not_before|
  // would only need to be reconsidered in the advent of a time machine.
  not_before.reset(ASN1_TIME_set_posix(nullptr, 0L));
  not_after.reset(ASN1_TIME_set_posix(nullptr, INT64_C(253402300799)));

  bssl::UniquePtr<X509> root =
      MakeTestCert("Root", "Root", root_pkey.get(), /*is_ca=*/true);
  ASSERT_TRUE(root);
  ASSERT_TRUE(X509_set_notBefore(root.get(), not_before.get()));
  ASSERT_TRUE(X509_set_notAfter(root.get(), not_after.get()));
  // Root signs itself
  ASSERT_TRUE(X509_sign(root.get(), root_pkey.get(), EVP_sha256()));

  bssl::UniquePtr<X509> leaf =
      MakeTestCert("Root", "Leaf", leaf_pkey.get(), /*is_ca=*/false);
  ASSERT_TRUE(leaf);
  ASSERT_TRUE(X509_set_notBefore(leaf.get(), not_before.get()));
  ASSERT_TRUE(X509_set_notAfter(leaf.get(), not_after.get()));
  // Root signs leaf
  ASSERT_TRUE(X509_sign(leaf.get(), root_pkey.get(), EVP_sha256()));
  X509_up_ref(leaf.get());
  X509_up_ref(leaf.get());

  store.reset(X509_STORE_new());
  ASSERT_TRUE(X509_STORE_add_cert(store.get(), root.get()));

  certs.reset(sk_X509_new_null());
  ASSERT_TRUE(sk_X509_push(certs.get(), leaf.get()));

  bio_in.reset(BIO_new_mem_buf(buf, sizeof(buf)));
  p7.reset(PKCS7_sign(leaf.get(), leaf_pkey.get(), nullptr, bio_in.get(),
                      /*flags*/ 0));
  ASSERT_TRUE(p7);
  EXPECT_TRUE(PKCS7_type_is_signed(p7.get()));

  STACK_OF(X509) *signers = PKCS7_get0_signers(p7.get(), certs.get(), 0);
  EXPECT_TRUE(signers);
  sk_X509_free(signers);
  EXPECT_FALSE(PKCS7_is_detached(p7.get()));

  // attached, check |outdata|
  bio_out.reset(BIO_new(BIO_s_mem()));
  // passing non-null |indata| with attached content should fail
  EXPECT_FALSE(PKCS7_verify(p7.get(), certs.get(), store.get(), bio_in.get(),
                            bio_out.get(), /*flags*/ 0));
  // but otherwise, it should succeed
  EXPECT_TRUE(PKCS7_verify(p7.get(), certs.get(), store.get(), nullptr,
                           bio_out.get(), /*flags*/ 0));
  ASSERT_EQ((int)sizeof(out_buf),
            BIO_read(bio_out.get(), out_buf, sizeof(out_buf)));
  EXPECT_EQ(Bytes(buf, sizeof(buf)), Bytes(out_buf, sizeof(out_buf)));

  // attached, but no |outdata|
  bio_in.reset(BIO_new_mem_buf(buf, sizeof(buf)));
  p7.reset(PKCS7_sign(leaf.get(), leaf_pkey.get(), nullptr, bio_in.get(),
                      /*flags*/ 0));
  EXPECT_TRUE(PKCS7_verify(p7.get(), certs.get(), store.get(),
                           /*indata*/ nullptr,
                           /*outdata*/ nullptr, /*flags*/ 0));

  // attached, but specify |PKCS7_NOINTERN| to ignore bundled certs. this should
  // fail when we elide the |certs| parameter to verify and succeed when we
  // provide it.
  bio_in.reset(BIO_new_mem_buf(buf, sizeof(buf)));
  p7.reset(PKCS7_sign(leaf.get(), leaf_pkey.get(), nullptr, bio_in.get(),
                      /*flags*/ 0));
  EXPECT_FALSE(PKCS7_verify(p7.get(), /*certs*/ nullptr, store.get(),
                            /*indata*/ nullptr,
                            /*outdata*/ nullptr, /*flags*/ PKCS7_NOINTERN));
  EXPECT_TRUE(PKCS7_verify(p7.get(), certs.get(), store.get(),
                           /*indata*/ nullptr,
                           /*outdata*/ nullptr, /*flags*/ PKCS7_NOINTERN));

  // detached
  bio_in.reset(BIO_new_mem_buf(buf, sizeof(buf)));
  // PKCS7_NOCERTS isn't supported
  ASSERT_FALSE(PKCS7_sign(leaf.get(), leaf_pkey.get(), nullptr, bio_in.get(),
                          (PKCS7_DETACHED | PKCS7_NOCERTS)));
  // but this should work fine without it
  p7.reset(PKCS7_sign(leaf.get(), leaf_pkey.get(), nullptr, bio_in.get(),
                      PKCS7_DETACHED));
  EXPECT_TRUE(PKCS7_is_detached(p7.get()));
  certs.reset(sk_X509_new_null());
  ASSERT_TRUE(sk_X509_push(certs.get(), leaf.get()));
  bio_in.reset(BIO_new_mem_buf(buf, sizeof(buf)));
  bio_out.reset(BIO_new(BIO_s_mem()));
  // detached mode requires data to be passed in via |indata
  EXPECT_FALSE(PKCS7_verify(p7.get(), certs.get(), store.get(), nullptr,
                            bio_out.get(), /*flags*/ 0));
  // but once we provide the |indata|, it should work
  EXPECT_TRUE(PKCS7_verify(p7.get(), certs.get(), store.get(), bio_in.get(),
                           bio_out.get(), /*flags*/ 0));
  OPENSSL_memset(out_buf, '\0', sizeof(out_buf));
  ASSERT_EQ((int)sizeof(out_buf),
            BIO_read(bio_out.get(), out_buf, sizeof(out_buf)));
  EXPECT_EQ(Bytes(buf, sizeof(buf)), Bytes(out_buf, sizeof(out_buf)));

  // Error cases
  p7.reset(PKCS7_new());
  ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_enveloped));
  BIO *bio_tmp = nullptr;
  EXPECT_FALSE(SMIME_read_PKCS7(bio_in.get(), &bio_tmp));
  ASSERT_FALSE(bio_tmp);  // never gets allocated
  EXPECT_FALSE(SMIME_write_PKCS7(bio_in.get(), p7.get(), bio_tmp, 0));
  EXPECT_FALSE(PKCS7_verify(p7.get(), nullptr, store.get(), bio_in.get(),
                            bio_out.get(), 0));   // |p7| is wrong type
  EXPECT_FALSE(PKCS7_get_signer_info(p7.get()));  // |p7| is wrong type

  // Misatched sign/verify keys
  bssl::UniquePtr<RSA> other_rsa;
  bssl::UniquePtr<EVP_PKEY> other_pkey;
  other_rsa.reset(RSA_new());
  ASSERT_TRUE(RSA_generate_key_fips(other_rsa.get(), 2048, nullptr));
  other_pkey.reset(EVP_PKEY_new());
  ASSERT_TRUE(EVP_PKEY_set1_RSA(other_pkey.get(), other_rsa.get()));
  bio_in.reset(BIO_new_mem_buf(buf, sizeof(buf)));
  p7.reset(PKCS7_sign(leaf.get(), other_pkey.get(), nullptr, bio_in.get(),
                      /*flags*/ 0));
  EXPECT_FALSE(PKCS7_verify(p7.get(), nullptr, store.get(), nullptr,
                            bio_out.get(), /*flags*/ 0));

  // Use different detached indata to induce signature mismatch
  bio_in.reset(BIO_new_mem_buf(buf, sizeof(buf)));
  p7.reset(PKCS7_sign(leaf.get(), leaf_pkey.get(), nullptr, bio_in.get(),
                      PKCS7_DETACHED));
  uint8_t other_data[sizeof(buf)];
  OPENSSL_memset(other_data, 'B', sizeof(other_data));
  bio_in.reset(BIO_new_mem_buf(other_data, sizeof(other_data)));
  bio_out.reset(BIO_new(BIO_s_mem()));
  EXPECT_FALSE(PKCS7_verify(p7.get(), certs.get(), store.get(), bio_in.get(),
                            bio_out.get(), /*flags*/ 0));
}

// Regression test: PKCS7_verify with detached data and multiple digest
// algorithms must free all intermediate digest BIOs, not just the head.
TEST(PKCS7Test, VerifyDetachedMultiDigestNoLeak) {
  // Generate two distinct ECDSA key-pairs and leaf certificates so that each
  // signer can use a different digest algorithm.
  bssl::UniquePtr<EC_KEY> root_ec(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
  ASSERT_TRUE(root_ec);
  ASSERT_TRUE(EC_KEY_generate_key(root_ec.get()));
  bssl::UniquePtr<EVP_PKEY> root_pkey(EVP_PKEY_new());
  ASSERT_TRUE(EVP_PKEY_set1_EC_KEY(root_pkey.get(), root_ec.get()));

  bssl::UniquePtr<EC_KEY> leaf1_ec(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
  ASSERT_TRUE(leaf1_ec);
  ASSERT_TRUE(EC_KEY_generate_key(leaf1_ec.get()));
  bssl::UniquePtr<EVP_PKEY> leaf1_pkey(EVP_PKEY_new());
  ASSERT_TRUE(EVP_PKEY_set1_EC_KEY(leaf1_pkey.get(), leaf1_ec.get()));

  bssl::UniquePtr<EC_KEY> leaf2_ec(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
  ASSERT_TRUE(leaf2_ec);
  ASSERT_TRUE(EC_KEY_generate_key(leaf2_ec.get()));
  bssl::UniquePtr<EVP_PKEY> leaf2_pkey(EVP_PKEY_new());
  ASSERT_TRUE(EVP_PKEY_set1_EC_KEY(leaf2_pkey.get(), leaf2_ec.get()));

  bssl::UniquePtr<ASN1_TIME> not_before(ASN1_TIME_set_posix(nullptr, 0L));
  bssl::UniquePtr<ASN1_TIME> not_after(
      ASN1_TIME_set_posix(nullptr, INT64_C(253402300799)));

  bssl::UniquePtr<X509> root =
      MakeTestCert("Root", "Root", root_pkey.get(), /*is_ca=*/true);
  ASSERT_TRUE(root);
  ASSERT_TRUE(X509_set_notBefore(root.get(), not_before.get()));
  ASSERT_TRUE(X509_set_notAfter(root.get(), not_after.get()));
  ASSERT_TRUE(X509_sign(root.get(), root_pkey.get(), EVP_sha256()));

  bssl::UniquePtr<X509> leaf1 =
      MakeTestCert("Root", "Leaf1", leaf1_pkey.get(), /*is_ca=*/false);
  ASSERT_TRUE(leaf1);
  ASSERT_TRUE(X509_set_notBefore(leaf1.get(), not_before.get()));
  ASSERT_TRUE(X509_set_notAfter(leaf1.get(), not_after.get()));
  ASSERT_TRUE(X509_sign(leaf1.get(), root_pkey.get(), EVP_sha256()));

  bssl::UniquePtr<X509> leaf2 =
      MakeTestCert("Root", "Leaf2", leaf2_pkey.get(), /*is_ca=*/false);
  ASSERT_TRUE(leaf2);
  ASSERT_TRUE(X509_set_notBefore(leaf2.get(), not_before.get()));
  ASSERT_TRUE(X509_set_notAfter(leaf2.get(), not_after.get()));
  ASSERT_TRUE(X509_sign(leaf2.get(), root_pkey.get(), EVP_sha256()));

  // Build a PKCS7 signed structure with two signers using *different* digest
  // algorithms. This causes PKCS7_dataInit to create two digest BIOs.
  bssl::UniquePtr<PKCS7> p7(PKCS7_new());
  ASSERT_TRUE(p7);
  ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signed));
  ASSERT_TRUE(PKCS7_content_new(p7.get(), NID_pkcs7_data));

  // Signer 1: SHA-256
  PKCS7_SIGNER_INFO *si1 = PKCS7_SIGNER_INFO_new();
  ASSERT_TRUE(si1);
  ASSERT_TRUE(
      PKCS7_SIGNER_INFO_set(si1, leaf1.get(), leaf1_pkey.get(), EVP_sha256()));
  ASSERT_TRUE(PKCS7_add_signer(p7.get(), si1));
  ASSERT_TRUE(PKCS7_add_certificate(p7.get(), leaf1.get()));

  // Signer 2: SHA-384 (different digest => second digest BIO in chain)
  PKCS7_SIGNER_INFO *si2 = PKCS7_SIGNER_INFO_new();
  ASSERT_TRUE(si2);
  ASSERT_TRUE(
      PKCS7_SIGNER_INFO_set(si2, leaf2.get(), leaf2_pkey.get(), EVP_sha384()));
  ASSERT_TRUE(PKCS7_add_signer(p7.get(), si2));
  ASSERT_TRUE(PKCS7_add_certificate(p7.get(), leaf2.get()));

  // Make it a detached signature.
  ASN1_OCTET_STRING_free(p7->d.sign->contents->d.data);
  p7->d.sign->contents->d.data = NULL;

  // The signatures don't need to be valid for this leak test -- the leak
  // happens during teardown regardless of verification outcome. Just add dummy
  // signer info entries so PKCS7_get_signer_info returns them and the code
  // path that builds the BIO chain in PKCS7_dataInit is reached.

  // Call PKCS7_verify with detached indata. The BIO chain teardown is where
  // intermediate digest BIOs are leaked.
  uint8_t buf[64];
  OPENSSL_memset(buf, 'A', sizeof(buf));
  bssl::UniquePtr<X509_STORE> store(X509_STORE_new());
  ASSERT_TRUE(X509_STORE_add_cert(store.get(), root.get()));

  bssl::UniquePtr<BIO> indata(BIO_new_mem_buf(buf, sizeof(buf)));
  ASSERT_TRUE(indata);
  bssl::UniquePtr<BIO> outdata(BIO_new(BIO_s_mem()));
  ASSERT_TRUE(outdata);

  // Verification will fail (signatures are not computed), but the BIO chain
  // teardown still runs to exercise the leak.
  PKCS7_verify(p7.get(), nullptr, store.get(), indata.get(), outdata.get(),
               PKCS7_NOVERIFY);
}

TEST(PKCS7Test, PKCS7PrintNoop) {
  bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
  bssl::UniquePtr<PKCS7> p7(PKCS7_new());
  ASSERT_TRUE(PKCS7_print_ctx(bio.get(), p7.get(), 0, nullptr));

  const uint8_t *contents;
  size_t len;
  ASSERT_TRUE(BIO_mem_contents(bio.get(), &contents, &len));
  EXPECT_EQ(Bytes(contents, len), Bytes("PKCS7 printing is not supported"));
}

TEST(PKCS7Test, SetDetached) {
  bssl::UniquePtr<PKCS7> p7(PKCS7_new());
  // |PKCS7_set_detached| does not work on an uninitialized |PKCS7|.
  EXPECT_FALSE(PKCS7_set_detached(p7.get(), 0));
  EXPECT_FALSE(PKCS7_set_detached(p7.get(), 1));
  EXPECT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signed));
  EXPECT_TRUE(PKCS7_type_is_signed(p7.get()));

  PKCS7 *p7_internal = PKCS7_new();
  EXPECT_TRUE(PKCS7_set_type(p7_internal, NID_pkcs7_data));
  EXPECT_TRUE(PKCS7_type_is_data(p7_internal));
  EXPECT_TRUE(PKCS7_set_content(p7.get(), p7_internal));

  // Access the |p7|'s internal contents to verify that |PKCS7_set_detached|
  // has the right behavior.
  EXPECT_TRUE(p7.get()->d.sign->contents->d.data);
  EXPECT_TRUE(PKCS7_set_detached(p7.get(), 0));
  EXPECT_TRUE(p7.get()->d.sign->contents->d.data);
  EXPECT_FALSE(PKCS7_set_detached(p7.get(), 2));
  EXPECT_TRUE(p7.get()->d.sign->contents->d.data);
  // data is "detached" when |PKCS7_set_detached| is set with 1.
  EXPECT_TRUE(PKCS7_set_detached(p7.get(), 1));
  EXPECT_FALSE(p7.get()->d.sign->contents->d.data);
}

TEST(PKCS7Test, PKCS7SignedAttributes) {
  // This file was generated with the following command:
  // openssl smime -sign -in input.txt -signer crypto/ocsp/aws/ca_cert.pem
  //        -inkey crypto/ocsp/aws/ca_key.pem -out signed.p7s -outform PEM
  //        -nodetach -md sha512
  //
  // Files with signed attributes aren't generatable with AWS-LC for now, as
  // |PKCS7_NOATTR| is always assumed with |PKCS7_sign|. See |PKCS7_sign|
  // for more details.
  static const char kPKCS7SignedAttributes[] = R"(
-----BEGIN PKCS7-----
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
-----END PKCS7-----
)";

  // Timestamp for March 11, 2025.
  static const int64_t kReferencePKCS7Time = 1741824000;

  const bssl::UniquePtr<BIO> bio(
      BIO_new_mem_buf(kPKCS7SignedAttributes, strlen(kPKCS7SignedAttributes)));
  ASSERT_TRUE(bio);
  bssl::UniquePtr<PKCS7> pkcs7(
      PEM_read_bio_PKCS7(bio.get(), nullptr, nullptr, nullptr));
  ASSERT_TRUE(pkcs7);
  ASSERT_TRUE(PKCS7_type_is_signed(pkcs7.get()));
  STACK_OF(X509) *signers = PKCS7_get0_signers(pkcs7.get(), nullptr, 0);
  EXPECT_TRUE(signers);
  sk_X509_free(signers);

  // Set up trust store for verification.
  bssl::UniquePtr<X509_STORE> store(X509_STORE_new());
  bssl::UniquePtr<X509> ca_cert(CertFromPEM(
      GetTestData(std::string("crypto/ocsp/test/aws/ca_cert.pem").c_str())
          .c_str()));
  ASSERT_TRUE(X509_STORE_add_cert(store.get(), ca_cert.get()));

  // Set a valid time to avoid time bomb in tests.
  X509_VERIFY_PARAM *param = X509_STORE_get0_param(store.get());
  X509_VERIFY_PARAM_set_time_posix(param, kReferencePKCS7Time);

  bssl::UniquePtr<BIO> out(BIO_new(BIO_s_mem()));
  EXPECT_TRUE(PKCS7_verify(pkcs7.get(), nullptr, store.get(), nullptr,
                           out.get(), /*flags*/ 0));

  // Run |PKCS7_verify| again to check that we're consuming a copy of the
  // underlying |EVP_MD_CTX|.
  EXPECT_TRUE(PKCS7_verify(pkcs7.get(), nullptr, store.get(), nullptr,
                           out.get(), /*flags*/ 0));
}

TEST(PKCS7Test, PKCS7SignedAttributesRuby) {
  // The following test file was taken from ruby/openssl's pkcs7 tests.
  static const char kPKCS7Ruby[] = R"(
-----BEGIN PKCS7-----
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
-----END PKCS7-----
)";

  // The test has an expected output. Check that we output the same contents
  // as OpenSSL.
  static const char kPKCS7RubyOpenSSLOutput[] =
      R"(-----BEGIN PKCS7-----
MIIDawYJKoZIhvcNAQcDoIIDXDCCA1gCAQAxggEQMIIBDAIBADB1MHAxEDAOBgNV
BAoMB2V4YW1wbGUxFzAVBgNVBAMMDlRBUk1BQyBST09UIENBMSIwIAYJKoZIhvcN
AQkBFhNzb21lb25lQGV4YW1wbGUub3JnMQswCQYDVQQGEwJVUzESMBAGA1UEBwwJ
VG93biBIYWxsAgFmMA0GCSqGSIb3DQEBAQUABIGAbKV17HvGYRtRRBNz1QLpW763
UedhVj5KXi70o4BJGM04lItAgt6aFC9SruZjpWr1gCYKCaRSAg273DeGTQwsDoZ8
6CPXzBpptYLz0MteQXYYWUaPZT+xmvx4NgDyk9P9MoT7JifsPrtXuzqCRFXhGdu8
d/ru+OWxhHLvKH+bYekwggI9BgkqhkiG9w0BBwEwFAYIKoZIhvcNAwcECBNs2U5m
Msd/gIICGFOnLq/EAc9Nv+HjKR3ZVPSJMq0TImjGf5Mvc3nDgI572Hdo2aku0YXM
6WjSWkpYtxpg7Cqxfl6hPSefLPUnBqlIoM2qbrE7MSKEVD6+2bW9GqYPFVg4qQLL
sOxnxJIMfOvLFfd7guL+iLH424XfiUUxaf8EdZE4u2IEl4REvkS1FoEGwyA4BEGM
SeVPedQCbZ0qY7Pc2tmZE3XfEUhIsyStG0Nb6i6AKcAFYGapbgE6kAB0gwsYcHlW
MOvsvdAfcTq6jwtHlO1s68qtvkWquTQ9lpX+fzddUUNxEHSqv5eU3oo6fT3Vj5ZF
IVlaA5ThZMrI5PgRPuwJM4GL8/VLwY5mbDLFqn/irGeEvP99J3S87ornLLunjpxS
y1/AymcVep2H32Tj82WS/IRQXBOzz4EnQRJGszKxAV6tY+Zje3sWyTTgObhlsiTQ
TDgnvtSW8RvVHqKrwgkxxEsRHg7u8UdzZ0jg+O5+3F8B6/NWMyts0OaFqT9wvI8y
O7VIy3dUtGdz7Hde6Ggp/iTn1LbgdJ3N8Hzxf1j6NMWUKHVsadvwpRJbUeqq9c3+
QuxsJi8wWemxxQCE+tPyc1dP+ej5/M7bERbSOHMGgX03758IvP7A/fy2DjGPv2+l
AwlEke0Uze1367QKgxM0nc3SZDlptY7zPIJC5saWXb8Rt2bw2JxEBOTavrp+ZwJ8
tcH961onq8Tme2ICaCzk
-----END PKCS7-----
)";

  const bssl::UniquePtr<BIO> bio(
      BIO_new_mem_buf(kPKCS7Ruby, strlen(kPKCS7Ruby)));
  ASSERT_TRUE(bio);
  bssl::UniquePtr<PKCS7> pkcs7(
      PEM_read_bio_PKCS7(bio.get(), nullptr, nullptr, nullptr));
  ASSERT_TRUE(pkcs7);
  ASSERT_TRUE(PKCS7_type_is_signed(pkcs7.get()));

  // Verify the file how Ruby's tests do it.
  bssl::UniquePtr<X509_STORE> store(X509_STORE_new());
  bssl::UniquePtr<BIO> out(BIO_new(BIO_s_mem()));
  EXPECT_TRUE(PKCS7_verify(pkcs7.get(), nullptr, store.get(), nullptr,
                           out.get(), /*flags*/ PKCS7_NOVERIFY));

  // The following is bit wonky with the pkcs7 bytes being read and rewritten,
  // but that's how Ruby's underlying PKCS7 test gets the PEM output.
  BUF_MEM *buf;
  BIO_get_mem_ptr(out.get(), &buf);
  bssl::UniquePtr<BIO> out2(BIO_new_mem_buf(buf->data, buf->length));
  bssl::UniquePtr<PKCS7> new_pk7(d2i_PKCS7_bio(out2.get(), nullptr));
  ASSERT_TRUE(new_pk7);

  bssl::UniquePtr<BIO> out3(BIO_new(BIO_s_mem()));
  ASSERT_TRUE(PEM_write_bio_PKCS7(out3.get(), new_pk7.get()));
  BIO_get_mem_ptr(out3.get(), &buf);
  EXPECT_EQ(Bytes(buf->data, buf->length), Bytes(kPKCS7RubyOpenSSLOutput));
}


static const unsigned char test_data[] = {0x30, 0x02, 0x01, 0x02};

static bssl::UniquePtr<PKCS7> pkcs7_with_other(const unsigned char *data,
                                               int data_len) {
  bssl::UniquePtr<PKCS7> p7(PKCS7_new());
  if (!p7) {
    return nullptr;
  }

  bssl::UniquePtr<ASN1_STRING> seq(ASN1_STRING_new());
  if (!seq || !ASN1_STRING_set(seq.get(), data, data_len)) {
    return nullptr;
  }

  // Set up the ASN.1 structure
  p7->d.other = ASN1_TYPE_new();
  if (!p7->d.other) {
    return nullptr;
  }

  ASN1_TYPE_set(p7->d.other, V_ASN1_OCTET_STRING, seq.release());

  return p7;
}

TEST(PKCS7Test, OtherFieldMemoryLeak) {
  // Set up the ASN.1 structure
  // |p7->type| is intentionally undefined. OpenSSL frees all contents whether
  // it's defined or not.
  bssl::UniquePtr<PKCS7> p7(pkcs7_with_other(test_data, sizeof(test_data)));

  ASSERT_EQ(p7->d.other->type, V_ASN1_OCTET_STRING);
  EXPECT_EQ(p7->d.other->value.sequence->length,
            static_cast<int>(sizeof(test_data)));
  EXPECT_EQ(OPENSSL_memcmp(p7->d.other->value.sequence->data, test_data,
                           sizeof(test_data)),
            0);
}

TEST(PKCS7Test, SerdeOtherField) {
  // Create PKCS7 and required ASN.1 structures. |p7->type | needs to be defined
  // to be properly serialized.
  bssl::UniquePtr<PKCS7> p7(pkcs7_with_other(test_data, sizeof(test_data)));
  p7->type = OBJ_nid2obj(NID_pkcs7);

  // Serialize the original object. This should echo back the original saved
  // bytes.
  uint8_t *bytes = nullptr;
  int bytes_len = i2d_PKCS7(p7.get(), &bytes);
  ASSERT_GT(bytes_len, 0);
  bssl::UniquePtr<uint8_t> free_bytes(bytes);

  const uint8_t *ptr = bytes;
  bssl::UniquePtr<PKCS7> pkcs7_obj(d2i_PKCS7(nullptr, &ptr, bytes_len));
  ASSERT_TRUE(pkcs7_obj);
  ASSERT_EQ(p7->d.other->type, V_ASN1_OCTET_STRING);
  EXPECT_EQ(p7->d.other->value.sequence->length,
            static_cast<int>(sizeof(test_data)));
  EXPECT_EQ(OPENSSL_memcmp(p7->d.other->value.sequence->data, test_data,
                           sizeof(test_data)),
            0);
}

// Test for signature bypass when authenticated attributes contain a
// malformed attribute that causes ASN.1 re-encoding to fail.
TEST(PKCS7Test, SignatureBypassWithMalformedAuthAttr) {
  const unsigned char original_data[] = "Original legitimate content";
  const size_t original_len = sizeof(original_data) - 1;
  const unsigned char malicious_data[] = "MALICIOUS MODIFIED CONTENT!";
  const size_t malicious_len = sizeof(malicious_data) - 1;

  // Generate RSA key pair
  bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
  ASSERT_TRUE(pkey);
  bssl::UniquePtr<EVP_PKEY_CTX> pkey_ctx(
      EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr));
  ASSERT_TRUE(pkey_ctx);
  ASSERT_TRUE(EVP_PKEY_keygen_init(pkey_ctx.get()));
  ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_keygen_bits(pkey_ctx.get(), 2048));
  EVP_PKEY *pkey_raw = nullptr;
  ASSERT_TRUE(EVP_PKEY_keygen(pkey_ctx.get(), &pkey_raw));
  pkey.reset(pkey_raw);

  // Create self-signed certificate
  bssl::UniquePtr<X509> cert(X509_new());
  ASSERT_TRUE(cert);
  ASSERT_TRUE(X509_set_version(cert.get(), 2));
  ASSERT_TRUE(ASN1_INTEGER_set(X509_get_serialNumber(cert.get()), 1));
  X509_gmtime_adj(X509_get_notBefore(cert.get()), 0);
  X509_gmtime_adj(X509_get_notAfter(cert.get()), 31536000L);
  ASSERT_TRUE(X509_set_pubkey(cert.get(), pkey.get()));
  X509_NAME *name = X509_get_subject_name(cert.get());
  ASSERT_TRUE(X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
                                          (const unsigned char *)"Test",
                                          -1, -1, 0));
  ASSERT_TRUE(X509_set_issuer_name(cert.get(), name));
  ASSERT_TRUE(X509_sign(cert.get(), pkey.get(), EVP_sha256()));

  // Set up trust store
  bssl::UniquePtr<X509_STORE> store(X509_STORE_new());
  ASSERT_TRUE(store);
  ASSERT_TRUE(X509_STORE_add_cert(store.get(), cert.get()));

  // Compute SHA-256 digest of original data
  unsigned char md[SHA256_DIGEST_LENGTH];
  SHA256(original_data, original_len, md);

  // Create the PKCS7 SignedData structure
  bssl::UniquePtr<PKCS7> p7(PKCS7_new());
  ASSERT_TRUE(p7);
  ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signed));
  ASSERT_TRUE(PKCS7_content_new(p7.get(), NID_pkcs7_data));

  // Set the content payload
  ASSERT_TRUE(ASN1_OCTET_STRING_set(p7->d.sign->contents->d.data,
                                     original_data, (int)original_len));

  // Add SHA-256 to the digest algorithms set
  X509_ALGOR *alg = X509_ALGOR_new();
  ASSERT_TRUE(alg);
  ASSERT_TRUE(
      X509_ALGOR_set0(alg, OBJ_nid2obj(NID_sha256), V_ASN1_NULL, nullptr));
  ASSERT_TRUE(sk_X509_ALGOR_push(p7->d.sign->md_algs, alg));

  // Create and configure SIGNER_INFO
  PKCS7_SIGNER_INFO *sinfo = PKCS7_SIGNER_INFO_new();
  ASSERT_TRUE(sinfo);
  ASSERT_TRUE(
      PKCS7_SIGNER_INFO_set(sinfo, cert.get(), pkey.get(), EVP_sha256()));

  // Build authenticated attributes: contentType + messageDigest
  sinfo->auth_attr = sk_X509_ATTRIBUTE_new_null();
  ASSERT_TRUE(sinfo->auth_attr);

  // Add contentType attribute (pkcs7-data)
  ASN1_OBJECT *content_type_obj = OBJ_dup(OBJ_nid2obj(NID_pkcs7_data));
  ASSERT_TRUE(content_type_obj);
  X509_ATTRIBUTE *ct_attr = X509_ATTRIBUTE_create(
      NID_pkcs9_contentType, V_ASN1_OBJECT, content_type_obj);
  ASSERT_TRUE(ct_attr);
  ASSERT_TRUE(sk_X509_ATTRIBUTE_push(sinfo->auth_attr, ct_attr));

  // Add messageDigest attribute
  ASN1_OCTET_STRING *digest_os = ASN1_OCTET_STRING_new();
  ASSERT_TRUE(digest_os);
  ASSERT_TRUE(ASN1_OCTET_STRING_set(digest_os, md, SHA256_DIGEST_LENGTH));
  X509_ATTRIBUTE *md_attr = X509_ATTRIBUTE_create(
      NID_pkcs9_messageDigest, V_ASN1_OCTET_STRING, digest_os);
  ASSERT_TRUE(md_attr);
  ASSERT_TRUE(sk_X509_ATTRIBUTE_push(sinfo->auth_attr, md_attr));

  // DER-encode the authenticated attributes for signing
  unsigned char *attr_der = nullptr;
  int attr_der_len = ASN1_item_i2d((ASN1_VALUE *)sinfo->auth_attr, &attr_der,
                                    ASN1_ITEM_rptr(PKCS7_ATTR_VERIFY));
  ASSERT_GT(attr_der_len, 0);
  ASSERT_TRUE(attr_der);

  // Sign the DER-encoded authenticated attributes
  bssl::UniquePtr<EVP_MD_CTX> md_ctx(EVP_MD_CTX_new());
  ASSERT_TRUE(md_ctx);
  ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), nullptr, EVP_sha256(), nullptr,
                                  pkey.get()));
  ASSERT_TRUE(EVP_DigestSignUpdate(md_ctx.get(), attr_der, attr_der_len));

  size_t sig_len = 0;
  ASSERT_TRUE(EVP_DigestSignFinal(md_ctx.get(), nullptr, &sig_len));
  unsigned char *sig =
      (unsigned char *)OPENSSL_malloc(sig_len);
  ASSERT_TRUE(sig);
  ASSERT_TRUE(EVP_DigestSignFinal(md_ctx.get(), sig, &sig_len));

  // Set the signature on the signer info
  ASSERT_TRUE(
      ASN1_OCTET_STRING_set(sinfo->enc_digest, sig, (int)sig_len));
  OPENSSL_free(sig);
  OPENSSL_free(attr_der);

  // Attach signer info and certificate to the PKCS7
  ASSERT_TRUE(sk_PKCS7_SIGNER_INFO_push(p7->d.sign->signer_info, sinfo));
  ASSERT_TRUE(PKCS7_add_certificate(p7.get(), cert.get()));

  // Verify the original (unmodified) message succeeds
  bssl::UniquePtr<BIO> out_bio(BIO_new(BIO_s_mem()));
  ASSERT_TRUE(out_bio);
  EXPECT_TRUE(PKCS7_verify(p7.get(), nullptr, store.get(), nullptr,
                            out_bio.get(), /*flags*/ 0));

  // Now tamper with the message to attempt bypass

  // Get the signer info back for modification
  STACK_OF(PKCS7_SIGNER_INFO) *sinfos = PKCS7_get_signer_info(p7.get());
  ASSERT_TRUE(sinfos);
  ASSERT_GT(sk_PKCS7_SIGNER_INFO_num(sinfos), (size_t)0);
  PKCS7_SIGNER_INFO *sinfo_ptr = sk_PKCS7_SIGNER_INFO_value(sinfos, 0);
  ASSERT_TRUE(sinfo_ptr);

  // Modify the content to malicious data
  ASSERT_TRUE(PKCS7_type_is_signed(p7.get()));
  ASSERT_TRUE(p7->d.sign && p7->d.sign->contents);
  ASSERT_EQ(OBJ_obj2nid(p7->d.sign->contents->type), NID_pkcs7_data);
  ASSERT_TRUE(ASN1_OCTET_STRING_set(p7->d.sign->contents->d.data,
                                     malicious_data, (int)malicious_len));

  // Update the messageDigest attribute to match the malicious content
  unsigned char new_md[SHA256_DIGEST_LENGTH];
  SHA256(malicious_data, malicious_len, new_md);
  ASN1_TYPE *md_type =
      PKCS7_get_signed_attribute(sinfo_ptr, NID_pkcs9_messageDigest);
  ASSERT_TRUE(md_type);
  ASSERT_EQ(md_type->type, V_ASN1_OCTET_STRING);
  ASSERT_TRUE(ASN1_OCTET_STRING_set(md_type->value.octet_string, new_md,
                                     SHA256_DIGEST_LENGTH));

  // Add a malformed attribute whose ASN1_OBJECT has zero length.
  // This causes ASN1_item_i2d() to fail with ASN1_R_ILLEGAL_OBJECT when
  // pkcs7_signature_verify() tries to re-encode auth_attr for signature
  // verification.
  ASN1_OCTET_STRING *bad_os = ASN1_OCTET_STRING_new();
  ASSERT_TRUE(bad_os);
  ASSERT_TRUE(
      ASN1_OCTET_STRING_set(bad_os, (const unsigned char *)"test", 4));
  X509_ATTRIBUTE *bad_attr = X509_ATTRIBUTE_create(
      NID_id_smime_aa_signingCertificate, V_ASN1_OCTET_STRING, bad_os);
  ASSERT_TRUE(bad_attr);

  // Create an ASN1_OBJECT with zero-length OID data. When ASN1_item_i2d
  // tries to encode this, i2d_ASN1_OBJECT returns -1 because length <= 0,
  // which makes the overall encoding fail safely.
  bssl::UniquePtr<ASN1_OBJECT> empty_obj(
      ASN1_OBJECT_create(NID_undef, nullptr, 0, nullptr, nullptr));
  ASSERT_TRUE(empty_obj);
  ASSERT_TRUE(X509_ATTRIBUTE_set1_object(bad_attr, empty_obj.get()));

  ASSERT_TRUE(sk_X509_ATTRIBUTE_push(sinfo_ptr->auth_attr, bad_attr));

  // Verify that the tampered message is correctly rejected
  out_bio.reset(BIO_new(BIO_s_mem()));
  ASSERT_TRUE(out_bio);
  EXPECT_FALSE(PKCS7_verify(p7.get(), nullptr, store.get(), nullptr,
                             out_bio.get(), /*flags*/ 0));
}
