'pcre2-util.c',
'pcrextend-util.c',
'pe-binary.c',
+ 'pkcs7-util.c',
'pkcs11-util.c',
'plymouth-util.c',
'polkit-agent.c',
--- /dev/null
+/* 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
+}
--- /dev/null
+/* 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);
'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,
--- /dev/null
+/* 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);