From: Daan De Meyer Date: Tue, 25 Feb 2025 07:53:13 +0000 (+0100) Subject: openssl-util: Introduce pkcs7_new() X-Git-Tag: v258-rc1~1231^2~6 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d46b16aff287d52bddc31476b71a81ddee801778;p=thirdparty%2Fsystemd.git openssl-util: Introduce pkcs7_new() --- diff --git a/src/keyutil/keyutil.c b/src/keyutil/keyutil.c index 36bb33f9f11..9df85902f70 100644 --- a/src/keyutil/keyutil.c +++ b/src/keyutil/keyutil.c @@ -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); diff --git a/src/shared/openssl-util.c b/src/shared/openssl-util.c index 302cf3d0f6f..92d4f4d9555 100644 --- a/src/shared/openssl-util.c +++ b/src/shared/openssl-util.c @@ -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, diff --git a/src/shared/openssl-util.h b/src/shared/openssl-util.h index 85d622b5b9a..73fd72001f8 100644 --- a/src/shared/openssl-util.h +++ b/src/shared/openssl-util.h @@ -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;