/* ECDH temporary parameters */ static int cmd_ECDHParameters(SSL_CONF_CTX *cctx, const char *value) { int rv = 1; EC_KEY *ecdh; int nid; /* Ignore values supported by 1.0.2 for the automatic selection */ if ((cctx->flags & SSL_CONF_FLAG_FILE) && strcasecmp(value, "+automatic") == 0) return 1; if ((cctx->flags & SSL_CONF_FLAG_CMDLINE) && strcmp(value, "auto") == 0) return 1; nid = EC_curve_nist2nid(value); if (nid == NID_undef) nid = OBJ_sn2nid(value); if (nid == 0) return 0; ecdh = EC_KEY_new_by_curve_name(nid); if (!ecdh) return 0; if (cctx->ctx) rv = SSL_CTX_set_tmp_ecdh(cctx->ctx, ecdh); else if (cctx->ssl) rv = SSL_set_tmp_ecdh(cctx->ssl, ecdh); EC_KEY_free(ecdh); return rv > 0; }
/* ECDH temporary parameters */ static int cmd_ECDHParameters(SSL_CONF_CTX *cctx, const char *value) { int onoff = -1, rv = 1; if (!(cctx->flags & SSL_CONF_FLAG_SERVER)) return -2; if (cctx->flags & SSL_CONF_FLAG_FILE) { if (*value == '+') { onoff = 1; value++; } if (*value == '-') { onoff = 0; value++; } if (!strcasecmp(value, "automatic")) { if (onoff == -1) onoff = 1; } else if (onoff != -1) return 0; } else if (cctx->flags & SSL_CONF_FLAG_CMDLINE) { if (!strcmp(value, "auto")) onoff = 1; } if (onoff != -1) { if (cctx->ctx) rv = SSL_CTX_set_ecdh_auto(cctx->ctx, onoff); else if (cctx->ssl) rv = SSL_set_ecdh_auto(cctx->ssl, onoff); } else { EC_KEY *ecdh; int nid; nid = EC_curve_nist2nid(value); if (nid == NID_undef) nid = OBJ_sn2nid(value); if (nid == 0) return 0; ecdh = EC_KEY_new_by_curve_name(nid); if (!ecdh) return 0; if (cctx->ctx) rv = SSL_CTX_set_tmp_ecdh(cctx->ctx, ecdh); else if (cctx->ssl) rv = SSL_set_tmp_ecdh(cctx->ssl, ecdh); EC_KEY_free(ecdh); } return rv > 0; }
struct dtls_transport * create_dtls_transport(struct rtcdc_peer_connection *peer, const struct dtls_context *context) { if (peer == NULL || peer->transport == NULL || context == NULL || context->ctx == NULL) return NULL; struct dtls_transport *dtls = (struct dtls_transport *)calloc(1, sizeof *dtls); if (dtls == NULL) return NULL; peer->transport->dtls = dtls; SSL *ssl = SSL_new(context->ctx); if (ssl == NULL) goto trans_err; dtls->ssl = ssl; BIO *bio = BIO_new(BIO_s_mem()); if (bio == NULL) goto trans_err; BIO_set_mem_eof_return(bio, -1); dtls->incoming_bio = bio; bio = BIO_new(BIO_s_mem()); if (bio == NULL) goto trans_err; BIO_set_mem_eof_return(bio, -1); dtls->outgoing_bio = bio; SSL_set_bio(dtls->ssl, dtls->incoming_bio, dtls->outgoing_bio); EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); SSL_set_options(dtls->ssl, SSL_OP_SINGLE_ECDH_USE); SSL_set_tmp_ecdh(dtls->ssl, ecdh); EC_KEY_free(ecdh); if (0) { trans_err: peer->transport->dtls = NULL; SSL_free(ssl); free(dtls); dtls = NULL; } return dtls; }
/* ECDH temporary parameters */ static int cmd_ECDHParameters(SSL_CONF_CTX *cctx, const char *value) { int rv = 1; EC_KEY *ecdh; int nid; nid = EC_curve_nist2nid(value); if (nid == NID_undef) nid = OBJ_sn2nid(value); if (nid == 0) return 0; ecdh = EC_KEY_new_by_curve_name(nid); if (!ecdh) return 0; if (cctx->ctx) rv = SSL_CTX_set_tmp_ecdh(cctx->ctx, ecdh); else if (cctx->ssl) rv = SSL_set_tmp_ecdh(cctx->ssl, ecdh); EC_KEY_free(ecdh); return rv > 0; }
int dtls_connection_init(struct packet_stream *ps, int active, struct dtls_cert *cert) { struct dtls_connection *d; unsigned long err; if (!ps || !ps->sfd) return 0; __DBG("dtls_connection_init(%i)", active); d = &ps->sfd->dtls; if (d->init) { if ((d->active && active) || (!d->active && !active)) goto done; dtls_connection_cleanup(d); } d->ssl_ctx = SSL_CTX_new(active ? DTLSv1_client_method() : DTLSv1_server_method()); if (!d->ssl_ctx) goto error; if (SSL_CTX_use_certificate(d->ssl_ctx, cert->x509) != 1) goto error; if (SSL_CTX_use_PrivateKey(d->ssl_ctx, cert->pkey) != 1) goto error; SSL_CTX_set_verify(d->ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback); SSL_CTX_set_verify_depth(d->ssl_ctx, 4); SSL_CTX_set_cipher_list(d->ssl_ctx, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); if (SSL_CTX_set_tlsext_use_srtp(d->ssl_ctx, ciphers_str)) goto error; if (SSL_CTX_set_read_ahead(d->ssl_ctx, 1)) goto error; d->ssl = SSL_new(d->ssl_ctx); if (!d->ssl) goto error; d->r_bio = BIO_new(BIO_s_mem()); d->w_bio = BIO_new(BIO_s_mem()); if (!d->r_bio || !d->w_bio) goto error; SSL_set_app_data(d->ssl, ps->sfd); /* XXX obj reference here? */ SSL_set_bio(d->ssl, d->r_bio, d->w_bio); SSL_set_mode(d->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); EC_KEY* ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); if (ecdh == NULL) goto error; SSL_set_options(d->ssl, SSL_OP_SINGLE_ECDH_USE); SSL_set_tmp_ecdh(d->ssl, ecdh); EC_KEY_free(ecdh); d->init = 1; d->active = active ? -1 : 0; done: return 0; error: err = ERR_peek_last_error(); if (d->r_bio) BIO_free(d->r_bio); if (d->w_bio) BIO_free(d->w_bio); if (d->ssl) SSL_free(d->ssl); if (d->ssl_ctx) SSL_CTX_free(d->ssl_ctx); ZERO(*d); ilog(LOG_ERROR, "Failed to init DTLS connection: %s", ERR_reason_error_string(err)); return -1; }
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; }