diff --git a/Makefile.am b/Makefile.am index 88ff956472..145733e636 100644 --- a/Makefile.am +++ b/Makefile.am @@ -232,6 +232,7 @@ libfreeswitch_la_SOURCES = \ src/switch_core_memory.c \ src/switch_core_codec.c \ src/switch_core_file.c \ + src/switch_core_cert.c \ src/switch_core_hash.c \ src/switch_core_sqldb.c \ src/switch_core_session.c \ diff --git a/configure.in b/configure.in index b47d725e35..817bb1a56b 100644 --- a/configure.in +++ b/configure.in @@ -76,6 +76,11 @@ AC_ARG_WITH([grammardir], AC_SUBST(grammardir) AC_DEFINE_UNQUOTED([SWITCH_GRAMMAR_DIR],"${grammardir}",[where to put grammar files]) +AC_ARG_WITH([certsdir], + [AS_HELP_STRING([--with-certsdir=DIR], [Put certs files into this location (default: $prefix/certs)])], [certsdir="$withval"], [certsdir="$prefix/certs"]) +AC_SUBST(certsdir) +AC_DEFINE_UNQUOTED([SWITCH_CERTS_DIR],"${certsdir}",[where to put certs files]) + AC_ARG_WITH([scriptdir], [AS_HELP_STRING([--with-scriptdir=DIR], [Put script files into this location (default: $prefix/scripts)])], [scriptdir="$withval"], [scriptdir="$prefix/scripts"]) AC_SUBST(scriptdir) diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 1bad6377e8..7381adf1e8 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -40,6 +40,12 @@ #define SWITCH_CORE_H #include +#include +#include +#include +#ifndef OPENSSL_NO_ENGINE +#include +#endif SWITCH_BEGIN_EXTERN_C #define SWITCH_MAX_CORE_THREAD_SESSION_OBJS 128 @@ -77,6 +83,37 @@ typedef struct switch_thread_data_s { } switch_thread_data_t; +#define DTLS_SRTP_FNAME "dtls-srtp" +#define MAX_FPLEN 64 +#define MAX_FPSTRLEN 192 + +typedef struct dtls_fp_s { + uint32_t len; + uint8_t data[MAX_FPLEN+1]; + char *type; + char str[MAX_FPSTRLEN]; +} dtls_fingerprint_t; + +typedef enum { + DTLS_TYPE_CLIENT = (1 << 0), + DTLS_TYPE_SERVER = (1 << 1), + DTLS_TYPE_RTP = (1 << 2), + DTLS_TYPE_RTCP = (1 << 3) +} dtls_type_t; + +typedef enum { + DS_HANDSHAKE, + DS_SETUP, + DS_READY, + DS_FAIL, + DS_INVALID, +} dtls_state_t; + + + + + + #define MESSAGE_STAMP_FFL(_m) _m->_file = __FILE__; _m->_func = __SWITCH_FUNC__; _m->_line = __LINE__ #define MESSAGE_STRING_ARG_MAX 10 @@ -2478,6 +2515,12 @@ SWITCH_DECLARE(void) switch_sql_queue_manger_execute_sql_event_callback(switch_s SWITCH_DECLARE(pid_t) switch_fork(void); +SWITCH_DECLARE(int) switch_core_gen_certs(const char *prefix); +SWITCH_DECLARE(int) switch_core_cert_gen_fingerprint(const char *prefix, dtls_fingerprint_t *fp); +SWITCH_DECLARE(int) switch_core_cert_expand_fingerprint(dtls_fingerprint_t *fp, const char *str); +SWITCH_DECLARE(int) switch_core_cert_extract_fingerprint(X509* x509, dtls_fingerprint_t *fp); +SWITCH_DECLARE(int) switch_core_cert_verify(dtls_fingerprint_t *fp); + SWITCH_END_EXTERN_C #endif /* For Emacs: diff --git a/src/include/switch_rtp.h b/src/include/switch_rtp.h index 253677d847..cc6e0211fa 100644 --- a/src/include/switch_rtp.h +++ b/src/include/switch_rtp.h @@ -96,7 +96,7 @@ typedef struct icand_s { #define MAX_CAND 25 typedef struct ice_s { - icand_t cands[2][MAX_CAND]; + icand_t cands[MAX_CAND][2]; int cand_idx; int chosen; char *ufrag; @@ -506,6 +506,9 @@ SWITCH_DECLARE(switch_rtp_stats_t *) switch_rtp_get_stats(switch_rtp_t *rtp_sess SWITCH_DECLARE(switch_byte_t) switch_rtp_check_auto_adj(switch_rtp_t *rtp_session); SWITCH_DECLARE(void) switch_rtp_set_interdigit_delay(switch_rtp_t *rtp_session, uint32_t delay); +SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, dtls_fingerprint_t *local_fp, dtls_fingerprint_t *remote_fp, dtls_type_t type); + + /*! \} */ diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 16e845c2e9..fdd2bafc21 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -486,6 +486,7 @@ struct switch_directories { char *recordings_dir; char *sounds_dir; char *lib_dir; + char *certs_dir; }; typedef struct switch_directories switch_directories; @@ -1297,6 +1298,7 @@ typedef enum { CF_RTP_NOTIMER_DURING_BRIDGE, CF_WEBRTC, CF_ICE, + CF_DTLS, /* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */ /* IF YOU ADD NEW ONES CHECK IF THEY SHOULD PERSIST OR ZERO THEM IN switch_core_session.c switch_core_session_request_xml() */ CF_FLAG_MAX diff --git a/src/switch_core.c b/src/switch_core.c index 5e20fa6911..d9c3f4c35a 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -711,6 +711,17 @@ SWITCH_DECLARE(void) switch_core_set_globals(void) #endif } + if (!SWITCH_GLOBAL_dirs.certs_dir && (SWITCH_GLOBAL_dirs.certs_dir = (char *) malloc(BUFSIZE))) { + if (SWITCH_GLOBAL_dirs.base_dir) + switch_snprintf(SWITCH_GLOBAL_dirs.certs_dir, BUFSIZE, "%s%scert", SWITCH_GLOBAL_dirs.base_dir, SWITCH_PATH_SEPARATOR); + else +#ifdef SWITCH_CERTS_DIR + switch_snprintf(SWITCH_GLOBAL_dirs.certs_dir, BUFSIZE, "%s", SWITCH_CERTS_DIR); +#else + switch_snprintf(SWITCH_GLOBAL_dirs.certs_dir, BUFSIZE, "%s%scert", base_dir, SWITCH_PATH_SEPARATOR); +#endif + } + if (!SWITCH_GLOBAL_dirs.temp_dir && (SWITCH_GLOBAL_dirs.temp_dir = (char *) malloc(BUFSIZE))) { #ifdef SWITCH_TEMP_DIR switch_snprintf(SWITCH_GLOBAL_dirs.temp_dir, BUFSIZE, "%s", SWITCH_TEMP_DIR); @@ -745,6 +756,7 @@ SWITCH_DECLARE(void) switch_core_set_globals(void) switch_assert(SWITCH_GLOBAL_dirs.grammar_dir); switch_assert(SWITCH_GLOBAL_dirs.recordings_dir); switch_assert(SWITCH_GLOBAL_dirs.sounds_dir); + switch_assert(SWITCH_GLOBAL_dirs.certs_dir); switch_assert(SWITCH_GLOBAL_dirs.temp_dir); } @@ -1593,7 +1605,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switc switch_dir_make_recursive(SWITCH_GLOBAL_dirs.recordings_dir, SWITCH_DEFAULT_DIR_PERMS, runtime.memory_pool); switch_dir_make_recursive(SWITCH_GLOBAL_dirs.sounds_dir, SWITCH_DEFAULT_DIR_PERMS, runtime.memory_pool); switch_dir_make_recursive(SWITCH_GLOBAL_dirs.temp_dir, SWITCH_DEFAULT_DIR_PERMS, runtime.memory_pool); - + switch_dir_make_recursive(SWITCH_GLOBAL_dirs.certs_dir, SWITCH_DEFAULT_DIR_PERMS, runtime.memory_pool); switch_mutex_init(&runtime.uuid_mutex, SWITCH_MUTEX_NESTED, runtime.memory_pool); diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 1bd8c36b39..1238adcb8f 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -137,6 +137,10 @@ typedef struct switch_rtp_engine_s { int8_t rtcp_mux; + dtls_fingerprint_t local_dtls_fingerprint; + dtls_fingerprint_t remote_dtls_fingerprint; + + } switch_rtp_engine_t; @@ -742,7 +746,7 @@ SWITCH_DECLARE(void) switch_core_session_apply_crypto(switch_core_session_t *ses engine = &session->media_handle->engines[type]; - if (engine->ssec.remote_crypto_key && switch_channel_test_flag(session->channel, CF_SECURE)) { + if (engine->ssec.remote_crypto_key && switch_channel_test_flag(session->channel, CF_SECURE) && !switch_channel_test_flag(session->channel, CF_DTLS)) { switch_core_media_add_crypto(&engine->ssec, engine->ssec.remote_crypto_key, SWITCH_RTP_CRYPTO_RECV); @@ -801,7 +805,8 @@ SWITCH_DECLARE(int) switch_core_session_check_incoming_crypto(switch_core_sessio switch_channel_set_variable(session->channel, "srtp_remote_audio_crypto_key", crypto); engine->ssec.crypto_tag = crypto_tag; - if (switch_rtp_ready(engine->rtp_session) && switch_channel_test_flag(session->channel, CF_SECURE)) { + if (switch_rtp_ready(engine->rtp_session) && switch_channel_test_flag(session->channel, CF_SECURE) && + !switch_channel_test_flag(session->channel, CF_DTLS)) { switch_core_media_add_crypto(&engine->ssec, engine->ssec.remote_crypto_key, SWITCH_RTP_CRYPTO_RECV); switch_rtp_add_crypto_key(engine->rtp_session, SWITCH_RTP_CRYPTO_RECV, engine->ssec.crypto_tag, engine->ssec.crypto_type, engine->ssec.remote_raw_key, SWITCH_RTP_KEY_LEN); @@ -840,7 +845,7 @@ SWITCH_DECLARE(void) switch_core_session_check_outgoing_crypto(switch_core_sessi switch_channel_t *channel = switch_core_session_get_channel(session); const char *var; - if (!switch_core_session_media_handle_ready(session) == SWITCH_STATUS_SUCCESS) { + if (!switch_core_session_media_handle_ready(session) == SWITCH_STATUS_SUCCESS || switch_channel_test_flag(channel, CF_DTLS)) { return; } @@ -1771,6 +1776,21 @@ SWITCH_DECLARE(void) switch_core_media_check_video_codecs(switch_core_session_t } } +//? +static void generate_local_fingerprint(switch_media_handle_t *smh, switch_media_type_t type) +{ + switch_rtp_engine_t *engine = &smh->engines[type]; + + engine->local_dtls_fingerprint.type = "sha-256"; + switch_core_cert_gen_fingerprint(DTLS_SRTP_FNAME, &engine->local_dtls_fingerprint); + + + //engine->local_dtls_fingerprint.data[]; + + +} + + //? static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_media_t *m) { @@ -1799,6 +1819,28 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_ engine->ice_in.pwd = switch_core_session_strdup(smh->session, attr->a_value); } else if (!strcasecmp(attr->a_name, "ice-options")) { engine->ice_in.options = switch_core_session_strdup(smh->session, attr->a_value); + } else if (!strcasecmp(attr->a_name, "fingerprint") && !zstr(attr->a_value)) { + //a=fingerprint:sha-256 B6:14:E2:59:58:C9:DD:44:50:91:D4:75:AE:23:9F:67:9F:8E:C2:B3:36:62:C7:9C:F4:25:1F:F3:EF:58:B1:BF + + char *p; + + engine->remote_dtls_fingerprint.type = switch_core_session_strdup(smh->session, attr->a_value); + + if ((p = strchr(engine->remote_dtls_fingerprint.type, ' '))) { + *p++ = '\0'; + switch_set_string(engine->local_dtls_fingerprint.str, p); + } + + if (strcasecmp(engine->remote_dtls_fingerprint.type, "sha-256")) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_WARNING, "Unsupported fingerprint type.\n"); + engine->local_dtls_fingerprint.type = NULL; + engine->remote_dtls_fingerprint.type = NULL; + } + + generate_local_fingerprint(smh, type); + + switch_channel_set_flag(smh->session->channel, CF_DTLS); + #ifdef RTCP_MUX } else if (!strcasecmp(attr->a_name, "rtcp-mux")) { @@ -3652,6 +3694,16 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi } + if (!zstr(a_engine->local_dtls_fingerprint.str)) { + dtls_type_t dtype = switch_channel_direction(smh->session->channel) == SWITCH_CALL_DIRECTION_INBOUND ? DTLS_TYPE_SERVER : DTLS_TYPE_CLIENT; + + dtype |= DTLS_TYPE_RTP; + if (a_engine->rtcp_mux > 0) dtype |= DTLS_TYPE_RTCP; + + switch_rtp_add_dtls(a_engine->rtp_session, &a_engine->local_dtls_fingerprint, &a_engine->remote_dtls_fingerprint, dtype); + } + + if (a_engine->ice_in.cands[a_engine->ice_in.chosen][0].ready) { gen_ice(session, SWITCH_MEDIA_TYPE_AUDIO, NULL, 0); @@ -4756,8 +4808,11 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess } - - + if (!zstr(a_engine->local_dtls_fingerprint.type)) { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=fingerprint:%s %s\n", a_engine->local_dtls_fingerprint.type, + a_engine->local_dtls_fingerprint.str); + } + if (smh->mparams->rtcp_audio_interval_msec) { if (a_engine->rtcp_mux > 0) { switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtcp-mux\n"); @@ -4837,7 +4892,7 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess - if (!zstr(local_audio_crypto_key) && switch_channel_test_flag(session->channel, CF_SECURE)) { + if (!zstr(local_audio_crypto_key) && switch_channel_test_flag(session->channel, CF_SECURE) && !switch_channel_test_flag(session->channel, CF_DTLS)) { switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=crypto:%s\n", local_audio_crypto_key); //switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=encryption:optional\n"); } @@ -5051,6 +5106,11 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess } + if (!zstr(v_engine->local_dtls_fingerprint.type)) { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=fingerprint:%s %s\n", v_engine->local_dtls_fingerprint.type, + v_engine->local_dtls_fingerprint.str); + } + if (smh->mparams->rtcp_audio_interval_msec) { if (v_engine->rtcp_mux > 0) { @@ -5130,7 +5190,8 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess - if (switch_channel_test_flag(session->channel, CF_SECURE) && !zstr(local_video_crypto_key)) { + if (switch_channel_test_flag(session->channel, CF_SECURE) && !zstr(local_video_crypto_key) && + !switch_channel_test_flag(session->channel, CF_DTLS)) { switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=crypto:%s\n", local_video_crypto_key); //switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=encryption:optional\n"); } @@ -6807,7 +6868,7 @@ SWITCH_DECLARE (void) switch_core_media_recover_session(switch_core_session_t *s SWITCH_DECLARE(void) switch_core_media_init(void) { - + switch_core_gen_certs(DTLS_SRTP_FNAME); } SWITCH_DECLARE(void) switch_core_media_deinit(void) diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 0eff91c91e..a1c9855df3 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -50,6 +50,10 @@ #include #include +#include +#include +#include + #define READ_INC(rtp_session) switch_mutex_lock(rtp_session->read_mutex); rtp_session->reading++ #define READ_DEC(rtp_session) switch_mutex_unlock(rtp_session->read_mutex); rtp_session->reading-- #define WRITE_INC(rtp_session) switch_mutex_lock(rtp_session->write_mutex); rtp_session->writing++ @@ -176,6 +180,38 @@ typedef struct { uint8_t rready; } switch_rtp_ice_t; +struct switch_rtp; + +typedef struct switch_dtls_s { + /* DTLS */ + SSL_CTX *ssl_ctx; + SSL *ssl; + BIO *read_bio; + BIO *write_bio; + dtls_fingerprint_t *local_fp; + dtls_fingerprint_t *remote_fp; + dtls_state_t state; + dtls_type_t type; + switch_size_t bytes; + void *data; + switch_socket_t *sock_output; + switch_sockaddr_t *remote_addr; + char *rsa; + char *pvt; + struct switch_rtp *rtp_session; +} switch_dtls_t; + +typedef int (*dtls_state_handler_t)(switch_rtp_t *, switch_dtls_t *); + + +static int dtls_state_handshake(switch_rtp_t *rtp_session, switch_dtls_t *dtls); +static int dtls_state_ready(switch_rtp_t *rtp_session, switch_dtls_t *dtls); +static int dtls_state_setup(switch_rtp_t *rtp_session, switch_dtls_t *dtls); +static int dtls_state_dummy(switch_rtp_t *rtp_session, switch_dtls_t *dtls); + +dtls_state_handler_t dtls_states[DS_INVALID] = {dtls_state_handshake, dtls_state_setup, dtls_state_ready, dtls_state_dummy}; + + struct switch_rtp { /* * Two sockets are needed because we might be transcoding protocol families @@ -208,6 +244,9 @@ struct switch_rtp { uint32_t srtp_errs; uint32_t srctp_errs; + switch_dtls_t *dtls; + switch_dtls_t *rtcp_dtls; + uint16_t seq; uint32_t ssrc; int8_t sending_dtmf; @@ -1883,6 +1922,217 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_address(switch_rtp_t *rtp_ return status; } + +static const char *dtls_state_names_t[] = {"HANDSHAKE", "SETUP", "READY", "FAIL", "INVALID"}; +static const char *dtls_state_names(dtls_state_t s) +{ + if (s > DS_INVALID) { + s = DS_INVALID; + } + + return dtls_state_names_t[s]; +} + + +#define dtls_set_state(_dtls, _state) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_INFO, "Changing DTLS state from %s to %s\n", dtls_state_names(_dtls->state), dtls_state_names(_state)); _dtls->state = _state + +static int dtls_state_dummy(switch_rtp_t *rtp_session, switch_dtls_t *dtls) +{ + /// duhhh + + return -1; +} + +static int dtls_state_setup(switch_rtp_t *rtp_session, switch_dtls_t *dtls) +{ + dtls_set_state(dtls, DS_READY); + return 0; +} + +static int dtls_state_ready(switch_rtp_t *rtp_session, switch_dtls_t *dtls) +{ + printf("ready...\n"); + return 0; +} + +static int dtls_state_handshake(switch_rtp_t *rtp_session, switch_dtls_t *dtls) +{ + int ret; + + if ((ret = SSL_do_handshake(dtls->ssl)) != 1){ + switch((ret = SSL_get_error(dtls->ssl, ret))){ + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_NONE: + break; + default: + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "Handshake failure %d\n", ret); + dtls_set_state(dtls, DS_FAIL); + return -1; + } + } + + if (SSL_is_init_finished(dtls->ssl)) { + dtls_set_state(dtls, DS_SETUP); + } + + return 0; +} + +static int do_dtls(switch_rtp_t *rtp_session, switch_dtls_t *dtls) +{ + int r = 0, ret = 0, len; + void *data; + switch_size_t bytes; + + //printf("WTF %s...\n", dtls_state_names(dtls->state)); + + if (dtls->bytes) { + printf("READ %ld\n", dtls->bytes); + + if ((ret = BIO_write(dtls->read_bio, dtls->data, dtls->bytes)) != dtls->bytes) { + ret = SSL_get_error(dtls->ssl, ret); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "DTLS packet read err %d\n", ret); + dtls_set_state(dtls, DS_FAIL); + return -1; + } + } + + if (SSL_read(dtls->ssl, dtls->data, dtls->bytes) == dtls->bytes) { + if (BIO_reset(dtls->read_bio)); + } + r = dtls_states[dtls->state](rtp_session, dtls); + + + if ((len = BIO_get_mem_data(dtls->write_bio, &data)) && data) { + bytes = len; + printf("WRITE %ld\n", bytes); + if (switch_socket_sendto(dtls->sock_output, dtls->remote_addr, 0, data, &bytes ) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "DTLS packet not written\n"); + } else { + if (BIO_reset(dtls->write_bio)); + } + } + + + + + return r; +} + +static int cb_verify_peer(int preverify_ok, X509_STORE_CTX *ctx) +{ + SSL *ssl = NULL; + switch_dtls_t *dtls; + X509 *cert; + int r = 0; + + ssl = X509_STORE_CTX_get_app_data(ctx); + dtls = (switch_dtls_t *) SSL_get_app_data(ssl); + + if (!(ssl && dtls)) { + return 0; + } + + printf("OMFG?!!!!\n"); + + if ((cert = SSL_get_peer_certificate(dtls->ssl))) { + switch_core_cert_extract_fingerprint(cert, dtls->remote_fp); + + r = switch_core_cert_verify(dtls->remote_fp); + + X509_free(cert); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(dtls->rtp_session->session), SWITCH_LOG_ERROR, "CERT ERR!\n"); + } + + return r; +} + +SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, dtls_fingerprint_t *local_fp, dtls_fingerprint_t *remote_fp, dtls_type_t type) +{ + switch_dtls_t *dtls; + + if (!switch_rtp_ready(rtp_session)) { + return SWITCH_STATUS_FALSE; + } + + if (!((type & DTLS_TYPE_RTP) || (type & DTLS_TYPE_RTCP)) || !((type & DTLS_TYPE_CLIENT) || (type & DTLS_TYPE_SERVER))) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_CRIT, "INVALID TYPE!\n"); + } + + if (!(dtls = rtp_session->dtls)) { + dtls = switch_core_alloc(rtp_session->pool, sizeof(*dtls)); + + + dtls->pvt = switch_core_sprintf(rtp_session->pool, "%s%s%s.key", SWITCH_GLOBAL_dirs.certs_dir, SWITCH_PATH_SEPARATOR, DTLS_SRTP_FNAME); + dtls->rsa = switch_core_sprintf(rtp_session->pool, "%s%s%s.crt", SWITCH_GLOBAL_dirs.certs_dir, SWITCH_PATH_SEPARATOR, DTLS_SRTP_FNAME); + + dtls->ssl_ctx = SSL_CTX_new(DTLSv1_method()); + switch_assert(dtls->ssl_ctx); + + SSL_CTX_set_mode(dtls->ssl_ctx, SSL_MODE_AUTO_RETRY); + SSL_CTX_set_verify(dtls->ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + SSL_CTX_set_cipher_list(dtls->ssl_ctx, "ALL"); + + SSL_CTX_set_tlsext_use_srtp(dtls->ssl_ctx, "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32"); + + dtls->type = type; + dtls->read_bio = BIO_new(BIO_s_mem()); + switch_assert(dtls->read_bio); + + dtls->write_bio = BIO_new(BIO_s_mem()); + switch_assert(dtls->write_bio); + + BIO_set_mem_eof_return(dtls->read_bio, -1); + BIO_set_mem_eof_return(dtls->write_bio, -1); + + SSL_CTX_use_certificate_file(dtls->ssl_ctx, dtls->rsa, SSL_FILETYPE_PEM); + SSL_CTX_use_PrivateKey_file(dtls->ssl_ctx, dtls->pvt, SSL_FILETYPE_PEM); + + dtls->ssl = SSL_new(dtls->ssl_ctx); + + SSL_set_bio(dtls->ssl, dtls->read_bio, dtls->write_bio); + SSL_set_mode(dtls->ssl, SSL_MODE_AUTO_RETRY); + SSL_set_read_ahead(dtls->ssl, 1); + SSL_set_verify(dtls->ssl, (SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT), cb_verify_peer); + SSL_set_app_data(dtls->ssl, dtls); + + dtls->local_fp = local_fp; + dtls->remote_fp = remote_fp; + dtls->rtp_session = rtp_session; + + switch_core_cert_expand_fingerprint(remote_fp, remote_fp->str); + + if ((type & DTLS_TYPE_RTP)) { + rtp_session->dtls = dtls; + dtls->sock_output = rtp_session->sock_output; + dtls->remote_addr = rtp_session->remote_addr; + } + + if ((type & DTLS_TYPE_RTCP)) { + rtp_session->rtcp_dtls = dtls; + if (!(type & DTLS_TYPE_RTP)) { + dtls->sock_output = rtp_session->rtcp_sock_output; + dtls->remote_addr = rtp_session->rtcp_remote_addr; + } + } + + if ((type & DTLS_TYPE_SERVER)) { + SSL_set_accept_state(dtls->ssl); + } else { + SSL_set_connect_state(dtls->ssl); + } + + + return SWITCH_STATUS_SUCCESS; + } + + return SWITCH_STATUS_FALSE; + +} + + SWITCH_DECLARE(switch_status_t) switch_rtp_add_crypto_key(switch_rtp_t *rtp_session, switch_rtp_crypto_direction_t direction, uint32_t index, switch_rtp_crypto_key_type_t type, unsigned char *key, switch_size_t keylen) @@ -3183,13 +3433,31 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t status = switch_socket_recvfrom(rtp_session->from_addr, rtp_session->sock_input, 0, (void *) &rtp_session->recv_msg, bytes); - if (status == SWITCH_STATUS_SUCCESS && *bytes && rtp_session->flags[SWITCH_RTP_FLAG_RTCP_MUX]) { - if (rtp_session->recv_msg.header.pt != rtp_session->rpayload && (!rtp_session->recv_te || rtp_session->recv_msg.header.pt != rtp_session->recv_te) && - (!rtp_session->cng_pt || rtp_session->recv_msg.header.pt != rtp_session->cng_pt) && - rtp_session->rtcp_recv_msg_p->header.version == 2 && - rtp_session->rtcp_recv_msg_p->header.type > 199 && rtp_session->rtcp_recv_msg_p->header.type < 205) { //rtcp muxed - *flags |= SFF_RTCP; - return SWITCH_STATUS_SUCCESS; + if (rtp_session->dtls) { + char *b = (char *) &rtp_session->recv_msg; + + //printf("RECV %d %ld\n", *b, *bytes); + + if ((*b >= 20) && (*b <= 64)) { + rtp_session->dtls->bytes = *bytes; + rtp_session->dtls->data = (void *) &rtp_session->recv_msg; + } else { + rtp_session->dtls->bytes = 0; + rtp_session->dtls->data = NULL; + } + do_dtls(rtp_session, rtp_session->dtls); + } + + if (status == SWITCH_STATUS_SUCCESS && *bytes) { + if (rtp_session->flags[SWITCH_RTP_FLAG_RTCP_MUX]) { + if (rtp_session->recv_msg.header.pt != rtp_session->rpayload && (!rtp_session->recv_te || + rtp_session->recv_msg.header.pt != rtp_session->recv_te) && + (!rtp_session->cng_pt || rtp_session->recv_msg.header.pt != rtp_session->cng_pt) && + rtp_session->rtcp_recv_msg_p->header.version == 2 && + rtp_session->rtcp_recv_msg_p->header.type > 199 && rtp_session->rtcp_recv_msg_p->header.type < 205) { //rtcp muxed + *flags |= SFF_RTCP; + return SWITCH_STATUS_SUCCESS; + } } } @@ -3470,7 +3738,7 @@ static switch_status_t process_rtcp_packet(switch_rtp_t *rtp_session, switch_siz static switch_status_t read_rtcp_packet(switch_rtp_t *rtp_session, switch_size_t *bytes, switch_frame_flag_t *flags) { switch_status_t status = SWITCH_STATUS_FALSE; - + if (!rtp_session->flags[SWITCH_RTP_FLAG_ENABLE_RTCP]) { return SWITCH_STATUS_FALSE; } @@ -3484,6 +3752,24 @@ static switch_status_t read_rtcp_packet(switch_rtp_t *rtp_session, switch_size_t *bytes = 0; } + + if (rtp_session->rtcp_dtls) { + char *b = (char *) &rtp_session->rtcp_recv_msg; + + //printf("RECV %d %ld\n", *b, *bytes); + + if ((*b >= 20) && (*b <= 64)) { + rtp_session->rtcp_dtls->bytes = *bytes; + rtp_session->rtcp_dtls->data = (void *) &rtp_session->rtcp_recv_msg; + } else { + rtp_session->rtcp_dtls->bytes = 0; + rtp_session->rtcp_dtls->data = NULL; + } + + do_dtls(rtp_session, rtp_session->rtcp_dtls); + } + + #ifdef ENABLE_SRTP if (rtp_session->flags[SWITCH_RTP_FLAG_SECURE_RECV] && rtp_session->rtcp_recv_msg_p->header.version == 2) { @@ -4696,6 +4982,9 @@ static int rtp_common_write(switch_rtp_t *rtp_session, //printf("XXX skip no stun love %d/%d\n", rtp_session->ice.ready, rtp_session->ice.rready); } + if (rtp_session->dtls && rtp_session->dtls->state != DS_READY) { + send = 0; + } if (send) { send_msg->header.seq = htons(++rtp_session->seq);