Back to home page

LXR

 
 

    


0001 /* Sign a module file using the given key.
0002  *
0003  * Copyright © 2014-2016 Red Hat, Inc. All Rights Reserved.
0004  * Copyright © 2015      Intel Corporation.
0005  * Copyright © 2016      Hewlett Packard Enterprise Development LP
0006  *
0007  * Authors: David Howells <dhowells@redhat.com>
0008  *          David Woodhouse <dwmw2@infradead.org>
0009  *          Juerg Haefliger <juerg.haefliger@hpe.com>
0010  *
0011  * This program is free software; you can redistribute it and/or
0012  * modify it under the terms of the GNU Lesser General Public License
0013  * as published by the Free Software Foundation; either version 2.1
0014  * of the licence, or (at your option) any later version.
0015  */
0016 #define _GNU_SOURCE
0017 #include <stdio.h>
0018 #include <stdlib.h>
0019 #include <stdint.h>
0020 #include <stdbool.h>
0021 #include <string.h>
0022 #include <getopt.h>
0023 #include <err.h>
0024 #include <arpa/inet.h>
0025 #include <openssl/opensslv.h>
0026 #include <openssl/bio.h>
0027 #include <openssl/evp.h>
0028 #include <openssl/pem.h>
0029 #include <openssl/err.h>
0030 #include <openssl/engine.h>
0031 
0032 /*
0033  * Use CMS if we have openssl-1.0.0 or newer available - otherwise we have to
0034  * assume that it's not available and its header file is missing and that we
0035  * should use PKCS#7 instead.  Switching to the older PKCS#7 format restricts
0036  * the options we have on specifying the X.509 certificate we want.
0037  *
0038  * Further, older versions of OpenSSL don't support manually adding signers to
0039  * the PKCS#7 message so have to accept that we get a certificate included in
0040  * the signature message.  Nor do such older versions of OpenSSL support
0041  * signing with anything other than SHA1 - so we're stuck with that if such is
0042  * the case.
0043  */
0044 #if OPENSSL_VERSION_NUMBER < 0x10000000L || defined(OPENSSL_NO_CMS)
0045 #define USE_PKCS7
0046 #endif
0047 #ifndef USE_PKCS7
0048 #include <openssl/cms.h>
0049 #else
0050 #include <openssl/pkcs7.h>
0051 #endif
0052 
0053 struct module_signature {
0054     uint8_t     algo;       /* Public-key crypto algorithm [0] */
0055     uint8_t     hash;       /* Digest algorithm [0] */
0056     uint8_t     id_type;    /* Key identifier type [PKEY_ID_PKCS7] */
0057     uint8_t     signer_len; /* Length of signer's name [0] */
0058     uint8_t     key_id_len; /* Length of key identifier [0] */
0059     uint8_t     __pad[3];
0060     uint32_t    sig_len;    /* Length of signature data */
0061 };
0062 
0063 #define PKEY_ID_PKCS7 2
0064 
0065 static char magic_number[] = "~Module signature appended~\n";
0066 
0067 static __attribute__((noreturn))
0068 void format(void)
0069 {
0070     fprintf(stderr,
0071         "Usage: scripts/sign-file [-dp] <hash algo> <key> <x509> <module> [<dest>]\n");
0072     fprintf(stderr,
0073         "       scripts/sign-file -s <raw sig> <hash algo> <x509> <module> [<dest>]\n");
0074     exit(2);
0075 }
0076 
0077 static void display_openssl_errors(int l)
0078 {
0079     const char *file;
0080     char buf[120];
0081     int e, line;
0082 
0083     if (ERR_peek_error() == 0)
0084         return;
0085     fprintf(stderr, "At main.c:%d:\n", l);
0086 
0087     while ((e = ERR_get_error_line(&file, &line))) {
0088         ERR_error_string(e, buf);
0089         fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line);
0090     }
0091 }
0092 
0093 static void drain_openssl_errors(void)
0094 {
0095     const char *file;
0096     int line;
0097 
0098     if (ERR_peek_error() == 0)
0099         return;
0100     while (ERR_get_error_line(&file, &line)) {}
0101 }
0102 
0103 #define ERR(cond, fmt, ...)             \
0104     do {                        \
0105         bool __cond = (cond);           \
0106         display_openssl_errors(__LINE__);   \
0107         if (__cond) {               \
0108             err(1, fmt, ## __VA_ARGS__);    \
0109         }                   \
0110     } while(0)
0111 
0112 static const char *key_pass;
0113 
0114 static int pem_pw_cb(char *buf, int len, int w, void *v)
0115 {
0116     int pwlen;
0117 
0118     if (!key_pass)
0119         return -1;
0120 
0121     pwlen = strlen(key_pass);
0122     if (pwlen >= len)
0123         return -1;
0124 
0125     strcpy(buf, key_pass);
0126 
0127     /* If it's wrong, don't keep trying it. */
0128     key_pass = NULL;
0129 
0130     return pwlen;
0131 }
0132 
0133 static EVP_PKEY *read_private_key(const char *private_key_name)
0134 {
0135     EVP_PKEY *private_key;
0136 
0137     if (!strncmp(private_key_name, "pkcs11:", 7)) {
0138         ENGINE *e;
0139 
0140         ENGINE_load_builtin_engines();
0141         drain_openssl_errors();
0142         e = ENGINE_by_id("pkcs11");
0143         ERR(!e, "Load PKCS#11 ENGINE");
0144         if (ENGINE_init(e))
0145             drain_openssl_errors();
0146         else
0147             ERR(1, "ENGINE_init");
0148         if (key_pass)
0149             ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0),
0150                 "Set PKCS#11 PIN");
0151         private_key = ENGINE_load_private_key(e, private_key_name,
0152                               NULL, NULL);
0153         ERR(!private_key, "%s", private_key_name);
0154     } else {
0155         BIO *b;
0156 
0157         b = BIO_new_file(private_key_name, "rb");
0158         ERR(!b, "%s", private_key_name);
0159         private_key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb,
0160                               NULL);
0161         ERR(!private_key, "%s", private_key_name);
0162         BIO_free(b);
0163     }
0164 
0165     return private_key;
0166 }
0167 
0168 static X509 *read_x509(const char *x509_name)
0169 {
0170     unsigned char buf[2];
0171     X509 *x509;
0172     BIO *b;
0173     int n;
0174 
0175     b = BIO_new_file(x509_name, "rb");
0176     ERR(!b, "%s", x509_name);
0177 
0178     /* Look at the first two bytes of the file to determine the encoding */
0179     n = BIO_read(b, buf, 2);
0180     if (n != 2) {
0181         if (BIO_should_retry(b)) {
0182             fprintf(stderr, "%s: Read wanted retry\n", x509_name);
0183             exit(1);
0184         }
0185         if (n >= 0) {
0186             fprintf(stderr, "%s: Short read\n", x509_name);
0187             exit(1);
0188         }
0189         ERR(1, "%s", x509_name);
0190     }
0191 
0192     ERR(BIO_reset(b) != 0, "%s", x509_name);
0193 
0194     if (buf[0] == 0x30 && buf[1] >= 0x81 && buf[1] <= 0x84)
0195         /* Assume raw DER encoded X.509 */
0196         x509 = d2i_X509_bio(b, NULL);
0197     else
0198         /* Assume PEM encoded X.509 */
0199         x509 = PEM_read_bio_X509(b, NULL, NULL, NULL);
0200 
0201     BIO_free(b);
0202     ERR(!x509, "%s", x509_name);
0203 
0204     return x509;
0205 }
0206 
0207 int main(int argc, char **argv)
0208 {
0209     struct module_signature sig_info = { .id_type = PKEY_ID_PKCS7 };
0210     char *hash_algo = NULL;
0211     char *private_key_name = NULL, *raw_sig_name = NULL;
0212     char *x509_name, *module_name, *dest_name;
0213     bool save_sig = false, replace_orig;
0214     bool sign_only = false;
0215     bool raw_sig = false;
0216     unsigned char buf[4096];
0217     unsigned long module_size, sig_size;
0218     unsigned int use_signed_attrs;
0219     const EVP_MD *digest_algo;
0220     EVP_PKEY *private_key;
0221 #ifndef USE_PKCS7
0222     CMS_ContentInfo *cms = NULL;
0223     unsigned int use_keyid = 0;
0224 #else
0225     PKCS7 *pkcs7 = NULL;
0226 #endif
0227     X509 *x509;
0228     BIO *bd, *bm;
0229     int opt, n;
0230     OpenSSL_add_all_algorithms();
0231     ERR_load_crypto_strings();
0232     ERR_clear_error();
0233 
0234     key_pass = getenv("KBUILD_SIGN_PIN");
0235 
0236 #ifndef USE_PKCS7
0237     use_signed_attrs = CMS_NOATTR;
0238 #else
0239     use_signed_attrs = PKCS7_NOATTR;
0240 #endif
0241 
0242     do {
0243         opt = getopt(argc, argv, "sdpk");
0244         switch (opt) {
0245         case 's': raw_sig = true; break;
0246         case 'p': save_sig = true; break;
0247         case 'd': sign_only = true; save_sig = true; break;
0248 #ifndef USE_PKCS7
0249         case 'k': use_keyid = CMS_USE_KEYID; break;
0250 #endif
0251         case -1: break;
0252         default: format();
0253         }
0254     } while (opt != -1);
0255 
0256     argc -= optind;
0257     argv += optind;
0258     if (argc < 4 || argc > 5)
0259         format();
0260 
0261     if (raw_sig) {
0262         raw_sig_name = argv[0];
0263         hash_algo = argv[1];
0264     } else {
0265         hash_algo = argv[0];
0266         private_key_name = argv[1];
0267     }
0268     x509_name = argv[2];
0269     module_name = argv[3];
0270     if (argc == 5 && strcmp(argv[3], argv[4]) != 0) {
0271         dest_name = argv[4];
0272         replace_orig = false;
0273     } else {
0274         ERR(asprintf(&dest_name, "%s.~signed~", module_name) < 0,
0275             "asprintf");
0276         replace_orig = true;
0277     }
0278 
0279 #ifdef USE_PKCS7
0280     if (strcmp(hash_algo, "sha1") != 0) {
0281         fprintf(stderr, "sign-file: %s only supports SHA1 signing\n",
0282             OPENSSL_VERSION_TEXT);
0283         exit(3);
0284     }
0285 #endif
0286 
0287     /* Open the module file */
0288     bm = BIO_new_file(module_name, "rb");
0289     ERR(!bm, "%s", module_name);
0290 
0291     if (!raw_sig) {
0292         /* Read the private key and the X.509 cert the PKCS#7 message
0293          * will point to.
0294          */
0295         private_key = read_private_key(private_key_name);
0296         x509 = read_x509(x509_name);
0297 
0298         /* Digest the module data. */
0299         OpenSSL_add_all_digests();
0300         display_openssl_errors(__LINE__);
0301         digest_algo = EVP_get_digestbyname(hash_algo);
0302         ERR(!digest_algo, "EVP_get_digestbyname");
0303 
0304 #ifndef USE_PKCS7
0305         /* Load the signature message from the digest buffer. */
0306         cms = CMS_sign(NULL, NULL, NULL, NULL,
0307                    CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY |
0308                    CMS_DETACHED | CMS_STREAM);
0309         ERR(!cms, "CMS_sign");
0310 
0311         ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo,
0312                      CMS_NOCERTS | CMS_BINARY |
0313                      CMS_NOSMIMECAP | use_keyid |
0314                      use_signed_attrs),
0315             "CMS_add1_signer");
0316         ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) < 0,
0317             "CMS_final");
0318 
0319 #else
0320         pkcs7 = PKCS7_sign(x509, private_key, NULL, bm,
0321                    PKCS7_NOCERTS | PKCS7_BINARY |
0322                    PKCS7_DETACHED | use_signed_attrs);
0323         ERR(!pkcs7, "PKCS7_sign");
0324 #endif
0325 
0326         if (save_sig) {
0327             char *sig_file_name;
0328             BIO *b;
0329 
0330             ERR(asprintf(&sig_file_name, "%s.p7s", module_name) < 0,
0331                 "asprintf");
0332             b = BIO_new_file(sig_file_name, "wb");
0333             ERR(!b, "%s", sig_file_name);
0334 #ifndef USE_PKCS7
0335             ERR(i2d_CMS_bio_stream(b, cms, NULL, 0) < 0,
0336                 "%s", sig_file_name);
0337 #else
0338             ERR(i2d_PKCS7_bio(b, pkcs7) < 0,
0339                 "%s", sig_file_name);
0340 #endif
0341             BIO_free(b);
0342         }
0343 
0344         if (sign_only) {
0345             BIO_free(bm);
0346             return 0;
0347         }
0348     }
0349 
0350     /* Open the destination file now so that we can shovel the module data
0351      * across as we read it.
0352      */
0353     bd = BIO_new_file(dest_name, "wb");
0354     ERR(!bd, "%s", dest_name);
0355 
0356     /* Append the marker and the PKCS#7 message to the destination file */
0357     ERR(BIO_reset(bm) < 0, "%s", module_name);
0358     while ((n = BIO_read(bm, buf, sizeof(buf))),
0359            n > 0) {
0360         ERR(BIO_write(bd, buf, n) < 0, "%s", dest_name);
0361     }
0362     BIO_free(bm);
0363     ERR(n < 0, "%s", module_name);
0364     module_size = BIO_number_written(bd);
0365 
0366     if (!raw_sig) {
0367 #ifndef USE_PKCS7
0368         ERR(i2d_CMS_bio_stream(bd, cms, NULL, 0) < 0, "%s", dest_name);
0369 #else
0370         ERR(i2d_PKCS7_bio(bd, pkcs7) < 0, "%s", dest_name);
0371 #endif
0372     } else {
0373         BIO *b;
0374 
0375         /* Read the raw signature file and write the data to the
0376          * destination file
0377          */
0378         b = BIO_new_file(raw_sig_name, "rb");
0379         ERR(!b, "%s", raw_sig_name);
0380         while ((n = BIO_read(b, buf, sizeof(buf))), n > 0)
0381             ERR(BIO_write(bd, buf, n) < 0, "%s", dest_name);
0382         BIO_free(b);
0383     }
0384 
0385     sig_size = BIO_number_written(bd) - module_size;
0386     sig_info.sig_len = htonl(sig_size);
0387     ERR(BIO_write(bd, &sig_info, sizeof(sig_info)) < 0, "%s", dest_name);
0388     ERR(BIO_write(bd, magic_number, sizeof(magic_number) - 1) < 0, "%s", dest_name);
0389 
0390     ERR(BIO_free(bd) < 0, "%s", dest_name);
0391 
0392     /* Finally, if we're signing in place, replace the original. */
0393     if (replace_orig)
0394         ERR(rename(dest_name, module_name) < 0, "%s", dest_name);
0395 
0396     return 0;
0397 }