diff options
-rw-r--r-- | LIBTLS_VERSION | 2 | ||||
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | VERSION | 2 | ||||
-rw-r--r-- | compat/getentropy_aix.c | 4 | ||||
-rw-r--r-- | compat/getentropy_hpux.c | 4 | ||||
-rw-r--r-- | compat/getentropy_linux.c | 4 | ||||
-rw-r--r-- | compat/getentropy_osx.c | 4 | ||||
-rw-r--r-- | compat/getentropy_solaris.c | 4 | ||||
-rw-r--r-- | include/compat/netinet/ip.h | 2 | ||||
-rw-r--r-- | include/tls.h | 22 | ||||
-rw-r--r-- | m4/check-libc.m4 | 10 | ||||
-rw-r--r-- | m4/check-os-options.m4 | 15 | ||||
-rw-r--r-- | man/tls_load_file.3 | 6 | ||||
-rw-r--r-- | tls.c | 25 | ||||
-rw-r--r-- | tls.sym | 7 | ||||
-rw-r--r-- | tls_bio_cb.c | 44 | ||||
-rw-r--r-- | tls_client.c | 9 | ||||
-rw-r--r-- | tls_config.c | 15 | ||||
-rw-r--r-- | tls_internal.h | 7 | ||||
-rw-r--r-- | tls_ocsp.c | 39 | ||||
-rw-r--r-- | tls_server.c | 30 | ||||
-rw-r--r-- | tls_signer.c | 451 |
22 files changed, 627 insertions, 80 deletions
diff --git a/LIBTLS_VERSION b/LIBTLS_VERSION index 2005c06..27179fd 100644 --- a/LIBTLS_VERSION +++ b/LIBTLS_VERSION @@ -1 +1 @@ -22:0:0 +24:1:0 diff --git a/Makefile.am b/Makefile.am index eb913b0..69a8133 100644 --- a/Makefile.am +++ b/Makefile.am @@ -29,6 +29,7 @@ libtls_la_SOURCES += tls_config.c libtls_la_SOURCES += tls_conninfo.c libtls_la_SOURCES += tls_keypair.c libtls_la_SOURCES += tls_server.c +libtls_la_SOURCES += tls_signer.c libtls_la_SOURCES += tls_ocsp.c libtls_la_SOURCES += tls_peer.c libtls_la_SOURCES += tls_util.c diff --git a/VERSION b/VERSION index ec46c1f..fc1335a 100644 --- a/VERSION +++ b/VERSION @@ -1,2 +1,2 @@ -3.4.2 +3.5.0 diff --git a/compat/getentropy_aix.c b/compat/getentropy_aix.c index 422e685..7fb857e 100644 --- a/compat/getentropy_aix.c +++ b/compat/getentropy_aix.c @@ -1,4 +1,4 @@ -/* $OpenBSD: getentropy_aix.c,v 1.7 2020/05/17 14:44:20 deraadt Exp $ */ +/* $OpenBSD: getentropy_aix.c,v 1.8 2021/10/24 21:24:20 deraadt Exp $ */ /* * Copyright (c) 2015 Michael Felt <aixtools@gmail.com> @@ -134,7 +134,7 @@ start: #ifdef O_CLOEXEC flags |= O_CLOEXEC; #endif - fd = open(path, flags, 0); + fd = open(path, flags); if (fd == -1) { if (errno == EINTR) goto start; diff --git a/compat/getentropy_hpux.c b/compat/getentropy_hpux.c index c981880..7188ae5 100644 --- a/compat/getentropy_hpux.c +++ b/compat/getentropy_hpux.c @@ -1,4 +1,4 @@ -/* $OpenBSD: getentropy_hpux.c,v 1.7 2020/05/17 14:44:20 deraadt Exp $ */ +/* $OpenBSD: getentropy_hpux.c,v 1.8 2021/10/24 21:24:20 deraadt Exp $ */ /* * Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org> @@ -138,7 +138,7 @@ start: #ifdef O_CLOEXEC flags |= O_CLOEXEC; #endif - fd = open(path, flags, 0); + fd = open(path, flags); if (fd == -1) { if (errno == EINTR) goto start; diff --git a/compat/getentropy_linux.c b/compat/getentropy_linux.c index bc7a6be..c7c39c2 100644 --- a/compat/getentropy_linux.c +++ b/compat/getentropy_linux.c @@ -1,4 +1,4 @@ -/* $OpenBSD: getentropy_linux.c,v 1.47 2020/05/17 14:44:20 deraadt Exp $ */ +/* $OpenBSD: getentropy_linux.c,v 1.48 2021/10/24 21:24:20 deraadt Exp $ */ /* * Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org> @@ -212,7 +212,7 @@ start: #ifdef O_CLOEXEC flags |= O_CLOEXEC; #endif - fd = open("/dev/urandom", flags, 0); + fd = open("/dev/urandom", flags); if (fd == -1) { if (errno == EINTR) goto start; diff --git a/compat/getentropy_osx.c b/compat/getentropy_osx.c index 5d4067b..db028d1 100644 --- a/compat/getentropy_osx.c +++ b/compat/getentropy_osx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: getentropy_osx.c,v 1.13 2020/05/17 14:44:20 deraadt Exp $ */ +/* $OpenBSD: getentropy_osx.c,v 1.14 2021/10/24 21:24:20 deraadt Exp $ */ /* * Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org> @@ -158,7 +158,7 @@ start: #ifdef O_CLOEXEC flags |= O_CLOEXEC; #endif - fd = open("/dev/urandom", flags, 0); + fd = open("/dev/urandom", flags); if (fd == -1) { if (errno == EINTR) goto start; diff --git a/compat/getentropy_solaris.c b/compat/getentropy_solaris.c index cf5b9bf..e36426c 100644 --- a/compat/getentropy_solaris.c +++ b/compat/getentropy_solaris.c @@ -1,4 +1,4 @@ -/* $OpenBSD: getentropy_solaris.c,v 1.14 2020/05/17 14:44:20 deraadt Exp $ */ +/* $OpenBSD: getentropy_solaris.c,v 1.15 2021/10/24 21:24:20 deraadt Exp $ */ /* * Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org> @@ -164,7 +164,7 @@ start: #ifdef O_CLOEXEC flags |= O_CLOEXEC; #endif - fd = open(path, flags, 0); + fd = open(path, flags); if (fd == -1) { if (errno == EINTR) goto start; diff --git a/include/compat/netinet/ip.h b/include/compat/netinet/ip.h index 6019f7d..29f17f3 100644 --- a/include/compat/netinet/ip.h +++ b/include/compat/netinet/ip.h @@ -8,7 +8,9 @@ #endif #ifndef _WIN32 +#ifdef HAVE_NETINET_IP_H #include_next <netinet/ip.h> +#endif #else #include <win32netcompat.h> #endif diff --git a/include/tls.h b/include/tls.h index de6d257..429c171 100644 --- a/include/tls.h +++ b/include/tls.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tls.h,v 1.58 2020/01/22 06:44:02 beck Exp $ */ +/* $OpenBSD: tls.h,v 1.61 2022/02/01 17:18:38 jsing Exp $ */ /* * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> * @@ -79,6 +79,10 @@ typedef SSIZE_T ssize_t; #define TLS_MAX_SESSION_ID_LENGTH 32 #define TLS_TICKET_KEY_SIZE 48 +#define TLS_PADDING_NONE 0 +#define TLS_PADDING_RSA_PKCS1 1 +#define TLS_PADDING_RSA_X9_31 2 + struct tls; struct tls_config; @@ -86,6 +90,9 @@ typedef ssize_t (*tls_read_cb)(struct tls *_ctx, void *_buf, size_t _buflen, void *_cb_arg); typedef ssize_t (*tls_write_cb)(struct tls *_ctx, const void *_buf, size_t _buflen, void *_cb_arg); +typedef int (*tls_sign_cb)(void *_cb_arg, const char *_pubkey_hash, + const uint8_t *_input, size_t _input_len, int _padding_type, + uint8_t **_out_signature, size_t *_out_signature_len); int tls_init(void); @@ -142,6 +149,8 @@ int tls_config_set_ocsp_staple_file(struct tls_config *_config, int tls_config_set_protocols(struct tls_config *_config, uint32_t _protocols); int tls_config_set_session_fd(struct tls_config *_config, int _session_fd); int tls_config_set_verify_depth(struct tls_config *_config, int _verify_depth); +int tls_config_set_sign_cb(struct tls_config *_config, tls_sign_cb _cb, + void *_cb_arg); void tls_config_prefer_ciphers_client(struct tls_config *_config); void tls_config_prefer_ciphers_server(struct tls_config *_config); @@ -219,6 +228,17 @@ time_t tls_peer_ocsp_revocation_time(struct tls *_ctx); time_t tls_peer_ocsp_this_update(struct tls *_ctx); const char *tls_peer_ocsp_url(struct tls *_ctx); +struct tls_signer* tls_signer_new(void); +void tls_signer_free(struct tls_signer * _signer); +const char *tls_signer_error(struct tls_signer * _signer); +int tls_signer_add_keypair_file(struct tls_signer *_signer, + const char *_cert_file, const char *_key_file); +int tls_signer_add_keypair_mem(struct tls_signer *_signer, const uint8_t *_cert, + size_t _cert_len, const uint8_t *_key, size_t _key_len); +int tls_signer_sign(struct tls_signer *_signer, const char *_pubkey_hash, + const uint8_t *_input, size_t _input_len, int _padding_type, + uint8_t **_out_signature, size_t *_out_signature_len); + #ifdef __cplusplus } #endif diff --git a/m4/check-libc.m4 b/m4/check-libc.m4 index 2ca08a5..b33224f 100644 --- a/m4/check-libc.m4 +++ b/m4/check-libc.m4 @@ -1,4 +1,9 @@ AC_DEFUN([CHECK_LIBC_COMPAT], [ +# Check for libc headers +AC_CHECK_HEADERS([netinet/ip.h], [], [], +[#include <sys/types.h> +#include <arpa/inet.h> +]) # Check for general libc functions AC_CHECK_FUNCS([asprintf freezero memmem]) AC_CHECK_FUNCS([reallocarray recallocarray]) @@ -7,10 +12,7 @@ AC_CHECK_FUNCS([timegm _mkgmtime timespecsub]) AC_CHECK_FUNCS([getprogname]) AC_CACHE_CHECK([for getpagesize], ac_cv_func_getpagesize, [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ -// Since Android NDK v16 getpagesize is defined as inline inside unistd.h -#ifdef __ANDROID__ -# include <unistd.h> -#endif +#include <unistd.h> ]], [[ getpagesize(); ]])], diff --git a/m4/check-os-options.m4 b/m4/check-os-options.m4 index 644bf71..bd38938 100644 --- a/m4/check-os-options.m4 +++ b/m4/check-os-options.m4 @@ -68,10 +68,15 @@ char buf[1]; getentropy(buf, 1); ;; *hpux*) HOST_OS=hpux; - if test "`echo $CC | cut -d ' ' -f 1`" = "gcc" ; then - CFLAGS="$CFLAGS -mlp64" - else - CFLAGS="-g -O2 +DD64 +Otype_safety=off $USER_CFLAGS" + if test "`echo $host_os | cut -c 1-4`" = "ia64" ; then + if test "`echo $CC | cut -d ' ' -f 1`" = "gcc" ; then + CFLAGS="$CFLAGS -mlp64" + else + CFLAGS="+DD64" + fi + fi + if ! test "`echo $CC | cut -d ' ' -f 1`" = "gcc" ; then + CFLAGS="-g -O2 +Otype_safety=off $CFLAGS $USER_CFLAGS" fi CPPFLAGS="$CPPFLAGS -D_XOPEN_SOURCE=600 -D__STRICT_ALIGNMENT" ;; @@ -118,7 +123,7 @@ char buf[1]; getentropy(buf, 1); HOST_OS=solaris HOST_ABI=elf CPPFLAGS="$CPPFLAGS -D__EXTENSIONS__ -D_XOPEN_SOURCE=600 -DBSD_COMP" - AC_SUBST([PLATFORM_LDADD], ['-ldl -lnsl -lsocket']) + AC_SUBST([PLATFORM_LDADD], ['-ldl -lmd -lnsl -lsocket']) ;; *) ;; esac diff --git a/man/tls_load_file.3 b/man/tls_load_file.3 index 6f82759..cf33b57 100644 --- a/man/tls_load_file.3 +++ b/man/tls_load_file.3 @@ -1,4 +1,4 @@ -.\" $OpenBSD: tls_load_file.3,v 1.13 2021/06/22 20:01:19 jmc Exp $ +.\" $OpenBSD: tls_load_file.3,v 1.14 2022/01/01 02:18:28 jsg Exp $ .\" .\" Copyright (c) 2014 Ted Unangst <tedu@openbsd.org> .\" Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org> @@ -17,7 +17,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: June 22 2021 $ +.Dd $Mdocdate: January 1 2022 $ .Dt TLS_LOAD_FILE 3 .Os .Sh NAME @@ -357,7 +357,7 @@ appeared in .Ox 6.2 . .Sh AUTHORS .An Joel Sing Aq Mt jsing@openbsd.org -with contibutions from +with contributions from .An Ted Unangst Aq Mt tedu@openbsd.org and .An Bob Beck Aq Mt beck@openbsd.org . diff --git a/tls.c b/tls.c index fabf790..1dcf933 100644 --- a/tls.c +++ b/tls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tls.c,v 1.90 2021/10/02 09:46:48 jsing Exp $ */ +/* $OpenBSD: tls.c,v 1.94 2022/02/08 19:13:50 tb Exp $ */ /* * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> * @@ -448,6 +448,8 @@ tls_keypair_to_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY **pke static int tls_keypair_setup_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY *pkey) { + RSA_METHOD *rsa_method; + ECDSA_METHOD *ecdsa_method; RSA *rsa = NULL; EC_KEY *eckey = NULL; int ret = -1; @@ -468,6 +470,14 @@ tls_keypair_setup_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY *p tls_set_errorx(ctx, "RSA key setup failure"); goto err; } + if (ctx->config->sign_cb == NULL) + break; + if ((rsa_method = tls_signer_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"); + goto err; + } break; case EVP_PKEY_EC: if ((eckey = EVP_PKEY_get1_EC_KEY(pkey)) == NULL || @@ -475,6 +485,14 @@ tls_keypair_setup_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY *p tls_set_errorx(ctx, "EC key setup failure"); goto err; } + if (ctx->config->sign_cb == NULL) + break; + if ((ecdsa_method = tls_signer_ecdsa_method()) == NULL || + ECDSA_set_ex_data(eckey, 1, ctx->config) == 0 || + ECDSA_set_method(eckey, ecdsa_method) == 0) { + tls_set_errorx(ctx, "failed to setup EC key"); + goto err; + } break; default: tls_set_errorx(ctx, "incorrect key type"); @@ -731,9 +749,8 @@ tls_configure_ssl_verify(struct tls *ctx, SSL_CTX *ssl_ctx, int verify) tls_set_error(ctx, "failed to add crl"); goto err; } - xi->crl = NULL; } - X509_VERIFY_PARAM_set_flags(X509_STORE_get0_param(store), + X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); } @@ -849,7 +866,7 @@ tls_ssl_error(struct tls *ctx, SSL *ssl_conn, int ssl_ret, const char *prefix) case SSL_ERROR_WANT_ACCEPT: case SSL_ERROR_WANT_X509_LOOKUP: default: - tls_set_ssl_errorx(ctx, "%s failed (%i)", prefix, ssl_err); + tls_set_ssl_errorx(ctx, "%s failed (%d)", prefix, ssl_err); return (-1); } } diff --git a/tls.sym b/tls.sym index 42c039d..54d8dd7 100644 --- a/tls.sym +++ b/tls.sym @@ -43,6 +43,7 @@ tls_config_set_protocols tls_config_set_session_id tls_config_set_session_lifetime tls_config_set_session_fd +tls_config_set_sign_cb tls_config_set_verify_depth tls_config_skip_private_key_check tls_config_use_fake_private_key @@ -87,5 +88,11 @@ tls_peer_ocsp_url tls_read tls_reset tls_server +tls_signer_add_keypair_file +tls_signer_add_keypair_mem +tls_signer_error +tls_signer_free +tls_signer_new +tls_signer_sign tls_unload_file tls_write diff --git a/tls_bio_cb.c b/tls_bio_cb.c index 8adbf55..9dd435a 100644 --- a/tls_bio_cb.c +++ b/tls_bio_cb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tls_bio_cb.c,v 1.19 2017/01/12 16:18:39 jsing Exp $ */ +/* $OpenBSD: tls_bio_cb.c,v 1.20 2022/01/10 23:39:48 tb Exp $ */ /* * Copyright (c) 2016 Tobias Pape <tobias@netshed.de> * @@ -32,26 +32,39 @@ static long bio_cb_ctrl(BIO *bio, int cmd, long num, void *ptr); static BIO_METHOD *bio_cb_method; -static pthread_once_t bio_cb_init_once = PTHREAD_ONCE_INIT; +static pthread_mutex_t bio_cb_method_lock = PTHREAD_MUTEX_INITIALIZER; static void -bio_s_cb_init(void) +bio_cb_method_init(void) { - bio_cb_method = BIO_meth_new(BIO_TYPE_MEM, "libtls_callbacks"); - if (bio_cb_method == NULL) + BIO_METHOD *bio_method; + + if (bio_cb_method != NULL) + return; + + bio_method = BIO_meth_new(BIO_TYPE_MEM, "libtls_callbacks"); + if (bio_method == NULL) return; - BIO_meth_set_write(bio_cb_method, bio_cb_write); - BIO_meth_set_read(bio_cb_method, bio_cb_read); - BIO_meth_set_puts(bio_cb_method, bio_cb_puts); - BIO_meth_set_ctrl(bio_cb_method, bio_cb_ctrl); + BIO_meth_set_write(bio_method, bio_cb_write); + BIO_meth_set_read(bio_method, bio_cb_read); + BIO_meth_set_puts(bio_method, bio_cb_puts); + BIO_meth_set_ctrl(bio_method, bio_cb_ctrl); + + bio_cb_method = bio_method; } static BIO_METHOD * bio_s_cb(void) { - pthread_once(&bio_cb_init_once, bio_s_cb_init); - return bio_cb_method; + if (bio_cb_method != NULL) + return (bio_cb_method); + + pthread_mutex_lock(&bio_cb_method_lock); + bio_cb_method_init(); + pthread_mutex_unlock(&bio_cb_method_lock); + + return (bio_cb_method); } static int @@ -125,8 +138,9 @@ int tls_set_cbs(struct tls *ctx, tls_read_cb read_cb, tls_write_cb write_cb, void *cb_arg) { - int rv = -1; + const BIO_METHOD *bio_cb; BIO *bio; + int rv = -1; if (read_cb == NULL || write_cb == NULL) { tls_set_errorx(ctx, "no callbacks provided"); @@ -137,7 +151,11 @@ tls_set_cbs(struct tls *ctx, tls_read_cb read_cb, tls_write_cb write_cb, ctx->write_cb = write_cb; ctx->cb_arg = cb_arg; - if ((bio = BIO_new(bio_s_cb())) == NULL) { + if ((bio_cb = bio_s_cb()) == NULL) { + tls_set_errorx(ctx, "failed to create callback method"); + goto err; + } + if ((bio = BIO_new(bio_cb)) == NULL) { tls_set_errorx(ctx, "failed to create callback i/o"); goto err; } diff --git a/tls_client.c b/tls_client.c index 47ebc40..b1d2a44 100644 --- a/tls_client.c +++ b/tls_client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tls_client.c,v 1.47 2021/06/01 20:26:11 tb Exp $ */ +/* $OpenBSD: tls_client.c,v 1.48 2021/10/21 08:38:11 tb Exp $ */ /* * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> * @@ -75,11 +75,8 @@ tls_connect_servername(struct tls *ctx, const char *host, const char *port, goto err; } - /* - * If port is NULL try to extract a port from the specified host, - * otherwise use the default. - */ - if ((p = (char *)port) == NULL) { + /* If port is NULL, try to extract a port from the specified host. */ + if (port == NULL) { ret = tls_host_port(host, &hs, &ps); if (ret == -1) { tls_set_errorx(ctx, "memory allocation failure"); diff --git a/tls_config.c b/tls_config.c index 3b1f4ff..38ed1bb 100644 --- a/tls_config.c +++ b/tls_config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tls_config.c,v 1.63 2021/01/21 22:03:25 eric Exp $ */ +/* $OpenBSD: tls_config.c,v 1.65 2022/01/25 21:51:24 eric Exp $ */ /* * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> * @@ -723,7 +723,7 @@ tls_config_set_session_fd(struct tls_config *config, int session_fd) if (sb.st_uid != getuid()) { tls_config_set_errorx(config, "session file has incorrect " - "owner (uid %i != %i)", sb.st_uid, getuid()); + "owner (uid %u != %u)", sb.st_uid, getuid()); return (-1); } mugo = sb.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO); @@ -739,6 +739,17 @@ tls_config_set_session_fd(struct tls_config *config, int session_fd) } int +tls_config_set_sign_cb(struct tls_config *config, tls_sign_cb cb, void *cb_arg) +{ + config->use_fake_private_key = 1; + config->skip_private_key_check = 1; + config->sign_cb = cb; + config->sign_cb_arg = cb_arg; + + return (0); +} + +int tls_config_set_verify_depth(struct tls_config *config, int verify_depth) { config->verify_depth = verify_depth; diff --git a/tls_internal.h b/tls_internal.h index 72b08f4..c4e62b3 100644 --- a/tls_internal.h +++ b/tls_internal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tls_internal.h,v 1.78 2021/01/21 19:09:10 eric Exp $ */ +/* $OpenBSD: tls_internal.h,v 1.79 2022/01/25 21:51:24 eric Exp $ */ /* * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org> * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> @@ -108,6 +108,8 @@ struct tls_config { int verify_time; int skip_private_key_check; int use_fake_private_key; + tls_sign_cb sign_cb; + void *sign_cb_arg; }; struct tls_conninfo { @@ -287,6 +289,9 @@ int tls_cert_pubkey_hash(X509 *_cert, char **_hash); int tls_password_cb(char *_buf, int _size, int _rwflag, void *_u); +RSA_METHOD *tls_signer_rsa_method(void); +ECDSA_METHOD *tls_signer_ecdsa_method(void); + __END_HIDDEN_DECLS /* XXX this function is not fully hidden so relayd can use it */ diff --git a/tls_ocsp.c b/tls_ocsp.c index 2a322c1..f1c54ab 100644 --- a/tls_ocsp.c +++ b/tls_ocsp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tls_ocsp.c,v 1.20 2021/03/23 20:04:29 tb Exp $ */ +/* $OpenBSD: tls_ocsp.c,v 1.22 2021/10/31 16:39:32 tb Exp $ */ /* * Copyright (c) 2015 Marko Kreen <markokr@gmail.com> * Copyright (c) 2016 Bob Beck <beck@openbsd.org> @@ -131,39 +131,38 @@ tls_ocsp_get_certid(X509 *main_cert, STACK_OF(X509) *extra_certs, X509_NAME *issuer_name; X509 *issuer; X509_STORE_CTX *storectx = NULL; - X509_OBJECT *tmpobj = NULL; + X509_OBJECT *obj = NULL; OCSP_CERTID *cid = NULL; X509_STORE *store; if ((issuer_name = X509_get_issuer_name(main_cert)) == NULL) - return NULL; + goto out; if (extra_certs != NULL) { issuer = X509_find_by_subject(extra_certs, issuer_name); - if (issuer != NULL) - return OCSP_cert_to_id(NULL, main_cert, issuer); + if (issuer != NULL) { + cid = OCSP_cert_to_id(NULL, main_cert, issuer); + goto out; + } } if ((store = SSL_CTX_get_cert_store(ssl_ctx)) == NULL) - return NULL; + goto out; if ((storectx = X509_STORE_CTX_new()) == NULL) - return NULL; + goto out; if (X509_STORE_CTX_init(storectx, store, main_cert, extra_certs) != 1) - goto err; - if ((tmpobj = X509_OBJECT_new()) == NULL) - goto err; - if (X509_STORE_get_by_subject(storectx, X509_LU_X509, issuer_name, - tmpobj) == 1) { - cid = OCSP_cert_to_id(NULL, main_cert, X509_OBJECT_get0_X509(tmpobj)); - X509_OBJECT_free(tmpobj); - } - X509_STORE_CTX_free(storectx); - return cid; + goto out; + if ((obj = X509_STORE_CTX_get_obj_by_subject(storectx, X509_LU_X509, + issuer_name)) == NULL) + goto out; - err: - X509_OBJECT_free(tmpobj); + cid = OCSP_cert_to_id(NULL, main_cert, X509_OBJECT_get0_X509(obj)); + + out: X509_STORE_CTX_free(storectx); - return NULL; + X509_OBJECT_free(obj); + + return cid; } struct tls_ocsp * diff --git a/tls_server.c b/tls_server.c index 831255a..ebf76bc 100644 --- a/tls_server.c +++ b/tls_server.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tls_server.c,v 1.47 2021/06/14 03:53:59 tb Exp $ */ +/* $OpenBSD: tls_server.c,v 1.48 2022/01/19 11:10:55 inoguchi Exp $ */ /* * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> * @@ -186,10 +186,16 @@ tls_server_ticket_cb(SSL *ssl, unsigned char *keyname, unsigned char *iv, memcpy(keyname, key->key_name, sizeof(key->key_name)); arc4random_buf(iv, EVP_MAX_IV_LENGTH); - EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, - key->aes_key, iv); - HMAC_Init_ex(hctx, key->hmac_key, sizeof(key->hmac_key), - EVP_sha256(), NULL); + if (!EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, + key->aes_key, iv)) { + tls_set_errorx(tls_ctx, "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"); + return (-1); + } return (0); } else { /* get key by name */ @@ -197,10 +203,16 @@ tls_server_ticket_cb(SSL *ssl, unsigned char *keyname, unsigned char *iv, if (key == NULL) return (0); - EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, - key->aes_key, iv); - HMAC_Init_ex(hctx, key->hmac_key, sizeof(key->hmac_key), - EVP_sha256(), NULL); + if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, + key->aes_key, iv)) { + tls_set_errorx(tls_ctx, "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"); + return (-1); + } /* time to renew the ticket? is it the primary key? */ if (key != &tls_ctx->config->ticket_keys[0]) diff --git a/tls_signer.c b/tls_signer.c new file mode 100644 index 0000000..1f11096 --- /dev/null +++ b/tls_signer.c @@ -0,0 +1,451 @@ +/* $OpenBSD: tls_signer.c,v 1.4 2022/02/01 17:18:38 jsing Exp $ */ +/* + * Copyright (c) 2021 Eric Faurot <eric@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <limits.h> + +#include <openssl/ecdsa.h> +#include <openssl/err.h> +#include <openssl/rsa.h> + +#include "tls.h" +#include "tls_internal.h" + +struct tls_signer_key { + char *hash; + RSA *rsa; + EC_KEY *ecdsa; + struct tls_signer_key *next; +}; + +struct tls_signer { + struct tls_error error; + struct tls_signer_key *keys; +}; + +static pthread_mutex_t signer_method_lock = PTHREAD_MUTEX_INITIALIZER; + +struct tls_signer * +tls_signer_new(void) +{ + struct tls_signer *signer; + + if ((signer = calloc(1, sizeof(*signer))) == NULL) + return (NULL); + + return (signer); +} + +void +tls_signer_free(struct tls_signer *signer) +{ + struct tls_signer_key *skey; + + if (signer == NULL) + return; + + tls_error_clear(&signer->error); + + while (signer->keys) { + skey = signer->keys; + signer->keys = skey->next; + RSA_free(skey->rsa); + EC_KEY_free(skey->ecdsa); + free(skey->hash); + free(skey); + } + + free(signer); +} + +const char * +tls_signer_error(struct tls_signer *signer) +{ + return (signer->error.msg); +} + +int +tls_signer_add_keypair_mem(struct tls_signer *signer, const uint8_t *cert, + size_t cert_len, const uint8_t *key, size_t key_len) +{ + struct tls_signer_key *skey = NULL; + char *errstr = "unknown"; + int ssl_err; + EVP_PKEY *pkey = NULL; + X509 *x509 = NULL; + BIO *bio = NULL; + char *hash = NULL; + + /* Compute certificate hash */ + if ((bio = BIO_new_mem_buf(cert, cert_len)) == NULL) { + tls_error_setx(&signer->error, + "failed to create certificate bio"); + goto err; + } + if ((x509 = PEM_read_bio_X509(bio, NULL, tls_password_cb, + 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); + goto err; + } + if (tls_cert_pubkey_hash(x509, &hash) == -1) { + tls_error_setx(&signer->error, + "failed to get certificate hash"); + goto err; + } + + X509_free(x509); + x509 = NULL; + BIO_free(bio); + bio = NULL; + + /* Read private key */ + if ((bio = BIO_new_mem_buf(key, key_len)) == NULL) { + tls_error_setx(&signer->error, "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"); + goto err; + } + + if ((skey = calloc(1, sizeof(*skey))) == NULL) { + tls_error_set(&signer->error, "failed to create key entry"); + 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"); + goto err; + } + + skey->next = signer->keys; + signer->keys = skey; + EVP_PKEY_free(pkey); + BIO_free(bio); + + return (0); + + err: + EVP_PKEY_free(pkey); + X509_free(x509); + BIO_free(bio); + free(hash); + free(skey); + + return (-1); +} + +int +tls_signer_add_keypair_file(struct tls_signer *signer, const char *cert_file, + const char *key_file) +{ + char *cert = NULL, *key = NULL; + size_t cert_len, key_len; + int rv = -1; + + if (tls_config_load_file(&signer->error, "certificate", cert_file, + &cert, &cert_len) == -1) + goto err; + + if (tls_config_load_file(&signer->error, "key", key_file, &key, + &key_len) == -1) + goto err; + + rv = tls_signer_add_keypair_mem(signer, cert, cert_len, key, key_len); + + err: + free(cert); + free(key); + + return (rv); +} + +static int +tls_sign_rsa(struct tls_signer *signer, struct tls_signer_key *skey, + const uint8_t *input, size_t input_len, int padding_type, + uint8_t **out_signature, size_t *out_signature_len) +{ + int rsa_padding, rsa_size, signature_len; + char *signature = NULL; + + *out_signature = NULL; + *out_signature_len = 0; + + if (padding_type == TLS_PADDING_NONE) { + rsa_padding = RSA_NO_PADDING; + } else if (padding_type == TLS_PADDING_RSA_PKCS1) { + rsa_padding = RSA_PKCS1_PADDING; + } else if (padding_type == TLS_PADDING_RSA_X9_31) { + rsa_padding = RSA_X931_PADDING; + } else { + tls_error_setx(&signer->error, "invalid RSA padding type (%d)", + padding_type); + return (-1); + } + + if (input_len > INT_MAX) { + tls_error_setx(&signer->error, "input too large"); + return (-1); + } + if ((rsa_size = RSA_size(skey->rsa)) <= 0) { + tls_error_setx(&signer->error, "invalid RSA size: %d", + rsa_size); + return (-1); + } + if ((signature = calloc(1, rsa_size)) == NULL) { + tls_error_set(&signer->error, "RSA signature"); + 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"); + free(signature); + return (-1); + } + + *out_signature = signature; + *out_signature_len = (size_t)signature_len; + + return (0); +} + +static int +tls_sign_ecdsa(struct tls_signer *signer, struct tls_signer_key *skey, + const uint8_t *input, size_t input_len, int padding_type, + uint8_t **out_signature, size_t *out_signature_len) +{ + unsigned char *signature; + int signature_len; + + *out_signature = NULL; + *out_signature_len = 0; + + if (padding_type != TLS_PADDING_NONE) { + tls_error_setx(&signer->error, "invalid ECDSA padding"); + return (-1); + } + + if (input_len > INT_MAX) { + tls_error_setx(&signer->error, "digest too large"); + return (-1); + } + if ((signature_len = ECDSA_size(skey->ecdsa)) <= 0) { + tls_error_setx(&signer->error, "invalid ECDSA size: %d", + signature_len); + return (-1); + } + if ((signature = calloc(1, signature_len)) == NULL) { + tls_error_set(&signer->error, "ECDSA signature"); + 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"); + free(signature); + return (-1); + } + + *out_signature = signature; + *out_signature_len = signature_len; + + return (0); +} + +int +tls_signer_sign(struct tls_signer *signer, const char *pubkey_hash, + const uint8_t *input, size_t input_len, int padding_type, + uint8_t **out_signature, size_t *out_signature_len) +{ + struct tls_signer_key *skey; + + *out_signature = NULL; + *out_signature_len = 0; + + for (skey = signer->keys; skey; skey = skey->next) + if (!strcmp(pubkey_hash, skey->hash)) + break; + + if (skey == NULL) { + tls_error_setx(&signer->error, "key not found"); + return (-1); + } + + if (skey->rsa != NULL) + return tls_sign_rsa(signer, skey, input, input_len, + padding_type, out_signature, out_signature_len); + + if (skey->ecdsa != NULL) + return tls_sign_ecdsa(signer, skey, input, input_len, + padding_type, out_signature, out_signature_len); + + tls_error_setx(&signer->error, "unknown key type"); + + return (-1); +} + +static int +tls_rsa_priv_enc(int from_len, const unsigned char *from, unsigned char *to, + RSA *rsa, int rsa_padding) +{ + struct tls_config *config; + uint8_t *signature = NULL; + size_t signature_len = 0; + const char *pubkey_hash; + int padding_type; + + /* + * This function is called via RSA_private_encrypt() and has to conform + * to its calling convention/signature. The caller is required to + * provide a 'to' buffer of at least RSA_size() bytes. + */ + + pubkey_hash = RSA_get_ex_data(rsa, 0); + config = RSA_get_ex_data(rsa, 1); + + if (pubkey_hash == NULL || config == NULL) + goto err; + + if (rsa_padding == RSA_NO_PADDING) { + padding_type = TLS_PADDING_NONE; + } else if (rsa_padding == RSA_PKCS1_PADDING) { + padding_type = TLS_PADDING_RSA_PKCS1; + } else if (rsa_padding == RSA_X931_PADDING) { + padding_type = TLS_PADDING_RSA_X9_31; + } else { + goto err; + } + + if (from_len < 0) + goto err; + + if (config->sign_cb(config->sign_cb_arg, pubkey_hash, from, from_len, + padding_type, &signature, &signature_len) == -1) + goto err; + + if (signature_len > INT_MAX || (int)signature_len > RSA_size(rsa)) + goto err; + + memcpy(to, signature, signature_len); + free(signature); + + return ((int)signature_len); + + err: + free(signature); + + return (-1); +} + +RSA_METHOD * +tls_signer_rsa_method(void) +{ + static RSA_METHOD *rsa_method = NULL; + + pthread_mutex_lock(&signer_method_lock); + + if (rsa_method != NULL) + goto out; + + rsa_method = RSA_meth_new("libtls RSA method", 0); + if (rsa_method == NULL) + goto out; + + RSA_meth_set_priv_enc(rsa_method, tls_rsa_priv_enc); + + out: + pthread_mutex_unlock(&signer_method_lock); + + return (rsa_method); +} + +static ECDSA_SIG * +tls_ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv, + const BIGNUM *rp, EC_KEY *eckey) +{ + struct tls_config *config; + ECDSA_SIG *ecdsa_sig = NULL; + uint8_t *signature = NULL; + size_t signature_len = 0; + const unsigned char *p; + const char *pubkey_hash; + + /* + * This function is called via ECDSA_do_sign_ex() and has to conform + * to its calling convention/signature. + */ + + pubkey_hash = ECDSA_get_ex_data(eckey, 0); + config = ECDSA_get_ex_data(eckey, 1); + + if (pubkey_hash == NULL || config == NULL) + goto err; + + if (dgst_len < 0) + goto err; + + if (config->sign_cb(config->sign_cb_arg, pubkey_hash, dgst, dgst_len, + TLS_PADDING_NONE, &signature, &signature_len) == -1) + goto err; + + p = signature; + if ((ecdsa_sig = d2i_ECDSA_SIG(NULL, &p, signature_len)) == NULL) + goto err; + + free(signature); + + return (ecdsa_sig); + + err: + free(signature); + + return (NULL); +} + +ECDSA_METHOD * +tls_signer_ecdsa_method(void) +{ + static ECDSA_METHOD *ecdsa_method = NULL; + + pthread_mutex_lock(&signer_method_lock); + + if (ecdsa_method != NULL) + goto out; + + ecdsa_method = calloc(1, sizeof(*ecdsa_method)); + if (ecdsa_method == NULL) + goto out; + + ecdsa_method->ecdsa_do_sign = tls_ecdsa_do_sign; + ecdsa_method->name = strdup("libtls ECDSA method"); + if (ecdsa_method->name == NULL) { + free(ecdsa_method); + ecdsa_method = NULL; + } + + out: + pthread_mutex_unlock(&signer_method_lock); + + return (ecdsa_method); +} |