From cd85e00508e178758948e7a759609d0f1e7764df Mon Sep 17 00:00:00 2001 From: jsing <> Date: Fri, 31 Oct 2014 13:46:17 +0000 Subject: Rename libressl to libtls to avoid confusion and to make it easier to distinguish between LibreSSL (the project) and libressl (the library). Discussed with many. --- src/lib/libressl/Makefile | 56 ------- src/lib/libressl/ressl.c | 300 ------------------------------------ src/lib/libressl/ressl.h | 81 ---------- src/lib/libressl/ressl_client.c | 212 ------------------------- src/lib/libressl/ressl_config.c | 201 ------------------------ src/lib/libressl/ressl_init.3 | 316 -------------------------------------- src/lib/libressl/ressl_internal.h | 72 --------- src/lib/libressl/ressl_server.c | 158 ------------------- src/lib/libressl/ressl_util.c | 81 ---------- src/lib/libressl/ressl_verify.c | 225 --------------------------- src/lib/libressl/shlib_version | 2 - src/lib/libtls/Makefile | 58 +++++++ src/lib/libtls/shlib_version | 2 + src/lib/libtls/tls.c | 300 ++++++++++++++++++++++++++++++++++++ src/lib/libtls/tls.h | 74 +++++++++ src/lib/libtls/tls_client.c | 212 +++++++++++++++++++++++++ src/lib/libtls/tls_config.c | 201 ++++++++++++++++++++++++ src/lib/libtls/tls_init.3 | 316 ++++++++++++++++++++++++++++++++++++++ src/lib/libtls/tls_internal.h | 72 +++++++++ src/lib/libtls/tls_server.c | 134 ++++++++++++++++ src/lib/libtls/tls_util.c | 81 ++++++++++ src/lib/libtls/tls_verify.c | 225 +++++++++++++++++++++++++++ 22 files changed, 1675 insertions(+), 1704 deletions(-) delete mode 100644 src/lib/libressl/Makefile delete mode 100644 src/lib/libressl/ressl.c delete mode 100644 src/lib/libressl/ressl.h delete mode 100644 src/lib/libressl/ressl_client.c delete mode 100644 src/lib/libressl/ressl_config.c delete mode 100644 src/lib/libressl/ressl_init.3 delete mode 100644 src/lib/libressl/ressl_internal.h delete mode 100644 src/lib/libressl/ressl_server.c delete mode 100644 src/lib/libressl/ressl_util.c delete mode 100644 src/lib/libressl/ressl_verify.c delete mode 100644 src/lib/libressl/shlib_version create mode 100644 src/lib/libtls/Makefile create mode 100644 src/lib/libtls/shlib_version create mode 100644 src/lib/libtls/tls.c create mode 100644 src/lib/libtls/tls.h create mode 100644 src/lib/libtls/tls_client.c create mode 100644 src/lib/libtls/tls_config.c create mode 100644 src/lib/libtls/tls_init.3 create mode 100644 src/lib/libtls/tls_internal.h create mode 100644 src/lib/libtls/tls_server.c create mode 100644 src/lib/libtls/tls_util.c create mode 100644 src/lib/libtls/tls_verify.c (limited to 'src') diff --git a/src/lib/libressl/Makefile b/src/lib/libressl/Makefile deleted file mode 100644 index f21c0474ed..0000000000 --- a/src/lib/libressl/Makefile +++ /dev/null @@ -1,56 +0,0 @@ -# $OpenBSD: Makefile,v 1.5 2014/10/08 19:01:40 tedu Exp $ - -CFLAGS+= -Wall -Werror -Wimplicit -CFLAGS+= -DLIBRESSL_INTERNAL - -LIB= ressl - -DPADD= ${LIBCRYPTO} ${LIBSSL} - -HDRS= ressl.h - -SRCS= ressl.c \ - ressl_client.c \ - ressl_config.c \ - ressl_server.c \ - ressl_util.c \ - ressl_verify.c - -MAN= ressl_init.3 - -MLINKS+=ressl_init.3 ressl_error.3 -MLINKS+=ressl_init.3 ressl_config_new.3 -MLINKS+=ressl_init.3 ressl_config_free.3 -MLINKS+=ressl_init.3 ressl_set_ca_file.3 -MLINKS+=ressl_init.3 ressl_set_ca_path.3 -MLINKS+=ressl_init.3 ressl_set_cert_file.3 -MLINKS+=ressl_init.3 ressl_set_cert_mem.3 -MLINKS+=ressl_init.3 ressl_set_ciphers.3 -MLINKS+=ressl_init.3 ressl_set_ecdhcurve.3 -MLINKS+=ressl_init.3 ressl_set_key_file.3 -MLINKS+=ressl_init.3 ressl_set_key_mem.3 -MLINKS+=ressl_init.3 ressl_set_protocols.3 -MLINKS+=ressl_init.3 ressl_set_verify_depth.3 -MLINKS+=ressl_init.3 ressl_clear_keys.3 -MLINKS+=ressl_init.3 ressl_insecure_noverifyhost.3 -MLINKS+=ressl_init.3 ressl_insecure_noverifycert.3 -MLINKS+=ressl_init.3 ressl_verify.3 -MLINKS+=ressl_init.3 ressl_configure.3 -MLINKS+=ressl_init.3 ressl_reset.3 -MLINKS+=ressl_init.3 ressl_free.3 -MLINKS+=ressl_init.3 ressl_close.3 -MLINKS+=ressl_init.3 ressl_connect.3 -MLINKS+=ressl_init.3 ressl_connect_socket.3 -MLINKS+=ressl_init.3 ressl_read.3 -MLINKS+=ressl_init.3 ressl_write.3 - -includes: - @cd ${.CURDIR}; for i in $(HDRS); do \ - j="cmp -s $$i ${DESTDIR}/usr/include/$$i || \ - ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} -m 444 $$i\ - ${DESTDIR}/usr/include/"; \ - echo $$j; \ - eval "$$j"; \ - done; - -.include diff --git a/src/lib/libressl/ressl.c b/src/lib/libressl/ressl.c deleted file mode 100644 index 06c7d54cc2..0000000000 --- a/src/lib/libressl/ressl.c +++ /dev/null @@ -1,300 +0,0 @@ -/* $OpenBSD: ressl.c,v 1.18 2014/10/15 21:02:39 tedu Exp $ */ -/* - * Copyright (c) 2014 Joel Sing - * - * 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 - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include "ressl_internal.h" - -static 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(); - - if ((ressl_config_default = ressl_config_new()) == NULL) - return (-1); - - 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(void) -{ - struct ressl *ctx; - - if ((ctx = calloc(1, sizeof(*ctx))) == NULL) - return (NULL); - - ctx->config = ressl_config_default; - - ressl_reset(ctx); - - return (ctx); -} - -int -ressl_configure(struct ressl *ctx, struct ressl_config *config) -{ - if (config == NULL) - config = ressl_config_default; - - ctx->config = config; - - if ((ctx->flags & RESSL_SERVER) != 0) - return (ressl_configure_server(ctx)); - - return (0); -} - -int -ressl_configure_keypair(struct ressl *ctx) -{ - EVP_PKEY *pkey = NULL; - X509 *cert = NULL; - BIO *bio = NULL; - - if (ctx->config->cert_mem != NULL) { - if (SSL_CTX_use_certificate_chain(ctx->ssl_ctx, - ctx->config->cert_mem, ctx->config->cert_len) != 1) { - ressl_set_error(ctx, "failed to load certificate"); - goto err; - } - cert = NULL; - } - if (ctx->config->key_mem != NULL) { - if ((bio = BIO_new_mem_buf(ctx->config->key_mem, - ctx->config->key_len)) == NULL) { - ressl_set_error(ctx, "failed to create buffer"); - goto err; - } - if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, - NULL)) == NULL) { - ressl_set_error(ctx, "failed to read private key"); - goto err; - } - if (SSL_CTX_use_PrivateKey(ctx->ssl_ctx, pkey) != 1) { - ressl_set_error(ctx, "failed to load private key"); - goto err; - } - BIO_free(bio); - bio = NULL; - EVP_PKEY_free(pkey); - pkey = NULL; - } - - if (ctx->config->cert_file != NULL) { - if (SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, - ctx->config->cert_file) != 1) { - ressl_set_error(ctx, "failed to load certificate file"); - goto err; - } - } - if (ctx->config->key_file != NULL) { - if (SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, - ctx->config->key_file, SSL_FILETYPE_PEM) != 1) { - ressl_set_error(ctx, "failed to load private key file"); - goto err; - } - } - - if (SSL_CTX_check_private_key(ctx->ssl_ctx) != 1) { - ressl_set_error(ctx, "private/public key mismatch"); - goto err; - } - - return (0); - -err: - EVP_PKEY_free(pkey); - X509_free(cert); - BIO_free(bio); - - return (1); -} - -int -ressl_configure_ssl(struct ressl *ctx) -{ - SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2); - SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv3); - - SSL_CTX_clear_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1); - SSL_CTX_clear_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_1); - SSL_CTX_clear_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_2); - - if ((ctx->config->protocols & RESSL_PROTOCOL_TLSv1_0) == 0) - SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1); - if ((ctx->config->protocols & RESSL_PROTOCOL_TLSv1_1) == 0) - SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_1); - if ((ctx->config->protocols & RESSL_PROTOCOL_TLSv1_2) == 0) - SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_2); - - if (ctx->config->ciphers != NULL) { - if (SSL_CTX_set_cipher_list(ctx->ssl_ctx, - ctx->config->ciphers) != 1) { - ressl_set_error(ctx, "failed to set ciphers"); - goto err; - } - } - - return (0); - -err: - return (-1); -} - -void -ressl_free(struct ressl *ctx) -{ - if (ctx == NULL) - return; - ressl_reset(ctx); - free(ctx); -} - -void -ressl_reset(struct ressl *ctx) -{ - SSL_CTX_free(ctx->ssl_ctx); - SSL_free(ctx->ssl_conn); - - ctx->ssl_conn = NULL; - ctx->ssl_ctx = NULL; - - ctx->socket = -1; - - ctx->err = 0; - free(ctx->errmsg); - ctx->errmsg = NULL; -} - -int -ressl_read(struct ressl *ctx, void *buf, size_t buflen, size_t *outlen) -{ - int ret, ssl_err; - - ret = SSL_read(ctx->ssl_conn, buf, buflen); - if (ret > 0) { - *outlen = (size_t)ret; - return (0); - } - - ssl_err = SSL_get_error(ctx->ssl_conn, ret); - switch (ssl_err) { - case SSL_ERROR_WANT_READ: - return (RESSL_READ_AGAIN); - case SSL_ERROR_WANT_WRITE: - return (RESSL_WRITE_AGAIN); - default: - ressl_set_error(ctx, "read failed (%i)", ssl_err); - return (-1); - } -} - -int -ressl_write(struct ressl *ctx, const void *buf, size_t buflen, size_t *outlen) -{ - int ret, ssl_err; - - ret = SSL_write(ctx->ssl_conn, buf, buflen); - if (ret > 0) { - *outlen = (size_t)ret; - return (0); - } - - ssl_err = SSL_get_error(ctx->ssl_conn, ret); - switch (ssl_err) { - case SSL_ERROR_WANT_READ: - return (RESSL_READ_AGAIN); - case SSL_ERROR_WANT_WRITE: - return (RESSL_WRITE_AGAIN); - default: - ressl_set_error(ctx, "write failed (%i)", ssl_err); - return (-1); - } -} - -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/src/lib/libressl/ressl.h b/src/lib/libressl/ressl.h deleted file mode 100644 index 4ca2507f5a..0000000000 --- a/src/lib/libressl/ressl.h +++ /dev/null @@ -1,81 +0,0 @@ -/* $OpenBSD: ressl.h,v 1.21 2014/10/15 21:02:39 tedu Exp $ */ -/* - * Copyright (c) 2014 Joel Sing - * - * 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 - -#define RESSL_API 20141008 - -#define RESSL_PROTOCOL_TLSv1_0 (1 << 1) -#define RESSL_PROTOCOL_TLSv1_1 (1 << 2) -#define RESSL_PROTOCOL_TLSv1_2 (1 << 3) -#define RESSL_PROTOCOL_TLSv1 \ - (RESSL_PROTOCOL_TLSv1_0|RESSL_PROTOCOL_TLSv1_1|RESSL_PROTOCOL_TLSv1_2) -#define RESSL_PROTOCOLS_DEFAULT RESSL_PROTOCOL_TLSv1 - -#define RESSL_READ_AGAIN -2 -#define RESSL_WRITE_AGAIN -3 - -struct ressl; -struct ressl_config; - -int ressl_init(void); - -const char *ressl_error(struct ressl *ctx); - -struct ressl_config *ressl_config_new(void); -void ressl_config_free(struct ressl_config *config); - -int ressl_config_set_ca_file(struct ressl_config *config, const char *ca_file); -int ressl_config_set_ca_path(struct ressl_config *config, const char *ca_path); -int ressl_config_set_cert_file(struct ressl_config *config, - const char *cert_file); -int ressl_config_set_cert_mem(struct ressl_config *config, const uint8_t *cert, - size_t len); -int ressl_config_set_ciphers(struct ressl_config *config, const char *ciphers); -int ressl_config_set_ecdhcurve(struct ressl_config *config, const char *name); -int ressl_config_set_key_file(struct ressl_config *config, - const char *key_file); -int ressl_config_set_key_mem(struct ressl_config *config, const uint8_t *key, - size_t len); -void ressl_config_set_protocols(struct ressl_config *config, - uint32_t protocols); -void ressl_config_set_verify_depth(struct ressl_config *config, - int verify_depth); - -void ressl_config_clear_keys(struct ressl_config *config); -void ressl_config_insecure_noverifyhost(struct ressl_config *config); -void ressl_config_insecure_noverifycert(struct ressl_config *config); -void ressl_config_verify(struct ressl_config *config); - -struct ressl *ressl_client(void); -struct ressl *ressl_server(void); -int ressl_configure(struct ressl *ctx, struct ressl_config *config); -void ressl_reset(struct ressl *ctx); -void ressl_free(struct ressl *ctx); - -int ressl_accept(struct ressl *ctx, struct ressl **cctx); -int ressl_accept_socket(struct ressl *ctx, struct ressl **cctx, int socket); -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_listen(struct ressl *ctx, const char *host, const char *port, int af); -int ressl_read(struct ressl *ctx, void *buf, size_t buflen, size_t *outlen); -int ressl_write(struct ressl *ctx, const void *buf, size_t buflen, - size_t *outlen); -int ressl_close(struct ressl *ctx); - -#endif /* HEADER_RESSL_H */ diff --git a/src/lib/libressl/ressl_client.c b/src/lib/libressl/ressl_client.c deleted file mode 100644 index 013963f3a1..0000000000 --- a/src/lib/libressl/ressl_client.c +++ /dev/null @@ -1,212 +0,0 @@ -/* $OpenBSD: ressl_client.c,v 1.5 2014/10/03 14:14:40 tedu Exp $ */ -/* - * Copyright (c) 2014 Joel Sing - * - * 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 -#include - -#include - -#include -#include -#include - -#include - -#include -#include "ressl_internal.h" - -struct ressl * -ressl_client(void) -{ - struct ressl *ctx; - - if ((ctx = ressl_new()) == NULL) - return (NULL); - - ctx->flags |= RESSL_CLIENT; - - return (ctx); -} - -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 ((ctx->flags & RESSL_CLIENT) == 0) { - ressl_set_error(ctx, "not a client context"); - goto err; - } - - 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; - - if ((ctx->flags & RESSL_CLIENT) == 0) { - ressl_set_error(ctx, "not a client context"); - goto err; - } - - ctx->socket = socket; - - if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) { - ressl_set_error(ctx, "ssl context failure"); - goto err; - } - - if (ressl_configure_ssl(ctx) != 0) - goto err; - - if (ctx->config->verify_host) { - if (hostname == NULL) { - ressl_set_error(ctx, "server name not specified"); - goto err; - } - } - - if (ctx->config->verify_cert) { - 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_host) { - 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); -} diff --git a/src/lib/libressl/ressl_config.c b/src/lib/libressl/ressl_config.c deleted file mode 100644 index a45364c2ef..0000000000 --- a/src/lib/libressl/ressl_config.c +++ /dev/null @@ -1,201 +0,0 @@ -/* $OpenBSD: ressl_config.c,v 1.14 2014/10/03 14:14:40 tedu Exp $ */ -/* - * Copyright (c) 2014 Joel Sing - * - * 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 -#include - -#include -#include "ressl_internal.h" - -static int -set_string(const char **dest, const char *src) -{ - free((char *)*dest); - *dest = NULL; - if (src != NULL) - if ((*dest = strdup(src)) == NULL) - return -1; - return 0; -} - -static void * -memdup(const void *in, size_t len) -{ - void *out; - - if ((out = malloc(len)) == NULL) - return NULL; - memcpy(out, in, len); - return out; -} - -static int -set_mem(char **dest, size_t *destlen, const void *src, size_t srclen) -{ - free(*dest); - *dest = NULL; - *destlen = 0; - if (src != NULL) - if ((*dest = memdup(src, srclen)) == NULL) - return -1; - *destlen = srclen; - return 0; -} - -struct ressl_config * -ressl_config_new(void) -{ - struct ressl_config *config; - - if ((config = calloc(1, sizeof(*config))) == NULL) - return (NULL); - - /* - * Default configuration. - */ - if (ressl_config_set_ca_file(config, _PATH_SSL_CA_FILE) != 0) { - ressl_config_free(config); - return (NULL); - } - ressl_config_set_ecdhcurve(config, "auto"); - ressl_config_set_protocols(config, RESSL_PROTOCOLS_DEFAULT); - ressl_config_set_verify_depth(config, 6); - - ressl_config_verify(config); - - return (config); -} - -void -ressl_config_free(struct ressl_config *config) -{ - if (config == NULL) - return; - - ressl_config_clear_keys(config); - - free((char *)config->ca_file); - free((char *)config->ca_path); - free((char *)config->cert_file); - free(config->cert_mem); - free((char *)config->ciphers); - free((char *)config->key_file); - free(config->key_mem); - - free(config); -} - -void -ressl_config_clear_keys(struct ressl_config *config) -{ - ressl_config_set_cert_mem(config, NULL, 0); - ressl_config_set_key_mem(config, NULL, 0); -} - -int -ressl_config_set_ca_file(struct ressl_config *config, const char *ca_file) -{ - return set_string(&config->ca_file, ca_file); -} - -int -ressl_config_set_ca_path(struct ressl_config *config, const char *ca_path) -{ - return set_string(&config->ca_path, ca_path); -} - -int -ressl_config_set_cert_file(struct ressl_config *config, const char *cert_file) -{ - return set_string(&config->cert_file, cert_file); -} - -int -ressl_config_set_cert_mem(struct ressl_config *config, const uint8_t *cert, - size_t len) -{ - return set_mem(&config->cert_mem, &config->cert_len, cert, len); -} - -int -ressl_config_set_ciphers(struct ressl_config *config, const char *ciphers) -{ - return set_string(&config->ciphers, ciphers); -} - -int -ressl_config_set_ecdhcurve(struct ressl_config *config, const char *name) -{ - int nid; - - if (name == NULL) - nid = NID_undef; - else if (strcasecmp(name, "auto") == 0) - nid = -1; - else if ((nid = OBJ_txt2nid(name)) == NID_undef) - return (-1); - - config->ecdhcurve = nid; - - return (0); -} - -int -ressl_config_set_key_file(struct ressl_config *config, const char *key_file) -{ - return set_string(&config->key_file, key_file); -} - -int -ressl_config_set_key_mem(struct ressl_config *config, const uint8_t *key, - size_t len) -{ - if (config->key_mem) - explicit_bzero(config->key_mem, config->key_len); - return set_mem(&config->key_mem, &config->key_len, key, len); -} - -void -ressl_config_set_protocols(struct ressl_config *config, uint32_t protocols) -{ - config->protocols = protocols; -} - -void -ressl_config_set_verify_depth(struct ressl_config *config, int verify_depth) -{ - config->verify_depth = verify_depth; -} - -void -ressl_config_insecure_noverifyhost(struct ressl_config *config) -{ - config->verify_host = 0; -} - -void -ressl_config_insecure_noverifycert(struct ressl_config *config) -{ - config->verify_cert = 0; -} - -void -ressl_config_verify(struct ressl_config *config) -{ - config->verify_host = 1; - config->verify_cert = 1; -} diff --git a/src/lib/libressl/ressl_init.3 b/src/lib/libressl/ressl_init.3 deleted file mode 100644 index 81a32350ee..0000000000 --- a/src/lib/libressl/ressl_init.3 +++ /dev/null @@ -1,316 +0,0 @@ -.\" $OpenBSD: ressl_init.3,v 1.9 2014/10/16 12:46:35 tedu Exp $ -.\" -.\" Copyright (c) 2014 Ted Unangst -.\" -.\" 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. -.\" -.Dd $Mdocdate: October 16 2014 $ -.Dt RESSL 3 -.Os -.Sh NAME -.Nm ressl_init , -.Nm ressl_error , -.Nm ressl_config_new , -.Nm ressl_config_free , -.Nm ressl_config_set_ca_file , -.Nm ressl_config_set_ca_path , -.Nm ressl_config_set_cert_file , -.Nm ressl_config_set_cert_mem , -.Nm ressl_config_set_ciphers , -.Nm ressl_config_set_ecdhcurve , -.Nm ressl_config_set_key_file , -.Nm ressl_config_set_key_mem , -.Nm ressl_config_set_protocols , -.Nm ressl_config_set_verify_depth , -.Nm ressl_config_clear_keys , -.Nm ressl_config_insecure_noverifyhost , -.Nm ressl_config_insecure_noverifycert , -.Nm ressl_config_verify , -.Nm ressl_client , -.Nm ressl_server , -.Nm ressl_configure , -.Nm ressl_reset , -.Nm ressl_close , -.Nm ressl_free , -.Nm ressl_connect , -.Nm ressl_connect_socket , -.Nm ressl_read , -.Nm ressl_write , -.Nd ressl TLS client and server API -.Sh SYNOPSIS -.In ressl.h -.Ft "int" -.Fn ressl_init "void" -.Ft "const char *" -.Fn ressl_error "struct ressl *ctx" -.Ft "struct ressl_config *" -.Fn ressl_config_new "void" -.Ft "void" -.Fn ressl_config_free "struct ressl_config *config" -.Ft "int" -.Fn ressl_config_set_ca_file "struct ressl_config *config" "const char *ca_file" -.Ft "int" -.Fn ressl_config_set_ca_path "struct ressl_config *config" "const char *ca_path" -.Ft "int" -.Fn ressl_config_set_cert_file "struct ressl_config *config" "const char *cert_file" -.Ft "int" -.Fn ressl_config_set_cert_mem "struct ressl_config *config" "const uint8_t *cert" "size_t len" -.Ft "int" -.Fn ressl_config_set_ciphers "struct ressl_config *config" "const char *ciphers" -.Ft "int" -.Fn ressl_config_set_ecdhcurve "struct ressl_config *config" "const char *name" -.Ft "int" -.Fn ressl_config_set_key_file "struct ressl_config *config" "const char *key_file" -.Ft "int" -.Fn ressl_config_set_key_mem "struct ressl_config *config" "const uint8_t *key" "size_t len" -.Ft "int" -.Fn ressl_config_set_protocols "struct ressl_config *config" "uint32_t protocols" -.Ft "int" -.Fn ressl_config_set_verify_depth "struct ressl_config *config" "int verify_depth" -.Ft "void" -.Fn ressl_config_clear_keys "struct ressl_config *config" -.Ft "void" -.Fn ressl_config_insecure_noverifyhost "struct ressl_config *config" -.Ft "void" -.Fn ressl_config_insecure_noverifycert "struct ressl_config *config" -.Ft "void" -.Fn ressl_config_verify "struct ressl_config *config" -.Ft "struct ressl *" -.Fn ressl_client void -.Ft "struct ressl *" -.Fn ressl_server void -.Ft "int" -.Fn ressl_configure "struct ressl *ctx" "struct ressl_config *config" -.Ft "void" -.Fn ressl_reset "struct ressl *ctx" -.Ft "int" -.Fn ressl_close "struct ressl *ctx" -.Ft "void" -.Fn ressl_free "struct ressl *ctx" -.Ft "int" -.Fn ressl_connect "struct ressl *ctx" "const char *host" "const char *port" -.Ft "int" -.Fn ressl_connect_socket "struct ressl *ctx" "int s" "const char *hostname" -.Ft "int" -.Fn ressl_read "struct ressl *ctx" "void *buf" "size_t buflen" "size_t *outlen" -.Ft "int" -.Fn ressl_write "struct ressl *ctx" "const void *buf" "size_t buflen" -.Sh DESCRIPTION -The -.Nm ressl -family of functions establishes a secure communications channel -using the TLS socket protocol. -Both clients and servers are supported. -.Pp -The -.Fn ressl_init -function should be called once before any function is used. -.Pp -Before a connection is created, a configuration must be created. -The -.Fn ressl_config_new -function returns a new default configuration that can be used for future -connections. -Several functions exist to change the options of the configuration; see below. -.Pp -A -.Em ressl -connection is represented as a -.Em context . -A new -.Em context -is created by either the -.Fn ressl_client -or -.Fn ressl_server -functions. -The context can then be configured with the function -.Fn ressl_configure . -The same -.Em ressl_config -object can be used to configure multiple contexts. -.Pp -A client connection is initiated after configuration by calling -.Fn ressl_connect . -This function will create a new socket, connect to the specified host and -port, and then establish a secure connection. -An already existing socket can be upgraded to a secure connection by calling -.Fn ressl_connect_socket . -.Pp -Two functions are provided for input and output, -.Fn ressl_read -and -.Fn ressl_write . -.Pp -After use, a ressl -.Em context -should be closed with -.Fn ressl_close , -and then freed by calling -.Fn ressl_free . -When no more contexts are to be created, the -.Em ressl_config -object should be freed by calling -.Fn ressl_config_free . -.Sh FUNCTIONS -The -.Fn ressl_init -function initializes global data structures. -It should be called once before any other functions. -.Pp -The following functions create and free configuration objects. -.Bl -bullet -offset four -.It -.Fn ressl_config_new -allocates a new default configuration object. -.It -.Fn ressl_config_free -frees a configuration object. -.El -.Pp -The following functions modify a configuration by setting parameters. -Configuration options may apply to only clients or only servers or both. -.Bl -bullet -offset four -.It -.Fn ressl_config_set_ca_file -sets the filename used to load a file -containing the root certificates. -.Em (Client) -.It -.Fn ressl_config_set_ca_path -sets the path (directory) which should be searched for root -certificates. -.Em (Client) -.It -.Fn ressl_config_set_cert_file -sets file from which the public certificate will be read. -.Em (Client and server) -.It -.Fn ressl_config_set_cert_mem -sets the public certificate directly from memory. -.Em (Client and server) -.It -.Fn ressl_config_set_ciphers -sets the list of ciphers that may be used. -.Em (Client and server) -.It -.Fn ressl_config_set_key_file -sets the file from which the private key will be read. -.Em (Server) -.It -.Fn ressl_config_set_key_mem -directly sets the private key from memory. -.Em (Server) -.It -.Fn ressl_config_set_protocols -sets which versions of the protocol may be used. -Possible values are the bitwise OR of: -.Pp -.Bl -tag -width "RESSL_PROTOCOL_TLSv1_2" -offset indent -compact -.It Dv RESSL_PROTOCOL_TLSv1_0 -.It Dv RESSL_PROTOCOL_TLSv1_1 -.It Dv RESSL_PROTOCOL_TLSv1_2 -.El -.Pp -Additionally, the values -.Dv RESSL_PROTOCOL_TLSv1 -(all TLS versions) and -.Dv RESSL_PROTOCOLS_DEFAULT -(currently all TLS versions) may be used. -.Em (Client and server) -.It -.Fn ressl_config_clear_keys -clears any secret keys from memory. -.Em (Server) -.It -.Fn ressl_config_insecure_noverifyhost -disables hostname verification. -Be careful when using this option. -.Em (Client) -.It -.Fn ressl_config_insecure_noverifycert -disables certificate verification. -Be extremely careful when using this option. -.Em (Client) -.It -.Fn ressl_config_verify -reenables hostname and certificate verification. -.Em (Client) -.El -.Pp -The following functions create, prepare, and free a connection context. -.Bl -bullet -offset four -.It -.Fn ressl_client -creates a new ressl context for client connections. -.It -.Fn ressl_server -creates a new ressl context for server connections. -.It -.Fn ressl_configure -readies a ressl context for use by applying the configuration -options. -.It -.Fn ressl_close -closes a connection after use. -.It -.Fn ressl_free -frees a ressl context after use. -.El -.Pp -The following functions initiate a connection and perform input and output -operations. -.Bl -bullet -offset four -.It -.Fn ressl_connect -connects a client context to the server named by -.Fa host . -The -.Fa port -may be numeric or a service name. -If it is NULL then a host of the format "hostname:port" is permitted. -.It -.Fn ressl_connect_socket -connects a client context to an already established socket connection. -.It -.Fn ressl_read -reads -.Fa buflen -bytes of data from the socket into -.Fa buf . -The amount of data read is returned in -.Fa outlen . -.It -.Fn ressl_write -writes -.Fa buflen -bytes of data from -.Fa buf -to the socket. -The amount of data written is returned in -.Fa outlen . -.El -.Sh RETURN VALUES -Functions that return -.Vt int -will return 0 on success and -1 on error. -Functions that return a pointer will return NULL on error. -.\" .Sh ERRORS -.\" .Sh SEE ALSO -.Sh HISTORY -The -.Nm ressl -API first appeared in -.Ox 5.6 -as a response to the unnecessary challenges other APIs present in -order to use them safely. diff --git a/src/lib/libressl/ressl_internal.h b/src/lib/libressl/ressl_internal.h deleted file mode 100644 index b752b5fd88..0000000000 --- a/src/lib/libressl/ressl_internal.h +++ /dev/null @@ -1,72 +0,0 @@ -/* $OpenBSD: ressl_internal.h,v 1.12 2014/10/03 14:14:40 tedu Exp $ */ -/* - * Copyright (c) 2014 Jeremie Courreges-Anglas - * Copyright (c) 2014 Joel Sing - * - * 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 - -#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 *cert_file; - char *cert_mem; - size_t cert_len; - const char *ciphers; - int ecdhcurve; - const char *key_file; - char *key_mem; - size_t key_len; - uint32_t protocols; - int verify_cert; - int verify_host; - int verify_depth; -}; - -#define RESSL_CLIENT (1 << 0) -#define RESSL_SERVER (1 << 1) -#define RESSL_SERVER_CONN (1 << 2) - -struct ressl { - struct ressl_config *config; - uint64_t flags; - - int err; - char *errmsg; - - int socket; - - SSL *ssl_conn; - SSL_CTX *ssl_ctx; -}; - -struct ressl *ressl_new(void); -struct ressl *ressl_server_conn(struct ressl *ctx); - -int ressl_check_hostname(X509 *cert, const char *host); -int ressl_configure_keypair(struct ressl *ctx); -int ressl_configure_server(struct ressl *ctx); -int ressl_configure_ssl(struct ressl *ctx); -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/src/lib/libressl/ressl_server.c b/src/lib/libressl/ressl_server.c deleted file mode 100644 index 4783674a0b..0000000000 --- a/src/lib/libressl/ressl_server.c +++ /dev/null @@ -1,158 +0,0 @@ -/* $OpenBSD: ressl_server.c,v 1.11 2014/10/15 14:08:26 jsing Exp $ */ -/* - * Copyright (c) 2014 Joel Sing - * - * 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 -#include - -#include -#include "ressl_internal.h" - -struct ressl * -ressl_server(void) -{ - struct ressl *ctx; - - if ((ctx = ressl_new()) == NULL) - return (NULL); - - ctx->flags |= RESSL_SERVER; - - return (ctx); -} - -struct ressl * -ressl_server_conn(struct ressl *ctx) -{ - struct ressl *conn_ctx; - - if ((conn_ctx = ressl_new()) == NULL) - return (NULL); - - conn_ctx->flags |= RESSL_SERVER_CONN; - - return (conn_ctx); -} - -int -ressl_configure_server(struct ressl *ctx) -{ - EC_KEY *ecdh_key; - - if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) { - ressl_set_error(ctx, "ssl context failure"); - goto err; - } - - if (ressl_configure_ssl(ctx) != 0) - goto err; - if (ressl_configure_keypair(ctx) != 0) - goto err; - - if (ctx->config->ecdhcurve == -1) { - SSL_CTX_set_ecdh_auto(ctx->ssl_ctx, 1); - } else if (ctx->config->ecdhcurve != NID_undef) { - if ((ecdh_key = EC_KEY_new_by_curve_name( - ctx->config->ecdhcurve)) == NULL) { - ressl_set_error(ctx, "failed to set ECDH curve"); - goto err; - } - SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_SINGLE_ECDH_USE); - SSL_CTX_set_tmp_ecdh(ctx->ssl_ctx, ecdh_key); - EC_KEY_free(ecdh_key); - } - - return (0); - -err: - return (-1); -} - -int -ressl_listen(struct ressl *ctx, const char *host, const char *port, int af) -{ - if ((ctx->flags & RESSL_SERVER) == 0) { - ressl_set_error(ctx, "not a server context"); - goto err; - } - -err: - return (-1); -} - -int -ressl_accept(struct ressl *ctx, struct ressl **cctx) -{ - if ((ctx->flags & RESSL_SERVER) == 0) { - ressl_set_error(ctx, "not a server context"); - goto err; - } - -err: - return (-1); -} - -int -ressl_accept_socket(struct ressl *ctx, struct ressl **cctx, int socket) -{ - struct ressl *conn_ctx = *cctx; - int ret, ssl_err; - - if ((ctx->flags & RESSL_SERVER) == 0) { - ressl_set_error(ctx, "not a server context"); - goto err; - } - - if (conn_ctx == NULL) { - if ((conn_ctx = ressl_server_conn(ctx)) == NULL) { - ressl_set_error(ctx, "connection context failure"); - goto err; - } - *cctx = conn_ctx; - - conn_ctx->socket = socket; - - if ((conn_ctx->ssl_conn = SSL_new(ctx->ssl_ctx)) == NULL) { - ressl_set_error(ctx, "ssl failure"); - goto err; - } - - if (SSL_set_fd(conn_ctx->ssl_conn, socket) != 1) { - ressl_set_error(ctx, "ssl set fd failure"); - goto err; - } - SSL_set_app_data(conn_ctx->ssl_conn, conn_ctx); - } - - if ((ret = SSL_accept(conn_ctx->ssl_conn)) != 1) { - ssl_err = SSL_get_error(conn_ctx->ssl_conn, ret); - switch (ssl_err) { - case SSL_ERROR_WANT_READ: - return (RESSL_READ_AGAIN); - case SSL_ERROR_WANT_WRITE: - return (RESSL_WRITE_AGAIN); - default: - ressl_set_error(ctx, "ssl accept failure (%i)", - ssl_err); - goto err; - } - } - - return (0); - -err: - return (-1); -} diff --git a/src/lib/libressl/ressl_util.c b/src/lib/libressl/ressl_util.c deleted file mode 100644 index d8b8f51738..0000000000 --- a/src/lib/libressl/ressl_util.c +++ /dev/null @@ -1,81 +0,0 @@ -/* $OpenBSD: ressl_util.c,v 1.2 2014/08/05 12:46:16 jsing Exp $ */ -/* - * Copyright (c) 2014 Joel Sing - * - * 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 - -#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/src/lib/libressl/ressl_verify.c b/src/lib/libressl/ressl_verify.c deleted file mode 100644 index 5e9f370e1c..0000000000 --- a/src/lib/libressl/ressl_verify.c +++ /dev/null @@ -1,225 +0,0 @@ -/* $OpenBSD: ressl_verify.c,v 1.5 2014/10/06 11:55:48 jca Exp $ */ -/* - * Copyright (c) 2014 Jeremie Courreges-Anglas - * - * 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 - -#include -#include - -#include - -#include - -#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, *next_dot; - - if (strcasecmp(cert_hostname, hostname) == 0) - return 0; - - /* Wildcard match? */ - if (cert_hostname[0] == '*') { - /* - * Valid wildcards: - * - "*.domain.tld" - * - "*.sub.domain.tld" - * - etc. - * Reject "*.tld". - * No attempt to prevent the use of eg. "*.co.uk". - */ - cert_domain = &cert_hostname[1]; - /* Disallow "*" */ - if (cert_domain[0] == '\0') - return -1; - /* Disallow "*foo" */ - if (cert_domain[0] != '.') - return -1; - /* Disallow "*.." */ - if (cert_domain[1] == '.') - return -1; - next_dot = strchr(&cert_domain[1], '.'); - /* Disallow "*.bar" */ - if (next_dot == NULL) - return -1; - /* Disallow "*.bar.." */ - if (next_dot[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; - int common_name_len; - int rv = -1; - union { struct in_addr ip4; struct in6_addr ip6; } addrbuf; - - 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 (inet_pton(AF_INET, host, &addrbuf) == 1 || - inet_pton(AF_INET6, host, &addrbuf) == 1) { - /* - * We don't want to attempt wildcard matching against IP - * addresses, so perform a simple comparison here. - */ - if (strcmp(common_name, host) == 0) - rv = 0; - else - rv = -1; - 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/src/lib/libressl/shlib_version b/src/lib/libressl/shlib_version deleted file mode 100644 index b52599a164..0000000000 --- a/src/lib/libressl/shlib_version +++ /dev/null @@ -1,2 +0,0 @@ -major=2 -minor=0 diff --git a/src/lib/libtls/Makefile b/src/lib/libtls/Makefile new file mode 100644 index 0000000000..b83a6de2ce --- /dev/null +++ b/src/lib/libtls/Makefile @@ -0,0 +1,58 @@ +# $OpenBSD: Makefile,v 1.1 2014/10/31 13:46:17 jsing Exp $ + +CFLAGS+= -Wall -Werror -Wimplicit +CFLAGS+= -DLIBRESSL_INTERNAL + +LIB= tls + +DPADD= ${LIBCRYPTO} ${LIBSSL} + +HDRS= tls.h + +SRCS= tls.c \ + tls_client.c \ + tls_config.c \ + tls_server.c \ + tls_util.c \ + tls_verify.c + +MAN= tls_init.3 + +MLINKS+=tls_init.3 tls_config_new.3 +MLINKS+=tls_init.3 tls_config_free.3 +MLINKS+=tls_init.3 tls_config_set_ca_file.3 +MLINKS+=tls_init.3 tls_config_set_ca_path.3 +MLINKS+=tls_init.3 tls_config_set_cert_file.3 +MLINKS+=tls_init.3 tls_config_set_cert_mem.3 +MLINKS+=tls_init.3 tls_config_set_ciphers.3 +MLINKS+=tls_init.3 tls_config_set_ecdhcurve.3 +MLINKS+=tls_init.3 tls_config_set_key_file.3 +MLINKS+=tls_init.3 tls_config_set_key_mem.3 +MLINKS+=tls_init.3 tls_config_set_protocols.3 +MLINKS+=tls_init.3 tls_config_set_verify_depth.3 +MLINKS+=tls_init.3 tls_config_clear_keys.3 +MLINKS+=tls_init.3 tls_config_insecure_noverifyhost.3 +MLINKS+=tls_init.3 tls_config_insecure_noverifycert.3 +MLINKS+=tls_init.3 tls_config_verify.3 +MLINKS+=tls_init.3 tls_client.3 +MLINKS+=tls_init.3 tls_server.3 +MLINKS+=tls_init.3 tls_configure.3 +MLINKS+=tls_init.3 tls_error.3 +MLINKS+=tls_init.3 tls_reset.3 +MLINKS+=tls_init.3 tls_free.3 +MLINKS+=tls_init.3 tls_close.3 +MLINKS+=tls_init.3 tls_connect.3 +MLINKS+=tls_init.3 tls_connect_socket.3 +MLINKS+=tls_init.3 tls_read.3 +MLINKS+=tls_init.3 tls_write.3 + +includes: + @cd ${.CURDIR}; for i in $(HDRS); do \ + j="cmp -s $$i ${DESTDIR}/usr/include/$$i || \ + ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} -m 444 $$i\ + ${DESTDIR}/usr/include/"; \ + echo $$j; \ + eval "$$j"; \ + done; + +.include diff --git a/src/lib/libtls/shlib_version b/src/lib/libtls/shlib_version new file mode 100644 index 0000000000..1edea46de9 --- /dev/null +++ b/src/lib/libtls/shlib_version @@ -0,0 +1,2 @@ +major=1 +minor=0 diff --git a/src/lib/libtls/tls.c b/src/lib/libtls/tls.c new file mode 100644 index 0000000000..a7f612e40b --- /dev/null +++ b/src/lib/libtls/tls.c @@ -0,0 +1,300 @@ +/* $OpenBSD: tls.c,v 1.1 2014/10/31 13:46:17 jsing Exp $ */ +/* + * Copyright (c) 2014 Joel Sing + * + * 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 + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include "tls_internal.h" + +static struct tls_config *tls_config_default; + +int +tls_init(void) +{ + static int tls_initialised = 0; + + if (tls_initialised) + return (0); + + SSL_load_error_strings(); + SSL_library_init(); + + if ((tls_config_default = tls_config_new()) == NULL) + return (-1); + + tls_initialised = 1; + + return (0); +} + +const char * +tls_error(struct tls *ctx) +{ + return ctx->errmsg; +} + +int +tls_set_error(struct tls *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 tls * +tls_new(void) +{ + struct tls *ctx; + + if ((ctx = calloc(1, sizeof(*ctx))) == NULL) + return (NULL); + + ctx->config = tls_config_default; + + tls_reset(ctx); + + return (ctx); +} + +int +tls_configure(struct tls *ctx, struct tls_config *config) +{ + if (config == NULL) + config = tls_config_default; + + ctx->config = config; + + if ((ctx->flags & TLS_SERVER) != 0) + return (tls_configure_server(ctx)); + + return (0); +} + +int +tls_configure_keypair(struct tls *ctx) +{ + EVP_PKEY *pkey = NULL; + X509 *cert = NULL; + BIO *bio = NULL; + + if (ctx->config->cert_mem != NULL) { + if (SSL_CTX_use_certificate_chain(ctx->ssl_ctx, + ctx->config->cert_mem, ctx->config->cert_len) != 1) { + tls_set_error(ctx, "failed to load certificate"); + goto err; + } + cert = NULL; + } + if (ctx->config->key_mem != NULL) { + if ((bio = BIO_new_mem_buf(ctx->config->key_mem, + ctx->config->key_len)) == NULL) { + tls_set_error(ctx, "failed to create buffer"); + goto err; + } + if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, + NULL)) == NULL) { + tls_set_error(ctx, "failed to read private key"); + goto err; + } + if (SSL_CTX_use_PrivateKey(ctx->ssl_ctx, pkey) != 1) { + tls_set_error(ctx, "failed to load private key"); + goto err; + } + BIO_free(bio); + bio = NULL; + EVP_PKEY_free(pkey); + pkey = NULL; + } + + if (ctx->config->cert_file != NULL) { + if (SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, + ctx->config->cert_file) != 1) { + tls_set_error(ctx, "failed to load certificate file"); + goto err; + } + } + if (ctx->config->key_file != NULL) { + if (SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, + ctx->config->key_file, SSL_FILETYPE_PEM) != 1) { + tls_set_error(ctx, "failed to load private key file"); + goto err; + } + } + + if (SSL_CTX_check_private_key(ctx->ssl_ctx) != 1) { + tls_set_error(ctx, "private/public key mismatch"); + goto err; + } + + return (0); + +err: + EVP_PKEY_free(pkey); + X509_free(cert); + BIO_free(bio); + + return (1); +} + +int +tls_configure_ssl(struct tls *ctx) +{ + SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2); + SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv3); + + SSL_CTX_clear_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1); + SSL_CTX_clear_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_1); + SSL_CTX_clear_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_2); + + if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_0) == 0) + SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1); + if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_1) == 0) + SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_1); + if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_2) == 0) + SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_2); + + if (ctx->config->ciphers != NULL) { + if (SSL_CTX_set_cipher_list(ctx->ssl_ctx, + ctx->config->ciphers) != 1) { + tls_set_error(ctx, "failed to set ciphers"); + goto err; + } + } + + return (0); + +err: + return (-1); +} + +void +tls_free(struct tls *ctx) +{ + if (ctx == NULL) + return; + tls_reset(ctx); + free(ctx); +} + +void +tls_reset(struct tls *ctx) +{ + SSL_CTX_free(ctx->ssl_ctx); + SSL_free(ctx->ssl_conn); + + ctx->ssl_conn = NULL; + ctx->ssl_ctx = NULL; + + ctx->socket = -1; + + ctx->err = 0; + free(ctx->errmsg); + ctx->errmsg = NULL; +} + +int +tls_read(struct tls *ctx, void *buf, size_t buflen, size_t *outlen) +{ + int ret, ssl_err; + + ret = SSL_read(ctx->ssl_conn, buf, buflen); + if (ret > 0) { + *outlen = (size_t)ret; + return (0); + } + + ssl_err = SSL_get_error(ctx->ssl_conn, ret); + switch (ssl_err) { + case SSL_ERROR_WANT_READ: + return (TLS_READ_AGAIN); + case SSL_ERROR_WANT_WRITE: + return (TLS_WRITE_AGAIN); + default: + tls_set_error(ctx, "read failed (%i)", ssl_err); + return (-1); + } +} + +int +tls_write(struct tls *ctx, const void *buf, size_t buflen, size_t *outlen) +{ + int ret, ssl_err; + + ret = SSL_write(ctx->ssl_conn, buf, buflen); + if (ret > 0) { + *outlen = (size_t)ret; + return (0); + } + + ssl_err = SSL_get_error(ctx->ssl_conn, ret); + switch (ssl_err) { + case SSL_ERROR_WANT_READ: + return (TLS_READ_AGAIN); + case SSL_ERROR_WANT_WRITE: + return (TLS_WRITE_AGAIN); + default: + tls_set_error(ctx, "write failed (%i)", ssl_err); + return (-1); + } +} + +int +tls_close(struct tls *ctx) +{ + /* XXX - handle case where multiple calls are required. */ + if (ctx->ssl_conn != NULL) { + if (SSL_shutdown(ctx->ssl_conn) == -1) { + tls_set_error(ctx, "SSL shutdown failed"); + goto err; + } + } + + if (ctx->socket != -1) { + if (shutdown(ctx->socket, SHUT_RDWR) != 0) { + tls_set_error(ctx, "shutdown"); + goto err; + } + if (close(ctx->socket) != 0) { + tls_set_error(ctx, "close"); + goto err; + } + ctx->socket = -1; + } + + return (0); + +err: + return (-1); +} diff --git a/src/lib/libtls/tls.h b/src/lib/libtls/tls.h new file mode 100644 index 0000000000..0fa776e584 --- /dev/null +++ b/src/lib/libtls/tls.h @@ -0,0 +1,74 @@ +/* $OpenBSD: tls.h,v 1.1 2014/10/31 13:46:17 jsing Exp $ */ +/* + * Copyright (c) 2014 Joel Sing + * + * 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_TLS_H +#define HEADER_TLS_H + +#define TLS_API 20141031 + +#define TLS_PROTOCOL_TLSv1_0 (1 << 1) +#define TLS_PROTOCOL_TLSv1_1 (1 << 2) +#define TLS_PROTOCOL_TLSv1_2 (1 << 3) +#define TLS_PROTOCOL_TLSv1 \ + (TLS_PROTOCOL_TLSv1_0|TLS_PROTOCOL_TLSv1_1|TLS_PROTOCOL_TLSv1_2) +#define TLS_PROTOCOLS_DEFAULT TLS_PROTOCOL_TLSv1 + +#define TLS_READ_AGAIN -2 +#define TLS_WRITE_AGAIN -3 + +struct tls; +struct tls_config; + +int tls_init(void); + +const char *tls_error(struct tls *ctx); + +struct tls_config *tls_config_new(void); +void tls_config_free(struct tls_config *config); + +int tls_config_set_ca_file(struct tls_config *config, const char *ca_file); +int tls_config_set_ca_path(struct tls_config *config, const char *ca_path); +int tls_config_set_cert_file(struct tls_config *config, const char *cert_file); +int tls_config_set_cert_mem(struct tls_config *config, const uint8_t *cert, + size_t len); +int tls_config_set_ciphers(struct tls_config *config, const char *ciphers); +int tls_config_set_ecdhcurve(struct tls_config *config, const char *name); +int tls_config_set_key_file(struct tls_config *config, const char *key_file); +int tls_config_set_key_mem(struct tls_config *config, const uint8_t *key, + size_t len); +void tls_config_set_protocols(struct tls_config *config, uint32_t protocols); +void tls_config_set_verify_depth(struct tls_config *config, int verify_depth); + +void tls_config_clear_keys(struct tls_config *config); +void tls_config_insecure_noverifyhost(struct tls_config *config); +void tls_config_insecure_noverifycert(struct tls_config *config); +void tls_config_verify(struct tls_config *config); + +struct tls *tls_client(void); +struct tls *tls_server(void); +int tls_configure(struct tls *ctx, struct tls_config *config); +void tls_reset(struct tls *ctx); +void tls_free(struct tls *ctx); + +int tls_accept_socket(struct tls *ctx, struct tls **cctx, int socket); +int tls_connect(struct tls *ctx, const char *host, const char *port); +int tls_connect_socket(struct tls *ctx, int s, const char *hostname); +int tls_read(struct tls *ctx, void *buf, size_t buflen, size_t *outlen); +int tls_write(struct tls *ctx, const void *buf, size_t buflen, size_t *outlen); +int tls_close(struct tls *ctx); + +#endif /* HEADER_TLS_H */ diff --git a/src/lib/libtls/tls_client.c b/src/lib/libtls/tls_client.c new file mode 100644 index 0000000000..853766f87b --- /dev/null +++ b/src/lib/libtls/tls_client.c @@ -0,0 +1,212 @@ +/* $OpenBSD: tls_client.c,v 1.1 2014/10/31 13:46:17 jsing Exp $ */ +/* + * Copyright (c) 2014 Joel Sing + * + * 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 +#include + +#include + +#include +#include +#include + +#include + +#include +#include "tls_internal.h" + +struct tls * +tls_client(void) +{ + struct tls *ctx; + + if ((ctx = tls_new()) == NULL) + return (NULL); + + ctx->flags |= TLS_CLIENT; + + return (ctx); +} + +int +tls_connect(struct tls *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 ((ctx->flags & TLS_CLIENT) == 0) { + tls_set_error(ctx, "not a client context"); + goto err; + } + + if (host == NULL) { + tls_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 = tls_host_port(host, &hs, &ps); + if (ret == -1) { + tls_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) { + tls_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) { + tls_set_error(ctx, "socket"); + continue; + } + if (connect(s, res->ai_addr, res->ai_addrlen) == -1) { + tls_set_error(ctx, "connect"); + close(s); + s = -1; + continue; + } + + break; /* Connected. */ + } + freeaddrinfo(res0); + + if (s == -1) + goto err; + + if (tls_connect_socket(ctx, s, h) != 0) { + close(s); + goto err; + } + + rv = 0; + +err: + + free(hs); + free(ps); + + return (rv); +} + +int +tls_connect_socket(struct tls *ctx, int socket, const char *hostname) +{ + union { struct in_addr ip4; struct in6_addr ip6; } addrbuf; + X509 *cert = NULL; + int ret; + + if ((ctx->flags & TLS_CLIENT) == 0) { + tls_set_error(ctx, "not a client context"); + goto err; + } + + ctx->socket = socket; + + if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) { + tls_set_error(ctx, "ssl context failure"); + goto err; + } + + if (tls_configure_ssl(ctx) != 0) + goto err; + + if (ctx->config->verify_host) { + if (hostname == NULL) { + tls_set_error(ctx, "server name not specified"); + goto err; + } + } + + if (ctx->config->verify_cert) { + 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) { + tls_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) { + tls_set_error(ctx, "ssl connection failure"); + goto err; + } + if (SSL_set_fd(ctx->ssl_conn, ctx->socket) != 1) { + tls_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) { + tls_set_error(ctx, "SNI host name failed"); + goto err; + } + } + + if ((ret = SSL_connect(ctx->ssl_conn)) != 1) { + tls_set_error(ctx, "SSL connect failed: %i", + SSL_get_error(ctx->ssl_conn, ret)); + goto err; + } + + if (ctx->config->verify_host) { + cert = SSL_get_peer_certificate(ctx->ssl_conn); + if (cert == NULL) { + tls_set_error(ctx, "no server certificate"); + goto err; + } + if (tls_check_hostname(cert, hostname) != 0) { + tls_set_error(ctx, "host `%s' not present in" + " server certificate", hostname); + goto err; + } + } + + return (0); + +err: + X509_free(cert); + + return (-1); +} diff --git a/src/lib/libtls/tls_config.c b/src/lib/libtls/tls_config.c new file mode 100644 index 0000000000..0e435f616a --- /dev/null +++ b/src/lib/libtls/tls_config.c @@ -0,0 +1,201 @@ +/* $OpenBSD: tls_config.c,v 1.1 2014/10/31 13:46:17 jsing Exp $ */ +/* + * Copyright (c) 2014 Joel Sing + * + * 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 +#include + +#include +#include "tls_internal.h" + +static int +set_string(const char **dest, const char *src) +{ + free((char *)*dest); + *dest = NULL; + if (src != NULL) + if ((*dest = strdup(src)) == NULL) + return -1; + return 0; +} + +static void * +memdup(const void *in, size_t len) +{ + void *out; + + if ((out = malloc(len)) == NULL) + return NULL; + memcpy(out, in, len); + return out; +} + +static int +set_mem(char **dest, size_t *destlen, const void *src, size_t srclen) +{ + free(*dest); + *dest = NULL; + *destlen = 0; + if (src != NULL) + if ((*dest = memdup(src, srclen)) == NULL) + return -1; + *destlen = srclen; + return 0; +} + +struct tls_config * +tls_config_new(void) +{ + struct tls_config *config; + + if ((config = calloc(1, sizeof(*config))) == NULL) + return (NULL); + + /* + * Default configuration. + */ + if (tls_config_set_ca_file(config, _PATH_SSL_CA_FILE) != 0) { + tls_config_free(config); + return (NULL); + } + tls_config_set_ecdhcurve(config, "auto"); + tls_config_set_protocols(config, TLS_PROTOCOLS_DEFAULT); + tls_config_set_verify_depth(config, 6); + + tls_config_verify(config); + + return (config); +} + +void +tls_config_free(struct tls_config *config) +{ + if (config == NULL) + return; + + tls_config_clear_keys(config); + + free((char *)config->ca_file); + free((char *)config->ca_path); + free((char *)config->cert_file); + free(config->cert_mem); + free((char *)config->ciphers); + free((char *)config->key_file); + free(config->key_mem); + + free(config); +} + +void +tls_config_clear_keys(struct tls_config *config) +{ + tls_config_set_cert_mem(config, NULL, 0); + tls_config_set_key_mem(config, NULL, 0); +} + +int +tls_config_set_ca_file(struct tls_config *config, const char *ca_file) +{ + return set_string(&config->ca_file, ca_file); +} + +int +tls_config_set_ca_path(struct tls_config *config, const char *ca_path) +{ + return set_string(&config->ca_path, ca_path); +} + +int +tls_config_set_cert_file(struct tls_config *config, const char *cert_file) +{ + return set_string(&config->cert_file, cert_file); +} + +int +tls_config_set_cert_mem(struct tls_config *config, const uint8_t *cert, + size_t len) +{ + return set_mem(&config->cert_mem, &config->cert_len, cert, len); +} + +int +tls_config_set_ciphers(struct tls_config *config, const char *ciphers) +{ + return set_string(&config->ciphers, ciphers); +} + +int +tls_config_set_ecdhcurve(struct tls_config *config, const char *name) +{ + int nid; + + if (name == NULL) + nid = NID_undef; + else if (strcasecmp(name, "auto") == 0) + nid = -1; + else if ((nid = OBJ_txt2nid(name)) == NID_undef) + return (-1); + + config->ecdhcurve = nid; + + return (0); +} + +int +tls_config_set_key_file(struct tls_config *config, const char *key_file) +{ + return set_string(&config->key_file, key_file); +} + +int +tls_config_set_key_mem(struct tls_config *config, const uint8_t *key, + size_t len) +{ + if (config->key_mem) + explicit_bzero(config->key_mem, config->key_len); + return set_mem(&config->key_mem, &config->key_len, key, len); +} + +void +tls_config_set_protocols(struct tls_config *config, uint32_t protocols) +{ + config->protocols = protocols; +} + +void +tls_config_set_verify_depth(struct tls_config *config, int verify_depth) +{ + config->verify_depth = verify_depth; +} + +void +tls_config_insecure_noverifyhost(struct tls_config *config) +{ + config->verify_host = 0; +} + +void +tls_config_insecure_noverifycert(struct tls_config *config) +{ + config->verify_cert = 0; +} + +void +tls_config_verify(struct tls_config *config) +{ + config->verify_host = 1; + config->verify_cert = 1; +} diff --git a/src/lib/libtls/tls_init.3 b/src/lib/libtls/tls_init.3 new file mode 100644 index 0000000000..faa9b99539 --- /dev/null +++ b/src/lib/libtls/tls_init.3 @@ -0,0 +1,316 @@ +.\" $OpenBSD: tls_init.3,v 1.1 2014/10/31 13:46:17 jsing Exp $ +.\" +.\" Copyright (c) 2014 Ted Unangst +.\" +.\" 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. +.\" +.Dd $Mdocdate: October 31 2014 $ +.Dt TLS 3 +.Os +.Sh NAME +.Nm tls_init , +.Nm tls_error , +.Nm tls_config_new , +.Nm tls_config_free , +.Nm tls_config_set_ca_file , +.Nm tls_config_set_ca_path , +.Nm tls_config_set_cert_file , +.Nm tls_config_set_cert_mem , +.Nm tls_config_set_ciphers , +.Nm tls_config_set_ecdhcurve , +.Nm tls_config_set_key_file , +.Nm tls_config_set_key_mem , +.Nm tls_config_set_protocols , +.Nm tls_config_set_verify_depth , +.Nm tls_config_clear_keys , +.Nm tls_config_insecure_noverifyhost , +.Nm tls_config_insecure_noverifycert , +.Nm tls_config_verify , +.Nm tls_client , +.Nm tls_server , +.Nm tls_configure , +.Nm tls_reset , +.Nm tls_close , +.Nm tls_free , +.Nm tls_connect , +.Nm tls_connect_socket , +.Nm tls_read , +.Nm tls_write , +.Nd tls TLS client and server API +.Sh SYNOPSIS +.In tls.h +.Ft "int" +.Fn tls_init "void" +.Ft "const char *" +.Fn tls_error "struct tls *ctx" +.Ft "struct tls_config *" +.Fn tls_config_new "void" +.Ft "void" +.Fn tls_config_free "struct tls_config *config" +.Ft "int" +.Fn tls_config_set_ca_file "struct tls_config *config" "const char *ca_file" +.Ft "int" +.Fn tls_config_set_ca_path "struct tls_config *config" "const char *ca_path" +.Ft "int" +.Fn tls_config_set_cert_file "struct tls_config *config" "const char *cert_file" +.Ft "int" +.Fn tls_config_set_cert_mem "struct tls_config *config" "const uint8_t *cert" "size_t len" +.Ft "int" +.Fn tls_config_set_ciphers "struct tls_config *config" "const char *ciphers" +.Ft "int" +.Fn tls_config_set_ecdhcurve "struct tls_config *config" "const char *name" +.Ft "int" +.Fn tls_config_set_key_file "struct tls_config *config" "const char *key_file" +.Ft "int" +.Fn tls_config_set_key_mem "struct tls_config *config" "const uint8_t *key" "size_t len" +.Ft "int" +.Fn tls_config_set_protocols "struct tls_config *config" "uint32_t protocols" +.Ft "int" +.Fn tls_config_set_verify_depth "struct tls_config *config" "int verify_depth" +.Ft "void" +.Fn tls_config_clear_keys "struct tls_config *config" +.Ft "void" +.Fn tls_config_insecure_noverifyhost "struct tls_config *config" +.Ft "void" +.Fn tls_config_insecure_noverifycert "struct tls_config *config" +.Ft "void" +.Fn tls_config_verify "struct tls_config *config" +.Ft "struct tls *" +.Fn tls_client void +.Ft "struct tls *" +.Fn tls_server void +.Ft "int" +.Fn tls_configure "struct tls *ctx" "struct tls_config *config" +.Ft "void" +.Fn tls_reset "struct tls *ctx" +.Ft "int" +.Fn tls_close "struct tls *ctx" +.Ft "void" +.Fn tls_free "struct tls *ctx" +.Ft "int" +.Fn tls_connect "struct tls *ctx" "const char *host" "const char *port" +.Ft "int" +.Fn tls_connect_socket "struct tls *ctx" "int s" "const char *hostname" +.Ft "int" +.Fn tls_read "struct tls *ctx" "void *buf" "size_t buflen" "size_t *outlen" +.Ft "int" +.Fn tls_write "struct tls *ctx" "const void *buf" "size_t buflen" +.Sh DESCRIPTION +The +.Nm tls +family of functions establishes a secure communications channel +using the TLS socket protocol. +Both clients and servers are supported. +.Pp +The +.Fn tls_init +function should be called once before any function is used. +.Pp +Before a connection is created, a configuration must be created. +The +.Fn tls_config_new +function returns a new default configuration that can be used for future +connections. +Several functions exist to change the options of the configuration; see below. +.Pp +A +.Em tls +connection is represented as a +.Em context . +A new +.Em context +is created by either the +.Fn tls_client +or +.Fn tls_server +functions. +The context can then be configured with the function +.Fn tls_configure . +The same +.Em tls_config +object can be used to configure multiple contexts. +.Pp +A client connection is initiated after configuration by calling +.Fn tls_connect . +This function will create a new socket, connect to the specified host and +port, and then establish a secure connection. +An already existing socket can be upgraded to a secure connection by calling +.Fn tls_connect_socket . +.Pp +Two functions are provided for input and output, +.Fn tls_read +and +.Fn tls_write . +.Pp +After use, a tls +.Em context +should be closed with +.Fn tls_close , +and then freed by calling +.Fn tls_free . +When no more contexts are to be created, the +.Em tls_config +object should be freed by calling +.Fn tls_config_free . +.Sh FUNCTIONS +The +.Fn tls_init +function initializes global data structures. +It should be called once before any other functions. +.Pp +The following functions create and free configuration objects. +.Bl -bullet -offset four +.It +.Fn tls_config_new +allocates a new default configuration object. +.It +.Fn tls_config_free +frees a configuration object. +.El +.Pp +The following functions modify a configuration by setting parameters. +Configuration options may apply to only clients or only servers or both. +.Bl -bullet -offset four +.It +.Fn tls_config_set_ca_file +sets the filename used to load a file +containing the root certificates. +.Em (Client) +.It +.Fn tls_config_set_ca_path +sets the path (directory) which should be searched for root +certificates. +.Em (Client) +.It +.Fn tls_config_set_cert_file +sets file from which the public certificate will be read. +.Em (Client and server) +.It +.Fn tls_config_set_cert_mem +sets the public certificate directly from memory. +.Em (Client and server) +.It +.Fn tls_config_set_ciphers +sets the list of ciphers that may be used. +.Em (Client and server) +.It +.Fn tls_config_set_key_file +sets the file from which the private key will be read. +.Em (Server) +.It +.Fn tls_config_set_key_mem +directly sets the private key from memory. +.Em (Server) +.It +.Fn tls_config_set_protocols +sets which versions of the protocol may be used. +Possible values are the bitwise OR of: +.Pp +.Bl -tag -width "TLS_PROTOCOL_TLSv1_2" -offset indent -compact +.It Dv TLS_PROTOCOL_TLSv1_0 +.It Dv TLS_PROTOCOL_TLSv1_1 +.It Dv TLS_PROTOCOL_TLSv1_2 +.El +.Pp +Additionally, the values +.Dv TLS_PROTOCOL_TLSv1 +(all TLS versions) and +.Dv TLS_PROTOCOLS_DEFAULT +(currently all TLS versions) may be used. +.Em (Client and server) +.It +.Fn tls_config_clear_keys +clears any secret keys from memory. +.Em (Server) +.It +.Fn tls_config_insecure_noverifyhost +disables hostname verification. +Be careful when using this option. +.Em (Client) +.It +.Fn tls_config_insecure_noverifycert +disables certificate verification. +Be extremely careful when using this option. +.Em (Client) +.It +.Fn tls_config_verify +reenables hostname and certificate verification. +.Em (Client) +.El +.Pp +The following functions create, prepare, and free a connection context. +.Bl -bullet -offset four +.It +.Fn tls_client +creates a new tls context for client connections. +.It +.Fn tls_server +creates a new tls context for server connections. +.It +.Fn tls_configure +readies a tls context for use by applying the configuration +options. +.It +.Fn tls_close +closes a connection after use. +.It +.Fn tls_free +frees a tls context after use. +.El +.Pp +The following functions initiate a connection and perform input and output +operations. +.Bl -bullet -offset four +.It +.Fn tls_connect +connects a client context to the server named by +.Fa host . +The +.Fa port +may be numeric or a service name. +If it is NULL then a host of the format "hostname:port" is permitted. +.It +.Fn tls_connect_socket +connects a client context to an already established socket connection. +.It +.Fn tls_read +reads +.Fa buflen +bytes of data from the socket into +.Fa buf . +The amount of data read is returned in +.Fa outlen . +.It +.Fn tls_write +writes +.Fa buflen +bytes of data from +.Fa buf +to the socket. +The amount of data written is returned in +.Fa outlen . +.El +.Sh RETURN VALUES +Functions that return +.Vt int +will return 0 on success and -1 on error. +Functions that return a pointer will return NULL on error. +.\" .Sh ERRORS +.\" .Sh SEE ALSO +.Sh HISTORY +The +.Nm tls +API first appeared in +.Ox 5.6 +as a response to the unnecessary challenges other APIs present in +order to use them safely. diff --git a/src/lib/libtls/tls_internal.h b/src/lib/libtls/tls_internal.h new file mode 100644 index 0000000000..da696e228d --- /dev/null +++ b/src/lib/libtls/tls_internal.h @@ -0,0 +1,72 @@ +/* $OpenBSD: tls_internal.h,v 1.1 2014/10/31 13:46:17 jsing Exp $ */ +/* + * Copyright (c) 2014 Jeremie Courreges-Anglas + * Copyright (c) 2014 Joel Sing + * + * 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_TLS_INTERNAL_H +#define HEADER_TLS_INTERNAL_H + +#include + +#define HTTPS_PORT "443" + +#define _PATH_SSL_CA_FILE "/etc/ssl/cert.pem" + +struct tls_config { + const char *ca_file; + const char *ca_path; + const char *cert_file; + char *cert_mem; + size_t cert_len; + const char *ciphers; + int ecdhcurve; + const char *key_file; + char *key_mem; + size_t key_len; + uint32_t protocols; + int verify_cert; + int verify_host; + int verify_depth; +}; + +#define TLS_CLIENT (1 << 0) +#define TLS_SERVER (1 << 1) +#define TLS_SERVER_CONN (1 << 2) + +struct tls { + struct tls_config *config; + uint64_t flags; + + int err; + char *errmsg; + + int socket; + + SSL *ssl_conn; + SSL_CTX *ssl_ctx; +}; + +struct tls *tls_new(void); +struct tls *tls_server_conn(struct tls *ctx); + +int tls_check_hostname(X509 *cert, const char *host); +int tls_configure_keypair(struct tls *ctx); +int tls_configure_server(struct tls *ctx); +int tls_configure_ssl(struct tls *ctx); +int tls_host_port(const char *hostport, char **host, char **port); +int tls_set_error(struct tls *ctx, char *fmt, ...); + +#endif /* HEADER_TLS_INTERNAL_H */ diff --git a/src/lib/libtls/tls_server.c b/src/lib/libtls/tls_server.c new file mode 100644 index 0000000000..001f19ded4 --- /dev/null +++ b/src/lib/libtls/tls_server.c @@ -0,0 +1,134 @@ +/* $OpenBSD: tls_server.c,v 1.1 2014/10/31 13:46:17 jsing Exp $ */ +/* + * Copyright (c) 2014 Joel Sing + * + * 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 +#include + +#include +#include "tls_internal.h" + +struct tls * +tls_server(void) +{ + struct tls *ctx; + + if ((ctx = tls_new()) == NULL) + return (NULL); + + ctx->flags |= TLS_SERVER; + + return (ctx); +} + +struct tls * +tls_server_conn(struct tls *ctx) +{ + struct tls *conn_ctx; + + if ((conn_ctx = tls_new()) == NULL) + return (NULL); + + conn_ctx->flags |= TLS_SERVER_CONN; + + return (conn_ctx); +} + +int +tls_configure_server(struct tls *ctx) +{ + EC_KEY *ecdh_key; + + if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) { + tls_set_error(ctx, "ssl context failure"); + goto err; + } + + if (tls_configure_ssl(ctx) != 0) + goto err; + if (tls_configure_keypair(ctx) != 0) + goto err; + + if (ctx->config->ecdhcurve == -1) { + SSL_CTX_set_ecdh_auto(ctx->ssl_ctx, 1); + } else if (ctx->config->ecdhcurve != NID_undef) { + if ((ecdh_key = EC_KEY_new_by_curve_name( + ctx->config->ecdhcurve)) == NULL) { + tls_set_error(ctx, "failed to set ECDH curve"); + goto err; + } + SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_SINGLE_ECDH_USE); + SSL_CTX_set_tmp_ecdh(ctx->ssl_ctx, ecdh_key); + EC_KEY_free(ecdh_key); + } + + return (0); + +err: + return (-1); +} + +int +tls_accept_socket(struct tls *ctx, struct tls **cctx, int socket) +{ + struct tls *conn_ctx = *cctx; + int ret, ssl_err; + + if ((ctx->flags & TLS_SERVER) == 0) { + tls_set_error(ctx, "not a server context"); + goto err; + } + + if (conn_ctx == NULL) { + if ((conn_ctx = tls_server_conn(ctx)) == NULL) { + tls_set_error(ctx, "connection context failure"); + goto err; + } + *cctx = conn_ctx; + + conn_ctx->socket = socket; + + if ((conn_ctx->ssl_conn = SSL_new(ctx->ssl_ctx)) == NULL) { + tls_set_error(ctx, "ssl failure"); + goto err; + } + + if (SSL_set_fd(conn_ctx->ssl_conn, socket) != 1) { + tls_set_error(ctx, "ssl set fd failure"); + goto err; + } + SSL_set_app_data(conn_ctx->ssl_conn, conn_ctx); + } + + if ((ret = SSL_accept(conn_ctx->ssl_conn)) != 1) { + ssl_err = SSL_get_error(conn_ctx->ssl_conn, ret); + switch (ssl_err) { + case SSL_ERROR_WANT_READ: + return (TLS_READ_AGAIN); + case SSL_ERROR_WANT_WRITE: + return (TLS_WRITE_AGAIN); + default: + tls_set_error(ctx, "ssl accept failure (%i)", + ssl_err); + goto err; + } + } + + return (0); + +err: + return (-1); +} diff --git a/src/lib/libtls/tls_util.c b/src/lib/libtls/tls_util.c new file mode 100644 index 0000000000..2adfb674b8 --- /dev/null +++ b/src/lib/libtls/tls_util.c @@ -0,0 +1,81 @@ +/* $OpenBSD: tls_util.c,v 1.1 2014/10/31 13:46:17 jsing Exp $ */ +/* + * Copyright (c) 2014 Joel Sing + * + * 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 + +#include "tls_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 +tls_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/src/lib/libtls/tls_verify.c b/src/lib/libtls/tls_verify.c new file mode 100644 index 0000000000..fa0010922f --- /dev/null +++ b/src/lib/libtls/tls_verify.c @@ -0,0 +1,225 @@ +/* $OpenBSD: tls_verify.c,v 1.1 2014/10/31 13:46:17 jsing Exp $ */ +/* + * Copyright (c) 2014 Jeremie Courreges-Anglas + * + * 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 + +#include +#include + +#include + +#include + +#include "tls_internal.h" + +int tls_match_hostname(const char *cert_hostname, const char *hostname); +int tls_check_subject_altname(X509 *cert, const char *host); +int tls_check_common_name(X509 *cert, const char *host); + +int +tls_match_hostname(const char *cert_hostname, const char *hostname) +{ + const char *cert_domain, *domain, *next_dot; + + if (strcasecmp(cert_hostname, hostname) == 0) + return 0; + + /* Wildcard match? */ + if (cert_hostname[0] == '*') { + /* + * Valid wildcards: + * - "*.domain.tld" + * - "*.sub.domain.tld" + * - etc. + * Reject "*.tld". + * No attempt to prevent the use of eg. "*.co.uk". + */ + cert_domain = &cert_hostname[1]; + /* Disallow "*" */ + if (cert_domain[0] == '\0') + return -1; + /* Disallow "*foo" */ + if (cert_domain[0] != '.') + return -1; + /* Disallow "*.." */ + if (cert_domain[1] == '.') + return -1; + next_dot = strchr(&cert_domain[1], '.'); + /* Disallow "*.bar" */ + if (next_dot == NULL) + return -1; + /* Disallow "*.bar.." */ + if (next_dot[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 +tls_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 (tls_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 +tls_check_common_name(X509 *cert, const char *host) +{ + X509_NAME *name; + char *common_name = NULL; + int common_name_len; + int rv = -1; + union { struct in_addr ip4; struct in6_addr ip6; } addrbuf; + + 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 (inet_pton(AF_INET, host, &addrbuf) == 1 || + inet_pton(AF_INET6, host, &addrbuf) == 1) { + /* + * We don't want to attempt wildcard matching against IP + * addresses, so perform a simple comparison here. + */ + if (strcmp(common_name, host) == 0) + rv = 0; + else + rv = -1; + goto out; + } + + if (tls_match_hostname(common_name, host) == 0) + rv = 0; +out: + free(common_name); + return rv; +} + +int +tls_check_hostname(X509 *cert, const char *host) +{ + int rv; + + rv = tls_check_subject_altname(cert, host); + if (rv == 0 || rv == -2) + return rv; + + return tls_check_common_name(cert, host); +} -- cgit v1.2.3-55-g6feb