summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjsing <jsing@openbsd.org>2014-07-12 01:20:24 +0000
committerjsing <jsing@openbsd.org>2014-07-12 01:20:24 +0000
commitb6553af360687681cf2edd0462090e9c76c35110 (patch)
treee67f9b41e3bfc17ca096f2d14258d6d7990c1baa
parentTest filtering by method (diff)
downloadwireguard-openbsd-b6553af360687681cf2edd0462090e9c76c35110.tar.xz
wireguard-openbsd-b6553af360687681cf2edd0462090e9c76c35110.zip
Initial version of libressl - a library that provides a clean, simple,
consistent and secure-by-default API for SSL clients (and soon servers). This is a long way from complete and the interface will likely change substantially - committing now so that further work can happen in the tree. Initiated by tedu@ and inspired by discussions with tedu@, beck@ and other developers.
-rw-r--r--lib/libressl/Makefile28
-rw-r--r--lib/libressl/ressl.c335
-rw-r--r--lib/libressl/ressl.h39
-rw-r--r--lib/libressl/ressl_config.c88
-rw-r--r--lib/libressl/ressl_config.h33
-rw-r--r--lib/libressl/ressl_internal.h52
-rw-r--r--lib/libressl/ressl_util.c80
-rw-r--r--lib/libressl/ressl_verify.c190
-rw-r--r--lib/libressl/shlib_version2
9 files changed, 847 insertions, 0 deletions
diff --git a/lib/libressl/Makefile b/lib/libressl/Makefile
new file mode 100644
index 00000000000..c6f4328b797
--- /dev/null
+++ b/lib/libressl/Makefile
@@ -0,0 +1,28 @@
+# $OpenBSD: Makefile,v 1.1 2014/07/12 01:20:24 jsing Exp $
+
+CFLAGS+= -Wall -Werror -Wimplicit
+CFLAGS+= -DLIBRESSL_INTERNAL
+
+LIB= ressl
+
+DPADD= ${LIBCRYPTO} ${LIBSSL}
+
+HDRS= ressl.h ressl_config.h
+
+SRCS= ressl.c \
+ ressl_config.c \
+ ressl_util.c \
+ ressl_verify.c
+
+includes:
+ @test -d ${DESTDIR}/usr/include/ressl || \
+ mkdir ${DESTDIR}/usr/include/ressl
+ @cd ${.CURDIR}; for i in $(HDRS); do \
+ j="cmp -s $$i ${DESTDIR}/usr/include/ressl/$$i || \
+ ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} -m 444 $$i\
+ ${DESTDIR}/usr/include/ressl"; \
+ echo $$j; \
+ eval "$$j"; \
+ done;
+
+.include <bsd.lib.mk>
diff --git a/lib/libressl/ressl.c b/lib/libressl/ressl.c
new file mode 100644
index 00000000000..21b7c0ead04
--- /dev/null
+++ b/lib/libressl/ressl.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <openssl/x509.h>
+
+#include <ressl/ressl.h>
+
+#include "ressl_internal.h"
+
+extern struct ressl_config ressl_config_default;
+
+int
+ressl_init(void)
+{
+ static int ressl_initialised = 0;
+
+ if (ressl_initialised)
+ return (0);
+
+ SSL_load_error_strings();
+ SSL_library_init();
+
+ ressl_initialised = 1;
+
+ return (0);
+}
+
+const char *
+ressl_error(struct ressl *ctx)
+{
+ return ctx->errmsg;
+}
+
+int
+ressl_set_error(struct ressl *ctx, char *fmt, ...)
+{
+ va_list ap;
+ int rv;
+
+ ctx->err = errno;
+ free(ctx->errmsg);
+ ctx->errmsg = NULL;
+
+ va_start(ap, fmt);
+ rv = vasprintf(&ctx->errmsg, fmt, ap);
+ va_end(ap);
+
+ return (rv);
+}
+
+struct ressl *
+ressl_new(struct ressl_config *config)
+{
+ struct ressl *ctx;
+
+ if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
+ return (NULL);
+
+ if (config == NULL)
+ config = &ressl_config_default;
+
+ ctx->config = config;
+
+ ressl_reset(ctx);
+
+ return (ctx);
+}
+
+void
+ressl_free(struct ressl *ctx)
+{
+ if (ctx == NULL)
+ return;
+ ressl_reset(ctx);
+ free(ctx);
+}
+
+void
+ressl_reset(struct ressl *ctx)
+{
+ /* SSL_free frees the SSL context. */
+ if (ctx->ssl_conn != NULL)
+ SSL_free(ctx->ssl_conn);
+ else
+ SSL_CTX_free(ctx->ssl_ctx);
+
+ ctx->ssl_conn = NULL;
+ ctx->ssl_ctx = NULL;
+
+ ctx->socket = -1;
+
+ ctx->err = 0;
+ free(ctx->errmsg);
+ ctx->errmsg = NULL;
+}
+
+int
+ressl_connect(struct ressl *ctx, const char *host, const char *port)
+{
+ struct addrinfo hints, *res, *res0;
+ const char *h = NULL, *p = NULL;
+ char *hs = NULL, *ps = NULL;
+ int rv = -1, s = -1, ret;
+
+ if (host == NULL) {
+ ressl_set_error(ctx, "host not specified");
+ goto err;
+ }
+
+ /*
+ * If port is NULL try to extract a port from the specified host,
+ * otherwise use the default.
+ */
+ if ((p = (char *)port) == NULL) {
+ ret = ressl_host_port(host, &hs, &ps);
+ if (ret == -1) {
+ ressl_set_error(ctx, "memory allocation failure");
+ goto err;
+ }
+ if (ret != 0)
+ port = HTTPS_PORT;
+ }
+
+ h = (hs != NULL) ? hs : host;
+ p = (ps != NULL) ? ps : port;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+
+ if ((ret = getaddrinfo(h, p, &hints, &res0)) != 0) {
+ ressl_set_error(ctx, "%s", gai_strerror(ret));
+ goto err;
+ }
+ for (res = res0; res; res = res->ai_next) {
+ s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (s == -1) {
+ ressl_set_error(ctx, "socket");
+ continue;
+ }
+ if (connect(s, res->ai_addr, res->ai_addrlen) == -1) {
+ ressl_set_error(ctx, "connect");
+ close(s);
+ s = -1;
+ continue;
+ }
+
+ break; /* Connected. */
+ }
+ freeaddrinfo(res0);
+
+ if (s == -1)
+ goto err;
+
+ if (ressl_connect_socket(ctx, s, h) != 0) {
+ close(s);
+ goto err;
+ }
+
+ rv = 0;
+
+err:
+
+ free(hs);
+ free(ps);
+
+ return (rv);
+}
+
+int
+ressl_connect_socket(struct ressl *ctx, int socket, const char *hostname)
+{
+ union { struct in_addr ip4; struct in6_addr ip6; } addrbuf;
+ X509 *cert = NULL;
+ int ret;
+
+ ctx->socket = socket;
+
+ /* XXX - add a configuration option to control versions. */
+ if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) {
+ ressl_set_error(ctx, "ssl context failure");
+ goto err;
+ }
+ if (ctx->config->verify) {
+ if (hostname == NULL) {
+ ressl_set_error(ctx, "server name not specified");
+ goto err;
+ }
+
+ SSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, NULL);
+
+ if (SSL_CTX_load_verify_locations(ctx->ssl_ctx,
+ ctx->config->ca_file, ctx->config->ca_path) != 1) {
+ ressl_set_error(ctx, "ssl verify setup failure");
+ goto err;
+ }
+ if (ctx->config->verify_depth >= 0)
+ SSL_CTX_set_verify_depth(ctx->ssl_ctx,
+ ctx->config->verify_depth);
+ }
+
+ if ((ctx->ssl_conn = SSL_new(ctx->ssl_ctx)) == NULL) {
+ ressl_set_error(ctx, "ssl connection failure");
+ goto err;
+ }
+ if (SSL_set_fd(ctx->ssl_conn, ctx->socket) != 1) {
+ ressl_set_error(ctx, "ssl file descriptor failure");
+ goto err;
+ }
+
+ /*
+ * RFC4366 (SNI): Literal IPv4 and IPv6 addresses are not
+ * permitted in "HostName".
+ */
+ if (hostname != NULL &&
+ inet_pton(AF_INET, hostname, &addrbuf) != 1 &&
+ inet_pton(AF_INET6, hostname, &addrbuf) != 1) {
+ if (SSL_set_tlsext_host_name(ctx->ssl_conn, hostname) == 0) {
+ ressl_set_error(ctx, "SNI host name failed");
+ goto err;
+ }
+ }
+
+ if ((ret = SSL_connect(ctx->ssl_conn)) != 1) {
+ ressl_set_error(ctx, "SSL connect failed: %i",
+ SSL_get_error(ctx->ssl_conn, ret));
+ goto err;
+ }
+
+ if (ctx->config->verify) {
+ cert = SSL_get_peer_certificate(ctx->ssl_conn);
+ if (cert == NULL) {
+ ressl_set_error(ctx, "no server certificate");
+ goto err;
+ }
+ if (ressl_check_hostname(cert, hostname) != 0) {
+ ressl_set_error(ctx, "host `%s' not present in"
+ " server certificate", hostname);
+ goto err;
+ }
+ }
+
+ return (0);
+
+err:
+ X509_free(cert);
+
+ return (-1);
+}
+
+int
+ressl_read(struct ressl *ctx, char *buf, size_t buflen, size_t *outlen)
+{
+ int ret;
+
+ /* XXX - handle async/non-blocking. */
+ ret = SSL_read(ctx->ssl_conn, buf, buflen);
+ if (ret <= 0) {
+ ret = SSL_get_error(ctx->ssl_conn, ret);
+ if (ret == SSL_ERROR_WANT_READ)
+ return (-2);
+ ressl_set_error(ctx, "read failed: %i", ret);
+ return (-1);
+ }
+ *outlen = (size_t)ret;
+ return (0);
+}
+
+int
+ressl_write(struct ressl *ctx, const char *buf, size_t buflen, size_t *outlen)
+{
+ int ret;
+
+ /* XXX - handle async/non-blocking. */
+ ret = SSL_write(ctx->ssl_conn, buf, buflen);
+ if (ret < 0) {
+ ressl_set_error(ctx, "write failed %d",
+ SSL_get_error(ctx->ssl_conn, ret));
+ return (-1);
+ }
+ *outlen = (size_t)ret;
+ return (0);
+}
+
+int
+ressl_close(struct ressl *ctx)
+{
+ /* XXX - handle case where multiple calls are required. */
+ if (ctx->ssl_conn != NULL) {
+ if (SSL_shutdown(ctx->ssl_conn) == -1) {
+ ressl_set_error(ctx, "SSL shutdown failed");
+ goto err;
+ }
+ }
+
+ if (ctx->socket != -1) {
+ if (shutdown(ctx->socket, SHUT_RDWR) != 0) {
+ ressl_set_error(ctx, "shutdown");
+ goto err;
+ }
+ if (close(ctx->socket) != 0) {
+ ressl_set_error(ctx, "close");
+ goto err;
+ }
+ ctx->socket = -1;
+ }
+
+ return (0);
+
+err:
+ return (-1);
+}
diff --git a/lib/libressl/ressl.h b/lib/libressl/ressl.h
new file mode 100644
index 00000000000..5217a69c155
--- /dev/null
+++ b/lib/libressl/ressl.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef HEADER_RESSL_H
+#define HEADER_RESSL_H
+
+#include <ressl/ressl_config.h>
+
+struct ressl;
+
+int ressl_init(void);
+
+const char *ressl_error(struct ressl *ctx);
+
+struct ressl *ressl_new(struct ressl_config *config);
+void ressl_reset(struct ressl *ctx);
+void ressl_free(struct ressl *ctx);
+
+int ressl_connect(struct ressl *ctx, const char *host, const char *port);
+int ressl_connect_socket(struct ressl *ctx, int s, const char *hostname);
+int ressl_read(struct ressl *ctx, char *buf, size_t buflen, size_t *outlen);
+int ressl_write(struct ressl *ctx, const char *buf, size_t buflen,
+ size_t *outlen);
+int ressl_close(struct ressl *ctx);
+
+#endif /* HEADER_RESSL_H */
diff --git a/lib/libressl/ressl_config.c b/lib/libressl/ressl_config.c
new file mode 100644
index 00000000000..a84de591bc1
--- /dev/null
+++ b/lib/libressl/ressl_config.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <ressl/ressl.h>
+
+#include "ressl_internal.h"
+
+/*
+ * Default configuration.
+ */
+struct ressl_config ressl_config_default = {
+ .ca_file = _PATH_SSL_CA_FILE,
+ .ca_path = NULL,
+ .ciphers = NULL,
+ .verify = 1,
+ .verify_depth = 6,
+};
+
+struct ressl_config *
+ressl_config_new(void)
+{
+ struct ressl_config *config;
+
+ if ((config = malloc(sizeof(*config))) == NULL)
+ return (NULL);
+
+ memcpy(config, &ressl_config_default, sizeof(*config));
+
+ return (config);
+}
+
+void
+ressl_config_free(struct ressl_config *config)
+{
+ free(config);
+}
+
+void
+ressl_config_ca_file(struct ressl_config *config, char *ca_file)
+{
+ config->ca_file = ca_file;
+}
+
+void
+ressl_config_ca_path(struct ressl_config *config, char *ca_path)
+{
+ config->ca_path = ca_path;
+}
+
+void
+ressl_config_ciphers(struct ressl_config *config, char *ciphers)
+{
+ config->ciphers = ciphers;
+}
+
+void
+ressl_config_insecure(struct ressl_config *config)
+{
+ config->verify = 0;
+}
+
+void
+ressl_config_secure(struct ressl_config *config)
+{
+ config->verify = 1;
+}
+
+void
+ressl_config_verify_depth(struct ressl_config *config, int verify_depth)
+{
+ config->verify_depth = verify_depth;
+}
diff --git a/lib/libressl/ressl_config.h b/lib/libressl/ressl_config.h
new file mode 100644
index 00000000000..da13d91efab
--- /dev/null
+++ b/lib/libressl/ressl_config.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef HEADER_RESSL_CONFIG_H
+#define HEADER_RESSL_CONFIG_H
+
+struct ressl_config;
+
+struct ressl_config *ressl_config_new(void);
+void ressl_config_free(struct ressl_config *config);
+
+void ressl_config_ca_file(struct ressl_config *config, char *ca_file);
+void ressl_config_ca_path(struct ressl_config *config, char *ca_path);
+void ressl_config_ciphers(struct ressl_config *config, char *ciphers);
+void ressl_config_verify_depth(struct ressl_config *config, int verify_depth);
+
+void ressl_config_insecure(struct ressl_config *config);
+void ressl_config_secure(struct ressl_config *config);
+
+#endif /* HEADER_RESSL_H */
diff --git a/lib/libressl/ressl_internal.h b/lib/libressl/ressl_internal.h
new file mode 100644
index 00000000000..f4eec10e63e
--- /dev/null
+++ b/lib/libressl/ressl_internal.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org>
+ * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef HEADER_RESSL_INTERNAL_H
+#define HEADER_RESSL_INTERNAL_H
+
+#include <openssl/ssl.h>
+
+#define HTTPS_PORT "443"
+
+#define _PATH_SSL_CA_FILE "/etc/ssl/cert.pem"
+
+struct ressl_config {
+ const char *ca_file;
+ const char *ca_path;
+ const char *ciphers;
+ const char *server_name;
+ int verify;
+ int verify_depth;
+};
+
+struct ressl {
+ struct ressl_config *config;
+
+ int err;
+ char *errmsg;
+
+ int socket;
+
+ SSL *ssl_conn;
+ SSL_CTX *ssl_ctx;
+};
+
+int ressl_check_hostname(X509 *cert, const char *host);
+int ressl_host_port(const char *hostport, char **host, char **port);
+int ressl_set_error(struct ressl *ctx, char *fmt, ...);
+
+#endif /* HEADER_RESSL_INTERNAL_H */
diff --git a/lib/libressl/ressl_util.c b/lib/libressl/ressl_util.c
new file mode 100644
index 00000000000..ee7b1edbd39
--- /dev/null
+++ b/lib/libressl/ressl_util.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+
+#include "ressl_internal.h"
+
+/*
+ * Extract the host and port from a colon separated value. For a literal IPv6
+ * address the address must be contained with square braces. If a host and
+ * port are successfully extracted, the function will return 0 and the
+ * caller is responsible for freeing the host and port. If no port is found
+ * then the function will return 1, with both host and port being NULL.
+ * On memory allocation failure -1 will be returned.
+ */
+int
+ressl_host_port(const char *hostport, char **host, char **port)
+{
+ char *h, *p, *s;
+ int rv = 1;
+
+ *host = NULL;
+ *port = NULL;
+
+ if ((s = strdup(hostport)) == NULL)
+ goto fail;
+
+ h = p = s;
+
+ /* See if this is an IPv6 literal with square braces. */
+ if (p[0] == '[') {
+ h++;
+ if ((p = strchr(s, ']')) == NULL)
+ goto done;
+ *p++ = '\0';
+ }
+
+ /* Find the port seperator. */
+ if ((p = strchr(p, ':')) == NULL)
+ goto done;
+
+ /* If there is another separator then we have issues. */
+ if (strchr(p + 1, ':') != NULL)
+ goto done;
+
+ *p++ = '\0';
+
+ if (asprintf(host, "%s", h) == -1)
+ goto fail;
+ if (asprintf(port, "%s", p) == -1)
+ goto fail;
+
+ rv = 0;
+ goto done;
+
+fail:
+ free(*host);
+ *host = NULL;
+ free(*port);
+ *port = NULL;
+ rv = -1;
+
+done:
+ free(s);
+
+ return (rv);
+}
diff --git a/lib/libressl/ressl_verify.c b/lib/libressl/ressl_verify.c
new file mode 100644
index 00000000000..e98a264f4f7
--- /dev/null
+++ b/lib/libressl/ressl_verify.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/socket.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include <string.h>
+
+#include <openssl/x509v3.h>
+
+#include "ressl_internal.h"
+
+int ressl_match_hostname(const char *cert_hostname, const char *hostname);
+int ressl_check_subject_altname(X509 *cert, const char *host);
+int ressl_check_common_name(X509 *cert, const char *host);
+
+int
+ressl_match_hostname(const char *cert_hostname, const char *hostname)
+{
+ const char *cert_domain, *domain;
+
+ if (strcasecmp(cert_hostname, hostname) == 0)
+ return 0;
+
+ /* Wildcard match? */
+ if (cert_hostname[0] == '*') {
+ cert_domain = &cert_hostname[1];
+ if (cert_domain[0] != '.')
+ return -1;
+ if (strlen(cert_domain) == 1)
+ return -1;
+
+ domain = strchr(hostname, '.');
+
+ /* No wildcard match against a hostname with no domain part. */
+ if (domain == NULL || strlen(domain) == 1)
+ return -1;
+
+ if (strcasecmp(cert_domain, domain) == 0)
+ return 0;
+ }
+
+ return -1;
+}
+
+int
+ressl_check_subject_altname(X509 *cert, const char *host)
+{
+ STACK_OF(GENERAL_NAME) *altname_stack = NULL;
+ union { struct in_addr ip4; struct in6_addr ip6; } addrbuf;
+ int addrlen, type;
+ int count, i;
+ int rv = -1;
+
+ altname_stack = X509_get_ext_d2i(cert, NID_subject_alt_name,
+ NULL, NULL);
+ if (altname_stack == NULL)
+ return -1;
+
+ if (inet_pton(AF_INET, host, &addrbuf) == 1) {
+ type = GEN_IPADD;
+ addrlen = 4;
+ } else if (inet_pton(AF_INET6, host, &addrbuf) == 1) {
+ type = GEN_IPADD;
+ addrlen = 16;
+ } else {
+ type = GEN_DNS;
+ addrlen = 0;
+ }
+
+ count = sk_GENERAL_NAME_num(altname_stack);
+ for (i = 0; i < count; i++) {
+ GENERAL_NAME *altname;
+
+ altname = sk_GENERAL_NAME_value(altname_stack, i);
+
+ if (altname->type != type)
+ continue;
+
+ if (type == GEN_DNS) {
+ unsigned char *data;
+ int format;
+
+ format = ASN1_STRING_type(altname->d.dNSName);
+ if (format == V_ASN1_IA5STRING) {
+ data = ASN1_STRING_data(altname->d.dNSName);
+
+ if (ASN1_STRING_length(altname->d.dNSName) !=
+ (int)strlen(data)) {
+ fprintf(stdout, "%s: NUL byte in "
+ "subjectAltName, probably a "
+ "malicious certificate.\n",
+ getprogname());
+ rv = -2;
+ break;
+ }
+
+ if (ressl_match_hostname(data, host) == 0) {
+ rv = 0;
+ break;
+ }
+ } else
+ fprintf(stdout, "%s: unhandled subjectAltName "
+ "dNSName encoding (%d)\n", getprogname(),
+ format);
+
+ } else if (type == GEN_IPADD) {
+ unsigned char *data;
+ int datalen;
+
+ datalen = ASN1_STRING_length(altname->d.iPAddress);
+ data = ASN1_STRING_data(altname->d.iPAddress);
+
+ if (datalen == addrlen &&
+ memcmp(data, &addrbuf, addrlen) == 0) {
+ rv = 0;
+ break;
+ }
+ }
+ }
+
+ sk_GENERAL_NAME_free(altname_stack);
+ return rv;
+}
+
+int
+ressl_check_common_name(X509 *cert, const char *host)
+{
+ X509_NAME *name;
+ char *common_name = NULL;
+ size_t common_name_len;
+ int rv = -1;
+
+ name = X509_get_subject_name(cert);
+ if (name == NULL)
+ goto out;
+
+ common_name_len = X509_NAME_get_text_by_NID(name, NID_commonName,
+ NULL, 0);
+ if (common_name_len < 0)
+ goto out;
+
+ common_name = calloc(common_name_len + 1, 1);
+ if (common_name == NULL)
+ goto out;
+
+ X509_NAME_get_text_by_NID(name, NID_commonName, common_name,
+ common_name_len + 1);
+
+ /* NUL bytes in CN? */
+ if (common_name_len != (int)strlen(common_name)) {
+ fprintf(stdout, "%s: NUL byte in Common Name field, "
+ "probably a malicious certificate.\n", getprogname());
+ rv = -2;
+ goto out;
+ }
+
+ if (ressl_match_hostname(common_name, host) == 0)
+ rv = 0;
+out:
+ free(common_name);
+ return rv;
+}
+
+int
+ressl_check_hostname(X509 *cert, const char *host)
+{
+ int rv;
+
+ rv = ressl_check_subject_altname(cert, host);
+ if (rv == 0 || rv == -2)
+ return rv;
+
+ return ressl_check_common_name(cert, host);
+}
diff --git a/lib/libressl/shlib_version b/lib/libressl/shlib_version
new file mode 100644
index 00000000000..1edea46de91
--- /dev/null
+++ b/lib/libressl/shlib_version
@@ -0,0 +1,2 @@
+major=1
+minor=0