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