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