Back to home page

LXR

 
 

    


0001 /* Extract X.509 certificate in DER form from PKCS#11 or PEM.
0002  *
0003  * Copyright © 2014-2015 Red Hat, Inc. All Rights Reserved.
0004  * Copyright © 2015      Intel Corporation.
0005  *
0006  * Authors: David Howells <dhowells@redhat.com>
0007  *          David Woodhouse <dwmw2@infradead.org>
0008  *
0009  * This program is free software; you can redistribute it and/or
0010  * modify it under the terms of the GNU Lesser General Public License
0011  * as published by the Free Software Foundation; either version 2.1
0012  * of the licence, or (at your option) any later version.
0013  */
0014 #define _GNU_SOURCE
0015 #include <stdio.h>
0016 #include <stdlib.h>
0017 #include <stdint.h>
0018 #include <stdbool.h>
0019 #include <string.h>
0020 #include <err.h>
0021 #include <openssl/bio.h>
0022 #include <openssl/pem.h>
0023 #include <openssl/err.h>
0024 #include <openssl/engine.h>
0025 
0026 #define PKEY_ID_PKCS7 2
0027 
0028 static __attribute__((noreturn))
0029 void format(void)
0030 {
0031     fprintf(stderr,
0032         "Usage: scripts/extract-cert <source> <dest>\n");
0033     exit(2);
0034 }
0035 
0036 static void display_openssl_errors(int l)
0037 {
0038     const char *file;
0039     char buf[120];
0040     int e, line;
0041 
0042     if (ERR_peek_error() == 0)
0043         return;
0044     fprintf(stderr, "At main.c:%d:\n", l);
0045 
0046     while ((e = ERR_get_error_line(&file, &line))) {
0047         ERR_error_string(e, buf);
0048         fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line);
0049     }
0050 }
0051 
0052 static void drain_openssl_errors(void)
0053 {
0054     const char *file;
0055     int line;
0056 
0057     if (ERR_peek_error() == 0)
0058         return;
0059     while (ERR_get_error_line(&file, &line)) {}
0060 }
0061 
0062 #define ERR(cond, fmt, ...)             \
0063     do {                        \
0064         bool __cond = (cond);           \
0065         display_openssl_errors(__LINE__);   \
0066         if (__cond) {               \
0067             err(1, fmt, ## __VA_ARGS__);    \
0068         }                   \
0069     } while(0)
0070 
0071 static const char *key_pass;
0072 static BIO *wb;
0073 static char *cert_dst;
0074 int kbuild_verbose;
0075 
0076 static void write_cert(X509 *x509)
0077 {
0078     char buf[200];
0079 
0080     if (!wb) {
0081         wb = BIO_new_file(cert_dst, "wb");
0082         ERR(!wb, "%s", cert_dst);
0083     }
0084     X509_NAME_oneline(X509_get_subject_name(x509), buf, sizeof(buf));
0085     ERR(!i2d_X509_bio(wb, x509), "%s", cert_dst);
0086     if (kbuild_verbose)
0087         fprintf(stderr, "Extracted cert: %s\n", buf);
0088 }
0089 
0090 int main(int argc, char **argv)
0091 {
0092     char *cert_src;
0093 
0094     OpenSSL_add_all_algorithms();
0095     ERR_load_crypto_strings();
0096     ERR_clear_error();
0097 
0098     kbuild_verbose = atoi(getenv("KBUILD_VERBOSE")?:"0");
0099 
0100         key_pass = getenv("KBUILD_SIGN_PIN");
0101 
0102     if (argc != 3)
0103         format();
0104 
0105     cert_src = argv[1];
0106     cert_dst = argv[2];
0107 
0108     if (!cert_src[0]) {
0109         /* Invoked with no input; create empty file */
0110         FILE *f = fopen(cert_dst, "wb");
0111         ERR(!f, "%s", cert_dst);
0112         fclose(f);
0113         exit(0);
0114     } else if (!strncmp(cert_src, "pkcs11:", 7)) {
0115         ENGINE *e;
0116         struct {
0117             const char *cert_id;
0118             X509 *cert;
0119         } parms;
0120 
0121         parms.cert_id = cert_src;
0122         parms.cert = NULL;
0123 
0124         ENGINE_load_builtin_engines();
0125         drain_openssl_errors();
0126         e = ENGINE_by_id("pkcs11");
0127         ERR(!e, "Load PKCS#11 ENGINE");
0128         if (ENGINE_init(e))
0129             drain_openssl_errors();
0130         else
0131             ERR(1, "ENGINE_init");
0132         if (key_pass)
0133             ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN");
0134         ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &parms, NULL, 1);
0135         ERR(!parms.cert, "Get X.509 from PKCS#11");
0136         write_cert(parms.cert);
0137     } else {
0138         BIO *b;
0139         X509 *x509;
0140 
0141         b = BIO_new_file(cert_src, "rb");
0142         ERR(!b, "%s", cert_src);
0143 
0144         while (1) {
0145             x509 = PEM_read_bio_X509(b, NULL, NULL, NULL);
0146             if (wb && !x509) {
0147                 unsigned long err = ERR_peek_last_error();
0148                 if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
0149                     ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
0150                     ERR_clear_error();
0151                     break;
0152                 }
0153             }
0154             ERR(!x509, "%s", cert_src);
0155             write_cert(x509);
0156         }
0157     }
0158 
0159     BIO_free(wb);
0160 
0161     return 0;
0162 }