openssl: add hash_algorithm parameter to pkcs7_new()

The pkcs7_new() function currently uses the hash algorithm from the X509
certificate's signature, but the content signature may use a different hash
algorithm. This adds a parameter to allow specifying what hash algorithm the
content signature generation used.
This commit is contained in:
Dan Streetman
2025-06-06 12:31:40 -04:00
parent d83ceacc7e
commit 768a297c42
4 changed files with 15 additions and 12 deletions

View File

@@ -355,7 +355,7 @@ static int verb_pkcs7(int argc, char *argv[], void *userdata) {
_cleanup_(PKCS7_freep) PKCS7 *pkcs7 = NULL;
PKCS7_SIGNER_INFO *signer_info;
r = pkcs7_new(certificate, /* private_key= */ NULL, &pkcs7, &signer_info);
r = pkcs7_new(certificate, /* private_key= */ NULL, /* hash_algorithm= */ NULL, &pkcs7, &signer_info);
if (r < 0)
return log_error_errno(r, "Failed to allocate PKCS#7 context: %m");

View File

@@ -321,6 +321,7 @@ static int asn1_timestamp(ASN1_TIME **ret) {
static int pkcs7_new_with_attributes(
X509 *certificate,
EVP_PKEY *private_key,
const char *hash_algorithm,
STACK_OF(X509_ATTRIBUTE) *signed_attributes,
PKCS7 **ret_p7,
PKCS7_SIGNER_INFO **ret_si) {
@@ -336,7 +337,7 @@ static int pkcs7_new_with_attributes(
_cleanup_(PKCS7_freep) PKCS7 *p7 = NULL;
PKCS7_SIGNER_INFO *si = NULL; /* avoid false maybe-uninitialized warning */
r = pkcs7_new(certificate, private_key, &p7, &si);
r = pkcs7_new(certificate, private_key, hash_algorithm, &p7, &si);
if (r < 0)
return log_error_errno(r, "Failed to allocate PKCS# context: %m");
@@ -562,7 +563,7 @@ static int verb_sign(int argc, char *argv[], void *userdata) {
_cleanup_(PKCS7_freep) PKCS7 *p7 = NULL;
PKCS7_SIGNER_INFO *si = NULL; /* avoid false maybe-uninitialized warning */
r = pkcs7_new_with_attributes(certificate, private_key, signed_attributes, &p7, &si);
r = pkcs7_new_with_attributes(certificate, private_key, /* hash_algorithm= */ NULL, signed_attributes, &p7, &si);
if (r < 0)
return r;

View File

@@ -1126,14 +1126,15 @@ int digest_and_sign(
return 0;
}
int pkcs7_new(X509 *certificate, EVP_PKEY *private_key, PKCS7 **ret_p7, PKCS7_SIGNER_INFO **ret_si) {
int pkcs7_new(X509 *certificate, EVP_PKEY *private_key, const char *hash_algorithm, 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. */
* copied into the signer info's "enc_digest" field. If the signing hash algorithm is not provided,
* SHA-256 is used. */
_cleanup_(PKCS7_freep) PKCS7 *p7 = PKCS7_new();
if (!p7)
@@ -1151,21 +1152,22 @@ int pkcs7_new(X509 *certificate, EVP_PKEY *private_key, PKCS7 **ret_p7, PKCS7_SI
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)
int x509_pknid = 0;
if (X509_get_signature_info(certificate, NULL, &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);
const EVP_MD *md = EVP_get_digestbyname(hash_algorithm ?: "SHA256");
if (!md)
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to get digest algorithm via digest NID");
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to get digest algorithm '%s'",
hash_algorithm ?: "SHA256");
_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)
if (PKCS7_SIGNER_INFO_set(si, certificate, private_key, md) <= 0)
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to configure signer info: %s",
ERR_error_string(ERR_get_error(), NULL));
} else {
@@ -1183,7 +1185,7 @@ int pkcs7_new(X509 *certificate, EVP_PKEY *private_key, PKCS7 **ret_p7, PKCS7_SI
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)
if (X509_ALGOR_set0(si->digest_alg, OBJ_nid2obj(EVP_MD_type(md)), 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));

View File

@@ -165,7 +165,7 @@ 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);
int pkcs7_new(X509 *certificate, EVP_PKEY *private_key, const char *hash_algorithm, PKCS7 **ret_p7, PKCS7_SIGNER_INFO **ret_si);
int string_hashsum(const char *s, size_t len, const char *md_algorithm, char **ret);