From: Emil Velikov Date: Mon, 1 Jun 2026 14:45:57 +0000 (+0100) Subject: libkmod: move openssl-related functions to separate file X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=434bf35f65f89c7284c17c5f57156eb6ee29ac6f;p=thirdparty%2Fkmod.git libkmod: move openssl-related functions to separate file Move openssl-related function to a separate file so it's easier to isolate the dependency on each crypto library. This will allow multiple implementations to co-exist in the same build. As a nice side effect we fallback to the "dummy" implementation in the (very likely) case that the openssl one fails. Signed-off-by: Emil Velikov Link: https://github.com/kmod-project/kmod/pull/426 Signed-off-by: Lucas De Marchi --- diff --git a/libkmod/docs/meson.build b/libkmod/docs/meson.build index eefec18d..5913ab2f 100644 --- a/libkmod/docs/meson.build +++ b/libkmod/docs/meson.build @@ -13,6 +13,7 @@ built_docs = gnome.gtkdoc( f'@project_source_root@/libkmod/libkmod-index.h', f'@project_source_root@/libkmod/libkmod-internal-file.h', f'@project_source_root@/libkmod/libkmod-internal.h', + f'@project_source_root@/libkmod/libkmod-internal-signature.h', ], scan_args : '--ignore-decorators="KMOD_EXPORT"', src_dir : f'@project_source_root@/libkmod/', diff --git a/libkmod/libkmod-internal-signature.h b/libkmod/libkmod-internal-signature.h new file mode 100644 index 00000000..b58193d5 --- /dev/null +++ b/libkmod/libkmod-internal-signature.h @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +// SPDX-FileCopyrightText: 2026 Emil Velikov + +#include + +#if ENABLE_OPENSSL +bool kmod_fill_pkcs7_openssl(const char *mem, off_t size, size_t sig_len, + struct kmod_signature_info **out_sig_info); +#else +static inline bool kmod_fill_pkcs7_openssl(const char *mem, off_t size, size_t sig_len, + struct kmod_signature_info **out_sig_info) +{ + return false; +} +#endif diff --git a/libkmod/libkmod-signature-openssl.c b/libkmod/libkmod-signature-openssl.c new file mode 100644 index 00000000..0af525e8 --- /dev/null +++ b/libkmod/libkmod-signature-openssl.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +// SPDX-FileCopyrightText: 2013 Michal Marek, SUSE + +#define DLSYM_LOCALLY_ENABLED ENABLE_OPENSSL_DLOPEN + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "libkmod-internal-signature.h" + +#define DL_SYMBOL_TABLE(M) \ + M(ASN1_INTEGER_to_BN) \ + M(ASN1_STRING_get0_data) \ + M(ASN1_STRING_length) \ + M(BIO_free) \ + M(BIO_new_mem_buf) \ + M(BN_bn2bin) \ + M(BN_free) \ + M(BN_num_bits) \ + M(d2i_PKCS7_bio) \ + M(OBJ_obj2nid) \ + M(OBJ_obj2txt) \ + M(OPENSSL_sk_value) \ + M(PKCS7_free) \ + M(PKCS7_get_signer_info) \ + M(PKCS7_SIGNER_INFO_get0_algs) \ + M(X509_ALGOR_get0) \ + M(X509_NAME_entry_count) \ + M(X509_NAME_ENTRY_get_data) \ + M(X509_NAME_ENTRY_get_object) \ + M(X509_NAME_get_entry) + +DL_SYMBOL_TABLE(DECLARE_SYM) + +/* Portion of the libcrypto/openssl API is nested inline functions and/or macros. As such, we + * need to copy/paste a few so our forwarding works. + */ +#define sym_BN_num_bytes(a) ((sym_BN_num_bits(a) + 7) / 8) +#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 int dlopen_crypto(void) +{ +#if !DLSYM_LOCALLY_ENABLED + return 0; +#else + static void *dl; + + ELF_NOTE_DLOPEN("openssl", "Support for reading module signatures", + ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, "libcrypto.so.3"); + + return dlsym_many(&dl, "libcrypto.so.3", DL_SYMBOL_TABLE(DLSYM_ARG) NULL); +#endif +} + +static const char *x509_name_to_str(X509_NAME *name) +{ + int i; + X509_NAME_ENTRY *e; + ASN1_STRING *d; + ASN1_OBJECT *o; + int nid = -1; + const char *str; + + for (i = 0; i < sym_X509_NAME_entry_count(name); i++) { + e = sym_X509_NAME_get_entry(name, i); + o = sym_X509_NAME_ENTRY_get_object(e); + nid = sym_OBJ_obj2nid(o); + if (nid == NID_commonName) + break; + } + if (nid == -1) + return NULL; + + d = sym_X509_NAME_ENTRY_get_data(e); + str = (const char *)sym_ASN1_STRING_get0_data(d); + + return str; +} + +bool kmod_fill_pkcs7_openssl(const char *mem, off_t size, size_t sig_len, + struct kmod_signature_info **out_sig_info) +{ + struct kmod_signature_info *sig_info; + char *p; + const char *pkcs7_raw; + PKCS7 *pkcs7; + STACK_OF(PKCS7_SIGNER_INFO) * sis; + PKCS7_SIGNER_INFO *si; + const PKCS7_ISSUER_AND_SERIAL *is; + const ASN1_OCTET_STRING *sig; + BIGNUM *sno_bn; + X509_ALGOR *dig_alg; + const ASN1_OBJECT *o; + BIO *in; + const char *issuer_str; + int hash_algo_len; + size_t total_len; + int ret; + + ret = dlopen_crypto(); + if (ret < 0) + return false; + + size -= sig_len; + pkcs7_raw = mem + size; + + in = sym_BIO_new_mem_buf(pkcs7_raw, sig_len); + + pkcs7 = sym_d2i_PKCS7_bio(in, NULL); + sym_BIO_free(in); + + if (pkcs7 == NULL) + goto err; + + sis = sym_PKCS7_get_signer_info(pkcs7); + if (sis == NULL) + goto err; + + si = sym_sk_PKCS7_SIGNER_INFO_value(sis, 0); + if (si == NULL || si->issuer_and_serial == NULL || si->enc_digest == NULL) + goto err; + + is = si->issuer_and_serial; + + /* Calculate the total length */ + total_len = sizeof(struct kmod_signature_info); + + /* signer */ + issuer_str = x509_name_to_str(is->issuer); + if (issuer_str != NULL) + total_len += strlen(issuer_str); + + /* key_id */ + sno_bn = sym_ASN1_INTEGER_to_BN(is->serial, NULL); + if (sno_bn == NULL) + goto err; + + total_len += sym_BN_num_bytes(sno_bn); + + /* hash_algo */ + sym_PKCS7_SIGNER_INFO_get0_algs(si, NULL, &dig_alg, NULL); + sym_X509_ALGOR_get0(&o, NULL, NULL, dig_alg); + hash_algo_len = sym_OBJ_obj2txt(NULL, 0, o, 0); + if (hash_algo_len < 0) + goto err1; + + total_len += hash_algo_len + 1; + + /* sig */ + sig = si->enc_digest; + total_len += sym_ASN1_STRING_length(sig); + + sig_info = calloc(1, total_len); + if (sig_info == NULL) + goto err1; + + p = (char *)sig_info; + + p += sizeof(struct kmod_signature_info); + + /* signer */ + if (issuer_str != NULL) { + sig_info->signer = p; + sig_info->signer_len = strlen(issuer_str); + + memcpy(p, issuer_str, sig_info->signer_len); + p += sig_info->signer_len; + } + + /* key_id */ + sig_info->key_id = p; + sig_info->key_id_len = sym_BN_num_bytes(sno_bn); + + sym_BN_bn2bin(sno_bn, (unsigned char *)p); + p += sig_info->key_id_len; + + /* hash_algo */ + sig_info->hash_algo = p; + + hash_algo_len = sym_OBJ_obj2txt(p, hash_algo_len + 1, o, 0); + if (hash_algo_len < 0) + goto err2; + p += hash_algo_len; + + *p = '\0'; + p++; + + /* sig */ + sig_info->sig = p; + sig_info->sig_len = sym_ASN1_STRING_length(sig); + + memcpy(p, sym_ASN1_STRING_get0_data(sig), sig_info->sig_len); + + sym_BN_free(sno_bn); + sym_PKCS7_free(pkcs7); + + *out_sig_info = sig_info; + + return true; + +err2: + free(sig_info); +err1: + sym_BN_free(sno_bn); +err: + sym_PKCS7_free(pkcs7); + return false; +} diff --git a/libkmod/libkmod-signature.c b/libkmod/libkmod-signature.c index 04a29853..9f9181ee 100644 --- a/libkmod/libkmod-signature.c +++ b/libkmod/libkmod-signature.c @@ -3,23 +3,15 @@ * Copyright (C) 2013 Michal Marek, SUSE */ -#define DLSYM_LOCALLY_ENABLED ENABLE_OPENSSL_DLOPEN - #include #include -#if ENABLE_OPENSSL -#include -#include -#endif #include #include #include -#include -#include #include -#include "libkmod-internal.h" +#include "libkmod-internal-signature.h" /* These types and tables were copied from the 3.7 kernel sources. * As this is just description of the signature format, it should not be @@ -111,213 +103,8 @@ static bool fill_default(const char *mem, off_t size, return true; } -#if ENABLE_OPENSSL - -#define DL_SYMBOL_TABLE(M) \ - M(ASN1_INTEGER_to_BN) \ - M(ASN1_STRING_get0_data) \ - M(ASN1_STRING_length) \ - M(BIO_free) \ - M(BIO_new_mem_buf) \ - M(BN_bn2bin) \ - M(BN_free) \ - M(BN_num_bits) \ - M(d2i_PKCS7_bio) \ - M(OBJ_obj2nid) \ - M(OBJ_obj2txt) \ - M(OPENSSL_sk_value) \ - M(PKCS7_free) \ - M(PKCS7_get_signer_info) \ - M(PKCS7_SIGNER_INFO_get0_algs) \ - M(X509_ALGOR_get0) \ - M(X509_NAME_entry_count) \ - M(X509_NAME_ENTRY_get_data) \ - M(X509_NAME_ENTRY_get_object) \ - M(X509_NAME_get_entry) - -DL_SYMBOL_TABLE(DECLARE_SYM) - -/* Portion of the libcrypto/openssl API is nested inline functions and/or macros. As such, we - * need to copy/paste a few so our forwarding works. - */ -#define sym_BN_num_bytes(a) ((sym_BN_num_bits(a) + 7) / 8) -#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 int dlopen_crypto(void) -{ -#if !DLSYM_LOCALLY_ENABLED - return 0; -#else - static void *dl; - - ELF_NOTE_DLOPEN("openssl", "Support for reading module signatures", - ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, "libcrypto.so.3"); - - return dlsym_many(&dl, "libcrypto.so.3", DL_SYMBOL_TABLE(DLSYM_ARG) NULL); -#endif -} - -static const char *x509_name_to_str(X509_NAME *name) -{ - int i; - X509_NAME_ENTRY *e; - ASN1_STRING *d; - ASN1_OBJECT *o; - int nid = -1; - const char *str; - - for (i = 0; i < sym_X509_NAME_entry_count(name); i++) { - e = sym_X509_NAME_get_entry(name, i); - o = sym_X509_NAME_ENTRY_get_object(e); - nid = sym_OBJ_obj2nid(o); - if (nid == NID_commonName) - break; - } - if (nid == -1) - return NULL; - - d = sym_X509_NAME_ENTRY_get_data(e); - str = (const char *)sym_ASN1_STRING_get0_data(d); - - return str; -} - -static bool fill_pkcs7(const char *mem, off_t size, size_t sig_len, - struct kmod_signature_info **out_sig_info) -{ - struct kmod_signature_info *sig_info; - char *p; - const char *pkcs7_raw; - PKCS7 *pkcs7; - STACK_OF(PKCS7_SIGNER_INFO) * sis; - PKCS7_SIGNER_INFO *si; - const PKCS7_ISSUER_AND_SERIAL *is; - const ASN1_OCTET_STRING *sig; - BIGNUM *sno_bn; - X509_ALGOR *dig_alg; - const ASN1_OBJECT *o; - BIO *in; - const char *issuer_str; - int hash_algo_len; - size_t total_len; - int ret; - - ret = dlopen_crypto(); - if (ret < 0) - return false; - - size -= sig_len; - pkcs7_raw = mem + size; - - in = sym_BIO_new_mem_buf(pkcs7_raw, sig_len); - - pkcs7 = sym_d2i_PKCS7_bio(in, NULL); - sym_BIO_free(in); - - if (pkcs7 == NULL) - goto err; - - sis = sym_PKCS7_get_signer_info(pkcs7); - if (sis == NULL) - goto err; - - si = sym_sk_PKCS7_SIGNER_INFO_value(sis, 0); - if (si == NULL || si->issuer_and_serial == NULL || si->enc_digest == NULL) - goto err; - - is = si->issuer_and_serial; - - /* Calculate the total length */ - total_len = sizeof(struct kmod_signature_info); - - /* signer */ - issuer_str = x509_name_to_str(is->issuer); - if (issuer_str != NULL) - total_len += strlen(issuer_str); - - /* key_id */ - sno_bn = sym_ASN1_INTEGER_to_BN(is->serial, NULL); - if (sno_bn == NULL) - goto err; - - total_len += sym_BN_num_bytes(sno_bn); - - /* hash_algo */ - sym_PKCS7_SIGNER_INFO_get0_algs(si, NULL, &dig_alg, NULL); - sym_X509_ALGOR_get0(&o, NULL, NULL, dig_alg); - hash_algo_len = sym_OBJ_obj2txt(NULL, 0, o, 0); - if (hash_algo_len < 0) - goto err1; - - total_len += hash_algo_len + 1; - - /* sig */ - sig = si->enc_digest; - total_len += sym_ASN1_STRING_length(sig); - - sig_info = calloc(1, total_len); - if (sig_info == NULL) - goto err1; - - p = (char *)sig_info; - - p += sizeof(struct kmod_signature_info); - - /* signer */ - if (issuer_str != NULL) { - sig_info->signer = p; - sig_info->signer_len = strlen(issuer_str); - - memcpy(p, issuer_str, sig_info->signer_len); - p += sig_info->signer_len; - } - - /* key_id */ - sig_info->key_id = p; - sig_info->key_id_len = sym_BN_num_bytes(sno_bn); - - sym_BN_bn2bin(sno_bn, (unsigned char *)p); - p += sig_info->key_id_len; - - /* hash_algo */ - sig_info->hash_algo = p; - - hash_algo_len = sym_OBJ_obj2txt(p, hash_algo_len + 1, o, 0); - if (hash_algo_len < 0) - goto err2; - p += hash_algo_len; - - *p = '\0'; - p++; - - /* sig */ - sig_info->sig = p; - sig_info->sig_len = sym_ASN1_STRING_length(sig); - - memcpy(p, sym_ASN1_STRING_get0_data(sig), sig_info->sig_len); - - sym_BN_free(sno_bn); - sym_PKCS7_free(pkcs7); - - *out_sig_info = sig_info; - - return true; - -err2: - free(sig_info); -err1: - sym_BN_free(sno_bn); -err: - sym_PKCS7_free(pkcs7); - return false; -} - -#else - -static bool fill_pkcs7(const char *mem, off_t size, size_t sig_len, - struct kmod_signature_info **out_sig_info) +static bool kmod_fill_pkcs7_dummy(const char *mem, off_t size, size_t sig_len, + struct kmod_signature_info **out_sig_info) { struct kmod_signature_info *sig_info = calloc(1, sizeof(*sig_info)); if (sig_info == NULL) @@ -328,8 +115,6 @@ static bool fill_pkcs7(const char *mem, off_t size, size_t sig_len, return true; } -#endif - #define SIG_MAGIC "~Module signature appended~\n" /* @@ -382,7 +167,9 @@ bool kmod_module_signature_info(const struct kmod_file *file, switch (modsig.id_type) { case PKEY_ID_PKCS7: - ret = fill_pkcs7(mem, size, sig_len, sig_info); + ret = kmod_fill_pkcs7_openssl(mem, size, sig_len, sig_info); + if (!ret) + ret = kmod_fill_pkcs7_dummy(mem, size, sig_len, sig_info); break; default: ret = fill_default(mem, size, &modsig, sig_len, sig_info); diff --git a/meson.build b/meson.build index 9fdf7634..076c552b 100644 --- a/meson.build +++ b/meson.build @@ -388,6 +388,7 @@ if dep_map.get('zlib').found() endif if dep_map.get('openssl').found() + libkmod_files += files('libkmod/libkmod-signature-openssl.c') libkmod_deps += dep_map['openssl'] endif