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