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