Hi, Lucas! Sending again because of accidental HTML previous time. >>>>> On Fri, 30 Nov 2018 12:41:48 -0800, Lucas De Marchi wrote: > On Mon, Nov 19, 2018 at 6:00 AM Yauheni Kaliuta > <yauheni.kaliuta@xxxxxxxxxx> wrote: >> >> The patch adds data fetching from the PKCS#7 certificate using >> gnutls library. >> >> In general the certificate can contain many signatures, but since >> kmod (modinfo) supports only one signature at the moment, only first >> one is taken. >> >> With the current sign-file.c certificate doesn't contain signer >> key's fingerprint, so "serial number" is used for the key id. >> >> gnutls has LGPL2.1 license, same as libkmod. > but... why are you adding both openssl and gnutls? They are mutually exclusive options since I do not get any feedback and do not know which direction to go :) > Lucas De Marchi >> >> Signed-off-by: Yauheni Kaliuta <yauheni.kaliuta@xxxxxxxxxx> >> --- >> Makefile.am | 4 +- >> configure.ac | 11 ++ >> libkmod/libkmod-internal.h | 3 + >> libkmod/libkmod-module.c | 3 + >> libkmod/libkmod-signature.c | 208 +++++++++++++++++++++++++++++++++++- >> 5 files changed, 224 insertions(+), 5 deletions(-) >> >> diff --git a/Makefile.am b/Makefile.am >> index 194e1115ae70..2fd44fca69f2 100644 >> --- a/Makefile.am >> +++ b/Makefile.am >> @@ -35,6 +35,8 @@ SED_PROCESS = \ >> -e 's,@liblzma_LIBS\@,${liblzma_LIBS},g' \ >> -e 's,@zlib_CFLAGS\@,${zlib_CFLAGS},g' \ >> -e 's,@zlib_LIBS\@,${zlib_LIBS},g' \ >> + -e 's,@gnutls_CFLAGS\@,${gnutls_CFLAGS},g' \ >> + -e 's,@gnutls_LIBS\@,${gnutls_LIBS},g' \ >> < $< > $@ || rm $@ >> >> %.pc: %.pc.in Makefile >> @@ -87,7 +89,7 @@ libkmod_libkmod_la_DEPENDENCIES = \ >> ${top_srcdir}/libkmod/libkmod.sym >> libkmod_libkmod_la_LIBADD = \ >> shared/libshared.la \ >> - ${liblzma_LIBS} ${zlib_LIBS} >> + ${liblzma_LIBS} ${zlib_LIBS} ${gnutls_LIBS} >> >> noinst_LTLIBRARIES += libkmod/libkmod-internal.la >> libkmod_libkmod_internal_la_SOURCES = $(libkmod_libkmod_la_SOURCES) >> diff --git a/configure.ac b/configure.ac >> index fbc7391b2d1b..0a6787fa9a36 100644 >> --- a/configure.ac >> +++ b/configure.ac >> @@ -106,6 +106,17 @@ AS_IF([test "x$with_zlib" != "xno"], [ >> ]) >> CC_FEATURE_APPEND([with_features], [with_zlib], [ZLIB]) >> >> +AC_ARG_WITH([gnutls], >> + AS_HELP_STRING([--with-gnutls], [handle PKCS7 signatures @<:@default=disabled@:>@]), >> + [], [with_gnutls=no]) >> +AS_IF([test "x$with_gnutls" != "xno"], [ >> + PKG_CHECK_MODULES([gnutls], [gnutls]) >> + AC_DEFINE([ENABLE_GNUTLS], [1], [Enable gnutls for modinfo.]) >> +], [ >> + AC_MSG_NOTICE([gnutls support not requested]) >> +]) >> +CC_FEATURE_APPEND([with_features], [with_gnutls], [GNUTLS]) >> + >> AC_ARG_WITH([bashcompletiondir], >> AS_HELP_STRING([--with-bashcompletiondir=DIR], [Bash completions directory]), >> [], >> diff --git a/libkmod/libkmod-internal.h b/libkmod/libkmod-internal.h >> index 346579c71aab..a65ddd156f18 100644 >> --- a/libkmod/libkmod-internal.h >> +++ b/libkmod/libkmod-internal.h >> @@ -188,5 +188,8 @@ struct kmod_signature_info { >> const char *algo, *hash_algo, *id_type; >> const char *sig; >> size_t sig_len; >> + void (*free)(void *); >> + void *private; >> }; >> bool kmod_module_signature_info(const struct kmod_file *file, struct kmod_signature_info *sig_info) _must_check_ __attribute__((nonnull(1, 2))); >> +void kmod_module_signature_info_free(struct kmod_signature_info *sig_info) __attribute__((nonnull)); >> diff --git a/libkmod/libkmod-module.c b/libkmod/libkmod-module.c >> index 889f26479a98..bffe715cdef4 100644 >> --- a/libkmod/libkmod-module.c >> +++ b/libkmod/libkmod-module.c >> @@ -2357,6 +2357,9 @@ KMOD_EXPORT int kmod_module_get_info(const struct kmod_module *mod, struct kmod_ >> ret = count; >> >> list_error: >> + /* aux structures freed in normal case also */ >> + kmod_module_signature_info_free(&sig_info); >> + >> if (ret < 0) { >> kmod_module_info_free_list(*list); >> *list = NULL; >> diff --git a/libkmod/libkmod-signature.c b/libkmod/libkmod-signature.c >> index 429ffbd8a957..326fa2ea776a 100644 >> --- a/libkmod/libkmod-signature.c >> +++ b/libkmod/libkmod-signature.c >> @@ -19,6 +19,9 @@ >> >> #include <endian.h> >> #include <inttypes.h> >> +#ifdef ENABLE_GNUTLS >> +#include <gnutls/pkcs7.h> >> +#endif >> #include <stdio.h> >> #include <stdlib.h> >> #include <string.h> >> @@ -92,6 +95,13 @@ struct module_signature { >> uint32_t sig_len; /* Length of signature data (big endian) */ >> }; >> >> +static const char *pkey_hash_algo_to_str(enum pkey_hash_algo algo) >> +{ >> + if (algo < 0 || algo >= PKEY_HASH__LAST) >> + return "unknown"; >> + return pkey_hash_algo[algo]; >> +} >> + >> static bool fill_default(const char *mem, off_t size, >> const struct module_signature *modsig, size_t sig_len, >> struct kmod_signature_info *sig_info) >> @@ -115,15 +125,199 @@ static bool fill_default(const char *mem, off_t size, >> return true; >> } >> >> -static bool fill_unknown(const char *mem, off_t size, >> - const struct module_signature *modsig, size_t sig_len, >> - struct kmod_signature_info *sig_info) >> +#ifdef ENABLE_GNUTLS >> + >> +struct pkcs7_private { >> + gnutls_pkcs7_t pkcs7; >> + gnutls_pkcs7_signature_info_st si; >> + gnutls_x509_dn_t dn; >> + gnutls_datum_t dn_data; >> + char *issuer; >> +}; >> + >> +static void pkcs7_free(void *s) >> +{ >> + struct kmod_signature_info *si = s; >> + struct pkcs7_private *pvt = si->private; >> + >> + free(pvt->issuer); >> + gnutls_free(pvt->dn_data.data); >> + gnutls_x509_dn_deinit(pvt->dn); >> + gnutls_pkcs7_signature_info_deinit(&pvt->si); >> + gnutls_pkcs7_deinit(pvt->pkcs7); >> + >> + free(pvt); >> + si->private = NULL; >> +} >> + >> +static int gnutls_algo_translate(gnutls_sign_algorithm_t algo) >> +{ >> + switch (algo) { >> + case GNUTLS_SIGN_RSA_SHA1: >> + case GNUTLS_SIGN_DSA_SHA1: >> + case GNUTLS_SIGN_ECDSA_SHA1: >> + return PKEY_HASH_SHA1; >> + case GNUTLS_SIGN_RSA_MD5: >> + return PKEY_HASH_MD5; >> + case GNUTLS_SIGN_RSA_RMD160: >> + return PKEY_HASH_RIPE_MD_160; >> + case GNUTLS_SIGN_RSA_SHA256: >> + case GNUTLS_SIGN_DSA_SHA256: >> + case GNUTLS_SIGN_ECDSA_SHA256: >> + return PKEY_HASH_SHA256; >> + case GNUTLS_SIGN_RSA_SHA384: >> + case GNUTLS_SIGN_ECDSA_SHA384: >> + case GNUTLS_SIGN_DSA_SHA384: >> + return PKEY_HASH_SHA384; >> + case GNUTLS_SIGN_RSA_SHA512: >> + case GNUTLS_SIGN_ECDSA_SHA512: >> + case GNUTLS_SIGN_DSA_SHA512: >> + return PKEY_HASH_SHA512; >> + case GNUTLS_SIGN_RSA_SHA224: >> + case GNUTLS_SIGN_DSA_SHA224: >> + case GNUTLS_SIGN_ECDSA_SHA224: >> + return PKEY_HASH_SHA224; >> + default: >> + return -1; >> + } >> + return -1; >> +} >> + >> +/* >> + * Extracts CN from O=Org,CN=CommonName,EMAIL=email >> + */ >> +static char *dn_str_to_cn(unsigned char *dn) >> +{ >> + char *s; >> + char *e; >> + char *r; >> + size_t len; >> + >> + s = strstr((char *)dn, "CN="); >> + if (s == NULL) >> + return NULL; >> + >> + len = strlen(s); >> + if (len < strlen("CN=") + 1) /* at least one symbol */ >> + return NULL; >> + s += strlen("CN="); >> + >> + e = strchr(s, ','); >> + if (e == NULL) >> + e = s + len; >> + len = e - s; >> + >> + r = malloc(len + 1); >> + if (r == NULL) >> + return NULL; >> + >> + memcpy(r, s, len); >> + r[len] = '\0'; >> + return r; >> +} >> +static bool fill_pkcs7(const char *mem, off_t size, >> + const struct module_signature *modsig, size_t sig_len, >> + struct kmod_signature_info *sig_info) >> +{ >> + int rc; >> + const char *pkcs7_raw; >> + gnutls_pkcs7_t pkcs7; >> + gnutls_datum_t data; >> + gnutls_pkcs7_signature_info_st si; >> + gnutls_x509_dn_t dn; >> + struct pkcs7_private *pvt; >> + char *issuer; >> + >> + size -= sig_len; >> + pkcs7_raw = mem + size; >> + >> + rc = gnutls_pkcs7_init(&pkcs7); >> + if (rc < 0) >> + return false; >> + >> + data.data = (unsigned char *)pkcs7_raw; >> + data.size = sig_len; >> + rc = gnutls_pkcs7_import(pkcs7, &data, GNUTLS_X509_FMT_DER); >> + if (rc < 0) >> + goto err1; >> + >> + rc = gnutls_pkcs7_get_signature_info(pkcs7, 0, &si); >> + if (rc < 0) >> + goto err1; >> + >> + rc = gnutls_x509_dn_init(&dn); >> + if (rc < 0) >> + goto err2; >> + >> + rc = gnutls_x509_dn_import(dn, &si.issuer_dn); >> + if (rc < 0) >> + goto err3; >> + >> + /* >> + * I could not find simple wrapper to extract the data >> + * directly from ASN1, so get the string and parse it. >> + * >> + * Returns null-terminated string in data.data >> + */ >> + rc = gnutls_x509_dn_get_str(dn, &data); >> + if (rc < 0) >> + goto err3; >> + >> + sig_info->sig = (const char *)si.sig.data; >> + sig_info->sig_len = si.sig.size; >> + >> + sig_info->key_id = (const char *)si.signer_serial.data; >> + sig_info->key_id_len = si.signer_serial.size; >> + >> + issuer = dn_str_to_cn(data.data); >> + if (issuer != NULL) { >> + sig_info->signer = issuer; >> + sig_info->signer_len = strlen(issuer); >> + } >> + >> + sig_info->hash_algo = pkey_hash_algo_to_str(gnutls_algo_translate(si.algo)); >> + sig_info->id_type = pkey_id_type[modsig->id_type]; >> + >> + pvt = malloc(sizeof(*pvt)); >> + if (pvt == NULL) >> + goto err4; >> + >> + pvt->pkcs7 = pkcs7; >> + pvt->si = si; >> + pvt->dn = dn; >> + pvt->dn_data = data; >> + pvt->issuer = issuer; >> + >> + sig_info->private = pvt; >> + sig_info->free = pkcs7_free; >> + >> + return true; >> + >> +err4: >> + gnutls_free(data.data); >> +err3: >> + gnutls_x509_dn_deinit(dn); >> +err2: >> + gnutls_pkcs7_signature_info_deinit(&si); >> +err1: >> + gnutls_pkcs7_deinit(pkcs7); >> + >> + return false; >> +} >> + >> +#else /* ENABLE GNUTLS */ >> + >> +static bool fill_pkcs7(const char *mem, off_t size, >> + const struct module_signature *modsig, size_t sig_len, >> + struct kmod_signature_info *sig_info) >> { sig_info-> hash_algo = "unknown"; sig_info-> id_type = pkey_id_type[modsig->id_type]; >> return true; >> } >> >> +#endif /* ENABLE GNUTLS */ >> + >> #define SIG_MAGIC "~Module signature appended~\n" >> >> /* >> @@ -167,8 +361,14 @@ bool kmod_module_signature_info(const struct kmod_file *file, struct kmod_signat >> >> switch (modsig->id_type) { >> case PKEY_ID_PKCS7: >> - return fill_unknown(mem, size, modsig, sig_len, sig_info); >> + return fill_pkcs7(mem, size, modsig, sig_len, sig_info); >> default: >> return fill_default(mem, size, modsig, sig_len, sig_info); >> } >> } >> + >> +void kmod_module_signature_info_free(struct kmod_signature_info *sig_info) >> +{ >> + if (sig_info->free) >> + sig_info->free(sig_info); >> +} >> -- >> 2.19.1 >> > -- > Lucas De Marchi -- WBR, Yauheni Kaliuta