summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2026-06-01 14:42:49 -0400
committerJune McEnroe <june@causal.agency>2026-06-01 14:42:49 -0400
commitd08958f5d2c4d71d8132ea5c6cb45e48b5c4d83d (patch)
tree01f7eb5bc8d9d0e708ec077364a6b3fda7f1bdde
parentImport LibreSSL 3.9.2 (diff)
downloadlibretls-d08958f5d2c4d71d8132ea5c6cb45e48b5c4d83d.tar.gz
libretls-d08958f5d2c4d71d8132ea5c6cb45e48b5c4d83d.zip
Import LibreSSL 4.0.0
Diffstat (limited to '')
-rw-r--r--LIBTLS_VERSION2
-rw-r--r--VERSION2
-rw-r--r--compat/arc4random.h3
-rw-r--r--compat/posix_win.c9
-rw-r--r--compat/timegm.c220
-rw-r--r--configure.ac4
-rw-r--r--import.sh1
-rw-r--r--include/Makefile.am1
-rw-r--r--include/compat/sys/time.h9
-rw-r--r--include/compat/time.h9
-rw-r--r--include/tls.h18
-rw-r--r--m4/check-libc.m41
-rw-r--r--m4/check-os-options.m48
-rw-r--r--man/Makefile.am109
-rw-r--r--tls.c176
-rw-r--r--tls_bio_cb.c10
-rw-r--r--tls_client.c90
-rw-r--r--tls_config.c88
-rw-r--r--tls_conninfo.c30
-rw-r--r--tls_internal.h47
-rw-r--r--tls_keypair.c11
-rw-r--r--tls_ocsp.c47
-rw-r--r--tls_server.c55
-rw-r--r--tls_signer.c72
-rw-r--r--tls_verify.c26
25 files changed, 468 insertions, 580 deletions
diff --git a/LIBTLS_VERSION b/LIBTLS_VERSION
index 3857442..a4e70a8 100644
--- a/LIBTLS_VERSION
+++ b/LIBTLS_VERSION
@@ -1 +1 @@
-29:0:0
+31:0:0
diff --git a/VERSION b/VERSION
index 2009c7d..fcdb2e1 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.9.2
+4.0.0
diff --git a/compat/arc4random.h b/compat/arc4random.h
index ffa3239..fbf2dce 100644
--- a/compat/arc4random.h
+++ b/compat/arc4random.h
@@ -30,6 +30,9 @@
 #elif defined(_WIN32)
 #include "arc4random_win.h"
 
+#elif defined(__EMSCRIPTEN__)
+#include "arc4random_linux.h"
+
 #else
 #error "No arc4random hooks defined for this platform."
 
diff --git a/compat/posix_win.c b/compat/posix_win.c
index 3e78a07..bed8c84 100644
--- a/compat/posix_win.c
+++ b/compat/posix_win.c
@@ -9,6 +9,8 @@
 
 #define NO_REDEF_POSIX_FUNCTIONS
 
+#include <sys/time.h>
+
 #include <ws2tcpip.h>
 #include <windows.h>
 
@@ -164,9 +166,10 @@ static void noop_handler(const wchar_t *expression,	const wchar_t *function,
 }
 
 #define BEGIN_SUPPRESS_IPH \
-	int old_report_mode = _CrtSetReportMode(_CRT_ASSERT, 0); \
-	_invalid_parameter_handler old_handler = _set_thread_local_invalid_parameter_handler(noop_handler)
+	const int old_report_mode = _CrtSetReportMode(_CRT_ASSERT, 0); \
+	const _invalid_parameter_handler old_handler = _set_thread_local_invalid_parameter_handler(noop_handler)
 #define END_SUPPRESS_IPH \
+	(void)old_report_mode; /* Silence warning in release mode when _CrtSetReportMode compiles to void. */ \
 	_CrtSetReportMode(_CRT_ASSERT, old_report_mode); \
 	_set_thread_local_invalid_parameter_handler(old_handler)
 
@@ -305,7 +308,7 @@ int gettimeofday(struct timeval * tp, struct timezone * tzp)
 	time = ((uint64_t)file_time.dwLowDateTime);
 	time += ((uint64_t)file_time.dwHighDateTime) << 32;
 
-	tp->tv_sec = (long)((time - EPOCH) / 10000000L);
+	tp->tv_sec = (long long)((time - EPOCH) / 10000000L);
 	tp->tv_usec = (long)(system_time.wMilliseconds * 1000);
 	return 0;
 }
diff --git a/compat/timegm.c b/compat/timegm.c
deleted file mode 100644
index 2658445..0000000
--- a/compat/timegm.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * ----------------------------------------------------------------------
- * Copyright © 2005-2014 Rich Felker, et al.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- * ----------------------------------------------------------------------
- */
-
-#include <errno.h>
-#include <limits.h>
-#include <time.h>
-
-/* 2000-03-01 (mod 400 year, immediately after feb29 */
-#define LEAPOCH (946684800LL + 86400*(31+29))
-
-#define DAYS_PER_400Y (365*400 + 97)
-#define DAYS_PER_100Y (365*100 + 24)
-#define DAYS_PER_4Y   (365*4   + 1)
-
-static int __month_to_secs(int month, int is_leap)
-{
-	static const int secs_through_month[] = {
-		0, 31*86400, 59*86400, 90*86400,
-		120*86400, 151*86400, 181*86400, 212*86400,
-		243*86400, 273*86400, 304*86400, 334*86400 };
-	int t = secs_through_month[month];
-	if (is_leap && month >= 2) t+=86400;
-	return t;
-}
-
-static long long __year_to_secs(long long year, int *is_leap)
-{
-	if (year-2ULL <= 136) {
-		int y = year;
-		int leaps = (y-68)>>2;
-		if (!((y-68)&3)) {
-			leaps--;
-			if (is_leap) *is_leap = 1;
-		} else if (is_leap) *is_leap = 0;
-		return 31536000*(y-70) + 86400*leaps;
-	}
-
-	int cycles, centuries, leaps, rem;
-
-	if (!is_leap) is_leap = &(int){0};
-	cycles = (year-100) / 400;
-	rem = (year-100) % 400;
-	if (rem < 0) {
-		cycles--;
-		rem += 400;
-	}
-	if (!rem) {
-		*is_leap = 1;
-		centuries = 0;
-		leaps = 0;
-	} else {
-		if (rem >= 200) {
-			if (rem >= 300) centuries = 3, rem -= 300;
-			else centuries = 2, rem -= 200;
-		} else {
-			if (rem >= 100) centuries = 1, rem -= 100;
-			else centuries = 0;
-		}
-		if (!rem) {
-			*is_leap = 0;
-			leaps = 0;
-		} else {
-			leaps = rem / 4U;
-			rem %= 4U;
-			*is_leap = !rem;
-		}
-	}
-
-	leaps += 97*cycles + 24*centuries - *is_leap;
-
-	return (year-100) * 31536000LL + leaps * 86400LL + 946684800 + 86400;
-}
-
-static long long __tm_to_secs(const struct tm *tm)
-{
-	int is_leap;
-	long long year = tm->tm_year;
-	int month = tm->tm_mon;
-	if (month >= 12 || month < 0) {
-		int adj = month / 12;
-		month %= 12;
-		if (month < 0) {
-			adj--;
-			month += 12;
-		}
-		year += adj;
-	}
-	long long t = __year_to_secs(year, &is_leap);
-	t += __month_to_secs(month, is_leap);
-	t += 86400LL * (tm->tm_mday-1);
-	t += 3600LL * tm->tm_hour;
-	t += 60LL * tm->tm_min;
-	t += tm->tm_sec;
-	return t;
-}
-
-static int __secs_to_tm(long long t, struct tm *tm)
-{
-	long long days, secs;
-	int remdays, remsecs, remyears;
-	int qc_cycles, c_cycles, q_cycles;
-	int years, months;
-	int wday, yday, leap;
-	static const char days_in_month[] = {31,30,31,30,31,31,30,31,30,31,31,29};
-
-	/* Reject time_t values whose year would overflow int */
-	if (t < INT_MIN * 31622400LL || t > INT_MAX * 31622400LL)
-		return -1;
-
-	secs = t - LEAPOCH;
-	days = secs / 86400;
-	remsecs = secs % 86400;
-	if (remsecs < 0) {
-		remsecs += 86400;
-		days--;
-	}
-
-	wday = (3+days)%7;
-	if (wday < 0) wday += 7;
-
-	qc_cycles = days / DAYS_PER_400Y;
-	remdays = days % DAYS_PER_400Y;
-	if (remdays < 0) {
-		remdays += DAYS_PER_400Y;
-		qc_cycles--;
-	}
-
-	c_cycles = remdays / DAYS_PER_100Y;
-	if (c_cycles == 4) c_cycles--;
-	remdays -= c_cycles * DAYS_PER_100Y;
-
-	q_cycles = remdays / DAYS_PER_4Y;
-	if (q_cycles == 25) q_cycles--;
-	remdays -= q_cycles * DAYS_PER_4Y;
-
-	remyears = remdays / 365;
-	if (remyears == 4) remyears--;
-	remdays -= remyears * 365;
-
-	leap = !remyears && (q_cycles || !c_cycles);
-	yday = remdays + 31 + 28 + leap;
-	if (yday >= 365+leap) yday -= 365+leap;
-
-	years = remyears + 4*q_cycles + 100*c_cycles + 400*qc_cycles;
-
-	for (months=0; days_in_month[months] <= remdays; months++)
-		remdays -= days_in_month[months];
-
-	if (years+100 > INT_MAX || years+100 < INT_MIN)
-		return -1;
-
-	tm->tm_year = years + 100;
-	tm->tm_mon = months + 2;
-	if (tm->tm_mon >= 12) {
-		tm->tm_mon -=12;
-		tm->tm_year++;
-	}
-	tm->tm_mday = remdays + 1;
-	tm->tm_wday = wday;
-	tm->tm_yday = yday;
-
-	tm->tm_hour = remsecs / 3600;
-	tm->tm_min = remsecs / 60 % 60;
-	tm->tm_sec = remsecs % 60;
-
-	return 0;
-}
-
-#ifdef _WIN32
-struct tm *__gmtime_r(const time_t *t, struct tm *tm)
-{
-	if (__secs_to_tm(*t, tm) < 0) {
-		errno = EOVERFLOW;
-		return 0;
-	}
-	tm->tm_isdst = 0;
-	return tm;
-}
-#endif
-
-time_t timegm(struct tm *tm)
-{
-	struct tm new;
-	long long t = __tm_to_secs(tm);
-	if (__secs_to_tm(t, &new) < 0) {
-		errno = EOVERFLOW;
-		return -1;
-	}
-#if SIZEOF_TIME_T != 8
-	if (t > (long long)INT_MAX || t < (long long)INT_MIN) {
-		errno = EOVERFLOW;
-		return -1;
-	}
-#endif
-	*tm = new;
-	tm->tm_isdst = 0;
-	return t;
-}
diff --git a/configure.ac b/configure.ac
index 51e096b..87a80cc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -32,6 +32,10 @@ LT_INIT([pic-only])
 
 CHECK_OS_OPTIONS
 
+if test "$HOST_OS" = "unsupported"; then
+	AC_MSG_ERROR([unsupported platform: $host_os])
+fi
+
 CHECK_C_HARDENING_OPTIONS
 
 DISABLE_AS_EXECUTABLE_STACK
diff --git a/import.sh b/import.sh
index e791de5..70439b5 100644
--- a/import.sh
+++ b/import.sh
@@ -55,7 +55,6 @@ tar -x -f "${input}" --strip-components 2 \
 	'libressl-*/crypto/compat/strcasecmp.c' \
 	'libressl-*/crypto/compat/strlcpy.c' \
 	'libressl-*/crypto/compat/strsep.c' \
-	'libressl-*/crypto/compat/timegm.c' \
 	'libressl-*/crypto/compat/timingsafe_memcmp.c' \
 	'libressl-*/tls/*.[ch]' \
 	'libressl-*/tls/Makefile.am' \
diff --git a/include/Makefile.am b/include/Makefile.am
index 22819c8..feaaa60 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -17,6 +17,7 @@ noinst_HEADERS += compat/poll.h
 noinst_HEADERS += compat/pthread.h
 noinst_HEADERS += compat/readpassphrase.h
 noinst_HEADERS += compat/resolv.h
+noinst_HEADERS += compat/stdint.h
 noinst_HEADERS += compat/stdio.h
 noinst_HEADERS += compat/stdlib.h
 noinst_HEADERS += compat/string.h
diff --git a/include/compat/sys/time.h b/include/compat/sys/time.h
index 76428c1..2448969 100644
--- a/include/compat/sys/time.h
+++ b/include/compat/sys/time.h
@@ -8,6 +8,15 @@
 
 #ifdef _MSC_VER
 #include <winsock2.h>
+
+#define timeval libressl_timeval
+#define gettimeofday libressl_gettimeofday
+
+struct timeval {
+	long long	tv_sec;
+	long		tv_usec;
+};
+
 int gettimeofday(struct timeval *tp, void *tzp);
 #else
 #include_next <sys/time.h>
diff --git a/include/compat/time.h b/include/compat/time.h
index 2748521..a0f6d29 100644
--- a/include/compat/time.h
+++ b/include/compat/time.h
@@ -24,15 +24,6 @@
 #ifndef LIBCRYPTOCOMPAT_TIME_H
 #define LIBCRYPTOCOMPAT_TIME_H
 
-#ifdef _WIN32
-struct tm *__gmtime_r(const time_t * t, struct tm * tm);
-#define gmtime_r(tp, tm) __gmtime_r(tp, tm)
-#endif
-
-#ifndef HAVE_TIMEGM
-time_t timegm(struct tm *tm);
-#endif
-
 #ifndef CLOCK_MONOTONIC
 #define CLOCK_MONOTONIC CLOCK_REALTIME
 #endif
diff --git a/include/tls.h b/include/tls.h
index 59b2c4c..26d5982 100644
--- a/include/tls.h
+++ b/include/tls.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tls.h,v 1.63 2023/07/02 06:37:27 beck Exp $ */
+/* $OpenBSD: tls.h,v 1.67 2024/08/02 15:00:01 tb Exp $ */
 /*
  * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
  *
@@ -40,8 +40,8 @@ typedef SSIZE_T ssize_t;
  * 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)
+#define TLS_PROTOCOL_TLSv1_0	(1 << 1)
+#define TLS_PROTOCOL_TLSv1_1	(1 << 2)
 /* Supported versions of TLS */
 #define TLS_PROTOCOL_TLSv1_2	(1 << 3)
 #define TLS_PROTOCOL_TLSv1_3	(1 << 4)
@@ -83,6 +83,14 @@ typedef SSIZE_T ssize_t;
 #define TLS_MAX_SESSION_ID_LENGTH		32
 #define TLS_TICKET_KEY_SIZE			48
 
+/* Error codes */
+#if defined(LIBRESSL_NEXT_API) || defined(LIBRESSL_INTERNAL)
+#define TLS_ERROR_UNKNOWN			0x0000
+#define TLS_ERROR_OUT_OF_MEMORY			0x1000
+#define TLS_ERROR_INVALID_CONTEXT		0x2000
+#define TLS_ERROR_INVALID_ARGUMENT		0x2001
+#endif
+
 struct tls;
 struct tls_config;
 
@@ -95,6 +103,10 @@ int tls_init(void);
 
 const char *tls_config_error(struct tls_config *_config);
 const char *tls_error(struct tls *_ctx);
+#if defined(LIBRESSL_NEXT_API) || defined(LIBRESSL_INTERNAL)
+int tls_config_error_code(struct tls_config *_config);
+int tls_error_code(struct tls *_ctx);
+#endif
 
 struct tls_config *tls_config_new(void);
 void tls_config_free(struct tls_config *_config);
diff --git a/m4/check-libc.m4 b/m4/check-libc.m4
index 50fb8e1..40df15b 100644
--- a/m4/check-libc.m4
+++ b/m4/check-libc.m4
@@ -37,7 +37,6 @@ AM_CONDITIONAL([HAVE_STRNDUP], [test "x$ac_cv_func_strndup" = xyes])
 AM_CONDITIONAL([HAVE_STRNLEN], [test "x$ac_cv_func_strnlen" = xyes])
 AM_CONDITIONAL([HAVE_STRSEP], [test "x$ac_cv_func_strsep" = xyes])
 AM_CONDITIONAL([HAVE_STRTONUM], [test "x$ac_cv_func_strtonum" = xyes])
-AM_CONDITIONAL([HAVE_TIMEGM], [test "x$ac_cv_func_timegm" = xyes])
 AM_CONDITIONAL([HAVE_GETPROGNAME], [test "x$ac_cv_func_getprogname" = xyes])
 AM_CONDITIONAL([HAVE_SYSLOG], [test "x$ac_cv_func_syslog" = xyes])
 AM_CONDITIONAL([HAVE_SYSLOG_R], [test "x$ac_cv_func_syslog_r" = xyes])
diff --git a/m4/check-os-options.m4 b/m4/check-os-options.m4
index 77edd14..91c3021 100644
--- a/m4/check-os-options.m4
+++ b/m4/check-os-options.m4
@@ -109,7 +109,7 @@ char buf[1]; getentropy(buf, 1);
 		)
 		CPPFLAGS="$CPPFLAGS -D_OPENBSD_SOURCE"
 		;;
-	*openbsd* | *bitrig*)
+	*openbsd*)
 		HOST_OS=openbsd
 		HOST_ABI=elf
 		AC_DEFINE([HAVE_ATTRIBUTE__BOUNDED__], [1], [OpenBSD gcc has bounded])
@@ -131,7 +131,9 @@ char buf[1]; getentropy(buf, 1);
 		CPPFLAGS="$CPPFLAGS -D__EXTENSIONS__ -D_XOPEN_SOURCE=600 -DBSD_COMP"
 		AC_SUBST([PLATFORM_LDADD], ['-ldl -lmd -lnsl -lsocket'])
 		;;
-	*) ;;
+	*)
+		HOST_OS=unsupported
+		;;
 esac
 
 # Check if time_t is sized correctly
@@ -145,7 +147,7 @@ if test "$ac_cv_sizeof_time_t" = "4"; then
     if test "$host_os" = "mingw32" ; then
         echo " **"
         echo " ** You can solve this by adjusting the build flags in your"
-        echo " ** mingw-w64 toolchain. Refer to README.windows for details."
+        echo " ** mingw-w64 toolchain. Refer to README.mingw.md for details."
     fi
 fi
 
diff --git a/man/Makefile.am b/man/Makefile.am
index 2ae4f0a..0ed3d93 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -300,7 +300,7 @@ dist_man3_MANS += EVP_PKEY_CTX_ctrl.3
 dist_man3_MANS += EVP_PKEY_CTX_get_operation.3
 dist_man3_MANS += EVP_PKEY_CTX_new.3
 dist_man3_MANS += EVP_PKEY_CTX_set_hkdf_md.3
-dist_man3_MANS += EVP_PKEY_add1_attr.3
+dist_man3_MANS += EVP_PKEY_CTX_set_tls1_prf_md.3
 dist_man3_MANS += EVP_PKEY_asn1_get_count.3
 dist_man3_MANS += EVP_PKEY_asn1_new.3
 dist_man3_MANS += EVP_PKEY_check.3
@@ -331,7 +331,6 @@ dist_man3_MANS += EVP_sha1.3
 dist_man3_MANS += EVP_sha3_224.3
 dist_man3_MANS += EVP_sm3.3
 dist_man3_MANS += EVP_sm4_cbc.3
-dist_man3_MANS += EVP_whirlpool.3
 dist_man3_MANS += EXTENDED_KEY_USAGE_new.3
 dist_man3_MANS += GENERAL_NAME_new.3
 dist_man3_MANS += HMAC.3
@@ -423,11 +422,11 @@ dist_man3_MANS += SMIME_write_CMS.3
 dist_man3_MANS += SMIME_write_PKCS7.3
 dist_man3_MANS += STACK_OF.3
 dist_man3_MANS += TS_REQ_new.3
-dist_man3_MANS += UI_UTIL_read_pw.3
 dist_man3_MANS += UI_create_method.3
 dist_man3_MANS += UI_get_string_type.3
 dist_man3_MANS += UI_new.3
 dist_man3_MANS += X25519.3
+dist_man3_MANS += X509V3_EXT_get_nid.3
 dist_man3_MANS += X509V3_EXT_print.3
 dist_man3_MANS += X509V3_extensions_print.3
 dist_man3_MANS += X509V3_get_d2i.3
@@ -471,7 +470,6 @@ dist_man3_MANS += X509_STORE_load_locations.3
 dist_man3_MANS += X509_STORE_new.3
 dist_man3_MANS += X509_STORE_set1_param.3
 dist_man3_MANS += X509_STORE_set_verify_cb_func.3
-dist_man3_MANS += X509_TRUST_set.3
 dist_man3_MANS += X509_VERIFY_PARAM_new.3
 dist_man3_MANS += X509_VERIFY_PARAM_set_flags.3
 dist_man3_MANS += X509_add1_trust_object.3
@@ -480,7 +478,6 @@ dist_man3_MANS += X509_check_host.3
 dist_man3_MANS += X509_check_issued.3
 dist_man3_MANS += X509_check_private_key.3
 dist_man3_MANS += X509_check_purpose.3
-dist_man3_MANS += X509_check_trust.3
 dist_man3_MANS += X509_cmp.3
 dist_man3_MANS += X509_cmp_time.3
 dist_man3_MANS += X509_digest.3
@@ -502,8 +499,6 @@ dist_man3_MANS += X509_print_ex.3
 dist_man3_MANS += X509_sign.3
 dist_man3_MANS += X509_signature_dump.3
 dist_man3_MANS += X509_verify_cert.3
-dist_man3_MANS += X509at_add1_attr.3
-dist_man3_MANS += X509at_get_attr.3
 dist_man3_MANS += X509v3_addr_add_inherit.3
 dist_man3_MANS += X509v3_addr_get_range.3
 dist_man3_MANS += X509v3_addr_inherits.3
@@ -1121,8 +1116,6 @@ install-data-hook:
 	ln -sf "DES_set_key.3" "$(DESTDIR)$(mandir)/man3/DES_ede3_cbcm_encrypt.3"
 	ln -sf "DES_set_key.3" "$(DESTDIR)$(mandir)/man3/DES_ede3_cfb64_encrypt.3"
 	ln -sf "DES_set_key.3" "$(DESTDIR)$(mandir)/man3/DES_ede3_ofb64_encrypt.3"
-	ln -sf "DES_set_key.3" "$(DESTDIR)$(mandir)/man3/DES_enc_read.3"
-	ln -sf "DES_set_key.3" "$(DESTDIR)$(mandir)/man3/DES_enc_write.3"
 	ln -sf "DES_set_key.3" "$(DESTDIR)$(mandir)/man3/DES_fcrypt.3"
 	ln -sf "DES_set_key.3" "$(DESTDIR)$(mandir)/man3/DES_is_weak_key.3"
 	ln -sf "DES_set_key.3" "$(DESTDIR)$(mandir)/man3/DES_key_sched.3"
@@ -1248,6 +1241,8 @@ install-data-hook:
 	ln -sf "EC_GROUP_new.3" "$(DESTDIR)$(mandir)/man3/EC_GROUP_new_curve_GFp.3"
 	ln -sf "EC_GROUP_new.3" "$(DESTDIR)$(mandir)/man3/EC_GROUP_set_curve.3"
 	ln -sf "EC_GROUP_new.3" "$(DESTDIR)$(mandir)/man3/EC_GROUP_set_curve_GFp.3"
+	ln -sf "EC_GROUP_new.3" "$(DESTDIR)$(mandir)/man3/EC_curve_nid2nist.3"
+	ln -sf "EC_GROUP_new.3" "$(DESTDIR)$(mandir)/man3/EC_curve_nist2nid.3"
 	ln -sf "EC_GROUP_new.3" "$(DESTDIR)$(mandir)/man3/EC_get_builtin_curves.3"
 	ln -sf "EC_KEY_METHOD_new.3" "$(DESTDIR)$(mandir)/man3/EC_KEY_METHOD_free.3"
 	ln -sf "EC_KEY_METHOD_new.3" "$(DESTDIR)$(mandir)/man3/EC_KEY_METHOD_get_compute_key.3"
@@ -1361,8 +1356,6 @@ install-data-hook:
 	ln -sf "ERR_load_strings.3" "$(DESTDIR)$(mandir)/man3/ERR_get_next_error_library.3"
 	ln -sf "ERR_print_errors.3" "$(DESTDIR)$(mandir)/man3/ERR_print_errors_cb.3"
 	ln -sf "ERR_print_errors.3" "$(DESTDIR)$(mandir)/man3/ERR_print_errors_fp.3"
-	ln -sf "ERR_put_error.3" "$(DESTDIR)$(mandir)/man3/ERR_add_error_data.3"
-	ln -sf "ERR_put_error.3" "$(DESTDIR)$(mandir)/man3/ERR_add_error_vdata.3"
 	ln -sf "ERR_remove_state.3" "$(DESTDIR)$(mandir)/man3/ERR_remove_thread_state.3"
 	ln -sf "ERR_set_mark.3" "$(DESTDIR)$(mandir)/man3/ERR_pop_to_mark.3"
 	ln -sf "ESS_SIGNING_CERT_new.3" "$(DESTDIR)$(mandir)/man3/ESS_CERT_ID_free.3"
@@ -1562,14 +1555,8 @@ install-data-hook:
 	ln -sf "EVP_PKEY_CTX_set_hkdf_md.3" "$(DESTDIR)$(mandir)/man3/EVP_PKEY_CTX_hkdf_mode.3"
 	ln -sf "EVP_PKEY_CTX_set_hkdf_md.3" "$(DESTDIR)$(mandir)/man3/EVP_PKEY_CTX_set1_hkdf_key.3"
 	ln -sf "EVP_PKEY_CTX_set_hkdf_md.3" "$(DESTDIR)$(mandir)/man3/EVP_PKEY_CTX_set1_hkdf_salt.3"
-	ln -sf "EVP_PKEY_add1_attr.3" "$(DESTDIR)$(mandir)/man3/EVP_PKEY_add1_attr_by_NID.3"
-	ln -sf "EVP_PKEY_add1_attr.3" "$(DESTDIR)$(mandir)/man3/EVP_PKEY_add1_attr_by_OBJ.3"
-	ln -sf "EVP_PKEY_add1_attr.3" "$(DESTDIR)$(mandir)/man3/EVP_PKEY_add1_attr_by_txt.3"
-	ln -sf "EVP_PKEY_add1_attr.3" "$(DESTDIR)$(mandir)/man3/EVP_PKEY_delete_attr.3"
-	ln -sf "EVP_PKEY_add1_attr.3" "$(DESTDIR)$(mandir)/man3/EVP_PKEY_get_attr.3"
-	ln -sf "EVP_PKEY_add1_attr.3" "$(DESTDIR)$(mandir)/man3/EVP_PKEY_get_attr_by_NID.3"
-	ln -sf "EVP_PKEY_add1_attr.3" "$(DESTDIR)$(mandir)/man3/EVP_PKEY_get_attr_by_OBJ.3"
-	ln -sf "EVP_PKEY_add1_attr.3" "$(DESTDIR)$(mandir)/man3/EVP_PKEY_get_attr_count.3"
+	ln -sf "EVP_PKEY_CTX_set_tls1_prf_md.3" "$(DESTDIR)$(mandir)/man3/EVP_PKEY_CTX_add1_tls1_prf_seed.3"
+	ln -sf "EVP_PKEY_CTX_set_tls1_prf_md.3" "$(DESTDIR)$(mandir)/man3/EVP_PKEY_CTX_set1_tls1_prf_secret.3"
 	ln -sf "EVP_PKEY_asn1_get_count.3" "$(DESTDIR)$(mandir)/man3/EVP_PKEY_asn1_find.3"
 	ln -sf "EVP_PKEY_asn1_get_count.3" "$(DESTDIR)$(mandir)/man3/EVP_PKEY_asn1_find_str.3"
 	ln -sf "EVP_PKEY_asn1_get_count.3" "$(DESTDIR)$(mandir)/man3/EVP_PKEY_asn1_get0.3"
@@ -1781,7 +1768,6 @@ install-data-hook:
 	ln -sf "HMAC.3" "$(DESTDIR)$(mandir)/man3/HMAC_CTX_reset.3"
 	ln -sf "HMAC.3" "$(DESTDIR)$(mandir)/man3/HMAC_CTX_set_flags.3"
 	ln -sf "HMAC.3" "$(DESTDIR)$(mandir)/man3/HMAC_Final.3"
-	ln -sf "HMAC.3" "$(DESTDIR)$(mandir)/man3/HMAC_Init.3"
 	ln -sf "HMAC.3" "$(DESTDIR)$(mandir)/man3/HMAC_Init_ex.3"
 	ln -sf "HMAC.3" "$(DESTDIR)$(mandir)/man3/HMAC_Update.3"
 	ln -sf "HMAC.3" "$(DESTDIR)$(mandir)/man3/HMAC_size.3"
@@ -1902,10 +1888,8 @@ install-data-hook:
 	ln -sf "OPENSSL_load_builtin_modules.3" "$(DESTDIR)$(mandir)/man3/ASN1_add_oid_module.3"
 	ln -sf "OPENSSL_malloc.3" "$(DESTDIR)$(mandir)/man3/CRYPTO_free.3"
 	ln -sf "OPENSSL_malloc.3" "$(DESTDIR)$(mandir)/man3/CRYPTO_malloc.3"
-	ln -sf "OPENSSL_malloc.3" "$(DESTDIR)$(mandir)/man3/CRYPTO_realloc.3"
 	ln -sf "OPENSSL_malloc.3" "$(DESTDIR)$(mandir)/man3/CRYPTO_strdup.3"
 	ln -sf "OPENSSL_malloc.3" "$(DESTDIR)$(mandir)/man3/OPENSSL_free.3"
-	ln -sf "OPENSSL_malloc.3" "$(DESTDIR)$(mandir)/man3/OPENSSL_realloc.3"
 	ln -sf "OPENSSL_malloc.3" "$(DESTDIR)$(mandir)/man3/OPENSSL_strdup.3"
 	ln -sf "OPENSSL_sk_new.3" "$(DESTDIR)$(mandir)/man3/sk_delete.3"
 	ln -sf "OPENSSL_sk_new.3" "$(DESTDIR)$(mandir)/man3/sk_delete_ptr.3"
@@ -2223,6 +2207,7 @@ install-data-hook:
 	ln -sf "SSL_CIPHER_get_name.3" "$(DESTDIR)$(mandir)/man3/SSL_CIPHER_get_bits.3"
 	ln -sf "SSL_CIPHER_get_name.3" "$(DESTDIR)$(mandir)/man3/SSL_CIPHER_get_cipher_nid.3"
 	ln -sf "SSL_CIPHER_get_name.3" "$(DESTDIR)$(mandir)/man3/SSL_CIPHER_get_digest_nid.3"
+	ln -sf "SSL_CIPHER_get_name.3" "$(DESTDIR)$(mandir)/man3/SSL_CIPHER_get_handshake_digest.3"
 	ln -sf "SSL_CIPHER_get_name.3" "$(DESTDIR)$(mandir)/man3/SSL_CIPHER_get_id.3"
 	ln -sf "SSL_CIPHER_get_name.3" "$(DESTDIR)$(mandir)/man3/SSL_CIPHER_get_kx_nid.3"
 	ln -sf "SSL_CIPHER_get_name.3" "$(DESTDIR)$(mandir)/man3/SSL_CIPHER_get_version.3"
@@ -2311,6 +2296,7 @@ install-data-hook:
 	ln -sf "SSL_CTX_set_alpn_select_cb.3" "$(DESTDIR)$(mandir)/man3/SSL_select_next_proto.3"
 	ln -sf "SSL_CTX_set_alpn_select_cb.3" "$(DESTDIR)$(mandir)/man3/SSL_set_alpn_protos.3"
 	ln -sf "SSL_CTX_set_cert_store.3" "$(DESTDIR)$(mandir)/man3/SSL_CTX_get_cert_store.3"
+	ln -sf "SSL_CTX_set_cert_store.3" "$(DESTDIR)$(mandir)/man3/SSL_CTX_set1_cert_store.3"
 	ln -sf "SSL_CTX_set_cipher_list.3" "$(DESTDIR)$(mandir)/man3/SSL_set_cipher_list.3"
 	ln -sf "SSL_CTX_set_client_CA_list.3" "$(DESTDIR)$(mandir)/man3/SSL_CTX_add_client_CA.3"
 	ln -sf "SSL_CTX_set_client_CA_list.3" "$(DESTDIR)$(mandir)/man3/SSL_add_client_CA.3"
@@ -2519,7 +2505,6 @@ install-data-hook:
 	ln -sf "TS_REQ_new.3" "$(DESTDIR)$(mandir)/man3/TS_STATUS_INFO_new.3"
 	ln -sf "TS_REQ_new.3" "$(DESTDIR)$(mandir)/man3/TS_TST_INFO_free.3"
 	ln -sf "TS_REQ_new.3" "$(DESTDIR)$(mandir)/man3/TS_TST_INFO_new.3"
-	ln -sf "UI_UTIL_read_pw.3" "$(DESTDIR)$(mandir)/man3/UI_UTIL_read_pw_string.3"
 	ln -sf "UI_create_method.3" "$(DESTDIR)$(mandir)/man3/UI_destroy_method.3"
 	ln -sf "UI_create_method.3" "$(DESTDIR)$(mandir)/man3/UI_method_get_closer.3"
 	ln -sf "UI_create_method.3" "$(DESTDIR)$(mandir)/man3/UI_method_get_flusher.3"
@@ -2569,6 +2554,7 @@ install-data-hook:
 	ln -sf "X25519.3" "$(DESTDIR)$(mandir)/man3/ED25519_sign.3"
 	ln -sf "X25519.3" "$(DESTDIR)$(mandir)/man3/ED25519_verify.3"
 	ln -sf "X25519.3" "$(DESTDIR)$(mandir)/man3/X25519_keypair.3"
+	ln -sf "X509V3_EXT_get_nid.3" "$(DESTDIR)$(mandir)/man3/X509V3_EXT_get.3"
 	ln -sf "X509V3_get_d2i.3" "$(DESTDIR)$(mandir)/man3/X509V3_EXT_d2i.3"
 	ln -sf "X509V3_get_d2i.3" "$(DESTDIR)$(mandir)/man3/X509V3_EXT_i2d.3"
 	ln -sf "X509V3_get_d2i.3" "$(DESTDIR)$(mandir)/man3/X509V3_add1_i2d.3"
@@ -2587,7 +2573,6 @@ install-data-hook:
 	ln -sf "X509_ALGOR_dup.3" "$(DESTDIR)$(mandir)/man3/X509_ALGOR_get0.3"
 	ln -sf "X509_ALGOR_dup.3" "$(DESTDIR)$(mandir)/man3/X509_ALGOR_new.3"
 	ln -sf "X509_ALGOR_dup.3" "$(DESTDIR)$(mandir)/man3/X509_ALGOR_set0.3"
-	ln -sf "X509_ALGOR_dup.3" "$(DESTDIR)$(mandir)/man3/X509_ALGOR_set_md.3"
 	ln -sf "X509_ATTRIBUTE_get0_object.3" "$(DESTDIR)$(mandir)/man3/X509_ATTRIBUTE_count.3"
 	ln -sf "X509_ATTRIBUTE_get0_object.3" "$(DESTDIR)$(mandir)/man3/X509_ATTRIBUTE_get0_data.3"
 	ln -sf "X509_ATTRIBUTE_get0_object.3" "$(DESTDIR)$(mandir)/man3/X509_ATTRIBUTE_get0_type.3"
@@ -2628,15 +2613,9 @@ install-data-hook:
 	ln -sf "X509_LOOKUP_hash_dir.3" "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_mem.3"
 	ln -sf "X509_LOOKUP_new.3" "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_add_dir.3"
 	ln -sf "X509_LOOKUP_new.3" "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_add_mem.3"
-	ln -sf "X509_LOOKUP_new.3" "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_by_alias.3"
-	ln -sf "X509_LOOKUP_new.3" "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_by_fingerprint.3"
-	ln -sf "X509_LOOKUP_new.3" "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_by_issuer_serial.3"
-	ln -sf "X509_LOOKUP_new.3" "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_by_subject.3"
 	ln -sf "X509_LOOKUP_new.3" "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_ctrl.3"
 	ln -sf "X509_LOOKUP_new.3" "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_free.3"
-	ln -sf "X509_LOOKUP_new.3" "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_init.3"
 	ln -sf "X509_LOOKUP_new.3" "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_load_file.3"
-	ln -sf "X509_LOOKUP_new.3" "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_shutdown.3"
 	ln -sf "X509_LOOKUP_new.3" "$(DESTDIR)$(mandir)/man3/X509_get_default_cert_dir.3"
 	ln -sf "X509_LOOKUP_new.3" "$(DESTDIR)$(mandir)/man3/X509_get_default_cert_dir_env.3"
 	ln -sf "X509_LOOKUP_new.3" "$(DESTDIR)$(mandir)/man3/X509_get_default_cert_file.3"
@@ -2712,9 +2691,7 @@ install-data-hook:
 	ln -sf "X509_REQ_add1_attr.3" "$(DESTDIR)$(mandir)/man3/X509_REQ_get_attr_count.3"
 	ln -sf "X509_REQ_add_extensions.3" "$(DESTDIR)$(mandir)/man3/X509_REQ_add_extensions_nid.3"
 	ln -sf "X509_REQ_add_extensions.3" "$(DESTDIR)$(mandir)/man3/X509_REQ_extension_nid.3"
-	ln -sf "X509_REQ_add_extensions.3" "$(DESTDIR)$(mandir)/man3/X509_REQ_get_extension_nids.3"
 	ln -sf "X509_REQ_add_extensions.3" "$(DESTDIR)$(mandir)/man3/X509_REQ_get_extensions.3"
-	ln -sf "X509_REQ_add_extensions.3" "$(DESTDIR)$(mandir)/man3/X509_REQ_set_extension_nids.3"
 	ln -sf "X509_REQ_new.3" "$(DESTDIR)$(mandir)/man3/X509_REQ_INFO_free.3"
 	ln -sf "X509_REQ_new.3" "$(DESTDIR)$(mandir)/man3/X509_REQ_INFO_new.3"
 	ln -sf "X509_REQ_new.3" "$(DESTDIR)$(mandir)/man3/X509_REQ_dup.3"
@@ -2804,14 +2781,6 @@ install-data-hook:
 	ln -sf "X509_STORE_set1_param.3" "$(DESTDIR)$(mandir)/man3/X509_STORE_set_trust.3"
 	ln -sf "X509_STORE_set_verify_cb_func.3" "$(DESTDIR)$(mandir)/man3/X509_STORE_get_verify_cb.3"
 	ln -sf "X509_STORE_set_verify_cb_func.3" "$(DESTDIR)$(mandir)/man3/X509_STORE_set_verify_cb.3"
-	ln -sf "X509_TRUST_set.3" "$(DESTDIR)$(mandir)/man3/X509_TRUST_add.3"
-	ln -sf "X509_TRUST_set.3" "$(DESTDIR)$(mandir)/man3/X509_TRUST_cleanup.3"
-	ln -sf "X509_TRUST_set.3" "$(DESTDIR)$(mandir)/man3/X509_TRUST_get0.3"
-	ln -sf "X509_TRUST_set.3" "$(DESTDIR)$(mandir)/man3/X509_TRUST_get0_name.3"
-	ln -sf "X509_TRUST_set.3" "$(DESTDIR)$(mandir)/man3/X509_TRUST_get_by_id.3"
-	ln -sf "X509_TRUST_set.3" "$(DESTDIR)$(mandir)/man3/X509_TRUST_get_count.3"
-	ln -sf "X509_TRUST_set.3" "$(DESTDIR)$(mandir)/man3/X509_TRUST_get_flags.3"
-	ln -sf "X509_TRUST_set.3" "$(DESTDIR)$(mandir)/man3/X509_TRUST_get_trust.3"
 	ln -sf "X509_VERIFY_PARAM_new.3" "$(DESTDIR)$(mandir)/man3/X509_VERIFY_PARAM_add0_table.3"
 	ln -sf "X509_VERIFY_PARAM_new.3" "$(DESTDIR)$(mandir)/man3/X509_VERIFY_PARAM_free.3"
 	ln -sf "X509_VERIFY_PARAM_new.3" "$(DESTDIR)$(mandir)/man3/X509_VERIFY_PARAM_get0.3"
@@ -2847,7 +2816,6 @@ install-data-hook:
 	ln -sf "X509_check_host.3" "$(DESTDIR)$(mandir)/man3/X509_check_ip.3"
 	ln -sf "X509_check_host.3" "$(DESTDIR)$(mandir)/man3/X509_check_ip_asc.3"
 	ln -sf "X509_check_private_key.3" "$(DESTDIR)$(mandir)/man3/X509_REQ_check_private_key.3"
-	ln -sf "X509_check_trust.3" "$(DESTDIR)$(mandir)/man3/X509_TRUST_set_default.3"
 	ln -sf "X509_cmp.3" "$(DESTDIR)$(mandir)/man3/X509_CRL_cmp.3"
 	ln -sf "X509_cmp.3" "$(DESTDIR)$(mandir)/man3/X509_CRL_match.3"
 	ln -sf "X509_cmp.3" "$(DESTDIR)$(mandir)/man3/X509_NAME_cmp.3"
@@ -2887,6 +2855,7 @@ install-data-hook:
 	ln -sf "X509_get0_signature.3" "$(DESTDIR)$(mandir)/man3/X509_REQ_get0_signature.3"
 	ln -sf "X509_get0_signature.3" "$(DESTDIR)$(mandir)/man3/X509_REQ_get_signature_nid.3"
 	ln -sf "X509_get0_signature.3" "$(DESTDIR)$(mandir)/man3/X509_get0_tbs_sigalg.3"
+	ln -sf "X509_get0_signature.3" "$(DESTDIR)$(mandir)/man3/X509_get_signature_info.3"
 	ln -sf "X509_get0_signature.3" "$(DESTDIR)$(mandir)/man3/X509_get_signature_nid.3"
 	ln -sf "X509_get0_signature.3" "$(DESTDIR)$(mandir)/man3/X509_get_signature_type.3"
 	ln -sf "X509_get1_email.3" "$(DESTDIR)$(mandir)/man3/X509_email_free.3"
@@ -2939,14 +2908,6 @@ install-data-hook:
 	ln -sf "X509_sign.3" "$(DESTDIR)$(mandir)/man3/X509_sign_ctx.3"
 	ln -sf "X509_sign.3" "$(DESTDIR)$(mandir)/man3/X509_verify.3"
 	ln -sf "X509_signature_dump.3" "$(DESTDIR)$(mandir)/man3/X509_signature_print.3"
-	ln -sf "X509at_add1_attr.3" "$(DESTDIR)$(mandir)/man3/X509at_add1_attr_by_NID.3"
-	ln -sf "X509at_add1_attr.3" "$(DESTDIR)$(mandir)/man3/X509at_add1_attr_by_OBJ.3"
-	ln -sf "X509at_add1_attr.3" "$(DESTDIR)$(mandir)/man3/X509at_add1_attr_by_txt.3"
-	ln -sf "X509at_add1_attr.3" "$(DESTDIR)$(mandir)/man3/X509at_delete_attr.3"
-	ln -sf "X509at_get_attr.3" "$(DESTDIR)$(mandir)/man3/X509at_get0_data_by_OBJ.3"
-	ln -sf "X509at_get_attr.3" "$(DESTDIR)$(mandir)/man3/X509at_get_attr_by_NID.3"
-	ln -sf "X509at_get_attr.3" "$(DESTDIR)$(mandir)/man3/X509at_get_attr_by_OBJ.3"
-	ln -sf "X509at_get_attr.3" "$(DESTDIR)$(mandir)/man3/X509at_get_attr_count.3"
 	ln -sf "X509v3_addr_add_inherit.3" "$(DESTDIR)$(mandir)/man3/X509v3_addr_add_prefix.3"
 	ln -sf "X509v3_addr_add_inherit.3" "$(DESTDIR)$(mandir)/man3/X509v3_addr_add_range.3"
 	ln -sf "X509v3_addr_add_inherit.3" "$(DESTDIR)$(mandir)/man3/X509v3_addr_canonize.3"
@@ -3983,8 +3944,6 @@ uninstall-local:
 	-rm -f "$(DESTDIR)$(mandir)/man3/DES_ede3_cbcm_encrypt.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/DES_ede3_cfb64_encrypt.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/DES_ede3_ofb64_encrypt.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/DES_enc_read.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/DES_enc_write.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/DES_fcrypt.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/DES_is_weak_key.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/DES_key_sched.3"
@@ -4110,6 +4069,8 @@ uninstall-local:
 	-rm -f "$(DESTDIR)$(mandir)/man3/EC_GROUP_new_curve_GFp.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/EC_GROUP_set_curve.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/EC_GROUP_set_curve_GFp.3"
+	-rm -f "$(DESTDIR)$(mandir)/man3/EC_curve_nid2nist.3"
+	-rm -f "$(DESTDIR)$(mandir)/man3/EC_curve_nist2nid.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/EC_get_builtin_curves.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/EC_KEY_METHOD_free.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/EC_KEY_METHOD_get_compute_key.3"
@@ -4223,8 +4184,6 @@ uninstall-local:
 	-rm -f "$(DESTDIR)$(mandir)/man3/ERR_get_next_error_library.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/ERR_print_errors_cb.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/ERR_print_errors_fp.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/ERR_add_error_data.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/ERR_add_error_vdata.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/ERR_remove_thread_state.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/ERR_pop_to_mark.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/ESS_CERT_ID_free.3"
@@ -4424,14 +4383,8 @@ uninstall-local:
 	-rm -f "$(DESTDIR)$(mandir)/man3/EVP_PKEY_CTX_hkdf_mode.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/EVP_PKEY_CTX_set1_hkdf_key.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/EVP_PKEY_CTX_set1_hkdf_salt.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/EVP_PKEY_add1_attr_by_NID.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/EVP_PKEY_add1_attr_by_OBJ.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/EVP_PKEY_add1_attr_by_txt.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/EVP_PKEY_delete_attr.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/EVP_PKEY_get_attr.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/EVP_PKEY_get_attr_by_NID.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/EVP_PKEY_get_attr_by_OBJ.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/EVP_PKEY_get_attr_count.3"
+	-rm -f "$(DESTDIR)$(mandir)/man3/EVP_PKEY_CTX_add1_tls1_prf_seed.3"
+	-rm -f "$(DESTDIR)$(mandir)/man3/EVP_PKEY_CTX_set1_tls1_prf_secret.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/EVP_PKEY_asn1_find.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/EVP_PKEY_asn1_find_str.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/EVP_PKEY_asn1_get0.3"
@@ -4643,7 +4596,6 @@ uninstall-local:
 	-rm -f "$(DESTDIR)$(mandir)/man3/HMAC_CTX_reset.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/HMAC_CTX_set_flags.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/HMAC_Final.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/HMAC_Init.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/HMAC_Init_ex.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/HMAC_Update.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/HMAC_size.3"
@@ -4764,10 +4716,8 @@ uninstall-local:
 	-rm -f "$(DESTDIR)$(mandir)/man3/ASN1_add_oid_module.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/CRYPTO_free.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/CRYPTO_malloc.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/CRYPTO_realloc.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/CRYPTO_strdup.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/OPENSSL_free.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/OPENSSL_realloc.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/OPENSSL_strdup.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/sk_delete.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/sk_delete_ptr.3"
@@ -5085,6 +5035,7 @@ uninstall-local:
 	-rm -f "$(DESTDIR)$(mandir)/man3/SSL_CIPHER_get_bits.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/SSL_CIPHER_get_cipher_nid.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/SSL_CIPHER_get_digest_nid.3"
+	-rm -f "$(DESTDIR)$(mandir)/man3/SSL_CIPHER_get_handshake_digest.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/SSL_CIPHER_get_id.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/SSL_CIPHER_get_kx_nid.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/SSL_CIPHER_get_version.3"
@@ -5173,6 +5124,7 @@ uninstall-local:
 	-rm -f "$(DESTDIR)$(mandir)/man3/SSL_select_next_proto.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/SSL_set_alpn_protos.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/SSL_CTX_get_cert_store.3"
+	-rm -f "$(DESTDIR)$(mandir)/man3/SSL_CTX_set1_cert_store.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/SSL_set_cipher_list.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/SSL_CTX_add_client_CA.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/SSL_add_client_CA.3"
@@ -5381,7 +5333,6 @@ uninstall-local:
 	-rm -f "$(DESTDIR)$(mandir)/man3/TS_STATUS_INFO_new.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/TS_TST_INFO_free.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/TS_TST_INFO_new.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/UI_UTIL_read_pw_string.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/UI_destroy_method.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/UI_method_get_closer.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/UI_method_get_flusher.3"
@@ -5431,6 +5382,7 @@ uninstall-local:
 	-rm -f "$(DESTDIR)$(mandir)/man3/ED25519_sign.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/ED25519_verify.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X25519_keypair.3"
+	-rm -f "$(DESTDIR)$(mandir)/man3/X509V3_EXT_get.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509V3_EXT_d2i.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509V3_EXT_i2d.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509V3_add1_i2d.3"
@@ -5449,7 +5401,6 @@ uninstall-local:
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_ALGOR_get0.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_ALGOR_new.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_ALGOR_set0.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509_ALGOR_set_md.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_ATTRIBUTE_count.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_ATTRIBUTE_get0_data.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_ATTRIBUTE_get0_type.3"
@@ -5490,15 +5441,9 @@ uninstall-local:
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_mem.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_add_dir.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_add_mem.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_by_alias.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_by_fingerprint.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_by_issuer_serial.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_by_subject.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_ctrl.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_free.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_init.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_load_file.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509_LOOKUP_shutdown.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_get_default_cert_dir.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_get_default_cert_dir_env.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_get_default_cert_file.3"
@@ -5574,9 +5519,7 @@ uninstall-local:
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_REQ_get_attr_count.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_REQ_add_extensions_nid.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_REQ_extension_nid.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509_REQ_get_extension_nids.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_REQ_get_extensions.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509_REQ_set_extension_nids.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_REQ_INFO_free.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_REQ_INFO_new.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_REQ_dup.3"
@@ -5666,14 +5609,6 @@ uninstall-local:
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_STORE_set_trust.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_STORE_get_verify_cb.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_STORE_set_verify_cb.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509_TRUST_add.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509_TRUST_cleanup.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509_TRUST_get0.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509_TRUST_get0_name.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509_TRUST_get_by_id.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509_TRUST_get_count.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509_TRUST_get_flags.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509_TRUST_get_trust.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_VERIFY_PARAM_add0_table.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_VERIFY_PARAM_free.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_VERIFY_PARAM_get0.3"
@@ -5709,7 +5644,6 @@ uninstall-local:
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_check_ip.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_check_ip_asc.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_REQ_check_private_key.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509_TRUST_set_default.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_CRL_cmp.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_CRL_match.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_NAME_cmp.3"
@@ -5749,6 +5683,7 @@ uninstall-local:
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_REQ_get0_signature.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_REQ_get_signature_nid.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_get0_tbs_sigalg.3"
+	-rm -f "$(DESTDIR)$(mandir)/man3/X509_get_signature_info.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_get_signature_nid.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_get_signature_type.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_email_free.3"
@@ -5801,14 +5736,6 @@ uninstall-local:
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_sign_ctx.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_verify.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509_signature_print.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509at_add1_attr_by_NID.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509at_add1_attr_by_OBJ.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509at_add1_attr_by_txt.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509at_delete_attr.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509at_get0_data_by_OBJ.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509at_get_attr_by_NID.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509at_get_attr_by_OBJ.3"
-	-rm -f "$(DESTDIR)$(mandir)/man3/X509at_get_attr_count.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509v3_addr_add_prefix.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509v3_addr_add_range.3"
 	-rm -f "$(DESTDIR)$(mandir)/man3/X509v3_addr_canonize.3"
diff --git a/tls.c b/tls.c
index fdb994d..41bb06d 100644
--- a/tls.c
+++ b/tls.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tls.c,v 1.98 2023/07/02 06:37:27 beck Exp $ */
+/* $OpenBSD: tls.c,v 1.104 2024/04/08 20:47:32 tb Exp $ */
 /*
  * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
  *
@@ -72,24 +72,33 @@ tls_error(struct tls *ctx)
 	return ctx->error.msg;
 }
 
+int
+tls_error_code(struct tls *ctx)
+{
+	return ctx->error.code;
+}
+
 void
 tls_error_clear(struct tls_error *error)
 {
 	free(error->msg);
 	error->msg = NULL;
-	error->num = 0;
+	error->code = TLS_ERROR_UNKNOWN;
+	error->errno_value = 0;
 	error->tls = 0;
 }
 
 static int
-tls_error_vset(struct tls_error *error, int errnum, const char *fmt, va_list ap)
+tls_error_vset(struct tls_error *error, int code, int errno_value,
+    const char *fmt, va_list ap)
 {
 	char *errmsg = NULL;
 	int rv = -1;
 
 	tls_error_clear(error);
 
-	error->num = errnum;
+	error->code = code;
+	error->errno_value = errno_value;
 	error->tls = 1;
 
 	if (vasprintf(&errmsg, fmt, ap) == -1) {
@@ -97,12 +106,12 @@ tls_error_vset(struct tls_error *error, int errnum, const char *fmt, va_list ap)
 		goto err;
 	}
 
-	if (errnum == -1) {
+	if (errno_value == -1) {
 		error->msg = errmsg;
 		return (0);
 	}
 
-	if (asprintf(&error->msg, "%s: %s", errmsg, strerror(errnum)) == -1) {
+	if (asprintf(&error->msg, "%s: %s", errmsg, strerror(errno_value)) == -1) {
 		error->msg = NULL;
 		goto err;
 	}
@@ -115,91 +124,91 @@ tls_error_vset(struct tls_error *error, int errnum, const char *fmt, va_list ap)
 }
 
 int
-tls_error_set(struct tls_error *error, const char *fmt, ...)
+tls_error_set(struct tls_error *error, int code, const char *fmt, ...)
 {
 	va_list ap;
-	int errnum, rv;
+	int errno_value, rv;
 
-	errnum = errno;
+	errno_value = errno;
 
 	va_start(ap, fmt);
-	rv = tls_error_vset(error, errnum, fmt, ap);
+	rv = tls_error_vset(error, code, errno_value, fmt, ap);
 	va_end(ap);
 
 	return (rv);
 }
 
 int
-tls_error_setx(struct tls_error *error, const char *fmt, ...)
+tls_error_setx(struct tls_error *error, int code, const char *fmt, ...)
 {
 	va_list ap;
 	int rv;
 
 	va_start(ap, fmt);
-	rv = tls_error_vset(error, -1, fmt, ap);
+	rv = tls_error_vset(error, code, -1, fmt, ap);
 	va_end(ap);
 
 	return (rv);
 }
 
 int
-tls_config_set_error(struct tls_config *config, const char *fmt, ...)
+tls_config_set_error(struct tls_config *config, int code, const char *fmt, ...)
 {
 	va_list ap;
-	int errnum, rv;
+	int errno_value, rv;
 
-	errnum = errno;
+	errno_value = errno;
 
 	va_start(ap, fmt);
-	rv = tls_error_vset(&config->error, errnum, fmt, ap);
+	rv = tls_error_vset(&config->error, code, errno_value, fmt, ap);
 	va_end(ap);
 
 	return (rv);
 }
 
 int
-tls_config_set_errorx(struct tls_config *config, const char *fmt, ...)
+tls_config_set_errorx(struct tls_config *config, int code, const char *fmt, ...)
 {
 	va_list ap;
 	int rv;
 
 	va_start(ap, fmt);
-	rv = tls_error_vset(&config->error, -1, fmt, ap);
+	rv = tls_error_vset(&config->error, code, -1, fmt, ap);
 	va_end(ap);
 
 	return (rv);
 }
 
 int
-tls_set_error(struct tls *ctx, const char *fmt, ...)
+tls_set_error(struct tls *ctx, int code, const char *fmt, ...)
 {
 	va_list ap;
-	int errnum, rv;
+	int errno_value, rv;
 
-	errnum = errno;
+	errno_value = errno;
 
 	va_start(ap, fmt);
-	rv = tls_error_vset(&ctx->error, errnum, fmt, ap);
+	rv = tls_error_vset(&ctx->error, code, errno_value, fmt, ap);
 	va_end(ap);
 
 	return (rv);
 }
 
 int
-tls_set_errorx(struct tls *ctx, const char *fmt, ...)
+tls_set_errorx(struct tls *ctx, int code, const char *fmt, ...)
 {
 	va_list ap;
 	int rv;
 
 	va_start(ap, fmt);
-	rv = tls_error_vset(&ctx->error, -1, fmt, ap);
+	rv = tls_error_vset(&ctx->error, code, -1, fmt, ap);
 	va_end(ap);
 
 	return (rv);
 }
 
 int
-tls_set_ssl_errorx(struct tls *ctx, const char *fmt, ...)
+tls_set_ssl_errorx(struct tls *ctx, int code, const char *fmt, ...)
 {
 	va_list ap;
 	int rv;
@@ -209,7 +218,7 @@ tls_set_ssl_errorx(struct tls *ctx, const char *fmt, ...)
 		return (0);
 
 	va_start(ap, fmt);
-	rv = tls_error_vset(&ctx->error, -1, fmt, ap);
+	rv = tls_error_vset(&ctx->error, code, -1, fmt, ap);
 	va_end(ap);
 
 	return (rv);
@@ -350,30 +359,34 @@ tls_keypair_to_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY **pke
 		return (0);
 
 	if (len > INT_MAX) {
-		tls_set_errorx(ctx, ctx->config->use_fake_private_key ?
-		    "cert too long" : "key too long");
+		tls_set_errorx(ctx, TLS_ERROR_INVALID_ARGUMENT,
+		    ctx->config->use_fake_private_key ?
+		    "certificate too long" : "key too long");
 		goto err;
 	}
 
 	if ((bio = BIO_new_mem_buf(mem, len)) == NULL) {
-		tls_set_errorx(ctx, "failed to create buffer");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "failed to create buffer");
 		goto err;
 	}
 
 	if (ctx->config->use_fake_private_key) {
 		if ((x509 = PEM_read_bio_X509(bio, NULL, tls_password_cb,
 		    NULL)) == NULL) {
-			tls_set_errorx(ctx, "failed to read X509 certificate");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to read X509 certificate");
 			goto err;
 		}
 		if ((*pkey = X509_get_pubkey(x509)) == NULL) {
-			tls_set_errorx(ctx, "failed to retrieve pubkey");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to retrieve pubkey");
 			goto err;
 		}
 	} else {
 		if ((*pkey = PEM_read_bio_PrivateKey(bio, NULL, tls_password_cb,
 		    NULL)) ==  NULL) {
-			tls_set_errorx(ctx, "failed to read private key");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to read private key");
 			goto err;
 		}
 	}
@@ -399,7 +412,7 @@ tls_keypair_setup_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY *p
 		return (0);
 
 	if (keypair->pubkey_hash == NULL) {
-		tls_set_errorx(ctx, "public key hash not set");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "public key hash not set");
 		goto err;
 	}
 
@@ -407,7 +420,8 @@ tls_keypair_setup_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY *p
 	case EVP_PKEY_RSA:
 		if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL ||
 		    RSA_set_ex_data(rsa, 0, keypair->pubkey_hash) == 0) {
-			tls_set_errorx(ctx, "RSA key setup failure");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "RSA key setup failure");
 			goto err;
 		}
 		if (ctx->config->sign_cb != NULL) {
@@ -415,20 +429,23 @@ tls_keypair_setup_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY *p
 			if (rsa_method == NULL ||
 			    RSA_set_ex_data(rsa, 1, ctx->config) == 0 ||
 			    RSA_set_method(rsa, rsa_method) == 0) {
-				tls_set_errorx(ctx, "failed to setup RSA key");
+				tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+				    "failed to setup RSA key");
 				goto err;
 			}
 		}
 		/* Reset the key to work around caching in OpenSSL 3. */
 		if (EVP_PKEY_set1_RSA(pkey, rsa) == 0) {
-			tls_set_errorx(ctx, "failed to set RSA key");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to set RSA key");
 			goto err;
 		}
 		break;
 	case EVP_PKEY_EC:
 		if ((eckey = EVP_PKEY_get1_EC_KEY(pkey)) == NULL ||
 		    EC_KEY_set_ex_data(eckey, 0, keypair->pubkey_hash) == 0) {
-			tls_set_errorx(ctx, "EC key setup failure");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "EC key setup failure");
 			goto err;
 		}
 		if (ctx->config->sign_cb != NULL) {
@@ -436,18 +453,20 @@ tls_keypair_setup_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY *p
 			if (ecdsa_method == NULL ||
 			    EC_KEY_set_ex_data(eckey, 1, ctx->config) == 0 ||
 			    EC_KEY_set_method(eckey, ecdsa_method) == 0) {
-				tls_set_errorx(ctx, "failed to setup EC key");
+				tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+				    "failed to setup EC key");
 				goto err;
 			}
 		}
 		/* Reset the key to work around caching in OpenSSL 3. */
 		if (EVP_PKEY_set1_EC_KEY(pkey, eckey) == 0) {
-			tls_set_errorx(ctx, "failed to set EC key");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to set EC key");
 			goto err;
 		}
 		break;
 	default:
-		tls_set_errorx(ctx, "incorrect key type");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "incorrect key type");
 		goto err;
 	}
 
@@ -472,13 +491,15 @@ tls_configure_ssl_keypair(struct tls *ctx, SSL_CTX *ssl_ctx,
 
 	if (keypair->cert_mem != NULL) {
 		if (keypair->cert_len > INT_MAX) {
-			tls_set_errorx(ctx, "certificate too long");
+			tls_set_errorx(ctx, TLS_ERROR_INVALID_ARGUMENT,
+			    "certificate too long");
 			goto err;
 		}
 
 		if (SSL_CTX_use_certificate_chain_mem(ssl_ctx,
 		    keypair->cert_mem, keypair->cert_len) != 1) {
-			tls_set_errorx(ctx, "failed to load certificate");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to load certificate");
 			goto err;
 		}
 	}
@@ -489,7 +510,8 @@ tls_configure_ssl_keypair(struct tls *ctx, SSL_CTX *ssl_ctx,
 		if (tls_keypair_setup_pkey(ctx, keypair, pkey) == -1)
 			goto err;
 		if (SSL_CTX_use_PrivateKey(ssl_ctx, pkey) != 1) {
-			tls_set_errorx(ctx, "failed to load private key");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to load private key");
 			goto err;
 		}
 		EVP_PKEY_free(pkey);
@@ -498,7 +520,8 @@ tls_configure_ssl_keypair(struct tls *ctx, SSL_CTX *ssl_ctx,
 
 	if (!ctx->config->skip_private_key_check &&
 	    SSL_CTX_check_private_key(ssl_ctx) != 1) {
-		tls_set_errorx(ctx, "private/public key mismatch");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "private/public key mismatch");
 		goto err;
 	}
 
@@ -534,7 +557,8 @@ tls_configure_ssl(struct tls *ctx, SSL_CTX *ssl_ctx)
 	if (ctx->config->alpn != NULL) {
 		if (SSL_CTX_set_alpn_protos(ssl_ctx, ctx->config->alpn,
 		    ctx->config->alpn_len) != 0) {
-			tls_set_errorx(ctx, "failed to set alpn");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to set alpn");
 			goto err;
 		}
 	}
@@ -542,7 +566,8 @@ tls_configure_ssl(struct tls *ctx, SSL_CTX *ssl_ctx)
 	if (ctx->config->ciphers != NULL) {
 		if (SSL_CTX_set_cipher_list(ssl_ctx,
 		    ctx->config->ciphers) != 1) {
-			tls_set_errorx(ctx, "failed to set ciphers");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to set ciphers");
 			goto err;
 		}
 	}
@@ -572,7 +597,8 @@ tls_ssl_cert_verify_cb(X509_STORE_CTX *x509_ctx, void *arg)
 		return (1);
 
 	if ((X509_verify_cert(x509_ctx)) < 0) {
-		tls_set_errorx(ctx, "X509 verify cert failed");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "X509 verify cert failed");
 		return (0);
 	}
 
@@ -580,7 +606,8 @@ tls_ssl_cert_verify_cb(X509_STORE_CTX *x509_ctx, void *arg)
 	if (x509_err == X509_V_OK)
 		return (1);
 
-	tls_set_errorx(ctx, "certificate verification failed: %s",
+	tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+	    "certificate verification failed: %s",
 	    X509_verify_cert_error_string(x509_err));
 
 	return (0);
@@ -620,31 +647,37 @@ tls_configure_ssl_verify(struct tls *ctx, SSL_CTX *ssl_ctx, int verify)
 
 	if (ca_mem != NULL) {
 		if (ca_len > INT_MAX) {
-			tls_set_errorx(ctx, "ca too long");
+			tls_set_errorx(ctx, TLS_ERROR_INVALID_ARGUMENT,
+			    "ca too long");
 			goto err;
 		}
 		if (SSL_CTX_load_verify_mem(ssl_ctx, ca_mem, ca_len) != 1) {
-			tls_set_errorx(ctx, "ssl verify memory setup failure");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "ssl verify memory setup failure");
 			goto err;
 		}
 	} else if (SSL_CTX_load_verify_locations(ssl_ctx, NULL,
 	    ctx->config->ca_path) != 1) {
-		tls_set_errorx(ctx, "ssl verify locations failure");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "ssl verify locations failure");
 		goto err;
 	}
 
 	if (crl_mem != NULL) {
 		if (crl_len > INT_MAX) {
-			tls_set_errorx(ctx, "crl too long");
+			tls_set_errorx(ctx, TLS_ERROR_INVALID_ARGUMENT,
+			    "crl too long");
 			goto err;
 		}
 		if ((bio = BIO_new_mem_buf(crl_mem, crl_len)) == NULL) {
-			tls_set_errorx(ctx, "failed to create buffer");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to create buffer");
 			goto err;
 		}
 		if ((xis = PEM_X509_INFO_read_bio(bio, NULL, tls_password_cb,
 		    NULL)) == NULL) {
-			tls_set_errorx(ctx, "failed to parse crl");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to parse crl");
 			goto err;
 		}
 		store = SSL_CTX_get_cert_store(ssl_ctx);
@@ -653,7 +686,8 @@ tls_configure_ssl_verify(struct tls *ctx, SSL_CTX *ssl_ctx, int verify)
 			if (xi->crl == NULL)
 				continue;
 			if (!X509_STORE_add_crl(store, xi->crl)) {
-				tls_set_error(ctx, "failed to add crl");
+				tls_set_error(ctx, TLS_ERROR_UNKNOWN,
+				    "failed to add crl");
 				goto err;
 			}
 		}
@@ -709,7 +743,7 @@ tls_reset(struct tls *ctx)
 
 	free(ctx->error.msg);
 	ctx->error.msg = NULL;
-	ctx->error.num = -1;
+	ctx->error.errno_value = -1;
 
 	tls_conninfo_free(ctx->conninfo);
 	ctx->conninfo = NULL;
@@ -759,21 +793,24 @@ tls_ssl_error(struct tls *ctx, SSL *ssl_conn, int ssl_ret, const char *prefix)
 		} else if (ssl_ret == -1) {
 			errstr = strerror(errno);
 		}
-		tls_set_ssl_errorx(ctx, "%s failed: %s", prefix, errstr);
+		tls_set_ssl_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "%s failed: %s", prefix, errstr);
 		return (-1);
 
 	case SSL_ERROR_SSL:
 		if ((err = ERR_peek_error()) != 0) {
 			errstr = ERR_error_string(err, NULL);
 		}
-		tls_set_ssl_errorx(ctx, "%s failed: %s", prefix, errstr);
+		tls_set_ssl_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "%s failed: %s", prefix, errstr);
 		return (-1);
 
 	case SSL_ERROR_WANT_CONNECT:
 	case SSL_ERROR_WANT_ACCEPT:
 	case SSL_ERROR_WANT_X509_LOOKUP:
 	default:
-		tls_set_ssl_errorx(ctx, "%s failed (%d)", prefix, ssl_err);
+		tls_set_ssl_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "%s failed (%d)", prefix, ssl_err);
 		return (-1);
 	}
 }
@@ -786,12 +823,14 @@ tls_handshake(struct tls *ctx)
 	tls_error_clear(&ctx->error);
 
 	if ((ctx->flags & (TLS_CLIENT | TLS_SERVER_CONN)) == 0) {
-		tls_set_errorx(ctx, "invalid operation for context");
+		tls_set_errorx(ctx, TLS_ERROR_INVALID_CONTEXT,
+		    "invalid operation for context");
 		goto out;
 	}
 
 	if ((ctx->state & TLS_HANDSHAKE_COMPLETE) != 0) {
-		tls_set_errorx(ctx, "handshake already completed");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "handshake already completed");
 		goto out;
 	}
 
@@ -828,7 +867,8 @@ tls_read(struct tls *ctx, void *buf, size_t buflen)
 	}
 
 	if (buflen > INT_MAX) {
-		tls_set_errorx(ctx, "buflen too long");
+		tls_set_errorx(ctx, TLS_ERROR_INVALID_ARGUMENT,
+		    "buflen too long");
 		goto out;
 	}
 
@@ -859,7 +899,8 @@ tls_write(struct tls *ctx, const void *buf, size_t buflen)
 	}
 
 	if (buflen > INT_MAX) {
-		tls_set_errorx(ctx, "buflen too long");
+		tls_set_errorx(ctx, TLS_ERROR_INVALID_ARGUMENT,
+		    "buflen too long");
 		goto out;
 	}
 
@@ -885,7 +926,8 @@ tls_close(struct tls *ctx)
 	tls_error_clear(&ctx->error);
 
 	if ((ctx->flags & (TLS_CLIENT | TLS_SERVER_CONN)) == 0) {
-		tls_set_errorx(ctx, "invalid operation for context");
+		tls_set_errorx(ctx, TLS_ERROR_INVALID_CONTEXT,
+		    "invalid operation for context");
 		rv = -1;
 		goto out;
 	}
@@ -906,13 +948,13 @@ tls_close(struct tls *ctx)
 		if (shutdown(ctx->socket, SHUT_RDWR) != 0) {
 			if (rv == 0 &&
 			    errno != ENOTCONN && errno != ECONNRESET) {
-				tls_set_error(ctx, "shutdown");
+				tls_set_error(ctx, TLS_ERROR_UNKNOWN, "shutdown");
 				rv = -1;
 			}
 		}
 		if (close(ctx->socket) != 0) {
 			if (rv == 0) {
-				tls_set_error(ctx, "close");
+				tls_set_error(ctx, TLS_ERROR_UNKNOWN, "close");
 				rv = -1;
 			}
 		}
@@ -920,7 +962,7 @@ tls_close(struct tls *ctx)
 	}
 
 	if ((ctx->state & TLS_EOF_NO_CLOSE_NOTIFY) != 0) {
-		tls_set_errorx(ctx, "EOF without close notify");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "EOF without close notify");
 		rv = -1;
 	}
 
diff --git a/tls_bio_cb.c b/tls_bio_cb.c
index 8a1edfd..56b9e12 100644
--- a/tls_bio_cb.c
+++ b/tls_bio_cb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tls_bio_cb.c,v 1.21 2023/05/14 07:26:25 op Exp $ */
+/* $OpenBSD: tls_bio_cb.c,v 1.22 2024/03/26 06:24:52 joshua Exp $ */
 /*
  * Copyright (c) 2016 Tobias Pape <tobias@netshed.de>
  *
@@ -143,7 +143,7 @@ tls_set_cbs(struct tls *ctx, tls_read_cb read_cb, tls_write_cb write_cb,
 	int rv = -1;
 
 	if (read_cb == NULL || write_cb == NULL) {
-		tls_set_errorx(ctx, "no callbacks provided");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "no callbacks provided");
 		goto err;
 	}
 
@@ -152,11 +152,13 @@ tls_set_cbs(struct tls *ctx, tls_read_cb read_cb, tls_write_cb write_cb,
 	ctx->cb_arg = cb_arg;
 
 	if ((bio_cb = bio_s_cb()) == NULL) {
-		tls_set_errorx(ctx, "failed to create callback method");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "failed to create callback method");
 		goto err;
 	}
 	if ((bio = BIO_new(bio_cb)) == NULL) {
-		tls_set_errorx(ctx, "failed to create callback i/o");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "failed to create callback i/o");
 		goto err;
 	}
 	BIO_set_data(bio, ctx);
diff --git a/tls_client.c b/tls_client.c
index deb24eb..97e1d40 100644
--- a/tls_client.c
+++ b/tls_client.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tls_client.c,v 1.49 2023/05/14 07:26:25 op Exp $ */
+/* $OpenBSD: tls_client.c,v 1.51 2024/03/26 08:54:48 joshua Exp $ */
 /*
  * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
  *
@@ -66,12 +66,13 @@ tls_connect_servername(struct tls *ctx, const char *host, const char *port,
 	int rv = -1, s = -1, ret;
 
 	if ((ctx->flags & TLS_CLIENT) == 0) {
-		tls_set_errorx(ctx, "not a client context");
+		tls_set_errorx(ctx, TLS_ERROR_INVALID_CONTEXT,
+		    "not a client context");
 		goto err;
 	}
 
 	if (host == NULL) {
-		tls_set_errorx(ctx, "host not specified");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "host not specified");
 		goto err;
 	}
 
@@ -79,11 +80,11 @@ tls_connect_servername(struct tls *ctx, const char *host, const char *port,
 	if (port == NULL) {
 		ret = tls_host_port(host, &hs, &ps);
 		if (ret == -1) {
-			tls_set_errorx(ctx, "memory allocation failure");
+			tls_set_errorx(ctx, TLS_ERROR_OUT_OF_MEMORY, "out of memory");
 			goto err;
 		}
 		if (ret != 0) {
-			tls_set_errorx(ctx, "no port provided");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "no port provided");
 			goto err;
 		}
 	}
@@ -114,7 +115,8 @@ tls_connect_servername(struct tls *ctx, const char *host, const char *port,
 			hints.ai_family = AF_UNSPEC;
 			hints.ai_flags = AI_ADDRCONFIG;
 			if ((s = getaddrinfo(h, p, &hints, &res0)) != 0) {
-				tls_set_error(ctx, "%s", gai_strerror(s));
+				tls_set_error(ctx, TLS_ERROR_UNKNOWN,
+				    "%s", gai_strerror(s));
 				goto err;
 			}
 		}
@@ -125,11 +127,13 @@ tls_connect_servername(struct tls *ctx, const char *host, const char *port,
 	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");
+			tls_set_error(ctx, TLS_ERROR_UNKNOWN,
+			    "socket");
 			continue;
 		}
 		if (connect(s, res->ai_addr, res->ai_addrlen) == -1) {
-			tls_set_error(ctx, "connect");
+			tls_set_error(ctx, TLS_ERROR_UNKNOWN,
+			    "connect");
 			close(s);
 			s = -1;
 			continue;
@@ -174,11 +178,13 @@ tls_client_read_session(struct tls *ctx)
 	int rv = -1;
 
 	if (fstat(sfd, &sb) == -1) {
-		tls_set_error(ctx, "failed to stat session file");
+		tls_set_error(ctx, TLS_ERROR_UNKNOWN,
+		    "failed to stat session file");
 		goto err;
 	}
 	if (sb.st_size < 0 || sb.st_size > INT_MAX) {
-		tls_set_errorx(ctx, "invalid session file size");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "invalid session file size");
 		goto err;
 	}
 	session_len = (size_t)sb.st_size;
@@ -192,19 +198,22 @@ tls_client_read_session(struct tls *ctx)
 
 	n = pread(sfd, session, session_len, 0);
 	if (n < 0 || (size_t)n != session_len) {
-		tls_set_error(ctx, "failed to read session file");
+		tls_set_error(ctx, TLS_ERROR_UNKNOWN,
+		    "failed to read session file");
 		goto err;
 	}
 	if ((bio = BIO_new_mem_buf(session, session_len)) == NULL)
 		goto err;
 	if ((ss = PEM_read_bio_SSL_SESSION(bio, NULL, tls_password_cb,
 	    NULL)) == NULL) {
-		tls_set_errorx(ctx, "failed to parse session");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "failed to parse session");
 		goto err;
 	}
 
 	if (SSL_set_session(ctx->ssl_conn, ss) != 1) {
-		tls_set_errorx(ctx, "failed to set session");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "failed to set session");
 		goto err;
 	}
 
@@ -234,7 +243,8 @@ tls_client_write_session(struct tls *ctx)
 
 	if ((ss = SSL_get1_session(ctx->ssl_conn)) == NULL) {
 		if (ftruncate(sfd, 0) == -1) {
-			tls_set_error(ctx, "failed to truncate session file");
+			tls_set_error(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to truncate session file");
 			goto err;
 		}
 		goto done;
@@ -251,12 +261,14 @@ tls_client_write_session(struct tls *ctx)
 	offset = 0;
 
 	if (ftruncate(sfd, len) == -1) {
-		tls_set_error(ctx, "failed to truncate session file");
+		tls_set_error(ctx, TLS_ERROR_UNKNOWN,
+		    "failed to truncate session file");
 		goto err;
 	}
 	while (len > 0) {
 		if ((n = pwrite(sfd, data + offset, len, offset)) == -1) {
-			tls_set_error(ctx, "failed to write session file");
+			tls_set_error(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to write session file");
 			goto err;
 		}
 		offset += n;
@@ -281,13 +293,15 @@ tls_connect_common(struct tls *ctx, const char *servername)
 	int rv = -1;
 
 	if ((ctx->flags & TLS_CLIENT) == 0) {
-		tls_set_errorx(ctx, "not a client context");
+		tls_set_errorx(ctx, TLS_ERROR_INVALID_CONTEXT,
+		    "not a client context");
 		goto err;
 	}
 
 	if (servername != NULL) {
 		if ((ctx->servername = strdup(servername)) == NULL) {
-			tls_set_errorx(ctx, "out of memory");
+			tls_set_errorx(ctx, TLS_ERROR_OUT_OF_MEMORY,
+			    "out of memory");
 			goto err;
 		}
 
@@ -304,7 +318,7 @@ tls_connect_common(struct tls *ctx, const char *servername)
 	}
 
 	if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) {
-		tls_set_errorx(ctx, "ssl context failure");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "ssl context failure");
 		goto err;
 	}
 
@@ -317,7 +331,8 @@ tls_connect_common(struct tls *ctx, const char *servername)
 
 	if (ctx->config->verify_name) {
 		if (ctx->servername == NULL) {
-			tls_set_errorx(ctx, "server name not specified");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "server name not specified");
 			goto err;
 		}
 	}
@@ -328,23 +343,26 @@ tls_connect_common(struct tls *ctx, const char *servername)
 	if (ctx->config->ecdhecurves != NULL) {
 		if (SSL_CTX_set1_groups(ctx->ssl_ctx, ctx->config->ecdhecurves,
 		    ctx->config->ecdhecurves_len) != 1) {
-			tls_set_errorx(ctx, "failed to set ecdhe curves");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to set ecdhe curves");
 			goto err;
 		}
 	}
 
 	if (SSL_CTX_set_tlsext_status_cb(ctx->ssl_ctx, tls_ocsp_verify_cb) != 1) {
-		tls_set_errorx(ctx, "ssl OCSP verification setup failure");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "ssl OCSP verification setup failure");
 		goto err;
 	}
 
 	if ((ctx->ssl_conn = SSL_new(ctx->ssl_ctx)) == NULL) {
-		tls_set_errorx(ctx, "ssl connection failure");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "ssl connection failure");
 		goto err;
 	}
 
 	if (SSL_set_app_data(ctx->ssl_conn, ctx) != 1) {
-		tls_set_errorx(ctx, "ssl application data failure");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "ssl application data failure");
 		goto err;
 	}
 
@@ -355,7 +373,8 @@ tls_connect_common(struct tls *ctx, const char *servername)
 	}
 
 	if (SSL_set_tlsext_status_type(ctx->ssl_conn, TLSEXT_STATUSTYPE_ocsp) != 1) {
-		tls_set_errorx(ctx, "ssl OCSP extension setup failure");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "ssl OCSP extension setup failure");
 		goto err;
 	}
 
@@ -368,7 +387,8 @@ tls_connect_common(struct tls *ctx, const char *servername)
 	    inet_pton(AF_INET6, ctx->servername, &addrbuf) != 1) {
 		if (SSL_set_tlsext_host_name(ctx->ssl_conn,
 		    ctx->servername) == 0) {
-			tls_set_errorx(ctx, "server name indication failure");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "server name indication failure");
 			goto err;
 		}
 	}
@@ -393,7 +413,7 @@ tls_connect_fds(struct tls *ctx, int fd_read, int fd_write,
 	int rv = -1;
 
 	if (fd_read < 0 || fd_write < 0) {
-		tls_set_errorx(ctx, "invalid file descriptors");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "invalid file descriptors");
 		goto err;
 	}
 
@@ -402,7 +422,8 @@ tls_connect_fds(struct tls *ctx, int fd_read, int fd_write,
 
 	if (SSL_set_rfd(ctx->ssl_conn, fd_read) != 1 ||
 	    SSL_set_wfd(ctx->ssl_conn, fd_write) != 1) {
-		tls_set_errorx(ctx, "ssl file descriptor failure");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "ssl file descriptor failure");
 		goto err;
 	}
 
@@ -437,12 +458,13 @@ tls_handshake_client(struct tls *ctx)
 	int rv = -1;
 
 	if ((ctx->flags & TLS_CLIENT) == 0) {
-		tls_set_errorx(ctx, "not a client context");
+		tls_set_errorx(ctx, TLS_ERROR_INVALID_CONTEXT,
+		    "not a client context");
 		goto err;
 	}
 
 	if ((ctx->state & TLS_CONNECTED) == 0) {
-		tls_set_errorx(ctx, "context not connected");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "context not connected");
 		goto err;
 	}
 
@@ -457,14 +479,16 @@ tls_handshake_client(struct tls *ctx)
 	if (ctx->config->verify_name) {
 		cert = SSL_get_peer_certificate(ctx->ssl_conn);
 		if (cert == NULL) {
-			tls_set_errorx(ctx, "no server certificate");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "no server certificate");
 			goto err;
 		}
 		if (tls_check_name(ctx, cert, ctx->servername, &match) == -1)
 			goto err;
 		if (!match) {
-			tls_set_errorx(ctx, "name `%s' not present in"
-			    " server certificate", ctx->servername);
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "name `%s' not present in server certificate",
+			    ctx->servername);
 			goto err;
 		}
 	}
diff --git a/tls_config.c b/tls_config.c
index 5eb5b69..22fa845 100644
--- a/tls_config.c
+++ b/tls_config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tls_config.c,v 1.67 2023/07/02 06:37:27 beck Exp $ */
+/* $OpenBSD: tls_config.c,v 1.71 2024/08/02 15:00:01 tb Exp $ */
 /*
  * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
  *
@@ -50,12 +50,14 @@ tls_config_load_file(struct tls_error *error, const char *filetype,
 	*len = 0;
 
 	if ((fd = open(filename, O_RDONLY)) == -1) {
-		tls_error_set(error, "failed to open %s file '%s'",
+		tls_error_set(error, TLS_ERROR_UNKNOWN,
+		    "failed to open %s file '%s'",
 		    filetype, filename);
 		goto err;
 	}
 	if (fstat(fd, &st) != 0) {
-		tls_error_set(error, "failed to stat %s file '%s'",
+		tls_error_set(error, TLS_ERROR_UNKNOWN,
+		    "failed to stat %s file '%s'",
 		    filetype, filename);
 		goto err;
 	}
@@ -63,13 +65,15 @@ tls_config_load_file(struct tls_error *error, const char *filetype,
 		goto err;
 	*len = (size_t)st.st_size;
 	if ((*buf = malloc(*len)) == NULL) {
-		tls_error_set(error, "failed to allocate buffer for "
-		    "%s file", filetype);
+		tls_error_set(error, TLS_ERROR_UNKNOWN,
+		    "failed to allocate buffer for %s file",
+		    filetype);
 		goto err;
 	}
 	n = read(fd, *buf, *len);
 	if (n < 0 || (size_t)n != *len) {
-		tls_error_set(error, "failed to read %s file '%s'",
+		tls_error_set(error, TLS_ERROR_UNKNOWN,
+		    "failed to read %s file '%s'",
 		    filetype, filename);
 		goto err;
 	}
@@ -203,6 +207,12 @@ tls_config_error(struct tls_config *config)
 	return config->error.msg;
 }
 
+int
+tls_config_error_code(struct tls_config *config)
+{
+	return config->error.code;
+}
+
 void
 tls_config_clear_keys(struct tls_config *config)
 {
@@ -251,9 +261,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_2;
+			proto = TLS_PROTOCOL_TLSv1_0;
 		else if (strcasecmp(p, "tlsv1.1") == 0)
-			proto = TLS_PROTOCOL_TLSv1_2;
+			proto = TLS_PROTOCOL_TLSv1_1;
 		else if (strcasecmp(p, "tlsv1.2") == 0)
 			proto = TLS_PROTOCOL_TLSv1_2;
 		else if (strcasecmp(p, "tlsv1.3") == 0)
@@ -291,17 +301,20 @@ tls_config_parse_alpn(struct tls_config *config, const char *alpn,
 	*alpn_len = 0;
 
 	if ((buf_len = strlen(alpn) + 1) > 65535) {
-		tls_config_set_errorx(config, "alpn too large");
+		tls_config_set_errorx(config, TLS_ERROR_INVALID_ARGUMENT,
+		    "alpn too large");
 		goto err;
 	}
 
 	if ((buf = malloc(buf_len)) == NULL) {
-		tls_config_set_errorx(config, "out of memory");
+		tls_config_set_errorx(config, TLS_ERROR_OUT_OF_MEMORY,
+		    "out of memory");
 		goto err;
 	}
 
 	if ((s = strdup(alpn)) == NULL) {
-		tls_config_set_errorx(config, "out of memory");
+		tls_config_set_errorx(config, TLS_ERROR_OUT_OF_MEMORY,
+		    "out of memory");
 		goto err;
 	}
 
@@ -309,12 +322,12 @@ tls_config_parse_alpn(struct tls_config *config, const char *alpn,
 	q = s;
 	while ((p = strsep(&q, ",")) != NULL) {
 		if ((len = strlen(p)) == 0) {
-			tls_config_set_errorx(config,
+			tls_config_set_errorx(config, TLS_ERROR_INVALID_ARGUMENT,
 			    "alpn protocol with zero length");
 			goto err;
 		}
 		if (len > 255) {
-			tls_config_set_errorx(config,
+			tls_config_set_errorx(config, TLS_ERROR_INVALID_ARGUMENT,
 			    "alpn protocol too long");
 			goto err;
 		}
@@ -484,11 +497,13 @@ tls_config_set_ciphers(struct tls_config *config, const char *ciphers)
 		ciphers = TLS_CIPHERS_ALL;
 
 	if ((ssl_ctx = SSL_CTX_new(SSLv23_method())) == NULL) {
-		tls_config_set_errorx(config, "out of memory");
+		tls_config_set_errorx(config, TLS_ERROR_OUT_OF_MEMORY,
+		    "out of memory");
 		goto err;
 	}
 	if (SSL_CTX_set_cipher_list(ssl_ctx, ciphers) != 1) {
-		tls_config_set_errorx(config, "no ciphers for '%s'", ciphers);
+		tls_config_set_errorx(config, TLS_ERROR_UNKNOWN,
+		    "no ciphers for '%s'", ciphers);
 		goto err;
 	}
 
@@ -526,7 +541,8 @@ tls_config_set_dheparams(struct tls_config *config, const char *params)
 	else if (strcasecmp(params, "legacy") == 0)
 		keylen = 1024;
 	else {
-		tls_config_set_errorx(config, "invalid dhe param '%s'", params);
+		tls_config_set_errorx(config, TLS_ERROR_UNKNOWN,
+		    "invalid dhe param '%s'", params);
 		return (-1);
 	}
 
@@ -543,8 +559,8 @@ tls_config_set_ecdhecurve(struct tls_config *config, const char *curve)
 	    strcasecmp(curve, "auto") == 0) {
 		curve = TLS_ECDHE_CURVES;
 	} else if (strchr(curve, ',') != NULL || strchr(curve, ':') != NULL) {
-		tls_config_set_errorx(config, "invalid ecdhe curve '%s'",
-		    curve);
+		tls_config_set_errorx(config, TLS_ERROR_UNKNOWN,
+		    "invalid ecdhe curve '%s'", curve);
 		return (-1);
 	}
 
@@ -569,7 +585,8 @@ tls_config_set_ecdhecurves(struct tls_config *config, const char *curves)
 		curves = TLS_ECDHE_CURVES;
 
 	if ((cs = strdup(curves)) == NULL) {
-		tls_config_set_errorx(config, "out of memory");
+		tls_config_set_errorx(config, TLS_ERROR_OUT_OF_MEMORY,
+		    "out of memory");
 		goto err;
 	}
 
@@ -584,14 +601,15 @@ tls_config_set_ecdhecurves(struct tls_config *config, const char *curves)
 		if (nid == NID_undef)
 			nid = EC_curve_nist2nid(p);
 		if (nid == NID_undef) {
-			tls_config_set_errorx(config,
+			tls_config_set_errorx(config, TLS_ERROR_UNKNOWN,
 			    "invalid ecdhe curve '%s'", p);
 			goto err;
 		}
 
 		if ((curves_new = reallocarray(curves_list, curves_num + 1,
 		    sizeof(int))) == NULL) {
-			tls_config_set_errorx(config, "out of memory");
+			tls_config_set_errorx(config, TLS_ERROR_OUT_OF_MEMORY,
+			    "out of memory");
 			goto err;
 		}
 		curves_list = curves_new;
@@ -712,24 +730,26 @@ tls_config_set_session_fd(struct tls_config *config, int session_fd)
 	}
 
 	if (fstat(session_fd, &sb) == -1) {
-		tls_config_set_error(config, "failed to stat session file");
+		tls_config_set_error(config, TLS_ERROR_UNKNOWN,
+		    "failed to stat session file");
 		return (-1);
 	}
 	if (!S_ISREG(sb.st_mode)) {
-		tls_config_set_errorx(config,
+		tls_config_set_errorx(config, TLS_ERROR_UNKNOWN,
 		    "session file is not a regular file");
 		return (-1);
 	}
 
 	if (sb.st_uid != getuid()) {
-		tls_config_set_errorx(config, "session file has incorrect "
-		    "owner (uid %u != %u)", sb.st_uid, getuid());
+		tls_config_set_errorx(config, TLS_ERROR_UNKNOWN,
+		    "session file has incorrect owner (uid %u != %u)",
+		    sb.st_uid, getuid());
 		return (-1);
 	}
 	mugo = sb.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
 	if (mugo != (S_IRUSR|S_IWUSR)) {
-		tls_config_set_errorx(config, "session file has incorrect "
-		    "permissions (%o != 600)", mugo);
+		tls_config_set_errorx(config, TLS_ERROR_UNKNOWN,
+		    "session file has incorrect permissions (%o != 600)", mugo);
 		return (-1);
 	}
 
@@ -846,7 +866,8 @@ tls_config_set_session_id(struct tls_config *config,
     const unsigned char *session_id, size_t len)
 {
 	if (len > TLS_MAX_SESSION_ID_LENGTH) {
-		tls_config_set_errorx(config, "session ID too large");
+		tls_config_set_errorx(config, TLS_ERROR_INVALID_ARGUMENT,
+		    "session ID too large");
 		return (-1);
 	}
 	memset(config->session_id, 0, sizeof(config->session_id));
@@ -858,11 +879,13 @@ int
 tls_config_set_session_lifetime(struct tls_config *config, int lifetime)
 {
 	if (lifetime > TLS_MAX_SESSION_TIMEOUT) {
-		tls_config_set_errorx(config, "session lifetime too large");
+		tls_config_set_errorx(config, TLS_ERROR_INVALID_ARGUMENT,
+		    "session lifetime too large");
 		return (-1);
 	}
 	if (lifetime != 0 && lifetime < TLS_MIN_SESSION_TIMEOUT) {
-		tls_config_set_errorx(config, "session lifetime too small");
+		tls_config_set_errorx(config, TLS_ERROR_INVALID_ARGUMENT,
+		    "session lifetime too small");
 		return (-1);
 	}
 
@@ -879,7 +902,7 @@ tls_config_add_ticket_key(struct tls_config *config, uint32_t keyrev,
 
 	if (TLS_TICKET_KEY_SIZE != keylen ||
 	    sizeof(newkey.aes_key) + sizeof(newkey.hmac_key) > keylen) {
-		tls_config_set_errorx(config,
+		tls_config_set_errorx(config, TLS_ERROR_UNKNOWN,
 		    "wrong amount of ticket key data");
 		return (-1);
 	}
@@ -903,7 +926,8 @@ tls_config_add_ticket_key(struct tls_config *config, uint32_t keyrev,
 		    sizeof(tk->aes_key)) == 0 && memcmp(newkey.hmac_key,
 		    tk->hmac_key, sizeof(tk->hmac_key)) == 0)
 			return (0);
-		tls_config_set_errorx(config, "ticket key already present");
+		tls_config_set_errorx(config, TLS_ERROR_UNKNOWN,
+		    "ticket key already present");
 		return (-1);
 	}
 
diff --git a/tls_conninfo.c b/tls_conninfo.c
index 90fdfac..bf52517 100644
--- a/tls_conninfo.c
+++ b/tls_conninfo.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tls_conninfo.c,v 1.24 2023/11/13 10:51:49 tb Exp $ */
+/* $OpenBSD: tls_conninfo.c,v 1.27 2024/03/26 06:31:22 jsing Exp $ */
 /*
  * Copyright (c) 2015 Joel Sing <jsing@openbsd.org>
  * Copyright (c) 2015 Bob Beck <beck@openbsd.org>
@@ -19,12 +19,27 @@
 #include <stdio.h>
 #include <string.h>
 
+#include <openssl/posix_time.h>
 #include <openssl/x509.h>
 
 #include <tls.h>
 #include "tls_internal.h"
 
-int ASN1_time_tm_clamp_notafter(struct tm *tm);
+static int
+tls_convert_notafter(struct tm *tm, time_t *out_time)
+{
+	int64_t posix_time;
+
+	/* OPENSSL_timegm() fails if tm is not representable in a time_t */
+	if (OPENSSL_timegm(tm, out_time))
+		return 1;
+	if (!OPENSSL_tm_to_posix(tm, &posix_time))
+		return 0;
+	if (posix_time < INT32_MIN)
+		return 0;
+	*out_time = (posix_time > INT32_MAX) ? INT32_MAX : posix_time;
+	return 1;
+}
 
 int
 tls_hex_string(const unsigned char *in, size_t inlen, char **out,
@@ -64,7 +79,7 @@ tls_get_peer_cert_hash(struct tls *ctx, char **hash)
 		return (0);
 
 	if (tls_cert_hash(ctx->ssl_peer_cert, hash) == -1) {
-		tls_set_errorx(ctx, "unable to compute peer certificate hash - out of memory");
+		tls_set_errorx(ctx, TLS_ERROR_OUT_OF_MEMORY, "out of memory");
 		*hash = NULL;
 		return -1;
 	}
@@ -121,13 +136,10 @@ tls_get_peer_cert_times(struct tls *ctx, time_t *notbefore,
 		goto err;
 	if (!ASN1_TIME_to_tm(after, &after_tm))
 		goto err;
-	if (!ASN1_time_tm_clamp_notafter(&after_tm))
+	if (!tls_convert_notafter(&after_tm, notafter))
 		goto err;
-	if ((*notbefore = timegm(&before_tm)) == -1)
+	if (!OPENSSL_timegm(&before_tm, notbefore))
 		goto err;
-	if ((*notafter = timegm(&after_tm)) == -1)
-		goto err;
-
 	return (0);
 
  err:
@@ -233,7 +245,7 @@ tls_conninfo_populate(struct tls *ctx)
 	tls_conninfo_free(ctx->conninfo);
 
 	if ((ctx->conninfo = calloc(1, sizeof(struct tls_conninfo))) == NULL) {
-		tls_set_errorx(ctx, "out of memory");
+		tls_set_errorx(ctx, TLS_ERROR_OUT_OF_MEMORY, "out of memory");
 		goto err;
 	}
 
diff --git a/tls_internal.h b/tls_internal.h
index 5cac881..5ff48ed 100644
--- a/tls_internal.h
+++ b/tls_internal.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tls_internal.h,v 1.83 2023/06/27 18:19:59 tb Exp $ */
+/* $OpenBSD: tls_internal.h,v 1.85 2024/03/26 06:24:52 joshua Exp $ */
 /*
  * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org>
  * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
@@ -46,7 +46,8 @@ union tls_addr {
 
 struct tls_error {
 	char *msg;
-	int num;
+	int code;
+	int errno_value;
 	int tls;
 };
 
@@ -258,27 +259,27 @@ int tls_set_cbs(struct tls *ctx,
     tls_read_cb read_cb, tls_write_cb write_cb, void *cb_arg);
 
 void tls_error_clear(struct tls_error *error);
-int tls_error_set(struct tls_error *error, const char *fmt, ...)
-    __attribute__((__format__ (printf, 2, 3)))
-    __attribute__((__nonnull__ (2)));
-int tls_error_setx(struct tls_error *error, const char *fmt, ...)
-    __attribute__((__format__ (printf, 2, 3)))
-    __attribute__((__nonnull__ (2)));
-int tls_config_set_error(struct tls_config *cfg, const char *fmt, ...)
-    __attribute__((__format__ (printf, 2, 3)))
-    __attribute__((__nonnull__ (2)));
-int tls_config_set_errorx(struct tls_config *cfg, const char *fmt, ...)
-    __attribute__((__format__ (printf, 2, 3)))
-    __attribute__((__nonnull__ (2)));
-int tls_set_error(struct tls *ctx, const char *fmt, ...)
-    __attribute__((__format__ (printf, 2, 3)))
-    __attribute__((__nonnull__ (2)));
-int tls_set_errorx(struct tls *ctx, const char *fmt, ...)
-    __attribute__((__format__ (printf, 2, 3)))
-    __attribute__((__nonnull__ (2)));
-int tls_set_ssl_errorx(struct tls *ctx, const char *fmt, ...)
-    __attribute__((__format__ (printf, 2, 3)))
-    __attribute__((__nonnull__ (2)));
+int tls_error_set(struct tls_error *error, int code, const char *fmt, ...)
+    __attribute__((__format__ (printf, 3, 4)))
+    __attribute__((__nonnull__ (3)));
+int tls_error_setx(struct tls_error *error, int code, const char *fmt, ...)
+    __attribute__((__format__ (printf, 3, 4)))
+    __attribute__((__nonnull__ (3)));
+int tls_config_set_error(struct tls_config *cfg, int code, const char *fmt, ...)
+    __attribute__((__format__ (printf, 3, 4)))
+    __attribute__((__nonnull__ (3)));
+int tls_config_set_errorx(struct tls_config *cfg, int code, const char *fmt, ...)
+    __attribute__((__format__ (printf, 3, 4)))
+    __attribute__((__nonnull__ (3)));
+int tls_set_error(struct tls *ctx, int code, const char *fmt, ...)
+    __attribute__((__format__ (printf, 3, 4)))
+    __attribute__((__nonnull__ (3)));
+int tls_set_errorx(struct tls *ctx, int code, const char *fmt, ...)
+    __attribute__((__format__ (printf, 3, 4)))
+    __attribute__((__nonnull__ (3)));
+int tls_set_ssl_errorx(struct tls *ctx, int code, const char *fmt, ...)
+    __attribute__((__format__ (printf, 3, 4)))
+    __attribute__((__nonnull__ (3)));
 
 int tls_ssl_error(struct tls *ctx, SSL *ssl_conn, int ssl_ret,
     const char *prefix);
diff --git a/tls_keypair.c b/tls_keypair.c
index a12d21d..ffda91d 100644
--- a/tls_keypair.c
+++ b/tls_keypair.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tls_keypair.c,v 1.8 2021/01/05 17:37:12 jsing Exp $ */
+/* $OpenBSD: tls_keypair.c,v 1.9 2024/03/26 06:24:52 joshua Exp $ */
 /*
  * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
  *
@@ -144,19 +144,22 @@ tls_keypair_load_cert(struct tls_keypair *keypair, struct tls_error *error,
 	*cert = NULL;
 
 	if (keypair->cert_mem == NULL) {
-		tls_error_set(error, "keypair has no certificate");
+		tls_error_set(error, TLS_ERROR_UNKNOWN,
+		    "keypair has no certificate");
 		goto err;
 	}
 	if ((cert_bio = BIO_new_mem_buf(keypair->cert_mem,
 	    keypair->cert_len)) == NULL) {
-		tls_error_set(error, "failed to create certificate bio");
+		tls_error_set(error, TLS_ERROR_UNKNOWN,
+		    "failed to create certificate bio");
 		goto err;
 	}
 	if ((*cert = PEM_read_bio_X509(cert_bio, NULL, tls_password_cb,
 	    NULL)) == NULL) {
 		if ((ssl_err = ERR_peek_error()) != 0)
 			errstr = ERR_error_string(ssl_err, NULL);
-		tls_error_set(error, "failed to load certificate: %s", errstr);
+		tls_error_set(error, TLS_ERROR_UNKNOWN,
+		    "failed to load certificate: %s", errstr);
 		goto err;
 	}
 
diff --git a/tls_ocsp.c b/tls_ocsp.c
index c7eb3e5..bfd06e3 100644
--- a/tls_ocsp.c
+++ b/tls_ocsp.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: tls_ocsp.c,v 1.24 2023/11/13 10:56:19 tb Exp $ */
+/*	$OpenBSD: tls_ocsp.c,v 1.26 2024/03/26 06:24:52 joshua Exp $ */
 /*
  * Copyright (c) 2015 Marko Kreen <markokr@gmail.com>
  * Copyright (c) 2016 Bob Beck <beck@openbsd.org>
@@ -25,6 +25,7 @@
 
 #include <openssl/err.h>
 #include <openssl/ocsp.h>
+#include <openssl/posix_time.h>
 #include <openssl/x509.h>
 
 #include <tls.h>
@@ -68,7 +69,7 @@ tls_ocsp_asn1_parse_time(struct tls *ctx, ASN1_GENERALIZEDTIME *gt, time_t *gt_t
 		return -1;
 	if (!ASN1_TIME_to_tm(gt, &tm))
 		return -1;
-	if ((*gt_time = timegm(&tm)) == -1)
+	if (!OPENSSL_timegm(&tm, gt_time))
 		return -1;
 	return 0;
 }
@@ -84,7 +85,7 @@ tls_ocsp_fill_info(struct tls *ctx, int response_status, int cert_status,
 	ctx->ocsp->ocsp_result = NULL;
 
 	if ((info = calloc(1, sizeof (struct tls_ocsp_result))) == NULL) {
-		tls_set_error(ctx, "calloc");
+		tls_set_error(ctx, TLS_ERROR_OUT_OF_MEMORY, "out of memory");
 		return -1;
 	}
 	info->response_status = response_status;
@@ -101,19 +102,19 @@ tls_ocsp_fill_info(struct tls *ctx, int response_status, int cert_status,
 	info->revocation_time = info->this_update = info->next_update = -1;
 	if (revtime != NULL &&
 	    tls_ocsp_asn1_parse_time(ctx, revtime, &info->revocation_time) != 0) {
-		tls_set_error(ctx,
+		tls_set_error(ctx, TLS_ERROR_UNKNOWN,
 		    "unable to parse revocation time in OCSP reply");
 		goto err;
 	}
 	if (thisupd != NULL &&
 	    tls_ocsp_asn1_parse_time(ctx, thisupd, &info->this_update) != 0) {
-		tls_set_error(ctx,
+		tls_set_error(ctx, TLS_ERROR_UNKNOWN,
 		    "unable to parse this update time in OCSP reply");
 		goto err;
 	}
 	if (nextupd != NULL &&
 	    tls_ocsp_asn1_parse_time(ctx, nextupd, &info->next_update) != 0) {
-		tls_set_error(ctx,
+		tls_set_error(ctx, TLS_ERROR_UNKNOWN,
 		    "unable to parse next update time in OCSP reply");
 		goto err;
 	}
@@ -179,19 +180,21 @@ tls_ocsp_setup_from_peer(struct tls *ctx)
 	ocsp->main_cert = SSL_get_peer_certificate(ctx->ssl_conn);
 	ocsp->extra_certs = SSL_get_peer_cert_chain(ctx->ssl_conn);
 	if (ocsp->main_cert == NULL) {
-		tls_set_errorx(ctx, "no peer certificate for OCSP");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "no peer certificate for OCSP");
 		goto err;
 	}
 
 	ocsp_urls = X509_get1_ocsp(ocsp->main_cert);
 	if (ocsp_urls == NULL) {
-		tls_set_errorx(ctx, "no OCSP URLs in peer certificate");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "no OCSP URLs in peer certificate");
 		goto err;
 	}
 
 	ocsp->ocsp_url = strdup(sk_OPENSSL_STRING_value(ocsp_urls, 0));
 	if (ocsp->ocsp_url == NULL) {
-		tls_set_errorx(ctx, "out of memory");
+		tls_set_errorx(ctx, TLS_ERROR_OUT_OF_MEMORY, "out of memory");
 		goto err;
 	}
 
@@ -216,7 +219,7 @@ tls_ocsp_verify_response(struct tls *ctx, OCSP_RESPONSE *resp)
 	unsigned long flags;
 
 	if ((br = OCSP_response_get1_basic(resp)) == NULL) {
-		tls_set_errorx(ctx, "cannot load ocsp reply");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "cannot load ocsp reply");
 		goto err;
 	}
 
@@ -229,14 +232,15 @@ tls_ocsp_verify_response(struct tls *ctx, OCSP_RESPONSE *resp)
 	/* now verify */
 	if (OCSP_basic_verify(br, ctx->ocsp->extra_certs,
 		SSL_CTX_get_cert_store(ctx->ssl_ctx), flags) != 1) {
-		tls_set_errorx(ctx, "ocsp verify failed");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "ocsp verify failed");
 		goto err;
 	}
 
 	/* signature OK, look inside */
 	response_status = OCSP_response_status(resp);
 	if (response_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
-		tls_set_errorx(ctx, "ocsp verify failed: response - %s",
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "ocsp verify failed: response - %s",
 		    OCSP_response_status_str(response_status));
 		goto err;
 	}
@@ -244,19 +248,21 @@ tls_ocsp_verify_response(struct tls *ctx, OCSP_RESPONSE *resp)
 	cid = tls_ocsp_get_certid(ctx->ocsp->main_cert,
 	    ctx->ocsp->extra_certs, ctx->ssl_ctx);
 	if (cid == NULL) {
-		tls_set_errorx(ctx, "ocsp verify failed: no issuer cert");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "ocsp verify failed: no issuer cert");
 		goto err;
 	}
 
 	if (OCSP_resp_find_status(br, cid, &cert_status, &crl_reason,
 	    &revtime, &thisupd, &nextupd) != 1) {
-		tls_set_errorx(ctx, "ocsp verify failed: no result for cert");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "ocsp verify failed: no result for cert");
 		goto err;
 	}
 
 	if (OCSP_check_validity(thisupd, nextupd, JITTER_SEC,
 	    MAXAGE_SEC) != 1) {
-		tls_set_errorx(ctx,
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
 		    "ocsp verify failed: ocsp response not current");
 		goto err;
 	}
@@ -268,8 +274,9 @@ tls_ocsp_verify_response(struct tls *ctx, OCSP_RESPONSE *resp)
 	/* finally can look at status */
 	if (cert_status != V_OCSP_CERTSTATUS_GOOD && cert_status !=
 	    V_OCSP_CERTSTATUS_UNKNOWN) {
-		tls_set_errorx(ctx, "ocsp verify failed: revoked cert - %s",
-			       OCSP_crl_reason_str(crl_reason));
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "ocsp verify failed: revoked cert - %s",
+		    OCSP_crl_reason_str(crl_reason));
 		goto err;
 	}
 	ret = 0;
@@ -297,7 +304,8 @@ tls_ocsp_process_response_internal(struct tls *ctx, const unsigned char *respons
 	if (resp == NULL) {
 		tls_ocsp_free(ctx->ocsp);
 		ctx->ocsp = NULL;
-		tls_set_error(ctx, "unable to parse OCSP response");
+		tls_set_error(ctx, TLS_ERROR_UNKNOWN,
+		    "unable to parse OCSP response");
 		return -1;
 	}
 	ret = tls_ocsp_verify_response(ctx, resp);
@@ -319,7 +327,8 @@ tls_ocsp_verify_cb(SSL *ssl, void *arg)
 	size = SSL_get_tlsext_status_ocsp_resp(ssl, &raw);
 	if (size <= 0) {
 		if (ctx->config->ocsp_require_stapling) {
-			tls_set_errorx(ctx, "no stapled OCSP response provided");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "no stapled OCSP response provided");
 			return 0;
 		}
 		return 1;
diff --git a/tls_server.c b/tls_server.c
index 5f93c7a..a94b422 100644
--- a/tls_server.c
+++ b/tls_server.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tls_server.c,v 1.49 2023/05/14 07:26:25 op Exp $ */
+/* $OpenBSD: tls_server.c,v 1.51 2024/03/26 08:54:48 joshua Exp $ */
 /*
  * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
  *
@@ -181,7 +181,8 @@ tls_server_ticket_cb(SSL *ssl, unsigned char *keyname, unsigned char *iv,
 		/* create new session */
 		key = tls_server_ticket_key(tls_ctx->config, NULL);
 		if (key == NULL) {
-			tls_set_errorx(tls_ctx, "no valid ticket key found");
+			tls_set_errorx(tls_ctx, TLS_ERROR_UNKNOWN,
+			    "no valid ticket key found");
 			return (-1);
 		}
 
@@ -189,12 +190,14 @@ tls_server_ticket_cb(SSL *ssl, unsigned char *keyname, unsigned char *iv,
 		arc4random_buf(iv, EVP_MAX_IV_LENGTH);
 		if (!EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL,
 		    key->aes_key, iv)) {
-			tls_set_errorx(tls_ctx, "failed to init encrypt");
+			tls_set_errorx(tls_ctx, TLS_ERROR_UNKNOWN,
+			    "failed to init encrypt");
 			return (-1);
 		}
 		if (!HMAC_Init_ex(hctx, key->hmac_key, sizeof(key->hmac_key),
 		    EVP_sha256(), NULL)) {
-			tls_set_errorx(tls_ctx, "failed to init hmac");
+			tls_set_errorx(tls_ctx, TLS_ERROR_UNKNOWN,
+			    "failed to init hmac");
 			return (-1);
 		}
 		return (0);
@@ -206,12 +209,14 @@ tls_server_ticket_cb(SSL *ssl, unsigned char *keyname, unsigned char *iv,
 
 		if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL,
 		    key->aes_key, iv)) {
-			tls_set_errorx(tls_ctx, "failed to init decrypt");
+			tls_set_errorx(tls_ctx, TLS_ERROR_UNKNOWN,
+			    "failed to init decrypt");
 			return (-1);
 		}
 		if (!HMAC_Init_ex(hctx, key->hmac_key, sizeof(key->hmac_key),
 		    EVP_sha256(), NULL)) {
-			tls_set_errorx(tls_ctx, "failed to init hmac");
+			tls_set_errorx(tls_ctx, TLS_ERROR_UNKNOWN,
+			    "failed to init hmac");
 			return (-1);
 		}
 
@@ -229,7 +234,7 @@ tls_configure_server_ssl(struct tls *ctx, SSL_CTX **ssl_ctx,
 	SSL_CTX_free(*ssl_ctx);
 
 	if ((*ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
-		tls_set_errorx(ctx, "ssl context failure");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "ssl context failure");
 		goto err;
 	}
 
@@ -237,11 +242,13 @@ tls_configure_server_ssl(struct tls *ctx, SSL_CTX **ssl_ctx,
 
 	if (SSL_CTX_set_tlsext_servername_callback(*ssl_ctx,
 	    tls_servername_cb) != 1) {
-		tls_set_error(ctx, "failed to set servername callback");
+		tls_set_error(ctx, TLS_ERROR_UNKNOWN,
+		    "failed to set servername callback");
 		goto err;
 	}
 	if (SSL_CTX_set_tlsext_servername_arg(*ssl_ctx, ctx) != 1) {
-		tls_set_error(ctx, "failed to set servername callback arg");
+		tls_set_error(ctx, TLS_ERROR_UNKNOWN,
+		    "failed to set servername callback arg");
 		goto err;
 	}
 
@@ -270,7 +277,8 @@ tls_configure_server_ssl(struct tls *ctx, SSL_CTX **ssl_ctx,
 		SSL_CTX_set_ecdh_auto(*ssl_ctx, 1);
 		if (SSL_CTX_set1_groups(*ssl_ctx, ctx->config->ecdhecurves,
 		    ctx->config->ecdhecurves_len) != 1) {
-			tls_set_errorx(ctx, "failed to set ecdhe curves");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "failed to set ecdhe curves");
 			goto err;
 		}
 	}
@@ -279,7 +287,8 @@ tls_configure_server_ssl(struct tls *ctx, SSL_CTX **ssl_ctx,
 		SSL_CTX_set_options(*ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
 
 	if (SSL_CTX_set_tlsext_status_cb(*ssl_ctx, tls_ocsp_stapling_cb) != 1) {
-		tls_set_errorx(ctx, "failed to add OCSP stapling callback");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "failed to add OCSP stapling callback");
 		goto err;
 	}
 
@@ -289,7 +298,7 @@ tls_configure_server_ssl(struct tls *ctx, SSL_CTX **ssl_ctx,
 		SSL_CTX_clear_options(*ssl_ctx, SSL_OP_NO_TICKET);
 		if (!SSL_CTX_set_tlsext_ticket_key_cb(*ssl_ctx,
 		    tls_server_ticket_cb)) {
-			tls_set_error(ctx,
+			tls_set_error(ctx, TLS_ERROR_UNKNOWN,
 			    "failed to set the TLS ticket callback");
 			goto err;
 		}
@@ -297,7 +306,8 @@ tls_configure_server_ssl(struct tls *ctx, SSL_CTX **ssl_ctx,
 
 	if (SSL_CTX_set_session_id_context(*ssl_ctx, ctx->config->session_id,
 	    sizeof(ctx->config->session_id)) != 1) {
-		tls_set_error(ctx, "failed to set session id context");
+		tls_set_error(ctx, TLS_ERROR_UNKNOWN,
+		    "failed to set session id context");
 		goto err;
 	}
 
@@ -323,7 +333,7 @@ tls_configure_server_sni(struct tls *ctx)
 	sni_ctx = &ctx->sni_ctx;
 	for (kp = ctx->config->keypair->next; kp != NULL; kp = kp->next) {
 		if ((*sni_ctx = tls_sni_ctx_new()) == NULL) {
-			tls_set_errorx(ctx, "out of memory");
+			tls_set_errorx(ctx, TLS_ERROR_OUT_OF_MEMORY, "out of memory");
 			goto err;
 		}
 		(*sni_ctx)->keypair = kp;
@@ -362,22 +372,25 @@ tls_accept_common(struct tls *ctx)
 	struct tls *conn_ctx = NULL;
 
 	if ((ctx->flags & TLS_SERVER) == 0) {
-		tls_set_errorx(ctx, "not a server context");
+		tls_set_errorx(ctx, TLS_ERROR_INVALID_CONTEXT,
+		    "not a server context");
 		goto err;
 	}
 
 	if ((conn_ctx = tls_server_conn(ctx)) == NULL) {
-		tls_set_errorx(ctx, "connection context failure");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "connection context failure");
 		goto err;
 	}
 
 	if ((conn_ctx->ssl_conn = SSL_new(ctx->ssl_ctx)) == NULL) {
-		tls_set_errorx(ctx, "ssl failure");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN, "ssl failure");
 		goto err;
 	}
 
 	if (SSL_set_app_data(conn_ctx->ssl_conn, conn_ctx) != 1) {
-		tls_set_errorx(ctx, "ssl application data failure");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "ssl application data failure");
 		goto err;
 	}
 
@@ -405,7 +418,8 @@ tls_accept_fds(struct tls *ctx, struct tls **cctx, int fd_read, int fd_write)
 
 	if (SSL_set_rfd(conn_ctx->ssl_conn, fd_read) != 1 ||
 	    SSL_set_wfd(conn_ctx->ssl_conn, fd_write) != 1) {
-		tls_set_errorx(ctx, "ssl file descriptor failure");
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "ssl file descriptor failure");
 		goto err;
 	}
 
@@ -448,7 +462,8 @@ tls_handshake_server(struct tls *ctx)
 	int rv = -1;
 
 	if ((ctx->flags & TLS_SERVER_CONN) == 0) {
-		tls_set_errorx(ctx, "not a server connection context");
+		tls_set_errorx(ctx, TLS_ERROR_INVALID_CONTEXT,
+		    "not a server connection context");
 		goto err;
 	}
 
diff --git a/tls_signer.c b/tls_signer.c
index 177c9d0..2573803 100644
--- a/tls_signer.c
+++ b/tls_signer.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tls_signer.c,v 1.9 2023/06/18 19:12:58 tb Exp $ */
+/* $OpenBSD: tls_signer.c,v 1.13 2024/06/11 16:35:24 op Exp $ */
 /*
  * Copyright (c) 2021 Eric Faurot <eric@openbsd.org>
  *
@@ -16,10 +16,19 @@
  */
 
 #include <limits.h>
-
-#include <openssl/ecdsa.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/bio.h>
+#include <openssl/ec.h>
 #include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
 #include <openssl/rsa.h>
+#include <openssl/x509.h>
 
 #include "tls.h"
 #include "tls_internal.h"
@@ -91,7 +100,7 @@ tls_signer_add_keypair_mem(struct tls_signer *signer, const uint8_t *cert,
 
 	/* Compute certificate hash */
 	if ((bio = BIO_new_mem_buf(cert, cert_len)) == NULL) {
-		tls_error_setx(&signer->error,
+		tls_error_setx(&signer->error, TLS_ERROR_UNKNOWN,
 		    "failed to create certificate bio");
 		goto err;
 	}
@@ -99,12 +108,12 @@ tls_signer_add_keypair_mem(struct tls_signer *signer, const uint8_t *cert,
 	    NULL)) == NULL) {
 		if ((ssl_err = ERR_peek_error()) != 0)
 			errstr = ERR_error_string(ssl_err, NULL);
-		tls_error_setx(&signer->error, "failed to load certificate: %s",
-		    errstr);
+		tls_error_setx(&signer->error, TLS_ERROR_UNKNOWN,
+		    "failed to load certificate: %s", errstr);
 		goto err;
 	}
 	if (tls_cert_pubkey_hash(x509, &hash) == -1) {
-		tls_error_setx(&signer->error,
+		tls_error_setx(&signer->error, TLS_ERROR_UNKNOWN,
 		    "failed to get certificate hash");
 		goto err;
 	}
@@ -116,23 +125,27 @@ tls_signer_add_keypair_mem(struct tls_signer *signer, const uint8_t *cert,
 
 	/* Read private key */
 	if ((bio = BIO_new_mem_buf(key, key_len)) == NULL) {
-		tls_error_setx(&signer->error, "failed to create key bio");
+		tls_error_setx(&signer->error, TLS_ERROR_UNKNOWN,
+		    "failed to create key bio");
 		goto err;
 	}
 	if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, tls_password_cb,
 	    NULL)) == NULL) {
-		tls_error_setx(&signer->error, "failed to read private key");
+		tls_error_setx(&signer->error, TLS_ERROR_UNKNOWN,
+		    "failed to read private key");
 		goto err;
 	}
 
 	if ((skey = calloc(1, sizeof(*skey))) == NULL) {
-		tls_error_set(&signer->error, "failed to create key entry");
+		tls_error_set(&signer->error, TLS_ERROR_OUT_OF_MEMORY,
+		    "out of memory");
 		goto err;
 	}
 	skey->hash = hash;
 	if ((skey->rsa = EVP_PKEY_get1_RSA(pkey)) == NULL &&
 	    (skey->ecdsa = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) {
-		tls_error_setx(&signer->error, "unknown key type");
+		tls_error_setx(&signer->error, TLS_ERROR_UNKNOWN,
+		    "unknown key type");
 		goto err;
 	}
 
@@ -194,29 +207,32 @@ tls_sign_rsa(struct tls_signer *signer, struct tls_signer_key *skey,
 	} else if (padding_type == TLS_PADDING_RSA_PKCS1) {
 		rsa_padding = RSA_PKCS1_PADDING;
 	} else {
-		tls_error_setx(&signer->error, "invalid RSA padding type (%d)",
-		    padding_type);
+		tls_error_setx(&signer->error, TLS_ERROR_UNKNOWN,
+		    "invalid RSA padding type (%d)", padding_type);
 		return (-1);
 	}
 
 	if (input_len > INT_MAX) {
-		tls_error_setx(&signer->error, "input too large");
+		tls_error_setx(&signer->error, TLS_ERROR_INVALID_ARGUMENT,
+		    "input too large");
 		return (-1);
 	}
 	if ((rsa_size = RSA_size(skey->rsa)) <= 0) {
-		tls_error_setx(&signer->error, "invalid RSA size: %d",
-		    rsa_size);
+		tls_error_setx(&signer->error, TLS_ERROR_UNKNOWN,
+		    "invalid RSA size: %d", rsa_size);
 		return (-1);
 	}
 	if ((signature = calloc(1, rsa_size)) == NULL) {
-		tls_error_set(&signer->error, "RSA signature");
+		tls_error_set(&signer->error, TLS_ERROR_OUT_OF_MEMORY,
+		    "out of memory");
 		return (-1);
 	}
 
 	if ((signature_len = RSA_private_encrypt((int)input_len, input,
 	    signature, skey->rsa, rsa_padding)) <= 0) {
 		/* XXX - include further details from libcrypto. */
-		tls_error_setx(&signer->error, "RSA signing failed");
+		tls_error_setx(&signer->error, TLS_ERROR_UNKNOWN,
+		    "RSA signing failed");
 		free(signature);
 		return (-1);
 	}
@@ -239,28 +255,32 @@ tls_sign_ecdsa(struct tls_signer *signer, struct tls_signer_key *skey,
 	*out_signature_len = 0;
 
 	if (padding_type != TLS_PADDING_NONE) {
-		tls_error_setx(&signer->error, "invalid ECDSA padding");
+		tls_error_setx(&signer->error, TLS_ERROR_UNKNOWN,
+		    "invalid ECDSA padding");
 		return (-1);
 	}
 
 	if (input_len > INT_MAX) {
-		tls_error_setx(&signer->error, "digest too large");
+		tls_error_setx(&signer->error, TLS_ERROR_INVALID_ARGUMENT,
+		    "digest too large");
 		return (-1);
 	}
 	if ((signature_len = ECDSA_size(skey->ecdsa)) <= 0) {
-		tls_error_setx(&signer->error, "invalid ECDSA size: %d",
-		    signature_len);
+		tls_error_setx(&signer->error, TLS_ERROR_UNKNOWN,
+		    "invalid ECDSA size: %d", signature_len);
 		return (-1);
 	}
 	if ((signature = calloc(1, signature_len)) == NULL) {
-		tls_error_set(&signer->error, "ECDSA signature");
+		tls_error_set(&signer->error, TLS_ERROR_OUT_OF_MEMORY,
+		    "out of memory");
 		return (-1);
 	}
 
 	if (!ECDSA_sign(0, input, input_len, signature, &signature_len,
 	    skey->ecdsa)) {
 		/* XXX - include further details from libcrypto. */
-		tls_error_setx(&signer->error, "ECDSA signing failed");
+		tls_error_setx(&signer->error, TLS_ERROR_UNKNOWN,
+		    "ECDSA signing failed");
 		free(signature);
 		return (-1);
 	}
@@ -286,7 +306,7 @@ tls_signer_sign(struct tls_signer *signer, const char *pubkey_hash,
 			break;
 
 	if (skey == NULL) {
-		tls_error_setx(&signer->error, "key not found");
+		tls_error_setx(&signer->error, TLS_ERROR_UNKNOWN, "key not found");
 		return (-1);
 	}
 
@@ -298,7 +318,7 @@ tls_signer_sign(struct tls_signer *signer, const char *pubkey_hash,
 		return tls_sign_ecdsa(signer, skey, input, input_len,
 		    padding_type, out_signature, out_signature_len);
 
-	tls_error_setx(&signer->error, "unknown key type");
+	tls_error_setx(&signer->error, TLS_ERROR_UNKNOWN, "unknown key type");
 
 	return (-1);
 }
diff --git a/tls_verify.c b/tls_verify.c
index a35ebe0..78f6c24 100644
--- a/tls_verify.c
+++ b/tls_verify.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tls_verify.c,v 1.29 2023/11/22 18:23:09 op Exp $ */
+/* $OpenBSD: tls_verify.c,v 1.30 2024/03/26 06:24:52 joshua Exp $ */
 /*
  * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org>
  *
@@ -102,7 +102,8 @@ tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name,
 	    NULL);
 	if (altname_stack == NULL) {
 		if (critical != -1) {
-			tls_set_errorx(ctx, "error decoding subjectAltName");
+			tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+			    "error decoding subjectAltName");
 			goto err;
 		}
 		goto done;
@@ -141,7 +142,7 @@ tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name,
 				len = ASN1_STRING_length(altname->d.dNSName);
 
 				if (len < 0 || (size_t)len != strlen(data)) {
-					tls_set_errorx(ctx,
+					tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
 					    "error verifying name '%s': "
 					    "NUL byte in subjectAltName, "
 					    "probably a malicious certificate",
@@ -155,7 +156,7 @@ tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name,
 				 * dNSName must be rejected.
 				 */
 				if (strcmp(data, " ") == 0) {
-					tls_set_errorx(ctx,
+					tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
 					    "error verifying name '%s': "
 					    "a dNSName of \" \" must not be "
 					    "used", name);
@@ -182,7 +183,7 @@ tls_check_subject_altname(struct tls *ctx, X509 *cert, const char *name,
 			data = ASN1_STRING_get0_data(altname->d.iPAddress);
 
 			if (datalen < 0) {
-				tls_set_errorx(ctx,
+				tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
 				    "Unexpected negative length for an "
 				    "IP address: %d", datalen);
 				goto err;
@@ -243,7 +244,8 @@ tls_check_common_name(struct tls *ctx, X509 *cert, const char *name,
 		 * more than one CN fed to us in the subject, treating the
 		 * certificate as hostile.
 		 */
-		tls_set_errorx(ctx, "error verifying name '%s': "
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "error verifying name '%s': "
 		    "Certificate subject contains multiple Common Name fields, "
 		    "probably a malicious or malformed certificate", name);
 		goto err;
@@ -255,7 +257,8 @@ tls_check_common_name(struct tls *ctx, X509 *cert, const char *name,
 	 * 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': "
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "error verifying name '%s': "
 		    "Common Name field cannot be encoded as a UTF-8 string, "
 		    "probably a malicious certificate", name);
 		goto err;
@@ -265,7 +268,8 @@ tls_check_common_name(struct tls *ctx, X509 *cert, const char *name,
 	 * 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': "
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "error verifying name '%s': "
 		    "Common Name field has invalid length, "
 		    "probably a malicious certificate", name);
 		goto err;
@@ -274,7 +278,8 @@ tls_check_common_name(struct tls *ctx, X509 *cert, const char *name,
 	 * 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': "
+		tls_set_errorx(ctx, TLS_ERROR_UNKNOWN,
+		    "error verifying name '%s': "
 		    "NUL byte in Common Name field, "
 		    "probably a malicious certificate", name);
 		goto err;
@@ -282,7 +287,8 @@ tls_check_common_name(struct tls *ctx, X509 *cert, const char *name,
 
 	common_name = strndup(utf8_bytes, common_name_len);
 	if (common_name == NULL) {
-		tls_set_error(ctx, "out of memory");
+		tls_set_error(ctx, TLS_ERROR_OUT_OF_MEMORY,
+		    "out of memory");
 		goto err;
 	}