Accepting request 584512 from home:michals

- Fix PKCS#7 signature display in modinfo (bsc#1077693).
   + libkmod-signature-implement-pkcs7-parsing-with-asn1c.patch
   + libkmod-signature-Fix-crash-when-module-signature-is.patch
   + refresh 0010-modprobe-Implement-allow-unsupported-modules.patch

OBS-URL: https://build.opensuse.org/request/show/584512
OBS-URL: https://build.opensuse.org/package/show/Base:System/kmod?expand=0&rev=137
This commit is contained in:
Jan Engelhardt 2018-03-09 08:51:45 +00:00 committed by Git OBS Bridge
parent 5bca0c1f94
commit 5208542099
7 changed files with 1187 additions and 19 deletions

View File

@ -1,23 +1,25 @@
From ea7f79db6890b99558adc9badd543e8ab59bc756 Mon Sep 17 00:00:00 2001 From 5ed5ab09ff7d4fb581aec3a35f2eff24eaa838f9 Mon Sep 17 00:00:00 2001
From: Michal Marek <mmarek@suse.cz> From: Michal Marek <mmarek@suse.cz>
Date: Wed, 5 Mar 2014 15:02:44 +0100 Date: Wed, 5 Mar 2014 15:02:44 +0100
Subject: [PATCH 4/5] modprobe: Implement --allow-unsupported-modules Subject: [PATCH] modprobe: Implement --allow-unsupported-modules
References: fate#316971 References: fate#316971
Patch-mainline: never Patch-mainline: never
--- ---
Makefile.am | 4 +++- Makefile.am | 4 +++-
libkmod/libkmod-unsupported.c | 9 +++++++++ libkmod/libkmod-unsupported.c | 9 +++++++++
libkmod/libkmod-unsupported.h | 8 ++++++++ libkmod/libkmod-unsupported.h | 8 ++++++++
tools/modprobe.c | 8 +++++++- tools/modprobe.c | 8 +++++++-
4 files changed, 27 insertions(+), 2 deletions(-) 4 files changed, 27 insertions(+), 2 deletions(-)
create mode 100644 libkmod/libkmod-unsupported.c create mode 100644 libkmod/libkmod-unsupported.c
create mode 100644 libkmod/libkmod-unsupported.h create mode 100644 libkmod/libkmod-unsupported.h
--- kmod-20.orig/Makefile.am diff --git a/Makefile.am b/Makefile.am
+++ kmod-20/Makefile.am index 26384ccd6de1..d9856f77f8f6 100644
@@ -87,7 +87,9 @@ libkmod_libkmod_la_LIBADD = \ --- a/Makefile.am
${liblzma_LIBS} ${zlib_LIBS} +++ b/Makefile.am
@@ -106,7 +106,9 @@ libkmod_libkmod_la_LIBADD = \
${libpkcs7asn1c_LIBS}
noinst_LTLIBRARIES += libkmod/libkmod-internal.la noinst_LTLIBRARIES += libkmod/libkmod-internal.la
-libkmod_libkmod_internal_la_SOURCES = $(libkmod_libkmod_la_SOURCES) -libkmod_libkmod_internal_la_SOURCES = $(libkmod_libkmod_la_SOURCES)
@ -27,8 +29,11 @@ Patch-mainline: never
libkmod_libkmod_internal_la_LDFLAGS = $(AM_LDFLAGS) \ libkmod_libkmod_internal_la_LDFLAGS = $(AM_LDFLAGS) \
-Wl,--version-script=$(top_srcdir)/libkmod/libkmod.sym -Wl,--version-script=$(top_srcdir)/libkmod/libkmod.sym
libkmod_libkmod_internal_la_DEPENDENCIES = $(libkmod_libkmod_la_DEPENDENCIES) libkmod_libkmod_internal_la_DEPENDENCIES = $(libkmod_libkmod_la_DEPENDENCIES)
diff --git a/libkmod/libkmod-unsupported.c b/libkmod/libkmod-unsupported.c
new file mode 100644
index 000000000000..7ef9fc875b46
--- /dev/null --- /dev/null
+++ kmod-20/libkmod/libkmod-unsupported.c +++ b/libkmod/libkmod-unsupported.c
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
+#include "libkmod-internal.h" +#include "libkmod-internal.h"
+#include "libkmod-unsupported.h" +#include "libkmod-unsupported.h"
@ -39,8 +44,11 @@ Patch-mainline: never
+ +
+ config->block_unsupported = 0; + config->block_unsupported = 0;
+} +}
diff --git a/libkmod/libkmod-unsupported.h b/libkmod/libkmod-unsupported.h
new file mode 100644
index 000000000000..a95b4a22fd14
--- /dev/null --- /dev/null
+++ kmod-20/libkmod/libkmod-unsupported.h +++ b/libkmod/libkmod-unsupported.h
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
+#pragma once +#pragma once
+ +
@ -50,8 +58,10 @@ Patch-mainline: never
+ * library + * library
+ */ + */
+void kmod_internal_allow_unsupported(struct kmod_ctx *ctx); +void kmod_internal_allow_unsupported(struct kmod_ctx *ctx);
--- kmod-20.orig/tools/modprobe.c diff --git a/tools/modprobe.c b/tools/modprobe.c
+++ kmod-20/tools/modprobe.c index c0b7c6854375..1f6f28666183 100644
--- a/tools/modprobe.c
+++ b/tools/modprobe.c
@@ -38,6 +38,8 @@ @@ -38,6 +38,8 @@
#include "kmod.h" #include "kmod.h"
@ -61,7 +71,7 @@ Patch-mainline: never
static int log_priority = LOG_CRIT; static int log_priority = LOG_CRIT;
static int use_syslog = 0; static int use_syslog = 0;
#define LOG(...) log_printf(log_priority, __VA_ARGS__) #define LOG(...) log_printf(log_priority, __VA_ARGS__)
@@ -730,6 +732,7 @@ static int do_modprobe(int argc, char ** @@ -729,6 +731,7 @@ static int do_modprobe(int argc, char **orig_argv)
int do_remove = 0; int do_remove = 0;
int do_show_config = 0; int do_show_config = 0;
int do_show_modversions = 0; int do_show_modversions = 0;
@ -69,7 +79,7 @@ Patch-mainline: never
int err; int err;
argv = prepend_options_from_env(&argc, orig_argv); argv = prepend_options_from_env(&argc, orig_argv);
@@ -813,7 +816,7 @@ static int do_modprobe(int argc, char ** @@ -812,7 +815,7 @@ static int do_modprobe(int argc, char **orig_argv)
kversion = optarg; kversion = optarg;
break; break;
case 128: case 128:
@ -78,7 +88,7 @@ Patch-mainline: never
break; break;
case 's': case 's':
env_modprobe_options_append("-s"); env_modprobe_options_append("-s");
@@ -885,6 +888,9 @@ static int do_modprobe(int argc, char ** @@ -885,6 +888,9 @@ static int do_modprobe(int argc, char **orig_argv)
log_setup_kmod_log(ctx, verbose); log_setup_kmod_log(ctx, verbose);
@ -88,3 +98,6 @@ Patch-mainline: never
kmod_load_resources(ctx); kmod_load_resources(ctx);
if (do_show_config) if (do_show_config)
--
2.13.6

View File

@ -1,3 +1,11 @@
-------------------------------------------------------------------
Thu Mar 8 16:34:16 UTC 2018 - msuchanek@suse.com
- Fix PKCS#7 signature display in modinfo (bsc#1077693).
+ libkmod-signature-implement-pkcs7-parsing-with-asn1c.patch
+ libkmod-signature-Fix-crash-when-module-signature-is.patch
+ refresh 0010-modprobe-Implement-allow-unsupported-modules.patch
------------------------------------------------------------------- -------------------------------------------------------------------
Thu Feb 1 13:49:25 UTC 2018 - msuchanek@suse.com Thu Feb 1 13:49:25 UTC 2018 - msuchanek@suse.com

View File

@ -30,12 +30,15 @@ Url: http://www.jonmasters.org/blog/2011/12/20/libkmod-replaces-modul
#Git-Clone: git://git.kernel.org/pub/scm/utils/kernel/kmod/kmod #Git-Clone: git://git.kernel.org/pub/scm/utils/kernel/kmod/kmod
Source: https://www.kernel.org/pub/linux/utils/kernel/kmod/kmod-%version.tar.xz Source: https://www.kernel.org/pub/linux/utils/kernel/kmod/kmod-%version.tar.xz
Source2: https://www.kernel.org/pub/linux/utils/kernel/kmod/kmod-%version.tar.sign Source2: https://www.kernel.org/pub/linux/utils/kernel/kmod/kmod-%version.tar.sign
Patch0: libkmod-signature-implement-pkcs7-parsing-with-asn1c.patch
Patch1: 0002-modprobe-Recognize-allow-unsupported-modules-on-comm.patch Patch1: 0002-modprobe-Recognize-allow-unsupported-modules-on-comm.patch
Patch2: 0003-libkmod-config-Recognize-allow_unsupported_modules-i.patch Patch2: 0003-libkmod-config-Recognize-allow_unsupported_modules-i.patch
Patch3: 0009-libkmod-Implement-filtering-of-unsupported-modules-o.patch Patch3: 0009-libkmod-Implement-filtering-of-unsupported-modules-o.patch
Patch4: 0010-modprobe-Implement-allow-unsupported-modules.patch Patch4: 0010-modprobe-Implement-allow-unsupported-modules.patch
Patch5: 0011-Do-not-filter-unsupported-modules-when-running-a-van.patch Patch5: 0011-Do-not-filter-unsupported-modules-when-running-a-van.patch
Patch6: libkmod-signature-Fix-crash-when-module-signature-is.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRoot: %{_tmppath}/%{name}-%{version}-build
BuildRequires: asn1c
BuildRequires: autoconf BuildRequires: autoconf
BuildRequires: automake BuildRequires: automake
BuildRequires: git-core BuildRequires: git-core
@ -55,7 +58,7 @@ buildloop with the kernel.
%prep %prep
%setup -q -n kmod-%version %setup -q -n kmod-%version
%patch -P 1 -P 2 -P 3 -P 4 -P 5 -p1 %patch -P 0 -P 1 -P 2 -P 3 -P 4 -P 5 -P 6 -p1
%build %build
autoreconf -fi autoreconf -fi
@ -68,6 +71,7 @@ export LDFLAGS="-Wl,-z,relro,-z,now"
--includedir="%_includedir/kmod" \ --includedir="%_includedir/kmod" \
--with-rootlibdir="%_libdir" \ --with-rootlibdir="%_libdir" \
--bindir="%_bindir" --bindir="%_bindir"
make -C libkmod/pkcs7/asn1c-gen regen
make %{?_smp_mflags} V=1 KDIR="%kdir" make %{?_smp_mflags} V=1 KDIR="%kdir"
%install %install

View File

@ -1,3 +1,11 @@
-------------------------------------------------------------------
Thu Mar 8 16:34:16 UTC 2018 - msuchanek@suse.com
- Fix PKCS#7 signature display in modinfo (bsc#1077693).
+ libkmod-signature-implement-pkcs7-parsing-with-asn1c.patch
+ libkmod-signature-Fix-crash-when-module-signature-is.patch
+ refresh 0010-modprobe-Implement-allow-unsupported-modules.patch
------------------------------------------------------------------- -------------------------------------------------------------------
Thu Feb 1 13:49:25 UTC 2018 - msuchanek@suse.com Thu Feb 1 13:49:25 UTC 2018 - msuchanek@suse.com

View File

@ -29,12 +29,15 @@ Url: https://www.kernel.org/pub/linux/utils/kernel/kmod/
#Git-Clone: git://git.kernel.org/pub/scm/utils/kernel/kmod/kmod #Git-Clone: git://git.kernel.org/pub/scm/utils/kernel/kmod/kmod
Source: https://www.kernel.org/pub/linux/utils/kernel/kmod/kmod-%version.tar.xz Source: https://www.kernel.org/pub/linux/utils/kernel/kmod/kmod-%version.tar.xz
Source2: https://www.kernel.org/pub/linux/utils/kernel/kmod/kmod-%version.tar.sign Source2: https://www.kernel.org/pub/linux/utils/kernel/kmod/kmod-%version.tar.sign
Patch0: libkmod-signature-implement-pkcs7-parsing-with-asn1c.patch
Patch1: 0002-modprobe-Recognize-allow-unsupported-modules-on-comm.patch Patch1: 0002-modprobe-Recognize-allow-unsupported-modules-on-comm.patch
Patch2: 0003-libkmod-config-Recognize-allow_unsupported_modules-i.patch Patch2: 0003-libkmod-config-Recognize-allow_unsupported_modules-i.patch
Patch3: 0009-libkmod-Implement-filtering-of-unsupported-modules-o.patch Patch3: 0009-libkmod-Implement-filtering-of-unsupported-modules-o.patch
Patch4: 0010-modprobe-Implement-allow-unsupported-modules.patch Patch4: 0010-modprobe-Implement-allow-unsupported-modules.patch
Patch5: 0011-Do-not-filter-unsupported-modules-when-running-a-van.patch Patch5: 0011-Do-not-filter-unsupported-modules-when-running-a-van.patch
Patch6: libkmod-signature-Fix-crash-when-module-signature-is.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRoot: %{_tmppath}/%{name}-%{version}-build
BuildRequires: asn1c
BuildRequires: autoconf BuildRequires: autoconf
BuildRequires: automake BuildRequires: automake
BuildRequires: libtool BuildRequires: libtool
@ -105,7 +108,7 @@ in %lname.
%prep %prep
%setup -q -n kmod-%version %setup -q -n kmod-%version
%patch -P 1 -P 2 -P 3 -P 4 -P 5 -p1 %patch -P 0 -P 1 -P 2 -P 3 -P 4 -P 5 -P 6 -p1
%build %build
autoreconf -fi autoreconf -fi
@ -118,6 +121,7 @@ export LDFLAGS="-Wl,-z,relro,-z,now"
--includedir="%_includedir/kmod" \ --includedir="%_includedir/kmod" \
--with-rootlibdir="%_libdir" \ --with-rootlibdir="%_libdir" \
--bindir="%_bindir" --bindir="%_bindir"
make -C libkmod/pkcs7/asn1c-gen regen
make %{?_smp_mflags} V=1 make %{?_smp_mflags} V=1
%install %install

View File

@ -0,0 +1,235 @@
From 5336a1d1c0815da3e3b9e57f2ca9d04de3bc65dc Mon Sep 17 00:00:00 2001
From: Michal Suchanek <msuchanek@suse.de>
Date: Thu, 8 Mar 2018 18:30:46 +0100
Subject: [PATCH] libkmod-signature: Fix crash when module signature is not
present.
Signed-off-by: Michal Suchanek <msuchanek@suse.de>
---
libkmod/libkmod-internal.h | 2 +-
libkmod/libkmod-module.c | 21 +++++++++---------
libkmod/libkmod-signature.c | 53 +++++++++++++++++++++++++--------------------
3 files changed, 42 insertions(+), 34 deletions(-)
diff --git a/libkmod/libkmod-internal.h b/libkmod/libkmod-internal.h
index 2ad74c7a33a5..8bc9ecfb906e 100644
--- a/libkmod/libkmod-internal.h
+++ b/libkmod/libkmod-internal.h
@@ -192,5 +192,5 @@ struct kmod_signature_info {
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)));
+struct kmod_signature_info *kmod_module_signature_info(const struct kmod_file *file) _must_check_ __attribute__((nonnull(1)));
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 7b00d526edec..cbe35819932e 100644
--- a/libkmod/libkmod-module.c
+++ b/libkmod/libkmod-module.c
@@ -2304,7 +2304,7 @@ KMOD_EXPORT int kmod_module_get_info(const struct kmod_module *mod, struct kmod_
struct kmod_elf *elf;
char **strings;
int i, count, ret = -ENOMEM;
- struct kmod_signature_info sig_info;
+ struct kmod_signature_info *sig_info = NULL;
if (mod == NULL || list == NULL)
return -ENOENT;
@@ -2341,32 +2341,32 @@ KMOD_EXPORT int kmod_module_get_info(const struct kmod_module *mod, struct kmod_
goto list_error;
}
- if (kmod_module_signature_info(mod->file, &sig_info)) {
+ if (sig_info = kmod_module_signature_info(mod->file)) {
struct kmod_list *n;
n = kmod_module_info_append(list, "sig_id", strlen("sig_id"),
- sig_info.id_type, strlen(sig_info.id_type));
+ sig_info->id_type, strlen(sig_info->id_type));
if (n == NULL)
goto list_error;
count++;
n = kmod_module_info_append(list, "signer", strlen("signer"),
- sig_info.signer, sig_info.signer_len);
+ sig_info->signer, sig_info->signer_len);
if (n == NULL)
goto list_error;
count++;
n = kmod_module_info_append_hex(list, "sig_key", strlen("sig_key"),
- sig_info.key_id,
- sig_info.key_id_len);
+ sig_info->key_id,
+ sig_info->key_id_len);
if (n == NULL)
goto list_error;
count++;
n = kmod_module_info_append(list,
"sig_hashalgo", strlen("sig_hashalgo"),
- sig_info.hash_algo, strlen(sig_info.hash_algo));
+ sig_info->hash_algo, strlen(sig_info->hash_algo));
if (n == NULL)
goto list_error;
count++;
@@ -2377,8 +2377,8 @@ KMOD_EXPORT int kmod_module_get_info(const struct kmod_module *mod, struct kmod_
*/
n = kmod_module_info_append_hex(list, "signature",
strlen("signature"),
- sig_info.sig,
- sig_info.sig_len);
+ sig_info->sig,
+ sig_info->sig_len);
if (n == NULL)
goto list_error;
@@ -2389,7 +2389,8 @@ KMOD_EXPORT int kmod_module_get_info(const struct kmod_module *mod, struct kmod_
list_error:
/* aux structures freed in normal case also */
- kmod_module_signature_info_free(&sig_info);
+ if (sig_info)
+ kmod_module_signature_info_free(sig_info);
if (ret < 0) {
kmod_module_info_free_list(*list);
diff --git a/libkmod/libkmod-signature.c b/libkmod/libkmod-signature.c
index bdf84cb14718..fae074e6dd1d 100644
--- a/libkmod/libkmod-signature.c
+++ b/libkmod/libkmod-signature.c
@@ -93,13 +93,17 @@ struct module_signature {
uint32_t sig_len; /* Length of signature data (big endian) */
};
-static bool
+static struct kmod_signature_info *
kmod_module_signature_info_default(const char *mem,
off_t size,
const struct module_signature *modsig,
- size_t sig_len,
- struct kmod_signature_info *sig_info)
+ size_t sig_len)
{
+ struct kmod_signature_info *sig_info = malloc(sizeof *sig_info);
+
+ if (!sig_info)
+ return NULL;
+
size -= sig_len;
sig_info->sig = mem + size;
sig_info->sig_len = sig_len;
@@ -119,7 +123,7 @@ kmod_module_signature_info_default(const char *mem,
sig_info->free = NULL;
sig_info->private = NULL;
- return true;
+ return sig_info;
}
static void kmod_module_signature_info_pkcs7_free(void *s)
@@ -129,13 +133,13 @@ static void kmod_module_signature_info_pkcs7_free(void *s)
pkcs7_free_cert(si->private);
}
-static bool
+static struct kmod_signature_info *
kmod_module_signature_info_pkcs7(const char *mem,
off_t size,
const struct module_signature *modsig,
- size_t sig_len,
- struct kmod_signature_info *sig_info)
+ size_t sig_len)
{
+ struct kmod_signature_info *sig_info = NULL;
const char *pkcs7_raw;
struct pkcs7_cert *cert;
@@ -144,7 +148,13 @@ kmod_module_signature_info_pkcs7(const char *mem,
cert = pkcs7_parse_cert(pkcs7_raw, sig_len);
if (cert == NULL)
- return false;
+ return NULL;
+
+ sig_info = malloc(sizeof *sig_info);
+ if (!sig_info) {
+ free(cert);
+ return NULL;
+ }
sig_info->private = cert;
sig_info->free = kmod_module_signature_info_pkcs7_free;
@@ -162,7 +172,7 @@ kmod_module_signature_info_pkcs7(const char *mem,
sig_info->hash_algo = cert->hash_algo;
sig_info->id_type = pkey_id_type[modsig->id_type];
- return true;
+ return sig_info;
}
#define SIG_MAGIC "~Module signature appended~\n"
@@ -178,48 +188,45 @@ kmod_module_signature_info_pkcs7(const char *mem,
* [ SIG_MAGIC ]
*/
-bool kmod_module_signature_info(const struct kmod_file *file, struct kmod_signature_info *sig_info)
+struct kmod_signature_info *kmod_module_signature_info(const struct kmod_file *file)
{
const char *mem;
off_t size;
const struct module_signature *modsig;
size_t sig_len;
- bool ret;
size = kmod_file_get_size(file);
mem = kmod_file_get_contents(file);
if (size < (off_t)strlen(SIG_MAGIC))
- return false;
+ return NULL;
size -= strlen(SIG_MAGIC);
if (memcmp(SIG_MAGIC, mem + size, strlen(SIG_MAGIC)) != 0)
- return false;
+ return NULL;
if (size < (off_t)sizeof(struct module_signature))
- return false;
+ return NULL;
size -= sizeof(struct module_signature);
modsig = (struct module_signature *)(mem + size);
if (modsig->algo >= PKEY_ALGO__LAST ||
modsig->hash >= PKEY_HASH__LAST ||
modsig->id_type >= PKEY_ID_TYPE__LAST)
- return false;
+ return NULL;
sig_len = be32toh(get_unaligned(&modsig->sig_len));
if (sig_len == 0 ||
size < (int64_t)(modsig->signer_len + modsig->key_id_len + sig_len))
- return false;
+ return NULL;
if (modsig->id_type == PKEY_ID_PKCS7)
- ret = kmod_module_signature_info_pkcs7(mem, size,
- modsig, sig_len,
- sig_info);
+ return kmod_module_signature_info_pkcs7(mem, size,
+ modsig, sig_len);
else
- ret = kmod_module_signature_info_default(mem, size,
- modsig, sig_len,
- sig_info);
- return ret;
+ return kmod_module_signature_info_default(mem, size,
+ modsig, sig_len);
}
void kmod_module_signature_info_free(struct kmod_signature_info *sig_info)
{
if (sig_info->free)
sig_info->free(sig_info);
+ free(sig_info);
}
--
2.13.6

View File

@ -0,0 +1,896 @@
From: Yauheni Kaliuta <yauheni.kaliuta@redhat.com>
Subject: [PATCH RFC PKCS7 asn1c 1/2] libkmod-signature: implement pkcs7 parsing with asn1c compiler
Date: Thu, 8 Mar 2018 15:58:09 +0200
The patch adds pkcs7.asn1 description, taken from the linux kernel
and modified to be suitable for the asn1c compiler and a wrapper on
the asn1c's parser to make it more suitable for kmod.
Since kmod (modinfo) supports only one signature at the moment, the
wrapper ignores others and it also analyzes object IDs only for
hashing algorithms.
To compile the stuff you need to have asn1c installed, finish
./configure and invoke
make -C libkmod/pkcs7/asn1c-gen regen
to generate the parser.
Signed-off-by: Yauheni Kaliuta <yauheni.kaliuta@redhat.com>
---
Makefile.am | 22 ++-
configure.ac | 1 +
libkmod/libkmod-internal.h | 3 +
libkmod/libkmod-module.c | 3 +
libkmod/libkmod-signature.c | 105 ++++++++++---
libkmod/pkcs7/asn1c-gen/Makefile.am | 131 ++++++++++++++++
libkmod/pkcs7/pkcs7.asn1 | 135 ++++++++++++++++
libkmod/pkcs7/pkcs7_parser.c | 297 ++++++++++++++++++++++++++++++++++++
libkmod/pkcs7/pkcs7_parser.h | 42 +++++
9 files changed, 719 insertions(+), 20 deletions(-)
create mode 100644 libkmod/pkcs7/asn1c-gen/Makefile.am
create mode 100644 libkmod/pkcs7/pkcs7.asn1
create mode 100644 libkmod/pkcs7/pkcs7_parser.c
create mode 100644 libkmod/pkcs7/pkcs7_parser.h
diff --git a/Makefile.am b/Makefile.am
index 194e1115ae70..26384ccd6de1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = . libkmod/docs
+SUBDIRS = . libkmod/docs libkmod/pkcs7/asn1c-gen
if BUILD_MANPAGES
SUBDIRS += man
@@ -62,6 +62,13 @@ shared_libshared_la_SOURCES = \
include_HEADERS = libkmod/libkmod.h
lib_LTLIBRARIES = libkmod/libkmod.la
+
+PKCS7_SRCS = \
+ libkmod/pkcs7/pkcs7_parser.c \
+ libkmod/pkcs7/pkcs7_parser.h
+
+AM_CPPFLAGS += -Ilibkmod/pkcs7/asn1c-gen -D_DEFAULT_SOURCE
+
libkmod_libkmod_la_SOURCES = \
libkmod/libkmod.h \
libkmod/libkmod-internal.h \
@@ -73,7 +80,14 @@ libkmod_libkmod_la_SOURCES = \
libkmod/libkmod-module.c \
libkmod/libkmod-file.c \
libkmod/libkmod-elf.c \
- libkmod/libkmod-signature.c
+ libkmod/libkmod-signature.c \
+ $(PKCS7_SRCS)
+
+libpkcs7asn1c = libkmod/pkcs7/asn1c-gen/libpkcs7asn1c.la
+libpkcs7asn1c_LIBS = ${libpkcs7asn1c}
+
+${libpkcs7asn1c}:
+ ${MAKE} -C libkmod/pkcs7/asn1c-gen
EXTRA_DIST += libkmod/libkmod.sym
EXTRA_DIST += libkmod/README \
@@ -84,10 +98,12 @@ libkmod_libkmod_la_LDFLAGS = $(AM_LDFLAGS) \
-Wl,--version-script=$(top_srcdir)/libkmod/libkmod.sym
libkmod_libkmod_la_DEPENDENCIES = \
shared/libshared.la \
+ ${libpkcs7asn1c} \
${top_srcdir}/libkmod/libkmod.sym
libkmod_libkmod_la_LIBADD = \
shared/libshared.la \
- ${liblzma_LIBS} ${zlib_LIBS}
+ ${liblzma_LIBS} ${zlib_LIBS} \
+ ${libpkcs7asn1c_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..0d5f83a45778 100644
--- a/configure.ac
+++ b/configure.ac
@@ -271,6 +271,7 @@ AC_CONFIG_FILES([
man/Makefile
libkmod/docs/Makefile
libkmod/docs/version.xml
+ libkmod/pkcs7/asn1c-gen/Makefile
])
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 0a3ef11c860f..b5cee437ae0e 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 1f3e26dea203..bdf84cb14718 100644
--- a/libkmod/libkmod-signature.c
+++ b/libkmod/libkmod-signature.c
@@ -26,6 +26,7 @@
#include <shared/missing.h>
#include <shared/util.h>
+#include "pkcs7/pkcs7_parser.h"
#include "libkmod-internal.h"
/* These types and tables were copied from the 3.7 kernel sources.
@@ -92,6 +93,78 @@ struct module_signature {
uint32_t sig_len; /* Length of signature data (big endian) */
};
+static bool
+kmod_module_signature_info_default(const char *mem,
+ off_t size,
+ const struct module_signature *modsig,
+ size_t sig_len,
+ struct kmod_signature_info *sig_info)
+{
+ size -= sig_len;
+ sig_info->sig = mem + size;
+ sig_info->sig_len = sig_len;
+
+ size -= modsig->key_id_len;
+ sig_info->key_id = mem + size;
+ sig_info->key_id_len = modsig->key_id_len;
+
+ size -= modsig->signer_len;
+ sig_info->signer = mem + size;
+ sig_info->signer_len = modsig->signer_len;
+
+ sig_info->algo = pkey_algo[modsig->algo];
+ sig_info->hash_algo = pkey_hash_algo[modsig->hash];
+ sig_info->id_type = pkey_id_type[modsig->id_type];
+
+ sig_info->free = NULL;
+ sig_info->private = NULL;
+
+ return true;
+}
+
+static void kmod_module_signature_info_pkcs7_free(void *s)
+{
+ struct kmod_signature_info *si = s;
+
+ pkcs7_free_cert(si->private);
+}
+
+static bool
+kmod_module_signature_info_pkcs7(const char *mem,
+ off_t size,
+ const struct module_signature *modsig,
+ size_t sig_len,
+ struct kmod_signature_info *sig_info)
+{
+ const char *pkcs7_raw;
+ struct pkcs7_cert *cert;
+
+ size -= sig_len;
+ pkcs7_raw = mem + size;
+
+ cert = pkcs7_parse_cert(pkcs7_raw, sig_len);
+ if (cert == NULL)
+ return false;
+
+ sig_info->private = cert;
+ sig_info->free = kmod_module_signature_info_pkcs7_free;
+
+ sig_info->sig = (const char *)cert->signature;
+ sig_info->sig_len = cert->signature_size;
+
+ sig_info->key_id = (const char *)cert->key_id;
+ sig_info->key_id_len = cert->key_id_size;
+
+ sig_info->signer = cert->signer;
+ sig_info->signer_len = strlen(cert->signer);
+
+ sig_info->algo = NULL;
+ sig_info->hash_algo = cert->hash_algo;
+ sig_info->id_type = pkey_id_type[modsig->id_type];
+
+ return true;
+}
+
#define SIG_MAGIC "~Module signature appended~\n"
/*
@@ -111,7 +184,7 @@ bool kmod_module_signature_info(const struct kmod_file *file, struct kmod_signat
off_t size;
const struct module_signature *modsig;
size_t sig_len;
-
+ bool ret;
size = kmod_file_get_size(file);
mem = kmod_file_get_contents(file);
@@ -134,21 +207,19 @@ bool kmod_module_signature_info(const struct kmod_file *file, struct kmod_signat
size < (int64_t)(modsig->signer_len + modsig->key_id_len + sig_len))
return false;
- size -= sig_len;
- sig_info->sig = mem + size;
- sig_info->sig_len = sig_len;
-
- size -= modsig->key_id_len;
- sig_info->key_id = mem + size;
- sig_info->key_id_len = modsig->key_id_len;
-
- size -= modsig->signer_len;
- sig_info->signer = mem + size;
- sig_info->signer_len = modsig->signer_len;
-
- sig_info->algo = pkey_algo[modsig->algo];
- sig_info->hash_algo = pkey_hash_algo[modsig->hash];
- sig_info->id_type = pkey_id_type[modsig->id_type];
+ if (modsig->id_type == PKEY_ID_PKCS7)
+ ret = kmod_module_signature_info_pkcs7(mem, size,
+ modsig, sig_len,
+ sig_info);
+ else
+ ret = kmod_module_signature_info_default(mem, size,
+ modsig, sig_len,
+ sig_info);
+ return ret;
+}
- return true;
+void kmod_module_signature_info_free(struct kmod_signature_info *sig_info)
+{
+ if (sig_info->free)
+ sig_info->free(sig_info);
}
diff --git a/libkmod/pkcs7/asn1c-gen/Makefile.am b/libkmod/pkcs7/asn1c-gen/Makefile.am
new file mode 100644
index 000000000000..b9b613003039
--- /dev/null
+++ b/libkmod/pkcs7/asn1c-gen/Makefile.am
@@ -0,0 +1,131 @@
+ASN_MODULE_SOURCES= \
+ PKCS7ContentInfo.c \
+ ContentType.c \
+ SignedData.c \
+ ContentInfo.c \
+ Data.c \
+ DigestAlgorithmIdentifiers.c \
+ DigestAlgorithmIdentifier.c \
+ ExtendedCertificatesAndCertificates.c \
+ Certificates.c \
+ CertificateRevocationLists.c \
+ CertificateList.c \
+ CRLSequence.c \
+ Certificate.c \
+ SignerInfos.c \
+ SignerInfo.c \
+ SignerIdentifier.c \
+ IssuerAndSerialNumber.c \
+ CertificateSerialNumber.c \
+ SubjectKeyIdentifier.c \
+ SetOfAuthenticatedAttribute.c \
+ Values.c \
+ AuthenticatedAttribute.c \
+ UnauthenticatedAttribute.c \
+ DigestEncryptionAlgorithmIdentifier.c \
+ EncryptedDigest.c \
+ Name.c \
+ RelativeDistinguishedName.c \
+ AttributeValueAssertion.c
+
+ASN_MODULE_HEADERS= \
+ PKCS7ContentInfo.h \
+ ContentType.h \
+ SignedData.h \
+ ContentInfo.h \
+ Data.h \
+ DigestAlgorithmIdentifiers.h \
+ DigestAlgorithmIdentifier.h \
+ ExtendedCertificatesAndCertificates.h \
+ Certificates.h \
+ CertificateRevocationLists.h \
+ CertificateList.h \
+ CRLSequence.h \
+ Certificate.h \
+ SignerInfos.h \
+ SignerInfo.h \
+ SignerIdentifier.h \
+ IssuerAndSerialNumber.h \
+ CertificateSerialNumber.h \
+ SubjectKeyIdentifier.h \
+ SetOfAuthenticatedAttribute.h \
+ Values.h \
+ AuthenticatedAttribute.h \
+ UnauthenticatedAttribute.h \
+ DigestEncryptionAlgorithmIdentifier.h \
+ EncryptedDigest.h \
+ Name.h \
+ RelativeDistinguishedName.h \
+ AttributeValueAssertion.h
+
+ASN_MODULE_HEADERS+=ANY.h
+ASN_MODULE_SOURCES+=ANY.c
+ASN_MODULE_HEADERS+=INTEGER.h
+ASN_MODULE_HEADERS+=NativeEnumerated.h
+ASN_MODULE_SOURCES+=INTEGER.c
+ASN_MODULE_SOURCES+=NativeEnumerated.c
+ASN_MODULE_HEADERS+=NativeInteger.h
+ASN_MODULE_SOURCES+=NativeInteger.c
+ASN_MODULE_HEADERS+=OBJECT_IDENTIFIER.h
+ASN_MODULE_SOURCES+=OBJECT_IDENTIFIER.c
+ASN_MODULE_HEADERS+=asn_SEQUENCE_OF.h
+ASN_MODULE_SOURCES+=asn_SEQUENCE_OF.c
+ASN_MODULE_HEADERS+=asn_SET_OF.h
+ASN_MODULE_SOURCES+=asn_SET_OF.c
+ASN_MODULE_HEADERS+=constr_CHOICE.h
+ASN_MODULE_SOURCES+=constr_CHOICE.c
+ASN_MODULE_HEADERS+=constr_SEQUENCE.h
+ASN_MODULE_SOURCES+=constr_SEQUENCE.c
+ASN_MODULE_HEADERS+=constr_SEQUENCE_OF.h
+ASN_MODULE_SOURCES+=constr_SEQUENCE_OF.c
+ASN_MODULE_HEADERS+=constr_SET_OF.h
+ASN_MODULE_SOURCES+=constr_SET_OF.c
+ASN_MODULE_HEADERS+=asn_application.h
+ASN_MODULE_HEADERS+=asn_system.h
+ASN_MODULE_HEADERS+=asn_codecs.h
+ASN_MODULE_HEADERS+=asn_internal.h
+ASN_MODULE_HEADERS+=OCTET_STRING.h
+ASN_MODULE_SOURCES+=OCTET_STRING.c
+ASN_MODULE_HEADERS+=BIT_STRING.h
+ASN_MODULE_SOURCES+=BIT_STRING.c
+ASN_MODULE_SOURCES+=asn_codecs_prim.c
+ASN_MODULE_HEADERS+=asn_codecs_prim.h
+ASN_MODULE_HEADERS+=ber_tlv_length.h
+ASN_MODULE_SOURCES+=ber_tlv_length.c
+ASN_MODULE_HEADERS+=ber_tlv_tag.h
+ASN_MODULE_SOURCES+=ber_tlv_tag.c
+ASN_MODULE_HEADERS+=ber_decoder.h
+ASN_MODULE_SOURCES+=ber_decoder.c
+ASN_MODULE_HEADERS+=der_encoder.h
+ASN_MODULE_SOURCES+=der_encoder.c
+ASN_MODULE_HEADERS+=constr_TYPE.h
+ASN_MODULE_SOURCES+=constr_TYPE.c
+ASN_MODULE_HEADERS+=constraints.h
+ASN_MODULE_SOURCES+=constraints.c
+ASN_MODULE_HEADERS+=xer_support.h
+ASN_MODULE_SOURCES+=xer_support.c
+ASN_MODULE_HEADERS+=xer_decoder.h
+ASN_MODULE_SOURCES+=xer_decoder.c
+ASN_MODULE_HEADERS+=xer_encoder.h
+ASN_MODULE_SOURCES+=xer_encoder.c
+ASN_MODULE_HEADERS+=per_support.h
+ASN_MODULE_SOURCES+=per_support.c
+ASN_MODULE_HEADERS+=per_decoder.h
+ASN_MODULE_SOURCES+=per_decoder.c
+ASN_MODULE_HEADERS+=per_encoder.h
+ASN_MODULE_SOURCES+=per_encoder.c
+ASN_MODULE_HEADERS+=per_opentype.h
+ASN_MODULE_SOURCES+=per_opentype.c
+
+ASN_MODULEdir = .
+
+noinst_LTLIBRARIES=libpkcs7asn1c.la
+libpkcs7asn1c_la_SOURCES=$(ASN_MODULE_SOURCES) $(ASN_MODULE_HEADERS)
+
+AM_CPPFLAGS = -DEMIT_ASN_DEBUG=0 -D_DEFAULT_SOURCE
+
+regen: regenerate-from-asn1-source
+
+regenerate-from-asn1-source:
+ asn1c -fwide-types ../pkcs7.asn1
+
diff --git a/libkmod/pkcs7/pkcs7.asn1 b/libkmod/pkcs7/pkcs7.asn1
new file mode 100644
index 000000000000..c7d59c2bb4ab
--- /dev/null
+++ b/libkmod/pkcs7/pkcs7.asn1
@@ -0,0 +1,135 @@
+PKCS7 DEFINITIONS ::=
+BEGIN
+
+PKCS7ContentInfo ::= SEQUENCE {
+ contentType ContentType,
+ content [0] EXPLICIT SignedData OPTIONAL
+}
+
+ContentType ::= OBJECT IDENTIFIER
+
+SignedData ::= SEQUENCE {
+ version INTEGER,
+ digestAlgorithms DigestAlgorithmIdentifiers,
+ contentInfo ContentInfo,
+ certificates CHOICE {
+ certSet [0] IMPLICIT ExtendedCertificatesAndCertificates,
+ certSequence [2] IMPLICIT Certificates
+ } OPTIONAL,
+ crls CHOICE {
+ crlSet [1] IMPLICIT CertificateRevocationLists,
+ crlSequence [3] IMPLICIT CRLSequence
+ } OPTIONAL,
+ signerInfos SignerInfos
+}
+
+ContentInfo ::= SEQUENCE {
+ contentType ContentType,
+ content [0] EXPLICIT Data OPTIONAL
+}
+
+Data ::= ANY
+
+DigestAlgorithmIdentifiers ::= CHOICE {
+ daSet SET OF DigestAlgorithmIdentifier,
+ daSequence SEQUENCE OF DigestAlgorithmIdentifier
+}
+
+DigestAlgorithmIdentifier ::= SEQUENCE {
+ algorithm OBJECT IDENTIFIER,
+ parameters ANY OPTIONAL
+}
+
+--
+-- Certificates and certificate lists
+--
+ExtendedCertificatesAndCertificates ::= SET OF Certificate
+
+Certificates ::= SEQUENCE OF Certificate
+
+CertificateRevocationLists ::= SET OF CertificateList
+
+CertificateList ::= SEQUENCE OF Certificate -- This may be defined incorrectly
+
+CRLSequence ::= SEQUENCE OF CertificateList
+
+Certificate ::= ANY -- X.509, Skip
+
+--
+-- Signer information
+--
+SignerInfos ::= CHOICE {
+ siSet SET OF SignerInfo,
+ siSequence SEQUENCE OF SignerInfo
+}
+
+SignerInfo ::= SEQUENCE {
+ version INTEGER,
+ sid SignerIdentifier, -- CMS variant, not PKCS#7
+ digestAlgorithm DigestAlgorithmIdentifier,
+ authenticatedAttributes CHOICE {
+ aaSet [0] IMPLICIT SetOfAuthenticatedAttribute,
+ aaSequence [2] EXPLICIT SEQUENCE OF AuthenticatedAttribute
+ -- Explicit because easier to compute digest on
+ -- sequence of attributes and then reuse encoded
+ -- sequence in aaSequence.
+ } OPTIONAL,
+ digestEncryptionAlgorithm
+ DigestEncryptionAlgorithmIdentifier,
+ encryptedDigest EncryptedDigest,
+ unauthenticatedAttributes CHOICE {
+ uaSet [1] IMPLICIT SET OF UnauthenticatedAttribute,
+ uaSequence [3] IMPLICIT SEQUENCE OF UnauthenticatedAttribute
+ } OPTIONAL
+}
+
+SignerIdentifier ::= CHOICE {
+ -- RFC5652 sec 5.3
+ issuerAndSerialNumber IssuerAndSerialNumber,
+ subjectKeyIdentifier [0] IMPLICIT SubjectKeyIdentifier
+}
+
+IssuerAndSerialNumber ::= SEQUENCE {
+ issuer ANY,
+ serialNumber ANY
+}
+
+CertificateSerialNumber ::= INTEGER
+
+SubjectKeyIdentifier ::= OCTET STRING
+
+SetOfAuthenticatedAttribute ::= SET OF AuthenticatedAttribute
+
+Values ::= SET OF ANY
+
+AuthenticatedAttribute ::= SEQUENCE {
+ type OBJECT IDENTIFIER,
+ values Values
+}
+
+UnauthenticatedAttribute ::= SEQUENCE {
+ type OBJECT IDENTIFIER,
+ values Values
+}
+
+DigestEncryptionAlgorithmIdentifier ::= SEQUENCE {
+ algorithm OBJECT IDENTIFIER,
+ parameters ANY OPTIONAL
+}
+
+EncryptedDigest ::= OCTET STRING
+
+---
+--- X.500 Name
+---
+Name ::= SEQUENCE OF RelativeDistinguishedName
+
+RelativeDistinguishedName ::= SET OF AttributeValueAssertion
+
+AttributeValueAssertion ::= SEQUENCE {
+ attributeType OBJECT IDENTIFIER,
+ attributeValue ANY
+}
+
+END
+
diff --git a/libkmod/pkcs7/pkcs7_parser.c b/libkmod/pkcs7/pkcs7_parser.c
new file mode 100644
index 000000000000..d1da9a6b4ac8
--- /dev/null
+++ b/libkmod/pkcs7/pkcs7_parser.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc., Yauheni Kaliuta
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pkcs7_parser.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+enum pkey_hash_algo {
+ PKEY_HASH_MD4,
+ PKEY_HASH_MD5,
+ PKEY_HASH_SHA1,
+ PKEY_HASH_SHA256,
+ PKEY_HASH_SHA384,
+ PKEY_HASH_SHA512,
+ PKEY_HASH_SHA224,
+ PKEY_HASH__LAST
+};
+
+static const char *const pkey_hash_algo[PKEY_HASH__LAST] = {
+ [PKEY_HASH_MD4] = "md4",
+ [PKEY_HASH_MD5] = "md5",
+ [PKEY_HASH_SHA1] = "sha1",
+ [PKEY_HASH_SHA256] = "sha256",
+ [PKEY_HASH_SHA384] = "sha384",
+ [PKEY_HASH_SHA512] = "sha512",
+ [PKEY_HASH_SHA224] = "sha224",
+};
+
+/* 2.5.4.3 */
+static uint8_t OID_cn[] = { '\x55', '\x04', '\x03' };
+/* 1.3.14.3.2.26 */
+static uint8_t OID_SHA1[] = { '\x2b', '\x0e', '\x03', '\x02', '\x1a' };
+/* 2.16.840.1.101.3.4.2.1 */
+static uint8_t OID_SHA256[] = { '\x60', '\x86', '\x48', '\x01',
+ '\x65', '\x03', '\x04', '\x02', '\x01' };
+/* 2.16.840.1.101.3.4.2.2 */
+static uint8_t OID_SHA384[] = { '\x60', '\x86', '\x48', '\x01',
+ '\x65', '\x03', '\x04', '\x02', '\x02' };
+/* 2.16.840.1.101.3.4.2.3 */
+static uint8_t OID_SHA512[] = { '\x60', '\x86', '\x48', '\x01',
+ '\x65', '\x03', '\x04', '\x02', '\x03' };
+/* 2.16.840.1.101.3.4.2.4 */
+static uint8_t OID_SHA224[] = { '\x60', '\x86', '\x48', '\x01',
+ '\x65', '\x03', '\x04', '\x02', '\x04' };
+
+static uint8_t OID_MD4[] = { '\x2a', '\x86', '\x48', '\x86', '\xf7',
+ '\x0d', '\x02', '\x04' };
+static uint8_t OID_MD5[] = { '\x2a', '\x86', '\x48', '\x86', '\xf7',
+ '\x0d', '\x02', '\x05' };
+
+
+#define OID_TO_ID(oid) { OID_ ## oid, sizeof(OID_ ## oid), PKEY_HASH_ ## oid }
+static struct oid_to_id {
+ uint8_t *oid;
+ int oid_size;
+ int id;
+} oid_to_id[] = {
+ OID_TO_ID(SHA256),
+ OID_TO_ID(MD5),
+ OID_TO_ID(SHA1),
+ OID_TO_ID(SHA384),
+ OID_TO_ID(SHA512),
+ OID_TO_ID(SHA224),
+ OID_TO_ID(MD4),
+};
+
+
+static const char *pkey_hash_algo_to_str(unsigned id)
+{
+ if (id >= PKEY_HASH__LAST)
+ return "unknown";
+
+ return pkey_hash_algo[id];
+}
+
+void pkcs7_free_cert(struct pkcs7_cert *cert)
+{
+
+ asn_DEF_Name.free_struct(&asn_DEF_Name, cert->issuer, 0);
+
+ asn_DEF_PKCS7ContentInfo.free_struct
+ (&asn_DEF_PKCS7ContentInfo, cert->ci, 0);
+
+ free(cert->key_id);
+ free(cert->signer);
+ free(cert->signature);
+ free(cert);
+}
+
+static char *pkcs7_parse_utf8(uint8_t *buf, int size)
+{
+ char *p;
+ int len;
+ int llen = 1; /* length of length field */
+
+ if (buf[0] != 0x0C) /* utf8 string tag */
+ return NULL;
+
+ if (buf[1] & 0x80)
+ llen = (buf[1] & ~0x80) + 1;
+ len = size - 1 - llen; /* 1 is tag */
+
+ p = malloc(len + 1);
+ if (p == NULL)
+ return NULL;
+
+ memcpy(p, buf + 1 + llen, len);
+ p[len] = '\0';
+
+ return p;
+}
+
+static int pkcs7_parse_issuer(struct pkcs7_cert *cert, ANY_t *data)
+{
+ asn_dec_rval_t rval;
+ struct RelativeDistinguishedName **dnames;
+ int count;
+ int i;
+
+ rval = ber_decode(0, &asn_DEF_Name, (void **)&cert->issuer,
+ data->buf, data->size);
+
+ if(rval.code != RC_OK)
+ return -1;
+
+ dnames = cert->issuer->list.array;
+ count = cert->issuer->list.count;
+
+ for (i = 0; i < count; i++) {
+ int j;
+ int n = dnames[i]->list.count;
+ struct AttributeValueAssertion **ava = dnames[i]->list.array;
+
+ for (j = 0; j < n; j++) {
+ OBJECT_IDENTIFIER_t *oid = &ava[j]->attributeType;
+ ANY_t *d = &ava[j]->attributeValue;
+
+ if (oid->size != sizeof(OID_cn))
+ continue;
+
+ if (memcmp(oid->buf, OID_cn, sizeof(OID_cn)) == 0) {
+ cert->signer = pkcs7_parse_utf8(d->buf, d->size);
+ break;
+ }
+ }
+ if (cert->signer != NULL)
+ break;
+ }
+
+ return 0;
+}
+
+static int pkcs7_gen_keyid_from_skid(OCTET_STRING_t *skid,
+ uint8_t **buf, size_t *size)
+{
+ uint8_t *p;
+
+ p = malloc(skid->size);
+ if (p == NULL)
+ return -1;
+
+ memcpy(p, skid->buf, skid->size);
+
+ *buf = p;
+ *size = skid->size;
+
+ return 0;
+}
+
+static int pkcs7_gen_keyid_from_issuer(IssuerAndSerialNumber_t *issuer,
+ uint8_t **buf, size_t *size)
+{
+ size_t s;
+ uint8_t *p;
+
+ /*
+ * see asymmetric_key_generate_id(),
+ * crypto/asymmetric_keys/assymmetric_type.c in the linux kernel
+ */
+
+ s = issuer->issuer.size + issuer->serialNumber.size;
+
+ p = malloc(s);
+ if (p == NULL)
+ return -1;
+
+ memcpy(p, issuer->issuer.buf, issuer->issuer.size);
+ memcpy(p + issuer->issuer.size,
+ issuer->serialNumber.buf,
+ issuer->serialNumber.size);
+
+ *buf = p;
+ *size = s;
+
+ return 0;
+}
+
+static uint8_t pkcs7_hashalgo_oid_to_id(OBJECT_IDENTIFIER_t *oid)
+{
+ unsigned i;
+ struct oid_to_id *item;
+
+ for (i = 0; i < ARRAY_SIZE(oid_to_id); i++) {
+ item = &oid_to_id[i];
+ if (oid->size != item->oid_size)
+ continue;
+ if (memcmp(oid->buf, item->oid, oid->size) != 0)
+ continue;
+ return item->id;
+ }
+ return ~0;
+}
+
+static int pkcs7_parse_si(struct pkcs7_cert *cert)
+{
+ struct SignerInfo **infos;
+ struct SignerInfo *si;
+ int count;
+ OBJECT_IDENTIFIER_t *oid;
+ uint8_t *buf;
+
+ infos = cert->ci->content->signerInfos.choice.siSequence.list.array;
+ count = cert->ci->content->signerInfos.choice.siSequence.list.count;
+
+ if (count < 1)
+ return -1;
+
+ si = infos[0];
+
+ if (si->sid.present == SignerIdentifier_PR_subjectKeyIdentifier) {
+ if (pkcs7_gen_keyid_from_skid(&si->sid.choice.subjectKeyIdentifier, &cert->key_id, &cert->key_id_size) < 0)
+ return -1;
+ return 1;
+ }
+
+ if (pkcs7_parse_issuer(cert,
+ &si->sid.choice.issuerAndSerialNumber.issuer) < 0)
+ return -1;
+ if (pkcs7_gen_keyid_from_issuer(&si->sid.choice.issuerAndSerialNumber,
+ &cert->key_id, &cert->key_id_size) < 0)
+ return -1;
+
+ buf = malloc(si->encryptedDigest.size);
+ if (buf == NULL)
+ return -1;
+ memcpy(buf, si->encryptedDigest.buf, si->encryptedDigest.size);
+
+ cert->signature = buf;
+ cert->signature_size = si->encryptedDigest.size;
+
+ oid = &si->digestAlgorithm.algorithm;
+ cert->hash_algo = pkey_hash_algo_to_str(pkcs7_hashalgo_oid_to_id(oid));
+
+ return 0;
+}
+
+struct pkcs7_cert *pkcs7_parse_cert(const void *raw, size_t len)
+{
+ struct pkcs7_cert *cert;
+ asn_dec_rval_t rval;
+
+ cert = malloc(sizeof(*cert));
+ if (cert == NULL)
+ return NULL;
+ memset(cert, 0, sizeof(*cert));
+
+ rval = ber_decode(0, &asn_DEF_PKCS7ContentInfo, (void **)&cert->ci,
+ raw, len);
+
+ if(rval.code != RC_OK)
+ goto err;
+
+ if (cert->ci->content->signerInfos.present == SignerInfos_PR_NOTHING)
+ goto err;
+
+ if (pkcs7_parse_si(cert) < 0)
+ goto err;
+
+ return cert;
+err:
+ pkcs7_free_cert(cert);
+ return NULL;
+}
diff --git a/libkmod/pkcs7/pkcs7_parser.h b/libkmod/pkcs7/pkcs7_parser.h
new file mode 100644
index 000000000000..3a03a34ec240
--- /dev/null
+++ b/libkmod/pkcs7/pkcs7_parser.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc., Yauheni Kaliuta
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KMOD_PKCS7_PARSER_H_
+#define KMOD_PKCS7_PARSER_H_
+
+#define EMIT_ASN_DEBUG 0
+
+#include <PKCS7ContentInfo.h>
+#include <Name.h>
+
+struct pkcs7_cert {
+ PKCS7ContentInfo_t *ci;
+ /* issuer RAW data are needed as well, so parsed separately */
+ Name_t *issuer;
+
+ const char *hash_algo;
+ uint8_t *key_id;
+ size_t key_id_size;
+ char *signer; /* copy cn there, name like in module_signature */
+ uint8_t *signature;
+ size_t signature_size;
+};
+
+struct pkcs7_cert *pkcs7_parse_cert(const void *raw, size_t len);
+void pkcs7_free_cert(struct pkcs7_cert *cert);
+
+#endif
--
2.16.2