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 #if OPENSSL_VERSION_MAJOR >= 3 25 # define USE_PKCS11_PROVIDER 26 # include <openssl/provider.h> 27 # include <openssl/store.h> 28 #else 29 # if !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_DEPRECATED_3_0) 30 # define USE_PKCS11_ENGINE 31 # include <openssl/engine.h> 32 # endif 33 #endif 34 #include "ssl-common.h" 35 36 static __attribute__((noreturn)) 37 void format(void) 38 { 39 fprintf(stderr, 40 "Usage: extract-cert <source> <dest>\n"); 41 exit(2); 42 } 43 44 static const char *key_pass; 45 static BIO *wb; 46 static char *cert_dst; 47 static bool verbose; 48 49 static void write_cert(X509 *x509) 50 { 51 char buf[200]; 52 53 if (!wb) { 54 wb = BIO_new_file(cert_dst, "wb"); 55 ERR(!wb, "%s", cert_dst); 56 } 57 X509_NAME_oneline(X509_get_subject_name(x509), buf, sizeof(buf)); 58 ERR(!i2d_X509_bio(wb, x509), "%s", cert_dst); 59 if (verbose) 60 fprintf(stderr, "Extracted cert: %s\n", buf); 61 } 62 63 static X509 *load_cert_pkcs11(const char *cert_src) 64 { 65 X509 *cert = NULL; 66 #ifdef USE_PKCS11_PROVIDER 67 OSSL_STORE_CTX *store; 68 69 if (!OSSL_PROVIDER_try_load(NULL, "pkcs11", true)) 70 ERR(1, "OSSL_PROVIDER_try_load(pkcs11)"); 71 if (!OSSL_PROVIDER_try_load(NULL, "default", true)) 72 ERR(1, "OSSL_PROVIDER_try_load(default)"); 73 74 store = OSSL_STORE_open(cert_src, NULL, NULL, NULL, NULL); 75 ERR(!store, "OSSL_STORE_open"); 76 77 while (!OSSL_STORE_eof(store)) { 78 OSSL_STORE_INFO *info = OSSL_STORE_load(store); 79 80 if (!info) { 81 drain_openssl_errors(__LINE__, 0); 82 continue; 83 } 84 if (OSSL_STORE_INFO_get_type(info) == OSSL_STORE_INFO_CERT) { 85 cert = OSSL_STORE_INFO_get1_CERT(info); 86 ERR(!cert, "OSSL_STORE_INFO_get1_CERT"); 87 } 88 OSSL_STORE_INFO_free(info); 89 if (cert) 90 break; 91 } 92 OSSL_STORE_close(store); 93 #elif defined(USE_PKCS11_ENGINE) 94 ENGINE *e; 95 struct { 96 const char *cert_id; 97 X509 *cert; 98 } parms; 99 100 parms.cert_id = cert_src; 101 parms.cert = NULL; 102 103 ENGINE_load_builtin_engines(); 104 drain_openssl_errors(__LINE__, 1); 105 e = ENGINE_by_id("pkcs11"); 106 ERR(!e, "Load PKCS#11 ENGINE"); 107 if (ENGINE_init(e)) 108 drain_openssl_errors(__LINE__, 1); 109 else 110 ERR(1, "ENGINE_init"); 111 if (key_pass) 112 ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN"); 113 ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &parms, NULL, 1); 114 ERR(!parms.cert, "Get X.509 from PKCS#11"); 115 cert = parms.cert; 116 #else 117 fprintf(stderr, "no pkcs11 engine/provider available\n"); 118 exit(1); 119 #endif 120 return cert; 121 } 122 123 int main(int argc, char **argv) 124 { 125 char *cert_src; 126 char *verbose_env; 127 128 OpenSSL_add_all_algorithms(); 129 ERR_load_crypto_strings(); 130 ERR_clear_error(); 131 132 verbose_env = getenv("KBUILD_VERBOSE"); 133 if (verbose_env && strchr(verbose_env, '1')) 134 verbose = true; 135 136 key_pass = getenv("KBUILD_SIGN_PIN"); 137 138 if (argc != 3) 139 format(); 140 141 cert_src = argv[1]; 142 cert_dst = argv[2]; 143 144 if (!cert_src[0]) { 145 /* Invoked with no input; create empty file */ 146 FILE *f = fopen(cert_dst, "wb"); 147 ERR(!f, "%s", cert_dst); 148 fclose(f); 149 exit(0); 150 } else if (!strncmp(cert_src, "pkcs11:", 7)) { 151 X509 *cert = load_cert_pkcs11(cert_src); 152 153 ERR(!cert, "load_cert_pkcs11 failed"); 154 write_cert(cert); 155 } else { 156 BIO *b; 157 X509 *x509; 158 159 b = BIO_new_file(cert_src, "rb"); 160 ERR(!b, "%s", cert_src); 161 162 while (1) { 163 x509 = PEM_read_bio_X509(b, NULL, NULL, NULL); 164 if (wb && !x509) { 165 unsigned long err = ERR_peek_last_error(); 166 if (ERR_GET_LIB(err) == ERR_LIB_PEM && 167 ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { 168 ERR_clear_error(); 169 break; 170 } 171 } 172 ERR(!x509, "%s", cert_src); 173 write_cert(x509); 174 } 175 } 176 177 BIO_free(wb); 178 179 return 0; 180 } 181