xref: /linux/certs/extract-cert.c (revision c0d3b831)
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