]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
pki: use libtls for pki --est|--estca
authorAndreas Steffen <andreas.steffen@strongswan.org>
Mon, 22 Aug 2022 10:42:09 +0000 (12:42 +0200)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Thu, 25 Aug 2022 08:50:40 +0000 (10:50 +0200)
src/pki/Makefile.am
src/pki/commands/est.c
src/pki/commands/estca.c
src/pki/commands/scep.c
src/pki/commands/scepca.c
src/pki/est/est.c [deleted file]
src/pki/est/est.h [deleted file]
src/pki/est/est_tls.c
src/pki/est/est_tls.h
src/pki/pki_cert.c

index 22fb11fe8d89a61205142eb99f56c3c3dc9595b0..b4c05318a7144b6fca91baaffde6f552824d6dec 100644 (file)
@@ -20,7 +20,7 @@ pki_SOURCES = pki.c pki.h pki_cert.c pki_cert.h command.c command.h \
        commands/self.c \
        commands/signcrl.c \
        commands/verify.c \
-       est/est.h est/est.c est/est_tls.h est/est_tls.c \
+       est/est_tls.h est/est_tls.c     \
        scep/scep.h scep/scep.c
 
 pki_LDADD = \
index 8f39b0f5272ee1bca711e69a3e0b030cc1020014..67e011f96316ed260eab59feadd3e35cb029f7ee 100644 (file)
@@ -19,7 +19,6 @@
 
 #include "pki.h"
 #include "pki_cert.h"
-#include "est/est.h"
 #include "est/est_tls.h"
 
 #include <credentials/certificates/certificate.h>
@@ -64,7 +63,7 @@ static int est()
                        case 'i':       /* --in */
                                file = arg;
                                continue;
-                       case 'c':       /* --cacert */
+                       case 'C':       /* --cacert */
                                cacert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
                                                         CERT_X509,     BUILD_FROM_FILE, arg, BUILD_END);
                                if (!cacert)
@@ -74,7 +73,7 @@ static int est()
                                }
                                creds->add_cert(creds, TRUE, cacert);
                                continue;
-                       case 'o':       /* --cert */
+                       case 'c':       /* --cert */
                                client_cert_file = arg;
                                continue;
                        case 'X':       /* --certid */
@@ -193,7 +192,7 @@ static int est()
        {
                chunk_t handle;
 
-               if (client_cert_file)   /* loadold certificate file */
+               if (client_cert_file)   /* load old certificate file */
                {
                        client_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
                                                                                CERT_X509,
@@ -362,9 +361,9 @@ static void __attribute__ ((constructor))reg()
                        {"help",        'h', 0, "show usage information"},
                        {"url",         'u', 1, "URL of the EST server"},
                        {"in",          'i', 1, "PKCS#10 input file, default: stdin"},
-                       {"cacert",      'c', 1, "CA certificate"},
-                       {"cert",        'o', 1, "old certificate about to be renewed"},
-                       {"certid",              'X', 1, "smartcard or TPM certificate object handle" },
+                       {"cacert",      'C', 1, "CA certificate"},
+                       {"cert",        'c', 1, "old certificate about to be renewed"},
+                       {"certid",      'X', 1, "smartcard or TPM certificate object handle" },
                        {"key",         'k', 1, "old private key about to be replaced"},
                        {"keyid",       'x', 1, "smartcard or TPM private key object handle"},
                        {"userpass",    'p', 1, "username:password for http basic auth"},
index 02161ddd0448c5b50dc4c785bb7603f45147ff1c..f6a584bb7d55bc0f93b84e861a0feedd899eb3f5 100644 (file)
@@ -16,7 +16,7 @@
 
 #include "pki.h"
 #include "pki_cert.h"
-#include "est/est.h"
+#include "est/est_tls.h"
 
 #include <credentials/containers/pkcs7.h>
 #include <credentials/certificates/certificate.h>
@@ -29,35 +29,55 @@ static int estca()
 {
        cred_encoding_type_t form = CERT_ASN1_DER;
        chunk_t est_response = chunk_empty;
-       char *arg, *url = NULL, *caout = NULL;
+       certificate_t *cacert;
+       mem_cred_t *creds = NULL;
+       est_tls_t *est_tls;
+       char *arg, *error = NULL, *url = NULL, *caout = NULL;
        bool force = FALSE, success;
        u_int http_code = 0;
+       status_t status = 1;
+
+       /* initialize CA certificate storage */
+       creds = mem_cred_create();
+       lib->credmgr->add_set(lib->credmgr, &creds->set);
 
        while (TRUE)
        {
                switch (command_getopt(&arg))
                {
-                       case 'h':
-                               return command_usage(NULL);
-                       case 'u':
+                       case 'h':       /* --help */
+                               goto usage;
+                       case 'u':       /* --url */
                                url = arg;
                                continue;
-                       case 'c':
+                       case 'C':       /* --cacert */
+                               cacert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
+                                                        CERT_X509,     BUILD_FROM_FILE, arg, BUILD_END);
+                               if (!cacert)
+                               {
+                                       DBG1(DBG_APP, "could not load cacert file '%s'", arg);
+                                       goto err;
+                               }
+                               creds->add_cert(creds, TRUE, cacert);
+                               continue;
+                       case 'c':       /* --caout */
                                caout = arg;
                                continue;
-                       case 'f':
+                       case 'f':       /* --outform */
                                if (!get_form(arg, &form, CRED_CERTIFICATE))
                                {
-                                       return command_usage("invalid certificate output format");
+                                       error ="invalid certificate output format";
+                                       goto usage;
                                }
                                continue;
-                       case 'F':
+                       case 'F':       /* --force */
                                force = TRUE;
                                continue;
                        case EOF:
                                break;
                        default:
-                               return command_usage("invalid --estca option");
+                               error ="invalid --estca option";
+                               goto usage;
                }
                break;
        }
@@ -67,17 +87,38 @@ static int estca()
                return command_usage("--url is required");
        }
 
-       if (!est_https_request(url, EST_CACERTS, FALSE, chunk_empty, &est_response,
-                                                  &http_code))
+       est_tls = est_tls_create(url, NULL, NULL);
+       if (!est_tls)
+       {
+               DBG1(DBG_APP, "TLS connection to EST server was not established");
+               goto err;
+       }
+       success = est_tls->request(est_tls, EST_CACERTS, chunk_empty, &est_response,
+                                                          &http_code, NULL);
+       est_tls->destroy(est_tls);
+
+       if (!success)
+       {
+               DBG1(DBG_APP, "EST request failed: HTTP %u", http_code);
+               goto err;
+       }
+       if (pki_cert_extract_cacerts(est_response, caout, NULL, TRUE, form, force))
        {
-               DBG1(DBG_APP, "did not receive a valid EST response: HTTP %u", http_code);
-               return 1;
+               status = 0;
        }
-       success = pki_cert_extract_cacerts(est_response, caout, NULL, TRUE, form,
-                                                                          force);
+
+err:
+       lib->credmgr->remove_set(lib->credmgr, &creds->set);
+       creds->destroy(creds);
        chunk_free(&est_response);
 
-       return success ? 0 : 1;
+       return status;
+
+usage:
+       lib->credmgr->remove_set(lib->credmgr, &creds->set);
+       creds->destroy(creds);
+
+       return command_usage(error);
 }
 
 /**
@@ -88,10 +129,11 @@ static void __attribute__ ((constructor))reg()
        command_register((command_t) {
                estca, 'e', "estca",
                "get CA certificate[s] from a EST server",
-               {"--url url [--caout file] [--outform der|pem] [--force]"},
+               {"--url url [--cacert file]+ [--caout file] [--outform der|pem] [--force]"},
                {
                        {"help",    'h', 0, "show usage information"},
                        {"url",     'u', 1, "URL of the SCEP server"},
+                       {"cacert",  'C', 1, "TLS CA certificate"},
                        {"caout",   'c', 1, "CA certificate [template]"},
                        {"outform", 'f', 1, "encoding of stored certificates, default: der"},
                        {"force",   'F', 0, "force overwrite of existing files"},
index 500735d17b041963736adfea83ac97d1ad8c5a6f..f7db744d5a94090eab6478f548d36a7db19d01c1 100644 (file)
@@ -39,7 +39,7 @@ static int scep()
 {
        char *arg, *url = NULL, *file = NULL, *dn = NULL, *error = NULL;
        char *ca_enc_file = NULL, *ca_sig_file = NULL;
-       char *old_cert_file = NULL, *old_key_file = NULL;
+       char *client_cert_file = NULL, *client_key_file = NULL;
        cred_encoding_type_t form = CERT_ASN1_DER;
        chunk_t scep_response = chunk_empty;
        chunk_t challenge_password = chunk_empty;
@@ -95,33 +95,33 @@ static int scep()
        {
                switch (command_getopt(&arg))
                {
-                       case 'h':
+                       case 'h':       /* --help */
                                goto usage;
-                       case 'u':
+                       case 'u':       /* --url */
                                url = arg;
                                continue;
-                       case 'i':
+                       case 'i':       /* --in */
                                file = arg;
                                continue;
-                       case 'd':
+                       case 'd':       /* --dn */
                                dn = arg;
                                continue;
-                       case 'a':
+                       case 'a':       /* --san */
                                san->insert_last(san, identification_create_from_string(arg));
                                continue;
-                       case 'P':
+                       case 'P':       /* --profile */
                                cert_type = chunk_create(arg, strlen(arg));
                                continue;
-                       case 'p':
+                       case 'p':       /* --password */
                                challenge_password = chunk_create(arg, strlen(arg));
                                continue;
-                       case 'e':
+                       case 'e':       /* --cacert-enc */
                                ca_enc_file = arg;
                                continue;
-                       case 's':
+                       case 's':       /* --cacert-sig */
                                ca_sig_file = arg;
                                continue;
-                       case 'c':
+                       case 'C':       /* --cacert */
                                cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
                                                                        BUILD_FROM_FILE, arg, BUILD_END);
                                if (!cert)
@@ -131,13 +131,13 @@ static int scep()
                                }
                                creds->add_cert(creds, TRUE, cert);
                                continue;
-                       case 'o':
-                               old_cert_file = arg;
+                       case 'c':       /* --cert */
+                               client_cert_file = arg;
                                continue;
-                       case 'k':
-                               old_key_file = arg;
+                       case 'k':       /* --key */
+                               client_key_file = arg;
                                continue;
-                       case 'C':
+                       case 'E':       /* --cipher */
                                if (strcaseeq(arg, "des3"))
                                {
                                        cipher = ENCR_3DES;
@@ -154,14 +154,14 @@ static int scep()
                                        goto usage;
                                }
                                continue;
-                       case 'g':
+                       case 'g':       /* --digest */
                                if (!enum_from_name(hash_algorithm_short_names, arg, &digest_alg))
                                {
                                        error = "invalid --digest type";
                                        goto usage;
                                }
                                continue;
-                       case 'R':
+                       case 'R':       /* --rsa-padding */
                                if (streq(arg, "pss"))
                                {
                                        pss = TRUE;
@@ -186,7 +186,7 @@ static int scep()
                        case 'm':       /* --maxpolltime */
                                max_poll_time = atoi(optarg);
                                continue;
-                       case 'f':
+                       case 'f':       /* --form */
                                if (!get_form(arg, &form, CRED_CERTIFICATE))
                                {
                                        error = "invalid certificate output format";
@@ -220,7 +220,7 @@ static int scep()
                goto usage;
        }
 
-       if (old_cert_file && !old_key_file)
+       if (client_cert_file && !client_key_file)
        {
                error = "--oldkey is required if --oldcert is set";
                goto usage;
@@ -374,7 +374,7 @@ static int scep()
        }
        DBG1(DBG_APP, "transaction ID: %.*s", (int)transID.len, transID.ptr);
 
-       if (old_cert_file)
+       if (client_cert_file)
        {
                /* check support of Renewal Operation */
                if (!(caps_flags & SCEP_CAPS_RENEWAL))
@@ -390,19 +390,21 @@ static int scep()
 
                /* load old client certificate */
                x509_signer  = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
-                                                                       BUILD_FROM_FILE, old_cert_file, BUILD_END);
+                                                                       BUILD_FROM_FILE, client_cert_file, BUILD_END);
                if (!x509_signer)
                {
-                       DBG1(DBG_APP, "could not load old cert file '%s'", old_cert_file);
+                       DBG1(DBG_APP, "loading client cert file '%s' failed",
+                                                  client_cert_file);
                        goto err;
                }
 
                /* load old RSA private key */
                priv_signer = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
-                                                                        BUILD_FROM_FILE, old_key_file, BUILD_END);
+                                                                        BUILD_FROM_FILE, client_key_file, BUILD_END);
                if (!priv_signer)
                {
-                       DBG1(DBG_APP, "parsing old private key failed");
+                       DBG1(DBG_APP, "loading client private key file '%s' failed",
+                                                  client_key_file);
                        goto err;
                }
        }
@@ -456,7 +458,7 @@ static int scep()
                DBG1(DBG_APP, "could not load signature cacert file '%s'", ca_sig_file);
                goto end;
        }
-       creds->add_cert(creds, TRUE, x509_ca_sig->get_ref(x509_ca_sig));
+       x509_ca_sig = creds->add_cert_ref(creds, TRUE, x509_ca_sig);
 
        /* build pkcs7 request */
        pkcs7_req = scep_build_request(pkcs10_encoding, transID, scep_msg_type,
@@ -642,10 +644,10 @@ static void __attribute__ ((constructor))reg()
                        {"password",    'p', 1, "challengePassword to include in cert request"},
                        {"cacert-enc",  'e', 1, "CA certificate for encryption"},
                        {"cacert-sig",  's', 1, "CA certificate for signature verification"},
-                       {"cacert",      'c', 1, "Additional CA certificates"},
-                       {"oldcert",     'o', 1, "Old certificate about to be renewed"},
-                       {"oldkey",      'k', 1, "Old RSA private key about to be replaced"},
-                       {"cipher",      'C', 1, "encryption cipher, default: aes"},
+                       {"cacert",      'C', 1, "Additional CA certificates"},
+                       {"cert",        'c', 1, "Old certificate about to be renewed"},
+                       {"key",         'k', 1, "Old RSA private key about to be replaced"},
+                       {"cipher",      'E', 1, "encryption cipher, default: aes"},
                        {"digest",      'g', 1, "digest for signature creation, default: sha256"},
                        {"rsa-padding", 'R', 1, "padding for RSA signatures, default: pkcs1"},
                        {"interval",    't', 1, "poll interval, default: 60s"},
index 32df55de724d7ea0085fc590c8133d54c8d0de9b..9ba72d41cf9f1e1381841af3ea222101c1796f2e 100644 (file)
@@ -37,24 +37,24 @@ static int scepca()
        {
                switch (command_getopt(&arg))
                {
-                       case 'h':
+                       case 'h':       /* --help */
                                return command_usage(NULL);
-                       case 'u':
+                       case 'u':       /* --url */
                                url = arg;
                                continue;
-                       case 'c':
+                       case 'c':       /* --caout */
                                caout = arg;
                                continue;
-                       case 'r':
+                       case 'r':       /* --raout */
                                raout = arg;
                                continue;
-                       case 'f':
+                       case 'f':       /* --form */
                                if (!get_form(arg, &form, CRED_CERTIFICATE))
                                {
                                        return command_usage("invalid certificate output format");
                                }
                                continue;
-                       case 'F':
+                       case 'F':       /* --force */
                                force = TRUE;
                                continue;
                        case EOF:
diff --git a/src/pki/est/est.c b/src/pki/est/est.c
deleted file mode 100644 (file)
index c24bf5c..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2022 Andreas Steffen, strongSec GmbH
- *
- * Copyright (C) secunet Security Networks AG
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-#define _GNU_SOURCE
-#include <stdio.h>
-
-#include "est.h"
-
-#define HTTP_CODE_OK         200
-
-static const char *operations[] = {
-       "cacerts",
-       "simpleenroll",
-       "simplereenroll",
-       "fullcmc",
-       "serverkeygen",
-       "csrattrs"
-};
-
-static const char *request_types[] = {
-       "",
-       "application/pkcs10",
-       "application/pkcs10",
-       "application/pkcs7-mime",
-       "application/pkcs10",
-       ""
-};
-
-/**
- * Send an EST request via HTTPS and wait for a response
- */
-bool est_https_request(const char *url, est_op_t op, bool http_post,
-                                          chunk_t data, chunk_t *response, u_int *http_code)
-{
-       host_t *srcip = NULL;
-       char *complete_url = NULL;
-       status_t status;
-
-       uint32_t http_timeout = lib->settings->get_time(lib->settings,
-                                                                               "%s.est.http_timeout", 30, lib->ns);
-
-       char *http_bind = lib->settings->get_str(lib->settings,
-                                                                               "%s.est.http_bind", NULL, lib->ns);
-
-       /* initialize response */
-       *response = chunk_empty;
-       *http_code = 0;
-
-       /* construct complete EST URL */
-       if (asprintf(&complete_url, "%s/.well-known/est/%s", url, operations[op]) == -1)
-       {
-               DBG1(DBG_APP, "could not allocate complete_url string");
-               return FALSE;
-       }
-       DBG2(DBG_APP, "sending EST request to '%s'", url);
-
-       if (http_bind)
-       {
-               srcip = host_create_from_string(http_bind, 0);
-       }
-
-       if (http_post)
-       {
-               status = lib->fetcher->fetch(lib->fetcher, complete_url, response,
-                                                                        FETCH_TIMEOUT, http_timeout,
-                                                                        FETCH_REQUEST_DATA, data,
-                                                                        FETCH_REQUEST_TYPE, request_types[op],
-                                                                        FETCH_REQUEST_HEADER, "Expect:",
-                                                                        FETCH_SOURCEIP, srcip,
-                                                                        FETCH_RESPONSE_CODE, http_code,
-                                                                        FETCH_END);
-       }
-       else /* HTTP_GET */
-       {
-               status = lib->fetcher->fetch(lib->fetcher, complete_url, response,
-                                                                        FETCH_TIMEOUT, http_timeout,
-                                                                        FETCH_SOURCEIP, srcip,
-                                                                        FETCH_RESPONSE_CODE, http_code,
-                                                                        FETCH_END);
-       }
-       DESTROY_IF(srcip);
-       free(complete_url);
-
-       if (status != SUCCESS)
-       {
-               return FALSE;
-       }
-
-       if (*http_code == HTTP_CODE_OK)
-       {
-               chunk_t base64_response = *response;
-
-               *response = chunk_from_base64(base64_response, NULL);
-               chunk_free(&base64_response);
-       }
-
-       return TRUE;
-}
-
diff --git a/src/pki/est/est.h b/src/pki/est/est.h
deleted file mode 100644 (file)
index 3d9bdd3..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2022 Andreas Steffen, strongSec GmbH
- *
- * Copyright (C) secunet Security Networks AG
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-#ifndef _EST_H
-#define _EST_H
-
-#include <library.h>
-
-/**
- * EST (RFC 7030) Operations
- */
-typedef enum {
-       EST_CACERTS,
-       EST_SIMPLE_ENROLL,
-       EST_SIMPLE_REENROLL,
-       EST_FULL_CMC,
-       EST_SERVER_KEYGEN,
-       EST_CSR_ATTRS
-} est_op_t;
-
-/**
- * Send an EST request via HTTPS and wait for a response
- */
-bool est_https_request(const char *url, est_op_t op, bool http_post,
-                                          chunk_t data, chunk_t *response, u_int *http_code);
-
-#endif /* _EST_H */
index a10ed1416b0feae6b666193b98bdef1e315be13f..ccc03280df1fe255694c8fafc4a8aa54178efcbe 100644 (file)
@@ -16,8 +16,6 @@
 
 #define _GNU_SOURCE /* for asprintf() */
 #include <stdio.h>
-#include <sys/types.h>
-#include <sys/socket.h>
 #include <unistd.h>
 #include <errno.h>
 
@@ -133,7 +131,8 @@ static chunk_t build_http_request(private_est_tls_t *this, est_op_t op, chunk_t
                len = asprintf(&http_header,
                                "GET %s/.well-known/est/%s HTTP/1.1\r\n"
                                "Host: %s\r\n"
-                               "%s",
+                               "%s"
+                               "\r\n",
                                this->http_path, operations[op], this->http_host, http_auth);
                if (len > 0)
                {
@@ -154,6 +153,11 @@ static bool parse_http_header(chunk_t *in,  u_int *http_code, u_int *content_len
        *content_len = 0;
        *base64 = FALSE;
 
+       if (retry_after)
+       {
+               *retry_after = 0;
+       }
+
        /* Process HTTP protocol version and HTTP status code */
        if (!fetchline(in, &line) || !extract_token(&version, ' ', &line) ||
                !match("HTTP/1.1", &version) || sscanf(line.ptr, "%d", http_code) != 1)
@@ -210,7 +214,11 @@ METHOD(est_tls_t, request, bool,
        /* initialize output variables */
        *out = chunk_empty;
        *http_code = 0;
-       *retry_after = 0;
+
+       if (retry_after)
+       {
+               *retry_after = 0;
+       }
 
        http = build_http_request(this, op, in);
 
index d05831c718338f3d7c716d7877c1c3f105767aae..ded2aeb19a32e199d62ed35809ef43081800a650 100644 (file)
@@ -22,8 +22,6 @@
 #ifndef EST_TLS_H_
 #define EST_TLS_H_
 
-#include "est.h"
-
 #include <library.h>
 #include <credentials/certificates/certificate.h>
 
 
 typedef struct est_tls_t est_tls_t;
 
+/**
+ * EST (RFC 7030) Operations
+ */
+typedef enum {
+    EST_CACERTS,
+    EST_SIMPLE_ENROLL,
+    EST_SIMPLE_REENROLL,
+    EST_FULL_CMC,
+    EST_SERVER_KEYGEN,
+    EST_CSR_ATTRS
+} est_op_t;
+
 /**
  * TLS Interface for sending and receiving HTTPS messages
  */
index 202284e43ef50669c74ed9e032bfbe788c7b4294..34f8d4691b69a4ba44015e6a7f029016b4722929 100644 (file)
@@ -73,11 +73,15 @@ static bool print_cert_info(certificate_t *cert, pki_cert_type_t cert_type)
        char digest_buf[HASH_SIZE_SHA256];
        char base64_buf[HASH_SIZE_SHA256];
        chunk_t cert_digest = {digest_buf, HASH_SIZE_SHA256};
-       chunk_t cert_id, encoding = chunk_empty;
+       chunk_t cert_id, serial, encoding = chunk_empty;
+       x509_t *x509;
        bool success = FALSE;
 
        DBG1(DBG_APP, "%s cert \"%Y\"", cert_type_label[cert_type],
                                                                        cert->get_subject(cert));
+       x509 = (x509_t*)cert;
+       serial = x509->get_serial(x509);
+       DBG1(DBG_APP, "  serial: %#B", &serial);
 
        if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoding))
        {
@@ -299,26 +303,53 @@ bool pki_cert_extract_cacerts(chunk_t data, char *caout, char *raout,
        {
                enumerator_t *enumerator;
                pkcs7_t *pkcs7 = (pkcs7_t*)container;
+               certificate_t *cert_found;
+               enumerator_t *certs;
+               bool trusted;
 
                enumerator = pkcs7->create_cert_enumerator(pkcs7);
                while (enumerator->enumerate(enumerator, &cert))
                {
+                       trusted = FALSE;
+
                        cert_type = get_pki_cert_type(cert);
                        if (cert_type == CERT_TYPE_ROOT_CA)
                        {
-                               /* trust in root CA has to be established manuallly */
-                               creds->add_cert(creds, TRUE, cert->get_ref(cert));
-
-                               cert_type_count[cert_type]++;
-
                                if (!print_cert_info(cert, cert_type))
                                {
                                        goto end;
                                }
+
+                               /* same root CA as trusted TLS root CA already in cred set? */
+                               certs = lib->credmgr->create_trusted_enumerator(lib->credmgr,
+                                                                       KEY_ANY, cert->get_subject(cert), FALSE);
+                               while (certs->enumerate(certs, &cert_found, NULL))
+                               {
+                                       if (cert->equals(cert, cert_found))
+                                       {
+                                               DBG1(DBG_APP, "Root CA equals trusted TLS Root CA");
+                                               trusted = TRUE;
+                                               break;
+                                       }
+                                       else
+                                       {
+                                               DBG1(DBG_APP, "non-matching TLS Root CA of same name");
+                                       }
+                               }
+                               certs->destroy(certs);
+
+                               /* otherwise trust in root CA has to be established manuallly */
+                               if (!trusted)
+                               {
+                                       creds->add_cert(creds, TRUE, cert->get_ref(cert));
+                                       trusted = FALSE;
+                               }
+                               cert_type_count[cert_type]++;
+
                                if (build_pathname(&path, cert_type, cert_type_count, caout,
                                                                   raout, form))
                                {
-                                       written = write_cert(cert, cert_type, FALSE, path, form,
+                                       written = write_cert(cert, cert_type, trusted, path, form,
                                                                                 force);
                                        free(path);
                                }
@@ -344,24 +375,31 @@ bool pki_cert_extract_cacerts(chunk_t data, char *caout, char *raout,
                while (enumerator->enumerate(enumerator, &cert))
                {
                        written = FALSE;
+                       trusted = FALSE;
 
                        cert_type = get_pki_cert_type(cert);
                        if (cert_type != CERT_TYPE_ROOT_CA)
                        {
-                               certificate_t *cert_found = NULL;
-                               enumerator_t *certs;
-                               bool trusted;
-
                                if (!print_cert_info(cert, cert_type))
                                {
                                        break;
                                }
 
-                               /* establish trust relativ to root CA */
+                               /* establish trust relative to root CA */
                                certs = lib->credmgr->create_trusted_enumerator(lib->credmgr,
                                                                        KEY_ANY, cert->get_subject(cert), FALSE);
-                               trusted = certs->enumerate(certs, &cert_found, NULL) &&
-                                                 (cert_found == cert);
+                               while (certs->enumerate(certs, &cert_found, NULL))
+                               {
+                                       if (cert->equals(cert, cert_found))
+                                       {
+                                               trusted = TRUE;
+                                               break;
+                                       }
+                                       else
+                                       {
+                                               DBG1(DBG_APP, "non-matching TLS Sub CA of same name");
+                                       }
+                               }
                                certs->destroy(certs);
 
                                cert_type_count[cert_type]++;
@@ -434,7 +472,7 @@ bool pki_cert_extract_cert(chunk_t data, cred_encoding_type_t form)
 
                if (!(x509->get_flags(x509) & X509_CA))
                {
-                       DBG1(DBG_APP, "issued certificate \"%Y\"", cert->get_subject(cert));
+                       DBG1(DBG_APP, "Issued certificate \"%Y\"", cert->get_subject(cert));
                        serial = x509->get_serial(x509);
                        DBG1(DBG_APP, "  serial: %#B", &serial);
 
@@ -453,7 +491,7 @@ bool pki_cert_extract_cert(chunk_t data, cred_encoding_type_t form)
                        certs->destroy(certs);
 
                        valid = cert->get_validity(cert, NULL, &from, &until);
-                       DBG1(DBG_APP, "issued certificate is %strusted, "
+                       DBG1(DBG_APP, "Issued certificate is %strusted, "
                                                  "valid from %T until %T (currently %svalid)",
                                                  trusted ? "" : "not ", &from, FALSE, &until, FALSE,
                                                  valid ? "" : "not ");