]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
pki: Get CA certs via EST (RFC 7030)
authorAndreas Steffen <andreas.steffen@strongswan.org>
Sat, 13 Aug 2022 10:31:44 +0000 (12:31 +0200)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Wed, 24 Aug 2022 18:46:44 +0000 (20:46 +0200)
src/pki/Makefile.am
src/pki/command.h
src/pki/commands/estca.c [new file with mode: 0644]
src/pki/commands/scep.c
src/pki/commands/scepca.c
src/pki/est/est.c [new file with mode: 0644]
src/pki/est/est.h [new file with mode: 0644]
src/pki/pki_cert.c [new file with mode: 0644]
src/pki/pki_cert.h [new file with mode: 0644]
src/pki/scep/scep.c
src/pki/scep/scep.h

index 172cfcdc3c60f2f188bc4141cb98f9e8a50f4b61..3c40a4f04126adf894efe7adc5e91a465c596cd9 100644 (file)
@@ -2,9 +2,10 @@ SUBDIRS = man
 
 bin_PROGRAMS = pki
 
-pki_SOURCES = pki.c pki.h command.c command.h \
+pki_SOURCES = pki.c pki.h pki_cert.c pki_cert.h command.c command.h \
        commands/acert.c \
        commands/dn.c \
+       commands/estca.c \
        commands/gen.c \
        commands/issue.c \
        commands/keyid.c \
@@ -18,6 +19,7 @@ pki_SOURCES = pki.c pki.h command.c command.h \
        commands/self.c \
        commands/signcrl.c \
        commands/verify.c \
+       est/est.h est/est.c \
        scep/scep.h scep/scep.c
 
 pki_LDADD = \
index 876a64b99c217fa4732afb53dd94e5920cb83e25..af6587fe93bb72a2ac399c05a960abaa742bc401 100644 (file)
@@ -25,7 +25,7 @@
 /**
  * Maximum number of commands (+1).
  */
-#define MAX_COMMANDS 16
+#define MAX_COMMANDS 17
 
 /**
  * Maximum number of options in a command (+3)
diff --git a/src/pki/commands/estca.c b/src/pki/commands/estca.c
new file mode 100644 (file)
index 0000000..02161dd
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#include "pki.h"
+#include "pki_cert.h"
+#include "est/est.h"
+
+#include <credentials/containers/pkcs7.h>
+#include <credentials/certificates/certificate.h>
+#include <credentials/sets/mem_cred.h>
+
+/**
+ * Get CA certificate[s] from an EST server (RFC 7030)
+ */
+static int estca()
+{
+       cred_encoding_type_t form = CERT_ASN1_DER;
+       chunk_t est_response = chunk_empty;
+       char *arg, *url = NULL, *caout = NULL;
+       bool force = FALSE, success;
+       u_int http_code = 0;
+
+       while (TRUE)
+       {
+               switch (command_getopt(&arg))
+               {
+                       case 'h':
+                               return command_usage(NULL);
+                       case 'u':
+                               url = arg;
+                               continue;
+                       case 'c':
+                               caout = arg;
+                               continue;
+                       case 'f':
+                               if (!get_form(arg, &form, CRED_CERTIFICATE))
+                               {
+                                       return command_usage("invalid certificate output format");
+                               }
+                               continue;
+                       case 'F':
+                               force = TRUE;
+                               continue;
+                       case EOF:
+                               break;
+                       default:
+                               return command_usage("invalid --estca option");
+               }
+               break;
+       }
+
+       if (!url)
+       {
+               return command_usage("--url is required");
+       }
+
+       if (!est_https_request(url, EST_CACERTS, FALSE, chunk_empty, &est_response,
+                                                  &http_code))
+       {
+               DBG1(DBG_APP, "did not receive a valid EST response: HTTP %u", http_code);
+               return 1;
+       }
+       success = pki_cert_extract_cacerts(est_response, caout, NULL, TRUE, form,
+                                                                          force);
+       chunk_free(&est_response);
+
+       return success ? 0 : 1;
+}
+
+/**
+ * Register the command.
+ */
+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]"},
+               {
+                       {"help",    'h', 0, "show usage information"},
+                       {"url",     'u', 1, "URL of the SCEP server"},
+                       {"caout",   'c', 1, "CA certificate [template]"},
+                       {"outform", 'f', 1, "encoding of stored certificates, default: der"},
+                       {"force",   'F', 0, "force overwrite of existing files"},
+               }
+       });
+}
index 03703e76a36b02956620a058f574d38de6cba89e..97a6fc285ec9a3bbf7ffde9a452dcffb040c733f 100644 (file)
  * for more details.
  */
 
-#define _GNU_SOURCE
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <unistd.h>
-#include <stdio.h>
 #include <errno.h>
 #include <time.h>
 
 #include "pki.h"
+#include "pki_cert.h"
 #include "scep/scep.h"
 
 #include <credentials/certificates/certificate.h>
@@ -50,7 +47,6 @@ static int scep()
        chunk_t serialNumber = chunk_empty;
        chunk_t transID = chunk_empty;
        chunk_t pkcs10_encoding = chunk_empty;
-       chunk_t cert_encoding = chunk_empty;
        chunk_t pkcs7_req = chunk_empty;
        chunk_t certPoll = chunk_empty;
        chunk_t issuerAndSubject = chunk_empty;
@@ -65,19 +61,17 @@ static int scep()
        certificate_t *x509_ca_sig = NULL, *x509_ca_enc = NULL;
        identification_t *subject = NULL, *issuer = NULL;
        container_t *container = NULL;
-       pkcs7_t *pkcs7;
        mem_cred_t *creds = NULL;
        scep_msg_t scep_msg_type;
        scep_attributes_t attrs = empty_scep_attributes;
        uint32_t caps_flags;
        u_int poll_interval = DEFAULT_POLL_INTERVAL;
-       u_int max_poll_time = 0;
-       u_int poll_start = 0;
+       u_int max_poll_time = 0, poll_start = 0;
+       u_int http_code = 0;
        time_t notBefore, notAfter;
        linked_list_t *san;
-       enumerator_t *enumerator;
        int status = 1;
-       bool ok, http_post = FALSE, stored = FALSE;
+       bool ok, http_post = FALSE;
 
        bool pss = lib->settings->get_bool(lib->settings,
                                                                "%s.rsa_pss", FALSE, lib->ns);
@@ -258,7 +252,7 @@ static int scep()
                set_file_mode(stdin, CERT_ASN1_DER);
                if (!chunk_from_fd(0, &chunk))
                {
-                       DBG1(DBG_APP, "reading private key failed: %s\n", strerror(errno));
+                       DBG1(DBG_APP, "reading private key failed: %s", strerror(errno));
                        goto end;
                }
                private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
@@ -273,10 +267,10 @@ static int scep()
        public = private->get_public_key(private);
 
        /* Request capabilities from SCEP server */
-       if (!scep_http_request(url, chunk_empty, SCEP_GET_CA_CAPS, FALSE,
-                                                  &scep_response))
+       if (!scep_http_request(url, SCEP_GET_CA_CAPS, FALSE, chunk_empty,
+                                                  &scep_response, &http_code))
        {
-               DBG1(DBG_APP, "did not receive a valid scep response");
+               DBG1(DBG_APP, "did not receive a valid scep response: HTTP %u", http_code);
                goto end;
        }
        caps_flags = scep_parse_caps(scep_response);
@@ -467,10 +461,10 @@ static int scep()
                goto end;
        }
 
-       if (!scep_http_request(url, pkcs7_req, SCEP_PKI_OPERATION, http_post,
-                                                  &scep_response))
+       if (!scep_http_request(url, SCEP_PKI_OPERATION, http_post, pkcs7_req,
+                                                  &scep_response, &http_code))
        {
-               DBG1(DBG_APP, "did not receive a valid SCEP response");
+               DBG1(DBG_APP, "did not receive a valid SCEP response: HTTP %u", http_code);
                goto end;
        }
 
@@ -526,10 +520,11 @@ static int scep()
                        DBG1(DBG_APP, "failed to build SCEP certPoll request");
                        goto end;
                }
-               if (!scep_http_request(url, certPoll, SCEP_PKI_OPERATION, http_post,
-                                                          &scep_response))
+               if (!scep_http_request(url, SCEP_PKI_OPERATION, http_post, certPoll,
+                                                          &scep_response, &http_code))
                {
-                       DBG1(DBG_APP, "did not receive a valid SCEP response");
+                       DBG1(DBG_APP, "did not receive a valid SCEP response: HTTP %u",
+                                                  http_code);
                        goto end;
                }
                if (!scep_parse_response(scep_response, transID, &container, &attrs))
@@ -570,79 +565,11 @@ static int scep()
                goto end;
        }
        container->destroy(container);
+       container = NULL;
 
-       /* parse signed-data container */
-       container = lib->creds->create(lib->creds,
-                                                                  CRED_CONTAINER, CONTAINER_PKCS7,
-                                                                  BUILD_BLOB_ASN1_DER, data,
-                                                                  BUILD_END);
+       status = pki_cert_extract_cert(data, form, creds) ? 0 : 1;
        chunk_free(&data);
 
-       if (!container)
-       {
-               DBG1(DBG_APP, "could not parse signed-data");
-               goto end;
-       }
-       /* no need to verify the signed-data container, the signature does NOT
-        * cover the contained certificates */
-
-       /* store the end entity certificate */
-       pkcs7 = (pkcs7_t*)container;
-       enumerator = pkcs7->create_cert_enumerator(pkcs7);
-
-       while (enumerator->enumerate(enumerator, &cert))
-       {
-               x509_t *x509 = (x509_t*)cert;
-               enumerator_t *certs;
-               time_t from, until;
-               bool trusted, valid;
-
-               if (!(x509->get_flags(x509) & X509_CA))
-               {
-                       DBG1(DBG_APP, "certificate \"%Y\"", cert->get_subject(cert));
-
-                       if (stored)
-                       {
-                               DBG1(DBG_APP, "multiple certs received, only first stored");
-                               continue;
-                       }
-
-                       /* establish trust relativ to root CA */
-                       creds->add_cert(creds, FALSE, cert->get_ref(cert));
-                       certs = lib->credmgr->create_trusted_enumerator(lib->credmgr,
-                                                               KEY_RSA, cert->get_subject(cert), FALSE);
-                       trusted = certs->enumerate(certs, &cert, NULL);
-                       valid = cert->get_validity(cert, NULL, &from, &until);
-
-                       DBG1(DBG_APP, "certificate is %strusted, valid from %T until %T "
-                                                 "(currently %svalid)",
-                                                 trusted ? "" : "not ", &from, FALSE, &until, FALSE,
-                                                 valid ? "" : "not ");
-
-                       certs->destroy(certs);
-
-                       if (!cert->get_encoding(cert, form, &cert_encoding))
-                       {
-                               DBG1(DBG_APP, "encoding certificate failed");
-                               break;
-                       }
-
-                       set_file_mode(stdout, form);
-                       if (fwrite(cert_encoding.ptr, cert_encoding.len, 1, stdout) != 1)
-                       {
-                               DBG1(DBG_APP, "writing certificate failed");
-                               break;
-                       }
-                       else
-                       {
-                               stored = TRUE;
-                               status = 0;
-                       }
-               }
-       }
-       enumerator->destroy(enumerator);
-
-
 end:
        lib->credmgr->remove_set(lib->credmgr, &creds->set);
        creds->destroy(creds);
@@ -661,7 +588,6 @@ end:
        chunk_free(&serialNumber);
        chunk_free(&transID);
        chunk_free(&pkcs10_encoding);
-       chunk_free(&cert_encoding);
        chunk_free(&pkcs7_req);
        chunk_free(&certPoll);
        chunk_free(&issuerAndSubject);
index 24271f78bc402ac53dafec52b4977ef267037b9d..32df55de724d7ea0085fc590c8133d54c8d0de9b 100644 (file)
  * for more details.
  */
 
-#define _GNU_SOURCE
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-
 #include "pki.h"
+#include "pki_cert.h"
 #include "scep/scep.h"
 
 #include <credentials/certificates/certificate.h>
-#include <credentials/certificates/x509.h>
-#include <credentials/sets/mem_cred.h>
-
-
-typedef enum {
-       CERT_TYPE_ROOT_CA,
-       CERT_TYPE_SUB_CA,
-       CERT_TYPE_RA
-} cert_type_t;
-
-static char *cert_type_label[] = { "Root CA", "Sub CA", "RA" };
-
-/**
- * Determine certificate type based on X.509 certificate flags
- */
-static cert_type_t get_cert_type(certificate_t *cert)
-{
-       x509_t *x509;
-       x509_flag_t flags;
-
-       x509 = (x509_t*)cert;
-       flags = x509->get_flags(x509);
-
-       if (flags & X509_CA)
-       {
-               if (flags & X509_SELF_SIGNED)
-               {
-                       return CERT_TYPE_ROOT_CA;
-               }
-               else
-               {
-                       return CERT_TYPE_SUB_CA;
-               }
-       }
-       else
-       {
-               return CERT_TYPE_RA;
-       }
-}
-
-/**
- * Output cert type, subject as well as SHA256 and SHA1 fingerprints
- */
-static bool print_cert_info(certificate_t *cert, cert_type_t cert_type)
-{
-       hasher_t *hasher = NULL;
-       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;
-       bool success = FALSE;
-
-       DBG1(DBG_APP, "%s cert \"%Y\"", cert_type_label[cert_type],
-                                                                       cert->get_subject(cert));
-
-       if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoding))
-       {
-               DBG1(DBG_APP, "could not get certificate encoding");
-               return FALSE;
-       }
-
-       /* SHA256 certificate digest */
-       hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA256);
-       if (!hasher)
-       {
-               DBG1(DBG_APP, "could not create SHA256 hasher");
-               goto end;
-       }
-       if (!hasher->get_hash(hasher, encoding, digest_buf))
-       {
-               DBG1(DBG_APP, "could not compute SHA256 hash");
-               goto end;
-       }
-       hasher->destroy(hasher);
-
-       DBG1(DBG_APP, "  SHA256: %#B", &cert_digest);
-
-       /* SHA1 certificate digest */
-       hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
-       if (!hasher)
-       {
-               DBG1(DBG_APP, "could not create SHA1 hasher");
-               goto end;
-       }
-       if (!hasher->get_hash(hasher, encoding, digest_buf))
-       {
-               DBG1(DBG_APP, "could not compute SHA1 hash");
-               goto end;
-       }
-       cert_digest.len = HASH_SIZE_SHA1;
-       cert_id = chunk_to_base64(cert_digest, base64_buf);
-
-       DBG1(DBG_APP, "  SHA1  : %#B (%.*s)", &cert_digest,
-                                                                                  cert_id.len-1, cert_id.ptr);
-       success = TRUE;
-
-end:
-       DESTROY_IF(hasher);
-       chunk_free(&encoding);
-
-       return success;
-}
-
-static bool build_pathname(char **path, cert_type_t cert_type, int *cert_type_count,
-                                                  char *caout, char *raout, cred_encoding_type_t form)
-{
-       char *basename, *extension, *dot, *suffix;
-       int  count, len;
-       bool number;
-
-       basename = caout;
-       extension = "";
-       suffix = (form == CERT_ASN1_DER) ? "der" : "pem";
-
-       count = cert_type_count[cert_type];
-       number = count > 1;
-
-       switch (cert_type)
-       {
-               default:
-               case CERT_TYPE_ROOT_CA:
-                       if (count > 1)
-                       {
-                               extension = "-root";
-                       }
-                       break;
-               case CERT_TYPE_SUB_CA:
-                       number = TRUE;
-                       break;
-               case CERT_TYPE_RA:
-                       if (raout)
-                       {
-                               basename = raout;
-                       }
-                       else
-                       {
-                               extension = "-ra";
-                       }
-                       break;
-       }
-
-       /* skip if no path is defined */
-       if (!basename)
-       {
-               *path = NULL;
-               return TRUE;
-       }
-
-       /* check for a file suffix */
-       dot = strrchr(basename, '.');
-       len = dot ? (dot - basename) : strlen(basename);
-       if (dot && (dot[1] != '\0'))
-       {
-               suffix = dot + 1;
-       }
-
-       if (number)
-       {
-               return asprintf(path, "%.*s%s-%d.%s", len, basename, extension,
-                                               count, suffix) > 0;
-       }
-       else
-       {
-               return asprintf(path, "%.*s%s.%s", len, basename, extension, suffix) > 0;
-       }
-}
-
-/**
- * Writo CA/RA certificate to file in DER or PEM format
- */
-static bool write_cert(certificate_t *cert, cert_type_t cert_type, bool trusted,
-                                          char *path, cred_encoding_type_t form, bool force)
-{
-       chunk_t encoding = chunk_empty;
-       time_t until;
-       bool written, valid;
-
-       if (path)
-       {
-               if (!cert->get_encoding(cert, form, &encoding))
-               {
-                       DBG1(DBG_APP, "could not get certificate encoding");
-                       return FALSE;
-               }
-
-               written = chunk_write(encoding, path, 0022, force);
-               chunk_free(&encoding);
-
-               if (!written)
-               {
-                       DBG1(DBG_APP, "could not write cert file '%s': %s",
-                                path, strerror(errno));
-                       return FALSE;
-               }
-       }
-       valid = cert->get_validity(cert, NULL, NULL, &until);
-       DBG1(DBG_APP, "%s cert is %strusted, %s %T, %s'%s'",
-                cert_type_label[cert_type], trusted ? "" : "un",
-                valid ? "valid until" : "invalid since", &until, FALSE,
-                path ? "written to " : "", path ? path : "not written");
-
-       return TRUE;
-}
 
 /**
  * Get CA certificate[s] from a SCEP server (RFC 8894)
@@ -238,15 +29,9 @@ static int scepca()
 {
        cred_encoding_type_t form = CERT_ASN1_DER;
        chunk_t scep_response = chunk_empty;
-       mem_cred_t *creds = NULL;
-       certificate_t *cert;
-       cert_type_t cert_type;
-       pkcs7_t *pkcs7 = NULL;
-       bool force = FALSE, written = FALSE;
-       char *arg, *url = NULL, *caout = NULL, *raout = NULL, *path = NULL;
-       int status = 1;
-
-       int cert_type_count[] = { 0, 0, 0 };
+       char *arg, *url = NULL, *caout = NULL, *raout = NULL;
+       bool force = FALSE, success;
+       u_int http_code = 0;
 
        while (TRUE)
        {
@@ -285,133 +70,18 @@ static int scepca()
                return command_usage("--url is required");
        }
 
-       if (!scep_http_request(url, chunk_empty, SCEP_GET_CA_CERT, FALSE,
-                                                  &scep_response))
+       if (!scep_http_request(url, SCEP_GET_CA_CERT, FALSE, chunk_empty,
+                                                  &scep_response, &http_code))
        {
-               DBG1(DBG_APP, "did not receive a valid scep response");
+               DBG1(DBG_APP, "did not receive a valid SCEP response: HTTP %u", http_code);
                return 1;
        }
 
-       creds = mem_cred_create();
-       lib->credmgr->add_set(lib->credmgr, &creds->set);
-
-       pkcs7 = lib->creds->create(lib->creds, CRED_CONTAINER, CONTAINER_PKCS7,
-                                                       BUILD_BLOB_ASN1_DER, scep_response, BUILD_END);
-       if (!pkcs7)
-       {       /* no PKCS#7 encoded CA+RA certificates, assume single root CA cert */
-
-               cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
-                                                                 BUILD_BLOB, scep_response, BUILD_END);
-               if (!cert)
-               {
-                       DBG1(DBG_APP, "could not parse single CA certificate");
-                       goto end;
-               }
-               cert_type = get_cert_type(cert);
-               cert_type_count[cert_type]++;
-
-               if (print_cert_info(cert, cert_type) &&
-                       build_pathname(&path, cert_type, cert_type_count, caout, raout, form))
-               {
-                       written = write_cert(cert, cert_type, FALSE, path, form, force);
-               }
-       }
-       else
-       {
-               enumerator_t *enumerator;
-
-               enumerator = pkcs7->create_cert_enumerator(pkcs7);
-               while (enumerator->enumerate(enumerator, &cert))
-               {
-                       cert_type = get_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;
-                               }
-                               if (build_pathname(&path, cert_type, cert_type_count,
-                                                                  caout, raout, form))
-                               {
-                                       written = write_cert(cert, cert_type, FALSE, path, form, force);
-                                       free(path);
-                               }
-                               if (!written)
-                               {
-                                       break;
-                               }
-                       }
-                       else
-                       {
-                               /* trust relative to root CA will be established in round 2 */
-                               creds->add_cert(creds, FALSE, cert->get_ref(cert));
-                       }
-               }
-               enumerator->destroy(enumerator);
-
-               if (!written)
-               {
-                       goto end;
-               }
-
-               enumerator = pkcs7->create_cert_enumerator(pkcs7);
-               while (enumerator->enumerate(enumerator, &cert))
-               {
-                       written = FALSE;
-
-                       cert_type = get_cert_type(cert);
-                       if (cert_type != CERT_TYPE_ROOT_CA)
-                       {
-                               enumerator_t *certs;
-                               bool trusted;
-
-                               if (!print_cert_info(cert, cert_type))
-                               {
-                                       break;
-                               }
-
-                               /* establish trust relativ to root CA */
-                               certs = lib->credmgr->create_trusted_enumerator(lib->credmgr,
-                                                                       KEY_RSA, cert->get_subject(cert), FALSE);
-                               trusted = certs->enumerate(certs, &cert, NULL);
-                               certs->destroy(certs);
-
-                               cert_type_count[cert_type]++;
-
-                               if (build_pathname(&path, cert_type, cert_type_count,
-                                                                   caout, raout, form))
-                               {
-                                       written = write_cert(cert, cert_type, trusted, path, form, force);
-                                       free(path);
-                               }
-                               if (!written)
-                               {
-                                       break;
-                               }
-                       }
-               }
-               enumerator->destroy(enumerator);
-       }
-       status = written ? 0 : 1;
-
-end:
-       /* cleanup */
-       lib->credmgr->remove_set(lib->credmgr, &creds->set);
-       creds->destroy(creds);
-       free(scep_response.ptr);
-       if (pkcs7)
-       {
-               container_t *container = &pkcs7->container;
-
-               container->destroy(container);
-       }
+       success = pki_cert_extract_cacerts(scep_response, caout, raout, TRUE, form,
+                                                                          force);
+       chunk_free(&scep_response);
 
-       return status;
+       return success ? 0 : 1;
 }
 
 /**
diff --git a/src/pki/est/est.c b/src/pki/est/est.c
new file mode 100644 (file)
index 0000000..c24bf5c
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..3d9bdd3
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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 */
diff --git a/src/pki/pki_cert.c b/src/pki/pki_cert.c
new file mode 100644 (file)
index 0000000..d3c49f2
--- /dev/null
@@ -0,0 +1,472 @@
+/*
+ * 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 <errno.h>
+
+#include "pki.h"
+#include "pki_cert.h"
+
+#include <credentials/certificates/certificate.h>
+#include <credentials/certificates/x509.h>
+#include <credentials/containers/pkcs7.h>
+
+/*
+ * Certificate types
+ */
+typedef enum {
+    CERT_TYPE_ROOT_CA,
+    CERT_TYPE_SUB_CA,
+    CERT_TYPE_RA
+} pki_cert_type_t;
+
+static char *cert_type_label[] = { "Root CA", "Sub CA", "RA" };
+
+/**
+ * Determine certificate type based on X.509 certificate flags
+ */
+static pki_cert_type_t get_pki_cert_type(certificate_t *cert)
+{
+       x509_t *x509;
+       x509_flag_t flags;
+
+       x509 = (x509_t*)cert;
+       flags = x509->get_flags(x509);
+
+       if (flags & X509_CA)
+       {
+               if (flags & X509_SELF_SIGNED)
+               {
+                       return CERT_TYPE_ROOT_CA;
+               }
+               else
+               {
+                       return CERT_TYPE_SUB_CA;
+               }
+       }
+       else
+       {
+               return CERT_TYPE_RA;
+       }
+}
+
+/**
+ * Output cert type, subject as well as SHA256 and SHA1 fingerprints
+ */
+static bool print_cert_info(certificate_t *cert, pki_cert_type_t cert_type)
+{
+       hasher_t *hasher = NULL;
+       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;
+       bool success = FALSE;
+
+       DBG1(DBG_APP, "%s cert \"%Y\"", cert_type_label[cert_type],
+                                                                       cert->get_subject(cert));
+
+       if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoding))
+       {
+               DBG1(DBG_APP, "could not get certificate encoding");
+               return FALSE;
+       }
+
+       /* SHA256 certificate digest */
+       hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA256);
+       if (!hasher)
+       {
+               DBG1(DBG_APP, "could not create SHA256 hasher");
+               goto end;
+       }
+       if (!hasher->get_hash(hasher, encoding, digest_buf))
+       {
+               DBG1(DBG_APP, "could not compute SHA256 hash");
+               goto end;
+       }
+       hasher->destroy(hasher);
+
+       DBG1(DBG_APP, "  SHA256: %#B", &cert_digest);
+
+       /* SHA1 certificate digest */
+       hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+       if (!hasher)
+       {
+               DBG1(DBG_APP, "could not create SHA1 hasher");
+               goto end;
+       }
+       if (!hasher->get_hash(hasher, encoding, digest_buf))
+       {
+               DBG1(DBG_APP, "could not compute SHA1 hash");
+               goto end;
+       }
+       cert_digest.len = HASH_SIZE_SHA1;
+       cert_id = chunk_to_base64(cert_digest, base64_buf);
+
+       DBG1(DBG_APP, "  SHA1  : %#B (%.*s)", &cert_digest,
+                                                                                  cert_id.len-1, cert_id.ptr);
+       success = TRUE;
+
+end:
+       DESTROY_IF(hasher);
+       chunk_free(&encoding);
+
+       return success;
+}
+
+/**
+ * Build a CA or RA pathname
+ */
+static bool build_pathname(char **path, pki_cert_type_t cert_type,
+                                                  int *cert_type_count, char *caout, char *raout,
+                                                  cred_encoding_type_t form)
+{
+       char *basename, *extension, *dot, *suffix;
+       int  count, len;
+       bool number;
+
+       basename = caout;
+       extension = "";
+       suffix = (form == CERT_ASN1_DER) ? "der" : "pem";
+
+       count = cert_type_count[cert_type];
+       number = count > 1;
+
+       switch (cert_type)
+       {
+               default:
+               case CERT_TYPE_ROOT_CA:
+                       if (count > 1)
+                       {
+                               extension = "-root";
+                       }
+                       break;
+               case CERT_TYPE_SUB_CA:
+                       number = TRUE;
+                       break;
+               case CERT_TYPE_RA:
+                       if (raout)
+                       {
+                               basename = raout;
+                       }
+                       else
+                       {
+                               extension = "-ra";
+                       }
+                       break;
+       }
+
+       /* skip if no path is defined */
+       if (!basename)
+       {
+               *path = NULL;
+               return TRUE;
+       }
+
+       /* check for a file suffix */
+       dot = strrchr(basename, '.');
+       len = dot ? (dot - basename) : strlen(basename);
+       if (dot && (dot[1] != '\0'))
+       {
+               suffix = dot + 1;
+       }
+
+       if (number)
+       {
+               return asprintf(path, "%.*s%s-%d.%s", len, basename, extension,
+                                               count, suffix) > 0;
+       }
+       else
+       {
+               return asprintf(path, "%.*s%s.%s", len, basename, extension, suffix) > 0;
+       }
+}
+
+/**
+ * Write CA/RA certificate to file in DER or PEM format
+ */
+static bool write_cert(certificate_t *cert, pki_cert_type_t cert_type,
+                                          bool trusted, char *path, cred_encoding_type_t form,
+                                          bool force)
+{
+       chunk_t encoding = chunk_empty;
+       time_t until;
+       bool written, valid;
+
+       if (path)
+       {
+               if (!cert->get_encoding(cert, form, &encoding))
+               {
+                       DBG1(DBG_APP, "could not get certificate encoding");
+                       return FALSE;
+               }
+
+               written = chunk_write(encoding, path, 0022, force);
+               chunk_free(&encoding);
+
+               if (!written)
+               {
+                       DBG1(DBG_APP, "could not write cert file '%s': %s",
+                                path, strerror(errno));
+                       return FALSE;
+               }
+       }
+       else if (form == CERT_PEM)
+       {
+               if (!cert->get_encoding(cert, form, &encoding))
+               {
+                       DBG1(DBG_APP, "could not get certificate encoding");
+                       return FALSE;
+               }
+               printf("%.*s", encoding.len, encoding.ptr);
+               chunk_free(&encoding);
+               path = "stdout";
+       }
+
+       valid = cert->get_validity(cert, NULL, NULL, &until);
+       DBG1(DBG_APP, "%s cert is %strusted, %s %T, %s'%s'",
+                cert_type_label[cert_type], trusted ? "" : "un",
+                valid ? "valid until" : "invalid since", &until, FALSE,
+                path ? "written to " : "", path ? path : "not written");
+
+       return TRUE;
+}
+
+/**
+ * Extract X.509 CA [and SCEP RA] certificates from PKCS#7 container,
+ * check trust as well as validity and write to files
+ */
+bool pki_cert_extract_cacerts(chunk_t data, char *caout, char *raout,
+                                                         bool is_scep, cred_encoding_type_t form,
+                                                         bool force)
+{
+       container_t *container;
+       mem_cred_t *creds = NULL;
+       certificate_t *cert;
+       pki_cert_type_t cert_type;
+       bool written = FALSE, success = FALSE;
+       char *path;
+
+       int cert_type_count[] = { 0, 0, 0 };
+
+       creds = mem_cred_create();
+       lib->credmgr->add_set(lib->credmgr, &creds->set);
+
+       container = lib->creds->create(lib->creds, CRED_CONTAINER, CONTAINER_PKCS7,
+                                                                  BUILD_BLOB_ASN1_DER, data, BUILD_END);
+       if (!container)
+       {
+               if (is_scep)
+               {
+                       /* no PKCS#7 encoded certificates, assume single root CA cert */
+                       cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
+                                                                         BUILD_BLOB, data, BUILD_END);
+                       if (!cert)
+                       {
+                               DBG1(DBG_APP, "could not parse single CA certificate");
+                               goto end;
+                       }
+                       cert_type = get_pki_cert_type(cert);
+                       cert_type_count[cert_type]++;
+
+                       if (print_cert_info(cert, cert_type) &&
+                               build_pathname(&path, cert_type, cert_type_count, caout, raout,
+                                                          form))
+                       {
+                               written = write_cert(cert, cert_type, FALSE, path, form, force);
+                       }
+               }
+               else
+               {
+                       DBG1(DBG_APP, "did not receive a valid pkcs7 container");
+                       goto end;
+               }
+       }
+       else
+       {
+               enumerator_t *enumerator;
+               pkcs7_t *pkcs7 = (pkcs7_t*)container;
+
+               enumerator = pkcs7->create_cert_enumerator(pkcs7);
+               while (enumerator->enumerate(enumerator, &cert))
+               {
+                       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;
+                               }
+                               if (build_pathname(&path, cert_type, cert_type_count, caout,
+                                                                  raout, form))
+                               {
+                                       written = write_cert(cert, cert_type, FALSE, path, form,
+                                                                                force);
+                                       free(path);
+                               }
+                               if (!written)
+                               {
+                                       break;
+                               }
+                       }
+                       else
+                       {
+                               /* trust relative to root CA will be established in round 2 */
+                               creds->add_cert(creds, FALSE, cert->get_ref(cert));
+                       }
+               }
+               enumerator->destroy(enumerator);
+
+               if (!written)
+               {
+                       goto end;
+               }
+
+               enumerator = pkcs7->create_cert_enumerator(pkcs7);
+               while (enumerator->enumerate(enumerator, &cert))
+               {
+                       written = FALSE;
+
+                       cert_type = get_pki_cert_type(cert);
+                       if (cert_type != CERT_TYPE_ROOT_CA)
+                       {
+                               enumerator_t *certs;
+                               bool trusted;
+
+                               if (!print_cert_info(cert, cert_type))
+                               {
+                                       break;
+                               }
+
+                               /* establish trust relativ to root CA */
+                               certs = lib->credmgr->create_trusted_enumerator(lib->credmgr,
+                                                                       KEY_ANY, cert->get_subject(cert), FALSE);
+                               trusted = certs->enumerate(certs, &cert, NULL);
+                               certs->destroy(certs);
+
+                               cert_type_count[cert_type]++;
+
+                               if (build_pathname(&path, cert_type, cert_type_count, caout,
+                                                                  raout, form))
+                               {
+                                       written = write_cert(cert, cert_type, trusted, path, form,
+                                                                                force);
+                                       free(path);
+                               }
+                               if (!written)
+                               {
+                                       break;
+                               }
+                       }
+               }
+               enumerator->destroy(enumerator);
+       }
+       success = TRUE;
+
+end:
+       /* cleanup */
+       lib->credmgr->remove_set(lib->credmgr, &creds->set);
+       creds->destroy(creds);
+       DESTROY_IF(container);
+
+       return success;
+}
+
+/**
+ * Extract an X.509 client certificates from PKCS#7 container
+ * check trust as well as validity and write to stdout
+ */
+bool pki_cert_extract_cert(chunk_t data, cred_encoding_type_t form,
+                           mem_cred_t *creds)
+{
+       pkcs7_t *pkcs7;
+       container_t *container;
+       certificate_t *cert;
+       chunk_t cert_encoding = chunk_empty;
+       enumerator_t *enumerator;
+       bool stored = FALSE;
+
+       /* parse pkcs7 signed-data container */
+       container = lib->creds->create(lib->creds, CRED_CONTAINER, CONTAINER_PKCS7,
+                                                                  BUILD_BLOB_ASN1_DER, data, BUILD_END);
+       if (!container)
+       {
+               DBG1(DBG_APP, "could not parse pkcs7 signed-data container");
+               return FALSE;
+       }
+
+       /* store the end entity certificate */
+       pkcs7 = (pkcs7_t*)container;
+       enumerator = pkcs7->create_cert_enumerator(pkcs7);
+
+       while (enumerator->enumerate(enumerator, &cert))
+       {
+               x509_t *x509 = (x509_t*)cert;
+               enumerator_t *certs;
+               time_t from, until;
+               bool trusted, valid;
+
+               if (!(x509->get_flags(x509) & X509_CA))
+               {
+                       DBG1(DBG_APP, "certificate \"%Y\"", cert->get_subject(cert));
+
+                       if (stored)
+                       {
+                               DBG1(DBG_APP, "multiple certs received, only first stored");
+                               continue;
+                       }
+
+                       /* establish trust relativ to root CA */
+                       creds->add_cert(creds, FALSE, cert->get_ref(cert));
+                       certs = lib->credmgr->create_trusted_enumerator(lib->credmgr,
+                                                               KEY_ANY, cert->get_subject(cert), FALSE);
+                       trusted = certs->enumerate(certs, &cert, NULL);
+                       valid = cert->get_validity(cert, NULL, &from, &until);
+
+                       DBG1(DBG_APP, "certificate is %strusted, valid from %T until %T "
+                                                 "(currently %svalid)",
+                                                 trusted ? "" : "not ", &from, FALSE, &until, FALSE,
+                                                 valid ? "" : "not ");
+
+                       certs->destroy(certs);
+
+                       if (!cert->get_encoding(cert, form, &cert_encoding))
+                       {
+                               DBG1(DBG_APP, "encoding certificate failed");
+                               break;
+                       }
+
+                       set_file_mode(stdout, form);
+                       stored = fwrite(cert_encoding.ptr, cert_encoding.len, 1, stdout) == 1;
+                       chunk_free(&cert_encoding);
+
+                       if (!stored)
+                       {
+                               DBG1(DBG_APP, "writing certificate failed");
+                               break;
+                       }
+               }
+       }
+       enumerator->destroy(enumerator);
+       container->destroy(container);
+
+       return stored;
+}
diff --git a/src/pki/pki_cert.h b/src/pki/pki_cert.h
new file mode 100644 (file)
index 0000000..853436c
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup pki_cert pki_cert
+ * @{ @ingroup pki
+ */
+
+#ifndef _PKI_CERT
+#define _PKI_CERT
+
+#include <library.h>
+#include <credentials/sets/mem_cred.h>
+
+/**
+ * Extract X.509 CA [and SCEP RA] certificates from PKCS#7 container
+ * check trust as well as validity and write to files
+ */
+bool pki_cert_extract_cacerts(chunk_t data, char *caout, char *raout,
+                              bool is_scep, cred_encoding_type_t form,
+                              bool force);
+
+/**
+ * Extract an X.509 client certificates from PKCS#7 container
+ * check trust as well as validity and write to stdout
+ */
+bool pki_cert_extract_cert(chunk_t data, cred_encoding_type_t form,
+                           mem_cred_t *creds);
+
+#endif /** PKI_CERT_H_ @}*/
index eaa5b53233bf8ddd3a0dcc39c478e2b1fda2e754..fbc6e1cfab893d64bd96648d09a14ed2b998b434 100644 (file)
@@ -333,8 +333,8 @@ static char* escape_http_request(chunk_t req)
 /**
  * Send a SCEP request via HTTP and wait for a response
  */
-bool scep_http_request(const char *url, chunk_t msg, scep_op_t op,
-                                          bool http_post, chunk_t *response)
+bool scep_http_request(const char *url, scep_op_t op, bool http_post,
+                                          chunk_t data, chunk_t *response, u_int *http_code)
 {
        int len;
        status_t status;
@@ -356,6 +356,7 @@ bool scep_http_request(const char *url, chunk_t msg, scep_op_t op,
 
        /* initialize response */
        *response = chunk_empty;
+       *http_code = 0;
 
        operation = operations[op];
        switch (op)
@@ -371,23 +372,23 @@ bool scep_http_request(const char *url, chunk_t msg, scep_op_t op,
 
                                status = lib->fetcher->fetch(lib->fetcher, complete_url, response,
                                                                                 FETCH_TIMEOUT, http_timeout,
-                                                                                FETCH_REQUEST_DATA, msg,
+                                                                                FETCH_REQUEST_DATA, data,
                                                                                 FETCH_REQUEST_TYPE, "",
                                                                                 FETCH_REQUEST_HEADER, "Expect:",
                                                                                 FETCH_SOURCEIP, srcip,
+                                                                                FETCH_RESPONSE_CODE, http_code,
                                                                                 FETCH_END);
                        }
                        else /* HTTP_GET */
                        {
-                               char *escaped_req = escape_http_request(msg);
+                               char *msg = escape_http_request(data);
 
                                /* form complete url */
-                               len = strlen(url) + 20 + strlen(operation) +
-                                         strlen(escaped_req) + 1;
+                               len = strlen(url) + 20 + strlen(operation) + strlen(msg) + 1;
                                complete_url = malloc(len);
                                snprintf(complete_url, len, "%s?operation=%s&message=%s"
-                                               , url, operation, escaped_req);
-                               free(escaped_req);
+                                               , url, operation, msg);
+                               free(msg);
 
                                status = lib->fetcher->fetch(lib->fetcher, complete_url, response,
                                                                                 FETCH_TIMEOUT, http_timeout,
@@ -395,6 +396,7 @@ bool scep_http_request(const char *url, chunk_t msg, scep_op_t op,
                                                                                 FETCH_REQUEST_HEADER, "Host:",
                                                                                 FETCH_REQUEST_HEADER, "Accept:",
                                                                                 FETCH_SOURCEIP, srcip,
+                                                                                FETCH_RESPONSE_CODE, http_code,
                                                                                 FETCH_END);
                        }
                        break;
@@ -409,6 +411,7 @@ bool scep_http_request(const char *url, chunk_t msg, scep_op_t op,
                        status = lib->fetcher->fetch(lib->fetcher, complete_url, response,
                                                                         FETCH_TIMEOUT, http_timeout,
                                                                         FETCH_SOURCEIP, srcip,
+                                                                        FETCH_RESPONSE_CODE, http_code,
                                                                         FETCH_END);
                }
        }
index ead203505b33d1a135626b64d0f888472701ed50..b24cb622a43fa556f4819605c1ff425d08476237 100644 (file)
@@ -101,8 +101,11 @@ chunk_t scep_build_request(chunk_t data, chunk_t transID, scep_msg_t msg,
                                                size_t key_size, certificate_t *signer_cert,
                                                hash_algorithm_t digest_alg, private_key_t *private_key);
 
-bool scep_http_request(const char *url, chunk_t msg, scep_op_t op, bool use_post,
-                                          chunk_t *response);
+/**
+ * Send a SCEP request via HTTP and wait for a response
+ */
+bool scep_http_request(const char *url, scep_op_t op, bool http_post,
+                                          chunk_t data, chunk_t *response, u_int *http_code);
 
 bool scep_parse_response(chunk_t response, chunk_t transID, container_t **out,
                                                 scep_attributes_t *attrs);