mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 08:25:20 +09:00
openssl-util: Introduce pkcs7_new()
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user