Re: [PATCH RFC] libkmod-signature: implement pkcs7 parsing with gnutls

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux