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 #include "ssl-common.h" 27 28 /* 29 * OpenSSL 3.0 deprecates the OpenSSL's ENGINE API. 30 * 31 * Remove this if/when that API is no longer used 32 */ 33 #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 34 35 #define PKEY_ID_PKCS7 2 36 37 static __attribute__((noreturn)) 38 void format(void) 39 { 40 fprintf(stderr, 41 "Usage: extract-cert <source> <dest>\n"); 42 exit(2); 43 } 44 45 static const char *key_pass; 46 static BIO *wb; 47 static char *cert_dst; 48 static bool verbose; 49 50 static void write_cert(X509 *x509) 51 { 52 char buf[200]; 53 54 if (!wb) { 55 wb = BIO_new_file(cert_dst, "wb"); 56 ERR(!wb, "%s", cert_dst); 57 } 58 X509_NAME_oneline(X509_get_subject_name(x509), buf, sizeof(buf)); 59 ERR(!i2d_X509_bio(wb, x509), "%s", cert_dst); 60 if (verbose) 61 fprintf(stderr, "Extracted cert: %s\n", buf); 62 } 63 64 int main(int argc, char **argv) 65 { 66 char *cert_src; 67 char *verbose_env; 68 69 OpenSSL_add_all_algorithms(); 70 ERR_load_crypto_strings(); 71 ERR_clear_error(); 72 73 verbose_env = getenv("KBUILD_VERBOSE"); 74 if (verbose_env && strchr(verbose_env, '1')) 75 verbose = true; 76 77 key_pass = getenv("KBUILD_SIGN_PIN"); 78 79 if (argc != 3) 80 format(); 81 82 cert_src = argv[1]; 83 cert_dst = argv[2]; 84 85 if (!cert_src[0]) { 86 /* Invoked with no input; create empty file */ 87 FILE *f = fopen(cert_dst, "wb"); 88 ERR(!f, "%s", cert_dst); 89 fclose(f); 90 exit(0); 91 } else if (!strncmp(cert_src, "pkcs11:", 7)) { 92 ENGINE *e; 93 struct { 94 const char *cert_id; 95 X509 *cert; 96 } parms; 97 98 parms.cert_id = cert_src; 99 parms.cert = NULL; 100 101 ENGINE_load_builtin_engines(); 102 drain_openssl_errors(__LINE__, 1); 103 e = ENGINE_by_id("pkcs11"); 104 ERR(!e, "Load PKCS#11 ENGINE"); 105 if (ENGINE_init(e)) 106 drain_openssl_errors(__LINE__, 1); 107 else 108 ERR(1, "ENGINE_init"); 109 if (key_pass) 110 ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN"); 111 ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &parms, NULL, 1); 112 ERR(!parms.cert, "Get X.509 from PKCS#11"); 113 write_cert(parms.cert); 114 } else { 115 BIO *b; 116 X509 *x509; 117 118 b = BIO_new_file(cert_src, "rb"); 119 ERR(!b, "%s", cert_src); 120 121 while (1) { 122 x509 = PEM_read_bio_X509(b, NULL, NULL, NULL); 123 if (wb && !x509) { 124 unsigned long err = ERR_peek_last_error(); 125 if (ERR_GET_LIB(err) == ERR_LIB_PEM && 126 ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { 127 ERR_clear_error(); 128 break; 129 } 130 } 131 ERR(!x509, "%s", cert_src); 132 write_cert(x509); 133 } 134 } 135 136 BIO_free(wb); 137 138 return 0; 139 } 140