0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
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
0034
0035
0036
0037 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
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;
0064 uint8_t hash;
0065 uint8_t id_type;
0066 uint8_t signer_len;
0067 uint8_t key_id_len;
0068 uint8_t __pad[3];
0069 uint32_t sig_len;
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
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
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
0205 x509 = d2i_X509_bio(b, NULL);
0206 else
0207
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
0297 bm = BIO_new_file(module_name, "rb");
0298 ERR(!bm, "%s", module_name);
0299
0300 if (!raw_sig) {
0301
0302
0303
0304 private_key = read_private_key(private_key_name);
0305 x509 = read_x509(x509_name);
0306
0307
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
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
0360
0361
0362 bd = BIO_new_file(dest_name, "wb");
0363 ERR(!bd, "%s", dest_name);
0364
0365
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
0385
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
0402 if (replace_orig)
0403 ERR(rename(dest_name, module_name) < 0, "%s", dest_name);
0404
0405 return 0;
0406 }