1340a0253SMasahiro Yamada /* Extract X.509 certificate in DER form from PKCS#11 or PEM.
2340a0253SMasahiro Yamada *
3340a0253SMasahiro Yamada * Copyright © 2014-2015 Red Hat, Inc. All Rights Reserved.
4340a0253SMasahiro Yamada * Copyright © 2015 Intel Corporation.
5340a0253SMasahiro Yamada *
6340a0253SMasahiro Yamada * Authors: David Howells <dhowells@redhat.com>
7340a0253SMasahiro Yamada * David Woodhouse <dwmw2@infradead.org>
8340a0253SMasahiro Yamada *
9340a0253SMasahiro Yamada * This program is free software; you can redistribute it and/or
10340a0253SMasahiro Yamada * modify it under the terms of the GNU Lesser General Public License
11340a0253SMasahiro Yamada * as published by the Free Software Foundation; either version 2.1
12340a0253SMasahiro Yamada * of the licence, or (at your option) any later version.
13340a0253SMasahiro Yamada */
14340a0253SMasahiro Yamada #define _GNU_SOURCE
15340a0253SMasahiro Yamada #include <stdio.h>
16340a0253SMasahiro Yamada #include <stdlib.h>
17340a0253SMasahiro Yamada #include <stdint.h>
18340a0253SMasahiro Yamada #include <stdbool.h>
19340a0253SMasahiro Yamada #include <string.h>
20340a0253SMasahiro Yamada #include <err.h>
21340a0253SMasahiro Yamada #include <openssl/bio.h>
22340a0253SMasahiro Yamada #include <openssl/pem.h>
23340a0253SMasahiro Yamada #include <openssl/err.h>
24340a0253SMasahiro Yamada #include <openssl/engine.h>
25340a0253SMasahiro Yamada
266bfb56e9SLinus Torvalds /*
276bfb56e9SLinus Torvalds * OpenSSL 3.0 deprecates the OpenSSL's ENGINE API.
286bfb56e9SLinus Torvalds *
296bfb56e9SLinus Torvalds * Remove this if/when that API is no longer used
306bfb56e9SLinus Torvalds */
316bfb56e9SLinus Torvalds #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
326bfb56e9SLinus Torvalds
33340a0253SMasahiro Yamada #define PKEY_ID_PKCS7 2
34340a0253SMasahiro Yamada
35340a0253SMasahiro Yamada static __attribute__((noreturn))
format(void)36340a0253SMasahiro Yamada void format(void)
37340a0253SMasahiro Yamada {
38340a0253SMasahiro Yamada fprintf(stderr,
39340a0253SMasahiro Yamada "Usage: extract-cert <source> <dest>\n");
40340a0253SMasahiro Yamada exit(2);
41340a0253SMasahiro Yamada }
42340a0253SMasahiro Yamada
display_openssl_errors(int l)43340a0253SMasahiro Yamada static void display_openssl_errors(int l)
44340a0253SMasahiro Yamada {
45340a0253SMasahiro Yamada const char *file;
46340a0253SMasahiro Yamada char buf[120];
47340a0253SMasahiro Yamada int e, line;
48340a0253SMasahiro Yamada
49340a0253SMasahiro Yamada if (ERR_peek_error() == 0)
50340a0253SMasahiro Yamada return;
51340a0253SMasahiro Yamada fprintf(stderr, "At main.c:%d:\n", l);
52340a0253SMasahiro Yamada
53340a0253SMasahiro Yamada while ((e = ERR_get_error_line(&file, &line))) {
54340a0253SMasahiro Yamada ERR_error_string(e, buf);
55340a0253SMasahiro Yamada fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line);
56340a0253SMasahiro Yamada }
57340a0253SMasahiro Yamada }
58340a0253SMasahiro Yamada
drain_openssl_errors(void)59340a0253SMasahiro Yamada static void drain_openssl_errors(void)
60340a0253SMasahiro Yamada {
61340a0253SMasahiro Yamada const char *file;
62340a0253SMasahiro Yamada int line;
63340a0253SMasahiro Yamada
64340a0253SMasahiro Yamada if (ERR_peek_error() == 0)
65340a0253SMasahiro Yamada return;
66340a0253SMasahiro Yamada while (ERR_get_error_line(&file, &line)) {}
67340a0253SMasahiro Yamada }
68340a0253SMasahiro Yamada
69340a0253SMasahiro Yamada #define ERR(cond, fmt, ...) \
70340a0253SMasahiro Yamada do { \
71340a0253SMasahiro Yamada bool __cond = (cond); \
72340a0253SMasahiro Yamada display_openssl_errors(__LINE__); \
73340a0253SMasahiro Yamada if (__cond) { \
74340a0253SMasahiro Yamada err(1, fmt, ## __VA_ARGS__); \
75340a0253SMasahiro Yamada } \
76340a0253SMasahiro Yamada } while(0)
77340a0253SMasahiro Yamada
78340a0253SMasahiro Yamada static const char *key_pass;
79340a0253SMasahiro Yamada static BIO *wb;
80340a0253SMasahiro Yamada static char *cert_dst;
81*c0d3b831SMasahiro Yamada static bool verbose;
82340a0253SMasahiro Yamada
write_cert(X509 * x509)83340a0253SMasahiro Yamada static void write_cert(X509 *x509)
84340a0253SMasahiro Yamada {
85340a0253SMasahiro Yamada char buf[200];
86340a0253SMasahiro Yamada
87340a0253SMasahiro Yamada if (!wb) {
88340a0253SMasahiro Yamada wb = BIO_new_file(cert_dst, "wb");
89340a0253SMasahiro Yamada ERR(!wb, "%s", cert_dst);
90340a0253SMasahiro Yamada }
91340a0253SMasahiro Yamada X509_NAME_oneline(X509_get_subject_name(x509), buf, sizeof(buf));
92340a0253SMasahiro Yamada ERR(!i2d_X509_bio(wb, x509), "%s", cert_dst);
93*c0d3b831SMasahiro Yamada if (verbose)
94340a0253SMasahiro Yamada fprintf(stderr, "Extracted cert: %s\n", buf);
95340a0253SMasahiro Yamada }
96340a0253SMasahiro Yamada
main(int argc,char ** argv)97340a0253SMasahiro Yamada int main(int argc, char **argv)
98340a0253SMasahiro Yamada {
99340a0253SMasahiro Yamada char *cert_src;
100*c0d3b831SMasahiro Yamada char *verbose_env;
101340a0253SMasahiro Yamada
102340a0253SMasahiro Yamada OpenSSL_add_all_algorithms();
103340a0253SMasahiro Yamada ERR_load_crypto_strings();
104340a0253SMasahiro Yamada ERR_clear_error();
105340a0253SMasahiro Yamada
106*c0d3b831SMasahiro Yamada verbose_env = getenv("KBUILD_VERBOSE");
107*c0d3b831SMasahiro Yamada if (verbose_env && strchr(verbose_env, '1'))
108*c0d3b831SMasahiro Yamada verbose = true;
109340a0253SMasahiro Yamada
110340a0253SMasahiro Yamada key_pass = getenv("KBUILD_SIGN_PIN");
111340a0253SMasahiro Yamada
112340a0253SMasahiro Yamada if (argc != 3)
113340a0253SMasahiro Yamada format();
114340a0253SMasahiro Yamada
115340a0253SMasahiro Yamada cert_src = argv[1];
116340a0253SMasahiro Yamada cert_dst = argv[2];
117340a0253SMasahiro Yamada
118340a0253SMasahiro Yamada if (!cert_src[0]) {
119340a0253SMasahiro Yamada /* Invoked with no input; create empty file */
120340a0253SMasahiro Yamada FILE *f = fopen(cert_dst, "wb");
121340a0253SMasahiro Yamada ERR(!f, "%s", cert_dst);
122340a0253SMasahiro Yamada fclose(f);
123340a0253SMasahiro Yamada exit(0);
124340a0253SMasahiro Yamada } else if (!strncmp(cert_src, "pkcs11:", 7)) {
125340a0253SMasahiro Yamada ENGINE *e;
126340a0253SMasahiro Yamada struct {
127340a0253SMasahiro Yamada const char *cert_id;
128340a0253SMasahiro Yamada X509 *cert;
129340a0253SMasahiro Yamada } parms;
130340a0253SMasahiro Yamada
131340a0253SMasahiro Yamada parms.cert_id = cert_src;
132340a0253SMasahiro Yamada parms.cert = NULL;
133340a0253SMasahiro Yamada
134340a0253SMasahiro Yamada ENGINE_load_builtin_engines();
135340a0253SMasahiro Yamada drain_openssl_errors();
136340a0253SMasahiro Yamada e = ENGINE_by_id("pkcs11");
137340a0253SMasahiro Yamada ERR(!e, "Load PKCS#11 ENGINE");
138340a0253SMasahiro Yamada if (ENGINE_init(e))
139340a0253SMasahiro Yamada drain_openssl_errors();
140340a0253SMasahiro Yamada else
141340a0253SMasahiro Yamada ERR(1, "ENGINE_init");
142340a0253SMasahiro Yamada if (key_pass)
143340a0253SMasahiro Yamada ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN");
144340a0253SMasahiro Yamada ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &parms, NULL, 1);
145340a0253SMasahiro Yamada ERR(!parms.cert, "Get X.509 from PKCS#11");
146340a0253SMasahiro Yamada write_cert(parms.cert);
147340a0253SMasahiro Yamada } else {
148340a0253SMasahiro Yamada BIO *b;
149340a0253SMasahiro Yamada X509 *x509;
150340a0253SMasahiro Yamada
151340a0253SMasahiro Yamada b = BIO_new_file(cert_src, "rb");
152340a0253SMasahiro Yamada ERR(!b, "%s", cert_src);
153340a0253SMasahiro Yamada
154340a0253SMasahiro Yamada while (1) {
155340a0253SMasahiro Yamada x509 = PEM_read_bio_X509(b, NULL, NULL, NULL);
156340a0253SMasahiro Yamada if (wb && !x509) {
157340a0253SMasahiro Yamada unsigned long err = ERR_peek_last_error();
158340a0253SMasahiro Yamada if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
159340a0253SMasahiro Yamada ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
160340a0253SMasahiro Yamada ERR_clear_error();
161340a0253SMasahiro Yamada break;
162340a0253SMasahiro Yamada }
163340a0253SMasahiro Yamada }
164340a0253SMasahiro Yamada ERR(!x509, "%s", cert_src);
165340a0253SMasahiro Yamada write_cert(x509);
166340a0253SMasahiro Yamada }
167340a0253SMasahiro Yamada }
168340a0253SMasahiro Yamada
169340a0253SMasahiro Yamada BIO_free(wb);
170340a0253SMasahiro Yamada
171340a0253SMasahiro Yamada return 0;
172340a0253SMasahiro Yamada }
173