]> git.proxmox.com Git - swtpm.git/commitdiff
Move swtpm_localca sources from samples/ to src/
authorNick Chevsky <nchevsky@users.noreply.github.com>
Sat, 24 Jul 2021 18:54:40 +0000 (13:54 -0500)
committerStefan Berger <stefanb@us.ibm.com>
Sun, 25 Jul 2021 12:52:13 +0000 (08:52 -0400)
- Move swtpm_localca's sources out of samples/ (where they no longer
  belong now that swtpm_localca is a binary) to src/swtpm_localca/.
- Tests now call the swtpm_localca binary directly at the location
  where it was built, as they do with all other compiled programs.
- Simplify samples/swtpm-localca.in and delete swtpm-localca.2inst,
  removing the now-unnecessary logic to selectively call swtpm_localca
  from different locations (samples/ when running tests vs. /usr/bin/
  post-installation).

Signed-off-by: Nick Chevsky <nchevsky@users.noreply.github.com>
26 files changed:
.gitignore
configure.ac
samples/Makefile.am
samples/swtpm-localca.2inst.in [deleted file]
samples/swtpm-localca.in
samples/swtpm_localca.c [deleted file]
samples/swtpm_localca.h [deleted file]
samples/swtpm_localca_conf.h.in [deleted file]
samples/swtpm_localca_utils.c [deleted file]
samples/swtpm_localca_utils.h [deleted file]
src/Makefile.am
src/swtpm_localca/Makefile.am [new file with mode: 0644]
src/swtpm_localca/swtpm_localca.c [new file with mode: 0644]
src/swtpm_localca/swtpm_localca.h [new file with mode: 0644]
src/swtpm_localca/swtpm_localca_conf.h.in [new file with mode: 0644]
src/swtpm_localca/swtpm_localca_utils.c [new file with mode: 0644]
src/swtpm_localca/swtpm_localca_utils.h [new file with mode: 0644]
tests/Makefile.am
tests/test_samples_create_tpmca
tests/test_swtpm_setup_create_cert
tests/test_tpm2_samples_create_tpmca
tests/test_tpm2_samples_swtpm_localca [deleted file]
tests/test_tpm2_samples_swtpm_localca_pkcs11 [deleted file]
tests/test_tpm2_swtpm_localca [new file with mode: 0755]
tests/test_tpm2_swtpm_localca_pkcs11 [new file with mode: 0755]
tests/test_tpm2_swtpm_setup_create_cert

index 2207bb221e12fc3893a4e4668f3486be710c303c..802848574b4eb347c5abe4dc30dd0c7e1710c0ae 100644 (file)
@@ -39,11 +39,8 @@ Makefile
 /man/man3/*.3
 /man/man8/*.8
 /samples/swtpm-create-user-config-files
-/samples/swtpm_localca
 /samples/swtpm-localca
-/samples/swtpm-localca.2inst
 /samples/swtpm-localca.conf
-/samples/swtpm_localca_conf.h
 /samples/swtpm_setup.conf
 /src/selinux/*.pp.bz2
 /src/selinux/swtpm.pp
@@ -57,6 +54,8 @@ Makefile
 /src/swtpm_bios/swtpm_bios
 /src/swtpm_cert/swtpm_cert
 /src/swtpm_ioctl/swtpm_ioctl
+/src/swtpm_localca/swtpm_localca
+/src/swtpm_localca/swtpm_localca_conf.h
 src/swtpm_setup/swtpm_setup
 src/swtpm_setup/swtpm_setup_conf.h
 /test-driver
index 67066b20e2c3f9c443be36070e4ee0cdb4fbf249..e703b21a10115535fd3225a2b6fd9a3292800bc0 100644 (file)
@@ -541,10 +541,8 @@ AC_CONFIG_FILES([Makefile                   \
                debian/swtpm-tools.postinst \
                swtpm.spec                  \
                samples/Makefile            \
-               samples/swtpm-localca.2inst \
                samples/swtpm-localca.conf  \
                samples/swtpm-create-user-config-files \
-               samples/swtpm_localca_conf.h \
                samples/swtpm_setup.conf    \
                include/Makefile            \
                include/swtpm/Makefile      \
@@ -555,6 +553,8 @@ AC_CONFIG_FILES([Makefile                   \
                src/swtpm_bios/Makefile     \
                src/swtpm_cert/Makefile     \
                src/swtpm_ioctl/Makefile    \
+               src/swtpm_localca/Makefile  \
+               src/swtpm_localca/swtpm_localca_conf.h \
                src/swtpm_setup/Makefile    \
                src/swtpm_setup/swtpm_setup_conf.h \
                src/utils/Makefile          \
index 550b1611bcd50643ed1b039c85ce9309bbdc8bbf..383c395ee959ca5413551f9b2784d2731f5e98bd 100644 (file)
@@ -9,43 +9,17 @@ samplessysconfdir = $(sysconfdir)
 
 samplesconf_SCRIPTS = \
        swtpm-create-tpmca \
-       swtpm-create-user-config-files
+       swtpm-create-user-config-files \
+       swtpm-localca
 
 samplessysconf_DATA = \
        swtpm-localca.conf \
        swtpm-localca.options \
        swtpm_setup.conf
 
-noinst_HEADERS = \
-       swtpm_localca.h \
-       swtpm_localca_utils.h
-
-bin_PROGRAMS = \
-       swtpm_localca
-
 $(top_builddir)/src/utils/libswtpm_utils.la:
        $(MAKE) -C$(dir $@)
 
-swtpm_localca_DEPENDENCIES = \
-       $(top_builddir)/src/utils/libswtpm_utils.la
-
-swtpm_localca_SOURCES = \
-       swtpm_localca.c \
-       swtpm_localca_utils.c
-
-swtpm_localca_LDADD = \
-       $(top_builddir)/src/utils/libswtpm_utils.la
-
-swtpm_localca_LDFLAGS = \
-       -L$(top_builddir)/src/utils -lswtpm_utils \
-       $(HARDENING_LDFLAGS) \
-       $(GLIB_LIBS)
-
-swtpm_localca_CFLAGS = \
-       -I$(top_srcdir)/src/utils \
-       $(HARDENING_CFLAGS) \
-       $(GLIB_CFLAGS)
-
 install-data-local:
        $(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/swtpm-localca
        if test -z $(DESTDIR); then \
@@ -53,13 +27,6 @@ install-data-local:
                chmod 0750 $(DESTDIR)$(localstatedir)/lib/swtpm-localca || true; \
        fi
 
-install-exec-local:
-       $(MKDIR_P) $(DESTDIR)$(samplesconfdir)
-       $(INSTALL_SCRIPT) swtpm-localca.2inst $(DESTDIR)$(samplesconfdir)/swtpm-localca
-
-uninstall-local:
-       rm -f $(DESTDIR)$(samplesconfdir)/swtpm-localca
-
 EXTRA_DIST= \
        swtpm-create-tpmca \
        swtpm-create-user-config-files \
diff --git a/samples/swtpm-localca.2inst.in b/samples/swtpm-localca.2inst.in
deleted file mode 100755 (executable)
index ee90695..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env sh
-
-@BINDIR@/swtpm_localca "$@"
-
-exit $?
index ca882e5373be596137640a0601c23dddeecb1b94..ee90695dc06053e7fe41e6e7c79be93a8b7d296b 100755 (executable)
@@ -1,10 +1,5 @@
 #!/usr/bin/env sh
 
-swtpm_localca_exe="$(dirname "$0")/swtpm_localca"
-if ! [ -x "$swtpm_localca_exe" ]; then
-  swtpm_localca_exe=@BINDIR@/swtpm_localca
-fi
-
-$swtpm_localca_exe "$@"
+@BINDIR@/swtpm_localca "$@"
 
 exit $?
diff --git a/samples/swtpm_localca.c b/samples/swtpm_localca.c
deleted file mode 100644 (file)
index 9b07a7c..0000000
+++ /dev/null
@@ -1,872 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * swtpm_localca.c: A tool for creating TPM 1.2 and TPM 2 certificates localy or using pkcs11
- *
- * Author: Stefan Berger, stefanb@linux.ibm.com
- *
- * Copyright (c) IBM Corporation, 2021
- */
-
-#include "config.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <pwd.h>
-#include <regex.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/file.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <glib.h>
-
-#include "swtpm_utils.h"
-#include "swtpm_localca_conf.h"
-#include "swtpm_localca_utils.h"
-
-#define SETUP_TPM2_F    1
-/* for TPM 2 EK */
-#define ALLOW_SIGNING_F 2
-#define DECRYPTION_F    4
-
-/* Default logging goes to stderr */
-gchar *gl_LOGFILE = NULL;
-
-#define LOCALCA_OPTIONS "swtpm-localca.options"
-#define LOCALCA_CONFIG  "swtpm-localca.conf"
-
-#if defined __APPLE__
-# define CERTTOOL_NAME "gnutls-certtool"
-#else
-# define CERTTOOL_NAME "certtool"
-#endif
-
-/* initialize the path of the options and config files */
-static int init(gchar **options_file, gchar **config_file)
-{
-    const char *xch = getenv("XDG_CONFIG_HOME");
-    const char *home = getenv("HOME");
-    char path[PATH_MAX];
-    const char *p = NULL;
-    int ret = 0;
-
-    if (xch != NULL &&
-        (p = pathjoin(path, sizeof(path), xch, LOCALCA_OPTIONS, NULL)) != NULL &&
-        access(p, R_OK) == 0) {
-        /* p is good */
-    } else if (home != NULL &&
-        (p = pathjoin(path, sizeof(path), home, ".config", LOCALCA_OPTIONS)) != NULL &&
-        access(p, R_OK) == 0) {
-        /* p is good */
-    } else {
-        p = pathjoin(path, sizeof(path), G_DIR_SEPARATOR_S, SYSCONFDIR, LOCALCA_OPTIONS);
-    }
-    *options_file = g_strdup(p);
-
-    if (xch != NULL &&
-        (p = pathjoin(path, sizeof(path), xch, LOCALCA_CONFIG, NULL)) != NULL &&
-        access(p, R_OK) == 0) {
-        /* p is good */
-    } else if (home != NULL &&
-        (p = pathjoin(path, sizeof(path), home, ".config", LOCALCA_CONFIG)) != NULL &&
-        access(p, R_OK) == 0) {
-        /* p is good */
-    } else {
-        p = pathjoin(path, sizeof(path), G_DIR_SEPARATOR_S, SYSCONFDIR, LOCALCA_CONFIG);
-    }
-    *config_file = g_strdup(p);
-
-    return ret;
-}
-
-/* Run the certtool command line prepared in cmd. Display error message
- * in case of failure and also display the keyfile if something goes wrong.
- */
-static int run_certtool(gchar **cmd, gchar **env, const char *msg, gchar *keyfile)
-{
-    g_autofree gchar *standard_error = NULL;
-    gint exit_status;
-    GError *error = NULL;
-    gboolean success;
-
-    success = g_spawn_sync(NULL, cmd, env, G_SPAWN_STDOUT_TO_DEV_NULL, NULL, NULL,
-                           NULL, &standard_error, &exit_status, &error);
-    if (!success || exit_status != 0) {
-        logerr(gl_LOGFILE, "%s" , msg);
-        if (keyfile)
-            logerr(gl_LOGFILE, " %s:", keyfile);
-        if (!success) {
-            logerr(gl_LOGFILE, "%s\n", error->message);
-            g_error_free(error);
-        } else {
-            logerr(gl_LOGFILE, "%s\n", standard_error);
-        }
-        return 1;
-    }
-    return 0;
-}
-
-/* Create a root CA key and cert and a local CA key and cert. The latter will be
- * used for signing the TPM certs.
- */
-static int create_localca_cert(const gchar *lockfile, const gchar *statedir,
-                               const gchar *signkey, const gchar *signkey_password,
-                               const gchar *issuercert)
-{
-    int lockfd;
-    int ret = 1;
-    struct stat statbuf;
-    int template1_file_fd = -1;
-    int template2_file_fd = -1;
-    g_autofree gchar *template1_file = NULL;
-    g_autofree gchar *template2_file = NULL;
-    gchar **certtool_env = NULL;
-
-    lockfd = lock_file(lockfile);
-    if (lockfd < 0)
-        return 1;
-
-    if (stat(statedir, &statbuf) != 0) {
-        if (makedir(statedir, "statedir") != 0)
-            goto error;
-    }
-
-    if (access(signkey, R_OK) != 0) {
-        g_autofree gchar *directory = g_path_get_dirname(signkey);
-        g_autofree gchar *cakey = g_strjoin(G_DIR_SEPARATOR_S, directory, "swtpm-localca-rootca-privkey.pem", NULL);
-        g_autofree gchar *cacert = g_strjoin(G_DIR_SEPARATOR_S, directory, "swtpm-localca-rootca-cert.pem", NULL);
-        const gchar *swtpm_rootca_password = g_getenv("SWTPM_ROOTCA_PASSWORD");
-        g_autofree gchar *certtool = g_find_program_in_path(CERTTOOL_NAME);
-        g_autofree gchar **cmd = NULL;
-        g_autofree gchar *fc = NULL;
-        const char *filecontent;
-
-        if (certtool == NULL) {
-            logerr(gl_LOGFILE, "Could not find %s in PATH.\n", CERTTOOL_NAME);
-            goto error;
-        }
-
-        /* generate the root-CA's private key */
-        cmd = concat_arrays(cmd, (gchar*[]){
-                                (gchar *)certtool, "--generate-privkey", "--outfile", cakey, NULL
-                            }, TRUE);
-        if (swtpm_rootca_password != NULL)
-            cmd = concat_arrays(cmd, (gchar*[]){
-                                   "--password", (gchar *)swtpm_rootca_password, NULL
-                                }, TRUE);
-        if (run_certtool(cmd, certtool_env, "Could not create root-CA key", cakey))
-            goto error;
-
-        if (chmod(cakey, S_IRUSR | S_IWUSR | S_IRGRP) != 0) {
-            logerr(gl_LOGFILE, "Could not chmod %s: %s\n", cakey, strerror(errno));
-            goto error;
-        }
-
-        certtool_env = g_environ_setenv(NULL, "PATH", g_getenv("PATH"), TRUE);
-
-        /* create the root-CA's cert */
-        filecontent = "cn=swtpm-localca-rootca\n"
-                      "ca\n"
-                      "cert_signing_key\n"
-                      "expiration_days = 3600\n";
-        template1_file_fd = write_to_tempfile(&template1_file,
-                                              (const unsigned char *)filecontent, strlen(filecontent));
-        if (template1_file_fd < 0)
-            goto error;
-
-        g_free(cmd);
-        cmd = concat_arrays(NULL,
-                            (gchar *[]) {
-                                certtool,
-                                "--generate-self-signed",
-                                "--template", template1_file,
-                                "--outfile", cacert,
-                                "--load-privkey", cakey,
-                                NULL
-                            }, FALSE);
-        if (swtpm_rootca_password != NULL)
-            certtool_env = g_environ_setenv(certtool_env, "GNUTLS_PIN", swtpm_rootca_password, TRUE);
-
-        if (run_certtool(cmd, certtool_env, "Could not create root-CA:", NULL))
-            goto error;
-
-        g_free(cmd);
-
-        /* create the intermediate CA's key */
-        cmd = concat_arrays(NULL,
-                            (gchar *[]) {
-                                certtool, "--generate-privkey", "--outfile", (gchar *)signkey, NULL
-                            }, FALSE);
-        if (signkey_password != NULL)
-            cmd = concat_arrays(cmd, (gchar *[]){
-                                    "--password", (gchar *)signkey_password, NULL},
-                                TRUE);
-        if (run_certtool(cmd, certtool_env, "Could not create local-CA key", cakey))
-            goto error;
-
-        if (chmod(signkey, S_IRUSR | S_IWUSR | S_IRGRP) != 0) {
-            logerr(gl_LOGFILE, "Could not chmod %s: %s\n", signkey, strerror(errno));
-            goto error;
-        }
-
-        filecontent = "cn=swtpm-localca\n"
-                      "ca\n"
-                      "cert_signing_key\n"
-                      "expiration_days = 3600\n";
-        if (swtpm_rootca_password != NULL && signkey_password != NULL)
-            fc = g_strdup_printf("%spassword = %s\n", filecontent, swtpm_rootca_password);
-        else
-            fc = g_strdup(filecontent);
-
-        template2_file_fd = write_to_tempfile(&template2_file,
-                                              (const unsigned char *)fc, strlen(fc));
-        if (template2_file_fd < 0)
-            goto error;
-
-        g_free(cmd);
-        cmd = concat_arrays(NULL,
-                            (gchar *[]) {
-                                certtool,
-                                "--generate-certificate",
-                                "--template", template2_file,
-                                "--outfile", (gchar *)issuercert,
-                                "--load-privkey", (gchar *)signkey,
-                                "--load-ca-privkey", cakey,
-                                "--load-ca-certificate", cacert,
-                                NULL
-                            }, FALSE);
-        if (signkey_password != NULL)
-            certtool_env = g_environ_setenv(certtool_env, "GNUTLS_PIN", signkey_password, TRUE);
-        else if (swtpm_rootca_password != NULL)
-            certtool_env = g_environ_setenv(certtool_env, "GNUTLS_PIN", swtpm_rootca_password, TRUE);
-
-        if (run_certtool(cmd, certtool_env, "Could not create local-CA:", NULL))
-            goto error;
-    }
-
-    ret = 0;
-
-error:
-    if (template1_file_fd >= 0)
-        close(template1_file_fd);
-    if (template1_file != NULL)
-        unlink(template1_file);
-
-    if (template2_file_fd >= 0)
-        close(template2_file_fd);
-    if (template2_file != NULL)
-        unlink(template2_file);
-    g_strfreev(certtool_env);
-
-    unlock_file(lockfd);
-
-    return ret;
-}
-
-/* Extract the ECC parameters from a string like x=12,y=34,id=secp384r1.
- * This function returns 1  on error, 2 if the ECC parameters could be extracted
- * and 0 if no parameters could be extracted (likely a modulus).
- */
-static gboolean extract_ecc_params(const gchar *ekparams, gchar **ecc_x, gchar **ecc_y, gchar **ecc_curveid)
-{
-    regmatch_t pmatch[5];
-    regex_t preg;
-    int ret;
-
-    if (regcomp(&preg, "x=([0-9A-Fa-f]+),y=([0-9A-Fa-f]+)(,id=([^,]+))?",
-                REG_EXTENDED) != 0) {
-        logerr(gl_LOGFILE, "Internal error: Could not compile regex\n");
-        return 1;
-    }
-
-    ret = 0;
-    if (regexec(&preg, ekparams, 5, pmatch, 0) == 0) {
-        *ecc_x = g_strndup(&ekparams[pmatch[1].rm_so],
-                           pmatch[1].rm_eo - pmatch[1].rm_so);
-        *ecc_y = g_strndup(&ekparams[pmatch[2].rm_so],
-                           pmatch[2].rm_eo - pmatch[2].rm_so);
-        if (pmatch[4].rm_so > 0 && pmatch[4].rm_eo > 0)
-            *ecc_curveid = g_strndup(&ekparams[pmatch[4].rm_so],
-                                     pmatch[4].rm_eo - pmatch[4].rm_so);
-        ret = 2;
-    }
-
-    regfree(&preg);
-
-    return ret;
-}
-
-/* Get the next serial number from the certserial file; if it contains
- * a non-numeric content start over with serial number '1'.
- */
-static int get_next_serial(const gchar *certserial, const gchar *lockfile,
-                           gchar **serial_str)
-{
-    g_autofree gchar *buffer = NULL;
-    size_t buffer_len;
-    unsigned long long serial, serial_n;
-    char *endptr = NULL;
-    int lockfd;
-    int ret = 1;
-
-    lockfd = lock_file(lockfile);
-    if (lockfd < 0)
-        return 1;
-
-    if (access(certserial, R_OK) != 0)
-        write_file(certserial, (unsigned char *)"1", 1);
-    if (read_file(certserial, &buffer, &buffer_len) != 0)
-        goto error;
-
-    if (buffer_len > 0) {
-        serial = strtoull(buffer, &endptr, 10);
-        if (*endptr == '\0') {
-            serial_n = serial + 1;
-        } else {
-            serial_n = 1;
-        }
-    } else {
-        serial_n = 1;
-    }
-    *serial_str = g_strdup_printf("%llu", serial_n);
-    write_file(certserial, (unsigned char *)*serial_str, strlen(*serial_str));
-    ret = 0;
-
-error:
-    unlock_file(lockfd);
-
-    return ret;
-}
-
-/* Create a TPM 1.2 or TPM 2 EK or platform cert */
-static int create_cert(unsigned long flags, const gchar *typ, const gchar *directory,
-                       gchar *ekparams, const gchar *vmid, gchar **tpm_spec_params,
-                       gchar **tpm_attr_params, const gchar *signkey,
-                       const gchar *signkey_password, const gchar *issuercert,
-                       const gchar *parentkey_password, gchar **swtpm_cert_env,
-                       const gchar *certserial, const gchar *lockfile,
-                       const gchar *optsfile)
-{
-    gchar ** optsfile_lines = NULL;
-    g_autofree gchar **options = NULL;
-    g_autofree gchar **keyparams = NULL;
-    g_autofree gchar **cmd = NULL;
-    g_autofree gchar *subject = NULL;
-    g_autofree gchar *ecc_x = NULL;
-    g_autofree gchar *ecc_y = NULL;
-    g_autofree gchar *ecc_curveid = NULL;
-    g_autofree gchar *certfile = NULL;
-    g_autofree gchar *serial_str = NULL;
-    gchar **to_free = NULL;
-    gchar **split;
-    const char *certtype;
-    int signkey_pwd_fd = -1;
-    int parentkey_pwd_fd  = -1;
-    g_autofree gchar *signkey_pwd_file = NULL;
-    g_autofree gchar *signkey_pwd_file_param = NULL;
-    g_autofree gchar *parentkey_pwd_file = NULL;
-    g_autofree gchar *parentkey_pwd_file_param = NULL;
-    gboolean success;
-    g_autofree gchar *standard_output = NULL;
-    g_autofree gchar *standard_error = NULL;
-    g_autofree gchar *swtpm_cert_path = NULL;
-    GError *error = NULL;
-    gint exit_status;
-    int ret = 1;
-    size_t i, j;
-
-    swtpm_cert_path = g_find_program_in_path("swtpm_cert");
-    if (swtpm_cert_path == NULL) {
-        logerr(gl_LOGFILE, "Could not find swtpm_cert in PATH.\n");
-        return 1;
-    }
-
-    if (get_next_serial(certserial, lockfile, &serial_str) != 0)
-        return 1;
-
-    /* try to read the optsfile */
-    read_file_lines(optsfile, &optsfile_lines);
-
-    /* split each line from the optsfile and add the stripped parameters to options */
-    for (i = 0; optsfile_lines != NULL && optsfile_lines[i] != NULL; i++) {
-        gchar *chomped = g_strchomp(optsfile_lines[i]);
-        if (strlen(chomped) == 0)
-            continue;
-
-        split = g_strsplit(chomped, " ", -1);
-        for (j = 0; split[j] != NULL; j++) {
-            chomped = g_strchomp(split[j]);
-            if (strlen(chomped) > 0) {
-                gchar *to_add = g_strdup(chomped);
-                options = concat_arrays(options, (gchar *[]){to_add, NULL}, TRUE);
-                /* need to collect this also to free later on */
-                to_free = concat_arrays(to_free, (gchar *[]){to_add, NULL}, TRUE);
-            }
-        }
-        g_strfreev(split);
-    }
-
-    if (vmid != NULL)
-        subject = g_strdup_printf("CN=%s", vmid);
-    else
-        subject = g_strdup("CN=unknown");
-
-    if (flags & SETUP_TPM2_F)
-        options = concat_arrays(options, (gchar *[]){"--tpm2", NULL}, TRUE);
-    else
-        options = concat_arrays(options, (gchar *[]){"--add-header", NULL}, TRUE);
-
-    if (strcmp(typ, "ek") == 0) {
-        if (flags & ALLOW_SIGNING_F)
-            options = concat_arrays(options, (gchar *[]){"--allow-signing", NULL}, TRUE);
-        if (flags & DECRYPTION_F)
-            options = concat_arrays(options, (gchar *[]){"--decryption", NULL}, TRUE);
-    }
-
-    switch (extract_ecc_params(ekparams, &ecc_x, &ecc_y, &ecc_curveid)) {
-    case 1:
-        goto error;
-    case 2:
-        keyparams = concat_arrays((gchar *[]){
-                                      "--ecc-x", ecc_x,
-                                      "--ecc-y", ecc_y,
-                                      NULL
-                                  },
-                                  NULL, FALSE);
-        if (ecc_curveid != NULL)
-           keyparams = concat_arrays(keyparams,
-                                     (gchar *[]){
-                                         "--ecc-curveid", ecc_curveid,
-                                         NULL
-                                     }, TRUE);
-        break;
-    case 0:
-        keyparams = concat_arrays((gchar *[]){
-                                      "--modulus", ekparams,
-                                      NULL},
-                                   NULL, FALSE);
-        break;
-    }
-
-    cmd = concat_arrays((gchar *[]){
-                            swtpm_cert_path, "--subject", subject, NULL
-                        }, options, FALSE);
-
-    if (signkey_password != NULL) {
-        signkey_pwd_fd = write_to_tempfile(&signkey_pwd_file,
-                                           (unsigned char *)signkey_password, strlen(signkey_password));
-        if (signkey_pwd_fd < 0)
-            goto error;
-
-        signkey_pwd_file_param = g_strdup_printf("file:%s", signkey_pwd_file);
-        cmd = concat_arrays(cmd, (gchar*[]){"--signkey-pwd", signkey_pwd_file_param, NULL}, TRUE);
-    }
-    if (parentkey_password != NULL) {
-        parentkey_pwd_fd = write_to_tempfile(&parentkey_pwd_file,
-                                             (unsigned char *)parentkey_password, strlen(parentkey_password));
-        if (parentkey_pwd_fd < 0)
-            goto error;
-
-        parentkey_pwd_file_param = g_strdup_printf("file:%s", parentkey_pwd_file);
-        cmd = concat_arrays(cmd, (gchar*[]){"--parentkey-pwd", parentkey_pwd_file_param, NULL}, TRUE);
-    }
-
-    if (strcmp(typ, "ek") == 0)
-        cmd = concat_arrays(cmd, tpm_spec_params, TRUE);
-
-    cmd = concat_arrays(cmd, tpm_attr_params, TRUE);
-
-    if (strcmp(typ, "platform") == 0) {
-        certfile = g_strjoin(G_DIR_SEPARATOR_S, directory, "platform.cert", NULL);
-        cmd = concat_arrays(cmd,
-                            (gchar *[]){
-                                "--type", "platform",
-                                "--out-cert", certfile,
-                                NULL},
-                            TRUE);
-    } else {
-        certfile = g_strjoin(G_DIR_SEPARATOR_S, directory, "ek.cert", NULL);
-        cmd = concat_arrays(cmd,
-                            (gchar *[]){
-                                "--out-cert", certfile,
-                                NULL
-                            }, TRUE);
-    }
-
-    cmd = concat_arrays(cmd, keyparams, TRUE);
-    cmd = concat_arrays(cmd, (gchar *[]){
-                            "--signkey", (gchar *)signkey,
-                            "--issuercert", (gchar *)issuercert,
-                            "--days", "3600",
-                            "--serial", (gchar *)serial_str,
-                            NULL
-                        }, TRUE);
-
-    if (strcmp(typ, "ek") == 0)
-        certtype = "EK";
-    else
-        certtype = "platform";
-#if 0
-    {
-        g_autofree gchar *join = g_strjoinv(" ", cmd);
-        fprintf(stderr, "Starting: %s\n", join);
-    }
-#endif
-    success = g_spawn_sync(NULL, cmd, swtpm_cert_env, G_SPAWN_DEFAULT, NULL, NULL,
-                           &standard_output, &standard_error, &exit_status, &error);
-    if (!success) {
-        logerr(gl_LOGFILE, "Could not run swtpm_cert: %s\n", error);
-        g_error_free(error);
-        goto error;
-    }
-    if (exit_status != 0) {
-        logerr(gl_LOGFILE, "Could not create %s certificate locally\n", certtype);
-        logerr(gl_LOGFILE, "%s\n", standard_error);
-        goto error;
-    }
-
-    logit(gl_LOGFILE, "Successfully created %s certificate locally.\n", certtype);
-    ret = 0;
-
-error:
-    g_strfreev(optsfile_lines);
-    g_strfreev(to_free);
-
-    if (signkey_pwd_fd >= 0)
-       close(signkey_pwd_fd);
-    if (signkey_pwd_file)
-       unlink(signkey_pwd_file);
-
-    if (parentkey_pwd_fd >= 0)
-       close(parentkey_pwd_fd);
-    if (parentkey_pwd_file)
-       unlink(parentkey_pwd_file);
-
-    return ret;
-}
-
-static void usage(const char *prgname)
-{
-   printf(
-        "Usage: %s [options]\n"
-        "\n"
-        "The following options are supported:\n"
-        "\n"
-        "--type type           The type of certificate to create: 'ek' or 'platform'\n"
-        "--ek key-param        The modulus of an RSA key or x=...,y=,... for an EC key\n"
-        "--dir directory       The directory to write the resulting certificate into\n"
-        "--vmid vmid           The ID of the virtual machine\n"
-        "--optsfile file       A file containing options to pass to swtpm_cert\n"
-        "--configfile file     A file containing configuration parameters for directory,\n"
-        "                      signing key and password and certificate to use\n"
-        "--logfile file        A file to write a log into\n"
-        "--tpm-spec-family s   The implemented spec family, e.g., '2.0'\n"
-        "--tpm-spec-revision i The spec revision of the TPM as integer; e.g., 146\n"
-        "--tpm-spec-level i    The spec level of the TPM; must be an integer; e.g. 0\n"
-        "--tpm-manufacturer s  The manufacturer of the TPM; e.g., id:00001014\n"
-        "--tpm-model s         The model of the TPM; e.g., 'swtpm'\n"
-        "--tpm-version i       The (firmware) version of the TPM; e.g., id:20160511\n"
-        "--tpm2                Generate a certificate for a TPM 2\n"
-        "--allow-signing       The TPM 2's EK can be used for signing\n"
-        "--decryption          The TPM 2's EK can be used for decryption\n"
-        "--help, -h, -?        Display this help screen and exit\n"
-        "\n"
-        "\n"
-        "The following environment variables are supported:\n"
-        "\n"
-        "SWTPM_ROOTCA_PASSWORD  The root CA's private key password\n"
-        "\n", prgname);
-}
-
-int main(int argc, char *argv[])
-{
-    int opt, option_index = 0;
-    static const struct option long_options[] = {
-        {"type", required_argument, NULL, 't'},
-        {"ek", required_argument, NULL, 'e'},
-        {"dir", required_argument, NULL, 'd'},
-        {"vmid", required_argument, NULL, 'v'},
-        {"optsfile", required_argument, NULL, 'o'},
-        {"configfile", required_argument, NULL, 'c'},
-        {"logfile", required_argument, NULL, 'l'},
-        {"tpm-spec-family", required_argument, NULL, 'f'},
-        {"tpm-spec-revision", required_argument, NULL, 'r'},
-        {"tpm-spec-level", required_argument, NULL, '1'},
-        {"tpm-manufacturer", required_argument, NULL, 'a'},
-        {"tpm-model", required_argument, NULL, 'm'},
-        {"tpm-version", required_argument, NULL, 's'},
-        {"tpm2", no_argument, NULL, '2'},
-        {"allow-signing", no_argument, NULL, 'i'},
-        {"decryption", no_argument, NULL, 'y'},
-        {"help", no_argument, NULL, 'h'},
-    };
-    g_autofree gchar *default_options_file = NULL;
-    g_autofree gchar *default_config_file = NULL;
-    g_autofree gchar *optsfile = NULL;
-    g_autofree gchar *configfile = NULL;
-    unsigned long flags = 0;
-    g_autofree gchar *typ =g_strdup("");
-    g_autofree gchar *ekparams = g_strdup("");
-    g_autofree gchar *directory = g_strdup("."); /* default to current directory */
-    g_autofree gchar *vmid = NULL;
-    g_autofree gchar *lockfile = NULL;
-    g_autofree gchar *statedir = NULL;
-    g_autofree gchar *signkey = NULL;
-    g_autofree gchar *signkey_password = NULL;
-    g_autofree gchar *parentkey_password = NULL;
-    g_autofree gchar *issuercert = NULL;
-    g_autofree gchar *certserial = NULL;
-    gchar **tpm_spec_params = NULL;
-    gchar **tpm_attr_params = NULL;
-    gchar **config_file_lines = NULL;
-    gchar **swtpm_cert_env = NULL;
-    const struct passwd *curr_user;
-    struct stat statbuf;
-    int ret = 1;
-
-    if (init(&default_options_file, &default_config_file) < 0)
-        goto error;
-    optsfile = g_strdup(default_options_file);
-    configfile = g_strdup(default_config_file);
-
-    while ((opt = getopt_long(argc, argv, "h?",
-                              long_options, &option_index)) != -1) {
-        switch (opt) {
-        case 't': /* --type */
-            g_free(typ);
-            typ = g_strdup(optarg);
-            break;
-        case 'e': /* --ek */
-            g_free(ekparams);
-            ekparams = g_strdup(optarg);
-            break;
-        case 'd': /* --dir */
-            g_free(directory);
-            directory = g_strdup(optarg);
-            break;
-        case 'v': /* --vmid */
-            g_free(vmid);
-            vmid = g_strdup(optarg);
-            break;
-        case 'o': /* --optsfile */
-            g_free(optsfile);
-            optsfile = g_strdup(optarg);
-            break;
-        case 'c': /* --configfile */
-            g_free(configfile);
-            configfile = g_strdup(optarg);
-            break;
-        case 'l': /* --logfile */
-            g_free(gl_LOGFILE);
-            gl_LOGFILE = g_strdup(optarg);
-            break;
-        case 'f': /* --tpm-spec-family */
-        case 'r': /* --tpm-spec-revision */
-        case '1': /* --tpm-spec-level */
-            tpm_spec_params = concat_arrays(tpm_spec_params,
-                          (gchar *[]) {
-                              g_strdup_printf("--%s", long_options[option_index].name), g_strdup(optarg), NULL
-                          }, TRUE);
-            break;
-        case 'a': /* --tpm-manufacturer */
-        case 'm': /* --tpm-model */
-        case 's': /* --tpm-version */
-            tpm_attr_params = concat_arrays(tpm_attr_params,
-                          (gchar *[]) {
-                              g_strdup_printf("--%s", long_options[option_index].name), g_strdup(optarg), NULL
-                          }, TRUE);
-            break;
-        case '2': /* --tpm2 */
-            flags |= SETUP_TPM2_F;
-            break;
-        case 'i': /* --allow-signing */
-            flags |= ALLOW_SIGNING_F;
-            break;
-        case 'y': /* --decryption */
-            flags |= DECRYPTION_F;
-            break;
-        case '?':
-        case 'h': /* --help */
-            usage(argv[0]);
-            ret = 0;
-            goto out;
-        default:
-            fprintf(stderr, "Unknown option code %d\n", opt);
-            usage(argv[0]);
-            goto error;
-        }
-    }
-
-    curr_user = getpwuid(getuid());
-
-    if (gl_LOGFILE != NULL) {
-        FILE *tmpfile;
-
-        if (stat(gl_LOGFILE, &statbuf) == 0 &&
-            (statbuf.st_mode & S_IFMT) == S_IFLNK) {
-            fprintf(stderr, "Logfile must not be a symlink.\n");
-            goto error;
-        }
-        tmpfile = fopen(gl_LOGFILE, "a"); // do not truncate
-        if (tmpfile == NULL) {
-            fprintf(stderr, "Cannot write to logfile %s.\n", gl_LOGFILE);
-            goto error;
-        }
-        fclose(tmpfile);
-    }
-
-    if (access(optsfile, R_OK) != 0) {
-        logerr(gl_LOGFILE, "Need read rights on options file %s for user %s.\n",
-               optsfile, curr_user ? curr_user->pw_name : "<unknown>");
-        goto error;
-    }
-
-    if (access(configfile, R_OK) != 0) {
-        logerr(gl_LOGFILE, "Need read rights on config file %s for user %s.\n",
-               configfile, curr_user ? curr_user->pw_name : "<unknown>");
-        goto error;
-    }
-
-    if (read_file_lines(configfile, &config_file_lines) != 0)
-        goto error;
-
-    statedir = get_config_value(config_file_lines, "statedir", NULL);
-    if (statedir == NULL) {
-        logerr(gl_LOGFILE, "Missing 'statedir' config value in config file %s.\n", configfile);
-        goto error;
-    }
-    if (makedir(statedir, "statedir") != 0)
-        goto error;
-    if (access(statedir, W_OK | R_OK) != 0) {
-        logerr(gl_LOGFILE, "Need read/write rights on statedir %s for user %s.\n",
-               statedir, curr_user ? curr_user->pw_name : "<unknown>");
-        goto error;
-    }
-
-    lockfile = g_strjoin(G_DIR_SEPARATOR_S, statedir, ".lock.swtpm-localca", NULL);
-    if (stat(lockfile, &statbuf) == 0 &&
-        access(lockfile, W_OK | R_OK) != 0) {
-        logerr(gl_LOGFILE, "Need read/write rights on %s for user %s.\n",
-               lockfile, curr_user ? curr_user->pw_name : "<unknown>");
-        goto error;
-    }
-
-    signkey = get_config_value(config_file_lines, "signingkey", NULL);
-    if (signkey == NULL) {
-        logerr(gl_LOGFILE, "Missing 'signingkey' config value in config file %s.\n",
-               configfile);
-        goto error;
-    }
-
-    if (!g_str_has_prefix(signkey, "tpmkey:file=") &&
-        !g_str_has_prefix(signkey, "tpmkey:uuid=") &&
-        !g_str_has_prefix(signkey, "pkcs11:")) {
-        g_autofree gchar *d = g_path_get_dirname(signkey);
-        if (makedir(d, "signkey") != 0)
-            goto error;
-    }
-
-    signkey_password = get_config_value(config_file_lines, "signingkey_password", NULL);
-    parentkey_password = get_config_value(config_file_lines, "parentkey_password", NULL);
-
-    issuercert = get_config_value(config_file_lines, "issuercert", NULL);
-    if (issuercert == NULL) {
-        logerr(gl_LOGFILE, "Missing 'issuercert' config value in config file %s.\n", configfile);
-        goto error;
-    }
-    {
-       g_autofree gchar *d = g_path_get_dirname(issuercert);
-       if (makedir(d, "issuercert") != 0)
-           goto error;
-    }
-
-    swtpm_cert_env = g_get_environ();
-
-    // TPM keys are GNUTLS URIs...
-    if (g_str_has_prefix(signkey, "tpmkey:file=") || g_str_has_prefix(signkey, "tpmkey:uuid=")) {
-        gchar *tss_tcsd_hostname = get_config_value(config_file_lines,
-                                                    "TSS_TCSD_HOSTNAME", "localhost");
-        gchar *tss_tcsd_port = get_config_value(config_file_lines,
-                                                "TSS_TCSD_PORT", "30003");
-        swtpm_cert_env = g_environ_setenv(swtpm_cert_env,
-                                          "TSS_TCSD_HOSTNAME", tss_tcsd_hostname, TRUE);
-        swtpm_cert_env = g_environ_setenv(swtpm_cert_env,
-                                          "TSS_TCSD_PORT", tss_tcsd_port, TRUE);
-
-        logit(gl_LOGFILE, "CA uses a GnuTLS TPM key; using TSS_TCSD_HOSTNAME=%s " \
-                          "TSS_TCSD_PORT=%s\n", tss_tcsd_hostname, tss_tcsd_port);
-    } else if (g_str_has_prefix(signkey, "pkcs11:")) {
-        gchar *tmp = str_replace(signkey, "\\;", ";"); /* historical reasons ... */
-        g_free(signkey);
-        signkey = tmp;
-
-        if (signkey_password != NULL) {
-            swtpm_cert_env = g_environ_setenv(swtpm_cert_env,
-                                              "SWTPM_PKCS11_PIN", g_strdup(signkey_password), TRUE);
-            logit(gl_LOGFILE, "CA uses a PKCS#11 key; using SWTPM_PKCS11_PIN\n");
-        } else {
-            g_autofree gchar *swtpm_pkcs11_pin = NULL;
-
-            swtpm_pkcs11_pin = get_config_value(config_file_lines,
-                                                "SWTPM_PKCS11_PIN", "swtpm-tpmca");
-            swtpm_cert_env = g_environ_setenv(swtpm_cert_env,
-                                              "SWTPM_PKCS11_PIN", swtpm_pkcs11_pin, TRUE);
-            logit(gl_LOGFILE, "CA uses a PKCS#11 key; using SWTPM_PKCS11_PIN\n");
-        }
-        ret = get_config_envvars(config_file_lines, &swtpm_cert_env);
-        if (ret != 0)
-            goto error;
-    } else {
-        if (access(signkey, R_OK) != 0) {
-            if (stat(signkey, &statbuf) == 0) {
-                logerr(gl_LOGFILE, "Need read rights on signing key %s for user %s.\n",
-                       signkey, curr_user ? curr_user->pw_name : "<unknown>");
-                goto error;
-            }
-
-            logit(gl_LOGFILE, "Creating root CA and a local CA's signing key and issuer cert.\n");
-            if (create_localca_cert(lockfile, statedir, signkey, signkey_password,
-                                    issuercert) != 0) {
-                logerr(gl_LOGFILE, "Error creating local CA's signing key and cert.\n");
-                goto error;
-            }
-
-            if (access(signkey, R_OK) != 0) {
-                logerr(gl_LOGFILE, "Need read rights on signing key %s for user %s.\n",
-                       signkey, curr_user ? curr_user->pw_name : "<unknown>");
-                goto error;
-            }
-        }
-    }
-
-    if (access(issuercert, R_OK) != 0) {
-        logerr(gl_LOGFILE, "Need read rights on issuer certificate %s for user %s.\n",
-               issuercert, curr_user ? curr_user->pw_name : "<unknown>");
-        goto error;
-    }
-
-    {
-        g_autofree gchar *d = NULL;
-        g_autofree gchar *p = g_strjoin(G_DIR_SEPARATOR_S, statedir, "certserial", NULL);
-
-        certserial = get_config_value(config_file_lines, "certserial", p);
-        d = g_path_get_dirname(certserial);
-        if (makedir(d, "certserial") != 0)
-            goto error;
-    }
-
-    ret = create_cert(flags, typ, directory, ekparams, vmid, tpm_spec_params, tpm_attr_params,
-                      signkey, signkey_password, issuercert, parentkey_password, swtpm_cert_env,
-                      certserial, lockfile, optsfile);
-
-out:
-error:
-    g_strfreev(tpm_attr_params);
-    g_strfreev(tpm_spec_params);
-
-    exit(ret);
-}
diff --git a/samples/swtpm_localca.h b/samples/swtpm_localca.h
deleted file mode 100644 (file)
index c1cb19f..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * swtpm_localca.h: Header file
- *
- * Author: Stefan Berger, stefanb@linux.ibm.com
- *
- * Copyright (c) IBM Corporation, 2021
- */
-
-#ifndef SWTPM_LOCALCA_H
-#define SWTPM_LOCALCA_H
-
-#include <glib.h>
-
-extern gchar *gl_LOGFILE;
-
-#endif /* SWTPM_LOCALCA_H */
diff --git a/samples/swtpm_localca_conf.h.in b/samples/swtpm_localca_conf.h.in
deleted file mode 100644 (file)
index 4276942..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * swtpm_setup_conf.h: Compile-time constants
- *
- * Author: Stefan Berger, stefanb@linux.ibm.com
- *
- * Copyright (c) IBM Corporation, 2021
- */
-
-#ifndef SWTPM_LOCALCA_CONF_H
-#define SWTPM_LOCALCA_CONF_H
-
-#define SYSCONFDIR "@SYSCONFDIR@"
-
-#endif /* SWTPM_LOCALCA_CONF_H */
diff --git a/samples/swtpm_localca_utils.c b/samples/swtpm_localca_utils.c
deleted file mode 100644 (file)
index 7aeb9cf..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * swtpm_localca_utils.c: Utility functions
- *
- * Author: Stefan Berger, stefanb@linux.ibm.com
- *
- * Copyright (c) IBM Corporation, 2021
- */
-
-#include "config.h"
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <regex.h>
-#include <errno.h>
-#include <sys/file.h>
-
-#include "swtpm_utils.h"
-#include "swtpm_localca.h"
-#include "swtpm_localca_utils.h"
-
-/* Create a directory pat (and all its predecessors) if it doesn't exist */
-int makedir(const char *dirname, const char *purpose)
-{
-    struct stat statbuf;
-
-    if (stat(dirname, &statbuf) != 0) {
-        logit(gl_LOGFILE, "Creating swtpm-localca dir '%s'.\n", dirname);
-        if (g_mkdir_with_parents(dirname, S_IRWXU | S_IRWXG | S_IXGRP | S_IRGRP) == -1) {
-            logerr(gl_LOGFILE, "Could not create directory for '%s': %s\n",
-                   purpose, strerror(errno));
-            return 1;
-        }
-    }
-    return 0;
-}
-
-/* Get a configuration value given its name */
-gchar *get_config_value(gchar **config_file_lines, const gchar *configname, const gchar *fallback)
-{
-    g_autofree gchar *regex = g_strdup_printf("^%s[[:space:]]*=[[:space:]]*([^#\n]*).*", configname);
-    gchar *result = NULL;
-    regex_t preg;
-    size_t idx;
-    regmatch_t pmatch[2];
-
-    if (regcomp(&preg, regex, REG_EXTENDED) != 0) {
-        logerr(gl_LOGFILE, "Internal error: Could not compile regex\n");
-        goto error;
-    }
-
-    for (idx = 0; config_file_lines[idx] != NULL; idx++) {
-        const gchar *line = config_file_lines[idx];
-        if (regexec(&preg, line, 2, pmatch, 0) == 0) {
-            result = g_strndup(&line[pmatch[1].rm_so],
-                               pmatch[1].rm_eo - pmatch[1].rm_so);
-            /* coverity: g_strchmop modifies in-place */
-            result = g_strchomp(result);
-            break;
-        }
-    }
-    regfree(&preg);
-
-error:
-    if (result == NULL)
-        result = g_strdup(fallback);
-    //printf("Found match for %s: |%s|\n", configname, result);
-
-    return result;
-}
-
-/* Extract all environment variables from the config file and add them to
- * the given environent.
- * Environment variable lines must start with 'env:' and must not contain
- * trailing spaces or a comment starting with '#'
- */
-int get_config_envvars(gchar **config_file_lines, gchar ***env)
-{
-    const char *regex = "^env:([a-zA-Z_][a-zA-Z_0-9]*)[[:space:]]*=[[:space:]]*([^\n]*)";
-    regex_t preg;
-    size_t idx;
-    regmatch_t pmatch[3];
-
-    if (regcomp(&preg, regex, REG_EXTENDED) != 0) {
-        logerr(gl_LOGFILE, "Internal error: Could not compile regex\n");
-        return 1;
-    }
-
-    for (idx = 0; config_file_lines[idx] != NULL; idx++) {
-        const gchar *line = config_file_lines[idx];
-        if (regexec(&preg, line, 3, pmatch, 0) == 0) {
-            g_autofree gchar *key = NULL, *value = NULL;
-
-            key = g_strndup(&line[pmatch[1].rm_so],
-                            pmatch[1].rm_eo - pmatch[1].rm_so);
-            value = g_strndup(&line[pmatch[2].rm_so],
-                              pmatch[2].rm_eo - pmatch[2].rm_so);
-            *env = g_environ_setenv(*env, key, value, TRUE);
-        }
-    }
-
-    regfree(&preg);
-
-    return 0;
-}
-
-/* flock a file; the file descriptor for the file to unlock later on is returned */
-int lock_file(const gchar *lockfile)
-{
-    int lockfd;
-    mode_t mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
-
-    lockfd = open(lockfile, O_RDWR | O_CREAT, mode);
-    if (lockfd < 0) {
-        logerr(gl_LOGFILE, "Could not open lockfile %s: %s\n", lockfile, strerror(errno));
-        return -1;
-    }
-
-    if (flock(lockfd, LOCK_EX) < 0) {
-        logerr(gl_LOGFILE, "Could not lock file %s: %s\n", lockfile, strerror(errno));
-        close(lockfd);
-        return -1;
-    }
-    return lockfd;
-}
-
-/* unlock a file previously locked using lock_file */
-void unlock_file(int lockfd) {
-    if (lockfd >= 0) {
-        flock(lockfd, LOCK_UN);
-        close(lockfd);
-    }
-}
diff --git a/samples/swtpm_localca_utils.h b/samples/swtpm_localca_utils.h
deleted file mode 100644 (file)
index ccbf714..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * swtpm_localca_utils.h: Header file for swtpm_localca_utils.c
- *
- * Author: Stefan Berger, stefanb@linux.ibm.com
- *
- * Copyright (c) IBM Corporation, 2021
- */
-
-#ifndef SWTPM_LOCALCA_UTILS_H
-#define SWTPM_LOCALCA_UTILS_H
-
-#include <glib.h>
-
-gchar *get_config_value(gchar **config_file_lines, const gchar *varname, const gchar *fallback);
-int get_config_envvars(gchar **config_file_lines, gchar  ***env);
-
-int makedir(const char *dirname, const char *purpose);
-
-int lock_file(const gchar *lockfile);
-void unlock_file(int lockfd);
-
-#endif /* SWTPM_LOCALCA_UTILS_H */
index dba32c8c0daa5e510af85460962fade1b50a2fe5..9e03c78afc46c409ad7613e332d7730316b40ce4 100644 (file)
@@ -10,6 +10,7 @@ SUBDIRS = \
        swtpm_bios \
        swtpm_cert \
        swtpm_ioctl \
+       swtpm_localca \
        swtpm_setup
 
 if WITH_SELINUX
diff --git a/src/swtpm_localca/Makefile.am b/src/swtpm_localca/Makefile.am
new file mode 100644 (file)
index 0000000..bc5c641
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# src/swtpm_localca/Makefile.am
+#
+# For the license, see the LICENSE file in the root directory.
+#
+
+bin_PROGRAMS = \
+       swtpm_localca
+
+noinst_HEADERS = \
+       swtpm_localca.h \
+       swtpm_localca_utils.h
+
+swtpm_localca_CFLAGS = \
+       -I$(top_srcdir)/src/utils \
+       $(GLIB_CFLAGS) \
+       $(HARDENING_CFLAGS)
+
+swtpm_localca_DEPENDENCIES = \
+       $(top_builddir)/src/utils/libswtpm_utils.la
+
+swtpm_localca_LDADD = \
+       $(top_builddir)/src/utils/libswtpm_utils.la
+
+swtpm_localca_LDFLAGS = \
+       -L$(top_builddir)/src/utils -lswtpm_utils \
+       $(GLIB_LIBS) \
+       $(HARDENING_LDFLAGS)
+
+swtpm_localca_SOURCES = \
+       swtpm_localca.c \
+       swtpm_localca_utils.c
diff --git a/src/swtpm_localca/swtpm_localca.c b/src/swtpm_localca/swtpm_localca.c
new file mode 100644 (file)
index 0000000..9b07a7c
--- /dev/null
@@ -0,0 +1,872 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * swtpm_localca.c: A tool for creating TPM 1.2 and TPM 2 certificates localy or using pkcs11
+ *
+ * Author: Stefan Berger, stefanb@linux.ibm.com
+ *
+ * Copyright (c) IBM Corporation, 2021
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <pwd.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <glib.h>
+
+#include "swtpm_utils.h"
+#include "swtpm_localca_conf.h"
+#include "swtpm_localca_utils.h"
+
+#define SETUP_TPM2_F    1
+/* for TPM 2 EK */
+#define ALLOW_SIGNING_F 2
+#define DECRYPTION_F    4
+
+/* Default logging goes to stderr */
+gchar *gl_LOGFILE = NULL;
+
+#define LOCALCA_OPTIONS "swtpm-localca.options"
+#define LOCALCA_CONFIG  "swtpm-localca.conf"
+
+#if defined __APPLE__
+# define CERTTOOL_NAME "gnutls-certtool"
+#else
+# define CERTTOOL_NAME "certtool"
+#endif
+
+/* initialize the path of the options and config files */
+static int init(gchar **options_file, gchar **config_file)
+{
+    const char *xch = getenv("XDG_CONFIG_HOME");
+    const char *home = getenv("HOME");
+    char path[PATH_MAX];
+    const char *p = NULL;
+    int ret = 0;
+
+    if (xch != NULL &&
+        (p = pathjoin(path, sizeof(path), xch, LOCALCA_OPTIONS, NULL)) != NULL &&
+        access(p, R_OK) == 0) {
+        /* p is good */
+    } else if (home != NULL &&
+        (p = pathjoin(path, sizeof(path), home, ".config", LOCALCA_OPTIONS)) != NULL &&
+        access(p, R_OK) == 0) {
+        /* p is good */
+    } else {
+        p = pathjoin(path, sizeof(path), G_DIR_SEPARATOR_S, SYSCONFDIR, LOCALCA_OPTIONS);
+    }
+    *options_file = g_strdup(p);
+
+    if (xch != NULL &&
+        (p = pathjoin(path, sizeof(path), xch, LOCALCA_CONFIG, NULL)) != NULL &&
+        access(p, R_OK) == 0) {
+        /* p is good */
+    } else if (home != NULL &&
+        (p = pathjoin(path, sizeof(path), home, ".config", LOCALCA_CONFIG)) != NULL &&
+        access(p, R_OK) == 0) {
+        /* p is good */
+    } else {
+        p = pathjoin(path, sizeof(path), G_DIR_SEPARATOR_S, SYSCONFDIR, LOCALCA_CONFIG);
+    }
+    *config_file = g_strdup(p);
+
+    return ret;
+}
+
+/* Run the certtool command line prepared in cmd. Display error message
+ * in case of failure and also display the keyfile if something goes wrong.
+ */
+static int run_certtool(gchar **cmd, gchar **env, const char *msg, gchar *keyfile)
+{
+    g_autofree gchar *standard_error = NULL;
+    gint exit_status;
+    GError *error = NULL;
+    gboolean success;
+
+    success = g_spawn_sync(NULL, cmd, env, G_SPAWN_STDOUT_TO_DEV_NULL, NULL, NULL,
+                           NULL, &standard_error, &exit_status, &error);
+    if (!success || exit_status != 0) {
+        logerr(gl_LOGFILE, "%s" , msg);
+        if (keyfile)
+            logerr(gl_LOGFILE, " %s:", keyfile);
+        if (!success) {
+            logerr(gl_LOGFILE, "%s\n", error->message);
+            g_error_free(error);
+        } else {
+            logerr(gl_LOGFILE, "%s\n", standard_error);
+        }
+        return 1;
+    }
+    return 0;
+}
+
+/* Create a root CA key and cert and a local CA key and cert. The latter will be
+ * used for signing the TPM certs.
+ */
+static int create_localca_cert(const gchar *lockfile, const gchar *statedir,
+                               const gchar *signkey, const gchar *signkey_password,
+                               const gchar *issuercert)
+{
+    int lockfd;
+    int ret = 1;
+    struct stat statbuf;
+    int template1_file_fd = -1;
+    int template2_file_fd = -1;
+    g_autofree gchar *template1_file = NULL;
+    g_autofree gchar *template2_file = NULL;
+    gchar **certtool_env = NULL;
+
+    lockfd = lock_file(lockfile);
+    if (lockfd < 0)
+        return 1;
+
+    if (stat(statedir, &statbuf) != 0) {
+        if (makedir(statedir, "statedir") != 0)
+            goto error;
+    }
+
+    if (access(signkey, R_OK) != 0) {
+        g_autofree gchar *directory = g_path_get_dirname(signkey);
+        g_autofree gchar *cakey = g_strjoin(G_DIR_SEPARATOR_S, directory, "swtpm-localca-rootca-privkey.pem", NULL);
+        g_autofree gchar *cacert = g_strjoin(G_DIR_SEPARATOR_S, directory, "swtpm-localca-rootca-cert.pem", NULL);
+        const gchar *swtpm_rootca_password = g_getenv("SWTPM_ROOTCA_PASSWORD");
+        g_autofree gchar *certtool = g_find_program_in_path(CERTTOOL_NAME);
+        g_autofree gchar **cmd = NULL;
+        g_autofree gchar *fc = NULL;
+        const char *filecontent;
+
+        if (certtool == NULL) {
+            logerr(gl_LOGFILE, "Could not find %s in PATH.\n", CERTTOOL_NAME);
+            goto error;
+        }
+
+        /* generate the root-CA's private key */
+        cmd = concat_arrays(cmd, (gchar*[]){
+                                (gchar *)certtool, "--generate-privkey", "--outfile", cakey, NULL
+                            }, TRUE);
+        if (swtpm_rootca_password != NULL)
+            cmd = concat_arrays(cmd, (gchar*[]){
+                                   "--password", (gchar *)swtpm_rootca_password, NULL
+                                }, TRUE);
+        if (run_certtool(cmd, certtool_env, "Could not create root-CA key", cakey))
+            goto error;
+
+        if (chmod(cakey, S_IRUSR | S_IWUSR | S_IRGRP) != 0) {
+            logerr(gl_LOGFILE, "Could not chmod %s: %s\n", cakey, strerror(errno));
+            goto error;
+        }
+
+        certtool_env = g_environ_setenv(NULL, "PATH", g_getenv("PATH"), TRUE);
+
+        /* create the root-CA's cert */
+        filecontent = "cn=swtpm-localca-rootca\n"
+                      "ca\n"
+                      "cert_signing_key\n"
+                      "expiration_days = 3600\n";
+        template1_file_fd = write_to_tempfile(&template1_file,
+                                              (const unsigned char *)filecontent, strlen(filecontent));
+        if (template1_file_fd < 0)
+            goto error;
+
+        g_free(cmd);
+        cmd = concat_arrays(NULL,
+                            (gchar *[]) {
+                                certtool,
+                                "--generate-self-signed",
+                                "--template", template1_file,
+                                "--outfile", cacert,
+                                "--load-privkey", cakey,
+                                NULL
+                            }, FALSE);
+        if (swtpm_rootca_password != NULL)
+            certtool_env = g_environ_setenv(certtool_env, "GNUTLS_PIN", swtpm_rootca_password, TRUE);
+
+        if (run_certtool(cmd, certtool_env, "Could not create root-CA:", NULL))
+            goto error;
+
+        g_free(cmd);
+
+        /* create the intermediate CA's key */
+        cmd = concat_arrays(NULL,
+                            (gchar *[]) {
+                                certtool, "--generate-privkey", "--outfile", (gchar *)signkey, NULL
+                            }, FALSE);
+        if (signkey_password != NULL)
+            cmd = concat_arrays(cmd, (gchar *[]){
+                                    "--password", (gchar *)signkey_password, NULL},
+                                TRUE);
+        if (run_certtool(cmd, certtool_env, "Could not create local-CA key", cakey))
+            goto error;
+
+        if (chmod(signkey, S_IRUSR | S_IWUSR | S_IRGRP) != 0) {
+            logerr(gl_LOGFILE, "Could not chmod %s: %s\n", signkey, strerror(errno));
+            goto error;
+        }
+
+        filecontent = "cn=swtpm-localca\n"
+                      "ca\n"
+                      "cert_signing_key\n"
+                      "expiration_days = 3600\n";
+        if (swtpm_rootca_password != NULL && signkey_password != NULL)
+            fc = g_strdup_printf("%spassword = %s\n", filecontent, swtpm_rootca_password);
+        else
+            fc = g_strdup(filecontent);
+
+        template2_file_fd = write_to_tempfile(&template2_file,
+                                              (const unsigned char *)fc, strlen(fc));
+        if (template2_file_fd < 0)
+            goto error;
+
+        g_free(cmd);
+        cmd = concat_arrays(NULL,
+                            (gchar *[]) {
+                                certtool,
+                                "--generate-certificate",
+                                "--template", template2_file,
+                                "--outfile", (gchar *)issuercert,
+                                "--load-privkey", (gchar *)signkey,
+                                "--load-ca-privkey", cakey,
+                                "--load-ca-certificate", cacert,
+                                NULL
+                            }, FALSE);
+        if (signkey_password != NULL)
+            certtool_env = g_environ_setenv(certtool_env, "GNUTLS_PIN", signkey_password, TRUE);
+        else if (swtpm_rootca_password != NULL)
+            certtool_env = g_environ_setenv(certtool_env, "GNUTLS_PIN", swtpm_rootca_password, TRUE);
+
+        if (run_certtool(cmd, certtool_env, "Could not create local-CA:", NULL))
+            goto error;
+    }
+
+    ret = 0;
+
+error:
+    if (template1_file_fd >= 0)
+        close(template1_file_fd);
+    if (template1_file != NULL)
+        unlink(template1_file);
+
+    if (template2_file_fd >= 0)
+        close(template2_file_fd);
+    if (template2_file != NULL)
+        unlink(template2_file);
+    g_strfreev(certtool_env);
+
+    unlock_file(lockfd);
+
+    return ret;
+}
+
+/* Extract the ECC parameters from a string like x=12,y=34,id=secp384r1.
+ * This function returns 1  on error, 2 if the ECC parameters could be extracted
+ * and 0 if no parameters could be extracted (likely a modulus).
+ */
+static gboolean extract_ecc_params(const gchar *ekparams, gchar **ecc_x, gchar **ecc_y, gchar **ecc_curveid)
+{
+    regmatch_t pmatch[5];
+    regex_t preg;
+    int ret;
+
+    if (regcomp(&preg, "x=([0-9A-Fa-f]+),y=([0-9A-Fa-f]+)(,id=([^,]+))?",
+                REG_EXTENDED) != 0) {
+        logerr(gl_LOGFILE, "Internal error: Could not compile regex\n");
+        return 1;
+    }
+
+    ret = 0;
+    if (regexec(&preg, ekparams, 5, pmatch, 0) == 0) {
+        *ecc_x = g_strndup(&ekparams[pmatch[1].rm_so],
+                           pmatch[1].rm_eo - pmatch[1].rm_so);
+        *ecc_y = g_strndup(&ekparams[pmatch[2].rm_so],
+                           pmatch[2].rm_eo - pmatch[2].rm_so);
+        if (pmatch[4].rm_so > 0 && pmatch[4].rm_eo > 0)
+            *ecc_curveid = g_strndup(&ekparams[pmatch[4].rm_so],
+                                     pmatch[4].rm_eo - pmatch[4].rm_so);
+        ret = 2;
+    }
+
+    regfree(&preg);
+
+    return ret;
+}
+
+/* Get the next serial number from the certserial file; if it contains
+ * a non-numeric content start over with serial number '1'.
+ */
+static int get_next_serial(const gchar *certserial, const gchar *lockfile,
+                           gchar **serial_str)
+{
+    g_autofree gchar *buffer = NULL;
+    size_t buffer_len;
+    unsigned long long serial, serial_n;
+    char *endptr = NULL;
+    int lockfd;
+    int ret = 1;
+
+    lockfd = lock_file(lockfile);
+    if (lockfd < 0)
+        return 1;
+
+    if (access(certserial, R_OK) != 0)
+        write_file(certserial, (unsigned char *)"1", 1);
+    if (read_file(certserial, &buffer, &buffer_len) != 0)
+        goto error;
+
+    if (buffer_len > 0) {
+        serial = strtoull(buffer, &endptr, 10);
+        if (*endptr == '\0') {
+            serial_n = serial + 1;
+        } else {
+            serial_n = 1;
+        }
+    } else {
+        serial_n = 1;
+    }
+    *serial_str = g_strdup_printf("%llu", serial_n);
+    write_file(certserial, (unsigned char *)*serial_str, strlen(*serial_str));
+    ret = 0;
+
+error:
+    unlock_file(lockfd);
+
+    return ret;
+}
+
+/* Create a TPM 1.2 or TPM 2 EK or platform cert */
+static int create_cert(unsigned long flags, const gchar *typ, const gchar *directory,
+                       gchar *ekparams, const gchar *vmid, gchar **tpm_spec_params,
+                       gchar **tpm_attr_params, const gchar *signkey,
+                       const gchar *signkey_password, const gchar *issuercert,
+                       const gchar *parentkey_password, gchar **swtpm_cert_env,
+                       const gchar *certserial, const gchar *lockfile,
+                       const gchar *optsfile)
+{
+    gchar ** optsfile_lines = NULL;
+    g_autofree gchar **options = NULL;
+    g_autofree gchar **keyparams = NULL;
+    g_autofree gchar **cmd = NULL;
+    g_autofree gchar *subject = NULL;
+    g_autofree gchar *ecc_x = NULL;
+    g_autofree gchar *ecc_y = NULL;
+    g_autofree gchar *ecc_curveid = NULL;
+    g_autofree gchar *certfile = NULL;
+    g_autofree gchar *serial_str = NULL;
+    gchar **to_free = NULL;
+    gchar **split;
+    const char *certtype;
+    int signkey_pwd_fd = -1;
+    int parentkey_pwd_fd  = -1;
+    g_autofree gchar *signkey_pwd_file = NULL;
+    g_autofree gchar *signkey_pwd_file_param = NULL;
+    g_autofree gchar *parentkey_pwd_file = NULL;
+    g_autofree gchar *parentkey_pwd_file_param = NULL;
+    gboolean success;
+    g_autofree gchar *standard_output = NULL;
+    g_autofree gchar *standard_error = NULL;
+    g_autofree gchar *swtpm_cert_path = NULL;
+    GError *error = NULL;
+    gint exit_status;
+    int ret = 1;
+    size_t i, j;
+
+    swtpm_cert_path = g_find_program_in_path("swtpm_cert");
+    if (swtpm_cert_path == NULL) {
+        logerr(gl_LOGFILE, "Could not find swtpm_cert in PATH.\n");
+        return 1;
+    }
+
+    if (get_next_serial(certserial, lockfile, &serial_str) != 0)
+        return 1;
+
+    /* try to read the optsfile */
+    read_file_lines(optsfile, &optsfile_lines);
+
+    /* split each line from the optsfile and add the stripped parameters to options */
+    for (i = 0; optsfile_lines != NULL && optsfile_lines[i] != NULL; i++) {
+        gchar *chomped = g_strchomp(optsfile_lines[i]);
+        if (strlen(chomped) == 0)
+            continue;
+
+        split = g_strsplit(chomped, " ", -1);
+        for (j = 0; split[j] != NULL; j++) {
+            chomped = g_strchomp(split[j]);
+            if (strlen(chomped) > 0) {
+                gchar *to_add = g_strdup(chomped);
+                options = concat_arrays(options, (gchar *[]){to_add, NULL}, TRUE);
+                /* need to collect this also to free later on */
+                to_free = concat_arrays(to_free, (gchar *[]){to_add, NULL}, TRUE);
+            }
+        }
+        g_strfreev(split);
+    }
+
+    if (vmid != NULL)
+        subject = g_strdup_printf("CN=%s", vmid);
+    else
+        subject = g_strdup("CN=unknown");
+
+    if (flags & SETUP_TPM2_F)
+        options = concat_arrays(options, (gchar *[]){"--tpm2", NULL}, TRUE);
+    else
+        options = concat_arrays(options, (gchar *[]){"--add-header", NULL}, TRUE);
+
+    if (strcmp(typ, "ek") == 0) {
+        if (flags & ALLOW_SIGNING_F)
+            options = concat_arrays(options, (gchar *[]){"--allow-signing", NULL}, TRUE);
+        if (flags & DECRYPTION_F)
+            options = concat_arrays(options, (gchar *[]){"--decryption", NULL}, TRUE);
+    }
+
+    switch (extract_ecc_params(ekparams, &ecc_x, &ecc_y, &ecc_curveid)) {
+    case 1:
+        goto error;
+    case 2:
+        keyparams = concat_arrays((gchar *[]){
+                                      "--ecc-x", ecc_x,
+                                      "--ecc-y", ecc_y,
+                                      NULL
+                                  },
+                                  NULL, FALSE);
+        if (ecc_curveid != NULL)
+           keyparams = concat_arrays(keyparams,
+                                     (gchar *[]){
+                                         "--ecc-curveid", ecc_curveid,
+                                         NULL
+                                     }, TRUE);
+        break;
+    case 0:
+        keyparams = concat_arrays((gchar *[]){
+                                      "--modulus", ekparams,
+                                      NULL},
+                                   NULL, FALSE);
+        break;
+    }
+
+    cmd = concat_arrays((gchar *[]){
+                            swtpm_cert_path, "--subject", subject, NULL
+                        }, options, FALSE);
+
+    if (signkey_password != NULL) {
+        signkey_pwd_fd = write_to_tempfile(&signkey_pwd_file,
+                                           (unsigned char *)signkey_password, strlen(signkey_password));
+        if (signkey_pwd_fd < 0)
+            goto error;
+
+        signkey_pwd_file_param = g_strdup_printf("file:%s", signkey_pwd_file);
+        cmd = concat_arrays(cmd, (gchar*[]){"--signkey-pwd", signkey_pwd_file_param, NULL}, TRUE);
+    }
+    if (parentkey_password != NULL) {
+        parentkey_pwd_fd = write_to_tempfile(&parentkey_pwd_file,
+                                             (unsigned char *)parentkey_password, strlen(parentkey_password));
+        if (parentkey_pwd_fd < 0)
+            goto error;
+
+        parentkey_pwd_file_param = g_strdup_printf("file:%s", parentkey_pwd_file);
+        cmd = concat_arrays(cmd, (gchar*[]){"--parentkey-pwd", parentkey_pwd_file_param, NULL}, TRUE);
+    }
+
+    if (strcmp(typ, "ek") == 0)
+        cmd = concat_arrays(cmd, tpm_spec_params, TRUE);
+
+    cmd = concat_arrays(cmd, tpm_attr_params, TRUE);
+
+    if (strcmp(typ, "platform") == 0) {
+        certfile = g_strjoin(G_DIR_SEPARATOR_S, directory, "platform.cert", NULL);
+        cmd = concat_arrays(cmd,
+                            (gchar *[]){
+                                "--type", "platform",
+                                "--out-cert", certfile,
+                                NULL},
+                            TRUE);
+    } else {
+        certfile = g_strjoin(G_DIR_SEPARATOR_S, directory, "ek.cert", NULL);
+        cmd = concat_arrays(cmd,
+                            (gchar *[]){
+                                "--out-cert", certfile,
+                                NULL
+                            }, TRUE);
+    }
+
+    cmd = concat_arrays(cmd, keyparams, TRUE);
+    cmd = concat_arrays(cmd, (gchar *[]){
+                            "--signkey", (gchar *)signkey,
+                            "--issuercert", (gchar *)issuercert,
+                            "--days", "3600",
+                            "--serial", (gchar *)serial_str,
+                            NULL
+                        }, TRUE);
+
+    if (strcmp(typ, "ek") == 0)
+        certtype = "EK";
+    else
+        certtype = "platform";
+#if 0
+    {
+        g_autofree gchar *join = g_strjoinv(" ", cmd);
+        fprintf(stderr, "Starting: %s\n", join);
+    }
+#endif
+    success = g_spawn_sync(NULL, cmd, swtpm_cert_env, G_SPAWN_DEFAULT, NULL, NULL,
+                           &standard_output, &standard_error, &exit_status, &error);
+    if (!success) {
+        logerr(gl_LOGFILE, "Could not run swtpm_cert: %s\n", error);
+        g_error_free(error);
+        goto error;
+    }
+    if (exit_status != 0) {
+        logerr(gl_LOGFILE, "Could not create %s certificate locally\n", certtype);
+        logerr(gl_LOGFILE, "%s\n", standard_error);
+        goto error;
+    }
+
+    logit(gl_LOGFILE, "Successfully created %s certificate locally.\n", certtype);
+    ret = 0;
+
+error:
+    g_strfreev(optsfile_lines);
+    g_strfreev(to_free);
+
+    if (signkey_pwd_fd >= 0)
+       close(signkey_pwd_fd);
+    if (signkey_pwd_file)
+       unlink(signkey_pwd_file);
+
+    if (parentkey_pwd_fd >= 0)
+       close(parentkey_pwd_fd);
+    if (parentkey_pwd_file)
+       unlink(parentkey_pwd_file);
+
+    return ret;
+}
+
+static void usage(const char *prgname)
+{
+   printf(
+        "Usage: %s [options]\n"
+        "\n"
+        "The following options are supported:\n"
+        "\n"
+        "--type type           The type of certificate to create: 'ek' or 'platform'\n"
+        "--ek key-param        The modulus of an RSA key or x=...,y=,... for an EC key\n"
+        "--dir directory       The directory to write the resulting certificate into\n"
+        "--vmid vmid           The ID of the virtual machine\n"
+        "--optsfile file       A file containing options to pass to swtpm_cert\n"
+        "--configfile file     A file containing configuration parameters for directory,\n"
+        "                      signing key and password and certificate to use\n"
+        "--logfile file        A file to write a log into\n"
+        "--tpm-spec-family s   The implemented spec family, e.g., '2.0'\n"
+        "--tpm-spec-revision i The spec revision of the TPM as integer; e.g., 146\n"
+        "--tpm-spec-level i    The spec level of the TPM; must be an integer; e.g. 0\n"
+        "--tpm-manufacturer s  The manufacturer of the TPM; e.g., id:00001014\n"
+        "--tpm-model s         The model of the TPM; e.g., 'swtpm'\n"
+        "--tpm-version i       The (firmware) version of the TPM; e.g., id:20160511\n"
+        "--tpm2                Generate a certificate for a TPM 2\n"
+        "--allow-signing       The TPM 2's EK can be used for signing\n"
+        "--decryption          The TPM 2's EK can be used for decryption\n"
+        "--help, -h, -?        Display this help screen and exit\n"
+        "\n"
+        "\n"
+        "The following environment variables are supported:\n"
+        "\n"
+        "SWTPM_ROOTCA_PASSWORD  The root CA's private key password\n"
+        "\n", prgname);
+}
+
+int main(int argc, char *argv[])
+{
+    int opt, option_index = 0;
+    static const struct option long_options[] = {
+        {"type", required_argument, NULL, 't'},
+        {"ek", required_argument, NULL, 'e'},
+        {"dir", required_argument, NULL, 'd'},
+        {"vmid", required_argument, NULL, 'v'},
+        {"optsfile", required_argument, NULL, 'o'},
+        {"configfile", required_argument, NULL, 'c'},
+        {"logfile", required_argument, NULL, 'l'},
+        {"tpm-spec-family", required_argument, NULL, 'f'},
+        {"tpm-spec-revision", required_argument, NULL, 'r'},
+        {"tpm-spec-level", required_argument, NULL, '1'},
+        {"tpm-manufacturer", required_argument, NULL, 'a'},
+        {"tpm-model", required_argument, NULL, 'm'},
+        {"tpm-version", required_argument, NULL, 's'},
+        {"tpm2", no_argument, NULL, '2'},
+        {"allow-signing", no_argument, NULL, 'i'},
+        {"decryption", no_argument, NULL, 'y'},
+        {"help", no_argument, NULL, 'h'},
+    };
+    g_autofree gchar *default_options_file = NULL;
+    g_autofree gchar *default_config_file = NULL;
+    g_autofree gchar *optsfile = NULL;
+    g_autofree gchar *configfile = NULL;
+    unsigned long flags = 0;
+    g_autofree gchar *typ =g_strdup("");
+    g_autofree gchar *ekparams = g_strdup("");
+    g_autofree gchar *directory = g_strdup("."); /* default to current directory */
+    g_autofree gchar *vmid = NULL;
+    g_autofree gchar *lockfile = NULL;
+    g_autofree gchar *statedir = NULL;
+    g_autofree gchar *signkey = NULL;
+    g_autofree gchar *signkey_password = NULL;
+    g_autofree gchar *parentkey_password = NULL;
+    g_autofree gchar *issuercert = NULL;
+    g_autofree gchar *certserial = NULL;
+    gchar **tpm_spec_params = NULL;
+    gchar **tpm_attr_params = NULL;
+    gchar **config_file_lines = NULL;
+    gchar **swtpm_cert_env = NULL;
+    const struct passwd *curr_user;
+    struct stat statbuf;
+    int ret = 1;
+
+    if (init(&default_options_file, &default_config_file) < 0)
+        goto error;
+    optsfile = g_strdup(default_options_file);
+    configfile = g_strdup(default_config_file);
+
+    while ((opt = getopt_long(argc, argv, "h?",
+                              long_options, &option_index)) != -1) {
+        switch (opt) {
+        case 't': /* --type */
+            g_free(typ);
+            typ = g_strdup(optarg);
+            break;
+        case 'e': /* --ek */
+            g_free(ekparams);
+            ekparams = g_strdup(optarg);
+            break;
+        case 'd': /* --dir */
+            g_free(directory);
+            directory = g_strdup(optarg);
+            break;
+        case 'v': /* --vmid */
+            g_free(vmid);
+            vmid = g_strdup(optarg);
+            break;
+        case 'o': /* --optsfile */
+            g_free(optsfile);
+            optsfile = g_strdup(optarg);
+            break;
+        case 'c': /* --configfile */
+            g_free(configfile);
+            configfile = g_strdup(optarg);
+            break;
+        case 'l': /* --logfile */
+            g_free(gl_LOGFILE);
+            gl_LOGFILE = g_strdup(optarg);
+            break;
+        case 'f': /* --tpm-spec-family */
+        case 'r': /* --tpm-spec-revision */
+        case '1': /* --tpm-spec-level */
+            tpm_spec_params = concat_arrays(tpm_spec_params,
+                          (gchar *[]) {
+                              g_strdup_printf("--%s", long_options[option_index].name), g_strdup(optarg), NULL
+                          }, TRUE);
+            break;
+        case 'a': /* --tpm-manufacturer */
+        case 'm': /* --tpm-model */
+        case 's': /* --tpm-version */
+            tpm_attr_params = concat_arrays(tpm_attr_params,
+                          (gchar *[]) {
+                              g_strdup_printf("--%s", long_options[option_index].name), g_strdup(optarg), NULL
+                          }, TRUE);
+            break;
+        case '2': /* --tpm2 */
+            flags |= SETUP_TPM2_F;
+            break;
+        case 'i': /* --allow-signing */
+            flags |= ALLOW_SIGNING_F;
+            break;
+        case 'y': /* --decryption */
+            flags |= DECRYPTION_F;
+            break;
+        case '?':
+        case 'h': /* --help */
+            usage(argv[0]);
+            ret = 0;
+            goto out;
+        default:
+            fprintf(stderr, "Unknown option code %d\n", opt);
+            usage(argv[0]);
+            goto error;
+        }
+    }
+
+    curr_user = getpwuid(getuid());
+
+    if (gl_LOGFILE != NULL) {
+        FILE *tmpfile;
+
+        if (stat(gl_LOGFILE, &statbuf) == 0 &&
+            (statbuf.st_mode & S_IFMT) == S_IFLNK) {
+            fprintf(stderr, "Logfile must not be a symlink.\n");
+            goto error;
+        }
+        tmpfile = fopen(gl_LOGFILE, "a"); // do not truncate
+        if (tmpfile == NULL) {
+            fprintf(stderr, "Cannot write to logfile %s.\n", gl_LOGFILE);
+            goto error;
+        }
+        fclose(tmpfile);
+    }
+
+    if (access(optsfile, R_OK) != 0) {
+        logerr(gl_LOGFILE, "Need read rights on options file %s for user %s.\n",
+               optsfile, curr_user ? curr_user->pw_name : "<unknown>");
+        goto error;
+    }
+
+    if (access(configfile, R_OK) != 0) {
+        logerr(gl_LOGFILE, "Need read rights on config file %s for user %s.\n",
+               configfile, curr_user ? curr_user->pw_name : "<unknown>");
+        goto error;
+    }
+
+    if (read_file_lines(configfile, &config_file_lines) != 0)
+        goto error;
+
+    statedir = get_config_value(config_file_lines, "statedir", NULL);
+    if (statedir == NULL) {
+        logerr(gl_LOGFILE, "Missing 'statedir' config value in config file %s.\n", configfile);
+        goto error;
+    }
+    if (makedir(statedir, "statedir") != 0)
+        goto error;
+    if (access(statedir, W_OK | R_OK) != 0) {
+        logerr(gl_LOGFILE, "Need read/write rights on statedir %s for user %s.\n",
+               statedir, curr_user ? curr_user->pw_name : "<unknown>");
+        goto error;
+    }
+
+    lockfile = g_strjoin(G_DIR_SEPARATOR_S, statedir, ".lock.swtpm-localca", NULL);
+    if (stat(lockfile, &statbuf) == 0 &&
+        access(lockfile, W_OK | R_OK) != 0) {
+        logerr(gl_LOGFILE, "Need read/write rights on %s for user %s.\n",
+               lockfile, curr_user ? curr_user->pw_name : "<unknown>");
+        goto error;
+    }
+
+    signkey = get_config_value(config_file_lines, "signingkey", NULL);
+    if (signkey == NULL) {
+        logerr(gl_LOGFILE, "Missing 'signingkey' config value in config file %s.\n",
+               configfile);
+        goto error;
+    }
+
+    if (!g_str_has_prefix(signkey, "tpmkey:file=") &&
+        !g_str_has_prefix(signkey, "tpmkey:uuid=") &&
+        !g_str_has_prefix(signkey, "pkcs11:")) {
+        g_autofree gchar *d = g_path_get_dirname(signkey);
+        if (makedir(d, "signkey") != 0)
+            goto error;
+    }
+
+    signkey_password = get_config_value(config_file_lines, "signingkey_password", NULL);
+    parentkey_password = get_config_value(config_file_lines, "parentkey_password", NULL);
+
+    issuercert = get_config_value(config_file_lines, "issuercert", NULL);
+    if (issuercert == NULL) {
+        logerr(gl_LOGFILE, "Missing 'issuercert' config value in config file %s.\n", configfile);
+        goto error;
+    }
+    {
+       g_autofree gchar *d = g_path_get_dirname(issuercert);
+       if (makedir(d, "issuercert") != 0)
+           goto error;
+    }
+
+    swtpm_cert_env = g_get_environ();
+
+    // TPM keys are GNUTLS URIs...
+    if (g_str_has_prefix(signkey, "tpmkey:file=") || g_str_has_prefix(signkey, "tpmkey:uuid=")) {
+        gchar *tss_tcsd_hostname = get_config_value(config_file_lines,
+                                                    "TSS_TCSD_HOSTNAME", "localhost");
+        gchar *tss_tcsd_port = get_config_value(config_file_lines,
+                                                "TSS_TCSD_PORT", "30003");
+        swtpm_cert_env = g_environ_setenv(swtpm_cert_env,
+                                          "TSS_TCSD_HOSTNAME", tss_tcsd_hostname, TRUE);
+        swtpm_cert_env = g_environ_setenv(swtpm_cert_env,
+                                          "TSS_TCSD_PORT", tss_tcsd_port, TRUE);
+
+        logit(gl_LOGFILE, "CA uses a GnuTLS TPM key; using TSS_TCSD_HOSTNAME=%s " \
+                          "TSS_TCSD_PORT=%s\n", tss_tcsd_hostname, tss_tcsd_port);
+    } else if (g_str_has_prefix(signkey, "pkcs11:")) {
+        gchar *tmp = str_replace(signkey, "\\;", ";"); /* historical reasons ... */
+        g_free(signkey);
+        signkey = tmp;
+
+        if (signkey_password != NULL) {
+            swtpm_cert_env = g_environ_setenv(swtpm_cert_env,
+                                              "SWTPM_PKCS11_PIN", g_strdup(signkey_password), TRUE);
+            logit(gl_LOGFILE, "CA uses a PKCS#11 key; using SWTPM_PKCS11_PIN\n");
+        } else {
+            g_autofree gchar *swtpm_pkcs11_pin = NULL;
+
+            swtpm_pkcs11_pin = get_config_value(config_file_lines,
+                                                "SWTPM_PKCS11_PIN", "swtpm-tpmca");
+            swtpm_cert_env = g_environ_setenv(swtpm_cert_env,
+                                              "SWTPM_PKCS11_PIN", swtpm_pkcs11_pin, TRUE);
+            logit(gl_LOGFILE, "CA uses a PKCS#11 key; using SWTPM_PKCS11_PIN\n");
+        }
+        ret = get_config_envvars(config_file_lines, &swtpm_cert_env);
+        if (ret != 0)
+            goto error;
+    } else {
+        if (access(signkey, R_OK) != 0) {
+            if (stat(signkey, &statbuf) == 0) {
+                logerr(gl_LOGFILE, "Need read rights on signing key %s for user %s.\n",
+                       signkey, curr_user ? curr_user->pw_name : "<unknown>");
+                goto error;
+            }
+
+            logit(gl_LOGFILE, "Creating root CA and a local CA's signing key and issuer cert.\n");
+            if (create_localca_cert(lockfile, statedir, signkey, signkey_password,
+                                    issuercert) != 0) {
+                logerr(gl_LOGFILE, "Error creating local CA's signing key and cert.\n");
+                goto error;
+            }
+
+            if (access(signkey, R_OK) != 0) {
+                logerr(gl_LOGFILE, "Need read rights on signing key %s for user %s.\n",
+                       signkey, curr_user ? curr_user->pw_name : "<unknown>");
+                goto error;
+            }
+        }
+    }
+
+    if (access(issuercert, R_OK) != 0) {
+        logerr(gl_LOGFILE, "Need read rights on issuer certificate %s for user %s.\n",
+               issuercert, curr_user ? curr_user->pw_name : "<unknown>");
+        goto error;
+    }
+
+    {
+        g_autofree gchar *d = NULL;
+        g_autofree gchar *p = g_strjoin(G_DIR_SEPARATOR_S, statedir, "certserial", NULL);
+
+        certserial = get_config_value(config_file_lines, "certserial", p);
+        d = g_path_get_dirname(certserial);
+        if (makedir(d, "certserial") != 0)
+            goto error;
+    }
+
+    ret = create_cert(flags, typ, directory, ekparams, vmid, tpm_spec_params, tpm_attr_params,
+                      signkey, signkey_password, issuercert, parentkey_password, swtpm_cert_env,
+                      certserial, lockfile, optsfile);
+
+out:
+error:
+    g_strfreev(tpm_attr_params);
+    g_strfreev(tpm_spec_params);
+
+    exit(ret);
+}
diff --git a/src/swtpm_localca/swtpm_localca.h b/src/swtpm_localca/swtpm_localca.h
new file mode 100644 (file)
index 0000000..c1cb19f
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * swtpm_localca.h: Header file
+ *
+ * Author: Stefan Berger, stefanb@linux.ibm.com
+ *
+ * Copyright (c) IBM Corporation, 2021
+ */
+
+#ifndef SWTPM_LOCALCA_H
+#define SWTPM_LOCALCA_H
+
+#include <glib.h>
+
+extern gchar *gl_LOGFILE;
+
+#endif /* SWTPM_LOCALCA_H */
diff --git a/src/swtpm_localca/swtpm_localca_conf.h.in b/src/swtpm_localca/swtpm_localca_conf.h.in
new file mode 100644 (file)
index 0000000..4276942
--- /dev/null
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * swtpm_setup_conf.h: Compile-time constants
+ *
+ * Author: Stefan Berger, stefanb@linux.ibm.com
+ *
+ * Copyright (c) IBM Corporation, 2021
+ */
+
+#ifndef SWTPM_LOCALCA_CONF_H
+#define SWTPM_LOCALCA_CONF_H
+
+#define SYSCONFDIR "@SYSCONFDIR@"
+
+#endif /* SWTPM_LOCALCA_CONF_H */
diff --git a/src/swtpm_localca/swtpm_localca_utils.c b/src/swtpm_localca/swtpm_localca_utils.c
new file mode 100644 (file)
index 0000000..7aeb9cf
--- /dev/null
@@ -0,0 +1,139 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * swtpm_localca_utils.c: Utility functions
+ *
+ * Author: Stefan Berger, stefanb@linux.ibm.com
+ *
+ * Copyright (c) IBM Corporation, 2021
+ */
+
+#include "config.h"
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <regex.h>
+#include <errno.h>
+#include <sys/file.h>
+
+#include "swtpm_utils.h"
+#include "swtpm_localca.h"
+#include "swtpm_localca_utils.h"
+
+/* Create a directory pat (and all its predecessors) if it doesn't exist */
+int makedir(const char *dirname, const char *purpose)
+{
+    struct stat statbuf;
+
+    if (stat(dirname, &statbuf) != 0) {
+        logit(gl_LOGFILE, "Creating swtpm-localca dir '%s'.\n", dirname);
+        if (g_mkdir_with_parents(dirname, S_IRWXU | S_IRWXG | S_IXGRP | S_IRGRP) == -1) {
+            logerr(gl_LOGFILE, "Could not create directory for '%s': %s\n",
+                   purpose, strerror(errno));
+            return 1;
+        }
+    }
+    return 0;
+}
+
+/* Get a configuration value given its name */
+gchar *get_config_value(gchar **config_file_lines, const gchar *configname, const gchar *fallback)
+{
+    g_autofree gchar *regex = g_strdup_printf("^%s[[:space:]]*=[[:space:]]*([^#\n]*).*", configname);
+    gchar *result = NULL;
+    regex_t preg;
+    size_t idx;
+    regmatch_t pmatch[2];
+
+    if (regcomp(&preg, regex, REG_EXTENDED) != 0) {
+        logerr(gl_LOGFILE, "Internal error: Could not compile regex\n");
+        goto error;
+    }
+
+    for (idx = 0; config_file_lines[idx] != NULL; idx++) {
+        const gchar *line = config_file_lines[idx];
+        if (regexec(&preg, line, 2, pmatch, 0) == 0) {
+            result = g_strndup(&line[pmatch[1].rm_so],
+                               pmatch[1].rm_eo - pmatch[1].rm_so);
+            /* coverity: g_strchmop modifies in-place */
+            result = g_strchomp(result);
+            break;
+        }
+    }
+    regfree(&preg);
+
+error:
+    if (result == NULL)
+        result = g_strdup(fallback);
+    //printf("Found match for %s: |%s|\n", configname, result);
+
+    return result;
+}
+
+/* Extract all environment variables from the config file and add them to
+ * the given environent.
+ * Environment variable lines must start with 'env:' and must not contain
+ * trailing spaces or a comment starting with '#'
+ */
+int get_config_envvars(gchar **config_file_lines, gchar ***env)
+{
+    const char *regex = "^env:([a-zA-Z_][a-zA-Z_0-9]*)[[:space:]]*=[[:space:]]*([^\n]*)";
+    regex_t preg;
+    size_t idx;
+    regmatch_t pmatch[3];
+
+    if (regcomp(&preg, regex, REG_EXTENDED) != 0) {
+        logerr(gl_LOGFILE, "Internal error: Could not compile regex\n");
+        return 1;
+    }
+
+    for (idx = 0; config_file_lines[idx] != NULL; idx++) {
+        const gchar *line = config_file_lines[idx];
+        if (regexec(&preg, line, 3, pmatch, 0) == 0) {
+            g_autofree gchar *key = NULL, *value = NULL;
+
+            key = g_strndup(&line[pmatch[1].rm_so],
+                            pmatch[1].rm_eo - pmatch[1].rm_so);
+            value = g_strndup(&line[pmatch[2].rm_so],
+                              pmatch[2].rm_eo - pmatch[2].rm_so);
+            *env = g_environ_setenv(*env, key, value, TRUE);
+        }
+    }
+
+    regfree(&preg);
+
+    return 0;
+}
+
+/* flock a file; the file descriptor for the file to unlock later on is returned */
+int lock_file(const gchar *lockfile)
+{
+    int lockfd;
+    mode_t mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
+
+    lockfd = open(lockfile, O_RDWR | O_CREAT, mode);
+    if (lockfd < 0) {
+        logerr(gl_LOGFILE, "Could not open lockfile %s: %s\n", lockfile, strerror(errno));
+        return -1;
+    }
+
+    if (flock(lockfd, LOCK_EX) < 0) {
+        logerr(gl_LOGFILE, "Could not lock file %s: %s\n", lockfile, strerror(errno));
+        close(lockfd);
+        return -1;
+    }
+    return lockfd;
+}
+
+/* unlock a file previously locked using lock_file */
+void unlock_file(int lockfd) {
+    if (lockfd >= 0) {
+        flock(lockfd, LOCK_UN);
+        close(lockfd);
+    }
+}
diff --git a/src/swtpm_localca/swtpm_localca_utils.h b/src/swtpm_localca/swtpm_localca_utils.h
new file mode 100644 (file)
index 0000000..ccbf714
--- /dev/null
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * swtpm_localca_utils.h: Header file for swtpm_localca_utils.c
+ *
+ * Author: Stefan Berger, stefanb@linux.ibm.com
+ *
+ * Copyright (c) IBM Corporation, 2021
+ */
+
+#ifndef SWTPM_LOCALCA_UTILS_H
+#define SWTPM_LOCALCA_UTILS_H
+
+#include <glib.h>
+
+gchar *get_config_value(gchar **config_file_lines, const gchar *varname, const gchar *fallback);
+int get_config_envvars(gchar **config_file_lines, gchar  ***env);
+
+int makedir(const char *dirname, const char *purpose);
+
+int lock_file(const gchar *lockfile);
+void unlock_file(int lockfd);
+
+#endif /* SWTPM_LOCALCA_UTILS_H */
index c422dd2deff88d3e5ececaf526ac411dae80b9fb..0c7157cb739dad9e175619a29d76e11442299c6f 100644 (file)
@@ -80,10 +80,10 @@ TESTS += \
        test_swtpm_cert \
        test_swtpm_setup_create_cert \
        test_tpm2_parameters \
-       test_tpm2_samples_swtpm_localca \
-       test_tpm2_samples_swtpm_localca_pkcs11 \
        test_tpm2_swtpm_cert \
        test_tpm2_swtpm_cert_ecc \
+       test_tpm2_swtpm_localca \
+       test_tpm2_swtpm_localca_pkcs11 \
        test_tpm2_swtpm_setup_create_cert
 if HAVE_TCSD
 TESTS += \
index 538d287d52f61481024710309db701cfdfd446c7..ee106f47527f2053e9701563526d671fb8071ee6 100755 (executable)
@@ -24,7 +24,7 @@ source ${abs_top_builddir:-$(dirname "$0")/..}/tests/test_config
 
 SWTPM_SETUP=${ROOT}/src/swtpm_setup/swtpm_setup
 SWTPM_CREATE_TPMCA=${SRCDIR}/samples/swtpm-create-tpmca
-SWTPM_LOCALCA=${ROOT}/samples/swtpm-localca
+SWTPM_LOCALCA=${ROOT}/src/swtpm_localca/swtpm_localca
 SWTPM=${ROOT}/src/swtpm/swtpm
 SWTPM_IOCTL=${ROOT}/src/swtpm_ioctl/swtpm_ioctl
 
index 42702077e70361f3f417f66766a292dda2e7ea7c..a0066743e33a7939534e168e2af2962d0242f70b 100755 (executable)
@@ -8,7 +8,7 @@ SRCDIR=${abs_top_srcdir:-$(dirname "$0")/..}
 
 source ${TESTDIR}/common
 
-SWTPM_LOCALCA=${ROOT}/samples/swtpm-localca
+SWTPM_LOCALCA=${ROOT}/src/swtpm_localca/swtpm_localca
 
 workdir=$(mktemp -d)
 
index b789d9d0870ef1bc5637fe3f5454d38d6315718b..5e002a142efda91cfe91a3bdefd6d2466cc55908 100755 (executable)
@@ -42,7 +42,7 @@ SRCDIR=${abs_top_srcdir:-$(dirname "$0")/..}
 
 SWTPM_SETUP=${ROOT}/src/swtpm_setup/swtpm_setup
 SWTPM_CREATE_TPMCA=${SRCDIR}/samples/swtpm-create-tpmca
-SWTPM_LOCALCA=${SRCDIR}/samples/swtpm-localca
+SWTPM_LOCALCA=${ROOT}/src/swtpm_localca/swtpm_localca
 SWTPM=${ROOT}/src/swtpm/swtpm
 SWTPM_IOCTL=${ROOT}/src/swtpm_ioctl/swtpm_ioctl
 
diff --git a/tests/test_tpm2_samples_swtpm_localca b/tests/test_tpm2_samples_swtpm_localca
deleted file mode 100755 (executable)
index 3954b75..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-#!/usr/bin/env bash
-
-# For the license, see the LICENSE file in the root directory.
-#set -x
-
-TOPBUILD=${abs_top_builddir:-$(dirname "$0")/..}
-TOPSRC=${abs_top_srcdir:-$(dirname "$0")/..}
-TESTDIR=${abs_top_testdir:-$(dirname "$0")}
-
-SWTPM_LOCALCA=${TOPBUILD}/samples/swtpm-localca
-
-workdir=$(mktemp -d "/tmp/path with spaces.XXXXXX")
-
-ek="80" # 2048 bit key must have highest bit set
-for ((i = 1; i < 256; i++)); do
-  ek="${ek}$(printf "%02x" $i)"
-done
-
-SIGNINGKEY=${workdir}/signingkey.pem
-ISSUERCERT=${workdir}/issuercert.pem
-CERTSERIAL=${workdir}/certserial
-
-PATH=${TOPBUILD}/src/swtpm_cert:$PATH
-
-source ${TESTDIR}/common
-
-trap "cleanup" SIGTERM EXIT
-
-function cleanup()
-{
-       rm -rf "${workdir}"
-}
-
-cat <<_EOF_ > "${workdir}/swtpm-localca.conf"
-statedir=${workdir}
-signingkey = ${SIGNINGKEY}
-issuercert = ${ISSUERCERT}
-certserial = ${CERTSERIAL}
-signingkey_password = password
-_EOF_
-
-cat <<_EOF_ > "${workdir}/swtpm-localca.options"
---tpm-manufacturer IBM
---tpm-model swtpm-libtpms
---tpm-version 2
---platform-manufacturer Fedora
---platform-version 2.1
---platform-model QEMU
-_EOF_
-
-# the following contains the test parameters and
-# expected key usage
-for testparams in \
-       "--allow-signing|Digital signature" \
-       "--allow-signing --decryption|Digital signature,Key encipherment" \
-       "--decryption|Key encipherment" \
-       "|Key encipherment";
-do
-  params=$(echo ${testparams} | cut -d"|" -f1)
-  usage=$(echo ${testparams} | cut -d"|" -f2)
-
-  ${SWTPM_LOCALCA} \
-    --type ek \
-    --ek "${ek}" \
-    --dir "${workdir}" \
-    --vmid test \
-    --tpm2 \
-    --configfile "${workdir}/swtpm-localca.conf" \
-    --optsfile "${workdir}/swtpm-localca.options" \
-    --tpm-spec-family 2.0 --tpm-spec-revision 146 --tpm-spec-level 0 \
-    ${params}
-  if [ $? -ne 0 ]; then
-    echo "Error: Test with parameters '$params' failed."
-    exit 1
-  fi
-
-  # Signing key should always be password protected
-  if [ -z "$(grep "ENCRYPTED PRIVATE KEY" "${SIGNINGKEY}")" ]; then
-    echo "Error: Signing key is not password protected."
-    exit 1
-  fi
-
-  # For the root CA's key we flip the password protection
-  if [ -n "${SWTPM_ROOTCA_PASSWORD}" ] ;then
-     if [ -z "$(grep "ENCRYPTED PRIVATE KEY" "${workdir}/swtpm-localca-rootca-privkey.pem")" ]; then
-       echo "Error: Root CA's private key is not password protected."
-       exit 1
-     fi
-     unset SWTPM_ROOTCA_PASSWORD
-  else
-     if [ -n "$(grep "ENCRYPTED PRIVATE KEY" "${workdir}/swtpm-localca-rootca-privkey.pem")" ]; then
-       echo "Error: Root CA's private key is password protected but should not be."
-       exit 1
-     fi
-     export SWTPM_ROOTCA_PASSWORD=xyz
-  fi
-
-  if [ ! -r "${workdir}/ek.cert" ]; then
-    echo "Error: ${workdir}/ek.cert was not created."
-    exit 1
-  fi
-
-  OIFS="$IFS"
-  IFS=","
-
-  for u in $usage; do
-    echo $u
-    if [ -z "$(${CERTTOOL} -i \
-                 --inder --infile "${workdir}/ek.cert" | \
-                grep "Key Usage" -A2 | \
-                grep "$u")" ]; then
-      echo "Error: Could not find key usage $u in key created " \
-           "with $params."
-    else
-      echo "Found '$u'"
-    fi
-  done
-
-  IFS="$OIFS"
-
-  ${CERTTOOL} \
-    -i \
-    --inder --infile "${workdir}/ek.cert" \
-    --outfile "${workdir}/ek.pem"
-
-  ${CERTTOOL} \
-    --verify \
-    --load-ca-certificate "${ISSUERCERT}" \
-    --infile "${workdir}/ek.pem"
-  if [ $? -ne 0 ]; then
-    echo "Error: Could not verify certificate chain."
-    exit 1
-  fi
-
-  # Delete all keys to have CA re-created
-  rm -rf "${workdir}"/*.pem
-done
-
-echo "Test 1: OK"
-echo
-
-#A few tests with odd vm Ids
-for vmid in \
-       's p a c e|s p a c e' \
-       '$(ls)>foo|$(ls)\>foo' \
-       '`ls`&; #12|`ls`&\; #12' \
-       'foo>&1<&2;$(ls)|foo\>&1\<&2\;$(ls)' \
-       "'*|'*" \
-       '"*|\"*' \
-       ':$$|:$$' \
-       '${t}[]|${t}[]';
-do
-  in=$(echo "$vmid" | cut -d"|" -f1)
-  exp=$(echo "$vmid" | cut -d"|" -f2)
-
-  ${SWTPM_LOCALCA} \
-    --type ek \
-    --ek "${ek}" \
-    --dir "${workdir}" \
-    --vmid "$in" \
-    --tpm2 \
-    --configfile "${workdir}/swtpm-localca.conf" \
-    --optsfile "${workdir}/swtpm-localca.options" \
-    --tpm-spec-family 2.0 --tpm-spec-revision 146 --tpm-spec-level 0 \
-    ${params} &>/dev/null
-  if [ $? -ne 0 ]; then
-    echo "Error: Test with parameters '$params' failed."
-    exit 1
-  fi
-
-  if [ ! -r "${workdir}/ek.cert" ]; then
-    echo "Error: ${workdir}/ek.cert was not created."
-    exit 1
-  fi
-
-  ac=$(${CERTTOOL} -i --inder --infile "${workdir}/ek.cert" | \
-       sed -n "s/.*Subject: CN=\(.*\)$/\1/p")
-  if [ "$ac" != "$exp" ]; then
-    echo "Error: unexpected subject string"
-    echo "actual   : $ac"
-    echo "expected : $exp"
-  else
-    echo "Pass: $ac"
-  fi
-done
-
-echo "Test 2: OK"
-
-exit 0
diff --git a/tests/test_tpm2_samples_swtpm_localca_pkcs11 b/tests/test_tpm2_samples_swtpm_localca_pkcs11
deleted file mode 100755 (executable)
index fa23da1..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-#!/usr/bin/env bash
-
-# For the license, see the LICENSE file in the root directory.
-#set -x
-
-TOPBUILD=${abs_top_builddir:-$(dirname "$0")/..}
-TOPSRC=${abs_top_srcdir:-$(dirname "$0")/..}
-TESTDIR=${abs_top_testdir:-$(dirname "$0")}
-
-SWTPM_LOCALCA=${TOPBUILD}/samples/swtpm-localca
-
-workdir=$(mktemp -d)
-if [ $? -ne 0 ]; then
-       exit 1
-fi
-
-# Have softhsm_setup use 'workdir'.
-export SOFTHSM_SETUP_CONFIGDIR="${workdir}"
-
-# Since we will be using the pkcs11 module as well via certtool
-# we have to set the environment variable to point to its config file.
-# This has to be the same as for swtpm_setup sets it.
-export SOFTHSM2_CONF="${workdir}"/softhsm2.conf
-
-ek="80" # 2048 bit key must have highest bit set
-for ((i = 1; i < 256; i++)); do
-  ek="${ek}$(printf "%02x" $i)"
-done
-
-SIGNINGKEY=${workdir}/signingkey.pem
-ISSUERCERT=${workdir}/issuercert.pem
-CERTSERIAL=${workdir}/certserial
-
-PATH=${TOPBUILD}/src/swtpm_cert:$PATH
-
-source ${TESTDIR}/common
-
-trap "cleanup" SIGTERM EXIT
-
-function cleanup()
-{
-       rm -rf ${workdir}
-       ${TESTDIR}/softhsm_setup teardown
-}
-
-unset GNUTLS_PIN
-export PIN="abcdef"
-
-# Generate the PKCS11 token and key; it uses env. variable 'PIN'
-msg=$(${TESTDIR}/softhsm_setup setup 2>&1)
-if [ $? -ne 0 ]; then
-       echo -e "Could not setup softhsm:\n${msg}"
-       echo "softhsm needs to be v2.3.0 or greater and pkcs11 correctly configured"
-       exit 77
-fi
-pkcs11uri=$(echo ${msg} | sed -n 's|^keyuri: \(.*\)|\1|p')
-
-# Now we need to create the root CA ...
-template=${workdir}/template
-
-cakey=${workdir}/swtpm-localca-rootca-privkey.pem
-cacert=${workdir}/swtpm-localca-rootca-cert.pem
-
-# first the private key
-msg=$(${CERTTOOL} \
-       --generate-privkey \
-       --outfile ${cakey} \
-       ${passparam} \
-       2>&1)
-if [ $? -ne 0 ]; then
-       echo "Could not create root-CA key ${cakey}."
-       echo "${msg}"
-       exit 1
-fi
-chmod 640 ${cakey}
-
-# now the self-signed certificate
-cat <<_EOF_ >${template}
-cn=swtpm-localca-rootca
-ca
-cert_signing_key
-expiration_days = 3650
-_EOF_
-
-msg=$(${CERTTOOL} \
-       --generate-self-signed \
-       --template ${template} \
-       --outfile ${cacert} \
-       --load-privkey ${cakey} \
-       2>&1)
-if [ $? -ne 0 ]; then
-       echo "Could not create root CA."
-       echo "${msg}"
-       exit 1
-fi
-
-# And now create the intermediate CA with the pkcs11 URI key
-
-pubkey=${workdir}/swtpm-localca-interm-pubkey.pem
-
-msg=$(GNUTLS_PIN=${PIN} ${CERTTOOL} \
-       --load-privkey ${pkcs11uri} \
-       --pubkey-info \
-       --outfile ${pubkey})
-if [ $? -ne 0 ]; then
-       echo "Could not get public key for pkcs11 uri key ($pkcs11uri}."
-       echo "${msg}"
-       exit 1
-fi
-
-cat <<_EOF_ > ${template}
-cn=swtpm-localca
-ca
-cert_signing_key
-expiration_days = 3650
-_EOF_
-
-msg=$(GNUTLS_PIN=${PIN} ${CERTTOOL} \
-       --generate-certificate \
-       --template ${template} \
-       --outfile ${ISSUERCERT} \
-       --load-ca-privkey ${cakey} \
-       --load-ca-certificate ${cacert} \
-       --load-privkey ${pkcs11uri} \
-       --load-pubkey ${pubkey} \
-       2>&1)
-if [ $? -ne 0 ]; then
-       echo "Could not create intermediate CA"
-       echo "${msg}"
-       exit 1
-fi
-
-echo -n 1 > ${CERTSERIAL}
-
-# Now we can create the config files
-cat <<_EOF_ > ${workdir}/swtpm-localca.conf
-statedir = ${workdir}
-signingkey = $(echo ${pkcs11uri} | sed 's|;|\\;|g')
-issuercert = ${ISSUERCERT}
-certserial = ${CERTSERIAL}
-SWTPM_PKCS11_PIN = ${PIN}
-_EOF_
-
-cat <<_EOF_ > ${workdir}/swtpm-localca.options
---tpm-manufacturer IBM
---tpm-model swtpm-libtpms
---tpm-version 2
---platform-manufacturer Fedora
---platform-version 2.1
---platform-model QEMU
-_EOF_
-
-# the following contains the test parameters and
-# expected key usage
-for testparams in \
-       "--allow-signing|Digital signature" \
-       "--allow-signing --decryption|Digital signature,Key encipherment" \
-       "--decryption|Key encipherment" \
-       "|Key encipherment";
-do
-  params=$(echo ${testparams} | cut -d"|" -f1)
-  usage=$(echo ${testparams} | cut -d"|" -f2)
-
-  msg=$(${SWTPM_LOCALCA} \
-    --type ek \
-    --ek ${ek} \
-    --dir ${workdir} \
-    --vmid test \
-    --tpm2 \
-    --configfile ${workdir}/swtpm-localca.conf \
-    --optsfile ${workdir}/swtpm-localca.options \
-    --tpm-spec-family 2.0 --tpm-spec-revision 146 --tpm-spec-level 0 \
-    ${params} 2>&1)
-  if [ $? -ne 0 ]; then
-    echo "Error: Test with parameters '$params' failed."
-    echo "${msg}"
-    if [[ "${msg}" =~ The\ requested\ PKCS\ #11\ object\ is\ not\ available ]]; then
-        # could be related to i386 executables on x86_64 host and
-        # libsofthsm.so only available for x86_64...
-        exit 77
-    fi
-    exit 1
-  fi
-
-  if [ ! -r ${workdir}/ek.cert ]; then
-    echo "${msg}"
-    echo "Error: ${workdir}/ek.cert was not created."
-    exit 1
-  fi
-
-  OIFS="$IFS"
-  IFS=","
-
-  for u in $usage; do
-    if [ -z "$(${CERTTOOL} -i \
-                 --inder --infile ${workdir}/ek.cert | \
-                grep "Key Usage" -A2 | \
-                grep "$u")" ]; then
-      echo "Error: Could not find key usage $u in key created " \
-           "with $params."
-    else
-      echo "Found '$u'"
-    fi
-  done
-
-  IFS="$OIFS"
-
-  ${CERTTOOL} \
-    -i \
-    --inder --infile ${workdir}/ek.cert \
-    --outfile ${workdir}/ek.pem
-
-  GNUTLS_PIN=${PIN} ${CERTTOOL} \
-    --verify \
-    --load-ca-certificate ${ISSUERCERT} \
-    --infile ${workdir}/ek.pem
-  if [ $? -ne 0 ]; then
-    echo "Error: Could not verify certificate chain."
-    exit 1
-  fi
-done
-
-exit 0
diff --git a/tests/test_tpm2_swtpm_localca b/tests/test_tpm2_swtpm_localca
new file mode 100755 (executable)
index 0000000..8cc0183
--- /dev/null
@@ -0,0 +1,189 @@
+#!/usr/bin/env bash
+
+# For the license, see the LICENSE file in the root directory.
+#set -x
+
+TOPBUILD=${abs_top_builddir:-$(dirname "$0")/..}
+TOPSRC=${abs_top_srcdir:-$(dirname "$0")/..}
+TESTDIR=${abs_top_testdir:-$(dirname "$0")}
+
+SWTPM_LOCALCA=${TOPBUILD}/src/swtpm_localca/swtpm_localca
+
+workdir=$(mktemp -d "/tmp/path with spaces.XXXXXX")
+
+ek="80" # 2048 bit key must have highest bit set
+for ((i = 1; i < 256; i++)); do
+  ek="${ek}$(printf "%02x" $i)"
+done
+
+SIGNINGKEY=${workdir}/signingkey.pem
+ISSUERCERT=${workdir}/issuercert.pem
+CERTSERIAL=${workdir}/certserial
+
+PATH=${TOPBUILD}/src/swtpm_cert:$PATH
+
+source ${TESTDIR}/common
+
+trap "cleanup" SIGTERM EXIT
+
+function cleanup()
+{
+       rm -rf "${workdir}"
+}
+
+cat <<_EOF_ > "${workdir}/swtpm-localca.conf"
+statedir=${workdir}
+signingkey = ${SIGNINGKEY}
+issuercert = ${ISSUERCERT}
+certserial = ${CERTSERIAL}
+signingkey_password = password
+_EOF_
+
+cat <<_EOF_ > "${workdir}/swtpm-localca.options"
+--tpm-manufacturer IBM
+--tpm-model swtpm-libtpms
+--tpm-version 2
+--platform-manufacturer Fedora
+--platform-version 2.1
+--platform-model QEMU
+_EOF_
+
+# the following contains the test parameters and
+# expected key usage
+for testparams in \
+       "--allow-signing|Digital signature" \
+       "--allow-signing --decryption|Digital signature,Key encipherment" \
+       "--decryption|Key encipherment" \
+       "|Key encipherment";
+do
+  params=$(echo ${testparams} | cut -d"|" -f1)
+  usage=$(echo ${testparams} | cut -d"|" -f2)
+
+  ${SWTPM_LOCALCA} \
+    --type ek \
+    --ek "${ek}" \
+    --dir "${workdir}" \
+    --vmid test \
+    --tpm2 \
+    --configfile "${workdir}/swtpm-localca.conf" \
+    --optsfile "${workdir}/swtpm-localca.options" \
+    --tpm-spec-family 2.0 --tpm-spec-revision 146 --tpm-spec-level 0 \
+    ${params}
+  if [ $? -ne 0 ]; then
+    echo "Error: Test with parameters '$params' failed."
+    exit 1
+  fi
+
+  # Signing key should always be password protected
+  if [ -z "$(grep "ENCRYPTED PRIVATE KEY" "${SIGNINGKEY}")" ]; then
+    echo "Error: Signing key is not password protected."
+    exit 1
+  fi
+
+  # For the root CA's key we flip the password protection
+  if [ -n "${SWTPM_ROOTCA_PASSWORD}" ] ;then
+     if [ -z "$(grep "ENCRYPTED PRIVATE KEY" "${workdir}/swtpm-localca-rootca-privkey.pem")" ]; then
+       echo "Error: Root CA's private key is not password protected."
+       exit 1
+     fi
+     unset SWTPM_ROOTCA_PASSWORD
+  else
+     if [ -n "$(grep "ENCRYPTED PRIVATE KEY" "${workdir}/swtpm-localca-rootca-privkey.pem")" ]; then
+       echo "Error: Root CA's private key is password protected but should not be."
+       exit 1
+     fi
+     export SWTPM_ROOTCA_PASSWORD=xyz
+  fi
+
+  if [ ! -r "${workdir}/ek.cert" ]; then
+    echo "Error: ${workdir}/ek.cert was not created."
+    exit 1
+  fi
+
+  OIFS="$IFS"
+  IFS=","
+
+  for u in $usage; do
+    echo $u
+    if [ -z "$(${CERTTOOL} -i \
+                 --inder --infile "${workdir}/ek.cert" | \
+                grep "Key Usage" -A2 | \
+                grep "$u")" ]; then
+      echo "Error: Could not find key usage $u in key created " \
+           "with $params."
+    else
+      echo "Found '$u'"
+    fi
+  done
+
+  IFS="$OIFS"
+
+  ${CERTTOOL} \
+    -i \
+    --inder --infile "${workdir}/ek.cert" \
+    --outfile "${workdir}/ek.pem"
+
+  ${CERTTOOL} \
+    --verify \
+    --load-ca-certificate "${ISSUERCERT}" \
+    --infile "${workdir}/ek.pem"
+  if [ $? -ne 0 ]; then
+    echo "Error: Could not verify certificate chain."
+    exit 1
+  fi
+
+  # Delete all keys to have CA re-created
+  rm -rf "${workdir}"/*.pem
+done
+
+echo "Test 1: OK"
+echo
+
+#A few tests with odd vm Ids
+for vmid in \
+       's p a c e|s p a c e' \
+       '$(ls)>foo|$(ls)\>foo' \
+       '`ls`&; #12|`ls`&\; #12' \
+       'foo>&1<&2;$(ls)|foo\>&1\<&2\;$(ls)' \
+       "'*|'*" \
+       '"*|\"*' \
+       ':$$|:$$' \
+       '${t}[]|${t}[]';
+do
+  in=$(echo "$vmid" | cut -d"|" -f1)
+  exp=$(echo "$vmid" | cut -d"|" -f2)
+
+  ${SWTPM_LOCALCA} \
+    --type ek \
+    --ek "${ek}" \
+    --dir "${workdir}" \
+    --vmid "$in" \
+    --tpm2 \
+    --configfile "${workdir}/swtpm-localca.conf" \
+    --optsfile "${workdir}/swtpm-localca.options" \
+    --tpm-spec-family 2.0 --tpm-spec-revision 146 --tpm-spec-level 0 \
+    ${params} &>/dev/null
+  if [ $? -ne 0 ]; then
+    echo "Error: Test with parameters '$params' failed."
+    exit 1
+  fi
+
+  if [ ! -r "${workdir}/ek.cert" ]; then
+    echo "Error: ${workdir}/ek.cert was not created."
+    exit 1
+  fi
+
+  ac=$(${CERTTOOL} -i --inder --infile "${workdir}/ek.cert" | \
+       sed -n "s/.*Subject: CN=\(.*\)$/\1/p")
+  if [ "$ac" != "$exp" ]; then
+    echo "Error: unexpected subject string"
+    echo "actual   : $ac"
+    echo "expected : $exp"
+  else
+    echo "Pass: $ac"
+  fi
+done
+
+echo "Test 2: OK"
+
+exit 0
diff --git a/tests/test_tpm2_swtpm_localca_pkcs11 b/tests/test_tpm2_swtpm_localca_pkcs11
new file mode 100755 (executable)
index 0000000..5c16a5e
--- /dev/null
@@ -0,0 +1,223 @@
+#!/usr/bin/env bash
+
+# For the license, see the LICENSE file in the root directory.
+#set -x
+
+TOPBUILD=${abs_top_builddir:-$(dirname "$0")/..}
+TOPSRC=${abs_top_srcdir:-$(dirname "$0")/..}
+TESTDIR=${abs_top_testdir:-$(dirname "$0")}
+
+SWTPM_LOCALCA=${TOPBUILD}/src/swtpm_localca/swtpm_localca
+
+workdir=$(mktemp -d)
+if [ $? -ne 0 ]; then
+       exit 1
+fi
+
+# Have softhsm_setup use 'workdir'.
+export SOFTHSM_SETUP_CONFIGDIR="${workdir}"
+
+# Since we will be using the pkcs11 module as well via certtool
+# we have to set the environment variable to point to its config file.
+# This has to be the same as for swtpm_setup sets it.
+export SOFTHSM2_CONF="${workdir}"/softhsm2.conf
+
+ek="80" # 2048 bit key must have highest bit set
+for ((i = 1; i < 256; i++)); do
+  ek="${ek}$(printf "%02x" $i)"
+done
+
+SIGNINGKEY=${workdir}/signingkey.pem
+ISSUERCERT=${workdir}/issuercert.pem
+CERTSERIAL=${workdir}/certserial
+
+PATH=${TOPBUILD}/src/swtpm_cert:$PATH
+
+source ${TESTDIR}/common
+
+trap "cleanup" SIGTERM EXIT
+
+function cleanup()
+{
+       rm -rf ${workdir}
+       ${TESTDIR}/softhsm_setup teardown
+}
+
+unset GNUTLS_PIN
+export PIN="abcdef"
+
+# Generate the PKCS11 token and key; it uses env. variable 'PIN'
+msg=$(${TESTDIR}/softhsm_setup setup 2>&1)
+if [ $? -ne 0 ]; then
+       echo -e "Could not setup softhsm:\n${msg}"
+       echo "softhsm needs to be v2.3.0 or greater and pkcs11 correctly configured"
+       exit 77
+fi
+pkcs11uri=$(echo ${msg} | sed -n 's|^keyuri: \(.*\)|\1|p')
+
+# Now we need to create the root CA ...
+template=${workdir}/template
+
+cakey=${workdir}/swtpm-localca-rootca-privkey.pem
+cacert=${workdir}/swtpm-localca-rootca-cert.pem
+
+# first the private key
+msg=$(${CERTTOOL} \
+       --generate-privkey \
+       --outfile ${cakey} \
+       ${passparam} \
+       2>&1)
+if [ $? -ne 0 ]; then
+       echo "Could not create root-CA key ${cakey}."
+       echo "${msg}"
+       exit 1
+fi
+chmod 640 ${cakey}
+
+# now the self-signed certificate
+cat <<_EOF_ >${template}
+cn=swtpm-localca-rootca
+ca
+cert_signing_key
+expiration_days = 3650
+_EOF_
+
+msg=$(${CERTTOOL} \
+       --generate-self-signed \
+       --template ${template} \
+       --outfile ${cacert} \
+       --load-privkey ${cakey} \
+       2>&1)
+if [ $? -ne 0 ]; then
+       echo "Could not create root CA."
+       echo "${msg}"
+       exit 1
+fi
+
+# And now create the intermediate CA with the pkcs11 URI key
+
+pubkey=${workdir}/swtpm-localca-interm-pubkey.pem
+
+msg=$(GNUTLS_PIN=${PIN} ${CERTTOOL} \
+       --load-privkey ${pkcs11uri} \
+       --pubkey-info \
+       --outfile ${pubkey})
+if [ $? -ne 0 ]; then
+       echo "Could not get public key for pkcs11 uri key ($pkcs11uri}."
+       echo "${msg}"
+       exit 1
+fi
+
+cat <<_EOF_ > ${template}
+cn=swtpm-localca
+ca
+cert_signing_key
+expiration_days = 3650
+_EOF_
+
+msg=$(GNUTLS_PIN=${PIN} ${CERTTOOL} \
+       --generate-certificate \
+       --template ${template} \
+       --outfile ${ISSUERCERT} \
+       --load-ca-privkey ${cakey} \
+       --load-ca-certificate ${cacert} \
+       --load-privkey ${pkcs11uri} \
+       --load-pubkey ${pubkey} \
+       2>&1)
+if [ $? -ne 0 ]; then
+       echo "Could not create intermediate CA"
+       echo "${msg}"
+       exit 1
+fi
+
+echo -n 1 > ${CERTSERIAL}
+
+# Now we can create the config files
+cat <<_EOF_ > ${workdir}/swtpm-localca.conf
+statedir = ${workdir}
+signingkey = $(echo ${pkcs11uri} | sed 's|;|\\;|g')
+issuercert = ${ISSUERCERT}
+certserial = ${CERTSERIAL}
+SWTPM_PKCS11_PIN = ${PIN}
+_EOF_
+
+cat <<_EOF_ > ${workdir}/swtpm-localca.options
+--tpm-manufacturer IBM
+--tpm-model swtpm-libtpms
+--tpm-version 2
+--platform-manufacturer Fedora
+--platform-version 2.1
+--platform-model QEMU
+_EOF_
+
+# the following contains the test parameters and
+# expected key usage
+for testparams in \
+       "--allow-signing|Digital signature" \
+       "--allow-signing --decryption|Digital signature,Key encipherment" \
+       "--decryption|Key encipherment" \
+       "|Key encipherment";
+do
+  params=$(echo ${testparams} | cut -d"|" -f1)
+  usage=$(echo ${testparams} | cut -d"|" -f2)
+
+  msg=$(${SWTPM_LOCALCA} \
+    --type ek \
+    --ek ${ek} \
+    --dir ${workdir} \
+    --vmid test \
+    --tpm2 \
+    --configfile ${workdir}/swtpm-localca.conf \
+    --optsfile ${workdir}/swtpm-localca.options \
+    --tpm-spec-family 2.0 --tpm-spec-revision 146 --tpm-spec-level 0 \
+    ${params} 2>&1)
+  if [ $? -ne 0 ]; then
+    echo "Error: Test with parameters '$params' failed."
+    echo "${msg}"
+    if [[ "${msg}" =~ The\ requested\ PKCS\ #11\ object\ is\ not\ available ]]; then
+        # could be related to i386 executables on x86_64 host and
+        # libsofthsm.so only available for x86_64...
+        exit 77
+    fi
+    exit 1
+  fi
+
+  if [ ! -r ${workdir}/ek.cert ]; then
+    echo "${msg}"
+    echo "Error: ${workdir}/ek.cert was not created."
+    exit 1
+  fi
+
+  OIFS="$IFS"
+  IFS=","
+
+  for u in $usage; do
+    if [ -z "$(${CERTTOOL} -i \
+                 --inder --infile ${workdir}/ek.cert | \
+                grep "Key Usage" -A2 | \
+                grep "$u")" ]; then
+      echo "Error: Could not find key usage $u in key created " \
+           "with $params."
+    else
+      echo "Found '$u'"
+    fi
+  done
+
+  IFS="$OIFS"
+
+  ${CERTTOOL} \
+    -i \
+    --inder --infile ${workdir}/ek.cert \
+    --outfile ${workdir}/ek.pem
+
+  GNUTLS_PIN=${PIN} ${CERTTOOL} \
+    --verify \
+    --load-ca-certificate ${ISSUERCERT} \
+    --infile ${workdir}/ek.pem
+  if [ $? -ne 0 ]; then
+    echo "Error: Could not verify certificate chain."
+    exit 1
+  fi
+done
+
+exit 0
index 8d0cdf69c84c306e40270034d7143289d9b5a546..63adfcb467ebdae4d221f50009782ab5f5706a18 100755 (executable)
@@ -9,7 +9,7 @@ TESTDIR=${abs_top_testdir:-$(dirname "$0")}
 
 source ${TESTDIR}/common
 
-SWTPM_LOCALCA=${TOPBUILD}/samples/swtpm-localca
+SWTPM_LOCALCA=${TOPBUILD}/src/swtpm_localca/swtpm_localca
 
 workdir=$(mktemp -d "/tmp/path with spaces.XXXXXX")