diff options
-rw-r--r-- | LIBTLS_VERSION | 2 | ||||
-rw-r--r-- | VERSION | 2 | ||||
-rw-r--r-- | compat/posix_win.c | 113 | ||||
-rw-r--r-- | include/compat/sys/types.h | 12 | ||||
-rw-r--r-- | include/compat/unistd.h | 4 | ||||
-rw-r--r-- | include/tls.h | 14 | ||||
-rw-r--r-- | man/tls_config_set_protocols.3 | 12 | ||||
-rw-r--r-- | tls.c | 10 | ||||
-rw-r--r-- | tls_config.c | 6 | ||||
-rw-r--r-- | tls_internal.h | 6 | ||||
-rw-r--r-- | tls_signer.c | 15 | ||||
-rw-r--r-- | tls_verify.c | 101 |
12 files changed, 204 insertions, 93 deletions
diff --git a/LIBTLS_VERSION b/LIBTLS_VERSION index 6e2f32a..fd02cce 100644 --- a/LIBTLS_VERSION +++ b/LIBTLS_VERSION @@ -1 +1 @@ -27:0:0 +28:0:0 diff --git a/VERSION b/VERSION index 6641052..1693986 100644 --- a/VERSION +++ b/VERSION @@ -1,2 +1,2 @@ -3.8.0 +3.8.1 diff --git a/compat/posix_win.c b/compat/posix_win.c index 30c93cd..b3a4687 100644 --- a/compat/posix_win.c +++ b/compat/posix_win.c @@ -148,6 +148,49 @@ wsa_errno(int err) return -1; } +/* + * Employ a similar trick to cpython (pycore_fileutils.h) where the CRT report + * handler is disabled while checking if a descriptor is a socket or a file + */ +#if defined _MSC_VER && _MSC_VER >= 1900 + +#include <crtdbg.h> +#include <stdlib.h> + +static void noop_handler(const wchar_t *expression, const wchar_t *function, + const wchar_t *file, unsigned int line, uintptr_t pReserved) +{ + return; +} + +#define BEGIN_SUPPRESS_IPH \ + _invalid_parameter_handler old_handler = _set_thread_local_invalid_parameter_handler(noop_handler) +#define END_SUPPRESS_IPH \ + _set_thread_local_invalid_parameter_handler(old_handler) + +#else + +#define BEGIN_SUPPRESS_IPH +#define END_SUPPRESS_IPH + +#endif + +static int +is_socket(int fd) +{ + intptr_t hd; + + BEGIN_SUPPRESS_IPH; + hd = _get_osfhandle(fd); + END_SUPPRESS_IPH; + + if (hd == (intptr_t)INVALID_HANDLE_VALUE) { + return 1; /* fd is not file descriptor */ + } + + return 0; +} + int posix_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { @@ -160,24 +203,31 @@ posix_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) int posix_close(int fd) { - if (closesocket(fd) == SOCKET_ERROR) { - int err = WSAGetLastError(); - return (err == WSAENOTSOCK || err == WSAEBADF || - err == WSANOTINITIALISED) ? - close(fd) : wsa_errno(err); + int rc; + + if (is_socket(fd)) { + if ((rc = closesocket(fd)) == SOCKET_ERROR) { + int err = WSAGetLastError(); + rc = wsa_errno(err); + } + } else { + rc = close(fd); } - return 0; + return rc; } ssize_t posix_read(int fd, void *buf, size_t count) { - ssize_t rc = recv(fd, buf, count, 0); - if (rc == SOCKET_ERROR) { - int err = WSAGetLastError(); - return (err == WSAENOTSOCK || err == WSAEBADF || - err == WSANOTINITIALISED) ? - read(fd, buf, count) : wsa_errno(err); + ssize_t rc; + + if (is_socket(fd)) { + if ((rc = recv(fd, buf, count, 0)) == SOCKET_ERROR) { + int err = WSAGetLastError(); + rc = wsa_errno(err); + } + } else { + rc = read(fd, buf, count); } return rc; } @@ -185,12 +235,13 @@ posix_read(int fd, void *buf, size_t count) ssize_t posix_write(int fd, const void *buf, size_t count) { - ssize_t rc = send(fd, buf, count, 0); - if (rc == SOCKET_ERROR) { - int err = WSAGetLastError(); - return (err == WSAENOTSOCK || err == WSAEBADF || - err == WSANOTINITIALISED) ? - write(fd, buf, count) : wsa_errno(err); + ssize_t rc; + if (is_socket(fd)) { + if ((rc = send(fd, buf, count, 0)) == SOCKET_ERROR) { + rc = wsa_errno(WSAGetLastError()); + } + } else { + rc = write(fd, buf, count); } return rc; } @@ -199,17 +250,32 @@ int posix_getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen) { - int rc = getsockopt(sockfd, level, optname, (char *)optval, optlen); - return rc == 0 ? 0 : wsa_errno(WSAGetLastError()); - + int rc; + if (is_socket(sockfd)) { + rc = getsockopt(sockfd, level, optname, (char *)optval, optlen); + if (rc != 0) { + rc = wsa_errno(WSAGetLastError()); + } + } else { + rc = -1; + } + return rc; } int posix_setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) { - int rc = setsockopt(sockfd, level, optname, (char *)optval, optlen); - return rc == 0 ? 0 : wsa_errno(WSAGetLastError()); + int rc; + if (is_socket(sockfd)) { + rc = setsockopt(sockfd, level, optname, (char *)optval, optlen); + if (rc != 0) { + rc = wsa_errno(WSAGetLastError()); + } + } else { + rc = -1; + } + return rc; } uid_t getuid(void) @@ -241,5 +307,4 @@ int gettimeofday(struct timeval * tp, struct timezone * tzp) tp->tv_usec = (long)(system_time.wMilliseconds * 1000); return 0; } - #endif diff --git a/include/compat/sys/types.h b/include/compat/sys/types.h index 4967843..59664bc 100644 --- a/include/compat/sys/types.h +++ b/include/compat/sys/types.h @@ -45,18 +45,6 @@ typedef SSIZE_T ssize_t; #endif -#if !defined(HAVE_ATTRIBUTE__BOUNDED__) && !defined(__bounded__) -# define __bounded__(x, y, z) -#endif - -#if !defined(HAVE_ATTRIBUTE__DEAD) && !defined(__dead) -#ifdef _MSC_VER -#define __dead __declspec(noreturn) -#else -#define __dead __attribute__((__noreturn__)) -#endif -#endif - #ifdef _WIN32 #define __warn_references(sym,msg) #else diff --git a/include/compat/unistd.h b/include/compat/unistd.h index 5e6ab1d..2583a6e 100644 --- a/include/compat/unistd.h +++ b/include/compat/unistd.h @@ -64,6 +64,10 @@ int getentropy(void *buf, size_t buflen); #endif #endif +#ifndef HAVE_GETOPT +#include <getopt.h> +#endif + #ifndef HAVE_GETPAGESIZE int getpagesize(void); #endif diff --git a/include/tls.h b/include/tls.h index 0c9e497..59b2c4c 100644 --- a/include/tls.h +++ b/include/tls.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tls.h,v 1.62 2022/03/24 15:56:34 tb Exp $ */ +/* $OpenBSD: tls.h,v 1.63 2023/07/02 06:37:27 beck Exp $ */ /* * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> * @@ -36,14 +36,18 @@ typedef SSIZE_T ssize_t; #define TLS_API 20200120 -#define TLS_PROTOCOL_TLSv1_0 (1 << 1) -#define TLS_PROTOCOL_TLSv1_1 (1 << 2) +/* + * Deprecated versions of TLS. Using these effectively selects + * the minimum supported version. + */ +#define TLS_PROTOCOL_TLSv1_0 (1 << 3) +#define TLS_PROTOCOL_TLSv1_1 (1 << 3) +/* Supported versions of TLS */ #define TLS_PROTOCOL_TLSv1_2 (1 << 3) #define TLS_PROTOCOL_TLSv1_3 (1 << 4) #define TLS_PROTOCOL_TLSv1 \ - (TLS_PROTOCOL_TLSv1_0|TLS_PROTOCOL_TLSv1_1|\ - TLS_PROTOCOL_TLSv1_2|TLS_PROTOCOL_TLSv1_3) + (TLS_PROTOCOL_TLSv1_2|TLS_PROTOCOL_TLSv1_3) #define TLS_PROTOCOLS_ALL TLS_PROTOCOL_TLSv1 #define TLS_PROTOCOLS_DEFAULT (TLS_PROTOCOL_TLSv1_2|TLS_PROTOCOL_TLSv1_3) diff --git a/man/tls_config_set_protocols.3 b/man/tls_config_set_protocols.3 index 7c62493..32b8cce 100644 --- a/man/tls_config_set_protocols.3 +++ b/man/tls_config_set_protocols.3 @@ -1,4 +1,4 @@ -.\" $OpenBSD: tls_config_set_protocols.3,v 1.11 2021/01/02 19:58:44 schwarze Exp $ +.\" $OpenBSD: tls_config_set_protocols.3,v 1.12 2023/07/02 06:37:27 beck Exp $ .\" .\" Copyright (c) 2014 Ted Unangst <tedu@openbsd.org> .\" Copyright (c) 2015, 2016 Joel Sing <jsing@openbsd.org> @@ -16,7 +16,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: January 2 2021 $ +.Dd $Mdocdate: July 2 2023 $ .Dt TLS_CONFIG_SET_PROTOCOLS 3 .Os .Sh NAME @@ -76,10 +76,6 @@ Possible values are the bitwise OR of: .Pp .Bl -item -offset indent -compact .It -.Dv TLS_PROTOCOL_TLSv1_0 -.It -.Dv TLS_PROTOCOL_TLSv1_1 -.It .Dv TLS_PROTOCOL_TLSv1_2 .It .Dv TLS_PROTOCOL_TLSv1_3 @@ -87,7 +83,7 @@ Possible values are the bitwise OR of: .Pp Additionally, the values .Dv TLS_PROTOCOL_TLSv1 -(TLSv1.0, TLSv1.1, TLSv1.2, TLSv1.3), +(TLSv1.2, TLSv1.3), .Dv TLS_PROTOCOLS_ALL (all supported protocols) and .Dv TLS_PROTOCOLS_DEFAULT @@ -106,8 +102,6 @@ The protocol string is a comma or colon separated list of keywords. Valid keywords are: .Pp .Bl -tag -width "tlsv1.3" -offset indent -compact -.It Dv tlsv1.0 -.It Dv tlsv1.1 .It Dv tlsv1.2 .It Dv tlsv1.3 .It Dv all diff --git a/tls.c b/tls.c index 18b93ef..d387952 100644 --- a/tls.c +++ b/tls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tls.c,v 1.96 2023/05/25 07:46:21 op Exp $ */ +/* $OpenBSD: tls.c,v 1.98 2023/07/02 06:37:27 beck Exp $ */ /* * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> * @@ -580,16 +580,12 @@ tls_configure_ssl(struct tls *ctx, SSL_CTX *ssl_ctx) SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2); SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv3); + SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1); + SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_1); - SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TLSv1); - SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TLSv1_1); SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TLSv1_2); SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TLSv1_3); - if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_0) == 0) - SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1); - if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_1) == 0) - SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_1); if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_2) == 0) SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_2); if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_3) == 0) diff --git a/tls_config.c b/tls_config.c index 864ef29..59c69f0 100644 --- a/tls_config.c +++ b/tls_config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tls_config.c,v 1.66 2023/05/14 07:26:25 op Exp $ */ +/* $OpenBSD: tls_config.c,v 1.67 2023/07/02 06:37:27 beck Exp $ */ /* * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> * @@ -251,9 +251,9 @@ tls_config_parse_protocols(uint32_t *protocols, const char *protostr) if (strcasecmp(p, "tlsv1") == 0) proto = TLS_PROTOCOL_TLSv1; else if (strcasecmp(p, "tlsv1.0") == 0) - proto = TLS_PROTOCOL_TLSv1_0; + proto = TLS_PROTOCOL_TLSv1_2; else if (strcasecmp(p, "tlsv1.1") == 0) - proto = TLS_PROTOCOL_TLSv1_1; + proto = TLS_PROTOCOL_TLSv1_2; else if (strcasecmp(p, "tlsv1.2") == 0) proto = TLS_PROTOCOL_TLSv1_2; else if (strcasecmp(p, "tlsv1.3") == 0) diff --git a/tls_internal.h b/tls_internal.h index 7424750..e1dcf35 100644 --- a/tls_internal.h +++ b/tls_internal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tls_internal.h,v 1.81 2023/04/09 18:26:26 tb Exp $ */ +/* $OpenBSD: tls_internal.h,v 1.83 2023/06/27 18:19:59 tb Exp $ */ /* * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org> * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> @@ -28,6 +28,10 @@ __BEGIN_HIDDEN_DECLS +#ifndef TLS_DEFAULT_CA_FILE +#define TLS_DEFAULT_CA_FILE "/etc/ssl/cert.pem" +#endif + #define TLS_CIPHERS_DEFAULT TLS_CIPHERS_COMPAT #define TLS_CIPHERS_COMPAT "HIGH:!aNULL" #define TLS_CIPHERS_LEGACY "HIGH:MEDIUM:!aNULL" diff --git a/tls_signer.c b/tls_signer.c index 97e5e38..76150fd 100644 --- a/tls_signer.c +++ b/tls_signer.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tls_signer.c,v 1.5 2023/04/09 18:26:26 tb Exp $ */ +/* $OpenBSD: tls_signer.c,v 1.9 2023/06/18 19:12:58 tb Exp $ */ /* * Copyright (c) 2021 Eric Faurot <eric@openbsd.org> * @@ -424,17 +424,26 @@ EC_KEY_METHOD * tls_signer_ecdsa_method(void) { static EC_KEY_METHOD *ecdsa_method = NULL; + const EC_KEY_METHOD *default_method; + int (*sign)(int type, const unsigned char *dgst, int dlen, + unsigned char *sig, unsigned int *siglen, + const BIGNUM *kinv, const BIGNUM *r, EC_KEY *eckey); + int (*sign_setup)(EC_KEY *eckey, BN_CTX *ctx_in, + BIGNUM **kinvp, BIGNUM **rp); pthread_mutex_lock(&signer_method_lock); if (ecdsa_method != NULL) goto out; - ecdsa_method = EC_KEY_METHOD_new(NULL); + default_method = EC_KEY_get_default_method(); + ecdsa_method = EC_KEY_METHOD_new(default_method); if (ecdsa_method == NULL) goto out; - EC_KEY_METHOD_set_sign(ecdsa_method, NULL, NULL, tls_ecdsa_do_sign); + EC_KEY_METHOD_get_sign(default_method, &sign, &sign_setup, NULL); + EC_KEY_METHOD_set_sign(ecdsa_method, sign, sign_setup, + tls_ecdsa_do_sign); out: pthread_mutex_unlock(&signer_method_lock); diff --git a/tls_verify.c b/tls_verify.c index 0cb86f6..c588f02 100644 --- a/tls_verify.c +++ b/tls_verify.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tls_verify.c,v 1.23 2023/05/11 07:35:27 tb Exp $ */ +/* $OpenBSD: tls_verify.c,v 1.28 2023/06/01 07:32:25 tb Exp $ */ /* * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org> * @@ -92,15 +92,21 @@ tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name, union tls_addr addrbuf; int addrlen, type; int count, i; - int rv = 0; + int critical = 0; + int rv = -1; *alt_match = 0; *alt_exists = 0; - altname_stack = X509_get_ext_d2i(cert, NID_subject_alt_name, - NULL, NULL); - if (altname_stack == NULL) - return 0; + altname_stack = X509_get_ext_d2i(cert, NID_subject_alt_name, &critical, + NULL); + if (altname_stack == NULL) { + if (critical != -1) { + tls_set_errorx(ctx, "error decoding subjectAltName"); + goto err; + } + goto done; + } if (inet_pton(AF_INET, name, &addrbuf) == 1) { type = GEN_IPADD; @@ -140,8 +146,7 @@ tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name, "NUL byte in subjectAltName, " "probably a malicious certificate", name); - rv = -1; - break; + goto err; } /* @@ -154,13 +159,12 @@ tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name, "error verifying name '%s': " "a dNSName of \" \" must not be " "used", name); - rv = -1; - break; + goto err; } if (tls_match_name(data, name) == 0) { *alt_match = 1; - break; + goto done; } } else { #ifdef DEBUG @@ -181,8 +185,7 @@ tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name, tls_set_errorx(ctx, "Unexpected negative length for an " "IP address: %d", datalen); - rv = -1; - break; + goto err; } /* @@ -192,11 +195,15 @@ tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name, if (datalen == addrlen && memcmp(data, &addrbuf, addrlen) == 0) { *alt_match = 1; - break; + goto done; } } } + done: + rv = 0; + + err: sk_GENERAL_NAME_pop_free(altname_stack, GENERAL_NAME_free); return rv; } @@ -205,10 +212,13 @@ static int tls_check_common_name(struct tls *ctx, X509 *cert, const char *name, int *cn_match) { + unsigned char *utf8_bytes = NULL; X509_NAME *subject_name; char *common_name = NULL; union tls_addr addrbuf; int common_name_len; + ASN1_STRING *data; + int lastpos = -1; int rv = -1; *cn_match = 0; @@ -217,29 +227,65 @@ tls_check_common_name(struct tls *ctx, X509 *cert, const char *name, if (subject_name == NULL) goto done; - common_name_len = X509_NAME_get_text_by_NID(subject_name, - NID_commonName, NULL, 0); - if (common_name_len < 0) + lastpos = X509_NAME_get_index_by_NID(subject_name, + NID_commonName, lastpos); + if (lastpos == -1) goto done; - - common_name = calloc(common_name_len + 1, 1); - if (common_name == NULL) { - tls_set_error(ctx, "out of memory"); + if (lastpos < 0) + goto err; + if (X509_NAME_get_index_by_NID(subject_name, NID_commonName, lastpos) + != -1) { + /* + * Having multiple CN's is possible, and even happened back in + * the glory days of mullets and Hammer pants. In anything like + * a modern TLS cert, CN is as close to deprecated as it gets, + * and having more than one is bad. We therefore fail if we have + * more than one CN fed to us in the subject, treating the + * certificate as hostile. + */ + tls_set_errorx(ctx, "error verifying name '%s': " + "Certificate subject contains mutiple Common Name fields, " + "probably a malicious or malformed certificate", name); goto err; } - X509_NAME_get_text_by_NID(subject_name, NID_commonName, common_name, - common_name_len + 1); - - /* NUL bytes in CN? */ - if (common_name_len < 0 || - (size_t)common_name_len != strlen(common_name)) { + data = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subject_name, + lastpos)); + /* + * Fail if we cannot encode the CN bytes as UTF-8. + */ + if ((common_name_len = ASN1_STRING_to_UTF8(&utf8_bytes, data)) < 0) { + tls_set_errorx(ctx, "error verifying name '%s': " + "Common Name field cannot be encoded as a UTF-8 string, " + "probably a malicious certificate", name); + goto err; + } + /* + * Fail if the CN is of invalid length. RFC 5280 specifies that a CN + * must be between 1 and 64 bytes long. + */ + if (common_name_len < 1 || common_name_len > 64) { + tls_set_errorx(ctx, "error verifying name '%s': " + "Common Name field has invalid length, " + "probably a malicious certificate", name); + goto err; + } + /* + * Fail if the resulting text contains a NUL byte. + */ + if (memchr(utf8_bytes, 0, common_name_len) != NULL) { tls_set_errorx(ctx, "error verifying name '%s': " "NUL byte in Common Name field, " "probably a malicious certificate", name); goto err; } + common_name = strndup(utf8_bytes, common_name_len); + if (common_name == NULL) { + tls_set_error(ctx, "out of memory"); + goto err; + } + /* * We don't want to attempt wildcard matching against IP addresses, * so perform a simple comparison here. @@ -258,6 +304,7 @@ tls_check_common_name(struct tls *ctx, X509 *cert, const char *name, rv = 0; err: + free(utf8_bytes); free(common_name); return rv; } |