aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac10
-rwxr-xr-xscripts/test.sh2
-rw-r--r--src/libstrongswan/Makefile.am7
-rw-r--r--src/libstrongswan/plugins/winhttp/Makefile.am18
-rw-r--r--src/libstrongswan/plugins/winhttp/winhttp_fetcher.c396
-rw-r--r--src/libstrongswan/plugins/winhttp/winhttp_fetcher.h46
-rw-r--r--src/libstrongswan/plugins/winhttp/winhttp_plugin.c74
-rw-r--r--src/libstrongswan/plugins/winhttp/winhttp_plugin.h42
-rw-r--r--src/libstrongswan/tests/suites/test_fetch_http.c2
-rw-r--r--src/pki/commands/verify.c134
10 files changed, 678 insertions, 53 deletions
diff --git a/configure.ac b/configure.ac
index 736f097c1..87aa40dd9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -161,6 +161,7 @@ ARG_ENABL_SET([curl], [enable CURL fetcher plugin to fetch files via l
ARG_ENABL_SET([ldap], [enable LDAP fetching plugin to fetch files via libldap. Requires openLDAP.])
ARG_ENABL_SET([soup], [enable soup fetcher plugin to fetch from HTTP via libsoup. Requires libsoup.])
ARG_ENABL_SET([unbound], [enable UNBOUND resolver plugin to perform DNS queries via libunbound. Requires libldns and libunbound.])
+ARG_ENABL_SET([winhttp], [enable WinHTTP based HTTP/HTTPS fetching plugin.])
# database plugins
ARG_ENABL_SET([mysql], [enable MySQL database support. Requires libmysqlclient_r.])
ARG_ENABL_SET([sqlite], [enable SQLite database support. Requires libsqlite3.])
@@ -1159,8 +1160,9 @@ s_plugins=
t_plugins=
ADD_PLUGIN([test-vectors], [s charon scepclient pki])
-ADD_PLUGIN([curl], [s charon scepclient scripts nm cmd])
-ADD_PLUGIN([soup], [s charon scripts nm cmd])
+ADD_PLUGIN([curl], [s charon scepclient pki scripts nm cmd])
+ADD_PLUGIN([winhttp], [s charon pki scripts])
+ADD_PLUGIN([soup], [s charon pki scripts nm cmd])
ADD_PLUGIN([unbound], [s charon scripts])
ADD_PLUGIN([ldap], [s charon scepclient scripts nm cmd])
ADD_PLUGIN([mysql], [s charon pool manager medsrv attest])
@@ -1178,7 +1180,7 @@ ADD_PLUGIN([rdrand], [s charon scepclient pki scripts medsrv attes
ADD_PLUGIN([random], [s charon scepclient pki scripts medsrv attest nm cmd aikgen])
ADD_PLUGIN([nonce], [s charon nm cmd aikgen])
ADD_PLUGIN([x509], [s charon scepclient pki scripts attest nm cmd aikgen])
-ADD_PLUGIN([revocation], [s charon nm cmd])
+ADD_PLUGIN([revocation], [s charon pki nm cmd])
ADD_PLUGIN([constraints], [s charon nm cmd])
ADD_PLUGIN([acert], [s charon])
ADD_PLUGIN([pubkey], [s charon cmd aikgen])
@@ -1305,6 +1307,7 @@ AC_SUBST(t_plugins)
# -----------------------
AM_CONDITIONAL(USE_TEST_VECTORS, test x$test_vectors = xtrue)
AM_CONDITIONAL(USE_CURL, test x$curl = xtrue)
+AM_CONDITIONAL(USE_WINHTTP, test x$winhttp = xtrue)
AM_CONDITIONAL(USE_UNBOUND, test x$unbound = xtrue)
AM_CONDITIONAL(USE_SOUP, test x$soup = xtrue)
AM_CONDITIONAL(USE_LDAP, test x$ldap = xtrue)
@@ -1571,6 +1574,7 @@ AC_CONFIG_FILES([
src/libstrongswan/plugins/sshkey/Makefile
src/libstrongswan/plugins/pem/Makefile
src/libstrongswan/plugins/curl/Makefile
+ src/libstrongswan/plugins/winhttp/Makefile
src/libstrongswan/plugins/unbound/Makefile
src/libstrongswan/plugins/soup/Makefile
src/libstrongswan/plugins/ldap/Makefile
diff --git a/scripts/test.sh b/scripts/test.sh
index 103b41103..7c1dc89ac 100755
--- a/scripts/test.sh
+++ b/scripts/test.sh
@@ -35,7 +35,7 @@ all)
--disable-lock-profiler --disable-maemo --disable-padlock
--disable-osx-attr --disable-tkm --disable-uci --disable-aikgen
--disable-svc --disable-dbghelp-backtraces --disable-socket-win
- --disable-kernel-wfp --disable-kernel-iph"
+ --disable-kernel-wfp --disable-kernel-iph --disable-winhttp"
if test "$LEAK_DETECTIVE" = "yes"; then
# libgcrypt can't be deinitialized
CONFIG="$CONFIG --disable-gcrypt"
diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am
index 2602a9eba..9a08825fd 100644
--- a/src/libstrongswan/Makefile.am
+++ b/src/libstrongswan/Makefile.am
@@ -425,6 +425,13 @@ if MONOLITHIC
endif
endif
+if USE_WINHTTP
+ SUBDIRS += plugins/winhttp
+if MONOLITHIC
+ libstrongswan_la_LIBADD += plugins/winhttp/libstrongswan-winhttp.la
+endif
+endif
+
if USE_UNBOUND
SUBDIRS += plugins/unbound
if MONOLITHIC
diff --git a/src/libstrongswan/plugins/winhttp/Makefile.am b/src/libstrongswan/plugins/winhttp/Makefile.am
new file mode 100644
index 000000000..f6b00a71e
--- /dev/null
+++ b/src/libstrongswan/plugins/winhttp/Makefile.am
@@ -0,0 +1,18 @@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/libstrongswan
+
+AM_CFLAGS = \
+ $(PLUGIN_CFLAGS)
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-winhttp.la
+else
+plugin_LTLIBRARIES = libstrongswan-winhttp.la
+endif
+
+libstrongswan_winhttp_la_SOURCES = \
+ winhttp_fetcher.c winhttp_fetcher.h \
+ winhttp_plugin.c winhttp_plugin.h
+
+libstrongswan_winhttp_la_LDFLAGS = -module -avoid-version
+libstrongswan_winhttp_la_LIBADD = -lwinhttp
diff --git a/src/libstrongswan/plugins/winhttp/winhttp_fetcher.c b/src/libstrongswan/plugins/winhttp/winhttp_fetcher.c
new file mode 100644
index 000000000..4a822bd9e
--- /dev/null
+++ b/src/libstrongswan/plugins/winhttp/winhttp_fetcher.c
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec 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 <winsock2.h>
+#include <windows.h>
+#include <winhttp.h>
+
+#include "winhttp_fetcher.h"
+
+#include <library.h>
+
+/**
+ * Timeout for DNS resolution, in ms
+ */
+#define RESOLVE_TIMEOUT 5000
+
+/**
+ * Timeout for TCP connect, in ms
+ */
+#define CONNECT_TIMEOUT 10000
+
+typedef struct private_winhttp_fetcher_t private_winhttp_fetcher_t;
+
+/**
+ * Private data of a winhttp_fetcher_t.
+ */
+struct private_winhttp_fetcher_t {
+
+ /**
+ * Public interface
+ */
+ winhttp_fetcher_t public;
+
+ /**
+ * WinHTTP session handle
+ */
+ HINTERNET session;
+
+ /**
+ * POST request data
+ */
+ chunk_t request;
+
+ /**
+ * HTTP version string to use
+ */
+ LPWSTR version;
+
+ /**
+ * Optional HTTP headers, as allocated LPWSTR
+ */
+ linked_list_t *headers;
+
+ /**
+ * Callback function
+ */
+ fetcher_callback_t cb;
+
+ /**
+ * Timeout for operations, in ms
+ */
+ u_long timeout;
+
+ /**
+ * User pointer to store HTTP status code to
+ */
+ u_int *result;
+};
+
+/**
+ * Configure and send the HTTP request
+ */
+static bool send_request(private_winhttp_fetcher_t *this, HINTERNET request)
+{
+ WCHAR headers[512] = L"";
+ LPWSTR hdr;
+
+ /* Set timeout. By default, send/receive does not time out */
+ if (!WinHttpSetTimeouts(request, RESOLVE_TIMEOUT, CONNECT_TIMEOUT,
+ this->timeout, this->timeout))
+ {
+ DBG1(DBG_LIB, "opening HTTP request failed: %u", GetLastError());
+ return FALSE;
+ }
+ while (this->headers->remove_first(this->headers, (void**)&hdr) == SUCCESS)
+ {
+ wcsncat(headers, hdr, countof(headers) - wcslen(headers) - 1);
+ if (this->headers->get_count(this->headers))
+ {
+ wcsncat(headers, L"\r\n", countof(headers) - wcslen(headers) - 1);
+ }
+ free(hdr);
+ }
+ if (!WinHttpSendRequest(request, headers, wcslen(headers),
+ this->request.ptr, this->request.len, this->request.len, 0))
+ {
+ DBG1(DBG_LIB, "sending HTTP request failed: %u", GetLastError());
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Read back result and invoke receive callback
+ */
+static bool read_result(private_winhttp_fetcher_t *this, HINTERNET request,
+ void *user)
+{
+ DWORD received;
+ char buf[1024];
+ u_int32_t code;
+ DWORD codelen = sizeof(code);
+
+ if (!WinHttpReceiveResponse(request, NULL))
+ {
+ DBG1(DBG_LIB, "reading HTTP response header failed: %u", GetLastError());
+ return FALSE;
+ }
+ if (!WinHttpQueryHeaders(request,
+ WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
+ NULL, &code, &codelen, NULL))
+ {
+ DBG1(DBG_LIB, "reading HTTP status code failed: %u", GetLastError());
+ return FALSE;
+ }
+ if (this->result)
+ {
+ *this->result = code;
+ }
+ if (code < 200 || code >= 300)
+ { /* non-successful HTTP status code */
+ if (!this->result)
+ {
+ DBG1(DBG_LIB, "HTTP request failed with status %u", code);
+ }
+ return FALSE;
+ }
+ if (this->cb == fetcher_default_callback)
+ {
+ *(chunk_t*)user = chunk_empty;
+ }
+ while (TRUE)
+ {
+ if (!WinHttpReadData(request, buf, sizeof(buf), &received))
+ {
+ DBG1(DBG_LIB, "reading HTTP response failed: %u", GetLastError());
+ return FALSE;
+ }
+ if (received == 0)
+ {
+ /* end of response */
+ break;
+ }
+ if (!this->cb(user, chunk_create(buf, received)))
+ {
+ DBG1(DBG_LIB, "processing response failed or cancelled");
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**
+ * Parse an uri to wide string host and path, optionally set flags and port
+ */
+static bool parse_uri(private_winhttp_fetcher_t *this, char *uri,
+ LPWSTR host, int hostlen, LPWSTR path, int pathlen,
+ LPWSTR user, int userlen, LPWSTR pass, int passlen,
+ DWORD *flags, INTERNET_PORT *port)
+{
+ WCHAR wuri[512], extra[256];
+ URL_COMPONENTS comps = {
+ .dwStructSize = sizeof(URL_COMPONENTS),
+ .lpszHostName = host,
+ .dwHostNameLength = hostlen,
+ .lpszUrlPath = path,
+ .dwUrlPathLength = pathlen,
+ .lpszUserName = user,
+ .dwUserNameLength = userlen,
+ .lpszPassword = pass,
+ .dwPasswordLength = passlen,
+ .lpszExtraInfo = extra,
+ .dwExtraInfoLength = countof(extra),
+ };
+
+ if (!MultiByteToWideChar(CP_THREAD_ACP, 0, uri, -1, wuri, countof(wuri)))
+ {
+ DBG1(DBG_LIB, "converting URI failed: %u", GetLastError());
+ return FALSE;
+ }
+ if (!WinHttpCrackUrl(wuri, 0, ICU_ESCAPE, &comps))
+ {
+ DBG1(DBG_LIB, "cracking URI failed: %u", GetLastError());
+ return FALSE;
+ }
+ if (comps.nScheme == INTERNET_SCHEME_HTTPS)
+ {
+ *flags |= WINHTTP_FLAG_SECURE;
+ }
+ if (comps.dwExtraInfoLength)
+ {
+ wcsncat(path, extra, countof(path) - comps.dwUrlPathLength - 1);
+ }
+ if (comps.nPort)
+ {
+ *port = comps.nPort;
+ }
+ return TRUE;
+}
+
+/**
+ * Set credentials for basic authentication, if given
+ */
+static bool set_credentials(private_winhttp_fetcher_t *this,
+ HINTERNET *request, LPWSTR user, LPWSTR pass)
+{
+ if (!wcslen(user) && !wcslen(pass))
+ { /* skip */
+ return TRUE;
+ }
+ return WinHttpSetCredentials(request, WINHTTP_AUTH_TARGET_SERVER,
+ WINHTTP_AUTH_SCHEME_BASIC, user, pass, NULL);
+}
+
+METHOD(fetcher_t, fetch, status_t,
+ private_winhttp_fetcher_t *this, char *uri, void *userdata)
+{
+ INTERNET_PORT port = INTERNET_DEFAULT_PORT;
+ status_t status = FAILED;
+ DWORD flags = 0;
+ HINTERNET connection, request;
+ WCHAR host[256], path[512], user[256], pass[256], *method;
+
+ if (this->request.len)
+ {
+ method = L"POST";
+ }
+ else
+ {
+ method = L"GET";
+ }
+
+ if (this->result)
+ { /* zero-initialize for early failures */
+ *this->result = 0;
+ }
+
+ if (parse_uri(this, uri, host, countof(host), path, countof(path),
+ user, countof(user), pass, countof(pass), &flags, &port))
+ {
+ connection = WinHttpConnect(this->session, host, port, 0);
+ if (connection)
+ {
+ request = WinHttpOpenRequest(connection, method, path, this->version,
+ WINHTTP_NO_REFERER,
+ WINHTTP_DEFAULT_ACCEPT_TYPES, flags);
+ if (request)
+ {
+ if (set_credentials(this, request, user, pass) &&
+ send_request(this, request) &&
+ read_result(this, request, userdata))
+ {
+ status = SUCCESS;
+ }
+ WinHttpCloseHandle(request);
+ }
+ else
+ {
+ DBG1(DBG_LIB, "opening request failed: %u", GetLastError());
+ }
+ WinHttpCloseHandle(connect);
+ }
+ else
+ {
+ DBG1(DBG_LIB, "connection failed: %u", GetLastError());
+ }
+ }
+ return status;
+}
+
+/**
+ * Append an header as wide string
+ */
+static bool append_header(private_winhttp_fetcher_t *this, char *name)
+{
+ int len;
+ LPWSTR buf;
+
+ len = MultiByteToWideChar(CP_THREAD_ACP, 0, name, -1, NULL, 0);
+ if (!len)
+ {
+ return FALSE;
+ }
+ buf = calloc(len, sizeof(WCHAR));
+ if (!MultiByteToWideChar(CP_THREAD_ACP, 0, name, -1, buf, len))
+ {
+ free(buf);
+ return FALSE;
+ }
+ this->headers->insert_last(this->headers, buf);
+ return TRUE;
+}
+
+METHOD(fetcher_t, set_option, bool,
+ private_winhttp_fetcher_t *this, fetcher_option_t option, ...)
+{
+ bool supported = TRUE;
+ char buf[128];
+ va_list args;
+
+ va_start(args, option);
+ switch (option)
+ {
+ case FETCH_REQUEST_DATA:
+ this->request = va_arg(args, chunk_t);
+ break;
+ case FETCH_REQUEST_TYPE:
+ snprintf(buf, sizeof(buf), "Content-Type: %s", va_arg(args, char*));
+ supported = append_header(this, buf);
+ break;
+ case FETCH_REQUEST_HEADER:
+ supported = append_header(this, va_arg(args, char*));
+ break;
+ case FETCH_HTTP_VERSION_1_0:
+ this->version = L"HTTP/1.0";
+ break;
+ case FETCH_TIMEOUT:
+ this->timeout = va_arg(args, u_int) * 1000;
+ break;
+ case FETCH_CALLBACK:
+ this->cb = va_arg(args, fetcher_callback_t);
+ break;
+ case FETCH_RESPONSE_CODE:
+ this->result = va_arg(args, u_int*);
+ break;
+ case FETCH_SOURCEIP:
+ /* not supported, FALL */
+ default:
+ supported = FALSE;
+ break;
+ }
+ va_end(args);
+ return supported;
+}
+
+METHOD(fetcher_t, destroy, void,
+ private_winhttp_fetcher_t *this)
+{
+ WinHttpCloseHandle(this->session);
+ this->headers->destroy_function(this->headers, free);
+ free(this);
+}
+/*
+ * Described in header.
+ */
+winhttp_fetcher_t *winhttp_fetcher_create()
+{
+ private_winhttp_fetcher_t *this;
+
+ INIT(this,
+ .public = {
+ .interface = {
+ .fetch = _fetch,
+ .set_option = _set_option,
+ .destroy = _destroy,
+ },
+ },
+ .version = L"HTTP/1.1",
+ .cb = fetcher_default_callback,
+ .headers = linked_list_create(),
+ .session = WinHttpOpen(L"strongSwan WinHTTP fetcher",
+ WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
+ WINHTTP_NO_PROXY_NAME,
+ WINHTTP_NO_PROXY_BYPASS, 0),
+ );
+
+ if (!this->session)
+ {
+ free(this);
+ return NULL;
+ }
+
+ return &this->public;
+}
diff --git a/src/libstrongswan/plugins/winhttp/winhttp_fetcher.h b/src/libstrongswan/plugins/winhttp/winhttp_fetcher.h
new file mode 100644
index 000000000..6129eb889
--- /dev/null
+++ b/src/libstrongswan/plugins/winhttp/winhttp_fetcher.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec 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 winhttp_fetcher winhttp_fetcher
+ * @{ @ingroup winhttp_p
+ */
+
+#ifndef WINHTTP_FETCHER_H_
+#define WINHTTP_FETCHER_H_
+
+#include <library.h>
+
+typedef struct winhttp_fetcher_t winhttp_fetcher_t;
+
+/**
+ * Fetcher implementation using Microsofts WinHTTP.
+ */
+struct winhttp_fetcher_t {
+
+ /**
+ * Implements fetcher interface.
+ */
+ fetcher_t interface;
+};
+
+/**
+ * Create a winhttp_fetcher instance
+ *
+ * @return WinHTTP based fetcher
+ */
+winhttp_fetcher_t *winhttp_fetcher_create();
+
+#endif /** WINHTTP_FETCHER_H_ @}*/
diff --git a/src/libstrongswan/plugins/winhttp/winhttp_plugin.c b/src/libstrongswan/plugins/winhttp/winhttp_plugin.c
new file mode 100644
index 000000000..8b67ff58b
--- /dev/null
+++ b/src/libstrongswan/plugins/winhttp/winhttp_plugin.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec 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 "winhttp_plugin.h"
+#include "winhttp_fetcher.h"
+
+typedef struct private_winhttp_plugin_t private_winhttp_plugin_t;
+
+/**
+ * Private data of winhttp_plugin
+ */
+struct private_winhttp_plugin_t {
+
+ /**
+ * Public functions
+ */
+ winhttp_plugin_t public;
+};
+
+METHOD(plugin_t, get_name, char*,
+ private_winhttp_plugin_t *this)
+{
+ return "winhttp";
+}
+
+METHOD(plugin_t, get_features, int,
+ private_winhttp_plugin_t *this, plugin_feature_t *features[])
+{
+ static plugin_feature_t f[] = {
+ PLUGIN_REGISTER(FETCHER, winhttp_fetcher_create),
+ PLUGIN_PROVIDE(FETCHER, "http://"),
+ PLUGIN_PROVIDE(FETCHER, "https://"),
+ };
+ *features = f;
+ return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+ private_winhttp_plugin_t *this)
+{
+ free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *winhttp_plugin_create()
+{
+ private_winhttp_plugin_t *this;
+
+ INIT(this,
+ .public = {
+ .plugin = {
+ .get_name = _get_name,
+ .get_features = _get_features,
+ .destroy = _destroy,
+ },
+ },
+ );
+
+ return &this->public.plugin;
+}
diff --git a/src/libstrongswan/plugins/winhttp/winhttp_plugin.h b/src/libstrongswan/plugins/winhttp/winhttp_plugin.h
new file mode 100644
index 000000000..30cd0518a
--- /dev/null
+++ b/src/libstrongswan/plugins/winhttp/winhttp_plugin.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec 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 winhttp_p winhttp
+ * @ingroup plugins
+ *
+ * @defgroup winhttp_plugin winhttp_plugin
+ * @{ @ingroup winhttp_p
+ */
+
+#ifndef WINHTTP_PLUGIN_H_
+#define WINHTTP_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct winhttp_plugin_t winhttp_plugin_t;
+
+/**
+ * Plugin implementing fetcher interface using Microsofts WinHTTP.
+ */
+struct winhttp_plugin_t {
+
+ /**
+ * Implements plugin interface.
+ */
+ plugin_t plugin;
+};
+
+#endif /** WINHTTP_PLUGIN_H_ @}*/
diff --git a/src/libstrongswan/tests/suites/test_fetch_http.c b/src/libstrongswan/tests/suites/test_fetch_http.c
index 42743c787..9f1eef2f3 100644
--- a/src/libstrongswan/tests/suites/test_fetch_http.c
+++ b/src/libstrongswan/tests/suites/test_fetch_http.c
@@ -281,7 +281,7 @@ START_TEST(test_response_code)
{
stream_service_t *service;
status_t status;
- chunk_t data;
+ chunk_t data = chunk_empty;
char uri[256];
u_int code;
diff --git a/src/pki/commands/verify.c b/src/pki/commands/verify.c
index 6cfaaf263..8cc633a95 100644
--- a/src/pki/commands/verify.c
+++ b/src/pki/commands/verify.c
@@ -19,32 +19,53 @@
#include <credentials/certificates/certificate.h>
#include <credentials/certificates/x509.h>
+#include <credentials/sets/mem_cred.h>
/**
* Verify a certificate signature
*/
static int verify()
{
- certificate_t *cert, *ca;
- char *file = NULL, *cafile = NULL;
- bool good = FALSE;
- char *arg;
+ bool trusted = FALSE, valid = FALSE, revoked = FALSE;
+ bool has_ca = FALSE, online = FALSE;
+ certificate_t *cert;
+ enumerator_t *enumerator;
+ auth_cfg_t *auth;
+ mem_cred_t *creds;
+ char *arg, *file = NULL;
+
+ creds = mem_cred_create();
+ lib->credmgr->add_set(lib->credmgr, &creds->set);
while (TRUE)
{
switch (command_getopt(&arg))
{
case 'h':
+ creds->destroy(creds);
return command_usage(NULL);
case 'i':
file = arg;
continue;
case 'c':
- cafile = arg;
+ cert = lib->creds->create(lib->creds,
+ CRED_CERTIFICATE, CERT_X509,
+ BUILD_FROM_FILE, arg, BUILD_END);
+ if (!cert)
+ {
+ fprintf(stderr, "parsing CA certificate failed\n");
+ goto end;
+ }
+ has_ca = TRUE;
+ creds->add_cert(creds, TRUE, cert);
+ continue;
+ case 'o':
+ online = TRUE;
continue;
case EOF:
break;
default:
+ creds->destroy(creds);
return command_usage("invalid --verify option");
}
break;
@@ -63,7 +84,7 @@ static int verify()
if (!chunk_from_fd(0, &chunk))
{
fprintf(stderr, "reading certificate failed: %s\n", strerror(errno));
- return 1;
+ goto end;
}
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
BUILD_BLOB, chunk, BUILD_END);
@@ -72,60 +93,76 @@ static int verify()
if (!cert)
{
fprintf(stderr, "parsing certificate failed\n");
- return 1;
- }
- if (cafile)
- {
- ca = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
- BUILD_FROM_FILE, cafile, BUILD_END);
- if (!ca)
- {
- fprintf(stderr, "parsing CA certificate failed\n");
- return 1;
- }
+ goto end;
}
- else
- {
- ca = cert;
- }
- if (cert->issued_by(cert, ca, NULL))
+ creds->add_cert(creds, !has_ca, cert);
+
+ enumerator = lib->credmgr->create_trusted_enumerator(lib->credmgr,
+ KEY_ANY, cert->get_subject(cert), online);
+ if (enumerator->enumerate(enumerator, &cert, &auth))
{
+ trusted = TRUE;
if (cert->get_validity(cert, NULL, NULL, NULL))
{
- if (cafile)
- {
- if (ca->get_validity(ca, NULL, NULL, NULL))
- {
- printf("signature good, certificates valid\n");
- good = TRUE;
- }
- else
- {
- printf("signature good, CA certificates not valid now\n");
- }
- }
- else
- {
- printf("signature good, certificate valid\n");
- good = TRUE;
- }
+ printf("certificate trusted, lifetimes valid");
+ valid = TRUE;
}
else
{
- printf("certificate not valid now\n");
+ printf("certificate trusted, but no valid lifetime");
}
+ if (online)
+ {
+ switch ((uintptr_t)auth->get(auth, AUTH_RULE_CRL_VALIDATION))
+ {
+ case VALIDATION_GOOD:
+ printf(", certificate not revoked");
+ break;
+ case VALIDATION_SKIPPED:
+ printf(", no revocation information");
+ break;
+ case VALIDATION_STALE:
+ printf(", revocation information stale");
+ break;
+ case VALIDATION_FAILED:
+ printf(", revocation checking failed");
+ break;
+ case VALIDATION_ON_HOLD:
+ printf(", certificate revocation on hold");
+ revoked = TRUE;
+ break;
+ case VALIDATION_REVOKED:
+ printf(", certificate revoked");
+ revoked = TRUE;
+ break;
+ }
+ }
+ printf("\n");
}
- else
+ enumerator->destroy(enumerator);
+
+ if (!trusted)
{
- printf("signature invalid\n");
+ printf("certificate untrusted\n");
}
- if (cafile)
+
+end:
+ lib->credmgr->remove_set(lib->credmgr, &creds->set);
+ creds->destroy(creds);
+
+ if (!trusted)
{
- ca->destroy(ca);
+ return 1;
}
- cert->destroy(cert);
-
- return good ? 0 : 2;
+ if (!valid)
+ {
+ return 2;
+ }
+ if (revoked)
+ {
+ return 3;
+ }
+ return 0;
}
/**
@@ -140,7 +177,8 @@ static void __attribute__ ((constructor))reg()
{
{"help", 'h', 0, "show usage information"},
{"in", 'i', 1, "X.509 certificate to verify, default: stdin"},
- {"cacert", 'c', 1, "CA certificate, default: verify self signed"},
+ {"cacert", 'c', 1, "CA certificate for trustchain verification"},
+ {"online", 'o', 0, "enable online CRL/OCSP revocation checking"},
}
});
}