initial commit
This commit is contained in:
1114
third_party/libhv/ssl/appletls.c
vendored
Executable file
1114
third_party/libhv/ssl/appletls.c
vendored
Executable file
File diff suppressed because it is too large
Load Diff
197
third_party/libhv/ssl/gnutls.c
vendored
Executable file
197
third_party/libhv/ssl/gnutls.c
vendored
Executable file
@@ -0,0 +1,197 @@
|
||||
#include "hssl.h"
|
||||
|
||||
#ifdef WITH_GNUTLS
|
||||
|
||||
#include "gnutls/gnutls.h"
|
||||
|
||||
const char* hssl_backend() {
|
||||
return "gnutls";
|
||||
}
|
||||
|
||||
typedef gnutls_certificate_credentials_t gnutls_ctx_t;
|
||||
|
||||
hssl_ctx_t hssl_ctx_new(hssl_ctx_opt_t* param) {
|
||||
static int s_initialized = 0;
|
||||
if (s_initialized == 0) {
|
||||
gnutls_global_init();
|
||||
s_initialized = 1;
|
||||
}
|
||||
|
||||
gnutls_ctx_t ctx;
|
||||
const char* crt_file = NULL;
|
||||
const char* key_file = NULL;
|
||||
const char* ca_file = NULL;
|
||||
const char* ca_path = NULL;
|
||||
|
||||
int ret = gnutls_certificate_allocate_credentials(&ctx);
|
||||
if (ret != GNUTLS_E_SUCCESS) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (param) {
|
||||
if (param->crt_file && *param->crt_file) {
|
||||
crt_file = param->crt_file;
|
||||
}
|
||||
if (param->key_file && *param->key_file) {
|
||||
key_file = param->key_file;
|
||||
}
|
||||
if (param->ca_file && *param->ca_file) {
|
||||
ca_file = param->ca_file;
|
||||
}
|
||||
if (param->ca_path && *param->ca_path) {
|
||||
ca_path = param->ca_path;
|
||||
}
|
||||
|
||||
if (ca_file) {
|
||||
ret = gnutls_certificate_set_x509_trust_file(ctx, ca_file, GNUTLS_X509_FMT_PEM);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "ssl ca_file failed!\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (ca_path) {
|
||||
ret = gnutls_certificate_set_x509_trust_dir(ctx, ca_path, GNUTLS_X509_FMT_PEM);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "ssl ca_path failed!\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (crt_file && key_file) {
|
||||
ret = gnutls_certificate_set_x509_key_file(ctx, crt_file, key_file, GNUTLS_X509_FMT_PEM);
|
||||
if (ret != GNUTLS_E_SUCCESS) {
|
||||
fprintf(stderr, "ssl crt_file/key_file error!\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (param->verify_peer && !ca_file && !ca_path) {
|
||||
gnutls_certificate_set_x509_system_trust(ctx);
|
||||
}
|
||||
}
|
||||
return ctx;
|
||||
error:
|
||||
gnutls_certificate_free_credentials(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void hssl_ctx_free(hssl_ctx_t ssl_ctx) {
|
||||
if (!ssl_ctx) return;
|
||||
gnutls_ctx_t ctx = (gnutls_ctx_t)ssl_ctx;
|
||||
gnutls_certificate_free_credentials(ctx);
|
||||
}
|
||||
|
||||
typedef struct gnutls_s {
|
||||
gnutls_session_t session;
|
||||
gnutls_ctx_t ctx;
|
||||
int fd;
|
||||
} gnutls_t;
|
||||
|
||||
hssl_t hssl_new(hssl_ctx_t ssl_ctx, int fd) {
|
||||
gnutls_t* gnutls = (gnutls_t*)malloc(sizeof(gnutls_t));
|
||||
if (gnutls == NULL) return NULL;
|
||||
gnutls->session = NULL;
|
||||
gnutls->ctx = (gnutls_ctx_t)ssl_ctx;
|
||||
gnutls->fd = fd;
|
||||
return (hssl_t)gnutls;
|
||||
}
|
||||
|
||||
static int hssl_init(hssl_t ssl, int endpoint) {
|
||||
if (ssl == NULL) return HSSL_ERROR;
|
||||
gnutls_t* gnutls = (gnutls_t*)ssl;
|
||||
if (gnutls->session == NULL) {
|
||||
gnutls_init(&gnutls->session, endpoint);
|
||||
gnutls_priority_set_direct(gnutls->session, "NORMAL", NULL);
|
||||
gnutls_credentials_set(gnutls->session, GNUTLS_CRD_CERTIFICATE, gnutls->ctx);
|
||||
gnutls_transport_set_ptr(gnutls->session, (gnutls_transport_ptr_t)(ptrdiff_t)gnutls->fd);
|
||||
}
|
||||
return HSSL_OK;
|
||||
}
|
||||
|
||||
void hssl_free(hssl_t ssl) {
|
||||
if (ssl == NULL) return;
|
||||
gnutls_t* gnutls = (gnutls_t*)ssl;
|
||||
if (gnutls->session) {
|
||||
gnutls_deinit(gnutls->session);
|
||||
gnutls->session = NULL;
|
||||
}
|
||||
free(gnutls);
|
||||
}
|
||||
|
||||
static int hssl_handshake(hssl_t ssl) {
|
||||
if (ssl == NULL) return HSSL_ERROR;
|
||||
gnutls_t* gnutls = (gnutls_t*)ssl;
|
||||
if (gnutls->session == NULL) return HSSL_ERROR;
|
||||
int ret = 0;
|
||||
while (1) {
|
||||
ret = gnutls_handshake(gnutls->session);
|
||||
if (ret == GNUTLS_E_SUCCESS) {
|
||||
return HSSL_OK;
|
||||
}
|
||||
else if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) {
|
||||
return gnutls_record_get_direction(gnutls->session) == 0 ? HSSL_WANT_READ : HSSL_WANT_WRITE;
|
||||
}
|
||||
else if (gnutls_error_is_fatal(ret)) {
|
||||
// fprintf(stderr, "gnutls_handshake failed: %s\n", gnutls_strerror(ret));
|
||||
return HSSL_ERROR;
|
||||
}
|
||||
}
|
||||
return HSSL_OK;
|
||||
}
|
||||
|
||||
int hssl_accept(hssl_t ssl) {
|
||||
if (ssl == NULL) return HSSL_ERROR;
|
||||
gnutls_t* gnutls = (gnutls_t*)ssl;
|
||||
if (gnutls->session == NULL) {
|
||||
hssl_init(ssl, GNUTLS_SERVER);
|
||||
}
|
||||
return hssl_handshake(ssl);
|
||||
}
|
||||
|
||||
int hssl_connect(hssl_t ssl) {
|
||||
if (ssl == NULL) return HSSL_ERROR;
|
||||
gnutls_t* gnutls = (gnutls_t*)ssl;
|
||||
if (gnutls->session == NULL) {
|
||||
hssl_init(ssl, GNUTLS_CLIENT);
|
||||
}
|
||||
return hssl_handshake(ssl);
|
||||
}
|
||||
|
||||
int hssl_read(hssl_t ssl, void* buf, int len) {
|
||||
if (ssl == NULL) return HSSL_ERROR;
|
||||
gnutls_t* gnutls = (gnutls_t*)ssl;
|
||||
if (gnutls->session == NULL) return HSSL_ERROR;
|
||||
int ret = 0;
|
||||
while ((ret = gnutls_record_recv(gnutls->session, buf, len)) == GNUTLS_E_INTERRUPTED);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int hssl_write(hssl_t ssl, const void* buf, int len) {
|
||||
if (ssl == NULL) return HSSL_ERROR;
|
||||
gnutls_t* gnutls = (gnutls_t*)ssl;
|
||||
if (gnutls->session == NULL) return HSSL_ERROR;
|
||||
int ret = 0;
|
||||
while ((ret = gnutls_record_send(gnutls->session, buf, len)) == GNUTLS_E_INTERRUPTED);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int hssl_close(hssl_t ssl) {
|
||||
if (ssl == NULL) return HSSL_ERROR;
|
||||
gnutls_t* gnutls = (gnutls_t*)ssl;
|
||||
if (gnutls->session == NULL) return HSSL_ERROR;
|
||||
gnutls_bye(gnutls->session, GNUTLS_SHUT_RDWR);
|
||||
return HSSL_OK;
|
||||
}
|
||||
|
||||
int hssl_set_sni_hostname(hssl_t ssl, const char* hostname) {
|
||||
if (ssl == NULL) return HSSL_ERROR;
|
||||
gnutls_t* gnutls = (gnutls_t*)ssl;
|
||||
if (gnutls->session == NULL) {
|
||||
hssl_init(ssl, GNUTLS_CLIENT);
|
||||
}
|
||||
gnutls_server_name_set(gnutls->session, GNUTLS_NAME_DNS, hostname, strlen(hostname));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // WITH_GNUTLS
|
||||
24
third_party/libhv/ssl/hssl.c
vendored
Executable file
24
third_party/libhv/ssl/hssl.c
vendored
Executable file
@@ -0,0 +1,24 @@
|
||||
#include "hssl.h"
|
||||
|
||||
hssl_ctx_t g_ssl_ctx = NULL;
|
||||
|
||||
hssl_ctx_t hssl_ctx_init(hssl_ctx_init_param_t* param) {
|
||||
if (g_ssl_ctx == NULL) {
|
||||
g_ssl_ctx = hssl_ctx_new(param);
|
||||
}
|
||||
return g_ssl_ctx;
|
||||
}
|
||||
|
||||
void hssl_ctx_cleanup(hssl_ctx_t ssl_ctx) {
|
||||
hssl_ctx_free(ssl_ctx);
|
||||
if (g_ssl_ctx == ssl_ctx) {
|
||||
g_ssl_ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
hssl_ctx_t hssl_ctx_instance() {
|
||||
if (g_ssl_ctx == NULL) {
|
||||
g_ssl_ctx = hssl_ctx_new(NULL);
|
||||
}
|
||||
return g_ssl_ctx;
|
||||
}
|
||||
91
third_party/libhv/ssl/hssl.h
vendored
Executable file
91
third_party/libhv/ssl/hssl.h
vendored
Executable file
@@ -0,0 +1,91 @@
|
||||
#ifndef HV_SSL_H_
|
||||
#define HV_SSL_H_
|
||||
|
||||
#include "hexport.h"
|
||||
|
||||
#include "hplatform.h"
|
||||
#if !defined(WITH_OPENSSL) && \
|
||||
!defined(WITH_GNUTLS) && \
|
||||
!defined(WITH_MBEDTLS)
|
||||
#ifdef OS_WIN
|
||||
#define WITH_WINTLS
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "secur32.lib")
|
||||
#pragma comment(lib, "crypt32.lib")
|
||||
#endif
|
||||
#elif defined(OS_DARWIN)
|
||||
#define WITH_APPLETLS
|
||||
#else
|
||||
#define HV_WITHOUT_SSL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef void* hssl_ctx_t; ///> SSL_CTX
|
||||
typedef void* hssl_t; ///> SSL
|
||||
|
||||
enum {
|
||||
HSSL_SERVER = 0,
|
||||
HSSL_CLIENT = 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
HSSL_OK = 0,
|
||||
HSSL_ERROR = -1,
|
||||
HSSL_WANT_READ = -2,
|
||||
HSSL_WANT_WRITE = -3,
|
||||
HSSL_WOULD_BLOCK = -4,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const char* crt_file;
|
||||
const char* key_file;
|
||||
const char* ca_file;
|
||||
const char* ca_path;
|
||||
short verify_peer;
|
||||
short endpoint; // HSSL_SERVER / HSSL_CLIENT
|
||||
} hssl_ctx_opt_t, hssl_ctx_init_param_t;
|
||||
|
||||
BEGIN_EXTERN_C
|
||||
|
||||
/*
|
||||
const char* hssl_backend() {
|
||||
#ifdef WITH_OPENSSL
|
||||
return "openssl";
|
||||
#elif defined(WITH_GNUTLS)
|
||||
return "gnutls";
|
||||
#elif defined(WITH_MBEDTLS)
|
||||
return "mbedtls";
|
||||
#else
|
||||
return "nossl";
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
HV_EXPORT const char* hssl_backend();
|
||||
#define HV_WITH_SSL (strcmp(hssl_backend(), "nossl") != 0)
|
||||
|
||||
HV_EXPORT extern hssl_ctx_t g_ssl_ctx;
|
||||
HV_EXPORT hssl_ctx_t hssl_ctx_init(hssl_ctx_init_param_t* param);
|
||||
HV_EXPORT void hssl_ctx_cleanup(hssl_ctx_t ssl_ctx);
|
||||
HV_EXPORT hssl_ctx_t hssl_ctx_instance();
|
||||
|
||||
HV_EXPORT hssl_ctx_t hssl_ctx_new(hssl_ctx_opt_t* opt);
|
||||
HV_EXPORT void hssl_ctx_free(hssl_ctx_t ssl_ctx);
|
||||
|
||||
HV_EXPORT hssl_t hssl_new(hssl_ctx_t ssl_ctx, int fd);
|
||||
HV_EXPORT void hssl_free(hssl_t ssl);
|
||||
|
||||
HV_EXPORT int hssl_accept(hssl_t ssl);
|
||||
HV_EXPORT int hssl_connect(hssl_t ssl);
|
||||
HV_EXPORT int hssl_read(hssl_t ssl, void* buf, int len);
|
||||
HV_EXPORT int hssl_write(hssl_t ssl, const void* buf, int len);
|
||||
HV_EXPORT int hssl_close(hssl_t ssl);
|
||||
|
||||
HV_EXPORT int hssl_set_sni_hostname(hssl_t ssl, const char* hostname);
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
HV_EXPORT int hssl_ctx_set_alpn_protos(hssl_ctx_t ssl_ctx, const unsigned char* protos, unsigned int protos_len);
|
||||
#endif
|
||||
|
||||
END_EXTERN_C
|
||||
|
||||
#endif // HV_SSL_H_
|
||||
194
third_party/libhv/ssl/mbedtls.c
vendored
Executable file
194
third_party/libhv/ssl/mbedtls.c
vendored
Executable file
@@ -0,0 +1,194 @@
|
||||
#include "hssl.h"
|
||||
#include "hsocket.h"
|
||||
|
||||
#ifdef WITH_MBEDTLS
|
||||
|
||||
#include "mbedtls/version.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include "mbedtls/x509.h"
|
||||
#include "mbedtls/ssl.h"
|
||||
#include "mbedtls/net_sockets.h"
|
||||
#include "mbedtls/error.h"
|
||||
#include "mbedtls/debug.h"
|
||||
|
||||
#if defined(MBEDTLS_SSL_CACHE_C)
|
||||
#include "mbedtls/ssl_cache.h"
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
//#pragma comment(lib, "libmbedtls.a")
|
||||
//#pragma comment(lib, "libmbedx509.a")
|
||||
//#pragma comment(lib, "libmbedcrypto.a")
|
||||
#endif
|
||||
|
||||
const char* hssl_backend() {
|
||||
return "mbedtls";
|
||||
}
|
||||
|
||||
struct mbedtls_ctx {
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
mbedtls_ssl_config conf;
|
||||
mbedtls_x509_crt cert;
|
||||
mbedtls_pk_context pkey;
|
||||
#if defined(MBEDTLS_SSL_CACHE_C)
|
||||
mbedtls_ssl_cache_context cache;
|
||||
#endif
|
||||
};
|
||||
|
||||
hssl_ctx_t hssl_ctx_new(hssl_ctx_opt_t* param) {
|
||||
struct mbedtls_ctx* ctx = (struct mbedtls_ctx*)malloc(sizeof(struct mbedtls_ctx));
|
||||
if (ctx == NULL) return NULL;
|
||||
|
||||
mbedtls_ssl_config_init(&ctx->conf);
|
||||
#if defined(MBEDTLS_SSL_CACHE_C)
|
||||
mbedtls_ssl_cache_init(&ctx->cache);
|
||||
#endif
|
||||
mbedtls_x509_crt_init(&ctx->cert);
|
||||
mbedtls_pk_init(&ctx->pkey);
|
||||
mbedtls_entropy_init(&ctx->entropy);
|
||||
mbedtls_ctr_drbg_init(&ctx->ctr_drbg);
|
||||
|
||||
int mode = MBEDTLS_SSL_VERIFY_NONE;
|
||||
int endpoint = MBEDTLS_SSL_IS_CLIENT;
|
||||
bool check = false;
|
||||
if (param) {
|
||||
if (param->crt_file && *param->crt_file) {
|
||||
if (mbedtls_x509_crt_parse_file(&ctx->cert, param->crt_file) != 0) {
|
||||
fprintf(stderr, "ssl crt_file error!\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (param->key_file && *param->key_file) {
|
||||
#if MBEDTLS_VERSION_MAJOR >= 3
|
||||
if (mbedtls_pk_parse_keyfile(&ctx->pkey, param->key_file, NULL, NULL, NULL) != 0) {
|
||||
#else
|
||||
if (mbedtls_pk_parse_keyfile(&ctx->pkey, param->key_file, NULL) != 0) {
|
||||
#endif
|
||||
fprintf(stderr, "ssl key_file error!\n");
|
||||
goto error;
|
||||
}
|
||||
check = true;
|
||||
}
|
||||
if (param->verify_peer) {
|
||||
mode = MBEDTLS_SSL_VERIFY_REQUIRED;
|
||||
}
|
||||
if (param->endpoint == HSSL_SERVER) {
|
||||
endpoint = MBEDTLS_SSL_IS_SERVER;
|
||||
}
|
||||
}
|
||||
mbedtls_ctr_drbg_seed(&ctx->ctr_drbg, mbedtls_entropy_func, &ctx->entropy, NULL, 0);
|
||||
if (mbedtls_ssl_config_defaults(&ctx->conf, endpoint,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT) != 0) {
|
||||
fprintf(stderr, "ssl config error!\n");
|
||||
goto error;
|
||||
}
|
||||
mbedtls_ssl_conf_authmode(&ctx->conf, mode);
|
||||
mbedtls_ssl_conf_rng(&ctx->conf, mbedtls_ctr_drbg_random, &ctx->ctr_drbg);
|
||||
|
||||
#if defined(MBEDTLS_SSL_CACHE_C)
|
||||
mbedtls_ssl_conf_session_cache(&ctx->conf, &ctx->cache, mbedtls_ssl_cache_get, mbedtls_ssl_cache_set);
|
||||
#endif
|
||||
|
||||
if (check) {
|
||||
mbedtls_ssl_conf_ca_chain(&ctx->conf, ctx->cert.next, NULL);
|
||||
if (mbedtls_ssl_conf_own_cert(&ctx->conf, &ctx->cert, &ctx->pkey) != 0) {
|
||||
fprintf(stderr, "ssl key_file check failed!\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
return ctx;
|
||||
error:
|
||||
free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void hssl_ctx_free(hssl_ctx_t ssl_ctx) {
|
||||
if (!ssl_ctx) return;
|
||||
struct mbedtls_ctx *mctx = (struct mbedtls_ctx *)ssl_ctx;
|
||||
mbedtls_x509_crt_free(&mctx->cert);
|
||||
mbedtls_pk_free(&mctx->pkey);
|
||||
mbedtls_ssl_config_free(&mctx->conf);
|
||||
#if defined(MBEDTLS_SSL_CACHE_C)
|
||||
mbedtls_ssl_cache_free(&mctx->cache);
|
||||
#endif
|
||||
mbedtls_ctr_drbg_free(&mctx->ctr_drbg);
|
||||
mbedtls_entropy_free(&mctx->entropy);
|
||||
free(mctx);
|
||||
}
|
||||
|
||||
static int __mbedtls_net_send(void *ctx, const unsigned char *buf, size_t len) {
|
||||
int fd = (intptr_t)ctx;
|
||||
// int n = write(fd, buf, len);
|
||||
int n = send(fd, (char*)(buf), (int)(len), 0);
|
||||
if (n >= 0) return n;
|
||||
return ((socket_errno() == EAGAIN || socket_errno() == EINPROGRESS) ? MBEDTLS_ERR_SSL_WANT_WRITE : -1);
|
||||
}
|
||||
|
||||
static int __mbedtls_net_recv(void *ctx, unsigned char *buf, size_t len) {
|
||||
int fd = (intptr_t)ctx;
|
||||
// int n = read(fd, buf, len);
|
||||
int n = recv(fd, (char*)(buf), (int)(len), 0);
|
||||
if (n >= 0) return n;
|
||||
return ((socket_errno() == EAGAIN || socket_errno() == EINPROGRESS) ? MBEDTLS_ERR_SSL_WANT_READ : -1);
|
||||
}
|
||||
|
||||
hssl_t hssl_new(hssl_ctx_t ssl_ctx, int fd) {
|
||||
struct mbedtls_ctx* mctx = (struct mbedtls_ctx*)ssl_ctx;
|
||||
mbedtls_ssl_context* ssl = (mbedtls_ssl_context*)malloc(sizeof(mbedtls_ssl_context));
|
||||
if (ssl == NULL) return NULL;
|
||||
mbedtls_ssl_init(ssl);
|
||||
mbedtls_ssl_setup(ssl, &mctx->conf);
|
||||
mbedtls_ssl_set_bio(ssl, (void*)(intptr_t)fd, __mbedtls_net_send, __mbedtls_net_recv, NULL);
|
||||
return ssl;
|
||||
}
|
||||
|
||||
void hssl_free(hssl_t ssl) {
|
||||
if (ssl) {
|
||||
mbedtls_ssl_free(ssl);
|
||||
ssl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int hssl_handshake(hssl_t ssl) {
|
||||
int ret = mbedtls_ssl_handshake(ssl);
|
||||
if (ret != 0) {
|
||||
if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
|
||||
return HSSL_WANT_READ;
|
||||
}
|
||||
else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
return HSSL_WANT_WRITE;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int hssl_accept(hssl_t ssl) {
|
||||
return hssl_handshake(ssl);
|
||||
}
|
||||
|
||||
int hssl_connect(hssl_t ssl) {
|
||||
return hssl_handshake(ssl);
|
||||
}
|
||||
|
||||
int hssl_read(hssl_t ssl, void* buf, int len) {
|
||||
return mbedtls_ssl_read(ssl, buf, len);
|
||||
}
|
||||
|
||||
int hssl_write(hssl_t ssl, const void* buf, int len) {
|
||||
return mbedtls_ssl_write(ssl, buf, len);
|
||||
}
|
||||
|
||||
int hssl_close(hssl_t ssl) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hssl_set_sni_hostname(hssl_t ssl, const char* hostname) {
|
||||
#ifdef MBEDTLS_X509_CRT_PARSE_C
|
||||
mbedtls_ssl_set_hostname(ssl, hostname);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // WITH_MBEDTLS
|
||||
50
third_party/libhv/ssl/nossl.c
vendored
Executable file
50
third_party/libhv/ssl/nossl.c
vendored
Executable file
@@ -0,0 +1,50 @@
|
||||
#include "hssl.h"
|
||||
|
||||
#ifdef HV_WITHOUT_SSL
|
||||
|
||||
const char* hssl_backend() {
|
||||
return "nossl";
|
||||
}
|
||||
|
||||
hssl_ctx_t hssl_ctx_new(hssl_ctx_opt_t* opt) {
|
||||
fprintf(stderr, "Please recompile WITH_SSL.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void hssl_ctx_free(hssl_ctx_t ssl_ctx) {
|
||||
}
|
||||
|
||||
hssl_t hssl_new(hssl_ctx_t ssl_ctx, int fd) {
|
||||
return (void*)(intptr_t)fd;
|
||||
}
|
||||
|
||||
void hssl_free(hssl_t ssl) {
|
||||
}
|
||||
|
||||
int hssl_accept(hssl_t ssl) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hssl_connect(hssl_t ssl) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hssl_read(hssl_t ssl, void* buf, int len) {
|
||||
int fd = (intptr_t)ssl;
|
||||
return read(fd, buf, len);
|
||||
}
|
||||
|
||||
int hssl_write(hssl_t ssl, const void* buf, int len) {
|
||||
int fd = (intptr_t)ssl;
|
||||
return write(fd, buf, len);
|
||||
}
|
||||
|
||||
int hssl_close(hssl_t ssl) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hssl_set_sni_hostname(hssl_t ssl, const char* hostname) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // HV_WITHOUT_SSL
|
||||
188
third_party/libhv/ssl/openssl.c
vendored
Executable file
188
third_party/libhv/ssl/openssl.c
vendored
Executable file
@@ -0,0 +1,188 @@
|
||||
#include "hssl.h"
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
|
||||
#include "openssl/ssl.h"
|
||||
#include "openssl/err.h"
|
||||
#ifdef _MSC_VER
|
||||
//#pragma comment(lib, "libssl.a")
|
||||
//#pragma comment(lib, "libcrypto.a")
|
||||
#endif
|
||||
|
||||
const char* hssl_backend() {
|
||||
return "openssl";
|
||||
}
|
||||
|
||||
hssl_ctx_t hssl_ctx_new(hssl_ctx_opt_t* param) {
|
||||
static int s_initialized = 0;
|
||||
if (s_initialized == 0) {
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
#else
|
||||
OPENSSL_init_ssl(OPENSSL_INIT_SSL_DEFAULT, NULL);
|
||||
#endif
|
||||
s_initialized = 1;
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
SSL_CTX* ctx = SSL_CTX_new(SSLv23_method());
|
||||
#else
|
||||
SSL_CTX* ctx = SSL_CTX_new(TLS_method());
|
||||
#endif
|
||||
if (ctx == NULL) return NULL;
|
||||
int mode = SSL_VERIFY_NONE;
|
||||
const char* ca_file = NULL;
|
||||
const char* ca_path = NULL;
|
||||
if (param) {
|
||||
if (param->ca_file && *param->ca_file) {
|
||||
ca_file = param->ca_file;
|
||||
}
|
||||
if (param->ca_path && *param->ca_path) {
|
||||
ca_path = param->ca_path;
|
||||
}
|
||||
if (ca_file || ca_path) {
|
||||
if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path)) {
|
||||
fprintf(stderr, "ssl ca_file/ca_path failed!\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (param->crt_file && *param->crt_file) {
|
||||
if (!SSL_CTX_use_certificate_file(ctx, param->crt_file, SSL_FILETYPE_PEM)) {
|
||||
fprintf(stderr, "ssl crt_file error!\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (param->key_file && *param->key_file) {
|
||||
if (!SSL_CTX_use_PrivateKey_file(ctx, param->key_file, SSL_FILETYPE_PEM)) {
|
||||
fprintf(stderr, "ssl key_file error!\n");
|
||||
goto error;
|
||||
}
|
||||
if (!SSL_CTX_check_private_key(ctx)) {
|
||||
fprintf(stderr, "ssl key_file check failed!\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (param->verify_peer) {
|
||||
mode = SSL_VERIFY_PEER;
|
||||
if (param->endpoint == HSSL_SERVER) {
|
||||
mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mode == SSL_VERIFY_PEER && !ca_file && !ca_path) {
|
||||
SSL_CTX_set_default_verify_paths(ctx);
|
||||
}
|
||||
|
||||
#ifdef SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER
|
||||
SSL_CTX_set_mode(ctx, SSL_CTX_get_mode(ctx) | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||
#endif
|
||||
SSL_CTX_set_verify(ctx, mode, NULL);
|
||||
return ctx;
|
||||
error:
|
||||
SSL_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void hssl_ctx_free(hssl_ctx_t ssl_ctx) {
|
||||
if (!ssl_ctx) return;
|
||||
SSL_CTX_free((SSL_CTX*)ssl_ctx);
|
||||
}
|
||||
|
||||
hssl_t hssl_new(hssl_ctx_t ssl_ctx, int fd) {
|
||||
SSL* ssl = SSL_new((SSL_CTX*)ssl_ctx);
|
||||
if (ssl == NULL) return NULL;
|
||||
SSL_set_fd(ssl, fd);
|
||||
return ssl;
|
||||
}
|
||||
|
||||
void hssl_free(hssl_t ssl) {
|
||||
if (ssl) {
|
||||
SSL_free((SSL*)ssl);
|
||||
ssl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int hssl_accept(hssl_t ssl) {
|
||||
int ret = SSL_accept((SSL*)ssl);
|
||||
if (ret == 1) return 0;
|
||||
|
||||
int err = SSL_get_error((SSL*)ssl, ret);
|
||||
if (err == SSL_ERROR_WANT_READ) {
|
||||
return HSSL_WANT_READ;
|
||||
}
|
||||
else if (err == SSL_ERROR_WANT_WRITE) {
|
||||
return HSSL_WANT_WRITE;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int hssl_connect(hssl_t ssl) {
|
||||
int ret = SSL_connect((SSL*)ssl);
|
||||
if (ret == 1) return 0;
|
||||
|
||||
int err = SSL_get_error((SSL*)ssl, ret);
|
||||
if (err == SSL_ERROR_WANT_READ) {
|
||||
return HSSL_WANT_READ;
|
||||
}
|
||||
else if (err == SSL_ERROR_WANT_WRITE) {
|
||||
return HSSL_WANT_WRITE;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int hssl_read(hssl_t ssl, void* buf, int len) {
|
||||
return SSL_read((SSL*)ssl, buf, len);
|
||||
}
|
||||
|
||||
int hssl_write(hssl_t ssl, const void* buf, int len) {
|
||||
return SSL_write((SSL*)ssl, buf, len);
|
||||
}
|
||||
|
||||
int hssl_close(hssl_t ssl) {
|
||||
SSL_shutdown((SSL*)ssl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hssl_set_sni_hostname(hssl_t ssl, const char* hostname) {
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
SSL_set_tlsext_host_name((SSL*)ssl, hostname);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
|
||||
static int hssl_ctx_alpn_select_cb(SSL *ssl,
|
||||
const unsigned char **out, unsigned char *outlen,
|
||||
const unsigned char *in, unsigned int inlen,
|
||||
void *arg) {
|
||||
const unsigned char* protos = (unsigned char*)arg;
|
||||
unsigned int protos_len = strlen((char*)protos);
|
||||
// printf("hssl_ctx_alpn_select_cb(in=%*.s:%u out=%.*s:%u protos=%.*s:%u)\n", inlen, in, inlen, (int)*outlen, (char*)out, (int)*outlen, protos_len, protos, protos_len);
|
||||
if (SSL_select_next_proto((unsigned char **) out, outlen, protos, protos_len, in, inlen) != OPENSSL_NPN_NEGOTIATED) {
|
||||
fprintf(stderr, "SSL_select_next_proto failed!\n");
|
||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||
}
|
||||
// printf("SSL_select_next_proto(out=%.*s:%u)\n", (int)*outlen, (char*)*out, (int)*outlen);
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
int hssl_ctx_set_alpn_protos(hssl_ctx_t ssl_ctx, const unsigned char* protos, unsigned int protos_len) {
|
||||
int ret = -1;
|
||||
// printf("hssl_ctx_set_alpn_protos(%.*s:%u)\n", protos_len, protos, protos_len);
|
||||
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
|
||||
// for HSSL_CLIENT
|
||||
// ret = SSL_CTX_set_alpn_protos((SSL_CTX*)ssl_ctx, (const unsigned char*)protos, protos_len);
|
||||
|
||||
// for HSSL_SERVER
|
||||
SSL_CTX_set_alpn_select_cb((SSL_CTX*)ssl_ctx, hssl_ctx_alpn_select_cb, (void*)protos);
|
||||
ret = 0;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif // WITH_OPENSSL
|
||||
837
third_party/libhv/ssl/wintls.c
vendored
Executable file
837
third_party/libhv/ssl/wintls.c
vendored
Executable file
@@ -0,0 +1,837 @@
|
||||
#include "hssl.h"
|
||||
|
||||
#ifdef WITH_WINTLS
|
||||
|
||||
// #define PRINT_DEBUG
|
||||
// #define PRINT_ERROR
|
||||
#include "hdef.h"
|
||||
#include <schannel.h>
|
||||
#include <wincrypt.h>
|
||||
#include <windows.h>
|
||||
#include <wintrust.h>
|
||||
|
||||
#define SECURITY_WIN32
|
||||
#include <security.h>
|
||||
#include <sspi.h>
|
||||
|
||||
#define TLS_SOCKET_BUFFER_SIZE 17000
|
||||
|
||||
#ifndef SP_PROT_SSL2_SERVER
|
||||
#define SP_PROT_SSL2_SERVER 0x00000004
|
||||
#endif
|
||||
|
||||
#ifndef SP_PROT_SSL2_CLIENT
|
||||
#define SP_PROT_SSL2_CLIENT 0x00000008
|
||||
#endif
|
||||
|
||||
#ifndef SP_PROT_SSL3_SERVER
|
||||
#define SP_PROT_SSL3_SERVER 0x00000010
|
||||
#endif
|
||||
|
||||
#ifndef SP_PROT_SSL3_CLIENT
|
||||
#define SP_PROT_SSL3_CLIENT 0x00000020
|
||||
#endif
|
||||
|
||||
#ifndef SP_PROT_TLS1_SERVER
|
||||
#define SP_PROT_TLS1_SERVER 0x00000040
|
||||
#endif
|
||||
|
||||
#ifndef SP_PROT_TLS1_CLIENT
|
||||
#define SP_PROT_TLS1_CLIENT 0x00000080
|
||||
#endif
|
||||
|
||||
#ifndef SP_PROT_TLS1_0_SERVER
|
||||
#define SP_PROT_TLS1_0_SERVER SP_PROT_TLS1_SERVER
|
||||
#endif
|
||||
|
||||
#ifndef SP_PROT_TLS1_0_CLIENT
|
||||
#define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT
|
||||
#endif
|
||||
|
||||
#ifndef SP_PROT_TLS1_1_SERVER
|
||||
#define SP_PROT_TLS1_1_SERVER 0x00000100
|
||||
#endif
|
||||
|
||||
#ifndef SP_PROT_TLS1_1_CLIENT
|
||||
#define SP_PROT_TLS1_1_CLIENT 0x00000200
|
||||
#endif
|
||||
|
||||
#ifndef SP_PROT_TLS1_2_SERVER
|
||||
#define SP_PROT_TLS1_2_SERVER 0x00000400
|
||||
#endif
|
||||
|
||||
#ifndef SP_PROT_TLS1_2_CLIENT
|
||||
#define SP_PROT_TLS1_2_CLIENT 0x00000800
|
||||
#endif
|
||||
|
||||
#ifndef SP_PROT_TLS1_3_SERVER
|
||||
#define SP_PROT_TLS1_3_SERVER 0x00001000
|
||||
#endif
|
||||
|
||||
#ifndef SP_PROT_TLS1_3_CLIENT
|
||||
#define SP_PROT_TLS1_3_CLIENT 0x00002000
|
||||
#endif
|
||||
|
||||
#ifndef SCH_USE_STRONG_CRYPTO
|
||||
#define SCH_USE_STRONG_CRYPTO 0x00400000
|
||||
#endif
|
||||
|
||||
#ifndef SECBUFFER_ALERT
|
||||
#define SECBUFFER_ALERT 17
|
||||
#endif
|
||||
|
||||
const char* hssl_backend()
|
||||
{
|
||||
return "schannel";
|
||||
}
|
||||
|
||||
static PCCERT_CONTEXT getservercert(const char* path)
|
||||
{
|
||||
/*
|
||||
According to the information I searched from the internet, it is not possible to specify an x509 private key and certificate using the
|
||||
CertCreateCertificateContext interface. We must first export them as a pkcs#12 formatted file, and then import them into the Windows certificate store. This
|
||||
is because the Windows certificate store is an integrated system location that does not support the direct use of separate private key files and certificate
|
||||
files. The pkcs#12 format is a complex format that can store and protect keys and certificates. You can use the OpenSSL tool to combine the private key file
|
||||
and certificate file into a pkcs#12 formatted file, For example: OpenSSL pkcs12 -export -out cert.pfx -inkey private.key -in cert.cer Then, you can use the
|
||||
certutil tool or a graphical interface to import this file into the personal store of your local computer. After importing, you can use the
|
||||
CertFindCertificateInStore interface to create and manipulate certificate contexts.
|
||||
*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hssl_ctx_t hssl_ctx_new(hssl_ctx_opt_t* opt)
|
||||
{
|
||||
SECURITY_STATUS SecStatus;
|
||||
TimeStamp Lifetime;
|
||||
CredHandle* hCred = NULL;
|
||||
SCHANNEL_CRED credData = { 0 };
|
||||
TCHAR unisp_name[] = UNISP_NAME;
|
||||
unsigned long credflag;
|
||||
|
||||
if (opt && opt->endpoint == HSSL_SERVER) {
|
||||
PCCERT_CONTEXT serverCert = NULL; // server-side certificate
|
||||
#if 1 // create cert from store
|
||||
|
||||
//-------------------------------------------------------
|
||||
// Get the server certificate.
|
||||
//-------------------------------------------------------
|
||||
// Open the My store(personal store).
|
||||
HCERTSTORE hMyCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"MY");
|
||||
if (hMyCertStore == NULL) {
|
||||
printe("Error opening MY store for server.\n");
|
||||
return NULL;
|
||||
}
|
||||
//-------------------------------------------------------
|
||||
// Search for a certificate match its subject string to opt->crt_file.
|
||||
serverCert = CertFindCertificateInStore(hMyCertStore, X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR_A, opt->crt_file, NULL);
|
||||
CertCloseStore(hMyCertStore, 0);
|
||||
if (serverCert == NULL) {
|
||||
printe("Error retrieving server certificate. %x\n", GetLastError());
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
serverCert = getservercert(opt->ca_file);
|
||||
#endif
|
||||
credData.cCreds = 1; // 数量
|
||||
credData.paCred = &serverCert;
|
||||
// credData.dwCredFormat = SCH_CRED_FORMAT_CERT_HASH;
|
||||
credData.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_3_SERVER;
|
||||
credflag = SECPKG_CRED_INBOUND;
|
||||
} else {
|
||||
credData.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_3_CLIENT;
|
||||
credflag = SECPKG_CRED_OUTBOUND;
|
||||
}
|
||||
#if 0 // just use the system defalut algs
|
||||
ALG_ID rgbSupportedAlgs[4];
|
||||
rgbSupportedAlgs[0] = CALG_DH_EPHEM;
|
||||
rgbSupportedAlgs[1] = CALG_RSA_KEYX;
|
||||
rgbSupportedAlgs[2] = CALG_AES_128;
|
||||
rgbSupportedAlgs[3] = CALG_SHA_256;
|
||||
credData.cSupportedAlgs = 4;
|
||||
credData.palgSupportedAlgs = rgbSupportedAlgs;
|
||||
#endif
|
||||
credData.dwVersion = SCHANNEL_CRED_VERSION;
|
||||
// credData.dwFlags = SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_NO_SERVERNAME_CHECK | SCH_USE_STRONG_CRYPTO | SCH_CRED_MANUAL_CRED_VALIDATION | SCH_CRED_IGNORE_NO_REVOCATION_CHECK | SCH_CRED_IGNORE_REVOCATION_OFFLINE;
|
||||
// credData.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION | SCH_CRED_REVOCATION_CHECK_CHAIN | SCH_CRED_IGNORE_REVOCATION_OFFLINE;
|
||||
// credData.dwMinimumCipherStrength = -1;
|
||||
// credData.dwMaximumCipherStrength = -1;
|
||||
|
||||
//-------------------------------------------------------
|
||||
hCred = (CredHandle*)malloc(sizeof(CredHandle));
|
||||
if (hCred == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SecStatus = AcquireCredentialsHandle(NULL, unisp_name, credflag, NULL, &credData, NULL, NULL, hCred, &Lifetime);
|
||||
if (SecStatus == SEC_E_OK) {
|
||||
#ifndef NDEBUG
|
||||
SecPkgCred_SupportedAlgs algs;
|
||||
if (QueryCredentialsAttributesA(hCred, SECPKG_ATTR_SUPPORTED_ALGS, &algs) == SEC_E_OK) {
|
||||
for (int i = 0; i < algs.cSupportedAlgs; i++) {
|
||||
printd("alg: 0x%08x\n", algs.palgSupportedAlgs[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
printe("ERROR: AcquireCredentialsHandle: 0x%x\n", SecStatus);
|
||||
free(hCred);
|
||||
hCred = NULL;
|
||||
}
|
||||
return hCred;
|
||||
}
|
||||
|
||||
void hssl_ctx_free(hssl_ctx_t ssl_ctx)
|
||||
{
|
||||
SECURITY_STATUS sec_status = FreeCredentialsHandle(ssl_ctx);
|
||||
if (sec_status != SEC_E_OK) {
|
||||
printe("free_cred_handle FreeCredentialsHandle %d\n", sec_status);
|
||||
}
|
||||
}
|
||||
|
||||
static void init_sec_buffer(SecBuffer* secure_buffer, unsigned long type, unsigned long len, void* buffer)
|
||||
{
|
||||
secure_buffer->BufferType = type;
|
||||
secure_buffer->cbBuffer = len;
|
||||
secure_buffer->pvBuffer = buffer;
|
||||
}
|
||||
|
||||
static void init_sec_buffer_desc(SecBufferDesc* secure_buffer_desc, unsigned long version, unsigned long num_buffers, SecBuffer* buffers)
|
||||
{
|
||||
secure_buffer_desc->ulVersion = version;
|
||||
secure_buffer_desc->cBuffers = num_buffers;
|
||||
secure_buffer_desc->pBuffers = buffers;
|
||||
}
|
||||
|
||||
/* enum for the nonblocking SSL connection state machine */
|
||||
typedef enum {
|
||||
ssl_connect_1,
|
||||
ssl_connect_2,
|
||||
ssl_connect_2_reading,
|
||||
ssl_connect_2_writing,
|
||||
ssl_connect_3,
|
||||
ssl_connect_done
|
||||
} ssl_connect_state;
|
||||
|
||||
struct wintls_s {
|
||||
hssl_ctx_t ssl_ctx; // CredHandle
|
||||
int fd;
|
||||
union {
|
||||
ssl_connect_state state2;
|
||||
ssl_connect_state connecting_state;
|
||||
};
|
||||
SecHandle sechandle;
|
||||
SecPkgContext_StreamSizes stream_sizes_;
|
||||
size_t buffer_to_decrypt_offset_;
|
||||
size_t dec_len_;
|
||||
char encrypted_buffer_[TLS_SOCKET_BUFFER_SIZE];
|
||||
char buffer_to_decrypt_[TLS_SOCKET_BUFFER_SIZE];
|
||||
char decrypted_buffer_[TLS_SOCKET_BUFFER_SIZE + TLS_SOCKET_BUFFER_SIZE];
|
||||
char* sni;
|
||||
};
|
||||
|
||||
hssl_t hssl_new(hssl_ctx_t ssl_ctx, int fd)
|
||||
{
|
||||
struct wintls_s* ret = malloc(sizeof(*ret));
|
||||
if (ret) {
|
||||
memset(ret, 0, sizeof(*ret));
|
||||
ret->ssl_ctx = ssl_ctx;
|
||||
ret->fd = fd;
|
||||
ret->sechandle.dwLower = 0;
|
||||
ret->sechandle.dwUpper = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void hssl_free(hssl_t _ssl)
|
||||
{
|
||||
struct wintls_s* ssl = _ssl;
|
||||
SECURITY_STATUS sec_status = DeleteSecurityContext(&ssl->sechandle);
|
||||
if (sec_status != SEC_E_OK) {
|
||||
printe("hssl_free DeleteSecurityContext %d", sec_status);
|
||||
}
|
||||
if (ssl->sni) {
|
||||
free(ssl->sni);
|
||||
}
|
||||
free(ssl);
|
||||
}
|
||||
|
||||
static void free_all_buffers(SecBufferDesc* secure_buffer_desc)
|
||||
{
|
||||
for (unsigned long i = 0; i < secure_buffer_desc->cBuffers; ++i) {
|
||||
void* buffer = secure_buffer_desc->pBuffers[i].pvBuffer;
|
||||
if (buffer != NULL) {
|
||||
FreeContextBuffer(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int __sendwrapper(SOCKET fd, const char* buf, size_t len, int flags)
|
||||
{
|
||||
int left = len;
|
||||
int offset = 0;
|
||||
while (left > 0) {
|
||||
int bytes_sent = send(fd, buf + offset, left, flags);
|
||||
if (bytes_sent == 0 || (bytes_sent == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK && WSAGetLastError() != WSAEINTR)) {
|
||||
break;
|
||||
}
|
||||
if (bytes_sent > 0) {
|
||||
offset += bytes_sent;
|
||||
left -= bytes_sent;
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int __recvwrapper(SOCKET fd, char* buf, int len, int flags)
|
||||
{
|
||||
int ret = 0;
|
||||
do {
|
||||
ret = recv(fd, buf, len, flags);
|
||||
} while (ret == SOCKET_ERROR && WSAGetLastError() == WSAEINTR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int hssl_accept(hssl_t ssl)
|
||||
{
|
||||
int ret = HSSL_ERROR;
|
||||
struct wintls_s* winssl = ssl;
|
||||
bool authn_completed = false;
|
||||
|
||||
// Input buffer
|
||||
char buffer_in[TLS_SOCKET_BUFFER_SIZE];
|
||||
|
||||
SecBuffer secure_buffer_in[2] = { 0 };
|
||||
init_sec_buffer(&secure_buffer_in[0], SECBUFFER_TOKEN, TLS_SOCKET_BUFFER_SIZE, buffer_in);
|
||||
init_sec_buffer(&secure_buffer_in[1], SECBUFFER_EMPTY, 0, NULL);
|
||||
|
||||
SecBufferDesc secure_buffer_desc_in = { 0 };
|
||||
init_sec_buffer_desc(&secure_buffer_desc_in, SECBUFFER_VERSION, 2, secure_buffer_in);
|
||||
|
||||
// Output buffer
|
||||
SecBuffer secure_buffer_out[3] = { 0 };
|
||||
init_sec_buffer(&secure_buffer_out[0], SECBUFFER_TOKEN, 0, NULL);
|
||||
init_sec_buffer(&secure_buffer_out[1], SECBUFFER_ALERT, 0, NULL);
|
||||
init_sec_buffer(&secure_buffer_out[2], SECBUFFER_EMPTY, 0, NULL);
|
||||
|
||||
SecBufferDesc secure_buffer_desc_out = { 0 };
|
||||
init_sec_buffer_desc(&secure_buffer_desc_out, SECBUFFER_VERSION, 3, secure_buffer_out);
|
||||
|
||||
unsigned long context_requirements = ASC_REQ_ALLOCATE_MEMORY | ASC_REQ_CONFIDENTIALITY;
|
||||
|
||||
// We use ASC_REQ_ALLOCATE_MEMORY which means the buffers will be allocated for us, we need to make sure we free them.
|
||||
|
||||
ULONG context_attributes = 0;
|
||||
TimeStamp life_time = { 0 };
|
||||
|
||||
secure_buffer_in[0].cbBuffer = __recvwrapper(winssl->fd, (char*)secure_buffer_in[0].pvBuffer, TLS_SOCKET_BUFFER_SIZE, 0);
|
||||
// printd("%s recv %d %d\n", __func__, secure_buffer_in[0].cbBuffer, WSAGetLastError());
|
||||
if (secure_buffer_in[0].cbBuffer == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK) {
|
||||
ret = HSSL_WANT_READ;
|
||||
} else if (secure_buffer_in[0].cbBuffer > 0) {
|
||||
SECURITY_STATUS sec_status = AcceptSecurityContext(winssl->ssl_ctx, winssl->state2 == 0 ? NULL : &winssl->sechandle, &secure_buffer_desc_in,
|
||||
context_requirements, 0, &winssl->sechandle, &secure_buffer_desc_out, &context_attributes, &life_time);
|
||||
|
||||
winssl->state2 = 1;
|
||||
// printd("establish_server_security_context AcceptSecurityContext %x\n", sec_status);
|
||||
|
||||
if (secure_buffer_out[0].cbBuffer > 0) {
|
||||
int rc = __sendwrapper(winssl->fd, (const char*)secure_buffer_out[0].pvBuffer, secure_buffer_out[0].cbBuffer, 0);
|
||||
if (rc != secure_buffer_out[0].cbBuffer) {
|
||||
goto END;
|
||||
}
|
||||
}
|
||||
|
||||
switch (sec_status) {
|
||||
case SEC_E_OK:
|
||||
ret = HSSL_OK;
|
||||
authn_completed = true;
|
||||
break;
|
||||
case SEC_I_CONTINUE_NEEDED:
|
||||
ret = HSSL_WANT_READ;
|
||||
break;
|
||||
case SEC_I_COMPLETE_AND_CONTINUE:
|
||||
case SEC_I_COMPLETE_NEEDED: {
|
||||
SECURITY_STATUS complete_sec_status = SEC_E_OK;
|
||||
complete_sec_status = CompleteAuthToken(&winssl->sechandle, &secure_buffer_desc_out);
|
||||
if (complete_sec_status != SEC_E_OK) {
|
||||
printe("establish_server_security_context CompleteAuthToken %x\n", complete_sec_status);
|
||||
goto END;
|
||||
}
|
||||
|
||||
if (sec_status == SEC_I_COMPLETE_NEEDED) {
|
||||
authn_completed = true;
|
||||
ret = HSSL_OK;
|
||||
} else {
|
||||
ret = HSSL_WANT_READ;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
END:
|
||||
free_all_buffers(&secure_buffer_desc_out);
|
||||
|
||||
if (authn_completed) {
|
||||
SECURITY_STATUS sec_status = QueryContextAttributes(&winssl->sechandle, SECPKG_ATTR_STREAM_SIZES, &winssl->stream_sizes_);
|
||||
if (sec_status != SEC_E_OK) {
|
||||
printe("get_stream_sizes QueryContextAttributes %d\n", sec_status);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int schannel_connect_step1(struct wintls_s* ssl)
|
||||
{
|
||||
int ret = 0;
|
||||
ULONG context_attributes = 0;
|
||||
unsigned long context_requirements = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM;
|
||||
|
||||
TimeStamp life_time = { 0 };
|
||||
|
||||
SecBuffer secure_buffer_out[1] = { 0 };
|
||||
init_sec_buffer(&secure_buffer_out[0], SECBUFFER_EMPTY, 0, NULL);
|
||||
|
||||
SecBufferDesc secure_buffer_desc_out = { 0 };
|
||||
init_sec_buffer_desc(&secure_buffer_desc_out, SECBUFFER_VERSION, 1, secure_buffer_out);
|
||||
|
||||
SECURITY_STATUS sec_status = InitializeSecurityContext(ssl->ssl_ctx, NULL, ssl->sni, context_requirements, 0, 0, NULL, 0, &ssl->sechandle,
|
||||
&secure_buffer_desc_out, &context_attributes, &life_time);
|
||||
|
||||
if (sec_status != SEC_I_CONTINUE_NEEDED) {
|
||||
printe("1InitializeSecurityContext: %x\n", sec_status);
|
||||
}
|
||||
|
||||
if (secure_buffer_out[0].cbBuffer > 0) {
|
||||
int rc = __sendwrapper(ssl->fd, (const char*)secure_buffer_out[0].pvBuffer, secure_buffer_out[0].cbBuffer, 0);
|
||||
if (rc != secure_buffer_out[0].cbBuffer) {
|
||||
// TODO: Handle the error
|
||||
printe("%s :send failed\n", __func__);
|
||||
ret = -1;
|
||||
} else {
|
||||
printd("%s :send len=%d\n", __func__, rc);
|
||||
ssl->connecting_state = ssl_connect_2;
|
||||
}
|
||||
}
|
||||
free_all_buffers(&secure_buffer_desc_out);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int schannel_connect_step2(struct wintls_s* ssl)
|
||||
{
|
||||
int ret = HSSL_ERROR;
|
||||
ULONG context_attributes = 0;
|
||||
bool verify_server_cert = 0;
|
||||
|
||||
unsigned long context_requirements = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM;
|
||||
if (!verify_server_cert) {
|
||||
context_requirements |= ISC_REQ_MANUAL_CRED_VALIDATION;
|
||||
}
|
||||
|
||||
TimeStamp life_time = { 0 };
|
||||
|
||||
// Allocate a temporary buffer for input
|
||||
char* buffer_in = malloc(TLS_SOCKET_BUFFER_SIZE);
|
||||
if (buffer_in == NULL) {
|
||||
printe("schannel_connect_step2: Memory allocation failed\n");
|
||||
return HSSL_ERROR;
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
bool skip_recv = false;
|
||||
bool authn_complete = false;
|
||||
while (!authn_complete) {
|
||||
int in_buffer_size = 0;
|
||||
|
||||
if (!skip_recv) {
|
||||
int received = __recvwrapper(ssl->fd, buffer_in + offset, TLS_SOCKET_BUFFER_SIZE, 0);
|
||||
if (received == SOCKET_ERROR) {
|
||||
if (WSAGetLastError() == WSAEWOULDBLOCK) {
|
||||
ret = HSSL_WANT_READ;
|
||||
} else {
|
||||
printe("schannel_connect_step2: Receive failed\n");
|
||||
}
|
||||
break;
|
||||
} else if (received == 0) {
|
||||
printe("schannel_connect_step2: peer closed\n");
|
||||
break;
|
||||
}
|
||||
in_buffer_size = received + offset;
|
||||
} else {
|
||||
in_buffer_size = offset;
|
||||
}
|
||||
|
||||
skip_recv = false;
|
||||
offset = 0;
|
||||
|
||||
// Input buffer
|
||||
SecBuffer secure_buffer_in[4] = { 0 };
|
||||
init_sec_buffer(&secure_buffer_in[0], SECBUFFER_TOKEN, in_buffer_size, buffer_in);
|
||||
init_sec_buffer(&secure_buffer_in[1], SECBUFFER_EMPTY, 0, NULL);
|
||||
|
||||
SecBufferDesc secure_buffer_desc_in = { 0 };
|
||||
init_sec_buffer_desc(&secure_buffer_desc_in, SECBUFFER_VERSION, 2, secure_buffer_in);
|
||||
|
||||
// Output buffer
|
||||
SecBuffer secure_buffer_out[3] = { 0 };
|
||||
init_sec_buffer(&secure_buffer_out[0], SECBUFFER_TOKEN, 0, NULL);
|
||||
init_sec_buffer(&secure_buffer_out[1], SECBUFFER_ALERT, 0, NULL);
|
||||
init_sec_buffer(&secure_buffer_out[2], SECBUFFER_EMPTY, 0, NULL);
|
||||
|
||||
SecBufferDesc secure_buffer_desc_out = { 0 };
|
||||
init_sec_buffer_desc(&secure_buffer_desc_out, SECBUFFER_VERSION, 3, secure_buffer_out);
|
||||
printd("h2:%d\n", in_buffer_size);
|
||||
SECURITY_STATUS sec_status = InitializeSecurityContext(ssl->ssl_ctx, &ssl->sechandle, ssl->sni, context_requirements, 0, 0, &secure_buffer_desc_in, 0,
|
||||
&ssl->sechandle, &secure_buffer_desc_out, &context_attributes, &life_time);
|
||||
|
||||
printd("h2 0x%x inbuf[1] type=%d %d inbuf[0]=%d\n", sec_status, secure_buffer_in[1].BufferType, secure_buffer_in[1].cbBuffer, secure_buffer_in[0].cbBuffer);
|
||||
if (sec_status == SEC_E_OK || sec_status == SEC_I_CONTINUE_NEEDED) {
|
||||
// for (size_t i = 0; i < 3; i++) {
|
||||
// printd("obuf[%zu] type=%d %d\n", i, secure_buffer_out[i].BufferType, secure_buffer_out[i].cbBuffer);
|
||||
// }
|
||||
if (secure_buffer_out[0].cbBuffer > 0) {
|
||||
int rc = __sendwrapper(ssl->fd, (const char*)secure_buffer_out[0].pvBuffer, secure_buffer_out[0].cbBuffer, 0);
|
||||
if (rc != secure_buffer_out[0].cbBuffer) {
|
||||
printe("schannel_connect_step2: Send failed\n");
|
||||
// TODO: Handle the error
|
||||
break;
|
||||
}
|
||||
// printd("%s :send ok\n", __func__);
|
||||
}
|
||||
|
||||
if (sec_status == SEC_I_CONTINUE_NEEDED) {
|
||||
if (secure_buffer_in[1].BufferType == SECBUFFER_EXTRA && secure_buffer_in[1].cbBuffer > 0) {
|
||||
offset = secure_buffer_in[0].cbBuffer - secure_buffer_in[1].cbBuffer;
|
||||
memmove(buffer_in, buffer_in + offset, secure_buffer_in[1].cbBuffer);
|
||||
offset = secure_buffer_in[1].cbBuffer;
|
||||
skip_recv = true;
|
||||
}
|
||||
} else if (sec_status == SEC_E_OK) {
|
||||
authn_complete = true;
|
||||
ret = HSSL_OK;
|
||||
ssl->connecting_state = ssl_connect_3;
|
||||
}
|
||||
} else if (sec_status == SEC_E_INCOMPLETE_MESSAGE) {
|
||||
offset = secure_buffer_in[0].cbBuffer;
|
||||
} else {
|
||||
printe("2InitializeSecurityContext: 0x%x\n", sec_status);
|
||||
break;
|
||||
}
|
||||
|
||||
free_all_buffers(&secure_buffer_desc_out);
|
||||
}
|
||||
// END:
|
||||
free(buffer_in); // Free the temporary buffer
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dumpconninfo(SecHandle* sechandle)
|
||||
{
|
||||
SECURITY_STATUS Status;
|
||||
SecPkgContext_ConnectionInfo ConnectionInfo;
|
||||
|
||||
Status = QueryContextAttributes(sechandle,
|
||||
SECPKG_ATTR_CONNECTION_INFO,
|
||||
(PVOID)&ConnectionInfo);
|
||||
if (Status != SEC_E_OK) {
|
||||
printe("Error 0x%x querying connection info\n", Status);
|
||||
return;
|
||||
}
|
||||
|
||||
printd("\n");
|
||||
|
||||
switch (ConnectionInfo.dwProtocol) {
|
||||
case SP_PROT_TLS1_CLIENT:
|
||||
printd("Protocol: TLS1\n");
|
||||
break;
|
||||
|
||||
case SP_PROT_SSL3_CLIENT:
|
||||
printd("Protocol: SSL3\n");
|
||||
break;
|
||||
|
||||
case SP_PROT_SSL2_CLIENT:
|
||||
printd("Protocol: SSL2\n");
|
||||
break;
|
||||
|
||||
case SP_PROT_PCT1_CLIENT:
|
||||
printd("Protocol: PCT\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
printd("Protocol: 0x%x\n", ConnectionInfo.dwProtocol);
|
||||
}
|
||||
|
||||
switch (ConnectionInfo.aiCipher) {
|
||||
case CALG_RC4:
|
||||
printd("Cipher: RC4\n");
|
||||
break;
|
||||
|
||||
case CALG_3DES:
|
||||
printd("Cipher: Triple DES\n");
|
||||
break;
|
||||
|
||||
case CALG_RC2:
|
||||
printd("Cipher: RC2\n");
|
||||
break;
|
||||
|
||||
case CALG_DES:
|
||||
case CALG_CYLINK_MEK:
|
||||
printd("Cipher: DES\n");
|
||||
break;
|
||||
|
||||
case CALG_SKIPJACK:
|
||||
printd("Cipher: Skipjack\n");
|
||||
break;
|
||||
|
||||
case CALG_AES_128:
|
||||
printd("Cipher: aes128\n");
|
||||
break;
|
||||
default:
|
||||
printd("Cipher: 0x%x\n", ConnectionInfo.aiCipher);
|
||||
}
|
||||
|
||||
printd("Cipher strength: %d\n", ConnectionInfo.dwCipherStrength);
|
||||
|
||||
switch (ConnectionInfo.aiHash) {
|
||||
case CALG_MD5:
|
||||
printd("Hash: MD5\n");
|
||||
break;
|
||||
|
||||
case CALG_SHA:
|
||||
printd("Hash: SHA\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
printd("Hash: 0x%x\n", ConnectionInfo.aiHash);
|
||||
}
|
||||
|
||||
printd("Hash strength: %d\n", ConnectionInfo.dwHashStrength);
|
||||
|
||||
switch (ConnectionInfo.aiExch) {
|
||||
case CALG_RSA_KEYX:
|
||||
case CALG_RSA_SIGN:
|
||||
printd("Key exchange: RSA\n");
|
||||
break;
|
||||
|
||||
case CALG_KEA_KEYX:
|
||||
printd("Key exchange: KEA\n");
|
||||
break;
|
||||
|
||||
case CALG_DH_EPHEM:
|
||||
printd("Key exchange: DH Ephemeral\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
printd("Key exchange: 0x%x\n", ConnectionInfo.aiExch);
|
||||
}
|
||||
|
||||
printd("Key exchange strength: %d\n", ConnectionInfo.dwExchStrength);
|
||||
}
|
||||
|
||||
int hssl_connect(hssl_t _ssl)
|
||||
{
|
||||
int ret = 0;
|
||||
struct wintls_s* ssl = _ssl;
|
||||
if (ssl->connecting_state == ssl_connect_1) {
|
||||
ret = schannel_connect_step1(ssl);
|
||||
}
|
||||
if (!ret && ssl->connecting_state == ssl_connect_2) {
|
||||
ret = schannel_connect_step2(ssl);
|
||||
}
|
||||
// printd("%s %x\n", __func__, ret);
|
||||
if (!ret) {
|
||||
if (ssl->connecting_state == ssl_connect_3) {
|
||||
// ret = schannel_connect_step3(ssl);
|
||||
}
|
||||
SECURITY_STATUS sec_status = QueryContextAttributes(&ssl->sechandle, SECPKG_ATTR_STREAM_SIZES, &ssl->stream_sizes_);
|
||||
if (sec_status != SEC_E_OK) {
|
||||
printe("get_stream_sizes QueryContextAttributes %d\n", sec_status);
|
||||
} else {
|
||||
printd("stream_sizes bs:%d h:%d t:%d max:%d bfs:%d\n", ssl->stream_sizes_.cbBlockSize, ssl->stream_sizes_.cbHeader, ssl->stream_sizes_.cbTrailer, ssl->stream_sizes_.cbMaximumMessage, ssl->stream_sizes_.cBuffers);
|
||||
}
|
||||
dumpconninfo(&ssl->sechandle);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int decrypt_message(SecHandle security_context, unsigned long* extra, char* in_buf, int in_len, char* out_buf, int out_len)
|
||||
{
|
||||
printd("%s: inlen=%d\n", __func__, in_len);
|
||||
// Initialize the secure buffers
|
||||
SecBuffer secure_buffers[4] = { 0 };
|
||||
init_sec_buffer(&secure_buffers[0], SECBUFFER_DATA, in_len, in_buf);
|
||||
init_sec_buffer(&secure_buffers[1], SECBUFFER_EMPTY, 0, NULL);
|
||||
init_sec_buffer(&secure_buffers[2], SECBUFFER_EMPTY, 0, NULL);
|
||||
init_sec_buffer(&secure_buffers[3], SECBUFFER_EMPTY, 0, NULL);
|
||||
|
||||
// Initialize the secure buffer descriptor
|
||||
SecBufferDesc secure_buffer_desc = { 0 };
|
||||
init_sec_buffer_desc(&secure_buffer_desc, SECBUFFER_VERSION, 4, secure_buffers);
|
||||
|
||||
// Decrypt the message using the security context
|
||||
SECURITY_STATUS sec_status = DecryptMessage(&security_context, &secure_buffer_desc, 0, NULL);
|
||||
|
||||
for (size_t i = 1; i < 4; i++) {
|
||||
printd("%d: %u %u\n", i, secure_buffers[i].BufferType, secure_buffers[i].cbBuffer);
|
||||
}
|
||||
if (sec_status == SEC_E_INCOMPLETE_MESSAGE) {
|
||||
printe("decrypt_message SEC_E_INCOMPLETE_MESSAGE\n");
|
||||
return -1;
|
||||
} else if (sec_status == SEC_E_DECRYPT_FAILURE) {
|
||||
printe("decrypt_message ignore SEC_E_DECRYPT_FAILURE\n");
|
||||
return 0;
|
||||
} else if (sec_status == SEC_E_UNSUPPORTED_FUNCTION) {
|
||||
printe("decrypt_message ignore SEC_E_UNSUPPORTED_FUNCTION\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sec_status != SEC_E_OK) {
|
||||
printe("decrypt_message DecryptMessage: 0x%x\n", sec_status);
|
||||
return -1;
|
||||
}
|
||||
if (secure_buffers[3].BufferType == SECBUFFER_EXTRA && secure_buffers[3].cbBuffer > 0) {
|
||||
*extra = secure_buffers[3].cbBuffer;
|
||||
}
|
||||
memcpy(out_buf, secure_buffers[1].pvBuffer, secure_buffers[1].cbBuffer);
|
||||
// printd("ob:%s\n", out_buf);
|
||||
return secure_buffers[1].cbBuffer;
|
||||
}
|
||||
|
||||
int hssl_read(hssl_t _ssl, void* buf, int len)
|
||||
{
|
||||
struct wintls_s* ssl = _ssl;
|
||||
printd("%s: dec_len_= %zu\n", __func__, ssl->dec_len_);
|
||||
if (ssl->dec_len_ > 0) {
|
||||
if (buf == NULL) {
|
||||
return 0;
|
||||
}
|
||||
int decrypted = MIN(ssl->dec_len_, len);
|
||||
memcpy(buf, ssl->decrypted_buffer_, (size_t)decrypted);
|
||||
ssl->dec_len_ -= decrypted;
|
||||
if (ssl->dec_len_) {
|
||||
memmove(ssl->decrypted_buffer_, ssl->decrypted_buffer_ + decrypted, (size_t)ssl->dec_len_);
|
||||
} else {
|
||||
// hssl_read(_ssl, NULL, 0);
|
||||
}
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
// We might have leftovers, an incomplete message from a previous call.
|
||||
// Calculate the available buffer length for tcp recv.
|
||||
int recv_max_len = TLS_SOCKET_BUFFER_SIZE - ssl->buffer_to_decrypt_offset_;
|
||||
int bytes_received = __recvwrapper(ssl->fd, ssl->buffer_to_decrypt_ + ssl->buffer_to_decrypt_offset_, recv_max_len, 0);
|
||||
// printd("%s recv %d %d\n", __func__, bytes_received, WSAGetLastError());
|
||||
if (bytes_received == SOCKET_ERROR) {
|
||||
if (WSAGetLastError() == WSAEWOULDBLOCK) {
|
||||
bytes_received = 0;
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else if (bytes_received == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int encrypted_buffer_len = ssl->buffer_to_decrypt_offset_ + bytes_received;
|
||||
ssl->buffer_to_decrypt_offset_ = 0;
|
||||
while (true) {
|
||||
// printd("%s:buffer_to_decrypt_offset_ = %d , encrypted_buffer_len= %d\n", __func__, ssl->buffer_to_decrypt_offset_, encrypted_buffer_len);
|
||||
if (ssl->buffer_to_decrypt_offset_ >= encrypted_buffer_len) {
|
||||
// Reached the encrypted buffer length, we decrypted everything so we can stop.
|
||||
break;
|
||||
}
|
||||
unsigned long extra = 0;
|
||||
int decrypted_len = decrypt_message(ssl->sechandle, &extra, ssl->buffer_to_decrypt_ + ssl->buffer_to_decrypt_offset_,
|
||||
encrypted_buffer_len - ssl->buffer_to_decrypt_offset_, ssl->decrypted_buffer_ + ssl->dec_len_,
|
||||
TLS_SOCKET_BUFFER_SIZE + TLS_SOCKET_BUFFER_SIZE - ssl->dec_len_);
|
||||
|
||||
if (decrypted_len == -1) {
|
||||
// Incomplete message, we shuold keep it so it will be decrypted on the next call to recv().
|
||||
// Shift the remaining buffer to the beginning and break the loop.
|
||||
|
||||
memmove(ssl->buffer_to_decrypt_, ssl->buffer_to_decrypt_ + ssl->buffer_to_decrypt_offset_, encrypted_buffer_len - ssl->buffer_to_decrypt_offset_);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
ssl->dec_len_ += decrypted_len;
|
||||
ssl->buffer_to_decrypt_offset_ = encrypted_buffer_len - extra;
|
||||
}
|
||||
ssl->buffer_to_decrypt_offset_ = encrypted_buffer_len - ssl->buffer_to_decrypt_offset_;
|
||||
return hssl_read(_ssl, buf, len);
|
||||
}
|
||||
|
||||
int hssl_write(hssl_t _ssl, const void* buf, int len)
|
||||
{
|
||||
struct wintls_s* ssl = _ssl;
|
||||
SecPkgContext_StreamSizes* stream_sizes = &ssl->stream_sizes_;
|
||||
if (len > (int)stream_sizes->cbMaximumMessage) {
|
||||
len = stream_sizes->cbMaximumMessage;
|
||||
}
|
||||
|
||||
// Calculate the minimum output buffer length
|
||||
int min_out_len = stream_sizes->cbHeader + len + stream_sizes->cbTrailer;
|
||||
if (min_out_len > TLS_SOCKET_BUFFER_SIZE) {
|
||||
printe("encrypt_message: Output buffer is too small");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Initialize the secure buffers
|
||||
SecBuffer secure_buffers[4] = { 0 };
|
||||
init_sec_buffer(&secure_buffers[0], SECBUFFER_STREAM_HEADER, stream_sizes->cbHeader, ssl->encrypted_buffer_);
|
||||
init_sec_buffer(&secure_buffers[1], SECBUFFER_DATA, len, ssl->encrypted_buffer_ + stream_sizes->cbHeader);
|
||||
init_sec_buffer(&secure_buffers[2], SECBUFFER_STREAM_TRAILER, stream_sizes->cbTrailer, ssl->encrypted_buffer_ + stream_sizes->cbHeader + len);
|
||||
init_sec_buffer(&secure_buffers[3], SECBUFFER_EMPTY, 0, NULL);
|
||||
|
||||
// Initialize the secure buffer descriptor
|
||||
SecBufferDesc secure_buffer_desc = { 0 };
|
||||
init_sec_buffer_desc(&secure_buffer_desc, SECBUFFER_VERSION, 4, secure_buffers);
|
||||
|
||||
// Copy the input buffer to the data buffer
|
||||
memcpy(secure_buffers[1].pvBuffer, buf, len);
|
||||
|
||||
// Encrypt the message using the security context
|
||||
SECURITY_STATUS sec_status = EncryptMessage(&ssl->sechandle, 0, &secure_buffer_desc, 0);
|
||||
|
||||
// Check the encryption status and the data buffer length
|
||||
if (sec_status != SEC_E_OK) {
|
||||
printe("encrypt_message EncryptMessage %d\n", sec_status);
|
||||
return -1;
|
||||
}
|
||||
if (secure_buffers[1].cbBuffer > (unsigned int)len) {
|
||||
printe("encrypt_message: Data buffer is too large\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Adjust the minimum output buffer length
|
||||
min_out_len = secure_buffers[0].cbBuffer + secure_buffers[1].cbBuffer + secure_buffers[2].cbBuffer;
|
||||
printd("enc02: %d %d\n", secure_buffers[0].cbBuffer, secure_buffers[2].cbBuffer);
|
||||
|
||||
// Send the encrypted message to the socket
|
||||
int offset = __sendwrapper(ssl->fd, ssl->encrypted_buffer_, min_out_len, 0);
|
||||
// Check the send result
|
||||
if (offset != min_out_len) {
|
||||
printe("hssl_write: Send failed\n");
|
||||
return -1;
|
||||
} else {
|
||||
printd("hssl_write: Send %d\n", min_out_len);
|
||||
}
|
||||
|
||||
// Return the number of bytes sent excluding the header and trailer
|
||||
return offset - secure_buffers[0].cbBuffer - secure_buffers[2].cbBuffer;
|
||||
}
|
||||
|
||||
int hssl_close(hssl_t _ssl)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hssl_set_sni_hostname(hssl_t _ssl, const char* hostname)
|
||||
{
|
||||
struct wintls_s* ssl = _ssl;
|
||||
ssl->sni = strdup(hostname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // WITH_WINTLS
|
||||
Reference in New Issue
Block a user