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

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