diff options
Diffstat (limited to 'tls_compat.c')
| -rw-r--r-- | tls_compat.c | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/tls_compat.c b/tls_compat.c new file mode 100644 index 0000000..cde80a9 --- /dev/null +++ b/tls_compat.c @@ -0,0 +1,283 @@ +#include "tls_compat.h" + +#ifndef NOSSL + +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <stdlib.h> +#include <openssl/ssl.h> +#include <openssl/err.h> +#include <openssl/x509v3.h> + +static char tls_error_buf[256]; +static tls_config_t global_tls_config = NULL; + +tls_config_t +tls_config_new(void) +{ + tls_config_t config; + SSL_CTX *ctx; + + SSL_library_init(); + SSL_load_error_strings(); + OpenSSL_add_all_algorithms(); + + ctx = SSL_CTX_new(TLS_client_method()); + if (ctx == NULL) + return NULL; + + config = calloc(1, sizeof(*config)); + if (config == NULL) { + SSL_CTX_free(ctx); + return NULL; + } + + config->ctx = ctx; + config->verify_depth = 100; + config->noverifycert = 0; + config->noverifyname = 0; + config->noverifytime = 0; + config->muststaple = 0; + config->session_fd = -1; + + SSL_CTX_set_options(ctx, SSL_OP_LEGACY_SERVER_CONNECT); + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); + + return config; +} + +void +tls_config_free(tls_config_t config) +{ + if (config) { + if (config->ctx) + SSL_CTX_free(config->ctx); + free(config); + } +} + +int +tls_config_set_ca_file(tls_config_t config, const char *ca_file) +{ + if (SSL_CTX_load_verify_locations(config->ctx, ca_file, NULL) != 1) + return -1; + return 0; +} + +int +tls_config_set_ca_path(tls_config_t config, const char *ca_path) +{ + if (SSL_CTX_load_verify_locations(config->ctx, NULL, ca_path) != 1) + return -1; + return 0; +} + +int +tls_config_set_ciphers(tls_config_t config, const char *ciphers) +{ + if (SSL_CTX_set_cipher_list(config->ctx, ciphers) != 1) + return -1; + return 0; +} + +void +tls_config_insecure_noverifycert(tls_config_t config) +{ + config->noverifycert = 1; + SSL_CTX_set_verify(config->ctx, SSL_VERIFY_NONE, NULL); +} + +void +tls_config_insecure_noverifyname(tls_config_t config) +{ + config->noverifyname = 1; +} + +void +tls_config_verify(tls_config_t config) +{ + config->noverifycert = 0; + config->noverifyname = 0; + SSL_CTX_set_verify(config->ctx, SSL_VERIFY_PEER, NULL); +} + +int +tls_config_set_verify_depth(tls_config_t config, int depth) +{ + config->verify_depth = depth; + SSL_CTX_set_verify_depth(config->ctx, depth); + return 0; +} + +void +tls_config_ocsp_require_stapling(tls_config_t config) +{ + config->muststaple = 1; +} + +void +tls_config_insecure_noverifytime(tls_config_t config) +{ + config->noverifytime = 1; + X509_STORE *store = SSL_CTX_get_cert_store(config->ctx); + if (store) + X509_STORE_set_flags(store, X509_V_FLAG_NO_CHECK_TIME); +} + +int +tls_config_set_session_fd(tls_config_t config, int fd) +{ + config->session_fd = fd; + return 0; +} + +int +tls_config_parse_protocols(uint32_t *protocols, const char *protostr) +{ + *protocols = 0; + if (strstr(protostr, "TLSv1.3") || strstr(protostr, "tlsv1.3")) + *protocols |= (1 << 0); + if (strstr(protostr, "TLSv1.2") || strstr(protostr, "tlsv1.2")) + *protocols |= (1 << 1); + if (strstr(protostr, "TLSv1.1") || strstr(protostr, "tlsv1.1")) + *protocols |= (1 << 2); + if (strstr(protostr, "TLSv1.0") || strstr(protostr, "tlsv1.0") || strstr(protostr, "TLSv1") || strstr(protostr, "tlsv1")) + *protocols |= (1 << 3); + if (*protocols == 0) + return -1; + return 0; +} + +int +tls_config_set_protocols(tls_config_t config, uint32_t protocols) +{ + long options = 0; + if (!(protocols & (1 << 3))) + options |= SSL_OP_NO_TLSv1; + if (!(protocols & (1 << 2))) + options |= SSL_OP_NO_TLSv1_1; + if (!(protocols & (1 << 1))) + options |= SSL_OP_NO_TLSv1_2; + if (!(protocols & (1 << 0))) + options |= SSL_OP_NO_TLSv1_3; + SSL_CTX_set_options(config->ctx, options); + return 0; +} + +const char * +tls_config_error(tls_config_t config) +{ + unsigned long err = ERR_get_error(); + if (err) + ERR_error_string_n(err, tls_error_buf, sizeof(tls_error_buf)); + else + strcpy(tls_error_buf, "unknown error"); + return tls_error_buf; +} + +tls_t +tls_client(void) +{ + tls_t tls = calloc(1, sizeof(*tls)); + if (tls == NULL) + return NULL; + return tls; +} + +int +tls_configure(tls_t ctx, tls_config_t config) +{ + ctx->ctx = config->ctx; + global_tls_config = config; + return 0; +} + +int +tls_connect_socket(tls_t ctx, int s, const char *servername) +{ + ctx->fd = s; + ctx->ssl = SSL_new(ctx->ctx); + if (ctx->ssl == NULL) + return -1; + if (SSL_set_fd(ctx->ssl, s) != 1) + return -1; + if (servername && SSL_set_tlsext_host_name(ctx->ssl, servername) != 1) + return -1; + return 0; +} + +int +tls_handshake(tls_t ctx) +{ + int ret = SSL_connect(ctx->ssl); + if (ret <= 0) { + int err = SSL_get_error(ctx->ssl, ret); + if (err == SSL_ERROR_WANT_READ) + return TLS_WANT_POLLIN; + if (err == SSL_ERROR_WANT_WRITE) + return TLS_WANT_POLLOUT; + return -1; + } + return 0; +} + +int +tls_read(tls_t ctx, void *buf, size_t buflen) +{ + return SSL_read(ctx->ssl, buf, buflen); +} + +int +tls_write(tls_t ctx, const void *buf, size_t buflen) +{ + return SSL_write(ctx->ssl, buf, buflen); +} + +int +tls_close(tls_t ctx) +{ + if (ctx && ctx->ssl) { + int ret = SSL_shutdown(ctx->ssl); + if (ret < 0) { + int err = SSL_get_error(ctx->ssl, ret); + if (err == SSL_ERROR_WANT_READ) + return TLS_WANT_POLLIN; + if (err == SSL_ERROR_WANT_WRITE) + return TLS_WANT_POLLOUT; + } + SSL_free(ctx->ssl); + ctx->ssl = NULL; + } + return 0; +} + +void +tls_free(tls_t ctx) +{ + if (ctx) { + if (ctx->ssl) + SSL_free(ctx->ssl); + free(ctx); + } +} + +const char * +tls_error(tls_t ctx) +{ + unsigned long err = ERR_get_error(); + if (err) + ERR_error_string_n(err, tls_error_buf, sizeof(tls_error_buf)); + else + strcpy(tls_error_buf, "unknown error"); + return tls_error_buf; +} + +int +tls_conn_session_resumed(tls_t ctx) +{ + return SSL_session_reused(ctx->ssl); +} + +#endif \ No newline at end of file |