Blame SOURCES/kmod-libkmod-signature-implement-pkcs7-parsing-with-opens.patch

068827
From 391b4714b495183baefa9cb10ac8e1600c166a59 Mon Sep 17 00:00:00 2001
068827
From: Yauheni Kaliuta <yauheni.kaliuta@redhat.com>
068827
Date: Fri, 1 Feb 2019 22:20:02 +0200
068827
Subject: [PATCH] libkmod-signature: implement pkcs7 parsing with openssl
068827
068827
The patch adds data fetching from the PKCS#7 certificate using
068827
openssl library (which is used by scripts/sign-file.c in the linux
068827
kernel to sign modules).
068827
068827
In general the certificate can contain many signatures, but since
068827
kmod (modinfo) supports only one signature at the moment, only first
068827
one is taken.
068827
068827
With the current sign-file.c certificate doesn't contain signer
068827
key's fingerprint, so "serial number" is used for the key id.
068827
068827
Signed-off-by: Yauheni Kaliuta <yauheni.kaliuta@redhat.com>
068827
---
068827
 Makefile.am                 |   4 +-
068827
 configure.ac                |  11 ++
068827
 libkmod/libkmod-internal.h  |   3 +
068827
 libkmod/libkmod-module.c    |   3 +
068827
 libkmod/libkmod-signature.c | 197 +++++++++++++++++++++++++++++++++++-
068827
 5 files changed, 213 insertions(+), 5 deletions(-)
068827
068827
diff --git a/Makefile.am b/Makefile.am
068827
index 1ab1db585316..de1026f8bd46 100644
068827
--- a/Makefile.am
068827
+++ b/Makefile.am
068827
@@ -35,6 +35,8 @@ SED_PROCESS = \
068827
 	-e 's,@liblzma_LIBS\@,${liblzma_LIBS},g' \
068827
 	-e 's,@zlib_CFLAGS\@,${zlib_CFLAGS},g' \
068827
 	-e 's,@zlib_LIBS\@,${zlib_LIBS},g' \
068827
+	-e 's,@openssl_CFLAGS\@,${openssl_CFLAGS},g' \
068827
+	-e 's,@openssl_LIBS\@,${openssl_LIBS},g' \
068827
 	< $< > $@ || rm $@
068827
 
068827
 %.pc: %.pc.in Makefile
068827
@@ -87,7 +89,7 @@ libkmod_libkmod_la_DEPENDENCIES = \
068827
 	${top_srcdir}/libkmod/libkmod.sym
068827
 libkmod_libkmod_la_LIBADD = \
068827
 	shared/libshared.la \
068827
-	${liblzma_LIBS} ${zlib_LIBS}
068827
+	${liblzma_LIBS} ${zlib_LIBS} ${openssl_LIBS}
068827
 
068827
 noinst_LTLIBRARIES += libkmod/libkmod-internal.la
068827
 libkmod_libkmod_internal_la_SOURCES = $(libkmod_libkmod_la_SOURCES)
068827
diff --git a/configure.ac b/configure.ac
068827
index fbc7391b2d1b..2e33380a0cc2 100644
068827
--- a/configure.ac
068827
+++ b/configure.ac
068827
@@ -106,6 +106,17 @@ AS_IF([test "x$with_zlib" != "xno"], [
068827
 ])
068827
 CC_FEATURE_APPEND([with_features], [with_zlib], [ZLIB])
068827
 
068827
+AC_ARG_WITH([openssl],
068827
+	AS_HELP_STRING([--with-openssl], [handle PKCS7 signatures @<:@default=disabled@:>@]),
068827
+	[], [with_openssl=no])
068827
+AS_IF([test "x$with_openssl" != "xno"], [
068827
+	PKG_CHECK_MODULES([openssl], [openssl])
068827
+	AC_DEFINE([ENABLE_OPENSSL], [1], [Enable openssl for modinfo.])
068827
+], [
068827
+	AC_MSG_NOTICE([openssl support not requested])
068827
+])
068827
+CC_FEATURE_APPEND([with_features], [with_openssl], [OPENSSL])
068827
+
068827
 AC_ARG_WITH([bashcompletiondir],
068827
 	AS_HELP_STRING([--with-bashcompletiondir=DIR], [Bash completions directory]),
068827
 	[],
068827
diff --git a/libkmod/libkmod-internal.h b/libkmod/libkmod-internal.h
068827
index 346579c71aab..a65ddd156f18 100644
068827
--- a/libkmod/libkmod-internal.h
068827
+++ b/libkmod/libkmod-internal.h
068827
@@ -188,5 +188,8 @@ struct kmod_signature_info {
068827
 	const char *algo, *hash_algo, *id_type;
068827
 	const char *sig;
068827
 	size_t sig_len;
068827
+	void (*free)(void *);
068827
+	void *private;
068827
 };
068827
 bool kmod_module_signature_info(const struct kmod_file *file, struct kmod_signature_info *sig_info) _must_check_ __attribute__((nonnull(1, 2)));
068827
+void kmod_module_signature_info_free(struct kmod_signature_info *sig_info) __attribute__((nonnull));
068827
diff --git a/libkmod/libkmod-module.c b/libkmod/libkmod-module.c
068827
index 889f26479a98..bffe715cdef4 100644
068827
--- a/libkmod/libkmod-module.c
068827
+++ b/libkmod/libkmod-module.c
068827
@@ -2357,6 +2357,9 @@ KMOD_EXPORT int kmod_module_get_info(const struct kmod_module *mod, struct kmod_
068827
 	ret = count;
068827
 
068827
 list_error:
068827
+	/* aux structures freed in normal case also */
068827
+	kmod_module_signature_info_free(&sig_info);
068827
+
068827
 	if (ret < 0) {
068827
 		kmod_module_info_free_list(*list);
068827
 		*list = NULL;
068827
diff --git a/libkmod/libkmod-signature.c b/libkmod/libkmod-signature.c
068827
index 429ffbd8a957..48d0145a7552 100644
068827
--- a/libkmod/libkmod-signature.c
068827
+++ b/libkmod/libkmod-signature.c
068827
@@ -19,6 +19,10 @@
068827
 
068827
 #include <endian.h>
068827
 #include <inttypes.h>
068827
+#ifdef ENABLE_OPENSSL
068827
+#include <openssl/cms.h>
068827
+#include <openssl/ssl.h>
068827
+#endif
068827
 #include <stdio.h>
068827
 #include <stdlib.h>
068827
 #include <string.h>
068827
@@ -115,15 +119,194 @@ static bool fill_default(const char *mem, off_t size,
068827
 	return true;
068827
 }
068827
 
068827
-static bool fill_unknown(const char *mem, off_t size,
068827
-			 const struct module_signature *modsig, size_t sig_len,
068827
-			 struct kmod_signature_info *sig_info)
068827
+#ifdef ENABLE_OPENSSL
068827
+
068827
+struct pkcs7_private {
068827
+	CMS_ContentInfo *cms;
068827
+	unsigned char *key_id;
068827
+	BIGNUM *sno;
068827
+};
068827
+
068827
+static void pkcs7_free(void *s)
068827
+{
068827
+	struct kmod_signature_info *si = s;
068827
+	struct pkcs7_private *pvt = si->private;
068827
+
068827
+	CMS_ContentInfo_free(pvt->cms);
068827
+	BN_free(pvt->sno);
068827
+	free(pvt->key_id);
068827
+	free(pvt);
068827
+	si->private = NULL;
068827
+}
068827
+
068827
+static int obj_to_hash_algo(const ASN1_OBJECT *o)
068827
+{
068827
+	int nid;
068827
+
068827
+	nid = OBJ_obj2nid(o);
068827
+	switch (nid) {
068827
+	case NID_md4:
068827
+		return PKEY_HASH_MD4;
068827
+	case NID_md5:
068827
+		return PKEY_HASH_MD5;
068827
+	case NID_sha1:
068827
+		return PKEY_HASH_SHA1;
068827
+	case NID_ripemd160:
068827
+		return PKEY_HASH_RIPE_MD_160;
068827
+	case NID_sha256:
068827
+		return PKEY_HASH_SHA256;
068827
+	case NID_sha384:
068827
+		return PKEY_HASH_SHA384;
068827
+	case NID_sha512:
068827
+		return PKEY_HASH_SHA512;
068827
+	case NID_sha224:
068827
+		return PKEY_HASH_SHA224;
068827
+	default:
068827
+		return -1;
068827
+	}
068827
+	return -1;
068827
+}
068827
+
068827
+static const char *x509_name_to_str(X509_NAME *name)
068827
+{
068827
+	int i;
068827
+	X509_NAME_ENTRY *e;
068827
+	ASN1_STRING *d;
068827
+	ASN1_OBJECT *o;
068827
+	int nid = -1;
068827
+	const char *str;
068827
+
068827
+	for (i = 0; i < X509_NAME_entry_count(name); i++) {
068827
+		e = X509_NAME_get_entry(name, i);
068827
+		o = X509_NAME_ENTRY_get_object(e);
068827
+		nid = OBJ_obj2nid(o);
068827
+		if (nid == NID_commonName)
068827
+			break;
068827
+	}
068827
+	if (nid == -1)
068827
+		return NULL;
068827
+
068827
+	d = X509_NAME_ENTRY_get_data(e);
068827
+	str = (const char *)ASN1_STRING_get0_data(d);
068827
+
068827
+	return str;
068827
+}
068827
+
068827
+static bool fill_pkcs7(const char *mem, off_t size,
068827
+		       const struct module_signature *modsig, size_t sig_len,
068827
+		       struct kmod_signature_info *sig_info)
068827
+{
068827
+	const char *pkcs7_raw;
068827
+	CMS_ContentInfo *cms;
068827
+	STACK_OF(CMS_SignerInfo) *sis;
068827
+	CMS_SignerInfo *si;
068827
+	int rc;
068827
+	ASN1_OCTET_STRING *key_id;
068827
+	X509_NAME *issuer;
068827
+	ASN1_INTEGER *sno;
068827
+	ASN1_OCTET_STRING *sig;
068827
+	BIGNUM *sno_bn;
068827
+	X509_ALGOR *dig_alg;
068827
+	X509_ALGOR *sig_alg;
068827
+	const ASN1_OBJECT *o;
068827
+	BIO *in;
068827
+	int len;
068827
+	unsigned char *key_id_str;
068827
+	struct pkcs7_private *pvt;
068827
+	const char *issuer_str;
068827
+
068827
+	size -= sig_len;
068827
+	pkcs7_raw = mem + size;
068827
+
068827
+	in = BIO_new_mem_buf(pkcs7_raw, sig_len);
068827
+
068827
+	cms = d2i_CMS_bio(in, NULL);
068827
+	if (cms == NULL) {
068827
+		BIO_free(in);
068827
+		return false;
068827
+	}
068827
+
068827
+	BIO_free(in);
068827
+
068827
+	sis = CMS_get0_SignerInfos(cms);
068827
+	if (sis == NULL)
068827
+		goto err;
068827
+
068827
+	si = sk_CMS_SignerInfo_value(sis, 0);
068827
+	if (si == NULL)
068827
+		goto err;
068827
+
068827
+	rc = CMS_SignerInfo_get0_signer_id(si, &key_id, &issuer, &sno);
068827
+	if (rc == 0)
068827
+		goto err;
068827
+
068827
+	sig = CMS_SignerInfo_get0_signature(si);
068827
+	if (sig == NULL)
068827
+		goto err;
068827
+
068827
+	CMS_SignerInfo_get0_algs(si, NULL, NULL, &dig_alg, &sig_alg);
068827
+
068827
+	sig_info->sig = (const char *)ASN1_STRING_get0_data(sig);
068827
+	sig_info->sig_len = ASN1_STRING_length(sig);
068827
+
068827
+	sno_bn = ASN1_INTEGER_to_BN(sno, NULL);
068827
+	if (sno_bn == NULL)
068827
+		goto err;
068827
+
068827
+	len = BN_num_bytes(sno_bn);
068827
+	key_id_str = malloc(len);
068827
+	if (key_id_str == NULL)
068827
+		goto err2;
068827
+	BN_bn2bin(sno_bn, key_id_str);
068827
+
068827
+	sig_info->key_id = (const char *)key_id_str;
068827
+	sig_info->key_id_len = len;
068827
+
068827
+	issuer_str = x509_name_to_str(issuer);
068827
+	if (issuer_str != NULL) {
068827
+		sig_info->signer = issuer_str;
068827
+		sig_info->signer_len = strlen(issuer_str);
068827
+	}
068827
+
068827
+	X509_ALGOR_get0(&o, NULL, NULL, dig_alg);
068827
+
068827
+	sig_info->hash_algo = pkey_hash_algo[obj_to_hash_algo(o)];
068827
+	sig_info->id_type = pkey_id_type[modsig->id_type];
068827
+
068827
+	pvt = malloc(sizeof(*pvt));
068827
+	if (pvt == NULL)
068827
+		goto err3;
068827
+
068827
+	pvt->cms = cms;
068827
+	pvt->key_id = key_id_str;
068827
+	pvt->sno = sno_bn;
068827
+	sig_info->private = pvt;
068827
+
068827
+	sig_info->free = pkcs7_free;
068827
+
068827
+	return true;
068827
+err3:
068827
+	free(key_id_str);
068827
+err2:
068827
+	BN_free(sno_bn);
068827
+err:
068827
+	CMS_ContentInfo_free(cms);
068827
+	return false;
068827
+}
068827
+
068827
+#else /* ENABLE OPENSSL */
068827
+
068827
+static bool fill_pkcs7(const char *mem, off_t size,
068827
+		       const struct module_signature *modsig, size_t sig_len,
068827
+		       struct kmod_signature_info *sig_info)
068827
 {
068827
 	sig_info->hash_algo = "unknown";
068827
 	sig_info->id_type = pkey_id_type[modsig->id_type];
068827
 	return true;
068827
 }
068827
 
068827
+#endif /* ENABLE OPENSSL */
068827
+
068827
 #define SIG_MAGIC "~Module signature appended~\n"
068827
 
068827
 /*
068827
@@ -167,8 +350,14 @@ bool kmod_module_signature_info(const struct kmod_file *file, struct kmod_signat
068827
 
068827
 	switch (modsig->id_type) {
068827
 	case PKEY_ID_PKCS7:
068827
-		return fill_unknown(mem, size, modsig, sig_len, sig_info);
068827
+		return fill_pkcs7(mem, size, modsig, sig_len, sig_info);
068827
 	default:
068827
 		return fill_default(mem, size, modsig, sig_len, sig_info);
068827
 	}
068827
 }
068827
+
068827
+void kmod_module_signature_info_free(struct kmod_signature_info *sig_info)
068827
+{
068827
+	if (sig_info->free)
068827
+		sig_info->free(sig_info);
068827
+}
068827
-- 
068827
2.20.1
068827