]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
openssl-util: Introduce pkcs7_new()
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Tue, 25 Feb 2025 07:53:13 +0000 (08:53 +0100)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Thu, 27 Feb 2025 08:52:38 +0000 (09:52 +0100)
src/keyutil/keyutil.c
src/shared/openssl-util.c
src/shared/openssl-util.h

index 36bb33f9f114702f7893fb614f0856cc591f02bc..9df85902f70f2c95ee5555263d4b51ac9fd4af86 100644 (file)
@@ -338,72 +338,20 @@ static int verb_pkcs7(int argc, char *argv[], void *userdata) {
         if (pkcs1_len == 0)
                 return log_error_errno(SYNTHETIC_ERRNO(EIO), "PKCS#1 file %s is empty", arg_signature);
 
-        /* Create PKCS7_SIGNER_INFO using X509 pubkey/digest NIDs */
-
-        _cleanup_(PKCS7_SIGNER_INFO_freep) PKCS7_SIGNER_INFO *signer_info = PKCS7_SIGNER_INFO_new();
-        if (!signer_info)
-                return log_oom();
-
-        if (ASN1_INTEGER_set(signer_info->version, 1) == 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to set ASN1 integer: %s",
-                                       ERR_error_string(ERR_get_error(), NULL));
-
-        if (X509_NAME_set(&signer_info->issuer_and_serial->issuer, X509_get_issuer_name(certificate)) == 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to set issuer name: %s",
-                                       ERR_error_string(ERR_get_error(), NULL));
-
-        ASN1_INTEGER_free(signer_info->issuer_and_serial->serial);
-        signer_info->issuer_and_serial->serial = ASN1_INTEGER_dup(X509_get0_serialNumber(certificate));
-        if (!signer_info->issuer_and_serial->serial)
-                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to set issuer serial: %s",
-                                       ERR_error_string(ERR_get_error(), NULL));
-
-        int x509_mdnid = 0, x509_pknid = 0;
-        if (X509_get_signature_info(certificate, &x509_mdnid, &x509_pknid, /* secbits= */ NULL, /* flags= */ NULL) == 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to get X.509 digest NID/PK: %s",
-                                       ERR_error_string(ERR_get_error(), NULL));
-
-        if (X509_ALGOR_set0(signer_info->digest_alg, OBJ_nid2obj(x509_mdnid), V_ASN1_NULL, /* pval= */ NULL) == 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to set digest alg: %s",
-                                       ERR_error_string(ERR_get_error(), NULL));
-
-        if (X509_ALGOR_set0(signer_info->digest_enc_alg, OBJ_nid2obj(x509_pknid), V_ASN1_NULL, /* pval= */ NULL) == 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to set digest enc alg: %s",
-                                       ERR_error_string(ERR_get_error(), NULL));
-
-        /* Create new PKCS7 using X509 certificate */
-
-        _cleanup_(PKCS7_freep) PKCS7 *pkcs7 = PKCS7_new();
-        if (!pkcs7)
-                return log_oom();
-
-        if (PKCS7_set_type(pkcs7, NID_pkcs7_signed) == 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to set PKCS#7 type: %s",
-                                       ERR_error_string(ERR_get_error(), NULL));
-
-        if (PKCS7_content_new(pkcs7, NID_pkcs7_data) == 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to set PKCS#7 content: %s",
-                                       ERR_error_string(ERR_get_error(), NULL));
+        _cleanup_(PKCS7_freep) PKCS7 *pkcs7 = NULL;
+        PKCS7_SIGNER_INFO *signer_info;
+        r = pkcs7_new(certificate, /* private_key= */ NULL, &pkcs7, &signer_info);
+        if (r < 0)
+                return log_error_errno(r, "Failed to allocate PKCS#7 context: %m");
 
         if (PKCS7_set_detached(pkcs7, true) == 0)
                 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to set PKCS#7 detached attribute: %s",
                                        ERR_error_string(ERR_get_error(), NULL));
 
-        if (PKCS7_add_certificate(pkcs7, certificate) == 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to set PKCS#7 certificate: %s",
-                                       ERR_error_string(ERR_get_error(), NULL));
-
         /* Add PKCS1 signature to PKCS7_SIGNER_INFO */
 
         ASN1_STRING_set0(signer_info->enc_digest, TAKE_PTR(pkcs1), pkcs1_len);
 
-        /* Add PKCS7_SIGNER_INFO to PKCS7 */
-
-        if (PKCS7_add_signer(pkcs7, signer_info) == 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to set PKCS#7 signer info: %s",
-                                       ERR_error_string(ERR_get_error(), NULL));
-        TAKE_PTR(signer_info);
-
         _cleanup_fclose_ FILE *output = fopen(arg_output, "we");
         if (!output)
                 return log_error_errno(errno, "Could not open PKCS#7 output file %s: %m", arg_output);
index 302cf3d0f6f8d5a5c404375aa97eab292d48f26c..92d4f4d955598eb69694a117d70ceddb4975df6a 100644 (file)
@@ -1125,6 +1125,86 @@ int digest_and_sign(
         return 0;
 }
 
+int pkcs7_new(X509 *certificate, EVP_PKEY *private_key, PKCS7 **ret_p7, PKCS7_SIGNER_INFO **ret_si) {
+        assert(certificate);
+        assert(ret_p7);
+
+        /* This function sets up a new PKCS7 signing context. If a private key is provided, the context is
+         * set up for "in-band" signing with PKCS7_dataFinal(). If a private key is not provided, the context
+         * is set up for "out-of-band" signing, meaning the signature has to be provided by the user and
+         * copied into the signer info's "enc_digest" field. */
+
+        _cleanup_(PKCS7_freep) PKCS7 *p7 = PKCS7_new();
+        if (!p7)
+                return log_oom();
+
+        if (PKCS7_set_type(p7, NID_pkcs7_signed) == 0)
+                return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set PKCS7 type: %s",
+                                       ERR_error_string(ERR_get_error(), NULL));
+
+        if (PKCS7_content_new(p7, NID_pkcs7_data) == 0)
+                return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set PKCS7 content: %s",
+                                       ERR_error_string(ERR_get_error(), NULL));
+
+        if (PKCS7_add_certificate(p7, certificate) == 0)
+                return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set PKCS7 certificate: %s",
+                                       ERR_error_string(ERR_get_error(), NULL));
+
+        int x509_mdnid = 0, x509_pknid = 0;
+        if (X509_get_signature_info(certificate, &x509_mdnid, &x509_pknid, NULL, NULL) == 0)
+                return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to get X509 digest NID: %s",
+                                       ERR_error_string(ERR_get_error(), NULL));
+
+        const EVP_MD *md = EVP_get_digestbynid(x509_mdnid);
+        if (!md)
+                return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to get digest algorithm via digest NID");
+
+        _cleanup_(PKCS7_SIGNER_INFO_freep) PKCS7_SIGNER_INFO *si = PKCS7_SIGNER_INFO_new();
+        if (!si)
+                return log_oom();
+
+        if (private_key) {
+                if (PKCS7_SIGNER_INFO_set(si, certificate, private_key, EVP_get_digestbynid(x509_mdnid)) <= 0)
+                        return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to configure signer info: %s",
+                                               ERR_error_string(ERR_get_error(), NULL));
+        } else {
+                if (ASN1_INTEGER_set(si->version, 1) == 0)
+                        return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set signer info version: %s",
+                                               ERR_error_string(ERR_get_error(), NULL));
+
+                if (X509_NAME_set(&si->issuer_and_serial->issuer, X509_get_issuer_name(certificate)) == 0)
+                        return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set signer info issuer: %s",
+                                               ERR_error_string(ERR_get_error(), NULL));
+
+                ASN1_INTEGER_free(si->issuer_and_serial->serial);
+                si->issuer_and_serial->serial = ASN1_INTEGER_dup(X509_get0_serialNumber(certificate));
+                if (!si->issuer_and_serial->serial)
+                        return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set signer info serial: %s",
+                                               ERR_error_string(ERR_get_error(), NULL));
+
+                if (X509_ALGOR_set0(si->digest_alg, OBJ_nid2obj(x509_mdnid), V_ASN1_NULL, NULL) == 0)
+                        return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set signer info digest algorithm: %s",
+                                               ERR_error_string(ERR_get_error(), NULL));
+
+                if (X509_ALGOR_set0(si->digest_enc_alg, OBJ_nid2obj(x509_pknid), V_ASN1_NULL, NULL) == 0)
+                        return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set signer info signing algorithm: %s",
+                                               ERR_error_string(ERR_get_error(), NULL));
+        }
+
+        if (PKCS7_add_signer(p7, si) == 0)
+                return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set PKCS7 signer info: %s",
+                                       ERR_error_string(ERR_get_error(), NULL));
+
+        *ret_p7 = TAKE_PTR(p7);
+        if (ret_si)
+                /* We do not pass ownership here, 'si' object remains owned by 'p7' object. */
+                *ret_si = si;
+
+        TAKE_PTR(si);
+
+        return 0;
+}
+
 #  if PREFER_OPENSSL
 int string_hashsum(
                 const char *s,
index 85d622b5b9a6c2966c761640b8fa46292233bc15..73fd72001f875363117a629c4eb0ebcb5274ccbd 100644 (file)
@@ -145,6 +145,8 @@ int pubkey_fingerprint(EVP_PKEY *pk, const EVP_MD *md, void **ret, size_t *ret_s
 
 int digest_and_sign(const EVP_MD *md, EVP_PKEY *privkey, const void *data, size_t size, void **ret, size_t *ret_size);
 
+int pkcs7_new(X509 *certificate, EVP_PKEY *private_key, PKCS7 **ret_p7, PKCS7_SIGNER_INFO **ret_si);
+
 #else
 
 typedef struct X509 X509;