1 /* Extract X.509 certificate in DER form from PKCS#11 or PEM. 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 <err.h> 21 #include <openssl/bio.h> 22 #include <openssl/pem.h> 23 #include <openssl/err.h> 24 #include <openssl/engine.h> 25 26 #define PKEY_ID_PKCS7 2 27 28 static __attribute__((noreturn)) 29 void format(void) 30 { 31 fprintf(stderr, 32 "Usage: extract-cert <source> <dest>\n"); 33 exit(2); 34 } 35 36 static void display_openssl_errors(int l) 37 { 38 const char *file; 39 char buf[120]; 40 int e, line; 41 42 if (ERR_peek_error() == 0) 43 return; 44 fprintf(stderr, "At main.c:%d:\n", l); 45 46 while ((e = ERR_get_error_line(&file, &line))) { 47 ERR_error_string(e, buf); 48 fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line); 49 } 50 } 51 52 static void drain_openssl_errors(void) 53 { 54 const char *file; 55 int line; 56 57 if (ERR_peek_error() == 0) 58 return; 59 while (ERR_get_error_line(&file, &line)) {} 60 } 61 62 #define ERR(cond, fmt, ...) \ 63 do { \ 64 bool __cond = (cond); \ 65 display_openssl_errors(__LINE__); \ 66 if (__cond) { \ 67 err(1, fmt, ## __VA_ARGS__); \ 68 } \ 69 } while(0) 70 71 static const char *key_pass; 72 static BIO *wb; 73 static char *cert_dst; 74 static int kbuild_verbose; 75 76 static void write_cert(X509 *x509) 77 { 78 char buf[200]; 79 80 if (!wb) { 81 wb = BIO_new_file(cert_dst, "wb"); 82 ERR(!wb, "%s", cert_dst); 83 } 84 X509_NAME_oneline(X509_get_subject_name(x509), buf, sizeof(buf)); 85 ERR(!i2d_X509_bio(wb, x509), "%s", cert_dst); 86 if (kbuild_verbose) 87 fprintf(stderr, "Extracted cert: %s\n", buf); 88 } 89 90 int main(int argc, char **argv) 91 { 92 char *cert_src; 93 94 OpenSSL_add_all_algorithms(); 95 ERR_load_crypto_strings(); 96 ERR_clear_error(); 97 98 kbuild_verbose = atoi(getenv("KBUILD_VERBOSE")?:"0"); 99 100 key_pass = getenv("KBUILD_SIGN_PIN"); 101 102 if (argc != 3) 103 format(); 104 105 cert_src = argv[1]; 106 cert_dst = argv[2]; 107 108 if (!cert_src[0]) { 109 /* Invoked with no input; create empty file */ 110 FILE *f = fopen(cert_dst, "wb"); 111 ERR(!f, "%s", cert_dst); 112 fclose(f); 113 exit(0); 114 } else if (!strncmp(cert_src, "pkcs11:", 7)) { 115 ENGINE *e; 116 struct { 117 const char *cert_id; 118 X509 *cert; 119 } parms; 120 121 parms.cert_id = cert_src; 122 parms.cert = NULL; 123 124 ENGINE_load_builtin_engines(); 125 drain_openssl_errors(); 126 e = ENGINE_by_id("pkcs11"); 127 ERR(!e, "Load PKCS#11 ENGINE"); 128 if (ENGINE_init(e)) 129 drain_openssl_errors(); 130 else 131 ERR(1, "ENGINE_init"); 132 if (key_pass) 133 ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN"); 134 ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &parms, NULL, 1); 135 ERR(!parms.cert, "Get X.509 from PKCS#11"); 136 write_cert(parms.cert); 137 } else { 138 BIO *b; 139 X509 *x509; 140 141 b = BIO_new_file(cert_src, "rb"); 142 ERR(!b, "%s", cert_src); 143 144 while (1) { 145 x509 = PEM_read_bio_X509(b, NULL, NULL, NULL); 146 if (wb && !x509) { 147 unsigned long err = ERR_peek_last_error(); 148 if (ERR_GET_LIB(err) == ERR_LIB_PEM && 149 ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { 150 ERR_clear_error(); 151 break; 152 } 153 } 154 ERR(!x509, "%s", cert_src); 155 write_cert(x509); 156 } 157 } 158 159 BIO_free(wb); 160 161 return 0; 162 } 163