#if HAVE_CRT #define _CRTDBG_MAP_ALLOC #include #include #endif //HAVE_CRT /* * Copyright (C) 2020, University of the Basque Country (UPV/EHU) * Contact for licensing options: * * The original file was part of Open Source Doubango Framework * Copyright (C) 2010-2011 Mamadou Diop. * Copyright (C) 2012 Doubango Telecom * * 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;