#include "tls_compat.h" #if !defined(NOSSL) || !NOSSL #include #include #include #include #include #include #include #include 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); SSL_CTX_set_default_verify_paths(ctx); 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_verify_hostname(tls_t ctx, const char *hostname) { X509 *cert; long verify_result; if (global_tls_config == NULL || global_tls_config->noverifyname) return 0; if (global_tls_config->noverifycert) return 0; verify_result = SSL_get_verify_result(ctx->ssl); if (verify_result != X509_V_OK) return -1; cert = SSL_get_peer_certificate(ctx->ssl); if (cert == NULL) return -1; if (X509_check_host(cert, hostname, 0, 0, NULL) != 1) { X509_free(cert); return -1; } X509_free(cert); 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