Exemplo n.º 1
0
void janus_dtls_srtp_incoming_msg(janus_dtls_srtp *dtls, char *buf, uint16_t len) {
	if(dtls == NULL) {
		JANUS_LOG(LOG_ERR, "No DTLS-SRTP stack, no incoming message...\n");
		return;
	}
	janus_ice_component *component = (janus_ice_component *)dtls->component;
	if(component == NULL) {
		JANUS_LOG(LOG_ERR, "No component, no DTLS...\n");
		return;
	}
	janus_ice_stream *stream = component->stream;
	if(!stream) {
		JANUS_LOG(LOG_ERR, "No stream, no DTLS...\n");
		return;
	}
	janus_ice_handle *handle = stream->handle;
	if(!handle || !handle->agent) {
		JANUS_LOG(LOG_ERR, "No handle/agent, no DTLS...\n");
		return;
	}
	if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT)) {
		JANUS_LOG(LOG_ERR, "Alert already received, clearing up...\n");
		return;
	}
	if(!dtls->ssl || !dtls->read_bio) {
		JANUS_LOG(LOG_ERR, "[%"SCNu64"] No DTLS stuff for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id);
		return;
	}
	/* We just got a message, can we get rid of the last sent message? */
	if(dtls->dtls_last_msg != NULL) {
		g_free(dtls->dtls_last_msg);
		dtls->dtls_last_msg = NULL;
		dtls->dtls_last_len = 0;
	}
	janus_dtls_fd_bridge(dtls);
	int written = BIO_write(dtls->read_bio, buf, len);
	JANUS_LOG(LOG_HUGE, "    Written %d of those bytes on the read BIO...\n", written);
	janus_dtls_fd_bridge(dtls);
	int read = SSL_read(dtls->ssl, buf, len);
	JANUS_LOG(LOG_HUGE, "    ...and read %d of them from SSL...\n", read);
	janus_dtls_fd_bridge(dtls);
	if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP) || janus_is_stopping()) {
		/* DTLS alert received, we should end it here */
		JANUS_LOG(LOG_VERB, "[%"SCNu64"] Forced to stop it here...\n", handle->handle_id);
		return;
	}
	if(SSL_is_init_finished(dtls->ssl)) {
		JANUS_LOG(LOG_VERB, "[%"SCNu64"] DTLS established, yay!\n", handle->handle_id);
		/* Check the remote fingerprint */
		X509 *rcert = SSL_get_peer_certificate(dtls->ssl);
		if(!rcert) {
			JANUS_LOG(LOG_ERR, "[%"SCNu64"] No remote certificate??\n", handle->handle_id);
		} else {
			unsigned int rsize;
			unsigned char rfingerprint[EVP_MAX_MD_SIZE];
			char remote_fingerprint[160];
			char *rfp = (char *)&remote_fingerprint;
			if(handle->remote_hashing && !strcasecmp(handle->remote_hashing, "sha-1")) {
				JANUS_LOG(LOG_VERB, "[%"SCNu64"] Computing sha-1 fingerprint of remote certificate...\n", handle->handle_id);
				X509_digest(rcert, EVP_sha1(), (unsigned char *)rfingerprint, &rsize);
			} else {
				JANUS_LOG(LOG_VERB, "[%"SCNu64"] Computing sha-256 fingerprint of remote certificate...\n", handle->handle_id);
				X509_digest(rcert, EVP_sha256(), (unsigned char *)rfingerprint, &rsize);
			}
			X509_free(rcert);
			rcert = NULL;
			int i = 0;
			for(i = 0; i < rsize; i++) {
				sprintf(rfp, "%.2X:", rfingerprint[i]);
				rfp += 3;
			}
			*(rfp-1) = 0;
			JANUS_LOG(LOG_VERB, "[%"SCNu64"] Remote fingerprint (%s) of the client is %s\n",
				handle->handle_id, handle->remote_hashing ? handle->remote_hashing : "sha-256", remote_fingerprint);
			if(!strcasecmp(remote_fingerprint, handle->remote_fingerprint ? handle->remote_fingerprint : "(none)")) {
				JANUS_LOG(LOG_VERB, "[%"SCNu64"]  Fingerprint is a match!\n", handle->handle_id);
				dtls->dtls_state = JANUS_DTLS_STATE_CONNECTED;
			} else {
				/* FIXME NOT a match! MITM? */
				JANUS_LOG(LOG_ERR, "[%"SCNu64"]  Fingerprint is NOT a match! expected %s\n", handle->handle_id, handle->remote_fingerprint);
				dtls->dtls_state = JANUS_DTLS_STATE_FAILED;
				goto done;
			}
			if(dtls->dtls_state == JANUS_DTLS_STATE_CONNECTED) {
				/* Complete with SRTP setup */
				unsigned char material[SRTP_MASTER_LENGTH*2];
				unsigned char *local_key, *local_salt, *remote_key, *remote_salt;
				/* Export keying material for SRTP */
				if (!SSL_export_keying_material(dtls->ssl, material, SRTP_MASTER_LENGTH*2, "EXTRACTOR-dtls_srtp", 19, NULL, 0, 0)) {
					/* Oops... */
					JANUS_LOG(LOG_ERR, "[%"SCNu64"] Oops, couldn't extract SRTP keying material for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id);
					goto done;
				}
				/* Key derivation (http://tools.ietf.org/html/rfc5764#section-4.2) */
				if(dtls->dtls_role == JANUS_DTLS_ROLE_CLIENT) {
					local_key = material;
					remote_key = local_key + SRTP_MASTER_KEY_LENGTH;
					local_salt = remote_key + SRTP_MASTER_KEY_LENGTH;
					remote_salt = local_salt + SRTP_MASTER_SALT_LENGTH;
				} else {
					remote_key = material;
					local_key = remote_key + SRTP_MASTER_KEY_LENGTH;
					remote_salt = local_key + SRTP_MASTER_KEY_LENGTH;
					local_salt = remote_salt + SRTP_MASTER_SALT_LENGTH;
				}
				/* Build master keys and set SRTP policies */
					/* Remote (inbound) */
				crypto_policy_set_rtp_default(&(dtls->remote_policy.rtp));
				crypto_policy_set_rtcp_default(&(dtls->remote_policy.rtcp));
				dtls->remote_policy.ssrc.type = ssrc_any_inbound;
				dtls->remote_policy.key = calloc(SRTP_MASTER_LENGTH+8, sizeof(char));
				if(dtls->remote_policy.key == NULL) {
					JANUS_LOG(LOG_FATAL, "Memory error!\n");
					goto done;
				}
				memcpy(dtls->remote_policy.key, remote_key, SRTP_MASTER_KEY_LENGTH);
				memcpy(dtls->remote_policy.key + SRTP_MASTER_KEY_LENGTH, remote_salt, SRTP_MASTER_SALT_LENGTH);
				dtls->remote_policy.window_size = 128;
				dtls->remote_policy.allow_repeat_tx = 0;
				dtls->remote_policy.next = NULL;
					/* Local (outbound) */
				crypto_policy_set_rtp_default(&(dtls->local_policy.rtp));
				crypto_policy_set_rtcp_default(&(dtls->local_policy.rtcp));
				dtls->local_policy.ssrc.type = ssrc_any_outbound;
				dtls->local_policy.key = calloc(SRTP_MASTER_LENGTH+8, sizeof(char));
				if(dtls->local_policy.key == NULL) {
					JANUS_LOG(LOG_FATAL, "Memory error!\n");
					goto done;
				}
				memcpy(dtls->local_policy.key, local_key, SRTP_MASTER_KEY_LENGTH);
				memcpy(dtls->local_policy.key + SRTP_MASTER_KEY_LENGTH, local_salt, SRTP_MASTER_SALT_LENGTH);
				dtls->local_policy.window_size = 128;
				dtls->local_policy.allow_repeat_tx = 0;
				dtls->local_policy.next = NULL;
				/* Create SRTP sessions */
				err_status_t res = srtp_create(&(dtls->srtp_in), &(dtls->remote_policy));
				if(res != err_status_ok) {
					/* Something went wrong... */
					JANUS_LOG(LOG_ERR, "[%"SCNu64"] Oops, error creating inbound SRTP session for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id);
					JANUS_LOG(LOG_ERR, "[%"SCNu64"]  -- %d (%s)\n", handle->handle_id, res, janus_get_srtp_error(res));
					goto done;
				}
				JANUS_LOG(LOG_VERB, "[%"SCNu64"] Created inbound SRTP session for component %d in stream %d\n", handle->handle_id, component->component_id, stream->stream_id);
				res = srtp_create(&(dtls->srtp_out), &(dtls->local_policy));
				if(res != err_status_ok) {
					/* Something went wrong... */
					JANUS_LOG(LOG_ERR, "[%"SCNu64"] Oops, error creating outbound SRTP session for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id);
					JANUS_LOG(LOG_ERR, "[%"SCNu64"]  -- %d (%s)\n", handle->handle_id, res, janus_get_srtp_error(res));
					goto done;
				}
				dtls->srtp_valid = 1;
				JANUS_LOG(LOG_VERB, "[%"SCNu64"] Created outbound SRTP session for component %d in stream %d\n", handle->handle_id, component->component_id, stream->stream_id);
			}
done:
			if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && dtls->srtp_valid) {
				/* Handshake successfully completed */
				janus_ice_dtls_handshake_done(handle, component);
			} else {
				/* Something went wrong in either DTLS or SRTP... tell the plugin about it */
				janus_dtls_callback(dtls->ssl, SSL_CB_ALERT, 0);
			}
		}
	}
}
Exemplo n.º 2
0
void janus_dtls_srtp_incoming_msg(janus_dtls_srtp *dtls, char *buf, uint16_t len) {
	if(dtls == NULL) {
		JANUS_LOG(LOG_ERR, "No DTLS-SRTP stack, no incoming message...\n");
		return;
	}
	janus_ice_component *component = (janus_ice_component *)dtls->component;
	if(component == NULL) {
		JANUS_LOG(LOG_ERR, "No component, no DTLS...\n");
		return;
	}
	janus_ice_stream *stream = component->stream;
	if(!stream) {
		JANUS_LOG(LOG_ERR, "No stream, no DTLS...\n");
		return;
	}
	janus_ice_handle *handle = stream->handle;
	if(!handle || !handle->agent) {
		JANUS_LOG(LOG_ERR, "No handle/agent, no DTLS...\n");
		return;
	}
	if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT)) {
		JANUS_LOG(LOG_WARN, "[%"SCNu64"] Alert already triggered, clearing up...\n", handle->handle_id);
		return;
	}
	if(!dtls->ssl || !dtls->read_bio) {
		JANUS_LOG(LOG_ERR, "[%"SCNu64"] No DTLS stuff for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id);
		return;
	}
	janus_dtls_fd_bridge(dtls);
	int written = BIO_write(dtls->read_bio, buf, len);
	JANUS_LOG(LOG_HUGE, "[%"SCNu64"]     Written %d of those bytes on the read BIO...\n", handle->handle_id, written);
	janus_dtls_fd_bridge(dtls);
	/* Try to read data */
	char data[1500];	/* FIXME */
	memset(&data, 0, 1500);
	int read = SSL_read(dtls->ssl, &data, 1500);
	JANUS_LOG(LOG_HUGE, "[%"SCNu64"]     ... and read %d of them from SSL...\n", handle->handle_id, read);
	if(read < 0) {
		unsigned long err = SSL_get_error(dtls->ssl, read);
		if(err == SSL_ERROR_SSL) {
			/* Ops, something went wrong with the DTLS handshake */
			char error[200];
			ERR_error_string_n(ERR_get_error(), error, 200);
			JANUS_LOG(LOG_ERR, "[%"SCNu64"] Handshake error: %s\n", handle->handle_id, error);
			return;
		}
	}
	janus_dtls_fd_bridge(dtls);
	if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP) || janus_is_stopping()) {
		/* DTLS alert triggered, we should end it here */
		JANUS_LOG(LOG_VERB, "[%"SCNu64"] Forced to stop it here...\n", handle->handle_id);
		return;
	}
	if(!SSL_is_init_finished(dtls->ssl)) {
		/* Nothing else to do for now */
		JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Initialization not finished yet...\n", handle->handle_id);
		return;
	}
	if(dtls->ready) {
		/* There's data to be read? */
		JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Any data available?\n", handle->handle_id);
#ifdef HAVE_SCTP
		if(dtls->sctp != NULL && read > 0) {
			JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Sending data (%d bytes) to the SCTP stack...\n", handle->handle_id, read);
			janus_sctp_data_from_dtls(dtls->sctp, data, read);
		}
#else
		if(read > 0) {
			JANUS_LOG(LOG_WARN, "[%"SCNu64"] Data available but Data Channels support disabled...\n", handle->handle_id);
		}
#endif
	} else {
		JANUS_LOG(LOG_VERB, "[%"SCNu64"] DTLS established, yay!\n", handle->handle_id);
		/* Check the remote fingerprint */
		X509 *rcert = SSL_get_peer_certificate(dtls->ssl);
		if(!rcert) {
			JANUS_LOG(LOG_ERR, "[%"SCNu64"] No remote certificate??\n", handle->handle_id);
		} else {
			unsigned int rsize;
			unsigned char rfingerprint[EVP_MAX_MD_SIZE];
			char remote_fingerprint[160];
			char *rfp = (char *)&remote_fingerprint;
			if(handle->remote_hashing && !strcasecmp(handle->remote_hashing, "sha-1")) {
				JANUS_LOG(LOG_VERB, "[%"SCNu64"] Computing sha-1 fingerprint of remote certificate...\n", handle->handle_id);
				X509_digest(rcert, EVP_sha1(), (unsigned char *)rfingerprint, &rsize);
			} else {
				JANUS_LOG(LOG_VERB, "[%"SCNu64"] Computing sha-256 fingerprint of remote certificate...\n", handle->handle_id);
				X509_digest(rcert, EVP_sha256(), (unsigned char *)rfingerprint, &rsize);
			}
			X509_free(rcert);
			rcert = NULL;
			unsigned int i = 0;
			for(i = 0; i < rsize; i++) {
				g_snprintf(rfp, 4, "%.2X:", rfingerprint[i]);
				rfp += 3;
			}
			*(rfp-1) = 0;
			JANUS_LOG(LOG_VERB, "[%"SCNu64"] Remote fingerprint (%s) of the client is %s\n",
				handle->handle_id, handle->remote_hashing ? handle->remote_hashing : "sha-256", remote_fingerprint);
			if(!strcasecmp(remote_fingerprint, handle->remote_fingerprint ? handle->remote_fingerprint : "(none)")) {
				JANUS_LOG(LOG_VERB, "[%"SCNu64"]  Fingerprint is a match!\n", handle->handle_id);
				dtls->dtls_state = JANUS_DTLS_STATE_CONNECTED;
				dtls->dtls_connected = janus_get_monotonic_time();
			} else {
				/* FIXME NOT a match! MITM? */
				JANUS_LOG(LOG_ERR, "[%"SCNu64"]  Fingerprint is NOT a match! got %s, expected %s\n", handle->handle_id, remote_fingerprint, handle->remote_fingerprint);
				dtls->dtls_state = JANUS_DTLS_STATE_FAILED;
				goto done;
			}
			if(dtls->dtls_state == JANUS_DTLS_STATE_CONNECTED) {
				if(component->stream_id == handle->audio_id || component->stream_id == handle->video_id) {
					/* Complete with SRTP setup */
					unsigned char material[SRTP_MASTER_LENGTH*2];
					unsigned char *local_key, *local_salt, *remote_key, *remote_salt;
					/* Export keying material for SRTP */
					if (!SSL_export_keying_material(dtls->ssl, material, SRTP_MASTER_LENGTH*2, "EXTRACTOR-dtls_srtp", 19, NULL, 0, 0)) {
						/* Oops... */
						JANUS_LOG(LOG_ERR, "[%"SCNu64"] Oops, couldn't extract SRTP keying material for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id);
						goto done;
					}
					/* Key derivation (http://tools.ietf.org/html/rfc5764#section-4.2) */
					if(dtls->dtls_role == JANUS_DTLS_ROLE_CLIENT) {
						local_key = material;
						remote_key = local_key + SRTP_MASTER_KEY_LENGTH;
						local_salt = remote_key + SRTP_MASTER_KEY_LENGTH;
						remote_salt = local_salt + SRTP_MASTER_SALT_LENGTH;
					} else {
						remote_key = material;
						local_key = remote_key + SRTP_MASTER_KEY_LENGTH;
						remote_salt = local_key + SRTP_MASTER_KEY_LENGTH;
						local_salt = remote_salt + SRTP_MASTER_SALT_LENGTH;
					}
					/* Build master keys and set SRTP policies */
						/* Remote (inbound) */
					crypto_policy_set_rtp_default(&(dtls->remote_policy.rtp));
					crypto_policy_set_rtcp_default(&(dtls->remote_policy.rtcp));
					dtls->remote_policy.ssrc.type = ssrc_any_inbound;
					unsigned char remote_policy_key[SRTP_MASTER_LENGTH];
					dtls->remote_policy.key = (unsigned char *)&remote_policy_key;
					memcpy(dtls->remote_policy.key, remote_key, SRTP_MASTER_KEY_LENGTH);
					memcpy(dtls->remote_policy.key + SRTP_MASTER_KEY_LENGTH, remote_salt, SRTP_MASTER_SALT_LENGTH);
#if HAS_DTLS_WINDOW_SIZE
					dtls->remote_policy.window_size = 128;
					dtls->remote_policy.allow_repeat_tx = 0;
#endif
					dtls->remote_policy.next = NULL;
						/* Local (outbound) */
					crypto_policy_set_rtp_default(&(dtls->local_policy.rtp));
					crypto_policy_set_rtcp_default(&(dtls->local_policy.rtcp));
					dtls->local_policy.ssrc.type = ssrc_any_outbound;
					unsigned char local_policy_key[SRTP_MASTER_LENGTH];
					dtls->local_policy.key = (unsigned char *)&local_policy_key;
					memcpy(dtls->local_policy.key, local_key, SRTP_MASTER_KEY_LENGTH);
					memcpy(dtls->local_policy.key + SRTP_MASTER_KEY_LENGTH, local_salt, SRTP_MASTER_SALT_LENGTH);
#if HAS_DTLS_WINDOW_SIZE
					dtls->local_policy.window_size = 128;
					dtls->local_policy.allow_repeat_tx = 0;
#endif
					dtls->local_policy.next = NULL;
					/* Create SRTP sessions */
					err_status_t res = srtp_create(&(dtls->srtp_in), &(dtls->remote_policy));
					if(res != err_status_ok) {
						/* Something went wrong... */
						JANUS_LOG(LOG_ERR, "[%"SCNu64"] Oops, error creating inbound SRTP session for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id);
						JANUS_LOG(LOG_ERR, "[%"SCNu64"]  -- %d (%s)\n", handle->handle_id, res, janus_get_srtp_error(res));
						goto done;
					}
					JANUS_LOG(LOG_VERB, "[%"SCNu64"] Created inbound SRTP session for component %d in stream %d\n", handle->handle_id, component->component_id, stream->stream_id);
					res = srtp_create(&(dtls->srtp_out), &(dtls->local_policy));
					if(res != err_status_ok) {
						/* Something went wrong... */
						JANUS_LOG(LOG_ERR, "[%"SCNu64"] Oops, error creating outbound SRTP session for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id);
						JANUS_LOG(LOG_ERR, "[%"SCNu64"]  -- %d (%s)\n", handle->handle_id, res, janus_get_srtp_error(res));
						goto done;
					}
					dtls->srtp_valid = 1;
					JANUS_LOG(LOG_VERB, "[%"SCNu64"] Created outbound SRTP session for component %d in stream %d\n", handle->handle_id, component->component_id, stream->stream_id);
				}
#ifdef HAVE_SCTP
				if(component->stream_id == handle->data_id ||
						(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE) &&
						janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_DATA_CHANNELS))) {
					/* FIXME Create SCTP association as well (5000 should be dynamic, from the SDP...) */
					dtls->sctp = janus_sctp_association_create(dtls, handle->handle_id, 5000);
					if(dtls->sctp != NULL) {
						/* FIXME We need to start it in a thread, though, since it has blocking accept/connect stuff */
						GError *error = NULL;
						g_thread_try_new("DTLS-SCTP", janus_dtls_sctp_setup_thread, dtls, &error);
						if(error != NULL) {
							/* Something went wrong... */
							JANUS_LOG(LOG_ERR, "[%"SCNu64"] Got error %d (%s) trying to launch the DTLS-SCTP thread...\n", handle->handle_id, error->code, error->message ? error->message : "??");
						}
						dtls->srtp_valid = 1;
					}
				}
#endif
				dtls->ready = 1;
			}
done:
			if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && dtls->srtp_valid) {
				/* Handshake successfully completed */
				janus_ice_dtls_handshake_done(handle, component);
			} else {
				/* Something went wrong in either DTLS or SRTP... tell the plugin about it */
				janus_dtls_callback(dtls->ssl, SSL_CB_ALERT, 0);
				janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_CLEANING);
			}
		}
	}
}
Exemplo n.º 3
0
void janus_dtls_srtp_incoming_msg(janus_dtls_srtp *dtls, char *buf, uint16_t len) {
	if(dtls == NULL) {
		JANUS_LOG(LOG_ERR, "No DTLS-SRTP stack, no incoming message...\n");
		return;
	}
	janus_ice_component *component = (janus_ice_component *)dtls->component;
	if(component == NULL) {
		JANUS_LOG(LOG_ERR, "No component, no DTLS...\n");
		return;
	}
	janus_ice_stream *stream = component->stream;
	if(!stream) {
		JANUS_LOG(LOG_ERR, "No stream, no DTLS...\n");
		return;
	}
	janus_ice_handle *handle = stream->handle;
	if(!handle || !handle->agent) {
		JANUS_LOG(LOG_ERR, "No handle/agent, no DTLS...\n");
		return;
	}
	if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT)) {
		JANUS_LOG(LOG_WARN, "[%"SCNu64"] Alert already triggered, clearing up...\n", handle->handle_id);
		return;
	}
	if(!dtls->ssl || !dtls->read_bio) {
		JANUS_LOG(LOG_ERR, "[%"SCNu64"] No DTLS stuff for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id);
		return;
	}
	if(dtls->dtls_started == 0) {
		/* Handshake not started yet: maybe we're still waiting for the answer and the DTLS role? */
		return;
	}
	janus_dtls_fd_bridge(dtls);
	int written = BIO_write(dtls->read_bio, buf, len);
	if(written != len) {
		JANUS_LOG(LOG_WARN, "[%"SCNu64"]     Only written %d/%d of those bytes on the read BIO...\n", handle->handle_id, written, len);
	} else {
		JANUS_LOG(LOG_HUGE, "[%"SCNu64"]     Written %d bytes on the read BIO...\n", handle->handle_id, written);
	}
	janus_dtls_fd_bridge(dtls);
	/* Try to read data */
	char data[1500];	/* FIXME */
	memset(&data, 0, 1500);
	int read = SSL_read(dtls->ssl, &data, 1500);
	JANUS_LOG(LOG_HUGE, "[%"SCNu64"]     ... and read %d of them from SSL...\n", handle->handle_id, read);
	if(read < 0) {
		unsigned long err = SSL_get_error(dtls->ssl, read);
		if(err == SSL_ERROR_SSL) {
			/* Ops, something went wrong with the DTLS handshake */
			char error[200];
			ERR_error_string_n(ERR_get_error(), error, 200);
			JANUS_LOG(LOG_ERR, "[%"SCNu64"] Handshake error: %s\n", handle->handle_id, error);
			return;
		}
	}
	janus_dtls_fd_bridge(dtls);
	if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP) || janus_is_stopping()) {
		/* DTLS alert triggered, we should end it here */
		JANUS_LOG(LOG_VERB, "[%"SCNu64"] Forced to stop it here...\n", handle->handle_id);
		return;
	}
	if(!SSL_is_init_finished(dtls->ssl)) {
		/* Nothing else to do for now */
		JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Initialization not finished yet...\n", handle->handle_id);
		return;
	}
	if(dtls->ready) {
		/* There's data to be read? */
		JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Any data available?\n", handle->handle_id);
#ifdef HAVE_SCTP
		if(dtls->sctp != NULL && read > 0) {
			JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Sending data (%d bytes) to the SCTP stack...\n", handle->handle_id, read);
			janus_sctp_data_from_dtls(dtls->sctp, data, read);
		}
#else
		if(read > 0) {
			JANUS_LOG(LOG_WARN, "[%"SCNu64"] Data available but Data Channels support disabled...\n", handle->handle_id);
		}
#endif
	} else {
		JANUS_LOG(LOG_VERB, "[%"SCNu64"] DTLS established, yay!\n", handle->handle_id);
		/* Check the remote fingerprint */
		X509 *rcert = SSL_get_peer_certificate(dtls->ssl);
		if(!rcert) {
			JANUS_LOG(LOG_ERR, "[%"SCNu64"] No remote certificate?? (%s)\n",
				handle->handle_id, ERR_reason_error_string(ERR_get_error()));
		} else {
			unsigned int rsize;
			unsigned char rfingerprint[EVP_MAX_MD_SIZE];
			char remote_fingerprint[160];
			char *rfp = (char *)&remote_fingerprint;
			if(stream->remote_hashing && !strcasecmp(stream->remote_hashing, "sha-1")) {
				JANUS_LOG(LOG_VERB, "[%"SCNu64"] Computing sha-1 fingerprint of remote certificate...\n", handle->handle_id);
				X509_digest(rcert, EVP_sha1(), (unsigned char *)rfingerprint, &rsize);
			} else {
				JANUS_LOG(LOG_VERB, "[%"SCNu64"] Computing sha-256 fingerprint of remote certificate...\n", handle->handle_id);
				X509_digest(rcert, EVP_sha256(), (unsigned char *)rfingerprint, &rsize);
			}
			X509_free(rcert);
			rcert = NULL;
			unsigned int i = 0;
			for(i = 0; i < rsize; i++) {
				g_snprintf(rfp, 4, "%.2X:", rfingerprint[i]);
				rfp += 3;
			}
			*(rfp-1) = 0;
			JANUS_LOG(LOG_VERB, "[%"SCNu64"] Remote fingerprint (%s) of the client is %s\n",
				handle->handle_id, stream->remote_hashing ? stream->remote_hashing : "sha-256", remote_fingerprint);
			if(!strcasecmp(remote_fingerprint, stream->remote_fingerprint ? stream->remote_fingerprint : "(none)")) {
				JANUS_LOG(LOG_VERB, "[%"SCNu64"]  Fingerprint is a match!\n", handle->handle_id);
				dtls->dtls_state = JANUS_DTLS_STATE_CONNECTED;
				dtls->dtls_connected = janus_get_monotonic_time();
				/* Notify event handlers */
				janus_dtls_notify_state_change(dtls);
			} else {
				/* FIXME NOT a match! MITM? */
				JANUS_LOG(LOG_ERR, "[%"SCNu64"]  Fingerprint is NOT a match! got %s, expected %s\n", handle->handle_id, remote_fingerprint, stream->remote_fingerprint);
				dtls->dtls_state = JANUS_DTLS_STATE_FAILED;
				/* Notify event handlers */
				janus_dtls_notify_state_change(dtls);
				goto done;
			}
			if(dtls->dtls_state == JANUS_DTLS_STATE_CONNECTED) {
				/* Which SRTP profile is being negotiated? */
				SRTP_PROTECTION_PROFILE *srtp_profile = SSL_get_selected_srtp_profile(dtls->ssl);
				if(srtp_profile == NULL) {
					/* Should never happen, but just in case... */
					JANUS_LOG(LOG_ERR, "[%"SCNu64"] No SRTP profile selected...\n", handle->handle_id);
					dtls->dtls_state = JANUS_DTLS_STATE_FAILED;
					/* Notify event handlers */
					janus_dtls_notify_state_change(dtls);
					goto done;
				}
				JANUS_LOG(LOG_VERB, "[%"SCNu64"] %s\n", handle->handle_id, srtp_profile->name);
				int key_length = 0, salt_length = 0, master_length = 0;
				switch(srtp_profile->id) {
					case SRTP_AES128_CM_SHA1_80:
					case SRTP_AES128_CM_SHA1_32:
						key_length = SRTP_MASTER_KEY_LENGTH;
						salt_length = SRTP_MASTER_SALT_LENGTH;
						master_length = SRTP_MASTER_LENGTH;
						break;
#ifdef HAVE_SRTP_AESGCM
					case SRTP_AEAD_AES_256_GCM:
						key_length = SRTP_AESGCM256_MASTER_KEY_LENGTH;
						salt_length = SRTP_AESGCM256_MASTER_SALT_LENGTH;
						master_length = SRTP_AESGCM256_MASTER_LENGTH;
						break;
					case SRTP_AEAD_AES_128_GCM:
						key_length = SRTP_AESGCM128_MASTER_KEY_LENGTH;
						salt_length = SRTP_AESGCM128_MASTER_SALT_LENGTH;
						master_length = SRTP_AESGCM128_MASTER_LENGTH;
						break;
#endif
					default:
						/* Will never happen? */
						JANUS_LOG(LOG_WARN, "[%"SCNu64"] Unsupported SRTP profile %lu\n", handle->handle_id, srtp_profile->id);
						break;
				}
				JANUS_LOG(LOG_VERB, "[%"SCNu64"] Key/Salt/Master: %d/%d/%d\n",
					handle->handle_id, master_length, key_length, salt_length);
				/* Complete with SRTP setup */
				unsigned char material[master_length*2];
				unsigned char *local_key, *local_salt, *remote_key, *remote_salt;
				/* Export keying material for SRTP */
				if(!SSL_export_keying_material(dtls->ssl, material, master_length*2, "EXTRACTOR-dtls_srtp", 19, NULL, 0, 0)) {
					/* Oops... */
					JANUS_LOG(LOG_ERR, "[%"SCNu64"] Oops, couldn't extract SRTP keying material for component %d in stream %d?? (%s)\n",
						handle->handle_id, component->component_id, stream->stream_id, ERR_reason_error_string(ERR_get_error()));
					goto done;
				}
				/* Key derivation (http://tools.ietf.org/html/rfc5764#section-4.2) */
				if(dtls->dtls_role == JANUS_DTLS_ROLE_CLIENT) {
					local_key = material;
					remote_key = local_key + key_length;
					local_salt = remote_key + key_length;
					remote_salt = local_salt + salt_length;
				} else {
					remote_key = material;
					local_key = remote_key + key_length;
					remote_salt = local_key + key_length;
					local_salt = remote_salt + salt_length;
				}
				/* Build master keys and set SRTP policies */
					/* Remote (inbound) */
				switch(srtp_profile->id) {
					case SRTP_AES128_CM_SHA1_80:
						srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&(dtls->remote_policy.rtp));
						srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&(dtls->remote_policy.rtcp));
						break;
					case SRTP_AES128_CM_SHA1_32:
						srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32(&(dtls->remote_policy.rtp));
						srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&(dtls->remote_policy.rtcp));
						break;
#ifdef HAVE_SRTP_AESGCM
					case SRTP_AEAD_AES_256_GCM:
						srtp_crypto_policy_set_aes_gcm_256_16_auth(&(dtls->remote_policy.rtp));
						srtp_crypto_policy_set_aes_gcm_256_16_auth(&(dtls->remote_policy.rtcp));
						break;
					case SRTP_AEAD_AES_128_GCM:
						srtp_crypto_policy_set_aes_gcm_128_16_auth(&(dtls->remote_policy.rtp));
						srtp_crypto_policy_set_aes_gcm_128_16_auth(&(dtls->remote_policy.rtcp));
						break;
#endif
					default:
						/* Will never happen? */
						JANUS_LOG(LOG_WARN, "[%"SCNu64"] Unsupported SRTP profile %s\n", handle->handle_id, srtp_profile->name);
						break;
				}
				dtls->remote_policy.ssrc.type = ssrc_any_inbound;
				unsigned char remote_policy_key[master_length];
				dtls->remote_policy.key = (unsigned char *)&remote_policy_key;
				memcpy(dtls->remote_policy.key, remote_key, key_length);
				memcpy(dtls->remote_policy.key + key_length, remote_salt, salt_length);
#if HAS_DTLS_WINDOW_SIZE
				dtls->remote_policy.window_size = 128;
				dtls->remote_policy.allow_repeat_tx = 0;
#endif
				dtls->remote_policy.next = NULL;
					/* Local (outbound) */
				switch(srtp_profile->id) {
					case SRTP_AES128_CM_SHA1_80:
						srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&(dtls->local_policy.rtp));
						srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&(dtls->local_policy.rtcp));
						break;
					case SRTP_AES128_CM_SHA1_32:
						srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32(&(dtls->local_policy.rtp));
						srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&(dtls->local_policy.rtcp));
						break;
#ifdef HAVE_SRTP_AESGCM
					case SRTP_AEAD_AES_256_GCM:
						srtp_crypto_policy_set_aes_gcm_256_16_auth(&(dtls->local_policy.rtp));
						srtp_crypto_policy_set_aes_gcm_256_16_auth(&(dtls->local_policy.rtcp));
						break;
					case SRTP_AEAD_AES_128_GCM:
						srtp_crypto_policy_set_aes_gcm_128_16_auth(&(dtls->local_policy.rtp));
						srtp_crypto_policy_set_aes_gcm_128_16_auth(&(dtls->local_policy.rtcp));
						break;
#endif
					default:
						/* Will never happen? */
						JANUS_LOG(LOG_WARN, "[%"SCNu64"] Unsupported SRTP profile %s\n", handle->handle_id, srtp_profile->name);
						break;
				}
				dtls->local_policy.ssrc.type = ssrc_any_outbound;
				unsigned char local_policy_key[master_length];
				dtls->local_policy.key = (unsigned char *)&local_policy_key;
				memcpy(dtls->local_policy.key, local_key, key_length);
				memcpy(dtls->local_policy.key + key_length, local_salt, salt_length);
#if HAS_DTLS_WINDOW_SIZE
				dtls->local_policy.window_size = 128;
				dtls->local_policy.allow_repeat_tx = 0;
#endif
				dtls->local_policy.next = NULL;
				/* Create SRTP sessions */
				srtp_err_status_t res = srtp_create(&(dtls->srtp_in), &(dtls->remote_policy));
				if(res != srtp_err_status_ok) {
					/* Something went wrong... */
					JANUS_LOG(LOG_ERR, "[%"SCNu64"] Oops, error creating inbound SRTP session for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id);
					JANUS_LOG(LOG_ERR, "[%"SCNu64"]  -- %d (%s)\n", handle->handle_id, res, janus_srtp_error_str(res));
					goto done;
				}
				JANUS_LOG(LOG_VERB, "[%"SCNu64"] Created inbound SRTP session for component %d in stream %d\n", handle->handle_id, component->component_id, stream->stream_id);
				res = srtp_create(&(dtls->srtp_out), &(dtls->local_policy));
				if(res != srtp_err_status_ok) {
					/* Something went wrong... */
					JANUS_LOG(LOG_ERR, "[%"SCNu64"] Oops, error creating outbound SRTP session for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id);
					JANUS_LOG(LOG_ERR, "[%"SCNu64"]  -- %d (%s)\n", handle->handle_id, res, janus_srtp_error_str(res));
					goto done;
				}
				dtls->srtp_profile = srtp_profile->id;
				dtls->srtp_valid = 1;
				JANUS_LOG(LOG_VERB, "[%"SCNu64"] Created outbound SRTP session for component %d in stream %d\n", handle->handle_id, component->component_id, stream->stream_id);
#ifdef HAVE_SCTP
				if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_DATA_CHANNELS)) {
					/* Create SCTP association as well */
					janus_dtls_srtp_create_sctp(dtls);
				}
#endif
				dtls->ready = 1;
			}
done:
			if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && dtls->srtp_valid) {
				/* Handshake successfully completed */
				janus_ice_dtls_handshake_done(handle, component);
			} else {
				/* Something went wrong in either DTLS or SRTP... tell the plugin about it */
				janus_dtls_callback(dtls->ssl, SSL_CB_ALERT, 0);
				janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_CLEANING);
			}
		}
	}
}