pkcs7-util: add helpers for extracting signer info from PKCS7 signatures
Once we start measuring Verity volumes as we activate them we want to include information about the signature keys used, so that we can have distinct ones for confext and for sysext and ther purposes and thus have a cryptograpically protected hint about the kind of image we have activated in the event log. Ideally we'd measure a fingerprint of the signing certificate here, but we don't have that here typically (as PKCS7 signatures used here typically do not embed that), hence use the next best thing: the issuer name and the serial number.
This commit is contained in:
@@ -152,6 +152,7 @@ shared_sources = files(
|
||||
'pcre2-util.c',
|
||||
'pcrextend-util.c',
|
||||
'pe-binary.c',
|
||||
'pkcs7-util.c',
|
||||
'pkcs11-util.c',
|
||||
'plymouth-util.c',
|
||||
'polkit-agent.c',
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "openssl-util.h"
|
||||
#include "pkcs7-util.h"
|
||||
#include "log.h"
|
||||
|
||||
#define SIGNERS_MAX 32
|
||||
|
||||
static void signer_done(Signer *signer) {
|
||||
assert(signer);
|
||||
|
||||
iovec_done(&signer->issuer);
|
||||
iovec_done(&signer->serial);
|
||||
}
|
||||
|
||||
void signer_free_many(Signer *signers, size_t n) {
|
||||
assert(signers || n == 0);
|
||||
|
||||
FOREACH_ARRAY(i, signers, n)
|
||||
signer_done(i);
|
||||
|
||||
free(signers);
|
||||
}
|
||||
|
||||
int pkcs7_extract_signers(
|
||||
const struct iovec *sig,
|
||||
Signer **ret_signers,
|
||||
size_t *ret_n_signers) {
|
||||
|
||||
assert(ret_signers);
|
||||
assert(ret_n_signers);
|
||||
|
||||
if (!iovec_is_set(sig))
|
||||
return -EBADMSG;
|
||||
|
||||
#if HAVE_OPENSSL
|
||||
const unsigned char *d = sig->iov_base;
|
||||
_cleanup_(PKCS7_freep) PKCS7 *p7 = NULL;
|
||||
p7 = d2i_PKCS7(/* a= */ NULL, &d, (long) sig->iov_len);
|
||||
if (!p7)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Failed to parse PKCS7 DER signature data.");
|
||||
|
||||
STACK_OF(PKCS7_SIGNER_INFO) *sinfos = PKCS7_get_signer_info(p7);
|
||||
if (!sinfos)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(ENODATA), "No signature information in PKCS7 signature?");
|
||||
int n = sk_PKCS7_SIGNER_INFO_num(sinfos);
|
||||
if (n == 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(ENODATA), "No signatures in PKCS7 signature, refusing.");
|
||||
if (n > SIGNERS_MAX) /* safety net, in case people send us weirdly complex signatures */
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Too many signatures, refusing.");
|
||||
assert(n > 0);
|
||||
|
||||
size_t n_signers = 0;
|
||||
Signer *signers = new(Signer, n);
|
||||
if (!signers)
|
||||
return log_oom_debug();
|
||||
|
||||
CLEANUP_ARRAY(signers, n_signers, signer_free_many);
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
PKCS7_SIGNER_INFO *si = sk_PKCS7_SIGNER_INFO_value(PKCS7_get_signer_info(p7), i);
|
||||
if (!si)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to get signer information.");
|
||||
|
||||
_cleanup_(signer_done) Signer signer = {};
|
||||
|
||||
_cleanup_free_ unsigned char *p = NULL;
|
||||
int len = i2d_X509_NAME(si->issuer_and_serial->issuer, &p);
|
||||
signer.issuer = IOVEC_MAKE(TAKE_PTR(p), len);
|
||||
|
||||
len = i2d_ASN1_INTEGER(si->issuer_and_serial->serial, &p);
|
||||
signer.serial = IOVEC_MAKE(TAKE_PTR(p), len);
|
||||
|
||||
signers[n_signers++] = TAKE_STRUCT(signer);
|
||||
}
|
||||
|
||||
*ret_signers = TAKE_PTR(signers);
|
||||
*ret_n_signers = n_signers;
|
||||
return n;
|
||||
#else
|
||||
return -EOPNOTSUPP;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <sys/uio.h>
|
||||
|
||||
typedef struct Signer {
|
||||
struct iovec issuer;
|
||||
struct iovec serial;
|
||||
} Signer;
|
||||
|
||||
void signer_free_many(Signer *signers, size_t n);
|
||||
|
||||
int pkcs7_extract_signers(
|
||||
const struct iovec *sig,
|
||||
Signer **ret_signers,
|
||||
size_t *ret_n_signers);
|
||||
@@ -405,6 +405,11 @@ executables += [
|
||||
'dependencies' : libopenssl,
|
||||
'conditions' : ['HAVE_OPENSSL'],
|
||||
},
|
||||
test_template + {
|
||||
'sources' : files('test-pkcs7-util.c'),
|
||||
'dependencies' : libopenssl,
|
||||
'conditions' : ['HAVE_OPENSSL'],
|
||||
},
|
||||
test_template + {
|
||||
'sources' : files('test-parse-util.c'),
|
||||
'dependencies' : libm,
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "hexdecoct.h"
|
||||
#include "iovec-util.h"
|
||||
#include "pkcs7-util.h"
|
||||
#include "tests.h"
|
||||
|
||||
TEST(pkcs7_extract_signers) {
|
||||
|
||||
const char tsig[] =
|
||||
"MIIEgwYJKoZIhvcNAQcCoIIEdDCCBHACAQExDzANBglghkgBZQMEAgEFADALBgkqhkiG9w0BBwGgggLp"
|
||||
"MIIC5TCCAc2gAwIBAgIURlvlj5ak0ZhvNS8hENNKwVv60x0wDQYJKoZIhvcNAQELBQAwGzEZMBcGA1UE"
|
||||
"AwwQbWtvc2kgb2YgbGVubmFydDAeFw0yNTAyMDMxMTAwMjNaFw0yNzAyMDMxMTAwMjNaMBsxGTAXBgNV"
|
||||
"BAMMEG1rb3NpIG9mIGxlbm5hcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCldQdmHVgU"
|
||||
"m4saaSqEpF1EVRf9pcIxpVShROBGAbxpxs4BQ7vV7zCg5bXwEVaqaENlIyzqPAj+YQifQS3Dj6LQfH3i"
|
||||
"War+ciKAv4PYcESG+pcdBb2kJOS8cVD6abZlO9rInvdhXK6PhYF7VohMwMPj/yJYdO50skwA5OQsCHO6"
|
||||
"amowh0tVzNzpbaJZg6wWIyTf3+ZzZdnOl5EvBCaUqeUhbaxRV9SrAw51rzAOnndUhW1we/vVKEGAPk3c"
|
||||
"SCb0LLPBG20XX2C00UXgnCWBkU5rkq6BnWSuInhFKCa48avstIet1ZFBA5T5J83ncU9UOVFksEYBXFoc"
|
||||
"lzcmcbx/2/oFAgMBAAGjITAfMB0GA1UdDgQWBBQewILFCixwq2rejOvJqmZSug2BBDANBgkqhkiG9w0B"
|
||||
"AQsFAAOCAQEAIvaeNPaJUoIUN5lQC/kcCiKeys96WNRGL2wbTp5PqdnRw14sbWY5iC2z13ih3dmTI9NF"
|
||||
"TBa7C/ji+5BaAfiJF17LOV00Y8eP5V94fHz4isb0sv5RzLsE4h8X7QFk4JBdV5GiCDzPXjxQAx9kM2so"
|
||||
"9RGtL8EhHpNygYDgyZ18YeiwcUPkCXT+xG2rM6s/Xlsji0s/18ycI4G8AC8dj5HycyS9BiZHgKrkgqTb"
|
||||
"VPo4zHYzhZdh0Qrd0J4YpoaotzQ35bkH9PtIkF6C7mE1Z7uMSGFkGQASgJ0BDTpM8QPAf2HIR2xxEtJR"
|
||||
"ZXkwxxdC+W9AJAzqJldmCHYGSrSR54J0rDGCAV4wggFaAgEBMDMwGzEZMBcGA1UEAwwQbWtvc2kgb2Yg"
|
||||
"bGVubmFydAIURlvlj5ak0ZhvNS8hENNKwVv60x0wDQYJYIZIAWUDBAIBBQAwDQYJKoZIhvcNAQEBBQAE"
|
||||
"ggEAXccqvpiEWsz/xvuLhINVZKIOznVdqjkERbZSqCBK94BYESSd+cijaB4XbYaFUZ45Bb3uUDQ56Ojq"
|
||||
"WoY1elEfqPyCb4vc887QoHmxI0BtdIaHhIDfCGBxhX8fwMknxqjgFa9YvONmDtv4QG4syTw+U3SEqBaa"
|
||||
"Avftqaa4v4eLk4uZ0nMIgMkx4qOlaxknpP404/nyZPANkOIwDxviNtRBCN9zSiPSqo1zre1vqzaM57Ww"
|
||||
"8zJASsPEzNR7OsPoLaIZv2OHXpowsRB78TuXGkQnm74T6xdG6DNs24jTYJuCPfGuYLHbrytdhXpFBS6m"
|
||||
"Orz9715jK2NU5VvGhNVXX4chcw==";
|
||||
|
||||
_cleanup_free_ void *sig = NULL;
|
||||
size_t siglen;
|
||||
ASSERT_OK(unbase64mem(tsig, &sig, &siglen));
|
||||
|
||||
size_t n_signers = 0;
|
||||
Signer *signers = NULL;
|
||||
CLEANUP_ARRAY(signers, n_signers, signer_free_many);
|
||||
|
||||
ASSERT_OK_EQ(pkcs7_extract_signers(&IOVEC_MAKE(sig, siglen), &signers, &n_signers), 1);
|
||||
ASSERT_EQ(n_signers, 1U);
|
||||
ASSERT_EQ(signers[0].issuer.iov_len, 29U);
|
||||
ASSERT_EQ(signers[0].serial.iov_len, 22U);
|
||||
|
||||
_cleanup_free_ char *issuer = NULL;
|
||||
ASSERT_OK(base64mem(signers[0].issuer.iov_base, signers[0].issuer.iov_len, &issuer));
|
||||
|
||||
_cleanup_free_ char *serial = NULL;
|
||||
ASSERT_OK(base64mem(signers[0].serial.iov_base, signers[0].serial.iov_len, &serial));
|
||||
|
||||
ASSERT_STREQ(issuer, "MBsxGTAXBgNVBAMMEG1rb3NpIG9mIGxlbm5hcnQ=");
|
||||
ASSERT_STREQ(serial, "AhRGW+WPlqTRmG81LyEQ00rBW/rTHQ==");
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_INFO);
|
||||
Reference in New Issue
Block a user