diff -urN asterisk-11.1.2/channels/chan_sip.c asterisk-11.1.2-dtls/channels/chan_sip.c --- asterisk-11.1.2/channels/chan_sip.c 2013-01-02 20:23:44.000000000 +0100 +++ asterisk-11.1.2-dtls/channels/chan_sip.c 2013-12-11 11:30:01.473579692 +0100 @@ -5850,9 +5850,9 @@ ice->stop(dialog->rtp); } - if (dialog_initialize_dtls_srtp(dialog, dialog->rtp, &dialog->srtp)) { - return -1; - } + //~ if (dialog_initialize_dtls_srtp(dialog, dialog->rtp, &dialog->srtp)) { + //~ return -1; + //~ } if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT_ALWAYS) || (ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT) && (ast_format_cap_has_type(dialog->caps, AST_FORMAT_TYPE_VIDEO)))) { @@ -5864,9 +5864,9 @@ ice->stop(dialog->vrtp); } - if (dialog_initialize_dtls_srtp(dialog, dialog->vrtp, &dialog->vsrtp)) { - return -1; - } + //~ if (dialog_initialize_dtls_srtp(dialog, dialog->vrtp, &dialog->vsrtp)) { + //~ return -1; + //~ } ast_rtp_instance_set_timeout(dialog->vrtp, dialog->rtptimeout); ast_rtp_instance_set_hold_timeout(dialog->vrtp, dialog->rtpholdtimeout); @@ -5874,6 +5874,11 @@ ast_rtp_instance_set_prop(dialog->vrtp, AST_RTP_PROPERTY_RTCP, 1); ast_rtp_instance_set_qos(dialog->vrtp, global_tos_video, global_cos_video, "SIP VIDEO"); + + /* Meetecho: moving DTLS setup after RTCP */ + if (dialog_initialize_dtls_srtp(dialog, dialog->vrtp, &dialog->vsrtp)) { + return -1; + } } if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_TEXTSUPPORT)) { @@ -5885,14 +5890,19 @@ ice->stop(dialog->trtp); } - if (dialog_initialize_dtls_srtp(dialog, dialog->trtp, &dialog->tsrtp)) { - return -1; - } + //~ if (dialog_initialize_dtls_srtp(dialog, dialog->trtp, &dialog->tsrtp)) { + //~ return -1; + //~ } /* Do not timeout text as its not constant*/ ast_rtp_instance_set_keepalive(dialog->trtp, dialog->rtpkeepalive); ast_rtp_instance_set_prop(dialog->trtp, AST_RTP_PROPERTY_RTCP, 1); + + /* Meetecho: moving DTLS setup after RTCP */ + if (dialog_initialize_dtls_srtp(dialog, dialog->trtp, &dialog->tsrtp)) { + return -1; + } } ast_rtp_instance_set_timeout(dialog->rtp, dialog->rtptimeout); @@ -5903,6 +5913,11 @@ ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&dialog->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833); ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF_COMPENSATE, ast_test_flag(&dialog->flags[1], SIP_PAGE2_RFC2833_COMPENSATE)); + /* Meetecho: moving DTLS setup after RTCP */ + if (dialog_initialize_dtls_srtp(dialog, dialog->rtp, &dialog->srtp)) { + return -1; + } + ast_rtp_instance_set_qos(dialog->rtp, global_tos_audio, global_cos_audio, "SIP RTP"); do_setnat(dialog); @@ -10915,7 +10930,8 @@ } else if (sscanf(a, "fingerprint: %5s %255s", hash, value) == 2) { found = TRUE; - if (!strcasecmp(hash, "sha-1")) { + /* Meetecho: add support for sha-256 in negotiation */ + if (!strcasecmp(hash, "sha-1") || !strcasecmp(hash, "sha-2")) { dtls->set_fingerprint(instance, AST_RTP_DTLS_HASH_SHA1, value); } else { ast_log(LOG_WARNING, "Unsupported fingerprint hash type '%s' received on dialog '%s'\n", @@ -11068,6 +11084,7 @@ ast_rtp_codecs_payloads_unset(newvideortp, NULL, codec); } } + } return found; @@ -12551,7 +12568,9 @@ } if ((fingerprint = dtls->get_fingerprint(instance, AST_RTP_DTLS_HASH_SHA1))) { - ast_str_append(a_buf, 0, "a=fingerprint:SHA-1 %s\r\n", fingerprint); + //~ ast_str_append(a_buf, 0, "a=fingerprint:SHA-1 %s\r\n", fingerprint); + /* Meetecho: use SHA-256 for DTLS-SRTP Fingerprint (lower case sha) */ + ast_str_append(a_buf, 0, "a=fingerprint:sha-256 %s\r\n", fingerprint); } } @@ -13029,7 +13048,7 @@ if (needvideo) { get_crypto_attrib(p, p->vsrtp, &v_a_crypto); ast_str_append(&m_video, 0, "m=video %d %s", ast_sockaddr_port(&vdest), - get_sdp_rtp_profile(p, a_crypto ? 1 : 0, p->vrtp)); + get_sdp_rtp_profile(p, v_a_crypto ? 1 : 0, p->vrtp)); /* Meetecho: fix for SAVPF */ /* Build max bitrate string */ if (p->maxcallbitrate) @@ -13054,7 +13073,7 @@ ast_verbose("Lets set up the text sdp\n"); get_crypto_attrib(p, p->tsrtp, &t_a_crypto); ast_str_append(&m_text, 0, "m=text %d %s", ast_sockaddr_port(&tdest), - get_sdp_rtp_profile(p, a_crypto ? 1 : 0, p->trtp)); + get_sdp_rtp_profile(p, t_a_crypto ? 1 : 0, p->trtp)); /* Meetecho: fix for SAVPF */ if (debug) { /* XXX should I use tdest below ? */ ast_verbose("Text is at %s\n", ast_sockaddr_stringify(&taddr)); } @@ -13252,6 +13271,7 @@ add_content(resp, bandwidth); } add_content(resp, session_time); + /* if this is a response to an invite, order our offers properly */ if (!AST_LIST_EMPTY(&p->offered_media)) { AST_LIST_TRAVERSE(&p->offered_media, offer, next) { @@ -25023,6 +25043,20 @@ /* Handle authentication if this is our first invite */ int cc_recall_core_id = -1; set_pvt_allowed_methods(p, req); + + /* Meetecho: enable DTLS if peer is asking for it (FIXME) */ + if (!p->dtls_cfg.enabled && strlen(get_content_line(req, "a=fingerprint", ':')) > 1) { + ast_log(LOG_WARNING, "a=fingerprint found, creating DTLS configuration\n"); + /* FIXME */ + ast_rtp_dtls_cfg_parse(&p->dtls_cfg, "dtlsenable", "yes"); + ast_rtp_dtls_cfg_parse(&p->dtls_cfg, "dtlsverify", "no"); + ast_rtp_dtls_cfg_parse(&p->dtls_cfg, "dtlscipher", "ALL:NULL:eNULL:aNULL"); /* FIXME was SHA256... */ + ast_rtp_dtls_cfg_parse(&p->dtls_cfg, "dtlscertfile", "/path/to/mycert.pem"); + ast_rtp_dtls_cfg_parse(&p->dtls_cfg, "dtlsprivatekey", "/path/to/mycert.key"); + /* Apply the encryption tag length to the DTLS configuration, in case DTLS is in use */ + p->dtls_cfg.suite = (ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TAG_32) ? AST_AES_CM_128_HMAC_SHA1_32 : AST_AES_CM_128_HMAC_SHA1_80); + } + res = check_user_full(p, req, SIP_INVITE, e, XMIT_RELIABLE, addr, &authpeer); if (res == AUTH_CHALLENGE_SENT) { p->invitestate = INV_COMPLETED; /* Needs to restart in another INVITE transaction */ diff -urN asterisk-11.1.2/res/pjproject/pjnath/src/pjnath/ice_session.c asterisk-11.1.2-dtls/res/pjproject/pjnath/src/pjnath/ice_session.c --- asterisk-11.1.2/res/pjproject/pjnath/src/pjnath/ice_session.c 2012-07-06 16:32:30.000000000 +0200 +++ asterisk-11.1.2-dtls/res/pjproject/pjnath/src/pjnath/ice_session.c 2013-05-17 11:57:56.330075000 +0200 @@ -1258,6 +1258,8 @@ LOG4((ice->obj_name, "ICE process complete, status=%s", pj_strerror(status, ice->tmp.errmsg, sizeof(ice->tmp.errmsg)).ptr)); + /* Meetecho: log on stdout as well */ + printf("ICE process complete, status=%s\n", pj_strerror(status, ice->tmp.errmsg, sizeof(ice->tmp.errmsg)).ptr); dump_checklist("Valid list", ice, &ice->valid_list); @@ -2226,6 +2228,15 @@ pj_mutex_unlock(ice->mutex); return; } + + /* Meetecho: don't give up immediately if it's unauthorized */ + if (status==PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED)) { + printf("Got a 401? I'm not giving up!\n"); + check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_WAITING, 0); + /* TODO Do we need to actively send request, or is there a timer? */ + pj_mutex_unlock(ice->mutex); + return; + } pj_strerror(status, errmsg, sizeof(errmsg)); LOG4((ice->obj_name, diff -urN asterisk-11.1.2/res/res_rtp_asterisk.c asterisk-11.1.2-dtls/res/res_rtp_asterisk.c --- asterisk-11.1.2/res/res_rtp_asterisk.c 2012-10-11 18:04:19.000000000 +0200 +++ asterisk-11.1.2-dtls/res/res_rtp_asterisk.c 2013-12-11 11:50:42.430886890 +0100 @@ -123,6 +123,8 @@ static int rtpdebug; /*!< Are we debugging? */ static int rtcpdebug; /*!< Are we debugging RTCP? */ static int rtcpstats; /*!< Are we debugging RTCP? */ +/* Meetecho: debug DTLS */ +static int dtlsdebug; /*!< Are we debugging DTLS? */ static int rtcpinterval = RTCP_DEFAULT_INTERVALMS; /*!< Time between rtcp reports in millisecs */ static struct ast_sockaddr rtpdebugaddr; /*!< Debug packets to/from this host */ static struct ast_sockaddr rtcpdebugaddr; /*!< Debug RTCP packets to/from this host */ @@ -256,6 +258,12 @@ ast_cond_t cond; /*!< Condition for signaling */ unsigned int passthrough:1; /*!< Bit to indicate that the received packet should be passed through */ unsigned int ice_started:1; /*!< Bit to indicate ICE connectivity checks have started */ + /* Meetecho */ + struct ast_rtp_instance *instance; + unsigned int icecomplete:1; /*!< Bit to indicate ICE connectivity checks have completed */ + unsigned int icedone:1; /*!< Bit to indicate ICE connectivity checks have completed (go on with RTP or DTLS) */ + unsigned int dtlsinit:1; /*!< Bit to indicate DTLS-SRTP setup has been started (whether to start DTLS or not) */ + unsigned int dtlsdone:1; /*!< Bit to indicate DTLS-SRTP setup has been completed (go on with RTP or DTLS) */ char remote_ufrag[256]; /*!< The remote ICE username */ char remote_passwd[256]; /*!< The remote ICE password */ @@ -341,6 +349,26 @@ double normdevrtt; double stdevrtt; unsigned int rtt_count; + + /* Meetecho */ + unsigned int icecomplete:1; /*!< Bit to indicate ICE connectivity checks have completed */ + unsigned int icedone:1; /*!< Bit to indicate ICE connectivity checks have completed (go on with RTCP or DTLS) */ + unsigned int dtlsdone:1; /*!< Bit to indicate DTLS-SRTP setup has been completed (go on with RTCP or DTLS) */ +#ifdef HAVE_OPENSSL_SRTP + SSL_CTX *ssl_ctx; /*!< SSL context */ + SSL *ssl; /*!< SSL session */ + BIO *read_bio; /*!< Memory buffer for reading */ + BIO *write_bio; /*!< Memory buffer for writing */ + enum ast_rtp_dtls_setup dtls_setup; /*!< Current setup state */ + enum ast_srtp_suite suite; /*!< SRTP crypto suite */ + char local_fingerprint[160]; /*!< Fingerprint of our certificate */ + unsigned char remote_fingerprint[EVP_MAX_MD_SIZE]; /*!< Fingerprint of the peer certificate */ + enum ast_rtp_dtls_connection connection; /*!< Whether this is a new or existing connection */ + unsigned int dtls_failure:1; /*!< Failure occurred during DTLS negotiation */ + unsigned int rekey; /*!< Interval at which to renegotiate and rekey */ + int rekeyid; /*!< Scheduled item id for rekeying */ +#endif + }; struct rtp_red { @@ -389,6 +417,10 @@ #ifdef HAVE_OPENSSL_SRTP static int ast_rtp_activate(struct ast_rtp_instance *instance); #endif +/* Meetecho: DTLS certificate verification callback */ +#ifdef HAVE_OPENSSL_SRTP +static int dtls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx); +#endif static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int rtcp, int *ice, int use_srtp); @@ -700,6 +732,10 @@ return; } + /* FIXME Meetecho: shouldn't it be a failure/error only when ret=0? */ + ast_verbose(VERBOSE_PREFIX_3 "dtls_info_callback: %s, where=%d, ret=%d\n", (where & SSL_CB_READ)?"read":"write", where, ret); + ast_verbose(VERBOSE_PREFIX_3 " >> %s, %s, %s\n", SSL_state_string(ssl), SSL_alert_type_string(ret), SSL_alert_desc_string(ret)); + rtp->dtls_failure = 1; } @@ -719,7 +755,7 @@ return -1; } - SSL_CTX_set_verify(rtp->ssl_ctx, dtls_cfg->verify ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_NONE, NULL); + SSL_CTX_set_verify(rtp->ssl_ctx, dtls_cfg->verify ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_NONE, dtls_verify_callback); if (dtls_cfg->suite == AST_AES_CM_128_HMAC_SHA1_80) { SSL_CTX_set_tlsext_use_srtp(rtp->ssl_ctx, "SRTP_AES128_CM_SHA1_80"); @@ -759,7 +795,9 @@ if (!BIO_read_filename(certbio, dtls_cfg->certfile) || !(cert = PEM_read_bio_X509(certbio, NULL, 0, NULL)) || - !X509_digest(cert, EVP_sha1(), fingerprint, &size) || + //~ !X509_digest(cert, EVP_sha1(), fingerprint, &size) || + /* Meetecho: use SHA256 for DTLS-SRTP Fingerprint */ + !X509_digest(cert, EVP_sha256(), fingerprint, &size) || !size) { ast_log(LOG_ERROR, "Could not produce fingerprint from certificate '%s' for RTP instance '%p'\n", dtls_cfg->certfile, instance); @@ -830,6 +868,104 @@ rtp->connection = AST_RTP_DTLS_CONNECTION_NEW; + /* Meetecho: do the same with RTCP */ + if (!(rtp->rtcp->ssl_ctx = SSL_CTX_new(DTLSv1_method()))) { + return -1; + } + SSL_CTX_set_verify(rtp->rtcp->ssl_ctx, dtls_cfg->verify ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_NONE, NULL); + if (dtls_cfg->suite == AST_AES_CM_128_HMAC_SHA1_80) { + SSL_CTX_set_tlsext_use_srtp(rtp->rtcp->ssl_ctx, "SRTP_AES128_CM_SHA1_80"); + } else if (dtls_cfg->suite == AST_AES_CM_128_HMAC_SHA1_32) { + SSL_CTX_set_tlsext_use_srtp(rtp->rtcp->ssl_ctx, "SRTP_AES128_CM_SHA1_32"); + } else { + ast_log(LOG_ERROR, "Unsupported suite specified for DTLS-SRTP on RTCP instance '%p'\n", instance); + goto error; + } + if (!ast_strlen_zero(dtls_cfg->certfile)) { + char *private = ast_strlen_zero(dtls_cfg->pvtfile) ? dtls_cfg->certfile : dtls_cfg->pvtfile; + BIO *certbio; + X509 *cert; + unsigned int size, i; + unsigned char fingerprint[EVP_MAX_MD_SIZE]; + char *local_fingerprint = rtp->rtcp->local_fingerprint; + if (!SSL_CTX_use_certificate_file(rtp->rtcp->ssl_ctx, dtls_cfg->certfile, SSL_FILETYPE_PEM)) { + ast_log(LOG_ERROR, "Specified certificate file '%s' for RTCP instance '%p' could not be used\n", + dtls_cfg->certfile, instance); + goto error; + } + if (!SSL_CTX_use_PrivateKey_file(rtp->rtcp->ssl_ctx, private, SSL_FILETYPE_PEM) || + !SSL_CTX_check_private_key(rtp->rtcp->ssl_ctx)) { + ast_log(LOG_ERROR, "Specified private key file '%s' for RTCP instance '%p' could not be used\n", + private, instance); + goto error; + } + if (!(certbio = BIO_new(BIO_s_file()))) { + ast_log(LOG_ERROR, "Failed to allocate memory for certificate fingerprinting on RTCP instance '%p'\n", + instance); + goto error; + } + if (!BIO_read_filename(certbio, dtls_cfg->certfile) || + !(cert = PEM_read_bio_X509(certbio, NULL, 0, NULL)) || + //~ !X509_digest(cert, EVP_sha1(), fingerprint, &size) || + /* Meetecho: use SHA256 for DTLS-SRTP Fingerprint */ + !X509_digest(cert, EVP_sha256(), fingerprint, &size) || + !size) { + ast_log(LOG_ERROR, "Could not produce fingerprint from certificate '%s' for RTCP instance '%p'\n", + dtls_cfg->certfile, instance); + BIO_free_all(certbio); + goto error; + } + for (i = 0; i < size; i++) { + sprintf(local_fingerprint, "%.2X:", fingerprint[i]); + local_fingerprint += 3; + } + *(local_fingerprint-1) = 0; + BIO_free_all(certbio); + } + if (!ast_strlen_zero(dtls_cfg->cipher)) { + if (!SSL_CTX_set_cipher_list(rtp->rtcp->ssl_ctx, dtls_cfg->cipher)) { + ast_log(LOG_ERROR, "Invalid cipher specified in cipher list '%s' for RTCP instance '%p'\n", + dtls_cfg->cipher, instance); + goto error; + } + } + if (!ast_strlen_zero(dtls_cfg->cafile) || !ast_strlen_zero(dtls_cfg->capath)) { + if (!SSL_CTX_load_verify_locations(rtp->rtcp->ssl_ctx, S_OR(dtls_cfg->cafile, NULL), S_OR(dtls_cfg->capath, NULL))) { + ast_log(LOG_ERROR, "Invalid certificate authority file '%s' or path '%s' specified for RTCP instance '%p'\n", + S_OR(dtls_cfg->cafile, ""), S_OR(dtls_cfg->capath, ""), instance); + goto error; + } + } + rtp->rtcp->rekey = dtls_cfg->rekey; + rtp->rtcp->dtls_setup = dtls_cfg->default_setup; + rtp->rtcp->suite = dtls_cfg->suite; + if (!(rtp->rtcp->ssl = SSL_new(rtp->rtcp->ssl_ctx))) { + ast_log(LOG_ERROR, "Failed to allocate memory for SSL context on RTCP instance '%p'\n", + instance); + goto error; + } + SSL_set_ex_data(rtp->rtcp->ssl, 0, rtp); + SSL_set_info_callback(rtp->rtcp->ssl, dtls_info_callback); + if (!(rtp->rtcp->read_bio = BIO_new(BIO_s_mem()))) { + ast_log(LOG_ERROR, "Failed to allocate memory for inbound SSL traffic on RTCP instance '%p'\n", + instance); + goto error; + } + BIO_set_mem_eof_return(rtp->rtcp->read_bio, -1); + if (!(rtp->rtcp->write_bio = BIO_new(BIO_s_mem()))) { + ast_log(LOG_ERROR, "Failed to allocate memory for outbound SSL traffic on RTCP instance '%p'\n", + instance); + goto error; + } + BIO_set_mem_eof_return(rtp->rtcp->write_bio, -1); + SSL_set_bio(rtp->rtcp->ssl, rtp->rtcp->read_bio, rtp->rtcp->write_bio); + if (rtp->rtcp->dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) { + SSL_set_accept_state(rtp->rtcp->ssl); + } else { + SSL_set_connect_state(rtp->rtcp->ssl); + } + rtp->rtcp->connection = AST_RTP_DTLS_CONNECTION_NEW; + return 0; error: @@ -850,6 +986,22 @@ SSL_CTX_free(rtp->ssl_ctx); rtp->ssl_ctx = NULL; + + /* Meetecho: do the same with RTCP */ + if (rtp->rtcp->read_bio) { + BIO_free(rtp->rtcp->read_bio); + rtp->rtcp->read_bio = NULL; + } + if (rtp->rtcp->write_bio) { + BIO_free(rtp->rtcp->write_bio); + rtp->rtcp->write_bio = NULL; + } + if (rtp->rtcp->ssl) { + SSL_free(rtp->rtcp->ssl); + rtp->rtcp->ssl = NULL; + } + SSL_CTX_free(rtp->rtcp->ssl_ctx); + rtp->rtcp->ssl_ctx = NULL; return -1; } @@ -864,7 +1016,9 @@ static void ast_rtp_dtls_stop(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - + + ast_verbose(VERBOSE_PREFIX_3 "Stopping DTLS...\n"); + if (rtp->ssl_ctx) { SSL_CTX_free(rtp->ssl_ctx); rtp->ssl_ctx = NULL; @@ -874,6 +1028,16 @@ SSL_free(rtp->ssl); rtp->ssl = NULL; } + + /* Meetecho: do the same with RTCP */ + if (rtp->rtcp->ssl_ctx) { + SSL_CTX_free(rtp->rtcp->ssl_ctx); + rtp->rtcp->ssl_ctx = NULL; + } + if (rtp->rtcp->ssl) { + SSL_free(rtp->rtcp->ssl); + rtp->rtcp->ssl = NULL; + } } static void ast_rtp_dtls_reset(struct ast_rtp_instance *instance) @@ -887,6 +1051,13 @@ SSL_shutdown(rtp->ssl); rtp->connection = AST_RTP_DTLS_CONNECTION_NEW; + + /* Meetecho: do the same with RTCP */ + if (!SSL_is_init_finished(rtp->rtcp->ssl)) { + return; + } + SSL_shutdown(rtp->rtcp->ssl); + rtp->rtcp->connection = AST_RTP_DTLS_CONNECTION_NEW; } static enum ast_rtp_dtls_connection ast_rtp_dtls_get_connection(struct ast_rtp_instance *instance) @@ -946,6 +1117,16 @@ } else { return; } + + /* Meetecho: do the same with RTCP */ + rtp->rtcp->dtls_setup = rtp->dtls_setup; + if (rtp->rtcp->dtls_setup == AST_RTP_DTLS_SETUP_ACTIVE) { + SSL_set_connect_state(rtp->rtcp->ssl); + } else if (rtp->rtcp->dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) { + SSL_set_accept_state(rtp->rtcp->ssl); + } else { + return; + } } static void ast_rtp_dtls_set_fingerprint(struct ast_rtp_instance *instance, enum ast_rtp_dtls_hash hash, const char *fingerprint) @@ -961,6 +1142,11 @@ while ((value = strsep(&tmp, ":")) && (pos != (EVP_MAX_MD_SIZE - 1))) { sscanf(value, "%02x", (unsigned int*)&rtp->remote_fingerprint[pos++]); } + + /* Meetecho: do the same with RTCP */ + while ((value = strsep(&tmp, ":")) && (pos != (EVP_MAX_MD_SIZE - 1))) { + sscanf(value, "%02x", (unsigned int*)&rtp->rtcp->remote_fingerprint[pos++]); + } } static const char *ast_rtp_dtls_get_fingerprint(struct ast_rtp_instance *instance, enum ast_rtp_dtls_hash hash) @@ -1039,11 +1225,27 @@ pj_ssize_t _size = (pj_ssize_t)size; if (transport_id == TRANSPORT_SOCKET_RTP) { + /* Meetecho: are we sending DTLS? */ + if(dtlsdebug > 1) + ast_verbose(VERBOSE_PREFIX_3 "[RTP] ast_rtp_on_ice_tx_pkt (%zu)\n", size); + const char *out = pkt; + if ((*out >= 20) && (*out <= 64)) { + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTP] Sending DTLS data (%zu)\n", size); + } /* Traffic is destined to go right out the RTP socket we already have */ status = pj_sock_sendto(rtp->s, pkt, &_size, 0, dst_addr, dst_addr_len); /* sendto on a connectionless socket should send all the data, or none at all */ ast_assert(_size == size || status != PJ_SUCCESS); } else if (transport_id == TRANSPORT_SOCKET_RTCP) { + /* Meetecho: are we sending DTLS? */ + if(dtlsdebug > 1) + ast_verbose(VERBOSE_PREFIX_3 "[RTCP] ast_rtp_on_ice_tx_pkt (%zu)\n", size); + const char *out = pkt; + if ((*out >= 20) && (*out <= 64)) { + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTCP] Sending DTLS data (%zu)\n", size); + } /* Traffic is destined to go right out the RTCP socket we already have */ if (rtp->rtcp) { status = pj_sock_sendto(rtp->rtcp->s, pkt, &_size, 0, dst_addr, dst_addr_len); @@ -1067,10 +1269,51 @@ return status; } +/* Meetecho: callback to known when ICE is complete */ +#ifdef HAVE_OPENSSL_SRTP +static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp); +#endif +static void ast_rtp_on_ice_complete(pj_ice_sess *ice, pj_status_t status) { + struct ast_rtp *rtp = ice->user_data; + ast_verbose(VERBOSE_PREFIX_3 "ICE is now complete\n"); + rtp->icecomplete = 1; + /* Meetecho: do the same with RTCP (FIXME is this true??) */ + rtp->rtcp->icecomplete = 1; + usleep(500000); + /* Meetecho: since ICE has been completed, we can do the DTLS handshake */ + if(rtp->icecomplete) { + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTP] ICE has been completed, yay!\n"); + rtp->icecomplete = 0; + rtp->icedone = 1; + if (rtp->ssl) { + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTP] >> Doing DTLS handshake as well...\n"); + SSL_do_handshake(rtp->ssl); + dtls_srtp_check_pending(rtp->instance, rtp); + } + } + /* Meetecho: do the same with RTCP */ + if(rtp->rtcp->icecomplete) { + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTCP] ICE has been completed, yay!\n"); + rtp->rtcp->icecomplete = 0; + rtp->rtcp->icedone = 1; + if (rtp->rtcp->ssl) { + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTCP] >> Doing DTLS handshake as well...\n"); + SSL_do_handshake(rtp->rtcp->ssl); + dtls_srtp_check_pending(rtp->instance, rtp); + } + } +} + /* ICE Session interface declaration */ static pj_ice_sess_cb ast_rtp_ice_sess_cb = { .on_rx_data = ast_rtp_on_ice_rx_data, .on_tx_pkt = ast_rtp_on_ice_tx_pkt, + /* Meetecho: add callback to know when ICE is complete */ + .on_ice_complete = ast_rtp_on_ice_complete, }; static void ast_rtp_on_turn_rx_rtp_data(pj_turn_sock *turn_sock, void *pkt, unsigned pkt_len, const pj_sockaddr_t *peer_addr, unsigned addr_len) @@ -1211,11 +1454,20 @@ } #ifdef HAVE_OPENSSL_SRTP +/* Meetecho: DTLS certificate verification callback */ +static int dtls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) { + /* We just use the verify_callback to request a certificate from the client */ + return 1; +} + static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp) { size_t pending = BIO_ctrl_pending(rtp->write_bio); + //~ ast_verbose(VERBOSE_PREFIX_3 "[RTP] DTLS check pending: %d\n", pending); if (pending > 0) { + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTP] >> Going to send DTLS data: %zu bytes\n", pending); char outgoing[pending]; size_t out; struct ast_sockaddr remote_address = { {0, } }; @@ -1229,8 +1481,38 @@ } out = BIO_read(rtp->write_bio, outgoing, sizeof(outgoing)); + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTP] >> >> Read %zu bytes from the write_BIO...\n", pending); __rtp_sendto(instance, outgoing, out, 0, &remote_address, 0, &ice, 0); + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTP] >> >> Called __rtp_sendto! (%zu)\n", pending); + } + + /* Meetecho: do the same with RTCP */ + pending = BIO_ctrl_pending(rtp->rtcp->write_bio); + //~ ast_verbose(VERBOSE_PREFIX_3 "[RTCP] DTLS check pending: %d\n", pending); + if (pending > 0) { + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTCP] >> Going to send DTLS data: %zu bytes\n", pending); + char outgoing[pending]; + size_t out; + struct ast_sockaddr remote_address = { {0, } }; + int ice; + //~ ast_rtp_instance_get_remote_address(instance, &remote_address); + if (ast_sockaddr_isnull(&rtp->rtcp->them)) { + return; + } + ast_sockaddr_copy(&remote_address, &rtp->rtcp->them); + if (ast_sockaddr_isnull(&remote_address)) { + return; + } + out = BIO_read(rtp->rtcp->write_bio, outgoing, sizeof(outgoing)); + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTCP] >> >> Read %zu bytes from the write_BIO...\n", pending); + __rtp_sendto(instance, outgoing, out, 0, &remote_address, 1, &ice, 0); + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTCP] >> >> Called __rtp_sendto! (%zu)\n", pending); } } @@ -1241,6 +1523,9 @@ SSL_renegotiate(rtp->ssl); SSL_do_handshake(rtp->ssl); + /* Meetecho: do the same with RTCP */ + SSL_do_handshake(rtp->rtcp->ssl); + //~ ast_verbose(VERBOSE_PREFIX_3 " >> [renegotiate] check pending...\n"); dtls_srtp_check_pending(instance, rtp); rtp->rekeyid = -1; @@ -1270,7 +1555,9 @@ unsigned char fingerprint[EVP_MAX_MD_SIZE]; unsigned int size; - if (!X509_digest(certificate, EVP_sha1(), fingerprint, &size) || + //~ if (!X509_digest(certificate, EVP_sha1(), fingerprint, &size) || + /* Meetecho: use SHA256 for DTLS-SRTP Fingerprint */ + if (!X509_digest(certificate, EVP_sha256(), fingerprint, &size) || !size || memcmp(fingerprint, rtp->remote_fingerprint, size)) { X509_free(certificate); @@ -1281,15 +1568,26 @@ } X509_free(certificate); - } + + /* Ensure that certificate verification was successful */ + if (SSL_get_verify_result(rtp->ssl) != X509_V_OK) { + ast_log(LOG_WARNING, "Peer certificate on RTP instance '%p' failed verification test\n", + instance); + return -1; + } - /* Ensure that certificate verification was successful */ - if (SSL_get_verify_result(rtp->ssl) != X509_V_OK) { - ast_log(LOG_WARNING, "Peer certificate on RTP instance '%p' failed verification test\n", - instance); - return -1; } + //~ /* Ensure that certificate verification was successful */ + //~ if (SSL_get_verify_result(rtp->ssl) != X509_V_OK) { + //~ ast_log(LOG_WARNING, "Peer certificate on RTP instance '%p' failed verification test\n", + //~ instance); + //~ return -1; + //~ } + + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "Verification was ok :-)\n"); + /* Produce key information and set up SRTP */ if (!SSL_export_keying_material(rtp->ssl, material, SRTP_MASTER_LEN * 2, "EXTRACTOR-dtls_srtp", 19, NULL, 0, 0)) { ast_log(LOG_WARNING, "Unable to extract SRTP keying material from DTLS-SRTP negotiation on RTP instance '%p'\n", @@ -1359,6 +1657,10 @@ } } + /* Meetecho: done with DTLS-SRTP */ + ast_verbose(VERBOSE_PREFIX_3 "Looks like SRTP setup was completed...\n"); + rtp->dtlsdone = 1; + return 0; error: @@ -1386,10 +1688,13 @@ if (!rtcp) { char *in = buf; + //~ ast_verbose(VERBOSE_PREFIX_3 " >> [recvfrom#1] check pending...\n"); dtls_srtp_check_pending(instance, rtp); /* If this is an SSL packet pass it to OpenSSL for processing */ if ((*in >= 20) && (*in <= 64)) { + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTP] Received a DTLS message\n"); int res = 0; /* If no SSL session actually exists terminate things */ @@ -1405,12 +1710,20 @@ SSL_set_accept_state(rtp->ssl); } + //~ ast_verbose(VERBOSE_PREFIX_3 " >> [recvfrom#2] check pending...\n"); dtls_srtp_check_pending(instance, rtp); - BIO_write(rtp->read_bio, buf, len); + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTP] >> >> writing %d bytes on read_BIO (to have it read later)\n", len); + int written = BIO_write(rtp->read_bio, buf, len); + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTP] >> >> >> actually wrote %d bytes (%s)\n", written, BIO_should_retry(rtp->read_bio) ? "should retry" : "should NOT retry"); len = SSL_read(rtp->ssl, buf, len); + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTP] >> >> read %d bytes from SSL\n", len); + //~ ast_verbose(VERBOSE_PREFIX_3 " >> [recvfrom#3] check pending...\n"); dtls_srtp_check_pending(instance, rtp); if (rtp->dtls_failure) { @@ -1420,6 +1733,8 @@ } if (SSL_is_init_finished(rtp->ssl)) { + //~ if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTP] >> DTLS established, yay!\n"); /* Any further connections will be existing since this is now established */ rtp->connection = AST_RTP_DTLS_CONNECTION_EXISTING; @@ -1429,6 +1744,66 @@ return res; } + /* Meetecho: since we don't do rtcp-mux, we need DTLS for RTCP as well */ + } else { + char *in = buf; + + dtls_srtp_check_pending(instance, rtp); + + /* If this is an SSL packet pass it to OpenSSL for processing */ + if ((*in >= 20) && (*in <= 64)) { + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTCP] Received a DTLS message\n"); + int res = 0; + + /* If no SSL session actually exists terminate things */ + if (!rtp->rtcp->ssl) { + ast_log(LOG_ERROR, "Received SSL traffic on RTP instance '%p' without an SSL session\n", + instance); + return -1; + } + + /* If we don't yet know if we are active or passive and we receive a packet... we are obviously passive */ + if (rtp->rtcp->dtls_setup == AST_RTP_DTLS_SETUP_ACTPASS) { + rtp->rtcp->dtls_setup = AST_RTP_DTLS_SETUP_PASSIVE; + SSL_set_accept_state(rtp->rtcp->ssl); + } + + //~ ast_verbose(VERBOSE_PREFIX_3 " >> [recvfrom#2] check pending...\n"); + dtls_srtp_check_pending(instance, rtp); + + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTCP] >> >> writing %d bytes on read_BIO (to have it read later)\n", len); + int written = BIO_write(rtp->rtcp->read_bio, buf, len); + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTCP] >> >> >> actually wrote %d bytes (%s)\n", written, BIO_should_retry(rtp->rtcp->read_bio) ? "should retry" : "should NOT retry"); + + len = SSL_read(rtp->rtcp->ssl, buf, len); + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTCP] >> >> read %d bytes from SSL\n", len); + + //~ ast_verbose(VERBOSE_PREFIX_3 " >> [recvfrom#3] check pending...\n"); + dtls_srtp_check_pending(instance, rtp); + + if (rtp->rtcp->dtls_failure) { + ast_log(LOG_ERROR, "DTLS failure occurred on RTCP instance '%p', terminating\n", + instance); + return -1; + } + + if (SSL_is_init_finished(rtp->rtcp->ssl)) { + //~ if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTCP] >> DTLS established, yay!\n"); + /* Any further connections will be existing since this is now established */ + rtp->rtcp->connection = AST_RTP_DTLS_CONNECTION_EXISTING; + + /* Use the keying material to set up key/salt information */ + //~ res = dtls_srtp_setup(rtp, srtp, instance); + rtp->rtcp->dtlsdone = 1; + } + + return res; + } } #endif @@ -1502,11 +1877,49 @@ static int rtcp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int *ice) { + /* Meetecho: don't send RTCP until ICE completed (FIXME useless? pjnath already does this?) */ + struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + //~ if(!rtp->rtcp->icedone) { + //~ if(dtlsdebug) + //~ ast_verbose(VERBOSE_PREFIX_3 "[RTCP] ICE not done yet, discarding packet\n"); + //~ return 0; + //~ } + /* Meetecho: don't send RTP until DTLS handshake has been completed */ + if(rtp->rtcp->ssl && !rtp->rtcp->dtlsdone) { + const char *out = buf; + if ((*out >= 20) && (*out <= 64)) { + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTCP] Sending DTLS data (%zu)\n", size); + } else if(rtp->rtcp->connection == AST_RTP_DTLS_CONNECTION_NEW) { + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTCP] >> Still waiting for the DTLS handshake to complete, discarding packet (%zu)\n", size); + return 0; + } + } return __rtp_sendto(instance, buf, size, flags, sa, 1, ice, 1); } static int rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int *ice) { + /* Meetecho: don't send RTP until ICE completed (FIXME useless? pjnath already does this?) */ + struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + //~ if(!rtp->icedone) { + //~ if(dtlsdebug) + //~ ast_verbose(VERBOSE_PREFIX_3 "[RTP] ICE not done yet, discarding packet\n"); + //~ return 0; + //~ } + /* Meetecho: don't send RTP until DTLS handshake has been completed */ + if(rtp->ssl && !rtp->dtlsdone) { + const char *out = buf; + if ((*out >= 20) && (*out <= 64)) { + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTP] Sending DTLS data (%zu)\n", size); + } else if(rtp->connection == AST_RTP_DTLS_CONNECTION_NEW) { + if(dtlsdebug) + ast_verbose(VERBOSE_PREFIX_3 "[RTP] >> Still waiting for the DTLS handshake to complete, discarding packet (%zu)\n", size); + return 0; + } + } return __rtp_sendto(instance, buf, size, flags, sa, 0, ice, 1); } @@ -1775,6 +2188,9 @@ rtp->rekeyid = -1; #endif + /* Meetecho: make rtp aware of instance as well... */ + rtp->instance = instance; + return 0; } @@ -4156,15 +4572,23 @@ #ifdef HAVE_OPENSSL_SRTP static int ast_rtp_activate(struct ast_rtp_instance *instance) { + ast_verbose(VERBOSE_PREFIX_3 "Activating RTP...\n"); struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); if (!rtp->ssl) { return 0; } - SSL_do_handshake(rtp->ssl); + /* Meetecho: only do the DTLS handshake right now if there's no ICE or if it has completed */ + if(!rtp->ice || rtp->icedone) { + ast_verbose(VERBOSE_PREFIX_3 " >> Doing DTLS handshake as well...\n"); + SSL_do_handshake(rtp->ssl); + /* Meetecho: do the same with RTCP */ + SSL_do_handshake(rtp->rtcp->ssl); - dtls_srtp_check_pending(instance, rtp); + ast_verbose(VERBOSE_PREFIX_3 " >> [activate] check pending...\n"); + dtls_srtp_check_pending(instance, rtp); + } return 0; } @@ -4297,10 +4721,46 @@ return CLI_SUCCESS; } +/* Meetecho: add DTLS debugging */ +static char *handle_cli_dtls_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + switch (cmd) { + case CLI_INIT: + e->command = "dtls set debug"; + e->usage = + "Usage: dtls set debug {status|none|normal|huge}\n" + " Enable/Disable DTLS debugging: normal only debugs setup and errors, huge debugs every single packet\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + if (a->argc != 4) + return CLI_SHOWUSAGE; + + if (!strncasecmp(a->argv[a->argc-1], "status", 6)) { + ast_cli(a->fd, "DTLS debugging %s\n", dtlsdebug > 1 ? "huge" : dtlsdebug > 0 ? "normal" : "none"); + return CLI_SUCCESS; + } + if (!strncasecmp(a->argv[a->argc-1], "huge", 4)) + dtlsdebug = 2; + else if (!strncasecmp(a->argv[a->argc-1], "normal", 6)) + dtlsdebug = 1; + else if (!strncasecmp(a->argv[a->argc-1], "none", 4)) + dtlsdebug = 0; + else + return CLI_SHOWUSAGE; + + ast_cli(a->fd, "DTLS debugging %s\n", dtlsdebug > 1 ? "huge" : dtlsdebug > 0 ? "normal" : "none"); + return CLI_SUCCESS; +} + static struct ast_cli_entry cli_rtp[] = { AST_CLI_DEFINE(handle_cli_rtp_set_debug, "Enable/Disable RTP debugging"), AST_CLI_DEFINE(handle_cli_rtcp_set_debug, "Enable/Disable RTCP debugging"), AST_CLI_DEFINE(handle_cli_rtcp_set_stats, "Enable/Disable RTCP stats"), + /* Meetecho: add DTLS debugging */ + AST_CLI_DEFINE(handle_cli_dtls_set_debug, "Enable/Disable DTLS debugging"), }; static int rtp_reload(int reload)