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