Skip to content

加密会话异常断开 routines::sslv3 alert bad record mac #815

@hiranni

Description

@hiranni

我尝试了tls1.2和ntls。在弱网(1-3mb/s)环境下会话断开频率过高

客户端: SSL error: error string: SSL routines::sslv3 alert bad record mac
服务器:error:0A000139:SSL routines::record layer failure

客户端版本 5.40 (golang sdk)
服务器版本 Tongsuo version 8.5.0-pre1 for target linux-x86_64 (Underlying OpenSSL version 3.5.4)

剥去tongsuo TLS连接正常

同样适用弱网环境,tcp会话测试正常。

使用非弱网环境(15-35mb/s)会话没碰到过异常。也有可能是我测试数据量不够大,我传输2G数据,弱网情况基本没有传输成功的。

客户端服务器IO都是单线程模型。

客户端代码

//go:build cgo && tongsuo
// +build cgo,tongsuo

package client

import (
	"fmt"
	"net"
	"os"
	"path/filepath"
	"client/common/config"
	"strings"

	"github.com/sirupsen/logrus"
	ts "github.com/tongsuo-project/tongsuo-go-sdk"
	"github.com/tongsuo-project/tongsuo-go-sdk/crypto"
)

func loadCertPem(file string) (*crypto.Certificate, error) {
	certPem, err := os.ReadFile(file)
	if err != nil {
		return nil, err
	}

	cert, err := crypto.LoadCertificateFromPEM(certPem)
	if err != nil {
		return nil, err
	}

	return cert, nil
}

func loadKeyPem(file string) (crypto.PrivateKey, error) {
	keyPem, err := os.ReadFile(file)
	if err != nil {
		return nil, err
	}

	key, err := crypto.LoadPrivateKeyFromPEM(keyPem)
	if err != nil {
		return nil, err
	}

	return key, nil
}

func resolveConfigPath(file string) string {
	file = strings.TrimSpace(file)
	if file == "" || filepath.IsAbs(file) {
		return file
	}

	candidates := []string{
		filepath.Join(config.GetCurrentPath(), file),
		filepath.Join(filepath.Dir(config.GetClientConfigPath()), file),
		filepath.Join(filepath.Dir(filepath.Dir(config.GetClientConfigPath())), file),
	}

	for _, candidate := range candidates {
		if _, err := os.Stat(candidate); err == nil {
			return candidate
		}
	}

	return filepath.Join(filepath.Dir(config.GetClientConfigPath()), file)
}

func loadVerifyLocations(ctx *ts.Ctx, ca string) error {
	ca = resolveConfigPath(ca)
	if ca == "" {
		return nil
	}
	if info, err := os.Stat(ca); err == nil && info.IsDir() {
		return ctx.LoadVerifyLocations("", ca)
	}
	return ctx.LoadVerifyLocations(ca, "")
}

func ntlsVersion(method config.EncryptionMethod) ts.SSLVersion {
	switch strings.ToUpper(string(method)) {
	case "TLS", "TLSV1.2":
		return ts.TLSv1_2
	case "TLSV1.3":
		return ts.TLSv1_3
	case "TLSV1.1":
		return ts.TLSv1_1
	case "TLSV1":
		return ts.TLSv1
	case "NTLS":
		return ts.NTLS
	default:
		return ts.NTLS
	}
}

func configureCipherSuites(ctx *ts.Ctx, version ts.SSLVersion, cryptoConf config.CryptoConfig) error {
	if version >= ts.TLSv1_3 {
		if strings.TrimSpace(cryptoConf.ChiperSuites) == "" {
			return nil
		}
		return ctx.SetCipherSuites(cryptoConf.ChiperSuites)
	}

	if strings.TrimSpace(cryptoConf.ChiperList) == "" {
		return nil
	}
	return ctx.SetCipherList(cryptoConf.ChiperList)
}

func loadTLSClientCertificate(ctx *ts.Ctx, cryptoConf config.CryptoConfig) error {
	certFile := strings.TrimSpace(cryptoConf.Cert)
	keyFile := strings.TrimSpace(cryptoConf.Key)
	if certFile == "" && keyFile == "" {
		return nil
	}
	if certFile == "" || keyFile == "" {
		return fmt.Errorf("tls client cert and key must be configured together")
	}

	cert, err := loadCertPem(resolveConfigPath(certFile))
	if err != nil {
		return err
	}
	if err := ctx.UseCertificate(cert); err != nil {
		return err
	}

	key, err := loadKeyPem(resolveConfigPath(keyFile))
	if err != nil {
		return err
	}
	return ctx.UsePrivateKey(key)
}

func loadNTLSClientCertificates(ctx *ts.Ctx, cryptoConf config.CryptoConfig) error {
	if cert, err := loadCertPem(resolveConfigPath(cryptoConf.SignCert)); err != nil {
		return err
	} else if err := ctx.UseSignCertificate(cert); err != nil {
		return err
	}

	if cert, err := loadCertPem(resolveConfigPath(cryptoConf.EncCert)); err != nil {
		return err
	} else if err := ctx.UseEncryptCertificate(cert); err != nil {
		return err
	}

	if key, err := loadKeyPem(resolveConfigPath(cryptoConf.SignKey)); err != nil {
		return err
	} else if err := ctx.UseSignPrivateKey(key); err != nil {
		return err
	}

	if key, err := loadKeyPem(resolveConfigPath(cryptoConf.EncKey)); err != nil {
		return err
	} else if err := ctx.UseEncryptPrivateKey(key); err != nil {
		return err
	}

	return nil
}

func (cli *Client) initNtls() error {
	return cli.initNtlsWithConn(nil)
}

func (cli *Client) initNtlsWithConn(baseConn net.Conn) error {
	version := ntlsVersion(cli.config.Crypto.Method)

	ctx, err := ts.NewCtxWithVersion(version)
	if err != nil {
		return fmt.Errorf("%s %s", err, cli.config.Crypto.Method)
	}

	logrus.Infof("%04x", version)
	cryptoConf := cli.config.Crypto
	if err := configureCipherSuites(ctx, version, cryptoConf); err != nil {
		return fmt.Errorf("configureCipherSuites: %s", err)
	}

	if version == ts.NTLS {
		if err := loadNTLSClientCertificates(ctx, cryptoConf); err != nil {
			return fmt.Errorf("loadNTLSClientCertificates: %s", err)
		}
	} else if err := loadTLSClientCertificate(ctx, cryptoConf); err != nil {
		return fmt.Errorf("loadTLSClientCertificate: %s", err)
	}

	if err := loadVerifyLocations(ctx, cryptoConf.ChainCa); err != nil {
		return fmt.Errorf("loadVerifyLocations: %s", err)
	}

	cli.state.Store(STATE_HANDSHAKE)
	server := net.JoinHostPort(cli.gatewayAddr, cli.gatewayPort)

	var conn *ts.Conn
	if baseConn != nil {
		logrus.Infof("ntls transport handshake start: mode=reused_conn addr=%s", server)
		conn, err = ts.Client(baseConn, ctx)
		if err != nil {
			_ = baseConn.Close()
			return fmt.Errorf("Client: %s", err)
		}
		if err := conn.Handshake(); err != nil {
			_ = conn.Close()
			return fmt.Errorf("Handshake: %s", err)
		}
		logrus.Infof("ntls transport handshake ready: mode=reused_conn addr=%s", server)
	} else {
		logrus.Infof("ntls transport handshake start: mode=direct_dial addr=%s", server)
		conn, err = ts.Dial("tcp", server, ctx, ts.InsecureSkipHostVerification, "")
		if err != nil {
			return fmt.Errorf("Dial: %s", err)
		}
		logrus.Infof("ntls transport handshake ready: mode=direct_dial addr=%s", server)
	}

	cli.state.Store(STATE_RUNNING)
	cli.ntls.ctx = ctx
	cli.ntls.conn = conn
	cli.conn = conn
	return nil
}

服务器代码

#include "_tls.h"

#include <openssl/err.h>
#include <openssl/ntls.h>
#include <openssl/opensslv.h>

#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct _tls_ctx
{
    SSL_CTX *ssl_ctx;
    _tls_config_t config;
};

struct _tls_conn
{
    SSL *ssl;
    int fd;
    _tls_ctx_t *ctx;
};

static _Thread_local char tls_error[512];

static int set_error(const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    vsnprintf(tls_error, sizeof(tls_error), fmt, ap);
    va_end(ap);
    return -1;
}

static int set_openssl_error(const char *op)
{
    unsigned long err = ERR_get_error();
    char detail[256];

    if (err != 0)
    {
        ERR_error_string_n(err, detail, sizeof(detail));
        return set_error("%s failed: %s", op, detail);
    }

    if (errno != 0) return set_error("%s failed: %s", op, strerror(errno));

    return set_error("%s failed", op);
}

static bool str_empty(const char *s) { return !s || s[0] == '\0'; }

static const SSL_METHOD *select_method(const _tls_config_t *config)
{
    if (config->version == TLS_VERSION_NTLS)
    {
        return config->role == _TLS_ROLE_CLIENT ? NTLS_client_method()
                                                     : NTLS_server_method();
    }

    return config->role == _TLS_ROLE_CLIENT ? TLS_client_method()
                                                 : TLS_server_method();
}

static int configure_protocol_version(SSL_CTX *ctx,
                                      const _tls_config_t *config)
{
    int version = 0;

    switch (config->version)
    {
        case TLS_VERSION_TLS1: version = TLS1_VERSION; break;
        case TLS_VERSION_TLS1_1: version = TLS1_1_VERSION; break;
        case TLS_VERSION_TLS1_2: version = TLS1_2_VERSION; break;
        case TLS_VERSION_TLS1_3: version = TLS1_3_VERSION; break;
        case TLS_VERSION_NTLS: return 0;
        default:
            return set_error("unsupported TLS version: %d", config->version);
    }

    if (SSL_CTX_set_min_proto_version(ctx, version) != 1)
        return set_openssl_error("SSL_CTX_set_min_proto_version");
    if (SSL_CTX_set_max_proto_version(ctx, version) != 1)
        return set_openssl_error("SSL_CTX_set_max_proto_version");

    return 0;
}

static int validate_config(const _tls_config_t *config)
{
    if (!config) return set_error("TLS config is NULL");

    if (config->role != _TLS_ROLE_SERVER &&
        config->role != _TLS_ROLE_CLIENT)
        return set_error("invalid TLS role: %d", config->role);

    if (config->version == TLS_VERSION_NTLS)
    {
        if (str_empty(config->sign_cert_file) ||
            str_empty(config->sign_key_file) ||
            str_empty(config->enc_cert_file) || str_empty(config->enc_key_file))
            return set_error(
                "NTLS requires sign and enc certificate/key files");
        return 0;
    }

    if (config->role == _TLS_ROLE_SERVER &&
        (str_empty(config->cert_file) || str_empty(config->key_file)))
        return set_error("TLS server requires cert_file and key_file");

    if (!str_empty(config->cert_file) && str_empty(config->key_file))
        return set_error("key_file is required when cert_file is set");
    if (str_empty(config->cert_file) && !str_empty(config->key_file))
        return set_error("cert_file is required when key_file is set");

    return 0;
}

static int load_standard_certificates(SSL_CTX *ctx,
                                      const _tls_config_t *config)
{
    if (str_empty(config->cert_file)) return 0;

    if (!str_empty(config->chain_file))
    {
        if (SSL_CTX_use_certificate_chain_file(ctx, config->chain_file) != 1)
            return set_openssl_error("SSL_CTX_use_certificate_chain_file");
    }
    else if (SSL_CTX_use_certificate_file(ctx, config->cert_file,
                                          SSL_FILETYPE_PEM) != 1)
    {
        return set_openssl_error("SSL_CTX_use_certificate_file");
    }

    if (SSL_CTX_use_PrivateKey_file(ctx, config->key_file, SSL_FILETYPE_PEM) !=
        1)
        return set_openssl_error("SSL_CTX_use_PrivateKey_file");

    if (SSL_CTX_check_private_key(ctx) != 1)
        return set_openssl_error("SSL_CTX_check_private_key");

    return 0;
}

static int load_ntls_certificates(SSL_CTX *ctx,
                                  const _tls_config_t *config)
{
    if (SSL_CTX_use_sign_certificate_file(ctx, config->sign_cert_file,
                                          SSL_FILETYPE_PEM) != 1)
        return set_openssl_error("SSL_CTX_use_sign_certificate_file");

    if (SSL_CTX_use_sign_PrivateKey_file(ctx, config->sign_key_file,
                                         SSL_FILETYPE_PEM) != 1)
        return set_openssl_error("SSL_CTX_use_sign_PrivateKey_file");

    if (SSL_CTX_use_enc_certificate_file(ctx, config->enc_cert_file,
                                         SSL_FILETYPE_PEM) != 1)
        return set_openssl_error("SSL_CTX_use_enc_certificate_file");

    if (SSL_CTX_use_enc_PrivateKey_file(ctx, config->enc_key_file,
                                        SSL_FILETYPE_PEM) != 1)
        return set_openssl_error("SSL_CTX_use_enc_PrivateKey_file");

    SSL_CTX_enable_ntls(ctx);
    return 0;
}

static int configure_trust(SSL_CTX *ctx, const _tls_config_t *config)
{
    int verify_mode = SSL_VERIFY_NONE;

    if (!str_empty(config->ca_file) || !str_empty(config->ca_path))
    {
        if (SSL_CTX_load_verify_locations(ctx, config->ca_file,
                                          config->ca_path) != 1)
            return set_openssl_error("SSL_CTX_load_verify_locations");
    }
    else if (config->verify_peer)
    {
        if (SSL_CTX_set_default_verify_paths(ctx) != 1)
            return set_openssl_error("SSL_CTX_set_default_verify_paths");
    }

    if (config->verify_peer || config->require_client_cert)
        verify_mode |= SSL_VERIFY_PEER;
    if (config->role == _TLS_ROLE_SERVER && config->require_client_cert)
        verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;

    SSL_CTX_set_verify(ctx, verify_mode, NULL);

    if (config->verify_depth > 0)
        SSL_CTX_set_verify_depth(ctx, config->verify_depth);

    return 0;
}

static int configure_ciphers(SSL_CTX *ctx, const _tls_config_t *config)
{
    if (!str_empty(config->cipher_list) &&
        SSL_CTX_set_cipher_list(ctx, config->cipher_list) != 1)
        return set_openssl_error("SSL_CTX_set_cipher_list");

    if (config->version == TLS_VERSION_TLS1_3 &&
        !str_empty(config->cipher_suites) &&
        SSL_CTX_set_ciphersuites(ctx, config->cipher_suites) != 1)
        return set_openssl_error("SSL_CTX_set_ciphersuites");

    if (!str_empty(config->groups_list) &&
        SSL_CTX_set1_groups_list(ctx, config->groups_list) != 1)
        return set_openssl_error("SSL_CTX_set1_groups_list");

    return 0;
}

static _tls_status_t map_ssl_status(SSL *ssl, int ret, const char *op)
{
    int err = SSL_get_error(ssl, ret);

    switch (err)
    {
        case SSL_ERROR_WANT_READ: return _TLS_WANT_READ;
        case SSL_ERROR_WANT_WRITE: return _TLS_WANT_WRITE;
        case SSL_ERROR_ZERO_RETURN: return _TLS_CLOSED;
        case SSL_ERROR_SYSCALL:
            if (ret == 0)
            {
                set_error("%s failed: peer closed connection", op);
                return _TLS_CLOSED;
            }
            set_openssl_error(op);
            return _TLS_ERROR;
        case SSL_ERROR_SSL:
        default: set_openssl_error(op); return _TLS_ERROR;
    }
}

int _tls_library_init(void)
{
    if (OPENSSL_init_ssl(
            OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS,
            NULL) != 1)
        return set_openssl_error("OPENSSL_init_ssl");

    return 0;
}

void _tls_library_cleanup(void) { OPENSSL_cleanup(); }

const char *_tls_last_error(void) { return tls_error; }

const char *_tls_status_name(_tls_status_t status)
{
    switch (status)
    {
        case _TLS_OK: return "ok";
        case _TLS_WANT_READ: return "want_read";
        case _TLS_WANT_WRITE: return "want_write";
        case _TLS_CLOSED: return "closed";
        case _TLS_ERROR: return "error";
        default: return "unknown";
    }
}

const char *_tls_version_string(void)
{
    return OpenSSL_version(OPENSSL_VERSION);
}

int _tls_ctx_create(const _tls_config_t *config,
                         _tls_ctx_t **out)
{
    _tls_ctx_t *ctx = NULL;
    const SSL_METHOD *method = NULL;

    if (!out) return set_error("out TLS ctx is NULL");
    *out = NULL;

    if (_tls_library_init() != 0) return -1;
    if (validate_config(config) != 0) return -1;

    method = select_method(config);
    if (!method) return set_error("failed to select TLS method");

    ctx = calloc(1, sizeof(*ctx));
    if (!ctx) return set_error("calloc _tls_ctx failed");

    ctx->config = *config;
    ctx->ssl_ctx = SSL_CTX_new(method);
    if (!ctx->ssl_ctx)
    {
        set_openssl_error("SSL_CTX_new");
        goto error;
    }

    SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_COMPRESSION | config->options);
    SSL_CTX_set_mode(ctx->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE |
                                       SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
                                       config->mode);

    if (configure_protocol_version(ctx->ssl_ctx, config) != 0) goto error;
    if (config->version == TLS_VERSION_NTLS)
    {
        if (load_ntls_certificates(ctx->ssl_ctx, config) != 0) goto error;
    }
    else if (load_standard_certificates(ctx->ssl_ctx, config) != 0)
    {
        goto error;
    }

    if (configure_trust(ctx->ssl_ctx, config) != 0) goto error;
    if (configure_ciphers(ctx->ssl_ctx, config) != 0) goto error;

    SSL_CTX_set_session_cache_mode(
        ctx->ssl_ctx,
        config->enable_session_cache
            ? (config->role == _TLS_ROLE_CLIENT ? SSL_SESS_CACHE_CLIENT
                                                     : SSL_SESS_CACHE_SERVER)
            : SSL_SESS_CACHE_OFF);

    *out = ctx;
    return 0;

error:
    _tls_ctx_free(ctx);
    return -1;
}

void _tls_ctx_free(_tls_ctx_t *ctx)
{
    if (!ctx) return;
    if (ctx->ssl_ctx) SSL_CTX_free(ctx->ssl_ctx);
    free(ctx);
}

SSL_CTX *_tls_ctx_get_ssl_ctx(_tls_ctx_t *ctx)
{
    return ctx ? ctx->ssl_ctx : NULL;
}

int _tls_conn_create(_tls_ctx_t *ctx, int fd, _tls_conn_t **out)
{
    _tls_conn_t *conn = NULL;

    if (!out) return set_error("out TLS conn is NULL");
    *out = NULL;
    if (!ctx || !ctx->ssl_ctx) return set_error("TLS ctx is NULL");
    if (fd < 0) return set_error("invalid TLS fd: %d", fd);

    conn = calloc(1, sizeof(*conn));
    if (!conn) return set_error("calloc _tls_conn failed");

    conn->ssl = SSL_new(ctx->ssl_ctx);
    if (!conn->ssl)
    {
        set_openssl_error("SSL_new");
        free(conn);
        return -1;
    }

    if (SSL_set_fd(conn->ssl, fd) != 1)
    {
        set_openssl_error("SSL_set_fd");
        SSL_free(conn->ssl);
        free(conn);
        return -1;
    }

    conn->fd = fd;
    conn->ctx = ctx;
    if (ctx->config.role == _TLS_ROLE_CLIENT)
        SSL_set_connect_state(conn->ssl);
    else
        SSL_set_accept_state(conn->ssl);

    *out = conn;
    return 0;
}

void _tls_conn_free(_tls_conn_t *conn)
{
    if (!conn) return;
    if (conn->ssl) SSL_free(conn->ssl);
    free(conn);
}

SSL *_tls_conn_get_ssl(_tls_conn_t *conn)
{
    return conn ? conn->ssl : NULL;
}

int _tls_conn_fd(const _tls_conn_t *conn)
{
    return conn ? conn->fd : -1;
}

_tls_status_t _tls_accept(_tls_conn_t *conn)
{
    int ret;

    if (!conn || !conn->ssl)
    {
        set_error("TLS conn is NULL");
        return _TLS_ERROR;
    }

    ret = SSL_accept(conn->ssl);
    return ret == 1 ? _TLS_OK
                    : map_ssl_status(conn->ssl, ret, "SSL_accept");
}

_tls_status_t _tls_connect(_tls_conn_t *conn)
{
    int ret;

    if (!conn || !conn->ssl)
    {
        set_error("TLS conn is NULL");
        return _TLS_ERROR;
    }

    ret = SSL_connect(conn->ssl);
    return ret == 1 ? _TLS_OK
                    : map_ssl_status(conn->ssl, ret, "SSL_connect");
}

_tls_status_t _tls_read(_tls_conn_t *conn, void *buf, size_t len,
                                  ssize_t *nread)
{
    int ret;

    if (nread) *nread = 0;
    if (!conn || !conn->ssl || !buf)
    {
        set_error("invalid TLS read arguments");
        return _TLS_ERROR;
    }

    ret = SSL_read(conn->ssl, buf, (int)len);
    if (ret > 0)
    {
        if (nread) *nread = ret;
        return _TLS_OK;
    }

    return map_ssl_status(conn->ssl, ret, "SSL_read");
}

_tls_status_t _tls_write(_tls_conn_t *conn, const void *buf,
                                   size_t len, ssize_t *nwritten)
{
    int ret;

    if (nwritten) *nwritten = 0;
    if (!conn || !conn->ssl || !buf)
    {
        set_error("invalid TLS write arguments");
        return _TLS_ERROR;
    }

    ret = SSL_write(conn->ssl, buf, (int)len);
    if (ret > 0)
    {
        if (nwritten) *nwritten = ret;
        return _TLS_OK;
    }

    return map_ssl_status(conn->ssl, ret, "SSL_write");
}

_tls_status_t _tls_shutdown(_tls_conn_t *conn)
{
    int ret;

    if (!conn || !conn->ssl)
    {
        set_error("TLS conn is NULL");
        return _TLS_ERROR;
    }

    ret = SSL_shutdown(conn->ssl);
    if (ret == 1) return _TLS_OK;
    if (ret == 0) return _TLS_WANT_READ;

    return map_ssl_status(conn->ssl, ret, "SSL_shutdown");
}

SSL_CTX *_tls_create_ctx(_tls_config_t *config)
{
    _tls_ctx_t *ctx = NULL;
    SSL_CTX *ssl_ctx = NULL;

    if (_tls_ctx_create(config, &ctx) != 0) return NULL;

    ssl_ctx = ctx->ssl_ctx;
    ctx->ssl_ctx = NULL;
    _tls_ctx_free(ctx);
    return ssl_ctx;
}

void _tls_free_ctx(SSL_CTX *ctx)
{
    if (ctx) SSL_CTX_free(ctx);
}


#pragma once

#include <openssl/ssl.h>
#include <stdbool.h>
#include <stddef.h>
#include <sys/types.h>

#ifdef __cplusplus
extern "C"
{
#endif

    typedef enum
    {
        _TLS_ROLE_SERVER = 0,
        _TLS_ROLE_CLIENT = 1,
    } _tls_role_t;

    typedef enum
    {
        TLS_VERSION_TLS1 = 0,
        TLS_VERSION_TLS1_1,
        TLS_VERSION_TLS1_2,
        TLS_VERSION_TLS1_3,
        TLS_VERSION_NTLS,
    } _tls_version_t;

    typedef _tls_version_t tls_version_t;

    typedef enum
    {
        _TLS_OK = 0,
        _TLS_WANT_READ = 1,
        _TLS_WANT_WRITE = 2,
        _TLS_CLOSED = 3,
        _TLS_ERROR = -1,
    } _tls_status_t;

    typedef struct _tls_config
    {
        _tls_role_t role;
        _tls_version_t version;

        const char *cert_file;
        const char *key_file;
        const char *chain_file;

        const char *sign_cert_file;
        const char *sign_key_file;
        const char *enc_cert_file;
        const char *enc_key_file;

        const char *ca_file;
        const char *ca_path;
        bool verify_peer;
        bool require_client_cert;
        int verify_depth;

        const char *cipher_list;
        const char *cipher_suites;
        const char *groups_list;

        bool enable_session_cache;
        long options;
        long mode;
    } _tls_config_t;

    typedef struct _tls_ctx _tls_ctx_t;
    typedef struct _tls_conn _tls_conn_t;

    int _tls_library_init(void);
    void _tls_library_cleanup(void);
    const char *_tls_last_error(void);
    const char *_tls_status_name(_tls_status_t status);
    const char *_tls_version_string(void);

    int _tls_ctx_create(const _tls_config_t *config,
                             _tls_ctx_t **out);
    void _tls_ctx_free(_tls_ctx_t *ctx);
    SSL_CTX *_tls_ctx_get_ssl_ctx(_tls_ctx_t *ctx);

    int _tls_conn_create(_tls_ctx_t *ctx, int fd,
                              _tls_conn_t **out);
    void _tls_conn_free(_tls_conn_t *conn);
    SSL *_tls_conn_get_ssl(_tls_conn_t *conn);
    int _tls_conn_fd(const _tls_conn_t *conn);

    _tls_status_t _tls_accept(_tls_conn_t *conn);
    _tls_status_t _tls_connect(_tls_conn_t *conn);
    _tls_status_t _tls_read(_tls_conn_t *conn, void *buf,
                                      size_t len, ssize_t *nread);
    _tls_status_t _tls_write(_tls_conn_t *conn, const void *buf,
                                       size_t len, ssize_t *nwritten);
    _tls_status_t _tls_shutdown(_tls_conn_t *conn);

    SSL_CTX *_tls_create_ctx(_tls_config_t *config);
    void _tls_free_ctx(SSL_CTX *ctx);

#ifdef __cplusplus
}
#endif


#ifdef __cplusplus
}
#endif

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions