Blame view
scripts/sign-file.c
9.76 KB
bc1c373dd MODSIGN: Provide ... |
1 2 |
/* Sign a module file using the given key. * |
9552c7aeb modsign: Make sig... |
3 |
* Copyright © 2014-2016 Red Hat, Inc. All Rights Reserved. |
09a77a885 modsign: Fix GPL/... |
4 |
* Copyright © 2015 Intel Corporation. |
e5a2e3c84 scripts/sign-file... |
5 |
* Copyright © 2016 Hewlett Packard Enterprise Development LP |
09a77a885 modsign: Fix GPL/... |
6 7 8 |
* * Authors: David Howells <dhowells@redhat.com> * David Woodhouse <dwmw2@infradead.org> |
e5a2e3c84 scripts/sign-file... |
9 |
* Juerg Haefliger <juerg.haefliger@hpe.com> |
bc1c373dd MODSIGN: Provide ... |
10 11 |
* * This program is free software; you can redistribute it and/or |
09a77a885 modsign: Fix GPL/... |
12 13 14 |
* 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 licence, or (at your option) any later version. |
bc1c373dd MODSIGN: Provide ... |
15 16 17 18 19 20 21 22 23 24 |
*/ #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <stdbool.h> #include <string.h> #include <getopt.h> #include <err.h> #include <arpa/inet.h> |
283e8ba2d MODSIGN: Change f... |
25 |
#include <openssl/opensslv.h> |
bc1c373dd MODSIGN: Provide ... |
26 27 28 |
#include <openssl/bio.h> #include <openssl/evp.h> #include <openssl/pem.h> |
bc1c373dd MODSIGN: Provide ... |
29 |
#include <openssl/err.h> |
6e3e281f3 modsign: Allow si... |
30 |
#include <openssl/engine.h> |
bc1c373dd MODSIGN: Provide ... |
31 |
|
283e8ba2d MODSIGN: Change f... |
32 33 34 35 36 37 38 39 40 41 42 43 |
/* * Use CMS if we have openssl-1.0.0 or newer available - otherwise we have to * assume that it's not available and its header file is missing and that we * should use PKCS#7 instead. Switching to the older PKCS#7 format restricts * the options we have on specifying the X.509 certificate we want. * * Further, older versions of OpenSSL don't support manually adding signers to * the PKCS#7 message so have to accept that we get a certificate included in * the signature message. Nor do such older versions of OpenSSL support * signing with anything other than SHA1 - so we're stuck with that if such is * the case. */ |
f86880175 sign-file: fix bu... |
44 45 46 |
#if defined(LIBRESSL_VERSION_NUMBER) || \ OPENSSL_VERSION_NUMBER < 0x10000000L || \ defined(OPENSSL_NO_CMS) |
283e8ba2d MODSIGN: Change f... |
47 48 49 50 51 52 53 |
#define USE_PKCS7 #endif #ifndef USE_PKCS7 #include <openssl/cms.h> #else #include <openssl/pkcs7.h> #endif |
bc1c373dd MODSIGN: Provide ... |
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
struct module_signature { uint8_t algo; /* Public-key crypto algorithm [0] */ uint8_t hash; /* Digest algorithm [0] */ uint8_t id_type; /* Key identifier type [PKEY_ID_PKCS7] */ uint8_t signer_len; /* Length of signer's name [0] */ uint8_t key_id_len; /* Length of key identifier [0] */ uint8_t __pad[3]; uint32_t sig_len; /* Length of signature data */ }; #define PKEY_ID_PKCS7 2 static char magic_number[] = "~Module signature appended~ "; static __attribute__((noreturn)) void format(void) { fprintf(stderr, "Usage: scripts/sign-file [-dp] <hash algo> <key> <x509> <module> [<dest>] "); |
e5a2e3c84 scripts/sign-file... |
75 76 77 |
fprintf(stderr, " scripts/sign-file -s <raw sig> <hash algo> <x509> <module> [<dest>] "); |
bc1c373dd MODSIGN: Provide ... |
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
exit(2); } static void display_openssl_errors(int l) { const char *file; char buf[120]; int e, line; if (ERR_peek_error() == 0) return; fprintf(stderr, "At main.c:%d: ", l); while ((e = ERR_get_error_line(&file, &line))) { ERR_error_string(e, buf); fprintf(stderr, "- SSL %s: %s:%d ", buf, file, line); } } static void drain_openssl_errors(void) { const char *file; int line; if (ERR_peek_error() == 0) return; while (ERR_get_error_line(&file, &line)) {} } #define ERR(cond, fmt, ...) \ do { \ bool __cond = (cond); \ display_openssl_errors(__LINE__); \ if (__cond) { \ err(1, fmt, ## __VA_ARGS__); \ } \ } while(0) |
af1eb2913 modsign: Allow pa... |
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
static const char *key_pass; static int pem_pw_cb(char *buf, int len, int w, void *v) { int pwlen; if (!key_pass) return -1; pwlen = strlen(key_pass); if (pwlen >= len) return -1; strcpy(buf, key_pass); /* If it's wrong, don't keep trying it. */ key_pass = NULL; return pwlen; } |
e5a2e3c84 scripts/sign-file... |
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
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) { |
9552c7aeb modsign: Make sig... |
174 |
unsigned char buf[2]; |
e5a2e3c84 scripts/sign-file... |
175 176 |
X509 *x509; BIO *b; |
9552c7aeb modsign: Make sig... |
177 |
int n; |
e5a2e3c84 scripts/sign-file... |
178 179 180 |
b = BIO_new_file(x509_name, "rb"); ERR(!b, "%s", x509_name); |
9552c7aeb modsign: Make sig... |
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
/* Look at the first two bytes of the file to determine the encoding */ n = BIO_read(b, buf, 2); if (n != 2) { if (BIO_should_retry(b)) { fprintf(stderr, "%s: Read wanted retry ", x509_name); exit(1); } if (n >= 0) { fprintf(stderr, "%s: Short read ", x509_name); exit(1); } ERR(1, "%s", x509_name); |
e5a2e3c84 scripts/sign-file... |
196 |
} |
9552c7aeb modsign: Make sig... |
197 198 199 200 201 202 203 204 205 |
ERR(BIO_reset(b) != 0, "%s", x509_name); if (buf[0] == 0x30 && buf[1] >= 0x81 && buf[1] <= 0x84) /* Assume raw DER encoded X.509 */ x509 = d2i_X509_bio(b, NULL); else /* Assume PEM encoded X.509 */ x509 = PEM_read_bio_X509(b, NULL, NULL, NULL); |
e5a2e3c84 scripts/sign-file... |
206 207 208 209 210 |
BIO_free(b); ERR(!x509, "%s", x509_name); return x509; } |
bc1c373dd MODSIGN: Provide ... |
211 212 213 214 |
int main(int argc, char **argv) { struct module_signature sig_info = { .id_type = PKEY_ID_PKCS7 }; char *hash_algo = NULL; |
e5a2e3c84 scripts/sign-file... |
215 216 |
char *private_key_name = NULL, *raw_sig_name = NULL; char *x509_name, *module_name, *dest_name; |
283e8ba2d MODSIGN: Change f... |
217 |
bool save_sig = false, replace_orig; |
23dfbbabb sign-file: Add op... |
218 |
bool sign_only = false; |
e5a2e3c84 scripts/sign-file... |
219 |
bool raw_sig = false; |
bc1c373dd MODSIGN: Provide ... |
220 |
unsigned char buf[4096]; |
283e8ba2d MODSIGN: Change f... |
221 222 |
unsigned long module_size, sig_size; unsigned int use_signed_attrs; |
bc1c373dd MODSIGN: Provide ... |
223 224 |
const EVP_MD *digest_algo; EVP_PKEY *private_key; |
283e8ba2d MODSIGN: Change f... |
225 |
#ifndef USE_PKCS7 |
e5a2e3c84 scripts/sign-file... |
226 |
CMS_ContentInfo *cms = NULL; |
283e8ba2d MODSIGN: Change f... |
227 228 |
unsigned int use_keyid = 0; #else |
e5a2e3c84 scripts/sign-file... |
229 |
PKCS7 *pkcs7 = NULL; |
283e8ba2d MODSIGN: Change f... |
230 |
#endif |
bc1c373dd MODSIGN: Provide ... |
231 |
X509 *x509; |
e5a2e3c84 scripts/sign-file... |
232 |
BIO *bd, *bm; |
bc1c373dd MODSIGN: Provide ... |
233 |
int opt, n; |
af1eb2913 modsign: Allow pa... |
234 |
OpenSSL_add_all_algorithms(); |
bc1c373dd MODSIGN: Provide ... |
235 236 |
ERR_load_crypto_strings(); ERR_clear_error(); |
af1eb2913 modsign: Allow pa... |
237 |
key_pass = getenv("KBUILD_SIGN_PIN"); |
283e8ba2d MODSIGN: Change f... |
238 239 240 241 242 |
#ifndef USE_PKCS7 use_signed_attrs = CMS_NOATTR; #else use_signed_attrs = PKCS7_NOATTR; #endif |
bc1c373dd MODSIGN: Provide ... |
243 |
do { |
e5a2e3c84 scripts/sign-file... |
244 |
opt = getopt(argc, argv, "sdpk"); |
bc1c373dd MODSIGN: Provide ... |
245 |
switch (opt) { |
e5a2e3c84 scripts/sign-file... |
246 |
case 's': raw_sig = true; break; |
283e8ba2d MODSIGN: Change f... |
247 248 249 |
case 'p': save_sig = true; break; case 'd': sign_only = true; save_sig = true; break; #ifndef USE_PKCS7 |
ed8c20762 sign-file: Genera... |
250 |
case 'k': use_keyid = CMS_USE_KEYID; break; |
283e8ba2d MODSIGN: Change f... |
251 |
#endif |
bc1c373dd MODSIGN: Provide ... |
252 253 254 255 256 257 258 259 260 |
case -1: break; default: format(); } } while (opt != -1); argc -= optind; argv += optind; if (argc < 4 || argc > 5) format(); |
e5a2e3c84 scripts/sign-file... |
261 262 263 264 265 266 267 |
if (raw_sig) { raw_sig_name = argv[0]; hash_algo = argv[1]; } else { hash_algo = argv[0]; private_key_name = argv[1]; } |
bc1c373dd MODSIGN: Provide ... |
268 269 |
x509_name = argv[2]; module_name = argv[3]; |
efcae7c93 sign-file: Fix in... |
270 |
if (argc == 5 && strcmp(argv[3], argv[4]) != 0) { |
bc1c373dd MODSIGN: Provide ... |
271 272 273 274 275 276 277 |
dest_name = argv[4]; replace_orig = false; } else { ERR(asprintf(&dest_name, "%s.~signed~", module_name) < 0, "asprintf"); replace_orig = true; } |
283e8ba2d MODSIGN: Change f... |
278 279 280 281 282 283 284 285 |
#ifdef USE_PKCS7 if (strcmp(hash_algo, "sha1") != 0) { fprintf(stderr, "sign-file: %s only supports SHA1 signing ", OPENSSL_VERSION_TEXT); exit(3); } #endif |
e5a2e3c84 scripts/sign-file... |
286 |
/* Open the module file */ |
bc1c373dd MODSIGN: Provide ... |
287 288 |
bm = BIO_new_file(module_name, "rb"); ERR(!bm, "%s", module_name); |
e5a2e3c84 scripts/sign-file... |
289 290 291 292 293 294 295 296 297 298 299 300 |
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"); |
283e8ba2d MODSIGN: Change f... |
301 |
#ifndef USE_PKCS7 |
e5a2e3c84 scripts/sign-file... |
302 303 304 305 306 307 308 309 310 311 312 313 314 |
/* 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"); |
bc1c373dd MODSIGN: Provide ... |
315 |
|
283e8ba2d MODSIGN: Change f... |
316 |
#else |
e5a2e3c84 scripts/sign-file... |
317 318 319 320 |
pkcs7 = PKCS7_sign(x509, private_key, NULL, bm, PKCS7_NOCERTS | PKCS7_BINARY | PKCS7_DETACHED | use_signed_attrs); ERR(!pkcs7, "PKCS7_sign"); |
283e8ba2d MODSIGN: Change f... |
321 |
#endif |
bc1c373dd MODSIGN: Provide ... |
322 |
|
e5a2e3c84 scripts/sign-file... |
323 324 325 |
if (save_sig) { char *sig_file_name; BIO *b; |
283e8ba2d MODSIGN: Change f... |
326 |
|
e5a2e3c84 scripts/sign-file... |
327 328 329 330 |
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); |
283e8ba2d MODSIGN: Change f... |
331 |
#ifndef USE_PKCS7 |
e5a2e3c84 scripts/sign-file... |
332 333 |
ERR(i2d_CMS_bio_stream(b, cms, NULL, 0) < 0, "%s", sig_file_name); |
283e8ba2d MODSIGN: Change f... |
334 |
#else |
e5a2e3c84 scripts/sign-file... |
335 336 |
ERR(i2d_PKCS7_bio(b, pkcs7) < 0, "%s", sig_file_name); |
283e8ba2d MODSIGN: Change f... |
337 |
#endif |
e5a2e3c84 scripts/sign-file... |
338 339 340 341 342 343 344 |
BIO_free(b); } if (sign_only) { BIO_free(bm); return 0; } |
bc1c373dd MODSIGN: Provide ... |
345 |
} |
e5a2e3c84 scripts/sign-file... |
346 347 348 349 350 |
/* 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); |
23dfbbabb sign-file: Add op... |
351 |
|
bc1c373dd MODSIGN: Provide ... |
352 353 354 355 356 357 |
/* Append the marker and the PKCS#7 message to the destination file */ ERR(BIO_reset(bm) < 0, "%s", module_name); while ((n = BIO_read(bm, buf, sizeof(buf))), n > 0) { ERR(BIO_write(bd, buf, n) < 0, "%s", dest_name); } |
e5a2e3c84 scripts/sign-file... |
358 |
BIO_free(bm); |
bc1c373dd MODSIGN: Provide ... |
359 360 |
ERR(n < 0, "%s", module_name); module_size = BIO_number_written(bd); |
e5a2e3c84 scripts/sign-file... |
361 |
if (!raw_sig) { |
283e8ba2d MODSIGN: Change f... |
362 |
#ifndef USE_PKCS7 |
e5a2e3c84 scripts/sign-file... |
363 |
ERR(i2d_CMS_bio_stream(bd, cms, NULL, 0) < 0, "%s", dest_name); |
283e8ba2d MODSIGN: Change f... |
364 |
#else |
e5a2e3c84 scripts/sign-file... |
365 |
ERR(i2d_PKCS7_bio(bd, pkcs7) < 0, "%s", dest_name); |
283e8ba2d MODSIGN: Change f... |
366 |
#endif |
e5a2e3c84 scripts/sign-file... |
367 368 369 370 371 372 373 374 375 376 377 378 |
} 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); } |
283e8ba2d MODSIGN: Change f... |
379 380 |
sig_size = BIO_number_written(bd) - module_size; sig_info.sig_len = htonl(sig_size); |
bc1c373dd MODSIGN: Provide ... |
381 382 383 384 385 386 387 388 389 390 391 |
ERR(BIO_write(bd, &sig_info, sizeof(sig_info)) < 0, "%s", dest_name); ERR(BIO_write(bd, magic_number, sizeof(magic_number) - 1) < 0, "%s", dest_name); ERR(BIO_free(bd) < 0, "%s", dest_name); /* Finally, if we're signing in place, replace the original. */ if (replace_orig) ERR(rename(dest_name, module_name) < 0, "%s", dest_name); return 0; } |