janus_dtls_srtp *janus_dtls_srtp_create(void *ice_component, janus_dtls_role role) { janus_ice_component *component = (janus_ice_component *)ice_component; if(component == NULL) { JANUS_LOG(LOG_ERR, "No component, no DTLS...\n"); return NULL; } janus_ice_stream *stream = component->stream; if(!stream) { JANUS_LOG(LOG_ERR, "No stream, no DTLS...\n"); return NULL; } janus_ice_handle *handle = stream->handle; if(!handle || !handle->agent) { JANUS_LOG(LOG_ERR, "No handle/agent, no DTLS...\n"); return NULL; } janus_dtls_srtp *dtls = g_malloc0(sizeof(janus_dtls_srtp)); if(dtls == NULL) { JANUS_LOG(LOG_FATAL, "Memory error!\n"); return NULL; } /* Create SSL context, at last */ dtls->srtp_valid = 0; dtls->ssl = SSL_new(janus_dtls_get_ssl_ctx()); if(!dtls->ssl) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] No component DTLS SSL session??\n", handle->handle_id); janus_dtls_srtp_destroy(dtls); return NULL; } SSL_set_ex_data(dtls->ssl, 0, dtls); SSL_set_info_callback(dtls->ssl, janus_dtls_callback); dtls->read_bio = BIO_new(BIO_s_mem()); if(!dtls->read_bio) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error creating read BIO!\n", handle->handle_id); janus_dtls_srtp_destroy(dtls); return NULL; } BIO_set_mem_eof_return(dtls->read_bio, -1); dtls->write_bio = BIO_new(BIO_s_mem()); if(!dtls->write_bio) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error creating write BIO!\n", handle->handle_id); janus_dtls_srtp_destroy(dtls); return NULL; } BIO_set_mem_eof_return(dtls->write_bio, -1); /* The write BIO needs our custom filter, or fragmentation won't work */ dtls->filter_bio = BIO_new(BIO_janus_dtls_filter()); if(!dtls->filter_bio) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error creating filter BIO!\n", handle->handle_id); janus_dtls_srtp_destroy(dtls); return NULL; } /* Chain filter and write BIOs */ BIO_push(dtls->filter_bio, dtls->write_bio); /* Set the filter as the BIO to use for outgoing data */ SSL_set_bio(dtls->ssl, dtls->read_bio, dtls->filter_bio); dtls->dtls_role = role; if(dtls->dtls_role == JANUS_DTLS_ROLE_CLIENT) { JANUS_LOG(LOG_VERB, "[%"SCNu64"] Setting connect state (DTLS client)\n", handle->handle_id); SSL_set_connect_state(dtls->ssl); } else { JANUS_LOG(LOG_VERB, "[%"SCNu64"] Setting accept state (DTLS server)\n", handle->handle_id); SSL_set_accept_state(dtls->ssl); } /* https://code.google.com/p/chromium/issues/detail?id=406458 * Specify an ECDH group for ECDHE ciphers, otherwise they cannot be * negotiated when acting as the server. Use NIST's P-256 which is * commonly supported. */ EC_KEY* ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); if(ecdh == NULL) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error creating ECDH group!\n", handle->handle_id); janus_dtls_srtp_destroy(dtls); return NULL; } SSL_set_options(dtls->ssl, SSL_OP_SINGLE_ECDH_USE); SSL_set_tmp_ecdh(dtls->ssl, ecdh); EC_KEY_free(ecdh); dtls->ready = 0; #ifdef HAVE_SCTP dtls->sctp = NULL; #endif janus_mutex_init(&dtls->srtp_mutex); /* Done */ dtls->dtls_connected = 0; dtls->component = component; return dtls; }
janus_dtls_srtp *janus_dtls_srtp_create(void *ice_component, janus_dtls_role role) { janus_ice_component *component = (janus_ice_component *)ice_component; if(component == NULL) { JANUS_LOG(LOG_ERR, "No component, no DTLS...\n"); return NULL; } janus_ice_stream *stream = component->stream; if(!stream) { JANUS_LOG(LOG_ERR, "No stream, no DTLS...\n"); return NULL; } janus_ice_handle *handle = stream->handle; if(!handle || !handle->agent) { JANUS_LOG(LOG_ERR, "No handle/agent, no DTLS...\n"); return NULL; } janus_dtls_srtp *dtls = g_malloc0(sizeof(janus_dtls_srtp)); g_atomic_int_set(&dtls->destroyed, 0); janus_refcount_init(&dtls->ref, janus_dtls_srtp_free); /* Create SSL context, at last */ dtls->srtp_valid = 0; dtls->ssl = SSL_new(ssl_ctx); if(!dtls->ssl) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error creating DTLS session! (%s)\n", handle->handle_id, ERR_reason_error_string(ERR_get_error())); janus_refcount_decrease(&dtls->ref); return NULL; } SSL_set_ex_data(dtls->ssl, 0, dtls); SSL_set_info_callback(dtls->ssl, janus_dtls_callback); dtls->read_bio = BIO_new(BIO_s_mem()); if(!dtls->read_bio) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error creating read BIO! (%s)\n", handle->handle_id, ERR_reason_error_string(ERR_get_error())); janus_refcount_decrease(&dtls->ref); return NULL; } BIO_set_mem_eof_return(dtls->read_bio, -1); dtls->write_bio = BIO_new(BIO_s_mem()); if(!dtls->write_bio) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error creating write BIO! (%s)\n", handle->handle_id, ERR_reason_error_string(ERR_get_error())); janus_refcount_decrease(&dtls->ref); return NULL; } BIO_set_mem_eof_return(dtls->write_bio, -1); /* The write BIO needs our custom filter, or fragmentation won't work */ dtls->filter_bio = BIO_new(BIO_janus_dtls_filter()); if(!dtls->filter_bio) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error creating filter BIO! (%s)\n", handle->handle_id, ERR_reason_error_string(ERR_get_error())); janus_refcount_decrease(&dtls->ref); return NULL; } /* Chain filter and write BIOs */ BIO_push(dtls->filter_bio, dtls->write_bio); /* Set the filter as the BIO to use for outgoing data */ SSL_set_bio(dtls->ssl, dtls->read_bio, dtls->filter_bio); /* The role may change later, depending on the negotiation */ dtls->dtls_role = role; /* https://code.google.com/p/chromium/issues/detail?id=406458 * Specify an ECDH group for ECDHE ciphers, otherwise they cannot be * negotiated when acting as the server. Use NIST's P-256 which is * commonly supported. */ EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); if(ecdh == NULL) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error creating ECDH group! (%s)\n", handle->handle_id, ERR_reason_error_string(ERR_get_error())); janus_refcount_decrease(&dtls->ref); return NULL; } const long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION | SSL_OP_SINGLE_ECDH_USE; SSL_set_options(dtls->ssl, flags); SSL_set_tmp_ecdh(dtls->ssl, ecdh); EC_KEY_free(ecdh); #ifdef HAVE_DTLS_SETTIMEOUT guint ms = 100; JANUS_LOG(LOG_VERB, "[%"SCNu64"] Setting DTLS initial timeout: %u\n", handle->handle_id, ms); DTLSv1_set_initial_timeout_duration(dtls->ssl, ms); #endif dtls->ready = 0; dtls->retransmissions = 0; #ifdef HAVE_SCTP dtls->sctp = NULL; #endif /* Done */ dtls->dtls_connected = 0; dtls->component = component; return dtls; }