c732d49e |
#if HAVE_CRT
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#endif //HAVE_CRT
/*
* Copyright (C) 2017, University of the Basque Country (UPV/EHU)
* Contact for licensing options: <licensing-mcpttclient(at)mcopenplatform(dot)com>
*
* The original file was part of Open Source Doubango Framework
* Copyright (C) 2010-2011 Mamadou Diop.
* Copyright (C) 2012 Doubango Telecom <http://doubango.org>
*
* This file is part of Open Source Doubango Framework.
*
* DOUBANGO is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* DOUBANGO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with DOUBANGO.
*
*/
/**@file tnet_dtls.c
* @brief DTLS utilitity functions, based on openssl.
*/
#include "tnet_dtls.h"
#include "tnet_tls.h"
#include "tnet_utils.h"
#include "tsk_object.h"
#include "tsk_string.h"
#include "tsk_memory.h"
#include "tsk_time.h"
#include "tsk_safeobj.h"
#include "tsk_debug.h"
typedef struct tnet_dtls_socket_s
{
TSK_DECLARE_OBJECT;
struct tnet_socket_s* wrapped_sock; /* not owner: do not try to close */
tsk_bool_t verify_peer;
tsk_bool_t use_srtp;
tsk_bool_t handshake_completed;
tsk_bool_t handshake_started;
tsk_bool_t handshake_storedata; // whether to store handshaking data or to send it to the remote party
tnet_dtls_setup_t setup;
struct {
void* ptr;
tsk_size_t size;
tsk_size_t count;
} handshake_data;
struct{
const void* usrdata;
tnet_dtls_socket_cb_f func;
} cb;
struct{
tnet_fingerprint_t fp;
tnet_dtls_hash_type_t hash;
struct sockaddr_storage addr;
} remote;
struct{
tnet_fingerprint_t fp;
tnet_dtls_hash_type_t hash;
} local;
#if HAVE_OPENSSL
SSL *ssl;
BIO* rbio;
BIO* wbio;
#endif
TSK_DECLARE_SAFEOBJ;
}
tnet_dtls_socket_t;
#define _tnet_dtls_socket_do_handshake(self) tnet_dtls_socket_do_handshake(self, tsk_null)
#define _tnet_dtls_socket_raise_event(self, type, data, size) ((self) && (self)->cb.func ? (self)->cb.func((self)->cb.usrdata, (type), (self), (data), (size)) : 0)
#define _tnet_dtls_socket_raise_event_dataless(self, type) _tnet_dtls_socket_raise_event((self), (type), tsk_null, 0)
tsk_bool_t tnet_dtls_is_srtp_supported()
{
#if HAVE_OPENSSL_DTLS_SRTP
return tsk_true;
#else
return tsk_false;
#endif
}
tsk_bool_t tnet_dtls_is_supported()
{
#if HAVE_OPENSSL_DTLS
return tsk_true;
#else
return tsk_false;
#endif
}
#if HAVE_OPENSSL
static tsk_bool_t _tnet_dtls_is_fingerprint_matching(X509* cert, tnet_fingerprint_t* fingerprint, tnet_dtls_hash_type_t hash);
static int _tnet_dtls_verify_cert(int preverify_ok, X509_STORE_CTX *ctx)
{
SSL *ssl;
tnet_dtls_socket_t* socket;
TSK_DEBUG_INFO("_tnet_dtls_verify_cert");
ssl = X509_STORE_CTX_get_app_data(ctx);
socket = (tnet_dtls_socket_t*)SSL_get_app_data(ssl);
if (!ssl || !socket){
TSK_DEBUG_ERROR("Not expected");
return 0;
}
tsk_safeobj_lock(socket);
if (_tnet_dtls_is_fingerprint_matching(ctx->cert, &socket->remote.fp, socket->remote.hash) == tsk_false) {
TSK_DEBUG_ERROR("Failed to match fingerprint");
tsk_safeobj_unlock(socket);
return 0;
}
tsk_safeobj_unlock(socket);
return 1;
}
static const EVP_MD *_tnet_dtls_get_hash_evp(tnet_dtls_hash_type_t hash)
{
switch (hash){
case tnet_dtls_hash_type_md5: return EVP_md5();
case tnet_dtls_hash_type_sha1: return EVP_sha1();
case tnet_dtls_hash_type_sha256: return EVP_sha256();
case tnet_dtls_hash_type_sha512: return EVP_sha512();
default: TSK_DEBUG_ERROR("Invalid parameter: %d not valid as hash type", hash); return tsk_null;
}
}
static int _tnet_dtls_get_fingerprint(X509* cert, const EVP_MD *evp, tnet_fingerprint_t* fingerprint)
{
if (!cert || !evp || !fingerprint){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
else{
unsigned len = 0, i, j;
tnet_fingerprint_t fp;
if (X509_digest(cert, evp, fp, &len) != 1 || len <= 0){
TSK_DEBUG_ERROR("X509_digest() failed [%s]", ERR_error_string(ERR_get_error(), tsk_null));
return -2;
}
for (i = 0, j = 0; i < len; ++i, j += 3){
sprintf((char*)&(*fingerprint)[j], (i == (len - 1)) ? "%.2X" : "%.2X:", fp[i]);
}
(*fingerprint)[len * 3] = '\0';
return 0;
}
}
static tsk_bool_t _tnet_dtls_is_fingerprint_matching(X509* cert, tnet_fingerprint_t* fingerprint, tnet_dtls_hash_type_t hash)
{
const EVP_MD* evp;
tnet_fingerprint_t fp;
int ret;
if (!cert || !fingerprint){
TSK_DEBUG_ERROR("Invalid parameter");
return tsk_false;
}
if (!(evp = _tnet_dtls_get_hash_evp(hash))){
return tsk_false;
}
if ((ret = _tnet_dtls_get_fingerprint(cert, evp, &fp))){
return tsk_false;
}
if (!tsk_striequals(fp, fingerprint)){
TSK_DEBUG_ERROR("DTLS certificate fingerprints mismatch: [%s]#[%s]", fp, *fingerprint);
return tsk_false;
}
return tsk_true;
}
static tsk_bool_t _tnet_dtls_socket_is_remote_cert_fp_match(tnet_dtls_socket_t* socket)
{
if (!socket){
TSK_DEBUG_ERROR("Invalid parameter");
return tsk_false;
}
else if (socket->verify_peer){
X509* cert;
if (!(cert = SSL_get_peer_certificate(socket->ssl))){
if (socket->verify_peer){ // print error only if verify certs is enabled
TSK_DEBUG_ERROR("Failed to get peer certificate [%s]", ERR_error_string(ERR_get_error(), tsk_null));
}
return tsk_false;
}
if (!_tnet_dtls_is_fingerprint_matching(cert, &socket->remote.fp, socket->remote.hash)){
X509_free(cert);
return tsk_false;
}
X509_free(cert);
if (SSL_get_verify_result(socket->ssl) != X509_V_OK){
TSK_DEBUG_ERROR("SSL_get_verify_result()#X509_V_OK [%s]", ERR_error_string(ERR_get_error(), tsk_null));
return tsk_false;
}
}
return tsk_true;
}
#endif /* HAVE_OPENSSL */
tnet_dtls_hash_type_t tnet_dtls_get_hash_from_string(const char* hash)
{
if (hash){
int32_t i;
for (i = 0; i < TNET_DTLS_HASH_TYPE_MAX; ++i){
if (tsk_striequals(TNET_DTLS_HASH_NAMES[i], hash)){
return (tnet_dtls_hash_type_t)i;
}
}
}
return tnet_dtls_hash_type_none;
}
tnet_dtls_setup_t tnet_dtls_get_setup_from_string(const char* setup)
{
if (setup){
int32_t i;
for (i = 0; i < TNET_DTLS_SETUP_MAX; ++i){
if (tsk_striequals(TNET_DTLS_SETUP_NAMES[i], setup)){
return (tnet_dtls_setup_t)i;
}
}
}
return tnet_dtls_setup_none;
}
int tnet_dtls_get_fingerprint(const char* certfile, tnet_fingerprint_t* fingerprint, tnet_dtls_hash_type_t hash)
{
#if !HAVE_OPENSSL || !HAVE_OPENSSL_DTLS
TSK_DEBUG_ERROR("OpenSSL or DTLS not enabled");
return -200;
#else
{
X509* x509;
BIO* bio;
int ret = 0;
const EVP_MD *evp;
if (tsk_strnullORempty(certfile) || !fingerprint){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
if (!(evp = _tnet_dtls_get_hash_evp(hash))){
return -1;
}
x509 = tsk_null;
bio = tsk_null;
if (!(bio = BIO_new(BIO_s_file()))){
TSK_DEBUG_ERROR("BIO_new(BIO_s_file()) failed [%s]", ERR_error_string(ERR_get_error(), tsk_null));
ret = -3;
goto bail;
}
if (BIO_read_filename(bio, certfile) != 1){
TSK_DEBUG_ERROR("BIO_read_filename(%s) failed [%s]", certfile, ERR_error_string(ERR_get_error(), tsk_null));
ret = -4;
goto bail;
}
if (!(x509 = PEM_read_bio_X509(bio, tsk_null, 0, tsk_null))){
TSK_DEBUG_ERROR("PEM_read_bio() failed [%s]", ERR_error_string(ERR_get_error(), tsk_null));
ret = -5;
goto bail;
}
if ((ret = _tnet_dtls_get_fingerprint(x509, evp, fingerprint))){
goto bail;
}
bail:
if (bio){
BIO_free_all(bio);
}
return ret;
}
#endif
}
tnet_dtls_socket_handle_t* tnet_dtls_socket_create(struct tnet_socket_s* wrapped_sock, struct ssl_ctx_st* ssl_ctx)
{
#if !HAVE_OPENSSL || !HAVE_OPENSSL_DTLS
TSK_DEBUG_ERROR("OpenSSL or DTLS not enabled");
return tsk_null;
#else
tnet_dtls_socket_t* socket;
if (!wrapped_sock || !ssl_ctx){
TSK_DEBUG_ERROR("Invalid parameter");
return tsk_null;
}
if ((socket = tsk_object_new(tnet_dtls_socket_def_t))){
socket->wrapped_sock = tsk_object_ref(wrapped_sock);
if (!(socket->ssl = SSL_new(ssl_ctx))){
TSK_DEBUG_ERROR("SSL_new(CTX) failed [%s]", ERR_error_string(ERR_get_error(), tsk_null));
TSK_OBJECT_SAFE_FREE(socket);
return tsk_null;
}
if (!(socket->rbio = BIO_new(BIO_s_mem())) || !(socket->wbio = BIO_new(BIO_s_mem()))){
TSK_DEBUG_ERROR("BIO_new_socket(%d) failed [%s]", socket->wrapped_sock->fd, ERR_error_string(ERR_get_error(), tsk_null));
if (socket->rbio){
BIO_free(socket->rbio);
}
if (socket->wbio){
BIO_free(socket->wbio);
}
TSK_OBJECT_SAFE_FREE(socket);
return tsk_null;
}
BIO_set_mem_eof_return(socket->rbio, -1);
BIO_set_mem_eof_return(socket->wbio, -1);
SSL_set_bio(socket->ssl, socket->rbio, socket->wbio);
SSL_set_mode(socket->ssl, SSL_MODE_AUTO_RETRY);
SSL_set_read_ahead(socket->ssl, 1);
if ((socket->verify_peer = (SSL_CTX_get_verify_mode(ssl_ctx) != SSL_VERIFY_NONE))){
TSK_DEBUG_INFO("SSL cert verify: ON");
socket->verify_peer = tsk_true;
SSL_set_verify(socket->ssl, (SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT), _tnet_dtls_verify_cert);
}
else {
// FIXME:
TSK_DEBUG_ERROR("????");
}
SSL_set_app_data(socket->ssl, socket);
}
return socket;
#endif
}
tnet_fd_t tnet_dtls_socket_get_fd(const tnet_dtls_socket_handle_t* handle)
{
return handle ? ((const tnet_dtls_socket_t*)handle)->wrapped_sock->fd : TNET_INVALID_FD;
}
const struct sockaddr_storage* tnet_dtls_socket_get_remote_addr(const tnet_dtls_socket_handle_t* handle)
{
return handle ? &((const tnet_dtls_socket_t*)handle)->remote.addr : tsk_null;
}
int tnet_dtls_socket_set_callback(tnet_dtls_socket_handle_t* handle, const void* usrdata, tnet_dtls_socket_cb_f func)
{
tnet_dtls_socket_t* socket = handle;
if (!socket){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
socket->cb.usrdata = usrdata;
socket->cb.func = func;
return 0;
}
int tnet_dtls_socket_set_remote_fingerprint(tnet_dtls_socket_handle_t* handle, const tnet_fingerprint_t* fingerprint, tnet_dtls_hash_type_t hash)
{
tnet_dtls_socket_t* socket = handle;
if (!socket || !fingerprint){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
memcpy(socket->remote.fp, &(*fingerprint)[0], sizeof(tnet_fingerprint_t));
socket->remote.hash = hash;
return 0;
}
/*
rfc5764: 4.1. The use_srtp Extension
*/
int tnet_dtls_socket_use_srtp(tnet_dtls_socket_handle_t*handle)
{
#if !HAVE_OPENSSL || !HAVE_OPENSSL_DTLS || !HAVE_OPENSSL_DTLS_SRTP
TSK_DEBUG_ERROR("OpenSSL or DTLS not enabled");
return -200;
#else
tnet_dtls_socket_t* socket = handle;
if (!socket){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
if ((socket->use_srtp = tsk_true)){
if (!socket->verify_peer){
socket->verify_peer = tsk_true; // DTLS-SRTP requires certtificates
SSL_set_verify(socket->ssl, (SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT), _tnet_dtls_verify_cert);
}
}
return 0;
#endif
}
int tnet_dtls_socket_set_setup(tnet_dtls_socket_handle_t* handle, tnet_dtls_setup_t setup)
{
#if !HAVE_OPENSSL || !HAVE_OPENSSL_DTLS
TSK_DEBUG_ERROR("OpenSSL or DTLS not enabled");
return -200;
#else
tnet_dtls_socket_t* socket = handle;
if (!socket){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
switch ((socket->setup = setup)){
case tnet_dtls_setup_passive:
SSL_set_accept_state(socket->ssl);
break;
case tnet_dtls_setup_active:
case tnet_dtls_setup_actpass:
case tnet_dtls_setup_none:
if (setup != tnet_dtls_setup_active){
TSK_DEBUG_WARN("using setup=%s is not a good idea", TNET_DTLS_SETUP_NAMES[setup]);
}
SSL_set_connect_state(socket->ssl);
break;
default:
TSK_DEBUG_ERROR("%d not valid value for DTLS setup", (int32_t)setup);
break;
}
return 0;
#endif
}
int tnet_dtls_socket_set_store_handshakingdata(tnet_dtls_socket_handle_t* handle, tsk_bool_t handshake_storedata)
{
if (!handle) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
((tnet_dtls_socket_t*)handle)->handshake_storedata = handshake_storedata;
return 0;
}
int tnet_dtls_socket_get_handshakingdata(tnet_dtls_socket_handle_t* handle, const void** data, tsk_size_t *size)
{
if (!handle || !data || !size) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
*data = ((tnet_dtls_socket_t*)handle)->handshake_data.ptr;
*size = ((tnet_dtls_socket_t*)handle)->handshake_data.count;
return 0;
}
tsk_bool_t tnet_dtls_socket_is_remote_cert_fp_match(tnet_dtls_socket_handle_t* handle)
{
#if !HAVE_OPENSSL || !HAVE_OPENSSL_DTLS
TSK_DEBUG_ERROR("OpenSSL or DTLS not enabled");
return -1;
#else
return _tnet_dtls_socket_is_remote_cert_fp_match((tnet_dtls_socket_t*)handle);
#endif
}
int tnet_dtls_socket_do_handshake(tnet_dtls_socket_handle_t* handle, const struct sockaddr_storage* remote_addr)
{
#if !HAVE_OPENSSL || !HAVE_OPENSSL_DTLS
TSK_DEBUG_ERROR("OpenSSL or DTLS not enabled");
return -1;
#else
tnet_dtls_socket_t *socket = handle;
int ret = 0, len;
void* out_data;
if (!socket) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
tsk_safeobj_lock(socket);
// update remote address even if handshaking is completed
if (remote_addr) {
socket->remote.addr = *remote_addr;
}
if (socket->handshake_completed) {
TSK_DEBUG_INFO("Handshake completed");
ret = 0;
goto bail;
}
if (!socket->handshake_started) {
if ((ret = SSL_do_handshake(socket->ssl)) != 1) {
switch ((ret = SSL_get_error(socket->ssl, ret))) {
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_NONE:
break;
default:
TSK_DEBUG_ERROR("DTLS handshake failed [%s]", ERR_error_string(ERR_get_error(), tsk_null));
_tnet_dtls_socket_raise_event_dataless(socket, tnet_dtls_socket_event_type_handshake_failed);
ret = -2;
goto bail;
}
}
socket->handshake_started = (ret == SSL_ERROR_NONE); // TODO: reset for renegotiation
}
if ((len = BIO_get_mem_data(socket->wbio, &out_data)) > 0 && out_data) {
if (socket->handshake_storedata) {
if ((int)socket->handshake_data.size < len) {
if (!(socket->handshake_data.ptr = tsk_realloc(socket->handshake_data.ptr, len))) {
socket->handshake_data.size = 0;
socket->handshake_data.count = 0;
ret = -5;
goto bail;
}
socket->handshake_data.size = len;
}
socket->handshake_data.count = len;
memcpy(socket->handshake_data.ptr, out_data, len);
}
else {
tnet_port_t port;
tnet_ip_t ip;
tnet_get_sockip_n_port((const struct sockaddr *)&socket->remote.addr, &ip, &port);
TSK_DEBUG_INFO("DTLS data handshake to send with len = %d, ip = %.*s and port = %d", len, sizeof(ip), ip, port);
if (TNET_SOCKET_TYPE_IS_DGRAM(socket->wrapped_sock->type)) { // UDP
len = tnet_sockfd_sendto(socket->wrapped_sock->fd, (const struct sockaddr *)&socket->remote.addr, out_data, len);
}
else { // TCP, TLS, WSS...
len = tnet_socket_send_stream(socket->wrapped_sock, out_data, len);
}
TSK_DEBUG_INFO("DTLS data handshake sent len = %d", len);
}
}
BIO_reset(socket->rbio);
BIO_reset(socket->wbio);
if ((socket->handshake_completed = SSL_is_init_finished(socket->ssl))) {
TSK_DEBUG_INFO("DTLS handshake completed");
#if HAVE_OPENSSL_DTLS_SRTP
if (socket->use_srtp){
#if !defined(SRTP_MAX_KEY_LEN)
# define cipher_key_length (128 >> 3) // rfc5764 4.1.2. SRTP Protection Profiles
# define cipher_salt_length (112 >> 3) // rfc5764 4.1.2. SRTP Protection Profiles
// "cipher_key_length" is also equal to srtp_profile_get_master_key_length(srtp_profile_aes128_cm_sha1_80)
// "cipher_salt_length" is also srtp_profile_get_master_salt_length(srtp_profile_aes128_cm_sha1_80)
# define SRTP_MAX_KEY_LEN (cipher_key_length + cipher_salt_length)
#endif /* SRTP_MAX_KEY_LEN */
#define EXTRACTOR_dtls_srtp_text "EXTRACTOR-dtls_srtp"
#define EXTRACTOR_dtls_srtp_text_len 19
uint8_t keying_material[SRTP_MAX_KEY_LEN << 1];
static const tsk_size_t keying_material_size = sizeof(keying_material);
/*if(socket->use_srtp)*/{
SRTP_PROTECTION_PROFILE *p = SSL_get_selected_srtp_profile(socket->ssl);
if (!p) {
TSK_DEBUG_ERROR("SSL_get_selected_srtp_profile() returned null [%s]", ERR_error_string(ERR_get_error(), tsk_null));
ret = -2;
goto bail;
}
// alert user
_tnet_dtls_socket_raise_event(socket, tnet_dtls_socket_event_type_dtls_srtp_profile_selected, p->name, tsk_strlen(p->name));
memset(keying_material, 0, sizeof(keying_material));
// rfc5764 - 4.2. Key Derivation
ret = SSL_export_keying_material(socket->ssl, keying_material, sizeof(keying_material), EXTRACTOR_dtls_srtp_text, EXTRACTOR_dtls_srtp_text_len, tsk_null, 0, 0);
if (ret != 1) {
// alert listener
_tnet_dtls_socket_raise_event_dataless(socket, tnet_dtls_socket_event_type_error);
TSK_DEBUG_ERROR("SSL_export_keying_material() failed [%s]", ERR_error_string(ERR_get_error(), tsk_null));
ret = -2;
goto bail;
}
}
// alert listener
_tnet_dtls_socket_raise_event(socket, tnet_dtls_socket_event_type_dtls_srtp_data, keying_material, keying_material_size);
}
#endif /* HAVE_OPENSSL_DTLS_SRTP */
_tnet_dtls_socket_raise_event_dataless(socket, tnet_dtls_socket_event_type_handshake_succeed);
}
ret = 0; // clear "ret", error will directly jump to "bail:"
bail:
tsk_safeobj_unlock(socket);
return ret;
#endif
}
tsk_bool_t tnet_dtls_socket_is_handshake_completed(const tnet_dtls_socket_handle_t* handle)
{
return (handle && ((const tnet_dtls_socket_t *)handle)->handshake_completed);
}
/*
Handles DTLS data received over the network using standard functions (e.g. recvfrom())
@param handle
@param data When "use_srtp" is enabled this must point to DTLS handshake data.
@param size DTLS data size
@returns 0 if succeed, non-zero error code otherwise
*/
int tnet_dtls_socket_handle_incoming_data(tnet_dtls_socket_handle_t* handle, const void* data, tsk_size_t size)
{
#if !HAVE_OPENSSL || !HAVE_OPENSSL_DTLS
TSK_DEBUG_ERROR("OpenSSL or DTLS not enabled");
return -200;
#else
tnet_dtls_socket_t *socket = handle;
int ret = 0;
if (!socket || !data || !size) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
tsk_safeobj_lock(socket);
TSK_DEBUG_INFO("Receive DTLS data: %u", size);
// BIO_reset(socket->rbio);
// BIO_reset(socket->wbio);
if (!socket->rbio || !socket->wbio) {
TSK_DEBUG_ERROR("BIO not initialized yet");
ret = -2;
goto bail;
}
if ((ret = _tnet_dtls_socket_do_handshake(socket))) {
goto bail;
}
if ((ret = BIO_write(socket->rbio, data, (int)size)) != size) {
ret = SSL_get_error(socket->ssl, ret);
TSK_DEBUG_ERROR("BIO_write(rbio, %u) failed [%s]", size, ERR_error_string(ERR_get_error(), tsk_null));
ret = -1;
goto bail;
}
/*if((ret = SSL_read(socket->ssl, (void*)data, size)) <= 0){
switch((ret = SSL_get_error(socket->ssl, ret))){
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_NONE:
break;
default:
{
unsigned long sslErr = ERR_get_error();
const uint8_t* pData = (const uint8_t*)data;
TSK_DEBUG_ERROR("%lu = SSL_read(rbio, %u) failed [%s]", sslErr, size, ERR_error_string(ret, tsk_null));
// try to understand what's going on
// rfc6347 - 4.1. Record Layer
// rfc6347 - 4.2.2. Handshake Message Format
// rfc6347 - 4.3.2. Handshake Protocol
if(size > 14 && pData[0] == 0x16){ // content-type=='Handshake'
if(pData[13] == 0x01 && (socket->setup == tnet_dtls_setup_active || socket->setup == tnet_dtls_setup_actpass)){ // Handshake Type=='client Hello'
TSK_DEBUG_INFO("DTLS engine was in client mode but we are receiving 'Client Hello' messages. This is a bug in the remote peer: Re-negotiating!");
tnet_dtls_socket_set_setup(socket, tnet_dtls_setup_passive);
break;
}
else if(pData[13] == 0x02 && (socket->setup == tnet_dtls_setup_passive || socket->setup == tnet_dtls_setup_actpass)){ // Handshake Type=='server Hello'
TSK_DEBUG_INFO("DTLS engine was in server mode but we are receiving 'Server Hello' messages. This is a bug in the remote peer: Re-negotiating!");
tnet_dtls_socket_set_setup(socket, tnet_dtls_setup_active);
break;
}
}
//return -1;
break;
}
}
}*/
ret = _tnet_dtls_socket_do_handshake(socket);
bail:
tsk_safeobj_unlock(socket);
return ret;
#endif
}
//=================================================================================================
// DTLS socket object definition
//
static tsk_object_t* tnet_dtls_socket_ctor(tsk_object_t * self, va_list * app)
{
tnet_dtls_socket_t *socket = self;
if (socket){
tsk_safeobj_init(socket);
}
return self;
}
static tsk_object_t* tnet_dtls_socket_dtor(tsk_object_t * self)
{
tnet_dtls_socket_t *socket = self;
if (socket){
#if HAVE_OPENSSL
if (socket->rbio) {
//BIO_free(socket->rbio);
socket->rbio = tsk_null;
}
if (socket->wbio) {
//BIO_free(socket->wbio);
socket->wbio = tsk_null;
}
if (socket->ssl) {
SSL_shutdown(socket->ssl);
// https://www.openssl.org/docs/crypto/BIO_s_bio.html
// implicitly frees internal_bio
SSL_free(socket->ssl);
}
#endif
TSK_FREE(socket->handshake_data.ptr);
TSK_OBJECT_SAFE_FREE(socket->wrapped_sock);
tsk_safeobj_deinit(socket);
}
return self;
}
static const tsk_object_def_t tnet_dtls_socket_def_s =
{
sizeof(tnet_dtls_socket_t),
tnet_dtls_socket_ctor,
tnet_dtls_socket_dtor,
tsk_null,
};
const tsk_object_def_t *tnet_dtls_socket_def_t = &tnet_dtls_socket_def_s; |