Back to home page

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