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