Blame view
scripts/sign-file.c
9.69 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. */ |
41693d1c0 sign-file: fix bu... |
44 |
#if OPENSSL_VERSION_NUMBER < 0x10000000L || defined(OPENSSL_NO_CMS) |
283e8ba2d MODSIGN: Change f... |
45 46 47 48 49 50 51 |
#define USE_PKCS7 #endif #ifndef USE_PKCS7 #include <openssl/cms.h> #else #include <openssl/pkcs7.h> #endif |
bc1c373dd MODSIGN: Provide ... |
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
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... |
73 74 75 |
fprintf(stderr, " scripts/sign-file -s <raw sig> <hash algo> <x509> <module> [<dest>] "); |
bc1c373dd MODSIGN: Provide ... |
76 77 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 |
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... |
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
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... |
135 136 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 |
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... |
172 |
unsigned char buf[2]; |
e5a2e3c84 scripts/sign-file... |
173 174 |
X509 *x509; BIO *b; |
9552c7aeb modsign: Make sig... |
175 |
int n; |
e5a2e3c84 scripts/sign-file... |
176 177 178 |
b = BIO_new_file(x509_name, "rb"); ERR(!b, "%s", x509_name); |
9552c7aeb modsign: Make sig... |
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
/* 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... |
194 |
} |
9552c7aeb modsign: Make sig... |
195 196 197 198 199 200 201 202 203 |
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... |
204 205 206 207 208 |
BIO_free(b); ERR(!x509, "%s", x509_name); return x509; } |
bc1c373dd MODSIGN: Provide ... |
209 210 211 212 |
int main(int argc, char **argv) { struct module_signature sig_info = { .id_type = PKEY_ID_PKCS7 }; char *hash_algo = NULL; |
e5a2e3c84 scripts/sign-file... |
213 214 |
char *private_key_name = NULL, *raw_sig_name = NULL; char *x509_name, *module_name, *dest_name; |
283e8ba2d MODSIGN: Change f... |
215 |
bool save_sig = false, replace_orig; |
23dfbbabb sign-file: Add op... |
216 |
bool sign_only = false; |
e5a2e3c84 scripts/sign-file... |
217 |
bool raw_sig = false; |
bc1c373dd MODSIGN: Provide ... |
218 |
unsigned char buf[4096]; |
283e8ba2d MODSIGN: Change f... |
219 220 |
unsigned long module_size, sig_size; unsigned int use_signed_attrs; |
bc1c373dd MODSIGN: Provide ... |
221 222 |
const EVP_MD *digest_algo; EVP_PKEY *private_key; |
283e8ba2d MODSIGN: Change f... |
223 |
#ifndef USE_PKCS7 |
e5a2e3c84 scripts/sign-file... |
224 |
CMS_ContentInfo *cms = NULL; |
283e8ba2d MODSIGN: Change f... |
225 226 |
unsigned int use_keyid = 0; #else |
e5a2e3c84 scripts/sign-file... |
227 |
PKCS7 *pkcs7 = NULL; |
283e8ba2d MODSIGN: Change f... |
228 |
#endif |
bc1c373dd MODSIGN: Provide ... |
229 |
X509 *x509; |
e5a2e3c84 scripts/sign-file... |
230 |
BIO *bd, *bm; |
bc1c373dd MODSIGN: Provide ... |
231 |
int opt, n; |
af1eb2913 modsign: Allow pa... |
232 |
OpenSSL_add_all_algorithms(); |
bc1c373dd MODSIGN: Provide ... |
233 234 |
ERR_load_crypto_strings(); ERR_clear_error(); |
af1eb2913 modsign: Allow pa... |
235 |
key_pass = getenv("KBUILD_SIGN_PIN"); |
283e8ba2d MODSIGN: Change f... |
236 237 238 239 240 |
#ifndef USE_PKCS7 use_signed_attrs = CMS_NOATTR; #else use_signed_attrs = PKCS7_NOATTR; #endif |
bc1c373dd MODSIGN: Provide ... |
241 |
do { |
e5a2e3c84 scripts/sign-file... |
242 |
opt = getopt(argc, argv, "sdpk"); |
bc1c373dd MODSIGN: Provide ... |
243 |
switch (opt) { |
e5a2e3c84 scripts/sign-file... |
244 |
case 's': raw_sig = true; break; |
283e8ba2d MODSIGN: Change f... |
245 246 247 |
case 'p': save_sig = true; break; case 'd': sign_only = true; save_sig = true; break; #ifndef USE_PKCS7 |
ed8c20762 sign-file: Genera... |
248 |
case 'k': use_keyid = CMS_USE_KEYID; break; |
283e8ba2d MODSIGN: Change f... |
249 |
#endif |
bc1c373dd MODSIGN: Provide ... |
250 251 252 253 254 255 256 257 258 |
case -1: break; default: format(); } } while (opt != -1); argc -= optind; argv += optind; if (argc < 4 || argc > 5) format(); |
e5a2e3c84 scripts/sign-file... |
259 260 261 262 263 264 265 |
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 ... |
266 267 268 269 270 271 272 273 274 275 |
x509_name = argv[2]; module_name = argv[3]; if (argc == 5) { 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... |
276 277 278 279 280 281 282 283 |
#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... |
284 |
/* Open the module file */ |
bc1c373dd MODSIGN: Provide ... |
285 286 |
bm = BIO_new_file(module_name, "rb"); ERR(!bm, "%s", module_name); |
e5a2e3c84 scripts/sign-file... |
287 288 289 290 291 292 293 294 295 296 297 298 |
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... |
299 |
#ifndef USE_PKCS7 |
e5a2e3c84 scripts/sign-file... |
300 301 302 303 304 305 306 307 308 309 310 311 312 |
/* 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 ... |
313 |
|
283e8ba2d MODSIGN: Change f... |
314 |
#else |
e5a2e3c84 scripts/sign-file... |
315 316 317 318 |
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... |
319 |
#endif |
bc1c373dd MODSIGN: Provide ... |
320 |
|
e5a2e3c84 scripts/sign-file... |
321 322 323 |
if (save_sig) { char *sig_file_name; BIO *b; |
283e8ba2d MODSIGN: Change f... |
324 |
|
e5a2e3c84 scripts/sign-file... |
325 326 327 328 |
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... |
329 |
#ifndef USE_PKCS7 |
e5a2e3c84 scripts/sign-file... |
330 331 |
ERR(i2d_CMS_bio_stream(b, cms, NULL, 0) < 0, "%s", sig_file_name); |
283e8ba2d MODSIGN: Change f... |
332 |
#else |
e5a2e3c84 scripts/sign-file... |
333 334 |
ERR(i2d_PKCS7_bio(b, pkcs7) < 0, "%s", sig_file_name); |
283e8ba2d MODSIGN: Change f... |
335 |
#endif |
e5a2e3c84 scripts/sign-file... |
336 337 338 339 340 341 342 |
BIO_free(b); } if (sign_only) { BIO_free(bm); return 0; } |
bc1c373dd MODSIGN: Provide ... |
343 |
} |
e5a2e3c84 scripts/sign-file... |
344 345 346 347 348 |
/* 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... |
349 |
|
bc1c373dd MODSIGN: Provide ... |
350 351 352 353 354 355 |
/* 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... |
356 |
BIO_free(bm); |
bc1c373dd MODSIGN: Provide ... |
357 358 |
ERR(n < 0, "%s", module_name); module_size = BIO_number_written(bd); |
e5a2e3c84 scripts/sign-file... |
359 |
if (!raw_sig) { |
283e8ba2d MODSIGN: Change f... |
360 |
#ifndef USE_PKCS7 |
e5a2e3c84 scripts/sign-file... |
361 |
ERR(i2d_CMS_bio_stream(bd, cms, NULL, 0) < 0, "%s", dest_name); |
283e8ba2d MODSIGN: Change f... |
362 |
#else |
e5a2e3c84 scripts/sign-file... |
363 |
ERR(i2d_PKCS7_bio(bd, pkcs7) < 0, "%s", dest_name); |
283e8ba2d MODSIGN: Change f... |
364 |
#endif |
e5a2e3c84 scripts/sign-file... |
365 366 367 368 369 370 371 372 373 374 375 376 |
} 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... |
377 378 |
sig_size = BIO_number_written(bd) - module_size; sig_info.sig_len = htonl(sig_size); |
bc1c373dd MODSIGN: Provide ... |
379 380 381 382 383 384 385 386 387 388 389 |
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; } |