Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359/* Sign a module file using the given key. * * Copyright © 2014-2016 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 * as published by the Free Software Foundation; either version 2.1 * of the licence, or (at your option) any later version. */#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>#include <openssl/opensslv.h>#include <openssl/bio.h>#include <openssl/cms.h>#include <openssl/evp.h>#include <openssl/pem.h>#include <openssl/err.h>#if OPENSSL_VERSION_NUMBER >= 0x30000000L# define USE_PKCS11_PROVIDER# include <openssl/provider.h># include <openssl/store.h>#else# if !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_DEPRECATED_3_0)# define USE_PKCS11_ENGINE# include <openssl/engine.h># endif#endif#include "ssl-common.h"
#include <linux/module_signature.h>
static __attribute__((noreturn))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);}
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;}
static EVP_PKEY *read_private_key_pkcs11(const char *private_key_name){ EVP_PKEY *private_key = NULL;#ifdef USE_PKCS11_PROVIDER OSSL_STORE_CTX *store;
if (!OSSL_PROVIDER_try_load(NULL, "pkcs11", true)) ERR(1, "OSSL_PROVIDER_try_load(pkcs11)"); if (!OSSL_PROVIDER_try_load(NULL, "default", true)) ERR(1, "OSSL_PROVIDER_try_load(default)");
store = OSSL_STORE_open(private_key_name, NULL, NULL, NULL, NULL); ERR(!store, "OSSL_STORE_open");
while (!OSSL_STORE_eof(store)) { OSSL_STORE_INFO *info = OSSL_STORE_load(store);
if (!info) { drain_openssl_errors(__LINE__, 0); continue; } if (OSSL_STORE_INFO_get_type(info) == OSSL_STORE_INFO_PKEY) { private_key = OSSL_STORE_INFO_get1_PKEY(info); ERR(!private_key, "OSSL_STORE_INFO_get1_PKEY"); } OSSL_STORE_INFO_free(info); if (private_key) break; } OSSL_STORE_close(store);#elif defined(USE_PKCS11_ENGINE) ENGINE *e;
ENGINE_load_builtin_engines(); drain_openssl_errors(__LINE__, 1); e = ENGINE_by_id("pkcs11"); ERR(!e, "Load PKCS#11 ENGINE"); if (ENGINE_init(e)) drain_openssl_errors(__LINE__, 1); 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 fprintf(stderr, "no pkcs11 engine/provider available\n"); exit(1);#endif return private_key;}
static EVP_PKEY *read_private_key(const char *private_key_name){ if (!strncmp(private_key_name, "pkcs11:", 7)) { return read_private_key_pkcs11(private_key_name); } else { EVP_PKEY *private_key; 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){ unsigned char buf[2]; X509 *x509; BIO *b; int n;
b = BIO_new_file(x509_name, "rb"); ERR(!b, "%s", x509_name);
/* 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\n", x509_name); exit(1); } if (n >= 0) { fprintf(stderr, "%s: Short read\n", x509_name); exit(1); } ERR(1, "%s", x509_name); }
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);
BIO_free(b); ERR(!x509, "%s", x509_name);
return x509;}
int main(int argc, char **argv){ struct module_signature sig_info = { .id_type = MODULE_SIGNATURE_TYPE_PKCS7 }; char *hash_algo = NULL; 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; const EVP_MD *digest_algo; EVP_PKEY *private_key; CMS_ContentInfo *cms = NULL; unsigned int use_keyid = 0; X509 *x509; BIO *bd, *bm; int opt, n; OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); ERR_clear_error();
key_pass = getenv("KBUILD_SIGN_PIN");
do { 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; case 'k': use_keyid = CMS_USE_KEYID; break; case -1: break; default: format(); } } while (opt != -1);
argc -= optind; argv += optind; if (argc < 4 || argc > 5) format();
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 && strcmp(argv[3], argv[4]) != 0) { dest_name = argv[4]; replace_orig = false; } else { ERR(asprintf(&dest_name, "%s.~signed~", module_name) < 0, "asprintf"); replace_orig = true; }
/* 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(); drain_openssl_errors(__LINE__, 0); digest_algo = EVP_get_digestbyname(hash_algo); ERR(!digest_algo, "EVP_get_digestbyname");
unsigned int flags = CMS_NOCERTS | CMS_NOATTR | CMS_PARTIAL | CMS_BINARY | CMS_DETACHED | CMS_STREAM | CMS_NOSMIMECAP |#ifdef CMS_NO_SIGNING_TIME CMS_NO_SIGNING_TIME |#endif use_keyid;
#if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_VERSION_NUMBER < 0x40000000L if (EVP_PKEY_is_a(private_key, "ML-DSA-44") || EVP_PKEY_is_a(private_key, "ML-DSA-65") || EVP_PKEY_is_a(private_key, "ML-DSA-87")) { /* ML-DSA + CMS_NOATTR is not supported in openssl-3.5 * and before. */ flags &= ~CMS_NOATTR; }#endif
/* Load the signature message from the digest buffer. */ cms = CMS_sign(NULL, NULL, NULL, NULL, flags); ERR(!cms, "CMS_sign");
ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo, flags), "CMS_add1_signer"); ERR(CMS_final(cms, bm, NULL, flags) != 1, "CMS_final");
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(i2d_CMS_bio_stream(b, cms, NULL, 0) != 1, "%s", sig_file_name); BIO_free(b); }
if (sign_only) { BIO_free(bm); 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); while ((n = BIO_read(bm, buf, sizeof(buf))), 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) { ERR(i2d_CMS_bio_stream(bd, cms, NULL, 0) != 1, "%s", dest_name); } 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); ERR(BIO_write(bd, MODULE_SIGNATURE_MARKER, sizeof(MODULE_SIGNATURE_MARKER) - 1) < 0, "%s", dest_name);
ERR(BIO_free(bd) != 1, "%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;}