Allow PKCS7_sign to work for signing kernel modules.

Linux module signing uses PKCS#7 / CMS because everything is awful and
broken. In order to make the lives of kernel developers easier, support
the calling pattern that the kernel uses to sign modules.

The kernel utility was written at a time when PKCS#7 was hard coded to
use SHA-1 for signing in OpenSSL and it reflects this: you can only
specify “sha1” on the command line, for example. As of OpenSSL 1.1.1, at
least, OpenSSL uses SHA-256 and thus so does this change.

Change-Id: I32b036123a0d8b272ec9e1c0130c45bf3ed0d2c7
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/49545
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
grpc-202302
Adam Langley 3 years ago committed by Boringssl LUCI CQ
parent f958727f75
commit 66e61c577d
  1. 23
      crypto/pkcs7/internal.h
  2. 13
      crypto/pkcs7/pkcs7.c
  3. 198
      crypto/pkcs7/pkcs7_test.cc
  4. 163
      crypto/pkcs7/pkcs7_x509.c
  5. 17
      include/openssl/pkcs7.h

@ -32,14 +32,23 @@ extern "C" {
// NULL.
int pkcs7_parse_header(uint8_t **der_bytes, CBS *out, CBS *cbs);
// pkcs7_bundle writes a PKCS#7, SignedData structure to |out| and then calls
// |cb| with a CBB to which certificate or CRL data can be written, and the
// opaque context pointer, |arg|. The callback can return zero to indicate an
// error.
// pkcs7_add_signed_data writes a PKCS#7, SignedData structure to |out|. While
// doing so it makes callbacks to let the caller fill in parts of the structure.
// All callbacks are ignored if NULL and return one on success or zero on error.
//
// pkcs7_bundle returns one on success or zero on error.
int pkcs7_bundle(CBB *out, int (*cb)(CBB *out, const void *arg),
const void *arg);
// digest_algos_cb: may write AlgorithmIdentifiers into the given CBB, which
// is a SET of digest algorithms.
// cert_crl_cb: may write the |certificates| or |crls| fields.
// (See https://datatracker.ietf.org/doc/html/rfc2315#section-9.1)
// signer_infos_cb: may write the contents of the |signerInfos| field.
// (See https://datatracker.ietf.org/doc/html/rfc2315#section-9.1)
//
// pkcs7_add_signed_data returns one on success or zero on error.
int pkcs7_add_signed_data(CBB *out,
int (*digest_algos_cb)(CBB *out, const void *arg),
int (*cert_crl_cb)(CBB *out, const void *arg),
int (*signer_infos_cb)(CBB *out, const void *arg),
const void *arg);
#if defined(__cplusplus)

@ -131,8 +131,11 @@ err:
return ret;
}
int pkcs7_bundle(CBB *out, int (*cb)(CBB *out, const void *arg),
const void *arg) {
int pkcs7_add_signed_data(CBB *out,
int (*digest_algos_cb)(CBB *out, const void *arg),
int (*cert_crl_cb)(CBB *out, const void *arg),
int (*signer_infos_cb)(CBB *out, const void *arg),
const void *arg) {
CBB outer_seq, oid, wrapped_seq, seq, version_bytes, digest_algos_set,
content_info, signer_infos;
@ -147,11 +150,13 @@ int pkcs7_bundle(CBB *out, int (*cb)(CBB *out, const void *arg),
!CBB_add_asn1(&seq, &version_bytes, CBS_ASN1_INTEGER) ||
!CBB_add_u8(&version_bytes, 1) ||
!CBB_add_asn1(&seq, &digest_algos_set, CBS_ASN1_SET) ||
(digest_algos_cb != NULL && !digest_algos_cb(&digest_algos_set, arg)) ||
!CBB_add_asn1(&seq, &content_info, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&content_info, &oid, CBS_ASN1_OBJECT) ||
!CBB_add_bytes(&oid, kPKCS7Data, sizeof(kPKCS7Data)) ||
!cb(&seq, arg) ||
!CBB_add_asn1(&seq, &signer_infos, CBS_ASN1_SET)) {
(cert_crl_cb != NULL && !cert_crl_cb(&seq, arg)) ||
!CBB_add_asn1(&seq, &signer_infos, CBS_ASN1_SET) ||
(signer_infos_cb != NULL && !signer_infos_cb(&signer_infos, arg))) {
return 0;
}

@ -775,3 +775,201 @@ xzfKY2TzxLiOmctG0hXFkH5J
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)));
// Other option combinations should fail.
EXPECT_FALSE(
PKCS7_sign(cert.get(), key.get(), /*certs=*/nullptr, data_bio.get(),
PKCS7_NOATTR | PKCS7_BINARY | PKCS7_NOCERTS));
EXPECT_FALSE(
PKCS7_sign(cert.get(), key.get(), /*certs=*/nullptr, data_bio.get(),
PKCS7_BINARY | PKCS7_NOCERTS | PKCS7_DETACHED));
EXPECT_FALSE(
PKCS7_sign(cert.get(), key.get(), /*certs=*/nullptr, data_bio.get(),
PKCS7_NOATTR | PKCS7_TEXT | PKCS7_NOCERTS | PKCS7_DETACHED));
EXPECT_FALSE(
PKCS7_sign(cert.get(), key.get(), /*certs=*/nullptr, data_bio.get(),
PKCS7_NOATTR | PKCS7_BINARY | PKCS7_DETACHED));
ERR_clear_error();
}

@ -20,6 +20,7 @@
#include <openssl/bytestring.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/obj.h>
#include <openssl/pem.h>
#include <openssl/pool.h>
#include <openssl/stack.h>
@ -197,7 +198,9 @@ static int pkcs7_bundle_certificates_cb(CBB *out, const void *arg) {
}
int PKCS7_bundle_certificates(CBB *out, const STACK_OF(X509) *certs) {
return pkcs7_bundle(out, pkcs7_bundle_certificates_cb, certs);
return pkcs7_add_signed_data(out, /*digest_algos_cb=*/NULL,
pkcs7_bundle_certificates_cb,
/*signer_infos_cb=*/NULL, certs);
}
static int pkcs7_bundle_crls_cb(CBB *out, const void *arg) {
@ -228,7 +231,9 @@ static int pkcs7_bundle_crls_cb(CBB *out, const void *arg) {
}
int PKCS7_bundle_CRLs(CBB *out, const STACK_OF(X509_CRL) *crls) {
return pkcs7_bundle(out, pkcs7_bundle_crls_cb, crls);
return pkcs7_add_signed_data(out, /*digest_algos_cb=*/NULL,
pkcs7_bundle_crls_cb,
/*signer_infos_cb=*/NULL, crls);
}
static PKCS7 *pkcs7_new(CBS *cbs) {
@ -362,26 +367,160 @@ int PKCS7_type_is_enveloped(const PKCS7 *p7) { return 0; }
int PKCS7_type_is_signed(const PKCS7 *p7) { return 1; }
int PKCS7_type_is_signedAndEnveloped(const PKCS7 *p7) { return 0; }
// write_sha256_ai writes an AlgorithmIdentifier for SHA-256 to
// |digest_algos_set|.
static int write_sha256_ai(CBB *digest_algos_set, const void *arg) {
CBB seq;
return CBB_add_asn1(digest_algos_set, &seq, CBS_ASN1_SEQUENCE) &&
OBJ_nid2cbb(&seq, NID_sha256) && //
// https://datatracker.ietf.org/doc/html/rfc5754#section-2
// "Implementations MUST generate SHA2 AlgorithmIdentifiers with absent
// parameters."
CBB_flush(digest_algos_set);
}
// sign_sha256 writes at most |max_out_sig| bytes of the signature of |data| by
// |pkey| to |out_sig| and sets |*out_sig_len| to the number of bytes written.
// It returns one on success or zero on error.
static int sign_sha256(uint8_t *out_sig, size_t *out_sig_len,
size_t max_out_sig, EVP_PKEY *pkey, BIO *data) {
static const size_t kBufSize = 4096;
uint8_t *buffer = OPENSSL_malloc(kBufSize);
if (!buffer) {
return 0;
}
EVP_MD_CTX ctx;
EVP_MD_CTX_init(&ctx);
int ret = 0;
if (!EVP_DigestSignInit(&ctx, NULL, EVP_sha256(), NULL, pkey)) {
goto out;
}
for (;;) {
const int n = BIO_read(data, buffer, kBufSize);
if (n == 0) {
break;
} else if (n < 0 || !EVP_DigestSignUpdate(&ctx, buffer, n)) {
goto out;
}
}
*out_sig_len = max_out_sig;
if (!EVP_DigestSignFinal(&ctx, out_sig, out_sig_len)) {
goto out;
}
ret = 1;
out:
EVP_MD_CTX_cleanup(&ctx);
OPENSSL_free(buffer);
return ret;
}
struct signer_info_data {
const X509 *sign_cert;
uint8_t *signature;
size_t signature_len;
};
// write_signer_info writes the SignerInfo structure from
// https://datatracker.ietf.org/doc/html/rfc2315#section-9.2 to |out|. It
// returns one on success or zero on error.
static int write_signer_info(CBB *out, const void *arg) {
const struct signer_info_data *const si_data = arg;
int ret = 0;
uint8_t *subject_bytes = NULL;
uint8_t *serial_bytes = NULL;
const int subject_len =
i2d_X509_NAME(X509_get_subject_name(si_data->sign_cert), &subject_bytes);
const int serial_len = i2d_ASN1_INTEGER(
(ASN1_INTEGER *)X509_get0_serialNumber(si_data->sign_cert),
&serial_bytes);
CBB seq, issuer_and_serial, signing_algo, null, signature;
if (subject_len < 0 ||
serial_len < 0 ||
!CBB_add_asn1(out, &seq, CBS_ASN1_SEQUENCE) ||
// version
!CBB_add_asn1_uint64(&seq, 1) ||
!CBB_add_asn1(&seq, &issuer_and_serial, CBS_ASN1_SEQUENCE) ||
!CBB_add_bytes(&issuer_and_serial, subject_bytes, subject_len) ||
!CBB_add_bytes(&issuer_and_serial, serial_bytes, serial_len) ||
!write_sha256_ai(&seq, NULL) ||
!CBB_add_asn1(&seq, &signing_algo, CBS_ASN1_SEQUENCE) ||
!OBJ_nid2cbb(&signing_algo, NID_rsaEncryption) ||
!CBB_add_asn1(&signing_algo, &null, CBS_ASN1_NULL) ||
!CBB_add_asn1(&seq, &signature, CBS_ASN1_OCTETSTRING) ||
!CBB_add_bytes(&signature, si_data->signature, si_data->signature_len) ||
!CBB_flush(out)) {
goto out;
}
ret = 1;
out:
OPENSSL_free(subject_bytes);
OPENSSL_free(serial_bytes);
return ret;
}
PKCS7 *PKCS7_sign(X509 *sign_cert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
BIO *data, int flags) {
if (sign_cert != NULL || pkey != NULL || flags != PKCS7_DETACHED) {
OPENSSL_PUT_ERROR(PKCS7, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
CBB cbb;
if (!CBB_init(&cbb, 2048)) {
return NULL;
}
uint8_t *der;
uint8_t *der = NULL;
size_t len;
CBB cbb;
if (!CBB_init(&cbb, 2048) ||
!PKCS7_bundle_certificates(&cbb, certs) ||
!CBB_finish(&cbb, &der, &len)) {
CBB_cleanup(&cbb);
return NULL;
PKCS7 *ret = NULL;
if (sign_cert == NULL && pkey == NULL && flags == PKCS7_DETACHED) {
// Caller just wants to bundle certificates.
if (!PKCS7_bundle_certificates(&cbb, certs)) {
goto out;
}
} else if (sign_cert != NULL && pkey != NULL && certs == NULL &&
data != NULL &&
flags == (PKCS7_NOATTR | PKCS7_BINARY | PKCS7_NOCERTS |
PKCS7_DETACHED) &&
EVP_PKEY_id(pkey) == NID_rsaEncryption) {
// sign-file.c from the Linux kernel.
const size_t signature_max_len = EVP_PKEY_size(pkey);
struct signer_info_data si_data = {
.sign_cert = sign_cert,
.signature = OPENSSL_malloc(signature_max_len),
};
if (!si_data.signature ||
!sign_sha256(si_data.signature, &si_data.signature_len,
signature_max_len, pkey, data) ||
!pkcs7_add_signed_data(&cbb, write_sha256_ai, /*cert_crl_cb=*/NULL,
write_signer_info, &si_data)) {
OPENSSL_free(si_data.signature);
goto out;
}
OPENSSL_free(si_data.signature);
} else {
OPENSSL_PUT_ERROR(PKCS7, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
goto out;
}
if (!CBB_finish(&cbb, &der, &len)) {
goto out;
}
CBS cbs;
CBS_init(&cbs, der, len);
PKCS7 *ret = pkcs7_new(&cbs);
ret = pkcs7_new(&cbs);
out:
CBB_cleanup(&cbb);
OPENSSL_free(der);
return ret;
}

@ -200,15 +200,22 @@ OPENSSL_EXPORT int PKCS7_type_is_signedAndEnveloped(const PKCS7 *p7);
#define PKCS7_STREAM 0x1000
#define PKCS7_PARTIAL 0x4000
// PKCS7_sign assembles |certs| into a PKCS#7 signed data ContentInfo with
// PKCS7_sign can operate in two modes to provide some backwards compatibility:
//
// The first mode assembles |certs| into a PKCS#7 signed data ContentInfo with
// external data and no signatures. It returns a newly-allocated |PKCS7| on
// success or NULL on error. |sign_cert| and |pkey| must be NULL. |data| is
// ignored. |flags| must be equal to |PKCS7_DETACHED|.
//
// Note this function only implements a subset of the corresponding OpenSSL
// function. It is provided for backwards compatibility only. Additionally,
// ignored. |flags| must be equal to |PKCS7_DETACHED|. Additionally,
// certificates in SignedData structures are unordered. The order of |certs|
// will not be preserved.
//
// The second mode generates a detached RSA SHA-256 signature of |data| using
// |pkey| and produces a PKCS#7 SignedData structure containing it. |certs|
// must be NULL and |flags| must be exactly |PKCS7_NOATTR | PKCS7_BINARY |
// PKCS7_NOCERTS | PKCS7_DETACHED|.
//
// Note this function only implements a subset of the corresponding OpenSSL
// function. It is provided for backwards compatibility only.
OPENSSL_EXPORT PKCS7 *PKCS7_sign(X509 *sign_cert, EVP_PKEY *pkey,
STACK_OF(X509) *certs, BIO *data, int flags);

Loading…
Cancel
Save