pki: use libtls for pki --est|--estca

This commit is contained in:
Andreas Steffen
2022-08-25 10:50:40 +02:00
parent 976c74b772
commit 784606a827
10 changed files with 183 additions and 236 deletions
+1 -1
View 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/self.c \
commands/signcrl.c \ commands/signcrl.c \
commands/verify.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 scep/scep.h scep/scep.c
pki_LDADD = \ pki_LDADD = \
+6 -7
View File
@@ -19,7 +19,6 @@
#include "pki.h" #include "pki.h"
#include "pki_cert.h" #include "pki_cert.h"
#include "est/est.h"
#include "est/est_tls.h" #include "est/est_tls.h"
#include <credentials/certificates/certificate.h> #include <credentials/certificates/certificate.h>
@@ -64,7 +63,7 @@ static int est()
case 'i': /* --in */ case 'i': /* --in */
file = arg; file = arg;
continue; continue;
case 'c': /* --cacert */ case 'C': /* --cacert */
cacert = lib->creds->create(lib->creds, CRED_CERTIFICATE, cacert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
CERT_X509, BUILD_FROM_FILE, arg, BUILD_END); CERT_X509, BUILD_FROM_FILE, arg, BUILD_END);
if (!cacert) if (!cacert)
@@ -74,7 +73,7 @@ static int est()
} }
creds->add_cert(creds, TRUE, cacert); creds->add_cert(creds, TRUE, cacert);
continue; continue;
case 'o': /* --cert */ case 'c': /* --cert */
client_cert_file = arg; client_cert_file = arg;
continue; continue;
case 'X': /* --certid */ case 'X': /* --certid */
@@ -193,7 +192,7 @@ static int est()
{ {
chunk_t handle; 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, client_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
CERT_X509, CERT_X509,
@@ -362,9 +361,9 @@ static void __attribute__ ((constructor))reg()
{"help", 'h', 0, "show usage information"}, {"help", 'h', 0, "show usage information"},
{"url", 'u', 1, "URL of the EST server"}, {"url", 'u', 1, "URL of the EST server"},
{"in", 'i', 1, "PKCS#10 input file, default: stdin"}, {"in", 'i', 1, "PKCS#10 input file, default: stdin"},
{"cacert", 'c', 1, "CA certificate"}, {"cacert", 'C', 1, "CA certificate"},
{"cert", 'o', 1, "old certificate about to be renewed"}, {"cert", 'c', 1, "old certificate about to be renewed"},
{"certid", 'X', 1, "smartcard or TPM certificate object handle" }, {"certid", 'X', 1, "smartcard or TPM certificate object handle" },
{"key", 'k', 1, "old private key about to be replaced"}, {"key", 'k', 1, "old private key about to be replaced"},
{"keyid", 'x', 1, "smartcard or TPM private key object handle"}, {"keyid", 'x', 1, "smartcard or TPM private key object handle"},
{"userpass", 'p', 1, "username:password for http basic auth"}, {"userpass", 'p', 1, "username:password for http basic auth"},
+60 -18
View File
@@ -16,7 +16,7 @@
#include "pki.h" #include "pki.h"
#include "pki_cert.h" #include "pki_cert.h"
#include "est/est.h" #include "est/est_tls.h"
#include <credentials/containers/pkcs7.h> #include <credentials/containers/pkcs7.h>
#include <credentials/certificates/certificate.h> #include <credentials/certificates/certificate.h>
@@ -29,35 +29,55 @@ static int estca()
{ {
cred_encoding_type_t form = CERT_ASN1_DER; cred_encoding_type_t form = CERT_ASN1_DER;
chunk_t est_response = chunk_empty; 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; bool force = FALSE, success;
u_int http_code = 0; 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) while (TRUE)
{ {
switch (command_getopt(&arg)) switch (command_getopt(&arg))
{ {
case 'h': case 'h': /* --help */
return command_usage(NULL); goto usage;
case 'u': case 'u': /* --url */
url = arg; url = arg;
continue; 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; caout = arg;
continue; continue;
case 'f': case 'f': /* --outform */
if (!get_form(arg, &form, CRED_CERTIFICATE)) if (!get_form(arg, &form, CRED_CERTIFICATE))
{ {
return command_usage("invalid certificate output format"); error ="invalid certificate output format";
goto usage;
} }
continue; continue;
case 'F': case 'F': /* --force */
force = TRUE; force = TRUE;
continue; continue;
case EOF: case EOF:
break; break;
default: default:
return command_usage("invalid --estca option"); error ="invalid --estca option";
goto usage;
} }
break; break;
} }
@@ -67,17 +87,38 @@ static int estca()
return command_usage("--url is required"); return command_usage("--url is required");
} }
if (!est_https_request(url, EST_CACERTS, FALSE, chunk_empty, &est_response, est_tls = est_tls_create(url, NULL, NULL);
&http_code)) if (!est_tls)
{ {
DBG1(DBG_APP, "did not receive a valid EST response: HTTP %u", http_code); DBG1(DBG_APP, "TLS connection to EST server was not established");
return 1; goto err;
} }
success = pki_cert_extract_cacerts(est_response, caout, NULL, TRUE, form, success = est_tls->request(est_tls, EST_CACERTS, chunk_empty, &est_response,
force); &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))
{
status = 0;
}
err:
lib->credmgr->remove_set(lib->credmgr, &creds->set);
creds->destroy(creds);
chunk_free(&est_response); 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) { command_register((command_t) {
estca, 'e', "estca", estca, 'e', "estca",
"get CA certificate[s] from a EST server", "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"}, {"help", 'h', 0, "show usage information"},
{"url", 'u', 1, "URL of the SCEP server"}, {"url", 'u', 1, "URL of the SCEP server"},
{"cacert", 'C', 1, "TLS CA certificate"},
{"caout", 'c', 1, "CA certificate [template]"}, {"caout", 'c', 1, "CA certificate [template]"},
{"outform", 'f', 1, "encoding of stored certificates, default: der"}, {"outform", 'f', 1, "encoding of stored certificates, default: der"},
{"force", 'F', 0, "force overwrite of existing files"}, {"force", 'F', 0, "force overwrite of existing files"},
+32 -30
View File
@@ -39,7 +39,7 @@ static int scep()
{ {
char *arg, *url = NULL, *file = NULL, *dn = NULL, *error = NULL; char *arg, *url = NULL, *file = NULL, *dn = NULL, *error = NULL;
char *ca_enc_file = NULL, *ca_sig_file = 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; cred_encoding_type_t form = CERT_ASN1_DER;
chunk_t scep_response = chunk_empty; chunk_t scep_response = chunk_empty;
chunk_t challenge_password = chunk_empty; chunk_t challenge_password = chunk_empty;
@@ -95,33 +95,33 @@ static int scep()
{ {
switch (command_getopt(&arg)) switch (command_getopt(&arg))
{ {
case 'h': case 'h': /* --help */
goto usage; goto usage;
case 'u': case 'u': /* --url */
url = arg; url = arg;
continue; continue;
case 'i': case 'i': /* --in */
file = arg; file = arg;
continue; continue;
case 'd': case 'd': /* --dn */
dn = arg; dn = arg;
continue; continue;
case 'a': case 'a': /* --san */
san->insert_last(san, identification_create_from_string(arg)); san->insert_last(san, identification_create_from_string(arg));
continue; continue;
case 'P': case 'P': /* --profile */
cert_type = chunk_create(arg, strlen(arg)); cert_type = chunk_create(arg, strlen(arg));
continue; continue;
case 'p': case 'p': /* --password */
challenge_password = chunk_create(arg, strlen(arg)); challenge_password = chunk_create(arg, strlen(arg));
continue; continue;
case 'e': case 'e': /* --cacert-enc */
ca_enc_file = arg; ca_enc_file = arg;
continue; continue;
case 's': case 's': /* --cacert-sig */
ca_sig_file = arg; ca_sig_file = arg;
continue; continue;
case 'c': case 'C': /* --cacert */
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
BUILD_FROM_FILE, arg, BUILD_END); BUILD_FROM_FILE, arg, BUILD_END);
if (!cert) if (!cert)
@@ -131,13 +131,13 @@ static int scep()
} }
creds->add_cert(creds, TRUE, cert); creds->add_cert(creds, TRUE, cert);
continue; continue;
case 'o': case 'c': /* --cert */
old_cert_file = arg; client_cert_file = arg;
continue; continue;
case 'k': case 'k': /* --key */
old_key_file = arg; client_key_file = arg;
continue; continue;
case 'C': case 'E': /* --cipher */
if (strcaseeq(arg, "des3")) if (strcaseeq(arg, "des3"))
{ {
cipher = ENCR_3DES; cipher = ENCR_3DES;
@@ -154,14 +154,14 @@ static int scep()
goto usage; goto usage;
} }
continue; continue;
case 'g': case 'g': /* --digest */
if (!enum_from_name(hash_algorithm_short_names, arg, &digest_alg)) if (!enum_from_name(hash_algorithm_short_names, arg, &digest_alg))
{ {
error = "invalid --digest type"; error = "invalid --digest type";
goto usage; goto usage;
} }
continue; continue;
case 'R': case 'R': /* --rsa-padding */
if (streq(arg, "pss")) if (streq(arg, "pss"))
{ {
pss = TRUE; pss = TRUE;
@@ -186,7 +186,7 @@ static int scep()
case 'm': /* --maxpolltime */ case 'm': /* --maxpolltime */
max_poll_time = atoi(optarg); max_poll_time = atoi(optarg);
continue; continue;
case 'f': case 'f': /* --form */
if (!get_form(arg, &form, CRED_CERTIFICATE)) if (!get_form(arg, &form, CRED_CERTIFICATE))
{ {
error = "invalid certificate output format"; error = "invalid certificate output format";
@@ -220,7 +220,7 @@ static int scep()
goto usage; goto usage;
} }
if (old_cert_file && !old_key_file) if (client_cert_file && !client_key_file)
{ {
error = "--oldkey is required if --oldcert is set"; error = "--oldkey is required if --oldcert is set";
goto usage; goto usage;
@@ -374,7 +374,7 @@ static int scep()
} }
DBG1(DBG_APP, "transaction ID: %.*s", (int)transID.len, transID.ptr); DBG1(DBG_APP, "transaction ID: %.*s", (int)transID.len, transID.ptr);
if (old_cert_file) if (client_cert_file)
{ {
/* check support of Renewal Operation */ /* check support of Renewal Operation */
if (!(caps_flags & SCEP_CAPS_RENEWAL)) if (!(caps_flags & SCEP_CAPS_RENEWAL))
@@ -390,19 +390,21 @@ static int scep()
/* load old client certificate */ /* load old client certificate */
x509_signer = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, 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) 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; goto err;
} }
/* load old RSA private key */ /* load old RSA private key */
priv_signer = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, 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) 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; goto err;
} }
} }
@@ -456,7 +458,7 @@ static int scep()
DBG1(DBG_APP, "could not load signature cacert file '%s'", ca_sig_file); DBG1(DBG_APP, "could not load signature cacert file '%s'", ca_sig_file);
goto end; 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 */ /* build pkcs7 request */
pkcs7_req = scep_build_request(pkcs10_encoding, transID, scep_msg_type, 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"}, {"password", 'p', 1, "challengePassword to include in cert request"},
{"cacert-enc", 'e', 1, "CA certificate for encryption"}, {"cacert-enc", 'e', 1, "CA certificate for encryption"},
{"cacert-sig", 's', 1, "CA certificate for signature verification"}, {"cacert-sig", 's', 1, "CA certificate for signature verification"},
{"cacert", 'c', 1, "Additional CA certificates"}, {"cacert", 'C', 1, "Additional CA certificates"},
{"oldcert", 'o', 1, "Old certificate about to be renewed"}, {"cert", 'c', 1, "Old certificate about to be renewed"},
{"oldkey", 'k', 1, "Old RSA private key about to be replaced"}, {"key", 'k', 1, "Old RSA private key about to be replaced"},
{"cipher", 'C', 1, "encryption cipher, default: aes"}, {"cipher", 'E', 1, "encryption cipher, default: aes"},
{"digest", 'g', 1, "digest for signature creation, default: sha256"}, {"digest", 'g', 1, "digest for signature creation, default: sha256"},
{"rsa-padding", 'R', 1, "padding for RSA signatures, default: pkcs1"}, {"rsa-padding", 'R', 1, "padding for RSA signatures, default: pkcs1"},
{"interval", 't', 1, "poll interval, default: 60s"}, {"interval", 't', 1, "poll interval, default: 60s"},
+6 -6
View File
@@ -37,24 +37,24 @@ static int scepca()
{ {
switch (command_getopt(&arg)) switch (command_getopt(&arg))
{ {
case 'h': case 'h': /* --help */
return command_usage(NULL); return command_usage(NULL);
case 'u': case 'u': /* --url */
url = arg; url = arg;
continue; continue;
case 'c': case 'c': /* --caout */
caout = arg; caout = arg;
continue; continue;
case 'r': case 'r': /* --raout */
raout = arg; raout = arg;
continue; continue;
case 'f': case 'f': /* --form */
if (!get_form(arg, &form, CRED_CERTIFICATE)) if (!get_form(arg, &form, CRED_CERTIFICATE))
{ {
return command_usage("invalid certificate output format"); return command_usage("invalid certificate output format");
} }
continue; continue;
case 'F': case 'F': /* --force */
force = TRUE; force = TRUE;
continue; continue;
case EOF: case EOF:
-112
View File
@@ -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;
}
-40
View File
@@ -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 */
+12 -4
View File
@@ -16,8 +16,6 @@
#define _GNU_SOURCE /* for asprintf() */ #define _GNU_SOURCE /* for asprintf() */
#include <stdio.h> #include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h> #include <unistd.h>
#include <errno.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, len = asprintf(&http_header,
"GET %s/.well-known/est/%s HTTP/1.1\r\n" "GET %s/.well-known/est/%s HTTP/1.1\r\n"
"Host: %s\r\n" "Host: %s\r\n"
"%s", "%s"
"\r\n",
this->http_path, operations[op], this->http_host, http_auth); this->http_path, operations[op], this->http_host, http_auth);
if (len > 0) 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; *content_len = 0;
*base64 = FALSE; *base64 = FALSE;
if (retry_after)
{
*retry_after = 0;
}
/* Process HTTP protocol version and HTTP status code */ /* Process HTTP protocol version and HTTP status code */
if (!fetchline(in, &line) || !extract_token(&version, ' ', &line) || if (!fetchline(in, &line) || !extract_token(&version, ' ', &line) ||
!match("HTTP/1.1", &version) || sscanf(line.ptr, "%d", http_code) != 1) !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 */ /* initialize output variables */
*out = chunk_empty; *out = chunk_empty;
*http_code = 0; *http_code = 0;
*retry_after = 0;
if (retry_after)
{
*retry_after = 0;
}
http = build_http_request(this, op, in); http = build_http_request(this, op, in);
+12 -2
View File
@@ -22,8 +22,6 @@
#ifndef EST_TLS_H_ #ifndef EST_TLS_H_
#define EST_TLS_H_ #define EST_TLS_H_
#include "est.h"
#include <library.h> #include <library.h>
#include <credentials/certificates/certificate.h> #include <credentials/certificates/certificate.h>
@@ -32,6 +30,18 @@
typedef struct est_tls_t est_tls_t; 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 * TLS Interface for sending and receiving HTTPS messages
*/ */
+54 -16
View 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 digest_buf[HASH_SIZE_SHA256];
char base64_buf[HASH_SIZE_SHA256]; char base64_buf[HASH_SIZE_SHA256];
chunk_t cert_digest = {digest_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; bool success = FALSE;
DBG1(DBG_APP, "%s cert \"%Y\"", cert_type_label[cert_type], DBG1(DBG_APP, "%s cert \"%Y\"", cert_type_label[cert_type],
cert->get_subject(cert)); 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)) 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; enumerator_t *enumerator;
pkcs7_t *pkcs7 = (pkcs7_t*)container; pkcs7_t *pkcs7 = (pkcs7_t*)container;
certificate_t *cert_found;
enumerator_t *certs;
bool trusted;
enumerator = pkcs7->create_cert_enumerator(pkcs7); enumerator = pkcs7->create_cert_enumerator(pkcs7);
while (enumerator->enumerate(enumerator, &cert)) while (enumerator->enumerate(enumerator, &cert))
{ {
trusted = FALSE;
cert_type = get_pki_cert_type(cert); cert_type = get_pki_cert_type(cert);
if (cert_type == CERT_TYPE_ROOT_CA) 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)) if (!print_cert_info(cert, cert_type))
{ {
goto end; 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, if (build_pathname(&path, cert_type, cert_type_count, caout,
raout, form)) raout, form))
{ {
written = write_cert(cert, cert_type, FALSE, path, form, written = write_cert(cert, cert_type, trusted, path, form,
force); force);
free(path); free(path);
} }
@@ -344,24 +375,31 @@ bool pki_cert_extract_cacerts(chunk_t data, char *caout, char *raout,
while (enumerator->enumerate(enumerator, &cert)) while (enumerator->enumerate(enumerator, &cert))
{ {
written = FALSE; written = FALSE;
trusted = FALSE;
cert_type = get_pki_cert_type(cert); cert_type = get_pki_cert_type(cert);
if (cert_type != CERT_TYPE_ROOT_CA) if (cert_type != CERT_TYPE_ROOT_CA)
{ {
certificate_t *cert_found = NULL;
enumerator_t *certs;
bool trusted;
if (!print_cert_info(cert, cert_type)) if (!print_cert_info(cert, cert_type))
{ {
break; break;
} }
/* establish trust relativ to root CA */ /* establish trust relative to root CA */
certs = lib->credmgr->create_trusted_enumerator(lib->credmgr, certs = lib->credmgr->create_trusted_enumerator(lib->credmgr,
KEY_ANY, cert->get_subject(cert), FALSE); KEY_ANY, cert->get_subject(cert), FALSE);
trusted = certs->enumerate(certs, &cert_found, NULL) && while (certs->enumerate(certs, &cert_found, NULL))
(cert_found == cert); {
if (cert->equals(cert, cert_found))
{
trusted = TRUE;
break;
}
else
{
DBG1(DBG_APP, "non-matching TLS Sub CA of same name");
}
}
certs->destroy(certs); certs->destroy(certs);
cert_type_count[cert_type]++; 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)) 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); serial = x509->get_serial(x509);
DBG1(DBG_APP, " serial: %#B", &serial); 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); certs->destroy(certs);
valid = cert->get_validity(cert, NULL, &from, &until); 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)", "valid from %T until %T (currently %svalid)",
trusted ? "" : "not ", &from, FALSE, &until, FALSE, trusted ? "" : "not ", &from, FALSE, &until, FALSE,
valid ? "" : "not "); valid ? "" : "not ");