aboutsummaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-03-17 14:33:45 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-17 14:33:45 -0400
commitbb7aeae3d680c2c777f54274b0270ced0599f33d (patch)
tree4801a103c2b157b5019cf38a19dc67d54bf38453 /scripts
parent70477371dc350746d10431d74f0f213a8d59924c (diff)
parent88a1b564a20e371e6be41b39b85673e9c1959491 (diff)
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/.gitignore1
-rw-r--r--scripts/Makefile1
-rwxr-xr-xscripts/extract-sys-certs.pl29
-rw-r--r--scripts/insert-sys-cert.c410
-rwxr-xr-xscripts/sign-file.c238
5 files changed, 580 insertions, 99 deletions
diff --git a/scripts/.gitignore b/scripts/.gitignore
index 1f78169d4254..e063daa3ec4a 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -13,3 +13,4 @@ sortextable
13asn1_compiler 13asn1_compiler
14extract-cert 14extract-cert
15sign-file 15sign-file
16insert-sys-cert
diff --git a/scripts/Makefile b/scripts/Makefile
index fd0d53d4a234..822ab4a6a4aa 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -19,6 +19,7 @@ hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable
19hostprogs-$(CONFIG_ASN1) += asn1_compiler 19hostprogs-$(CONFIG_ASN1) += asn1_compiler
20hostprogs-$(CONFIG_MODULE_SIG) += sign-file 20hostprogs-$(CONFIG_MODULE_SIG) += sign-file
21hostprogs-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert 21hostprogs-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert
22hostprogs-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert
22 23
23HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include 24HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include
24HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include 25HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include
diff --git a/scripts/extract-sys-certs.pl b/scripts/extract-sys-certs.pl
index d476e7d1fd88..8227ca10a494 100755
--- a/scripts/extract-sys-certs.pl
+++ b/scripts/extract-sys-certs.pl
@@ -91,13 +91,15 @@ print "Have $nr_symbols symbols\n";
91 91
92die "Can't find system certificate list" 92die "Can't find system certificate list"
93 unless (exists($symbols{"__cert_list_start"}) && 93 unless (exists($symbols{"__cert_list_start"}) &&
94 exists($symbols{"__cert_list_end"})); 94 exists($symbols{"system_certificate_list_size"}));
95 95
96my $start = Math::BigInt->new($symbols{"__cert_list_start"}); 96my $start = Math::BigInt->new($symbols{"__cert_list_start"});
97my $end = Math::BigInt->new($symbols{"__cert_list_end"}); 97my $end;
98my $size = $end - $start; 98my $size;
99my $size_sym = Math::BigInt->new($symbols{"system_certificate_list_size"});
99 100
100printf "Have %u bytes of certs at VMA 0x%x\n", $size, $start; 101open FD, "<$vmlinux" || die $vmlinux;
102binmode(FD);
101 103
102my $s = undef; 104my $s = undef;
103foreach my $sec (@sections) { 105foreach my $sec (@sections) {
@@ -110,11 +112,24 @@ foreach my $sec (@sections) {
110 next unless ($start >= $s_vma); 112 next unless ($start >= $s_vma);
111 next if ($start >= $s_vend); 113 next if ($start >= $s_vend);
112 114
113 die "Cert object partially overflows section $s_name\n" 115 die "Certificate list size was not found on the same section\n"
114 if ($end > $s_vend); 116 if ($size_sym < $s_vma || $size_sym > $s_vend);
115 117
116 die "Cert object in multiple sections: ", $s_name, " and ", $s->{name}, "\n" 118 die "Cert object in multiple sections: ", $s_name, " and ", $s->{name}, "\n"
117 if ($s); 119 if ($s);
120
121 my $size_off = $size_sym -$s_vma + $s_foff;
122 my $packed;
123 die $vmlinux if (!defined(sysseek(FD, $size_off, SEEK_SET)));
124 sysread(FD, $packed, 8);
125 $size = unpack 'L!', $packed;
126 $end = $start + $size;
127
128 printf "Have %u bytes of certs at VMA 0x%x\n", $size, $start;
129
130 die "Cert object partially overflows section $s_name\n"
131 if ($end > $s_vend);
132
118 $s = $sec; 133 $s = $sec;
119} 134}
120 135
@@ -127,8 +142,6 @@ my $foff = $start - $s->{vma} + $s->{foff};
127 142
128printf "Certificate list at file offset 0x%x\n", $foff; 143printf "Certificate list at file offset 0x%x\n", $foff;
129 144
130open FD, "<$vmlinux" || die $vmlinux;
131binmode(FD);
132die $vmlinux if (!defined(sysseek(FD, $foff, SEEK_SET))); 145die $vmlinux if (!defined(sysseek(FD, $foff, SEEK_SET)));
133my $buf = ""; 146my $buf = "";
134my $len = sysread(FD, $buf, $size); 147my $len = sysread(FD, $buf, $size);
diff --git a/scripts/insert-sys-cert.c b/scripts/insert-sys-cert.c
new file mode 100644
index 000000000000..8902836c2342
--- /dev/null
+++ b/scripts/insert-sys-cert.c
@@ -0,0 +1,410 @@
1/* Write the contents of the <certfile> into kernel symbol system_extra_cert
2 *
3 * Copyright (C) IBM Corporation, 2015
4 *
5 * Author: Mehmet Kayaalp <mkayaalp@linux.vnet.ibm.com>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 * Usage: insert-sys-cert [-s <System.map> -b <vmlinux> -c <certfile>
11 */
12
13#define _GNU_SOURCE
14#include <stdio.h>
15#include <ctype.h>
16#include <string.h>
17#include <limits.h>
18#include <stdbool.h>
19#include <errno.h>
20#include <stdlib.h>
21#include <stdarg.h>
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <sys/mman.h>
25#include <fcntl.h>
26#include <unistd.h>
27#include <elf.h>
28
29#define CERT_SYM "system_extra_cert"
30#define USED_SYM "system_extra_cert_used"
31#define LSIZE_SYM "system_certificate_list_size"
32
33#define info(format, args...) fprintf(stderr, "INFO: " format, ## args)
34#define warn(format, args...) fprintf(stdout, "WARNING: " format, ## args)
35#define err(format, args...) fprintf(stderr, "ERROR: " format, ## args)
36
37#if UINTPTR_MAX == 0xffffffff
38#define CURRENT_ELFCLASS ELFCLASS32
39#define Elf_Ehdr Elf32_Ehdr
40#define Elf_Shdr Elf32_Shdr
41#define Elf_Sym Elf32_Sym
42#else
43#define CURRENT_ELFCLASS ELFCLASS64
44#define Elf_Ehdr Elf64_Ehdr
45#define Elf_Shdr Elf64_Shdr
46#define Elf_Sym Elf64_Sym
47#endif
48
49static unsigned char endianness(void)
50{
51 uint16_t two_byte = 0x00FF;
52 uint8_t low_address = *((uint8_t *)&two_byte);
53
54 if (low_address == 0)
55 return ELFDATA2MSB;
56 else
57 return ELFDATA2LSB;
58}
59
60struct sym {
61 char *name;
62 unsigned long address;
63 unsigned long offset;
64 void *content;
65 int size;
66};
67
68static unsigned long get_offset_from_address(Elf_Ehdr *hdr, unsigned long addr)
69{
70 Elf_Shdr *x;
71 unsigned int i, num_sections;
72
73 x = (void *)hdr + hdr->e_shoff;
74 if (hdr->e_shnum == SHN_UNDEF)
75 num_sections = x[0].sh_size;
76 else
77 num_sections = hdr->e_shnum;
78
79 for (i = 1; i < num_sections; i++) {
80 unsigned long start = x[i].sh_addr;
81 unsigned long end = start + x[i].sh_size;
82 unsigned long offset = x[i].sh_offset;
83
84 if (addr >= start && addr <= end)
85 return addr - start + offset;
86 }
87 return 0;
88}
89
90
91#define LINE_SIZE 100
92
93static void get_symbol_from_map(Elf_Ehdr *hdr, FILE *f, char *name,
94 struct sym *s)
95{
96 char l[LINE_SIZE];
97 char *w, *p, *n;
98
99 s->size = 0;
100 s->address = 0;
101 s->offset = 0;
102 if (fseek(f, 0, SEEK_SET) != 0) {
103 perror("File seek failed");
104 exit(EXIT_FAILURE);
105 }
106 while (fgets(l, LINE_SIZE, f)) {
107 p = strchr(l, '\n');
108 if (!p) {
109 err("Missing line ending.\n");
110 return;
111 }
112 n = strstr(l, name);
113 if (n)
114 break;
115 }
116 if (!n) {
117 err("Unable to find symbol: %s\n", name);
118 return;
119 }
120 w = strchr(l, ' ');
121 if (!w)
122 return;
123
124 *w = '\0';
125 s->address = strtoul(l, NULL, 16);
126 if (s->address == 0)
127 return;
128 s->offset = get_offset_from_address(hdr, s->address);
129 s->name = name;
130 s->content = (void *)hdr + s->offset;
131}
132
133static Elf_Sym *find_elf_symbol(Elf_Ehdr *hdr, Elf_Shdr *symtab, char *name)
134{
135 Elf_Sym *sym, *symtab_start;
136 char *strtab, *symname;
137 unsigned int link;
138 Elf_Shdr *x;
139 int i, n;
140
141 x = (void *)hdr + hdr->e_shoff;
142 link = symtab->sh_link;
143 symtab_start = (void *)hdr + symtab->sh_offset;
144 n = symtab->sh_size / symtab->sh_entsize;
145 strtab = (void *)hdr + x[link].sh_offset;
146
147 for (i = 0; i < n; i++) {
148 sym = &symtab_start[i];
149 symname = strtab + sym->st_name;
150 if (strcmp(symname, name) == 0)
151 return sym;
152 }
153 err("Unable to find symbol: %s\n", name);
154 return NULL;
155}
156
157static void get_symbol_from_table(Elf_Ehdr *hdr, Elf_Shdr *symtab,
158 char *name, struct sym *s)
159{
160 Elf_Shdr *sec;
161 int secndx;
162 Elf_Sym *elf_sym;
163 Elf_Shdr *x;
164
165 x = (void *)hdr + hdr->e_shoff;
166 s->size = 0;
167 s->address = 0;
168 s->offset = 0;
169 elf_sym = find_elf_symbol(hdr, symtab, name);
170 if (!elf_sym)
171 return;
172 secndx = elf_sym->st_shndx;
173 if (!secndx)
174 return;
175 sec = &x[secndx];
176 s->size = elf_sym->st_size;
177 s->address = elf_sym->st_value;
178 s->offset = s->address - sec->sh_addr
179 + sec->sh_offset;
180 s->name = name;
181 s->content = (void *)hdr + s->offset;
182}
183
184static Elf_Shdr *get_symbol_table(Elf_Ehdr *hdr)
185{
186 Elf_Shdr *x;
187 unsigned int i, num_sections;
188
189 x = (void *)hdr + hdr->e_shoff;
190 if (hdr->e_shnum == SHN_UNDEF)
191 num_sections = x[0].sh_size;
192 else
193 num_sections = hdr->e_shnum;
194
195 for (i = 1; i < num_sections; i++)
196 if (x[i].sh_type == SHT_SYMTAB)
197 return &x[i];
198 return NULL;
199}
200
201static void *map_file(char *file_name, int *size)
202{
203 struct stat st;
204 void *map;
205 int fd;
206
207 fd = open(file_name, O_RDWR);
208 if (fd < 0) {
209 perror(file_name);
210 return NULL;
211 }
212 if (fstat(fd, &st)) {
213 perror("Could not determine file size");
214 close(fd);
215 return NULL;
216 }
217 *size = st.st_size;
218 map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
219 if (map == MAP_FAILED) {
220 perror("Mapping to memory failed");
221 close(fd);
222 return NULL;
223 }
224 close(fd);
225 return map;
226}
227
228static char *read_file(char *file_name, int *size)
229{
230 struct stat st;
231 char *buf;
232 int fd;
233
234 fd = open(file_name, O_RDONLY);
235 if (fd < 0) {
236 perror(file_name);
237 return NULL;
238 }
239 if (fstat(fd, &st)) {
240 perror("Could not determine file size");
241 close(fd);
242 return NULL;
243 }
244 *size = st.st_size;
245 buf = malloc(*size);
246 if (!buf) {
247 perror("Allocating memory failed");
248 close(fd);
249 return NULL;
250 }
251 if (read(fd, buf, *size) != *size) {
252 perror("File read failed");
253 close(fd);
254 return NULL;
255 }
256 close(fd);
257 return buf;
258}
259
260static void print_sym(Elf_Ehdr *hdr, struct sym *s)
261{
262 info("sym: %s\n", s->name);
263 info("addr: 0x%lx\n", s->address);
264 info("size: %d\n", s->size);
265 info("offset: 0x%lx\n", (unsigned long)s->offset);
266}
267
268static void print_usage(char *e)
269{
270 printf("Usage %s [-s <System.map>] -b <vmlinux> -c <certfile>\n", e);
271}
272
273int main(int argc, char **argv)
274{
275 char *system_map_file = NULL;
276 char *vmlinux_file = NULL;
277 char *cert_file = NULL;
278 int vmlinux_size;
279 int cert_size;
280 Elf_Ehdr *hdr;
281 char *cert;
282 FILE *system_map;
283 unsigned long *lsize;
284 int *used;
285 int opt;
286 Elf_Shdr *symtab = NULL;
287 struct sym cert_sym, lsize_sym, used_sym;
288
289 while ((opt = getopt(argc, argv, "b:c:s:")) != -1) {
290 switch (opt) {
291 case 's':
292 system_map_file = optarg;
293 break;
294 case 'b':
295 vmlinux_file = optarg;
296 break;
297 case 'c':
298 cert_file = optarg;
299 break;
300 default:
301 break;
302 }
303 }
304
305 if (!vmlinux_file || !cert_file) {
306 print_usage(argv[0]);
307 exit(EXIT_FAILURE);
308 }
309
310 cert = read_file(cert_file, &cert_size);
311 if (!cert)
312 exit(EXIT_FAILURE);
313
314 hdr = map_file(vmlinux_file, &vmlinux_size);
315 if (!hdr)
316 exit(EXIT_FAILURE);
317
318 if (vmlinux_size < sizeof(*hdr)) {
319 err("Invalid ELF file.\n");
320 exit(EXIT_FAILURE);
321 }
322
323 if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
324 (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
325 (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
326 (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
327 err("Invalid ELF magic.\n");
328 exit(EXIT_FAILURE);
329 }
330
331 if (hdr->e_ident[EI_CLASS] != CURRENT_ELFCLASS) {
332 err("ELF class mismatch.\n");
333 exit(EXIT_FAILURE);
334 }
335
336 if (hdr->e_ident[EI_DATA] != endianness()) {
337 err("ELF endian mismatch.\n");
338 exit(EXIT_FAILURE);
339 }
340
341 if (hdr->e_shoff > vmlinux_size) {
342 err("Could not find section header.\n");
343 exit(EXIT_FAILURE);
344 }
345
346 symtab = get_symbol_table(hdr);
347 if (!symtab) {
348 warn("Could not find the symbol table.\n");
349 if (!system_map_file) {
350 err("Please provide a System.map file.\n");
351 print_usage(argv[0]);
352 exit(EXIT_FAILURE);
353 }
354
355 system_map = fopen(system_map_file, "r");
356 if (!system_map) {
357 perror(system_map_file);
358 exit(EXIT_FAILURE);
359 }
360 get_symbol_from_map(hdr, system_map, CERT_SYM, &cert_sym);
361 get_symbol_from_map(hdr, system_map, USED_SYM, &used_sym);
362 get_symbol_from_map(hdr, system_map, LSIZE_SYM, &lsize_sym);
363 cert_sym.size = used_sym.address - cert_sym.address;
364 } else {
365 info("Symbol table found.\n");
366 if (system_map_file)
367 warn("System.map is ignored.\n");
368 get_symbol_from_table(hdr, symtab, CERT_SYM, &cert_sym);
369 get_symbol_from_table(hdr, symtab, USED_SYM, &used_sym);
370 get_symbol_from_table(hdr, symtab, LSIZE_SYM, &lsize_sym);
371 }
372
373 if (!cert_sym.offset || !lsize_sym.offset || !used_sym.offset)
374 exit(EXIT_FAILURE);
375
376 print_sym(hdr, &cert_sym);
377 print_sym(hdr, &used_sym);
378 print_sym(hdr, &lsize_sym);
379
380 lsize = (unsigned long *)lsize_sym.content;
381 used = (int *)used_sym.content;
382
383 if (cert_sym.size < cert_size) {
384 err("Certificate is larger than the reserved area!\n");
385 exit(EXIT_FAILURE);
386 }
387
388 /* If the existing cert is the same, don't overwrite */
389 if (cert_size == *used &&
390 strncmp(cert_sym.content, cert, cert_size) == 0) {
391 warn("Certificate was already inserted.\n");
392 exit(EXIT_SUCCESS);
393 }
394
395 if (*used > 0)
396 warn("Replacing previously inserted certificate.\n");
397
398 memcpy(cert_sym.content, cert, cert_size);
399 if (cert_size < cert_sym.size)
400 memset(cert_sym.content + cert_size,
401 0, cert_sym.size - cert_size);
402
403 *lsize = *lsize + cert_size - *used;
404 *used = cert_size;
405 info("Inserted the contents of %s into %lx.\n", cert_file,
406 cert_sym.address);
407 info("Used %d bytes out of %d bytes reserved.\n", *used,
408 cert_sym.size);
409 exit(EXIT_SUCCESS);
410}
diff --git a/scripts/sign-file.c b/scripts/sign-file.c
index 250a7a645033..d912d5a56a5e 100755
--- a/scripts/sign-file.c
+++ b/scripts/sign-file.c
@@ -2,9 +2,11 @@
2 * 2 *
3 * Copyright © 2014-2015 Red Hat, Inc. All Rights Reserved. 3 * Copyright © 2014-2015 Red Hat, Inc. All Rights Reserved.
4 * Copyright © 2015 Intel Corporation. 4 * Copyright © 2015 Intel Corporation.
5 * Copyright © 2016 Hewlett Packard Enterprise Development LP
5 * 6 *
6 * Authors: David Howells <dhowells@redhat.com> 7 * Authors: David Howells <dhowells@redhat.com>
7 * David Woodhouse <dwmw2@infradead.org> 8 * David Woodhouse <dwmw2@infradead.org>
9 * Juerg Haefliger <juerg.haefliger@hpe.com>
8 * 10 *
9 * This program is free software; you can redistribute it and/or 11 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License 12 * modify it under the terms of the GNU Lesser General Public License
@@ -39,7 +41,7 @@
39 * signing with anything other than SHA1 - so we're stuck with that if such is 41 * signing with anything other than SHA1 - so we're stuck with that if such is
40 * the case. 42 * the case.
41 */ 43 */
42#if OPENSSL_VERSION_NUMBER < 0x10000000L 44#if OPENSSL_VERSION_NUMBER < 0x10000000L || defined(OPENSSL_NO_CMS)
43#define USE_PKCS7 45#define USE_PKCS7
44#endif 46#endif
45#ifndef USE_PKCS7 47#ifndef USE_PKCS7
@@ -67,6 +69,8 @@ void format(void)
67{ 69{
68 fprintf(stderr, 70 fprintf(stderr,
69 "Usage: scripts/sign-file [-dp] <hash algo> <key> <x509> <module> [<dest>]\n"); 71 "Usage: scripts/sign-file [-dp] <hash algo> <key> <x509> <module> [<dest>]\n");
72 fprintf(stderr,
73 " scripts/sign-file -s <raw sig> <hash algo> <x509> <module> [<dest>]\n");
70 exit(2); 74 exit(2);
71} 75}
72 76
@@ -126,26 +130,84 @@ static int pem_pw_cb(char *buf, int len, int w, void *v)
126 return pwlen; 130 return pwlen;
127} 131}
128 132
133static EVP_PKEY *read_private_key(const char *private_key_name)
134{
135 EVP_PKEY *private_key;
136
137 if (!strncmp(private_key_name, "pkcs11:", 7)) {
138 ENGINE *e;
139
140 ENGINE_load_builtin_engines();
141 drain_openssl_errors();
142 e = ENGINE_by_id("pkcs11");
143 ERR(!e, "Load PKCS#11 ENGINE");
144 if (ENGINE_init(e))
145 drain_openssl_errors();
146 else
147 ERR(1, "ENGINE_init");
148 if (key_pass)
149 ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0),
150 "Set PKCS#11 PIN");
151 private_key = ENGINE_load_private_key(e, private_key_name,
152 NULL, NULL);
153 ERR(!private_key, "%s", private_key_name);
154 } else {
155 BIO *b;
156
157 b = BIO_new_file(private_key_name, "rb");
158 ERR(!b, "%s", private_key_name);
159 private_key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb,
160 NULL);
161 ERR(!private_key, "%s", private_key_name);
162 BIO_free(b);
163 }
164
165 return private_key;
166}
167
168static X509 *read_x509(const char *x509_name)
169{
170 X509 *x509;
171 BIO *b;
172
173 b = BIO_new_file(x509_name, "rb");
174 ERR(!b, "%s", x509_name);
175 x509 = d2i_X509_bio(b, NULL); /* Binary encoded X.509 */
176 if (!x509) {
177 ERR(BIO_reset(b) != 1, "%s", x509_name);
178 x509 = PEM_read_bio_X509(b, NULL, NULL,
179 NULL); /* PEM encoded X.509 */
180 if (x509)
181 drain_openssl_errors();
182 }
183 BIO_free(b);
184 ERR(!x509, "%s", x509_name);
185
186 return x509;
187}
188
129int main(int argc, char **argv) 189int main(int argc, char **argv)
130{ 190{
131 struct module_signature sig_info = { .id_type = PKEY_ID_PKCS7 }; 191 struct module_signature sig_info = { .id_type = PKEY_ID_PKCS7 };
132 char *hash_algo = NULL; 192 char *hash_algo = NULL;
133 char *private_key_name, *x509_name, *module_name, *dest_name; 193 char *private_key_name = NULL, *raw_sig_name = NULL;
194 char *x509_name, *module_name, *dest_name;
134 bool save_sig = false, replace_orig; 195 bool save_sig = false, replace_orig;
135 bool sign_only = false; 196 bool sign_only = false;
197 bool raw_sig = false;
136 unsigned char buf[4096]; 198 unsigned char buf[4096];
137 unsigned long module_size, sig_size; 199 unsigned long module_size, sig_size;
138 unsigned int use_signed_attrs; 200 unsigned int use_signed_attrs;
139 const EVP_MD *digest_algo; 201 const EVP_MD *digest_algo;
140 EVP_PKEY *private_key; 202 EVP_PKEY *private_key;
141#ifndef USE_PKCS7 203#ifndef USE_PKCS7
142 CMS_ContentInfo *cms; 204 CMS_ContentInfo *cms = NULL;
143 unsigned int use_keyid = 0; 205 unsigned int use_keyid = 0;
144#else 206#else
145 PKCS7 *pkcs7; 207 PKCS7 *pkcs7 = NULL;
146#endif 208#endif
147 X509 *x509; 209 X509 *x509;
148 BIO *b, *bd = NULL, *bm; 210 BIO *bd, *bm;
149 int opt, n; 211 int opt, n;
150 OpenSSL_add_all_algorithms(); 212 OpenSSL_add_all_algorithms();
151 ERR_load_crypto_strings(); 213 ERR_load_crypto_strings();
@@ -160,8 +222,9 @@ int main(int argc, char **argv)
160#endif 222#endif
161 223
162 do { 224 do {
163 opt = getopt(argc, argv, "dpk"); 225 opt = getopt(argc, argv, "sdpk");
164 switch (opt) { 226 switch (opt) {
227 case 's': raw_sig = true; break;
165 case 'p': save_sig = true; break; 228 case 'p': save_sig = true; break;
166 case 'd': sign_only = true; save_sig = true; break; 229 case 'd': sign_only = true; save_sig = true; break;
167#ifndef USE_PKCS7 230#ifndef USE_PKCS7
@@ -177,8 +240,13 @@ int main(int argc, char **argv)
177 if (argc < 4 || argc > 5) 240 if (argc < 4 || argc > 5)
178 format(); 241 format();
179 242
180 hash_algo = argv[0]; 243 if (raw_sig) {
181 private_key_name = argv[1]; 244 raw_sig_name = argv[0];
245 hash_algo = argv[1];
246 } else {
247 hash_algo = argv[0];
248 private_key_name = argv[1];
249 }
182 x509_name = argv[2]; 250 x509_name = argv[2];
183 module_name = argv[3]; 251 module_name = argv[3];
184 if (argc == 5) { 252 if (argc == 5) {
@@ -198,101 +266,74 @@ int main(int argc, char **argv)
198 } 266 }
199#endif 267#endif
200 268
201 /* Read the private key and the X.509 cert the PKCS#7 message 269 /* Open the module file */
202 * will point to.
203 */
204 if (!strncmp(private_key_name, "pkcs11:", 7)) {
205 ENGINE *e;
206
207 ENGINE_load_builtin_engines();
208 drain_openssl_errors();
209 e = ENGINE_by_id("pkcs11");
210 ERR(!e, "Load PKCS#11 ENGINE");
211 if (ENGINE_init(e))
212 drain_openssl_errors();
213 else
214 ERR(1, "ENGINE_init");
215 if (key_pass)
216 ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN");
217 private_key = ENGINE_load_private_key(e, private_key_name, NULL,
218 NULL);
219 ERR(!private_key, "%s", private_key_name);
220 } else {
221 b = BIO_new_file(private_key_name, "rb");
222 ERR(!b, "%s", private_key_name);
223 private_key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb, NULL);
224 ERR(!private_key, "%s", private_key_name);
225 BIO_free(b);
226 }
227
228 b = BIO_new_file(x509_name, "rb");
229 ERR(!b, "%s", x509_name);
230 x509 = d2i_X509_bio(b, NULL); /* Binary encoded X.509 */
231 if (!x509) {
232 ERR(BIO_reset(b) != 1, "%s", x509_name);
233 x509 = PEM_read_bio_X509(b, NULL, NULL, NULL); /* PEM encoded X.509 */
234 if (x509)
235 drain_openssl_errors();
236 }
237 BIO_free(b);
238 ERR(!x509, "%s", x509_name);
239
240 /* Open the destination file now so that we can shovel the module data
241 * across as we read it.
242 */
243 if (!sign_only) {
244 bd = BIO_new_file(dest_name, "wb");
245 ERR(!bd, "%s", dest_name);
246 }
247
248 /* Digest the module data. */
249 OpenSSL_add_all_digests();
250 display_openssl_errors(__LINE__);
251 digest_algo = EVP_get_digestbyname(hash_algo);
252 ERR(!digest_algo, "EVP_get_digestbyname");
253
254 bm = BIO_new_file(module_name, "rb"); 270 bm = BIO_new_file(module_name, "rb");
255 ERR(!bm, "%s", module_name); 271 ERR(!bm, "%s", module_name);
256 272
273 if (!raw_sig) {
274 /* Read the private key and the X.509 cert the PKCS#7 message
275 * will point to.
276 */
277 private_key = read_private_key(private_key_name);
278 x509 = read_x509(x509_name);
279
280 /* Digest the module data. */
281 OpenSSL_add_all_digests();
282 display_openssl_errors(__LINE__);
283 digest_algo = EVP_get_digestbyname(hash_algo);
284 ERR(!digest_algo, "EVP_get_digestbyname");
285
257#ifndef USE_PKCS7 286#ifndef USE_PKCS7
258 /* Load the signature message from the digest buffer. */ 287 /* Load the signature message from the digest buffer. */
259 cms = CMS_sign(NULL, NULL, NULL, NULL, 288 cms = CMS_sign(NULL, NULL, NULL, NULL,
260 CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY | CMS_DETACHED | CMS_STREAM); 289 CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY |
261 ERR(!cms, "CMS_sign"); 290 CMS_DETACHED | CMS_STREAM);
262 291 ERR(!cms, "CMS_sign");
263 ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo, 292
264 CMS_NOCERTS | CMS_BINARY | CMS_NOSMIMECAP | 293 ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo,
265 use_keyid | use_signed_attrs), 294 CMS_NOCERTS | CMS_BINARY |
266 "CMS_add1_signer"); 295 CMS_NOSMIMECAP | use_keyid |
267 ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) < 0, 296 use_signed_attrs),
268 "CMS_final"); 297 "CMS_add1_signer");
298 ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) < 0,
299 "CMS_final");
269 300
270#else 301#else
271 pkcs7 = PKCS7_sign(x509, private_key, NULL, bm, 302 pkcs7 = PKCS7_sign(x509, private_key, NULL, bm,
272 PKCS7_NOCERTS | PKCS7_BINARY | 303 PKCS7_NOCERTS | PKCS7_BINARY |
273 PKCS7_DETACHED | use_signed_attrs); 304 PKCS7_DETACHED | use_signed_attrs);
274 ERR(!pkcs7, "PKCS7_sign"); 305 ERR(!pkcs7, "PKCS7_sign");
275#endif 306#endif
276 307
277 if (save_sig) { 308 if (save_sig) {
278 char *sig_file_name; 309 char *sig_file_name;
310 BIO *b;
279 311
280 ERR(asprintf(&sig_file_name, "%s.p7s", module_name) < 0, 312 ERR(asprintf(&sig_file_name, "%s.p7s", module_name) < 0,
281 "asprintf"); 313 "asprintf");
282 b = BIO_new_file(sig_file_name, "wb"); 314 b = BIO_new_file(sig_file_name, "wb");
283 ERR(!b, "%s", sig_file_name); 315 ERR(!b, "%s", sig_file_name);
284#ifndef USE_PKCS7 316#ifndef USE_PKCS7
285 ERR(i2d_CMS_bio_stream(b, cms, NULL, 0) < 0, 317 ERR(i2d_CMS_bio_stream(b, cms, NULL, 0) < 0,
286 "%s", sig_file_name); 318 "%s", sig_file_name);
287#else 319#else
288 ERR(i2d_PKCS7_bio(b, pkcs7) < 0, 320 ERR(i2d_PKCS7_bio(b, pkcs7) < 0,
289 "%s", sig_file_name); 321 "%s", sig_file_name);
290#endif 322#endif
291 BIO_free(b); 323 BIO_free(b);
324 }
325
326 if (sign_only) {
327 BIO_free(bm);
328 return 0;
329 }
292 } 330 }
293 331
294 if (sign_only) 332 /* Open the destination file now so that we can shovel the module data
295 return 0; 333 * across as we read it.
334 */
335 bd = BIO_new_file(dest_name, "wb");
336 ERR(!bd, "%s", dest_name);
296 337
297 /* Append the marker and the PKCS#7 message to the destination file */ 338 /* Append the marker and the PKCS#7 message to the destination file */
298 ERR(BIO_reset(bm) < 0, "%s", module_name); 339 ERR(BIO_reset(bm) < 0, "%s", module_name);
@@ -300,14 +341,29 @@ int main(int argc, char **argv)
300 n > 0) { 341 n > 0) {
301 ERR(BIO_write(bd, buf, n) < 0, "%s", dest_name); 342 ERR(BIO_write(bd, buf, n) < 0, "%s", dest_name);
302 } 343 }
344 BIO_free(bm);
303 ERR(n < 0, "%s", module_name); 345 ERR(n < 0, "%s", module_name);
304 module_size = BIO_number_written(bd); 346 module_size = BIO_number_written(bd);
305 347
348 if (!raw_sig) {
306#ifndef USE_PKCS7 349#ifndef USE_PKCS7
307 ERR(i2d_CMS_bio_stream(bd, cms, NULL, 0) < 0, "%s", dest_name); 350 ERR(i2d_CMS_bio_stream(bd, cms, NULL, 0) < 0, "%s", dest_name);
308#else 351#else
309 ERR(i2d_PKCS7_bio(bd, pkcs7) < 0, "%s", dest_name); 352 ERR(i2d_PKCS7_bio(bd, pkcs7) < 0, "%s", dest_name);
310#endif 353#endif
354 } else {
355 BIO *b;
356
357 /* Read the raw signature file and write the data to the
358 * destination file
359 */
360 b = BIO_new_file(raw_sig_name, "rb");
361 ERR(!b, "%s", raw_sig_name);
362 while ((n = BIO_read(b, buf, sizeof(buf))), n > 0)
363 ERR(BIO_write(bd, buf, n) < 0, "%s", dest_name);
364 BIO_free(b);
365 }
366
311 sig_size = BIO_number_written(bd) - module_size; 367 sig_size = BIO_number_written(bd) - module_size;
312 sig_info.sig_len = htonl(sig_size); 368 sig_info.sig_len = htonl(sig_size);
313 ERR(BIO_write(bd, &sig_info, sizeof(sig_info)) < 0, "%s", dest_name); 369 ERR(BIO_write(bd, &sig_info, sizeof(sig_info)) < 0, "%s", dest_name);