Files
systemd/src/shared/crypto-util.h
T
Chris Coulson 768b6f21ec report: Add a TPM2 signing backend
This adds an initial TPM2 implementation of the io.systemd.Report.Signer
interface, which returns a set of signed TPM attestations that also
includes the supplied report digest.

The returned report consists of multiple components:
- A signed PCR quote generated with TPM2_Quote.
- Signed NvPCR attestations generated with TPM2_NV_Certify.
- A signed audit session attestation generated with
  TPM2_GetSessionAuditDigest.

Each signed report component includes the JSON encoded TPMS_ATTEST
attestation structure and corresponding signature, in both PEM encoded
form and as a JSON encoded TPMT_SIGNATURE structure.

NvPCR report components also include the readable name of the NvPCR, the
NV index public area as the JSON encoded TPMS_NV_PUBLIC structure, and some
additional authenticated data that is digested and supplied as the
qualifying data to the TPM2_NV_Certify command. This authenticated data
includes the NvPCR name and priority.

The report digest that is supplied via varlink is supplied as the
qualifying data to the audit session attestation.

The returned report also includes the event log which is retrieved from
pcrlock's varlink interface, and the public area of the signing key in
both PEM encoded form and as a JSON encoded TPMT_PUBLIC structure.

The audit session attestation is always the last component. The
preceding components are all executed with the audit session, and the
signer requires the audit session to remain exclusive whilst generating
the report. What this does is provide evidence to a verifier that the
overall report is a single, consistent snapshot of the system (ie, no
other TPM commands executed whilst generating the report) because the
audit session attestation contains a field that indicates that the
session was exclusive at the time it was attested.

The set of attested PCRs and NvPCRs are currently hardcoded. It includes
all firmware PCRs with the exception of PCR6, and all other PCRs with
the exception of the IMA one (which isn't useful on its own without the
IMA log). All defined NvPCRs are included.

A verifier can verify the signed attestation components individually by
verifying their signatures against the supplied attestation data, using
the supplied public key.

For the PCR report component, a verifier can replay the measurements in
the log in order to reconstruct the PCR values, and then use this and
the PCR selection from the attestation in order to calculate the PCR
digest, and then check that this matches the one in the attestation.

For the NvPCR report components, a verifier checks that the NV index
name in the attestation matches one that is anchored in PCR9 to be sure
that the attestation is for a valid NvPCR. A verifier can then replay
the measurements in the log to ensure that the resulting NvPCR value
matches the one supplied in the attestation. The authenticated data is a
JSON blob containing the NvPCR name and priority. A verifier can digest
this and ensure it matches the qualifying data in the attestation.

The audit session attestation includes the audit session digest and
whether the audit session was still exclusive when the attestation was
generated. A verifier should confirm exclusivity. The digest includes a
record of all TPM commands executed with the audit session, as each
command results in it being extended with the command parameter hash and
the result parameter hash. A verifier should replay the preceding report
components to compute an expected audit digest and make sure that this
digest matches the one in the attestation in order to be sure that the
overall report represents a single, consistent snapshot. The other
report components provide sufficient information for a verifier to
reconstruct the cpHash and rpHash.

When reconstructing the cpHash for the PCR and NvPCR components, the
signing scheme is the NULL scheme (they use the attestation key's
signing scheme). The required signing key public area is supplied in
the report. The supplied qualifying data is in the extra data field of
the attestation.

The PCR selection is also required to reconstruct the cpHash for the
PCR component. The PCR selection is available in the attestation.

The name of the NV index is also required to reconstruct the cpHash for
the NvPCR components. The name is available in the attestation.

The rpHash for each component can be reconstructed from the supplied
attestation blob and signature.

In the future, we might want to add more report component types. Eg, we
could add report components for ordinary NV indexes. Using the audit
session means that we could also add additional components that the TPM
can't attest directly, such as the values of interesting TPM properties
(as the TPM2_GetCapability calls will appear in the audit session digest).

The attestation signing key is stored as a JSON file in the report
signer's state directory. Different types of keys are supported:
- Ordinary keys that are protected by an existing persistent TPM key
  such as the SRK or EK.
- Persistent TPM keys.
- Primary keys, which are recreated using a template on use.

When an ordinary or primary key is used, the report signer saves the
object context in its runtime directory. This context is used on future
invocations. This has the benefit that where a primary key is used, it
doesn't need to be recreated on each use. When an ordinary key is used,
we don't need to run TPM2_Load, which requires authorization with the
parent key, on each This authorization currently requires a policy
session for low-range EKs.

Regardless of the key type, it must be a restricted signing key. If no
key exists, an ordinary key is generated automatically.

The attestation key can also have an associated credential which is
attached to the signed report. The credential can be issued by a CA or
some other party during onboarding, and is presented to a verifier as
proof that the attestation key is authentic. It is considered an opaque
blob in order to not require it to be a specific format, such as a X.509
certificate. I've called this a "voucher" though because "cred" or
"credential" has other meanings in systemd.

As a follow-up to this, I plan to add a varlink interface for creating
attestation keys that can be used for report signing.
2026-08-20 15:30:20 +02:00

472 lines
23 KiB
C

/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "dlopen-note.h"
#include "forward.h"
#include "iovec-util.h"
#include "sha256.h"
typedef enum CertificateSourceType {
OPENSSL_CERTIFICATE_SOURCE_FILE,
OPENSSL_CERTIFICATE_SOURCE_PROVIDER,
_OPENSSL_CERTIFICATE_SOURCE_MAX,
_OPENSSL_CERTIFICATE_SOURCE_INVALID = -EINVAL,
} CertificateSourceType;
typedef enum KeySourceType {
OPENSSL_KEY_SOURCE_FILE,
OPENSSL_KEY_SOURCE_ENGINE,
OPENSSL_KEY_SOURCE_PROVIDER,
_OPENSSL_KEY_SOURCE_MAX,
_OPENSSL_KEY_SOURCE_INVALID = -EINVAL,
} KeySourceType;
typedef struct OpenSSLAskPasswordUI OpenSSLAskPasswordUI;
int parse_openssl_certificate_source_argument(const char *argument, char **certificate_source, CertificateSourceType *certificate_source_type);
int parse_openssl_key_source_argument(const char *argument, char **private_key_source, KeySourceType *private_key_source_type);
#define X509_FINGERPRINT_SIZE SHA256_DIGEST_SIZE
#if HAVE_OPENSSL
#ifndef SYSTEMD_CFLAGS_MARKER_LIBOPENSSL
# error "missing libopenssl_cflags in meson dependency."
#endif
# include <openssl/bio.h> /* IWYU pragma: export */
# include <openssl/bn.h> /* IWYU pragma: export */
# include <openssl/core_names.h> /* IWYU pragma: export */
# include <openssl/crypto.h> /* IWYU pragma: export */
# include <openssl/ec.h> /* IWYU pragma: export */
# include <openssl/err.h> /* IWYU pragma: export */
# include <openssl/evp.h> /* IWYU pragma: export */
# include <openssl/hmac.h> /* IWYU pragma: export */
# include <openssl/param_build.h> /* IWYU pragma: export */
# include <openssl/pem.h> /* IWYU pragma: export */
# include <openssl/pkcs7.h> /* IWYU pragma: export */
# include <openssl/rsa.h> /* IWYU pragma: export */
# include <openssl/sha.h> /* IWYU pragma: export */
# include "dlfcn-util.h"
extern DLSYM_PROTOTYPE(ASN1_ANY_it);
extern DLSYM_PROTOTYPE(ASN1_BIT_STRING_it);
extern DLSYM_PROTOTYPE(ASN1_BMPSTRING_it);
extern DLSYM_PROTOTYPE(ASN1_BMPSTRING_new);
extern DLSYM_PROTOTYPE(ASN1_IA5STRING_it);
extern DLSYM_PROTOTYPE(ASN1_OBJECT_it);
extern DLSYM_PROTOTYPE(ASN1_OCTET_STRING_free);
extern DLSYM_PROTOTYPE(ASN1_OCTET_STRING_it);
extern DLSYM_PROTOTYPE(ASN1_OCTET_STRING_set);
extern DLSYM_PROTOTYPE(ASN1_STRING_get0_data);
extern DLSYM_PROTOTYPE(ASN1_STRING_length);
extern DLSYM_PROTOTYPE(ASN1_STRING_new);
extern DLSYM_PROTOTYPE(ASN1_STRING_set);
extern DLSYM_PROTOTYPE(ASN1_STRING_set0);
extern DLSYM_PROTOTYPE(ASN1_TIME_free);
extern DLSYM_PROTOTYPE(ASN1_TIME_set);
extern DLSYM_PROTOTYPE(ASN1_TYPE_new);
extern DLSYM_PROTOTYPE(ASN1_get_object);
extern DLSYM_PROTOTYPE(ASN1_item_d2i);
extern DLSYM_PROTOTYPE(ASN1_item_free);
extern DLSYM_PROTOTYPE(ASN1_item_i2d);
extern DLSYM_PROTOTYPE(ASN1_item_new);
extern DLSYM_PROTOTYPE(BIO_ctrl);
extern DLSYM_PROTOTYPE(BIO_find_type);
extern DLSYM_PROTOTYPE(BIO_free);
extern DLSYM_PROTOTYPE(BIO_free_all);
extern DLSYM_PROTOTYPE(BIO_new);
extern DLSYM_PROTOTYPE(BIO_new_mem_buf);
extern DLSYM_PROTOTYPE(BIO_new_socket);
extern DLSYM_PROTOTYPE(BIO_s_mem);
extern DLSYM_PROTOTYPE(BIO_write);
extern DLSYM_PROTOTYPE(BN_CTX_free);
extern DLSYM_PROTOTYPE(BN_CTX_new);
extern DLSYM_PROTOTYPE(BN_CTX_secure_new);
extern DLSYM_PROTOTYPE(BN_add);
extern DLSYM_PROTOTYPE(BN_add_word);
extern DLSYM_PROTOTYPE(BN_bin2bn);
extern DLSYM_PROTOTYPE(BN_bn2bin);
extern DLSYM_PROTOTYPE(BN_bn2binpad);
extern DLSYM_PROTOTYPE(BN_bn2nativepad);
extern DLSYM_PROTOTYPE(BN_check_prime);
extern DLSYM_PROTOTYPE(BN_clear_free);
extern DLSYM_PROTOTYPE(BN_cmp);
extern DLSYM_PROTOTYPE(BN_copy);
extern DLSYM_PROTOTYPE(BN_free);
extern DLSYM_PROTOTYPE(BN_is_negative);
extern DLSYM_PROTOTYPE(BN_mod_exp);
extern DLSYM_PROTOTYPE(BN_mod_inverse);
extern DLSYM_PROTOTYPE(BN_mod_lshift1_quick);
extern DLSYM_PROTOTYPE(BN_mod_mul);
extern DLSYM_PROTOTYPE(BN_mod_sqr);
extern DLSYM_PROTOTYPE(BN_mod_sub);
extern DLSYM_PROTOTYPE(BN_mul);
extern DLSYM_PROTOTYPE(BN_new);
extern DLSYM_PROTOTYPE(BN_nnmod);
extern DLSYM_PROTOTYPE(BN_num_bits);
extern DLSYM_PROTOTYPE(BN_secure_new);
extern DLSYM_PROTOTYPE(BN_set_word);
extern DLSYM_PROTOTYPE(BN_sub_word);
extern DLSYM_PROTOTYPE(CRYPTO_free);
extern DLSYM_PROTOTYPE(ECDSA_SIG_free);
extern DLSYM_PROTOTYPE(ECDSA_SIG_get0_r);
extern DLSYM_PROTOTYPE(ECDSA_SIG_get0_s);
extern DLSYM_PROTOTYPE(ECDSA_SIG_new);
extern DLSYM_PROTOTYPE(ECDSA_SIG_set0);
extern DLSYM_PROTOTYPE(EC_GROUP_free);
extern DLSYM_PROTOTYPE(EC_GROUP_get0_generator);
extern DLSYM_PROTOTYPE(EC_GROUP_get0_order);
extern DLSYM_PROTOTYPE(EC_GROUP_get_curve);
extern DLSYM_PROTOTYPE(EC_GROUP_get_curve_name);
extern DLSYM_PROTOTYPE(EC_GROUP_get_field_type);
extern DLSYM_PROTOTYPE(EC_GROUP_new_by_curve_name);
extern DLSYM_PROTOTYPE(EC_POINT_free);
extern DLSYM_PROTOTYPE(EC_POINT_new);
extern DLSYM_PROTOTYPE(EC_POINT_oct2point);
extern DLSYM_PROTOTYPE(EC_POINT_point2oct);
extern DLSYM_PROTOTYPE(ERR_clear_error);
extern DLSYM_PROTOTYPE(ERR_error_string);
extern DLSYM_PROTOTYPE(ERR_error_string_n);
extern DLSYM_PROTOTYPE(ERR_get_error);
extern DLSYM_PROTOTYPE(EVP_CIPHER_CTX_ctrl);
extern DLSYM_PROTOTYPE(EVP_CIPHER_CTX_free);
extern DLSYM_PROTOTYPE(EVP_CIPHER_CTX_get_tag_length);
extern DLSYM_PROTOTYPE(EVP_CIPHER_CTX_new);
extern DLSYM_PROTOTYPE(EVP_CIPHER_free);
extern DLSYM_PROTOTYPE(EVP_CIPHER_get_block_size);
extern DLSYM_PROTOTYPE(EVP_CIPHER_get_iv_length);
extern DLSYM_PROTOTYPE(EVP_CIPHER_get_key_length);
extern DLSYM_PROTOTYPE(EVP_DecryptFinal_ex);
extern DLSYM_PROTOTYPE(EVP_DecryptInit_ex);
extern DLSYM_PROTOTYPE(EVP_DecryptUpdate);
extern DLSYM_PROTOTYPE(EVP_Digest);
extern DLSYM_PROTOTYPE(EVP_DigestFinal_ex);
extern DLSYM_PROTOTYPE(EVP_DigestInit_ex);
extern DLSYM_PROTOTYPE(EVP_DigestUpdate);
extern DLSYM_PROTOTYPE(EVP_DigestVerify);
extern DLSYM_PROTOTYPE(EVP_DigestVerifyInit);
extern DLSYM_PROTOTYPE(EVP_EncryptFinal_ex);
extern DLSYM_PROTOTYPE(EVP_EncryptInit_ex);
extern DLSYM_PROTOTYPE(EVP_EncryptUpdate);
extern DLSYM_PROTOTYPE(EVP_MAC_CTX_free);
extern DLSYM_PROTOTYPE(EVP_MAC_CTX_new);
extern DLSYM_PROTOTYPE(EVP_MAC_fetch);
extern DLSYM_PROTOTYPE(EVP_MAC_final);
extern DLSYM_PROTOTYPE(EVP_MAC_free);
extern DLSYM_PROTOTYPE(EVP_MAC_init);
extern DLSYM_PROTOTYPE(EVP_MAC_update);
extern DLSYM_PROTOTYPE(EVP_MD_CTX_copy_ex);
extern DLSYM_PROTOTYPE(EVP_MD_CTX_free);
extern DLSYM_PROTOTYPE(EVP_MD_CTX_get0_md);
extern DLSYM_PROTOTYPE(EVP_MD_CTX_new);
extern DLSYM_PROTOTYPE(EVP_MD_CTX_set_pkey_ctx);
extern DLSYM_PROTOTYPE(EVP_MD_free);
extern DLSYM_PROTOTYPE(EVP_MD_get0_name);
extern DLSYM_PROTOTYPE(EVP_MD_get_size);
extern DLSYM_PROTOTYPE(EVP_PKEY_CTX_free);
extern DLSYM_PROTOTYPE(EVP_PKEY_CTX_new);
extern DLSYM_PROTOTYPE(EVP_PKEY_CTX_new_from_name);
extern DLSYM_PROTOTYPE(EVP_PKEY_CTX_new_id);
extern DLSYM_PROTOTYPE(EVP_PKEY_CTX_set_ec_paramgen_curve_nid);
extern DLSYM_PROTOTYPE(EVP_PKEY_CTX_set_rsa_keygen_bits);
extern DLSYM_PROTOTYPE(EVP_PKEY_CTX_set_rsa_padding);
extern DLSYM_PROTOTYPE(EVP_PKEY_CTX_set_signature_md);
extern DLSYM_PROTOTYPE(EVP_PKEY_eq);
extern DLSYM_PROTOTYPE(EVP_PKEY_free);
extern DLSYM_PROTOTYPE(EVP_PKEY_fromdata);
extern DLSYM_PROTOTYPE(EVP_PKEY_fromdata_init);
extern DLSYM_PROTOTYPE(EVP_PKEY_generate);
extern DLSYM_PROTOTYPE(EVP_PKEY_get_base_id);
extern DLSYM_PROTOTYPE(EVP_PKEY_get_bn_param);
extern DLSYM_PROTOTYPE(EVP_PKEY_get_id);
extern DLSYM_PROTOTYPE(EVP_PKEY_get_octet_string_param);
extern DLSYM_PROTOTYPE(EVP_PKEY_get_size);
extern DLSYM_PROTOTYPE(EVP_PKEY_keygen);
extern DLSYM_PROTOTYPE(EVP_PKEY_keygen_init);
extern DLSYM_PROTOTYPE(EVP_PKEY_new);
extern DLSYM_PROTOTYPE(EVP_PKEY_new_raw_public_key);
extern DLSYM_PROTOTYPE(EVP_PKEY_public_check);
extern DLSYM_PROTOTYPE(EVP_PKEY_sign);
extern DLSYM_PROTOTYPE(EVP_PKEY_sign_init);
extern DLSYM_PROTOTYPE(EVP_PKEY_verify);
extern DLSYM_PROTOTYPE(EVP_PKEY_verify_init);
extern DLSYM_PROTOTYPE(EVP_aes_256_ctr);
extern DLSYM_PROTOTYPE(EVP_aes_256_gcm);
extern DLSYM_PROTOTYPE(EVP_get_cipherbyname);
extern DLSYM_PROTOTYPE(EVP_get_digestbyname);
extern DLSYM_PROTOTYPE(EVP_sha1);
extern DLSYM_PROTOTYPE(EVP_sha256);
extern DLSYM_PROTOTYPE(EVP_sha384);
extern DLSYM_PROTOTYPE(EVP_sha512);
extern DLSYM_PROTOTYPE(HMAC);
extern DLSYM_PROTOTYPE(OBJ_nid2obj);
extern DLSYM_PROTOTYPE(OBJ_nid2sn);
extern DLSYM_PROTOTYPE(OBJ_sn2nid);
extern DLSYM_PROTOTYPE(OBJ_txt2obj);
extern DLSYM_PROTOTYPE(OPENSSL_sk_new_null);
extern DLSYM_PROTOTYPE(OPENSSL_sk_num);
extern DLSYM_PROTOTYPE(OPENSSL_sk_pop_free);
extern DLSYM_PROTOTYPE(OPENSSL_sk_push);
extern DLSYM_PROTOTYPE(OPENSSL_sk_value);
extern DLSYM_PROTOTYPE(OSSL_EC_curve_nid2name);
extern DLSYM_PROTOTYPE(OSSL_PARAM_BLD_free);
extern DLSYM_PROTOTYPE(OSSL_PARAM_BLD_new);
extern DLSYM_PROTOTYPE(OSSL_PARAM_BLD_push_BN);
extern DLSYM_PROTOTYPE(OSSL_PARAM_BLD_push_utf8_string);
extern DLSYM_PROTOTYPE(OSSL_PARAM_BLD_to_param);
extern DLSYM_PROTOTYPE(OSSL_PARAM_construct_BN);
extern DLSYM_PROTOTYPE(OSSL_PARAM_construct_end);
extern DLSYM_PROTOTYPE(OSSL_PARAM_construct_octet_string);
extern DLSYM_PROTOTYPE(OSSL_PARAM_construct_utf8_string);
extern DLSYM_PROTOTYPE(OSSL_PARAM_free);
extern DLSYM_PROTOTYPE(PEM_read_PUBKEY);
extern DLSYM_PROTOTYPE(PEM_read_PrivateKey);
extern DLSYM_PROTOTYPE(PEM_read_X509);
extern DLSYM_PROTOTYPE(PEM_write);
extern DLSYM_PROTOTYPE(PEM_write_PUBKEY);
extern DLSYM_PROTOTYPE(PEM_write_PrivateKey);
extern DLSYM_PROTOTYPE(PEM_write_X509);
extern DLSYM_PROTOTYPE(PKCS5_PBKDF2_HMAC);
extern DLSYM_PROTOTYPE(PKCS7_ATTR_SIGN_it);
extern DLSYM_PROTOTYPE(PKCS7_SIGNER_INFO_free);
extern DLSYM_PROTOTYPE(PKCS7_add0_attrib_signing_time);
extern DLSYM_PROTOTYPE(PKCS7_add1_attrib_digest);
extern DLSYM_PROTOTYPE(PKCS7_add_attrib_content_type);
extern DLSYM_PROTOTYPE(PKCS7_add_attrib_smimecap);
extern DLSYM_PROTOTYPE(PKCS7_add_signed_attribute);
extern DLSYM_PROTOTYPE(PKCS7_content_new);
extern DLSYM_PROTOTYPE(PKCS7_ctrl);
extern DLSYM_PROTOTYPE(PKCS7_dataFinal);
extern DLSYM_PROTOTYPE(PKCS7_dataInit);
extern DLSYM_PROTOTYPE(PKCS7_free);
extern DLSYM_PROTOTYPE(PKCS7_get_signer_info);
extern DLSYM_PROTOTYPE(PKCS7_new);
extern DLSYM_PROTOTYPE(PKCS7_set_content);
extern DLSYM_PROTOTYPE(PKCS7_sign);
extern DLSYM_PROTOTYPE(PKCS7_verify);
extern DLSYM_PROTOTYPE(SHA512);
extern DLSYM_PROTOTYPE(X509_ALGOR_free);
extern DLSYM_PROTOTYPE(X509_ATTRIBUTE_free);
extern DLSYM_PROTOTYPE(X509_NAME_free);
extern DLSYM_PROTOTYPE(X509_NAME_oneline);
extern DLSYM_PROTOTYPE(X509_VERIFY_PARAM_set1_host);
extern DLSYM_PROTOTYPE(X509_VERIFY_PARAM_set1_ip);
extern DLSYM_PROTOTYPE(X509_VERIFY_PARAM_set_hostflags);
extern DLSYM_PROTOTYPE(X509_free);
extern DLSYM_PROTOTYPE(X509_get0_pubkey);
extern DLSYM_PROTOTYPE(X509_get_pubkey);
extern DLSYM_PROTOTYPE(X509_get_subject_name);
extern DLSYM_PROTOTYPE(X509_gmtime_adj);
extern DLSYM_PROTOTYPE(d2i_ASN1_OCTET_STRING);
extern DLSYM_PROTOTYPE(d2i_ECDSA_SIG);
extern DLSYM_PROTOTYPE(d2i_ECPKParameters);
extern DLSYM_PROTOTYPE(d2i_PKCS7);
extern DLSYM_PROTOTYPE(d2i_PUBKEY);
extern DLSYM_PROTOTYPE(d2i_X509);
extern DLSYM_PROTOTYPE(i2d_ASN1_INTEGER);
extern DLSYM_PROTOTYPE(i2d_ECDSA_SIG);
extern DLSYM_PROTOTYPE(i2d_PKCS7);
extern DLSYM_PROTOTYPE(i2d_PKCS7_fp);
extern DLSYM_PROTOTYPE(i2d_PUBKEY);
extern DLSYM_PROTOTYPE(i2d_X509);
extern DLSYM_PROTOTYPE(i2d_X509_NAME);
/* Mirrors of OpenSSL macros that go through our dlopen'd sym_* variants, so we don't end up linking against
* libcrypto just for these. */
#define sym_BIO_get_md_ctx(b, mdcp) sym_BIO_ctrl((b), BIO_C_GET_MD_CTX, 0, (char*) (mdcp))
#define sym_BIO_get_mem_ptr(b, pp) sym_BIO_ctrl((b), BIO_C_GET_BUF_MEM_PTR, 0, (char *) (pp))
#define sym_BIO_reset(b) sym_BIO_ctrl((b), BIO_CTRL_RESET, 0, NULL)
#define sym_BN_num_bytes(a) ((sym_BN_num_bits(a) + 7) / 8)
#define sym_BN_one(a) sym_BN_set_word(a, 1)
#define sym_EVP_MD_CTX_get_size(ctx) sym_EVP_MD_get_size(sym_EVP_MD_CTX_get0_md(ctx))
#define sym_EVP_MD_CTX_get0_name(ctx) sym_EVP_MD_get0_name(sym_EVP_MD_CTX_get0_md(ctx))
#define sym_OPENSSL_free(addr) sym_CRYPTO_free((addr), OPENSSL_FILE, OPENSSL_LINE)
#define sym_PKCS7_set_detached(p, v) sym_PKCS7_ctrl((p), PKCS7_OP_SET_DETACHED_SIGNATURE, (v), NULL)
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_MACRO_RENAME(void*, sym_OPENSSL_free, OPENSSL_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(ASN1_OCTET_STRING*, sym_ASN1_OCTET_STRING_free, ASN1_OCTET_STRING_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(ASN1_TIME*, sym_ASN1_TIME_free, ASN1_TIME_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(BIGNUM*, sym_BN_free, BN_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(BIGNUM*, sym_BN_clear_free, BN_clear_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(BIO*, sym_BIO_free_all, BIO_free_allp, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(BIO*, sym_BIO_free, BIO_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(BN_CTX*, sym_BN_CTX_free, BN_CTX_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(EC_GROUP*, sym_EC_GROUP_free, EC_GROUP_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(EC_POINT*, sym_EC_POINT_free, EC_POINT_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(ECDSA_SIG*, sym_ECDSA_SIG_free, ECDSA_SIG_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(EVP_CIPHER_CTX*, sym_EVP_CIPHER_CTX_free, EVP_CIPHER_CTX_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(EVP_CIPHER*, sym_EVP_CIPHER_free, EVP_CIPHER_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(EVP_MAC_CTX*, sym_EVP_MAC_CTX_free, EVP_MAC_CTX_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(EVP_MAC*, sym_EVP_MAC_free, EVP_MAC_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(EVP_MD_CTX*, sym_EVP_MD_CTX_free, EVP_MD_CTX_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(EVP_MD*, sym_EVP_MD_free, EVP_MD_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(EVP_PKEY_CTX*, sym_EVP_PKEY_CTX_free, EVP_PKEY_CTX_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(EVP_PKEY*, sym_EVP_PKEY_free, EVP_PKEY_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(OSSL_PARAM_BLD*, sym_OSSL_PARAM_BLD_free, OSSL_PARAM_BLD_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(OSSL_PARAM*, sym_OSSL_PARAM_free, OSSL_PARAM_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(PKCS7_SIGNER_INFO*, sym_PKCS7_SIGNER_INFO_free, PKCS7_SIGNER_INFO_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(PKCS7*, sym_PKCS7_free, PKCS7_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(X509_NAME*, sym_X509_NAME_free, X509_NAME_freep, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(X509*, sym_X509_free, X509_freep, NULL);
/* Stack-of macros that go through the dlopen'd sym_OPENSSL_sk_* variants, mirroring the sk_TYPE_OP() helpers
* from <openssl/x509.h> and friends. */
#define sym_sk_X509_new_null() \
((STACK_OF(X509)*) sym_OPENSSL_sk_new_null())
#define sym_sk_X509_push(sk, ptr) \
sym_OPENSSL_sk_push(ossl_check_X509_sk_type(sk), ossl_check_X509_type(ptr))
#define sym_sk_X509_pop_free(sk, freefunc) \
sym_OPENSSL_sk_pop_free(ossl_check_X509_sk_type(sk), ossl_check_X509_freefunc_type(freefunc))
#define sym_sk_X509_ALGOR_pop_free(sk, freefunc) \
sym_OPENSSL_sk_pop_free(ossl_check_X509_ALGOR_sk_type(sk), ossl_check_X509_ALGOR_freefunc_type(freefunc))
#define sym_sk_X509_ATTRIBUTE_pop_free(sk, freefunc) \
sym_OPENSSL_sk_pop_free(ossl_check_X509_ATTRIBUTE_sk_type(sk), ossl_check_X509_ATTRIBUTE_freefunc_type(freefunc))
#define sym_sk_PKCS7_SIGNER_INFO_num(sk) \
sym_OPENSSL_sk_num(ossl_check_const_PKCS7_SIGNER_INFO_sk_type(sk))
#define sym_sk_PKCS7_SIGNER_INFO_value(sk, idx) \
((PKCS7_SIGNER_INFO*) sym_OPENSSL_sk_value(ossl_check_const_PKCS7_SIGNER_INFO_sk_type(sk), (idx)))
static inline STACK_OF(X509_ALGOR) *x509_algor_free_many(STACK_OF(X509_ALGOR) *attrs) {
if (!attrs)
return NULL;
sym_sk_X509_ALGOR_pop_free(attrs, sym_X509_ALGOR_free);
return NULL;
}
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(STACK_OF(X509_ALGOR)*, x509_algor_free_many, NULL);
static inline STACK_OF(X509_ATTRIBUTE) *x509_attribute_free_many(STACK_OF(X509_ATTRIBUTE) *attrs) {
if (!attrs)
return NULL;
sym_sk_X509_ATTRIBUTE_pop_free(attrs, sym_X509_ATTRIBUTE_free);
return NULL;
}
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(STACK_OF(X509_ATTRIBUTE)*, x509_attribute_free_many, NULL);
static inline void sk_X509_free_allp(STACK_OF(X509) **sk) {
if (!sk || !*sk)
return;
sym_sk_X509_pop_free(*sk, sym_X509_free);
}
/* Translates an OpenSSL error code (as returned by ERR_get_error()) into a negative errno. Returns
* -ENOTRECOVERABLE when passed 0 or when the error's reason has no more specific errno. */
int openssl_to_errno(unsigned long e);
int log_openssl_errors_internal(int level, const char *file, int line, const char *func, const char *format, ...) _printf_(5, 6);
/* Logs `format` at `level`, suffixed with each error from the OpenSSL thread-local error queue (or
* "No OpenSSL errors." when it is empty), and returns a negative errno derived from the last error
* (-ENOTRECOVERABLE when the queue is empty or the reason isn't recognized). */
#define log_openssl_errors(level, format, ...) \
log_openssl_errors_internal(level, PROJECT_FILE, __LINE__, __func__, format, ##__VA_ARGS__)
int openssl_pubkey_from_pem(const void *pem, size_t pem_size, EVP_PKEY **ret);
int openssl_pubkey_to_pem(EVP_PKEY *pkey, char **ret);
int openssl_digest_size(const char *digest_alg, size_t *ret_digest_size);
int openssl_digest_many(const char *digest_alg, const struct iovec data[], size_t n_data, void **ret_digest, size_t *ret_digest_size);
static inline int openssl_digest(const char *digest_alg, const void *buf, size_t len, void **ret_digest, size_t *ret_digest_size) {
return openssl_digest_many(digest_alg, &IOVEC_MAKE((void*) buf, len), 1, ret_digest, ret_digest_size);
}
int openssl_hmac_many(const char *digest_alg, const void *key, size_t key_size, const struct iovec data[], size_t n_data, void **ret_digest, size_t *ret_digest_size);
static inline int openssl_hmac(const char *digest_alg, const void *key, size_t key_size, const void *buf, size_t len, void **ret_digest, size_t *ret_digest_size) {
return openssl_hmac_many(digest_alg, key, key_size, &IOVEC_MAKE((void*) buf, len), 1, ret_digest, ret_digest_size);
}
int openssl_cipher_many(const char *alg, size_t bits, const char *mode, const void *key, size_t key_size, const void *iv, size_t iv_size, const struct iovec data[], size_t n_data, void **ret, size_t *ret_size);
static inline int openssl_cipher(const char *alg, size_t bits, const char *mode, const void *key, size_t key_size, const void *iv, size_t iv_size, const void *buf, size_t len, void **ret, size_t *ret_size) {
return openssl_cipher_many(alg, bits, mode, key, key_size, iv, iv_size, &IOVEC_MAKE((void*) buf, len), 1, ret, ret_size);
}
int kdf_ss_derive(const char *digest, const void *key, size_t key_size, const void *salt, size_t salt_size, const void *info, size_t info_size, size_t derive_size, void **ret);
int kdf_kb_hmac_derive(const char *mode, const char *digest, const void *key, size_t key_size, const void *salt, size_t salt_size, const void *info, size_t info_size, const void *seed, size_t seed_size, size_t derive_size, void **ret);
int kdf_hkdf_derive(const char *digest, const struct iovec *key, const struct iovec *salt, const struct iovec *info, size_t derive_size, struct iovec *ret);
int rsa_oaep_encrypt_bytes(const EVP_PKEY *pkey, const char *digest_alg, const char *label, const void *decrypted_key, size_t decrypted_key_size, void **ret_encrypt_key, size_t *ret_encrypt_key_size);
int rsa_pkey_to_suitable_key_size(EVP_PKEY *pkey, size_t *ret_suitable_key_size);
int rsa_pkey_from_n_e(const void *n, size_t n_size, const void *e, size_t e_size, EVP_PKEY **ret);
int rsa_pkey_to_n_e(const EVP_PKEY *pkey, void **ret_n, size_t *ret_n_size, void **ret_e, size_t *ret_e_size);
int ecc_pkey_from_curve_x_y(int curve_id, const void *x, size_t x_size, const void *y, size_t y_size, EVP_PKEY **ret);
int ecc_pkey_to_curve_x_y(const EVP_PKEY *pkey, int *ret_curve_id, void **ret_x, size_t *ret_x_size, void **ret_y, size_t *ret_y_size);
int ecc_pkey_new(int curve_id, EVP_PKEY **ret);
int ecc_ecdh(const EVP_PKEY *private_pkey, const EVP_PKEY *peer_pkey, void **ret_shared_secret, size_t *ret_shared_secret_size);
int pkey_generate_volume_keys(EVP_PKEY *pkey, const char *rsa_oaep_digest_alg, void **ret_decrypted_key, size_t *ret_decrypted_key_size, void **ret_saved_key, size_t *ret_saved_key_size);
int pubkey_fingerprint(EVP_PKEY *pk, const EVP_MD *md, void **ret, size_t *ret_size);
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, 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);
static inline int string_hashsum_sha224(const char *s, size_t len, char **ret) {
return string_hashsum(s, len, "SHA224", ret);
}
static inline int string_hashsum_sha256(const char *s, size_t len, char **ret) {
return string_hashsum(s, len, "SHA256", ret);
}
int x509_fingerprint(X509 *cert, uint8_t buffer[static X509_FINGERPRINT_SIZE]);
int openssl_load_x509_certificate(
CertificateSourceType certificate_source_type,
const char *certificate_source,
const char *certificate,
X509 **ret);
int openssl_load_private_key(
KeySourceType private_key_source_type,
const char *private_key_source,
const char *private_key,
const AskPasswordRequest *request,
EVP_PKEY **ret_private_key,
OpenSSLAskPasswordUI **ret_user_interface);
int openssl_extract_public_key(EVP_PKEY *private_key, EVP_PKEY **ret);
OpenSSLAskPasswordUI* openssl_ask_password_ui_free(OpenSSLAskPasswordUI *ui);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(OpenSSLAskPasswordUI*, openssl_ask_password_ui_free, NULL);
#endif
int dlopen_libcrypto(int log_level) _dlopen_loader_;
bool dlopen_libcrypto_has_argon2id(void);
typedef struct Argon2IdParameters {
uint64_t memcost_bytes;
uint32_t iterations;
uint32_t lanes;
} Argon2IdParameters;
#define ARGON2ID_PARAMETERS_DEFAULT \
(Argon2IdParameters) { \
.memcost_bytes = 64ULL * 1024 * 1024, \
.iterations = 8, \
.lanes = 4, \
}
int kdf_argon2id_derive(const struct iovec *password, const struct iovec *salt, const Argon2IdParameters *params, size_t derive_size, struct iovec *ret);
int kdf_hkdf_sha256(const struct iovec *key, const struct iovec *salt, const struct iovec *info, size_t derive_size, struct iovec *ret);