diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-17 11:33:45 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-17 11:33:45 -0700 |
commit | bb7aeae3d680c2c777f54274b0270ced0599f33d (patch) | |
tree | 4801a103c2b157b5019cf38a19dc67d54bf38453 /scripts | |
parent | 70477371dc350746d10431d74f0f213a8d59924c (diff) | |
parent | 88a1b564a20e371e6be41b39b85673e9c1959491 (diff) | |
download | op-kernel-dev-bb7aeae3d680c2c777f54274b0270ced0599f33d.zip op-kernel-dev-bb7aeae3d680c2c777f54274b0270ced0599f33d.tar.gz |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security layer updates from James Morris:
"There are a bunch of fixes to the TPM, IMA, and Keys code, with minor
fixes scattered across the subsystem.
IMA now requires signed policy, and that policy is also now measured
and appraised"
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (67 commits)
X.509: Make algo identifiers text instead of enum
akcipher: Move the RSA DER encoding check to the crypto layer
crypto: Add hash param to pkcs1pad
sign-file: fix build with CMS support disabled
MAINTAINERS: update tpmdd urls
MODSIGN: linux/string.h should be #included to get memcpy()
certs: Fix misaligned data in extra certificate list
X.509: Handle midnight alternative notation in GeneralizedTime
X.509: Support leap seconds
Handle ISO 8601 leap seconds and encodings of midnight in mktime64()
X.509: Fix leap year handling again
PKCS#7: fix unitialized boolean 'want'
firmware: change kernel read fail to dev_dbg()
KEYS: Use the symbol value for list size, updated by scripts/insert-sys-cert
KEYS: Reserve an extra certificate symbol for inserting without recompiling
modsign: hide openssl output in silent builds
tpm_tis: fix build warning with tpm_tis_resume
ima: require signed IMA policy
ima: measure and appraise the IMA policy itself
ima: load policy using path
...
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/.gitignore | 1 | ||||
-rw-r--r-- | scripts/Makefile | 1 | ||||
-rwxr-xr-x | scripts/extract-sys-certs.pl | 29 | ||||
-rw-r--r-- | scripts/insert-sys-cert.c | 410 | ||||
-rwxr-xr-x | scripts/sign-file.c | 238 |
5 files changed, 580 insertions, 99 deletions
diff --git a/scripts/.gitignore b/scripts/.gitignore index 1f78169..e063daa 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -13,3 +13,4 @@ sortextable asn1_compiler extract-cert sign-file +insert-sys-cert diff --git a/scripts/Makefile b/scripts/Makefile index fd0d53d..822ab4a 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -19,6 +19,7 @@ hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable hostprogs-$(CONFIG_ASN1) += asn1_compiler hostprogs-$(CONFIG_MODULE_SIG) += sign-file hostprogs-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert +hostprogs-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include diff --git a/scripts/extract-sys-certs.pl b/scripts/extract-sys-certs.pl index d476e7d..8227ca1 100755 --- a/scripts/extract-sys-certs.pl +++ b/scripts/extract-sys-certs.pl @@ -91,13 +91,15 @@ print "Have $nr_symbols symbols\n"; die "Can't find system certificate list" unless (exists($symbols{"__cert_list_start"}) && - exists($symbols{"__cert_list_end"})); + exists($symbols{"system_certificate_list_size"})); my $start = Math::BigInt->new($symbols{"__cert_list_start"}); -my $end = Math::BigInt->new($symbols{"__cert_list_end"}); -my $size = $end - $start; +my $end; +my $size; +my $size_sym = Math::BigInt->new($symbols{"system_certificate_list_size"}); -printf "Have %u bytes of certs at VMA 0x%x\n", $size, $start; +open FD, "<$vmlinux" || die $vmlinux; +binmode(FD); my $s = undef; foreach my $sec (@sections) { @@ -110,11 +112,24 @@ foreach my $sec (@sections) { next unless ($start >= $s_vma); next if ($start >= $s_vend); - die "Cert object partially overflows section $s_name\n" - if ($end > $s_vend); + die "Certificate list size was not found on the same section\n" + if ($size_sym < $s_vma || $size_sym > $s_vend); die "Cert object in multiple sections: ", $s_name, " and ", $s->{name}, "\n" if ($s); + + my $size_off = $size_sym -$s_vma + $s_foff; + my $packed; + die $vmlinux if (!defined(sysseek(FD, $size_off, SEEK_SET))); + sysread(FD, $packed, 8); + $size = unpack 'L!', $packed; + $end = $start + $size; + + printf "Have %u bytes of certs at VMA 0x%x\n", $size, $start; + + die "Cert object partially overflows section $s_name\n" + if ($end > $s_vend); + $s = $sec; } @@ -127,8 +142,6 @@ my $foff = $start - $s->{vma} + $s->{foff}; printf "Certificate list at file offset 0x%x\n", $foff; -open FD, "<$vmlinux" || die $vmlinux; -binmode(FD); die $vmlinux if (!defined(sysseek(FD, $foff, SEEK_SET))); my $buf = ""; my $len = sysread(FD, $buf, $size); diff --git a/scripts/insert-sys-cert.c b/scripts/insert-sys-cert.c new file mode 100644 index 0000000..8902836 --- /dev/null +++ b/scripts/insert-sys-cert.c @@ -0,0 +1,410 @@ +/* Write the contents of the <certfile> into kernel symbol system_extra_cert + * + * Copyright (C) IBM Corporation, 2015 + * + * Author: Mehmet Kayaalp <mkayaalp@linux.vnet.ibm.com> + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + * Usage: insert-sys-cert [-s <System.map> -b <vmlinux> -c <certfile> + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <limits.h> +#include <stdbool.h> +#include <errno.h> +#include <stdlib.h> +#include <stdarg.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <unistd.h> +#include <elf.h> + +#define CERT_SYM "system_extra_cert" +#define USED_SYM "system_extra_cert_used" +#define LSIZE_SYM "system_certificate_list_size" + +#define info(format, args...) fprintf(stderr, "INFO: " format, ## args) +#define warn(format, args...) fprintf(stdout, "WARNING: " format, ## args) +#define err(format, args...) fprintf(stderr, "ERROR: " format, ## args) + +#if UINTPTR_MAX == 0xffffffff +#define CURRENT_ELFCLASS ELFCLASS32 +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#else +#define CURRENT_ELFCLASS ELFCLASS64 +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Shdr Elf64_Shdr +#define Elf_Sym Elf64_Sym +#endif + +static unsigned char endianness(void) +{ + uint16_t two_byte = 0x00FF; + uint8_t low_address = *((uint8_t *)&two_byte); + + if (low_address == 0) + return ELFDATA2MSB; + else + return ELFDATA2LSB; +} + +struct sym { + char *name; + unsigned long address; + unsigned long offset; + void *content; + int size; +}; + +static unsigned long get_offset_from_address(Elf_Ehdr *hdr, unsigned long addr) +{ + Elf_Shdr *x; + unsigned int i, num_sections; + + x = (void *)hdr + hdr->e_shoff; + if (hdr->e_shnum == SHN_UNDEF) + num_sections = x[0].sh_size; + else + num_sections = hdr->e_shnum; + + for (i = 1; i < num_sections; i++) { + unsigned long start = x[i].sh_addr; + unsigned long end = start + x[i].sh_size; + unsigned long offset = x[i].sh_offset; + + if (addr >= start && addr <= end) + return addr - start + offset; + } + return 0; +} + + +#define LINE_SIZE 100 + +static void get_symbol_from_map(Elf_Ehdr *hdr, FILE *f, char *name, + struct sym *s) +{ + char l[LINE_SIZE]; + char *w, *p, *n; + + s->size = 0; + s->address = 0; + s->offset = 0; + if (fseek(f, 0, SEEK_SET) != 0) { + perror("File seek failed"); + exit(EXIT_FAILURE); + } + while (fgets(l, LINE_SIZE, f)) { + p = strchr(l, '\n'); + if (!p) { + err("Missing line ending.\n"); + return; + } + n = strstr(l, name); + if (n) + break; + } + if (!n) { + err("Unable to find symbol: %s\n", name); + return; + } + w = strchr(l, ' '); + if (!w) + return; + + *w = '\0'; + s->address = strtoul(l, NULL, 16); + if (s->address == 0) + return; + s->offset = get_offset_from_address(hdr, s->address); + s->name = name; + s->content = (void *)hdr + s->offset; +} + +static Elf_Sym *find_elf_symbol(Elf_Ehdr *hdr, Elf_Shdr *symtab, char *name) +{ + Elf_Sym *sym, *symtab_start; + char *strtab, *symname; + unsigned int link; + Elf_Shdr *x; + int i, n; + + x = (void *)hdr + hdr->e_shoff; + link = symtab->sh_link; + symtab_start = (void *)hdr + symtab->sh_offset; + n = symtab->sh_size / symtab->sh_entsize; + strtab = (void *)hdr + x[link].sh_offset; + + for (i = 0; i < n; i++) { + sym = &symtab_start[i]; + symname = strtab + sym->st_name; + if (strcmp(symname, name) == 0) + return sym; + } + err("Unable to find symbol: %s\n", name); + return NULL; +} + +static void get_symbol_from_table(Elf_Ehdr *hdr, Elf_Shdr *symtab, + char *name, struct sym *s) +{ + Elf_Shdr *sec; + int secndx; + Elf_Sym *elf_sym; + Elf_Shdr *x; + + x = (void *)hdr + hdr->e_shoff; + s->size = 0; + s->address = 0; + s->offset = 0; + elf_sym = find_elf_symbol(hdr, symtab, name); + if (!elf_sym) + return; + secndx = elf_sym->st_shndx; + if (!secndx) + return; + sec = &x[secndx]; + s->size = elf_sym->st_size; + s->address = elf_sym->st_value; + s->offset = s->address - sec->sh_addr + + sec->sh_offset; + s->name = name; + s->content = (void *)hdr + s->offset; +} + +static Elf_Shdr *get_symbol_table(Elf_Ehdr *hdr) +{ + Elf_Shdr *x; + unsigned int i, num_sections; + + x = (void *)hdr + hdr->e_shoff; + if (hdr->e_shnum == SHN_UNDEF) + num_sections = x[0].sh_size; + else + num_sections = hdr->e_shnum; + + for (i = 1; i < num_sections; i++) + if (x[i].sh_type == SHT_SYMTAB) + return &x[i]; + return NULL; +} + +static void *map_file(char *file_name, int *size) +{ + struct stat st; + void *map; + int fd; + + fd = open(file_name, O_RDWR); + if (fd < 0) { + perror(file_name); + return NULL; + } + if (fstat(fd, &st)) { + perror("Could not determine file size"); + close(fd); + return NULL; + } + *size = st.st_size; + map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (map == MAP_FAILED) { + perror("Mapping to memory failed"); + close(fd); + return NULL; + } + close(fd); + return map; +} + +static char *read_file(char *file_name, int *size) +{ + struct stat st; + char *buf; + int fd; + + fd = open(file_name, O_RDONLY); + if (fd < 0) { + perror(file_name); + return NULL; + } + if (fstat(fd, &st)) { + perror("Could not determine file size"); + close(fd); + return NULL; + } + *size = st.st_size; + buf = malloc(*size); + if (!buf) { + perror("Allocating memory failed"); + close(fd); + return NULL; + } + if (read(fd, buf, *size) != *size) { + perror("File read failed"); + close(fd); + return NULL; + } + close(fd); + return buf; +} + +static void print_sym(Elf_Ehdr *hdr, struct sym *s) +{ + info("sym: %s\n", s->name); + info("addr: 0x%lx\n", s->address); + info("size: %d\n", s->size); + info("offset: 0x%lx\n", (unsigned long)s->offset); +} + +static void print_usage(char *e) +{ + printf("Usage %s [-s <System.map>] -b <vmlinux> -c <certfile>\n", e); +} + +int main(int argc, char **argv) +{ + char *system_map_file = NULL; + char *vmlinux_file = NULL; + char *cert_file = NULL; + int vmlinux_size; + int cert_size; + Elf_Ehdr *hdr; + char *cert; + FILE *system_map; + unsigned long *lsize; + int *used; + int opt; + Elf_Shdr *symtab = NULL; + struct sym cert_sym, lsize_sym, used_sym; + + while ((opt = getopt(argc, argv, "b:c:s:")) != -1) { + switch (opt) { + case 's': + system_map_file = optarg; + break; + case 'b': + vmlinux_file = optarg; + break; + case 'c': + cert_file = optarg; + break; + default: + break; + } + } + + if (!vmlinux_file || !cert_file) { + print_usage(argv[0]); + exit(EXIT_FAILURE); + } + + cert = read_file(cert_file, &cert_size); + if (!cert) + exit(EXIT_FAILURE); + + hdr = map_file(vmlinux_file, &vmlinux_size); + if (!hdr) + exit(EXIT_FAILURE); + + if (vmlinux_size < sizeof(*hdr)) { + err("Invalid ELF file.\n"); + exit(EXIT_FAILURE); + } + + if ((hdr->e_ident[EI_MAG0] != ELFMAG0) || + (hdr->e_ident[EI_MAG1] != ELFMAG1) || + (hdr->e_ident[EI_MAG2] != ELFMAG2) || + (hdr->e_ident[EI_MAG3] != ELFMAG3)) { + err("Invalid ELF magic.\n"); + exit(EXIT_FAILURE); + } + + if (hdr->e_ident[EI_CLASS] != CURRENT_ELFCLASS) { + err("ELF class mismatch.\n"); + exit(EXIT_FAILURE); + } + + if (hdr->e_ident[EI_DATA] != endianness()) { + err("ELF endian mismatch.\n"); + exit(EXIT_FAILURE); + } + + if (hdr->e_shoff > vmlinux_size) { + err("Could not find section header.\n"); + exit(EXIT_FAILURE); + } + + symtab = get_symbol_table(hdr); + if (!symtab) { + warn("Could not find the symbol table.\n"); + if (!system_map_file) { + err("Please provide a System.map file.\n"); + print_usage(argv[0]); + exit(EXIT_FAILURE); + } + + system_map = fopen(system_map_file, "r"); + if (!system_map) { + perror(system_map_file); + exit(EXIT_FAILURE); + } + get_symbol_from_map(hdr, system_map, CERT_SYM, &cert_sym); + get_symbol_from_map(hdr, system_map, USED_SYM, &used_sym); + get_symbol_from_map(hdr, system_map, LSIZE_SYM, &lsize_sym); + cert_sym.size = used_sym.address - cert_sym.address; + } else { + info("Symbol table found.\n"); + if (system_map_file) + warn("System.map is ignored.\n"); + get_symbol_from_table(hdr, symtab, CERT_SYM, &cert_sym); + get_symbol_from_table(hdr, symtab, USED_SYM, &used_sym); + get_symbol_from_table(hdr, symtab, LSIZE_SYM, &lsize_sym); + } + + if (!cert_sym.offset || !lsize_sym.offset || !used_sym.offset) + exit(EXIT_FAILURE); + + print_sym(hdr, &cert_sym); + print_sym(hdr, &used_sym); + print_sym(hdr, &lsize_sym); + + lsize = (unsigned long *)lsize_sym.content; + used = (int *)used_sym.content; + + if (cert_sym.size < cert_size) { + err("Certificate is larger than the reserved area!\n"); + exit(EXIT_FAILURE); + } + + /* If the existing cert is the same, don't overwrite */ + if (cert_size == *used && + strncmp(cert_sym.content, cert, cert_size) == 0) { + warn("Certificate was already inserted.\n"); + exit(EXIT_SUCCESS); + } + + if (*used > 0) + warn("Replacing previously inserted certificate.\n"); + + memcpy(cert_sym.content, cert, cert_size); + if (cert_size < cert_sym.size) + memset(cert_sym.content + cert_size, + 0, cert_sym.size - cert_size); + + *lsize = *lsize + cert_size - *used; + *used = cert_size; + info("Inserted the contents of %s into %lx.\n", cert_file, + cert_sym.address); + info("Used %d bytes out of %d bytes reserved.\n", *used, + cert_sym.size); + exit(EXIT_SUCCESS); +} diff --git a/scripts/sign-file.c b/scripts/sign-file.c index 250a7a6..d912d5a 100755 --- a/scripts/sign-file.c +++ b/scripts/sign-file.c @@ -2,9 +2,11 @@ * * Copyright © 2014-2015 Red Hat, Inc. All Rights Reserved. * Copyright © 2015 Intel Corporation. + * Copyright © 2016 Hewlett Packard Enterprise Development LP * * Authors: David Howells <dhowells@redhat.com> * David Woodhouse <dwmw2@infradead.org> + * Juerg Haefliger <juerg.haefliger@hpe.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -39,7 +41,7 @@ * signing with anything other than SHA1 - so we're stuck with that if such is * the case. */ -#if OPENSSL_VERSION_NUMBER < 0x10000000L +#if OPENSSL_VERSION_NUMBER < 0x10000000L || defined(OPENSSL_NO_CMS) #define USE_PKCS7 #endif #ifndef USE_PKCS7 @@ -67,6 +69,8 @@ void format(void) { fprintf(stderr, "Usage: scripts/sign-file [-dp] <hash algo> <key> <x509> <module> [<dest>]\n"); + fprintf(stderr, + " scripts/sign-file -s <raw sig> <hash algo> <x509> <module> [<dest>]\n"); exit(2); } @@ -126,26 +130,84 @@ static int pem_pw_cb(char *buf, int len, int w, void *v) return pwlen; } +static EVP_PKEY *read_private_key(const char *private_key_name) +{ + EVP_PKEY *private_key; + + if (!strncmp(private_key_name, "pkcs11:", 7)) { + ENGINE *e; + + ENGINE_load_builtin_engines(); + drain_openssl_errors(); + e = ENGINE_by_id("pkcs11"); + ERR(!e, "Load PKCS#11 ENGINE"); + if (ENGINE_init(e)) + drain_openssl_errors(); + else + ERR(1, "ENGINE_init"); + if (key_pass) + ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), + "Set PKCS#11 PIN"); + private_key = ENGINE_load_private_key(e, private_key_name, + NULL, NULL); + ERR(!private_key, "%s", private_key_name); + } else { + BIO *b; + + b = BIO_new_file(private_key_name, "rb"); + ERR(!b, "%s", private_key_name); + private_key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb, + NULL); + ERR(!private_key, "%s", private_key_name); + BIO_free(b); + } + + return private_key; +} + +static X509 *read_x509(const char *x509_name) +{ + X509 *x509; + BIO *b; + + b = BIO_new_file(x509_name, "rb"); + ERR(!b, "%s", x509_name); + x509 = d2i_X509_bio(b, NULL); /* Binary encoded X.509 */ + if (!x509) { + ERR(BIO_reset(b) != 1, "%s", x509_name); + x509 = PEM_read_bio_X509(b, NULL, NULL, + NULL); /* PEM encoded X.509 */ + if (x509) + drain_openssl_errors(); + } + BIO_free(b); + ERR(!x509, "%s", x509_name); + + return x509; +} + int main(int argc, char **argv) { struct module_signature sig_info = { .id_type = PKEY_ID_PKCS7 }; char *hash_algo = NULL; - char *private_key_name, *x509_name, *module_name, *dest_name; + char *private_key_name = NULL, *raw_sig_name = NULL; + char *x509_name, *module_name, *dest_name; bool save_sig = false, replace_orig; bool sign_only = false; + bool raw_sig = false; unsigned char buf[4096]; unsigned long module_size, sig_size; unsigned int use_signed_attrs; const EVP_MD *digest_algo; EVP_PKEY *private_key; #ifndef USE_PKCS7 - CMS_ContentInfo *cms; + CMS_ContentInfo *cms = NULL; unsigned int use_keyid = 0; #else - PKCS7 *pkcs7; + PKCS7 *pkcs7 = NULL; #endif X509 *x509; - BIO *b, *bd = NULL, *bm; + BIO *bd, *bm; int opt, n; OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); @@ -160,8 +222,9 @@ int main(int argc, char **argv) #endif do { - opt = getopt(argc, argv, "dpk"); + opt = getopt(argc, argv, "sdpk"); switch (opt) { + case 's': raw_sig = true; break; case 'p': save_sig = true; break; case 'd': sign_only = true; save_sig = true; break; #ifndef USE_PKCS7 @@ -177,8 +240,13 @@ int main(int argc, char **argv) if (argc < 4 || argc > 5) format(); - hash_algo = argv[0]; - private_key_name = argv[1]; + if (raw_sig) { + raw_sig_name = argv[0]; + hash_algo = argv[1]; + } else { + hash_algo = argv[0]; + private_key_name = argv[1]; + } x509_name = argv[2]; module_name = argv[3]; if (argc == 5) { @@ -198,101 +266,74 @@ int main(int argc, char **argv) } #endif - /* Read the private key and the X.509 cert the PKCS#7 message - * will point to. - */ - if (!strncmp(private_key_name, "pkcs11:", 7)) { - ENGINE *e; - - ENGINE_load_builtin_engines(); - drain_openssl_errors(); - e = ENGINE_by_id("pkcs11"); - ERR(!e, "Load PKCS#11 ENGINE"); - if (ENGINE_init(e)) - drain_openssl_errors(); - else - ERR(1, "ENGINE_init"); - if (key_pass) - ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN"); - private_key = ENGINE_load_private_key(e, private_key_name, NULL, - NULL); - ERR(!private_key, "%s", private_key_name); - } else { - b = BIO_new_file(private_key_name, "rb"); - ERR(!b, "%s", private_key_name); - private_key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb, NULL); - ERR(!private_key, "%s", private_key_name); - BIO_free(b); - } - - b = BIO_new_file(x509_name, "rb"); - ERR(!b, "%s", x509_name); - x509 = d2i_X509_bio(b, NULL); /* Binary encoded X.509 */ - if (!x509) { - ERR(BIO_reset(b) != 1, "%s", x509_name); - x509 = PEM_read_bio_X509(b, NULL, NULL, NULL); /* PEM encoded X.509 */ - if (x509) - drain_openssl_errors(); - } - BIO_free(b); - ERR(!x509, "%s", x509_name); - - /* Open the destination file now so that we can shovel the module data - * across as we read it. - */ - if (!sign_only) { - bd = BIO_new_file(dest_name, "wb"); - ERR(!bd, "%s", dest_name); - } - - /* Digest the module data. */ - OpenSSL_add_all_digests(); - display_openssl_errors(__LINE__); - digest_algo = EVP_get_digestbyname(hash_algo); - ERR(!digest_algo, "EVP_get_digestbyname"); - + /* Open the module file */ bm = BIO_new_file(module_name, "rb"); ERR(!bm, "%s", module_name); + if (!raw_sig) { + /* Read the private key and the X.509 cert the PKCS#7 message + * will point to. + */ + private_key = read_private_key(private_key_name); + x509 = read_x509(x509_name); + + /* Digest the module data. */ + OpenSSL_add_all_digests(); + display_openssl_errors(__LINE__); + digest_algo = EVP_get_digestbyname(hash_algo); + ERR(!digest_algo, "EVP_get_digestbyname"); + #ifndef USE_PKCS7 - /* Load the signature message from the digest buffer. */ - cms = CMS_sign(NULL, NULL, NULL, NULL, - CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY | CMS_DETACHED | CMS_STREAM); - ERR(!cms, "CMS_sign"); - - ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo, - CMS_NOCERTS | CMS_BINARY | CMS_NOSMIMECAP | - use_keyid | use_signed_attrs), - "CMS_add1_signer"); - ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) < 0, - "CMS_final"); + /* Load the signature message from the digest buffer. */ + cms = CMS_sign(NULL, NULL, NULL, NULL, + CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY | + CMS_DETACHED | CMS_STREAM); + ERR(!cms, "CMS_sign"); + + ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo, + CMS_NOCERTS | CMS_BINARY | + CMS_NOSMIMECAP | use_keyid | + use_signed_attrs), + "CMS_add1_signer"); + ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) < 0, + "CMS_final"); #else - pkcs7 = PKCS7_sign(x509, private_key, NULL, bm, - PKCS7_NOCERTS | PKCS7_BINARY | - PKCS7_DETACHED | use_signed_attrs); - ERR(!pkcs7, "PKCS7_sign"); + pkcs7 = PKCS7_sign(x509, private_key, NULL, bm, + PKCS7_NOCERTS | PKCS7_BINARY | + PKCS7_DETACHED | use_signed_attrs); + ERR(!pkcs7, "PKCS7_sign"); #endif - if (save_sig) { - char *sig_file_name; + if (save_sig) { + char *sig_file_name; + BIO *b; - ERR(asprintf(&sig_file_name, "%s.p7s", module_name) < 0, - "asprintf"); - b = BIO_new_file(sig_file_name, "wb"); - ERR(!b, "%s", sig_file_name); + ERR(asprintf(&sig_file_name, "%s.p7s", module_name) < 0, + "asprintf"); + b = BIO_new_file(sig_file_name, "wb"); + ERR(!b, "%s", sig_file_name); #ifndef USE_PKCS7 - ERR(i2d_CMS_bio_stream(b, cms, NULL, 0) < 0, - "%s", sig_file_name); + ERR(i2d_CMS_bio_stream(b, cms, NULL, 0) < 0, + "%s", sig_file_name); #else - ERR(i2d_PKCS7_bio(b, pkcs7) < 0, - "%s", sig_file_name); + ERR(i2d_PKCS7_bio(b, pkcs7) < 0, + "%s", sig_file_name); #endif - BIO_free(b); + BIO_free(b); + } + + if (sign_only) { + BIO_free(bm); + return 0; + } } - if (sign_only) - return 0; + /* Open the destination file now so that we can shovel the module data + * across as we read it. + */ + bd = BIO_new_file(dest_name, "wb"); + ERR(!bd, "%s", dest_name); /* Append the marker and the PKCS#7 message to the destination file */ ERR(BIO_reset(bm) < 0, "%s", module_name); @@ -300,14 +341,29 @@ int main(int argc, char **argv) n > 0) { ERR(BIO_write(bd, buf, n) < 0, "%s", dest_name); } + BIO_free(bm); ERR(n < 0, "%s", module_name); module_size = BIO_number_written(bd); + if (!raw_sig) { #ifndef USE_PKCS7 - ERR(i2d_CMS_bio_stream(bd, cms, NULL, 0) < 0, "%s", dest_name); + ERR(i2d_CMS_bio_stream(bd, cms, NULL, 0) < 0, "%s", dest_name); #else - ERR(i2d_PKCS7_bio(bd, pkcs7) < 0, "%s", dest_name); + ERR(i2d_PKCS7_bio(bd, pkcs7) < 0, "%s", dest_name); #endif + } else { + BIO *b; + + /* Read the raw signature file and write the data to the + * destination file + */ + b = BIO_new_file(raw_sig_name, "rb"); + ERR(!b, "%s", raw_sig_name); + while ((n = BIO_read(b, buf, sizeof(buf))), n > 0) + ERR(BIO_write(bd, buf, n) < 0, "%s", dest_name); + BIO_free(b); + } + sig_size = BIO_number_written(bd) - module_size; sig_info.sig_len = htonl(sig_size); ERR(BIO_write(bd, &sig_info, sizeof(sig_info)) < 0, "%s", dest_name); |