18c2ecf20Sopenharmony_ci/* Extract X.509 certificate in DER form from PKCS#11 or PEM. 28c2ecf20Sopenharmony_ci * 38c2ecf20Sopenharmony_ci * Copyright © 2014-2015 Red Hat, Inc. All Rights Reserved. 48c2ecf20Sopenharmony_ci * Copyright © 2015 Intel Corporation. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Authors: David Howells <dhowells@redhat.com> 78c2ecf20Sopenharmony_ci * David Woodhouse <dwmw2@infradead.org> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 108c2ecf20Sopenharmony_ci * modify it under the terms of the GNU Lesser General Public License 118c2ecf20Sopenharmony_ci * as published by the Free Software Foundation; either version 2.1 128c2ecf20Sopenharmony_ci * of the licence, or (at your option) any later version. 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci#define _GNU_SOURCE 158c2ecf20Sopenharmony_ci#include <stdio.h> 168c2ecf20Sopenharmony_ci#include <stdlib.h> 178c2ecf20Sopenharmony_ci#include <stdint.h> 188c2ecf20Sopenharmony_ci#include <stdbool.h> 198c2ecf20Sopenharmony_ci#include <string.h> 208c2ecf20Sopenharmony_ci#include <err.h> 218c2ecf20Sopenharmony_ci#include <openssl/bio.h> 228c2ecf20Sopenharmony_ci#include <openssl/pem.h> 238c2ecf20Sopenharmony_ci#include <openssl/err.h> 248c2ecf20Sopenharmony_ci#include <openssl/engine.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* 278c2ecf20Sopenharmony_ci * OpenSSL 3.0 deprecates the OpenSSL's ENGINE API. 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * Remove this if/when that API is no longer used 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci#pragma GCC diagnostic ignored "-Wdeprecated-declarations" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define PKEY_ID_PKCS7 2 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic __attribute__((noreturn)) 368c2ecf20Sopenharmony_civoid format(void) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci fprintf(stderr, 398c2ecf20Sopenharmony_ci "Usage: scripts/extract-cert <source> <dest>\n"); 408c2ecf20Sopenharmony_ci exit(2); 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic void display_openssl_errors(int l) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci const char *file; 468c2ecf20Sopenharmony_ci char buf[120]; 478c2ecf20Sopenharmony_ci int e, line; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (ERR_peek_error() == 0) 508c2ecf20Sopenharmony_ci return; 518c2ecf20Sopenharmony_ci fprintf(stderr, "At main.c:%d:\n", l); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci while ((e = ERR_get_error_line(&file, &line))) { 548c2ecf20Sopenharmony_ci ERR_error_string(e, buf); 558c2ecf20Sopenharmony_ci fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line); 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic void drain_openssl_errors(void) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci const char *file; 628c2ecf20Sopenharmony_ci int line; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (ERR_peek_error() == 0) 658c2ecf20Sopenharmony_ci return; 668c2ecf20Sopenharmony_ci while (ERR_get_error_line(&file, &line)) {} 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define ERR(cond, fmt, ...) \ 708c2ecf20Sopenharmony_ci do { \ 718c2ecf20Sopenharmony_ci bool __cond = (cond); \ 728c2ecf20Sopenharmony_ci display_openssl_errors(__LINE__); \ 738c2ecf20Sopenharmony_ci if (__cond) { \ 748c2ecf20Sopenharmony_ci err(1, fmt, ## __VA_ARGS__); \ 758c2ecf20Sopenharmony_ci } \ 768c2ecf20Sopenharmony_ci } while(0) 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic const char *key_pass; 798c2ecf20Sopenharmony_cistatic BIO *wb; 808c2ecf20Sopenharmony_cistatic char *cert_dst; 818c2ecf20Sopenharmony_cistatic int kbuild_verbose; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic void write_cert(X509 *x509) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci char buf[200]; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (!wb) { 888c2ecf20Sopenharmony_ci wb = BIO_new_file(cert_dst, "wb"); 898c2ecf20Sopenharmony_ci ERR(!wb, "%s", cert_dst); 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci X509_NAME_oneline(X509_get_subject_name(x509), buf, sizeof(buf)); 928c2ecf20Sopenharmony_ci ERR(!i2d_X509_bio(wb, x509), "%s", cert_dst); 938c2ecf20Sopenharmony_ci if (kbuild_verbose) 948c2ecf20Sopenharmony_ci fprintf(stderr, "Extracted cert: %s\n", buf); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ciint main(int argc, char **argv) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci char *cert_src; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci OpenSSL_add_all_algorithms(); 1028c2ecf20Sopenharmony_ci ERR_load_crypto_strings(); 1038c2ecf20Sopenharmony_ci ERR_clear_error(); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci kbuild_verbose = atoi(getenv("KBUILD_VERBOSE")?:"0"); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci key_pass = getenv("KBUILD_SIGN_PIN"); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (argc != 3) 1108c2ecf20Sopenharmony_ci format(); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci cert_src = argv[1]; 1138c2ecf20Sopenharmony_ci cert_dst = argv[2]; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (!cert_src[0]) { 1168c2ecf20Sopenharmony_ci /* Invoked with no input; create empty file */ 1178c2ecf20Sopenharmony_ci FILE *f = fopen(cert_dst, "wb"); 1188c2ecf20Sopenharmony_ci ERR(!f, "%s", cert_dst); 1198c2ecf20Sopenharmony_ci fclose(f); 1208c2ecf20Sopenharmony_ci exit(0); 1218c2ecf20Sopenharmony_ci } else if (!strncmp(cert_src, "pkcs11:", 7)) { 1228c2ecf20Sopenharmony_ci ENGINE *e; 1238c2ecf20Sopenharmony_ci struct { 1248c2ecf20Sopenharmony_ci const char *cert_id; 1258c2ecf20Sopenharmony_ci X509 *cert; 1268c2ecf20Sopenharmony_ci } parms; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci parms.cert_id = cert_src; 1298c2ecf20Sopenharmony_ci parms.cert = NULL; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci ENGINE_load_builtin_engines(); 1328c2ecf20Sopenharmony_ci drain_openssl_errors(); 1338c2ecf20Sopenharmony_ci e = ENGINE_by_id("pkcs11"); 1348c2ecf20Sopenharmony_ci ERR(!e, "Load PKCS#11 ENGINE"); 1358c2ecf20Sopenharmony_ci if (ENGINE_init(e)) 1368c2ecf20Sopenharmony_ci drain_openssl_errors(); 1378c2ecf20Sopenharmony_ci else 1388c2ecf20Sopenharmony_ci ERR(1, "ENGINE_init"); 1398c2ecf20Sopenharmony_ci if (key_pass) 1408c2ecf20Sopenharmony_ci ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN"); 1418c2ecf20Sopenharmony_ci ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &parms, NULL, 1); 1428c2ecf20Sopenharmony_ci ERR(!parms.cert, "Get X.509 from PKCS#11"); 1438c2ecf20Sopenharmony_ci write_cert(parms.cert); 1448c2ecf20Sopenharmony_ci } else { 1458c2ecf20Sopenharmony_ci BIO *b; 1468c2ecf20Sopenharmony_ci X509 *x509; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci b = BIO_new_file(cert_src, "rb"); 1498c2ecf20Sopenharmony_ci ERR(!b, "%s", cert_src); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci while (1) { 1528c2ecf20Sopenharmony_ci x509 = PEM_read_bio_X509(b, NULL, NULL, NULL); 1538c2ecf20Sopenharmony_ci if (wb && !x509) { 1548c2ecf20Sopenharmony_ci unsigned long err = ERR_peek_last_error(); 1558c2ecf20Sopenharmony_ci if (ERR_GET_LIB(err) == ERR_LIB_PEM && 1568c2ecf20Sopenharmony_ci ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { 1578c2ecf20Sopenharmony_ci ERR_clear_error(); 1588c2ecf20Sopenharmony_ci break; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci ERR(!x509, "%s", cert_src); 1628c2ecf20Sopenharmony_ci write_cert(x509); 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci BIO_free(wb); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci return 0; 1698c2ecf20Sopenharmony_ci} 170