bool Parser::extractKeyingMaterial() { int r = 0; if (!isHandshakeFinished()) { printf("dtls::Parser::extractKeyingMaterial() - error: cannot extract keying material when the handshake isn't finished.\n"); return false; } r = SSL_export_keying_material(ssl, keying_material, DTLS_SRTP_MASTER_LEN * 2, "EXTRACTOR-dtls_srtp", 19, NULL, 0, 0); if (r != 1) { printf("dtls::Parser::extractKeyingMaterial() - error: cannot export the keying material.\n"); exit(1); } if (mode == DTLS_MODE_SERVER) { /* set the keying material in case we are a server. */ remote_key = keying_material; local_key = remote_key + DTLS_SRTP_MASTER_KEY_LEN; remote_salt = local_key + DTLS_SRTP_MASTER_KEY_LEN; local_salt = remote_salt + DTLS_SRTP_MASTER_SALT_LEN; } else if (mode == DTLS_MODE_CLIENT) { printf("dtls::Parser::extractKeyingMaterial() - error: client keying material not tested.\n"); /* set the keying material in case we are a client. */ local_key = keying_material; remote_key = local_key + DTLS_SRTP_MASTER_KEY_LEN; local_salt = remote_key + DTLS_SRTP_MASTER_KEY_LEN; remote_salt = local_salt + DTLS_SRTP_MASTER_SALT_LEN; exit(1); } else { printf("dtls::Parser::extractKeyingMaterial() - error: unhandled dtls::Parser mode!.\n"); exit(1); } #if 1 /* show some debug info (p->name probably = SRTP_AES128_CM_SHA1_80) */ SRTP_PROTECTION_PROFILE *p = SSL_get_selected_srtp_profile(ssl); if(!p) { printf("dtls::Parser::extractKeyingMaterial() - error: cannot extract the srtp_profile.\n"); exit(1); } printf("dtls::Parser::extractKeyingMaterial() - verbose: protection profile: %s\n", p->name); /* cipher probably is AES256-SHA */ printf("dtls::Parser::extractKeyingMaterial() - verbose: cipher: %s\n", SSL_CIPHER_get_name(SSL_get_current_cipher(ssl))); #endif return true; }
static int dlts_netsock_onhandshake_completed(NETIO_SOCK_T *pnetsock) { int rc = 0; SRTP_PROTECTION_PROFILE *srtpProfile = NULL; unsigned char keys[DTLS_SRTP_KEYING_MATERIAL_SIZE]; if(!(pnetsock->flags & NETIO_FLAG_SRTP)) { return 0; } if(!(srtpProfile = SSL_get_selected_srtp_profile(pnetsock->ssl.pCtxt))) { LOG(X_ERROR("DTLS-SRTP SSL_get_selected_srtp_profile failed, peer may not be DTLS-SRTP capable: %s"), ERR_reason_error_string(ERR_get_error())); return -1; } memset(keys, 0, sizeof(keys)); if(SSL_export_keying_material(pnetsock->ssl.pCtxt, keys, sizeof(keys), DTLS_SRTP_KEYS_LABEL, strlen(DTLS_SRTP_KEYS_LABEL), NULL, 0, 0) != 1) { LOG(X_ERROR("DTLS-SRTP SSL_export_keying_material failed: %s"), ERR_reason_error_string(ERR_get_error())); return -1; } //LOG(X_DEBUG("dlts_netsock_onhandshake_completed DTLS-SRTP handshake selected profile: '%s', master-keys: "), srtpProfile->name); LOGHEX_DEBUG(keys, sizeof(keys)); if(pnetsock->ssl.dtlsKeysUpdateCtxt.cbKeyUpdateFunc) { pnetsock->ssl.dtlsKeysUpdateCtxt.cbKeyUpdateFunc(pnetsock->ssl.dtlsKeysUpdateCtxt.pCbData, pnetsock, srtpProfile->name, pnetsock->ssl.dtlsKeysUpdateCtxt.dtls_serverkey, pnetsock->ssl.dtlsKeysUpdateCtxt.is_rtcp, keys, sizeof(keys)); } return rc; }
inline RTC::SrtpSession::Profile DtlsTransport::GetNegotiatedSrtpProfile() { MS_TRACE(); RTC::SrtpSession::Profile negotiated_srtp_profile = RTC::SrtpSession::Profile::NONE; // Ensure that the SRTP profile has been negotiated. SRTP_PROTECTION_PROFILE* ssl_srtp_profile = SSL_get_selected_srtp_profile(this->ssl); if (!ssl_srtp_profile) { return negotiated_srtp_profile; } // Get the negotiated SRTP profile. for (auto it = DtlsTransport::srtpProfiles.begin(); it != DtlsTransport::srtpProfiles.end(); ++it) { SrtpProfileMapEntry* profile_entry = &(*it); if (std::strcmp(ssl_srtp_profile->name, profile_entry->name) == 0) { MS_DEBUG("chosen SRTP profile: %s", profile_entry->name); negotiated_srtp_profile = profile_entry->profile; } } MS_ASSERT(negotiated_srtp_profile != RTC::SrtpSession::Profile::NONE, "chosen SRTP profile is not an available one"); return negotiated_srtp_profile; }
const char* Parser::getCipherSuite() { printf("dtls::Parser() - verbose: get cipher suite.\n"); if (!ssl) { return NULL; } if (!isHandshakeFinished()) { return NULL; } SRTP_PROTECTION_PROFILE *p = SSL_get_selected_srtp_profile(ssl); if (NULL == p) { printf("dtls::Parser::getCipherSuite() - cannot extract srtp profile.\n"); return NULL; } return p->name; }
static int get_srtp_key_info(const struct dtls_flow *tc, char *name, size_t sz, struct key *client_key, struct key *server_key) { SRTP_PROTECTION_PROFILE *sel; const char *keymatexportlabel = "EXTRACTOR-dtls_srtp"; uint8_t exportedkeymat[1024], *p; int keymatexportlen; size_t kl = 128, sl = 112; sel = SSL_get_selected_srtp_profile(tc->ssl); if (!sel) return ENOENT; str_ncpy(name, sel->name, sz); kl /= 8; sl /= 8; keymatexportlen = (int)(kl + sl)*2; if (keymatexportlen != 60) { warning("dtls: expected 60 bits, but keying material is %d\n", keymatexportlen); return EINVAL; } if (!SSL_export_keying_material(tc->ssl, exportedkeymat, keymatexportlen, keymatexportlabel, strlen(keymatexportlabel), NULL, 0, 0)) { return ENOENT; } p = exportedkeymat; memcpy(client_key->key, p, kl); p += kl; memcpy(server_key->key, p, kl); p += kl; memcpy(client_key->salt, p, sl); p += sl; memcpy(server_key->salt, p, sl); p += sl; client_key->key_len = server_key->key_len = kl; client_key->salt_len = server_key->salt_len = sl; return 0; }
static void export_srtp_keys(ErDtlsConnection *self) { typedef struct { guint8 v[SRTP_KEY_LEN]; } Key; typedef struct { guint8 v[SRTP_SALT_LEN]; } Salt; struct { Key client_key; Key server_key; Salt client_salt; Salt server_salt; } exported_keys; struct { Key key; Salt salt; } client_key, server_key; SRTP_PROTECTION_PROFILE *profile; ErDtlsSrtpCipher cipher; ErDtlsSrtpAuth auth; gint success; static gchar export_string[] = "EXTRACTOR-dtls_srtp"; success = SSL_export_keying_material(self->priv->ssl, (gpointer) &exported_keys, 60, export_string, strlen(export_string), NULL, 0, 0); if (!success) { LOG_WARNING(self, "failed to export srtp keys"); return; } profile = SSL_get_selected_srtp_profile(self->priv->ssl); LOG_INFO(self, "keys received, profile is %s", profile->name); switch (profile->id) { case SRTP_AES128_CM_SHA1_80: cipher = ER_DTLS_SRTP_CIPHER_AES_128_ICM; auth = ER_DTLS_SRTP_AUTH_HMAC_SHA1_80; break; case SRTP_AES128_CM_SHA1_32: cipher = ER_DTLS_SRTP_CIPHER_AES_128_ICM; auth = ER_DTLS_SRTP_AUTH_HMAC_SHA1_32; break; default: LOG_WARNING(self, "invalid crypto suite set by handshake"); goto beach; } client_key.key = exported_keys.client_key; server_key.key = exported_keys.server_key; client_key.salt = exported_keys.client_salt; server_key.salt = exported_keys.server_salt; if (self->priv->is_client) { g_signal_emit(self, signals[SIGNAL_ON_ENCODER_KEY], 0, &client_key, cipher, auth); g_signal_emit(self, signals[SIGNAL_ON_DECODER_KEY], 0, &server_key, cipher, auth); } else { g_signal_emit(self, signals[SIGNAL_ON_ENCODER_KEY], 0, &server_key, cipher, auth); g_signal_emit(self, signals[SIGNAL_ON_DECODER_KEY], 0, &client_key, cipher, auth); } beach: self->priv->keys_exported = TRUE; }
static int dtls_setup_crypto(struct packet_stream *ps, struct dtls_connection *d) { const char *err; SRTP_PROTECTION_PROFILE *spp; int i; const struct crypto_suite *cs; unsigned char keys[2 * (SRTP_MAX_MASTER_KEY_LEN + SRTP_MAX_MASTER_SALT_LEN)]; struct crypto_params client, server; err = "no SRTP protection profile negotiated"; spp = SSL_get_selected_srtp_profile(d->ssl); if (!spp) goto error; for (i = 0; i < num_crypto_suites; i++) { cs = &crypto_suites[i]; if (!cs->dtls_name) continue; if (!strcmp(cs->dtls_name, spp->name)) goto found; } err = "unknown SRTP protection profile negotiated"; goto error; found: i = SSL_export_keying_material(d->ssl, keys, sizeof(keys), "EXTRACTOR-dtls_srtp", strlen("EXTRACTOR-dtls_srtp"), NULL, 0, 0); err = "failed to export keying material"; if (i != 1) goto error; /* got everything XXX except MKI */ ZERO(client); ZERO(server); i = 0; client.crypto_suite = server.crypto_suite = cs; memcpy(client.master_key, &keys[i], cs->master_key_len); i += cs->master_key_len; memcpy(server.master_key, &keys[i], cs->master_key_len); i += cs->master_key_len; memcpy(client.master_salt, &keys[i], cs->master_salt_len); i += cs->master_salt_len; memcpy(server.master_salt, &keys[i], cs->master_salt_len); __DBG("SRTP keys negotiated: " "c-m: %02x%02x%02x%02x%02x%02x%02x%02x " "c-s: %02x%02x%02x%02x%02x%02x%02x%02x " "s-m: %02x%02x%02x%02x%02x%02x%02x%02x " "s-s: %02x%02x%02x%02x%02x%02x%02x%02x", client.master_key[0], client.master_key[1], client.master_key[2], client.master_key[3], client.master_key[4], client.master_key[5], client.master_key[6], client.master_key[7], client.master_salt[0], client.master_salt[1], client.master_salt[2], client.master_salt[3], client.master_salt[4], client.master_salt[5], client.master_salt[6], client.master_salt[7], server.master_key[0], server.master_key[1], server.master_key[2], server.master_key[3], server.master_key[4], server.master_key[5], server.master_key[6], server.master_key[7], server.master_salt[0], server.master_salt[1], server.master_salt[2], server.master_salt[3], server.master_salt[4], server.master_salt[5], server.master_salt[6], server.master_salt[7]); ilog(LOG_INFO, "DTLS-SRTP successfully negotiated"); if (d->active) { /* we're the client */ crypto_init(&ps->crypto, &client); crypto_init(&ps->sfd->crypto, &server); } else { /* we're the server */ crypto_init(&ps->crypto, &server); crypto_init(&ps->sfd->crypto, &client); } crypto_dump_keys(&ps->crypto, &ps->sfd->crypto); return 0; error: if (!spp) ilog(LOG_ERROR, "Failed to set up SRTP after DTLS negotiation: %s", err); else ilog(LOG_ERROR, "Failed to set up SRTP after DTLS negotiation: %s (profile \"%s\")", err, spp->name); return -1; }
int tnet_dtls_socket_do_handshake(tnet_dtls_socket_handle_t* handle, const struct sockaddr_storage* remote_addr) { #if !HAVE_OPENSSL || !HAVE_OPENSSL_DTLS TSK_DEBUG_ERROR("OpenSSL or DTLS not enabled"); return -1; #else tnet_dtls_socket_t *socket = handle; int ret = 0, len; void* out_data; if (!socket) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } tsk_safeobj_lock(socket); // update remote address even if handshaking is completed if (remote_addr) { socket->remote.addr = *remote_addr; } if (socket->handshake_completed) { TSK_DEBUG_INFO("Handshake completed"); ret = 0; goto bail; } if (!socket->handshake_started) { if ((ret = SSL_do_handshake(socket->ssl)) != 1) { switch ((ret = SSL_get_error(socket->ssl, ret))) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: case SSL_ERROR_NONE: break; default: TSK_DEBUG_ERROR("DTLS handshake failed [%s]", ERR_error_string(ERR_get_error(), tsk_null)); _tnet_dtls_socket_raise_event_dataless(socket, tnet_dtls_socket_event_type_handshake_failed); ret = -2; goto bail; } } socket->handshake_started = (ret == SSL_ERROR_NONE); // TODO: reset for renegotiation } if ((len = (int)BIO_get_mem_data(socket->wbio, &out_data)) > 0 && out_data) { if (socket->handshake_storedata) { // e.g. when TURN is enabled we have to query handshaking data and sent it via the negotiated channel if ((int)socket->handshake_data.size < len) { if (!(socket->handshake_data.ptr = tsk_realloc(socket->handshake_data.ptr, len))) { socket->handshake_data.size = 0; socket->handshake_data.count = 0; ret = -5; goto bail; } socket->handshake_data.size = len; } socket->handshake_data.count = len; memcpy(socket->handshake_data.ptr, out_data, len); } else { int sentlen = 0; tnet_port_t port; tnet_ip_t ip; tsk_bool_t is_dgram = TNET_SOCKET_TYPE_IS_DGRAM(socket->wrapped_sock->type); const uint8_t *record_ptr, *records_ptr = out_data; tsk_size_t record_size; int records_len = len; tnet_get_sockip_n_port((const struct sockaddr *)&socket->remote.addr, &ip, &port); TSK_DEBUG_INFO("DTLS data handshake to send with len = %d, from(%.*s/%d) to(%.*s/%d)", len, (int)sizeof(socket->wrapped_sock->ip), socket->wrapped_sock->ip, socket->wrapped_sock->port, (int)sizeof(ip), ip, port); //!\ IP fragmentation issues must be avoided even if the local transport is TCP/TLS because the relayed (TURN) transport could be UDP while (records_len > 0 && (ret = tnet_dtls_socket_get_record_first(records_ptr, (tsk_size_t)records_len, &record_ptr, &record_size)) == 0) { if (is_dgram) { sentlen += tnet_sockfd_sendto(socket->wrapped_sock->fd, (const struct sockaddr *)&socket->remote.addr, record_ptr, record_size); } else { sentlen += tnet_socket_send_stream(socket->wrapped_sock, record_ptr, record_size); } records_len -= (int)record_size; records_ptr += record_size; } TSK_DEBUG_INFO("DTLS data handshake sent len = %d", sentlen); } } BIO_reset(socket->rbio); BIO_reset(socket->wbio); if ((socket->handshake_completed = SSL_is_init_finished(socket->ssl))) { TSK_DEBUG_INFO("DTLS handshake completed"); #if HAVE_OPENSSL_DTLS_SRTP if (socket->use_srtp){ #if !defined(SRTP_MAX_KEY_LEN) # define cipher_key_length (128 >> 3) // rfc5764 4.1.2. SRTP Protection Profiles # define cipher_salt_length (112 >> 3) // rfc5764 4.1.2. SRTP Protection Profiles // "cipher_key_length" is also equal to srtp_profile_get_master_key_length(srtp_profile_aes128_cm_sha1_80) // "cipher_salt_length" is also srtp_profile_get_master_salt_length(srtp_profile_aes128_cm_sha1_80) # define SRTP_MAX_KEY_LEN (cipher_key_length + cipher_salt_length) #endif /* SRTP_MAX_KEY_LEN */ #define EXTRACTOR_dtls_srtp_text "EXTRACTOR-dtls_srtp" #define EXTRACTOR_dtls_srtp_text_len 19 uint8_t keying_material[SRTP_MAX_KEY_LEN << 1]; static const tsk_size_t keying_material_size = sizeof(keying_material); /*if(socket->use_srtp)*/{ SRTP_PROTECTION_PROFILE *p = SSL_get_selected_srtp_profile(socket->ssl); if (!p) { TSK_DEBUG_ERROR("SSL_get_selected_srtp_profile() returned null [%s]", ERR_error_string(ERR_get_error(), tsk_null)); ret = -2; goto bail; } // alert user _tnet_dtls_socket_raise_event(socket, tnet_dtls_socket_event_type_dtls_srtp_profile_selected, p->name, tsk_strlen(p->name)); memset(keying_material, 0, sizeof(keying_material)); // rfc5764 - 4.2. Key Derivation ret = SSL_export_keying_material(socket->ssl, keying_material, sizeof(keying_material), EXTRACTOR_dtls_srtp_text, EXTRACTOR_dtls_srtp_text_len, tsk_null, 0, 0); if (ret != 1) { // alert listener _tnet_dtls_socket_raise_event_dataless(socket, tnet_dtls_socket_event_type_error); TSK_DEBUG_ERROR("SSL_export_keying_material() failed [%s]", ERR_error_string(ERR_get_error(), tsk_null)); ret = -2; goto bail; } } // alert listener _tnet_dtls_socket_raise_event(socket, tnet_dtls_socket_event_type_dtls_srtp_data, keying_material, keying_material_size); } #endif /* HAVE_OPENSSL_DTLS_SRTP */ _tnet_dtls_socket_raise_event_dataless(socket, tnet_dtls_socket_event_type_handshake_succeed); } ret = 0; // clear "ret", error will directly jump to "bail:" bail: tsk_safeobj_unlock(socket); return ret; #endif }
static void print_stuff(BIO * bio, SSL * s, int full) { X509 *peer = NULL; char *p; static const char *space = " "; char buf[BUFSIZ]; STACK_OF(X509) * sk; STACK_OF(X509_NAME) * sk2; const SSL_CIPHER *c; X509_NAME *xn; int j, i; unsigned char *exportedkeymat; if (full) { int got_a_chain = 0; sk = SSL_get_peer_cert_chain(s); if (sk != NULL) { got_a_chain = 1; /* we don't have it for SSL2 * (yet) */ BIO_printf(bio, "---\nCertificate chain\n"); for (i = 0; i < sk_X509_num(sk); i++) { X509_NAME_oneline(X509_get_subject_name( sk_X509_value(sk, i)), buf, sizeof buf); BIO_printf(bio, "%2d s:%s\n", i, buf); X509_NAME_oneline(X509_get_issuer_name( sk_X509_value(sk, i)), buf, sizeof buf); BIO_printf(bio, " i:%s\n", buf); if (c_showcerts) PEM_write_bio_X509(bio, sk_X509_value(sk, i)); } } BIO_printf(bio, "---\n"); peer = SSL_get_peer_certificate(s); if (peer != NULL) { BIO_printf(bio, "Server certificate\n"); if (!(c_showcerts && got_a_chain)) /* Redundant if we * showed the whole * chain */ PEM_write_bio_X509(bio, peer); X509_NAME_oneline(X509_get_subject_name(peer), buf, sizeof buf); BIO_printf(bio, "subject=%s\n", buf); X509_NAME_oneline(X509_get_issuer_name(peer), buf, sizeof buf); BIO_printf(bio, "issuer=%s\n", buf); } else BIO_printf(bio, "no peer certificate available\n"); sk2 = SSL_get_client_CA_list(s); if ((sk2 != NULL) && (sk_X509_NAME_num(sk2) > 0)) { BIO_printf(bio, "---\nAcceptable client certificate CA names\n"); for (i = 0; i < sk_X509_NAME_num(sk2); i++) { xn = sk_X509_NAME_value(sk2, i); X509_NAME_oneline(xn, buf, sizeof(buf)); BIO_write(bio, buf, strlen(buf)); BIO_write(bio, "\n", 1); } } else { BIO_printf(bio, "---\nNo client certificate CA names sent\n"); } p = SSL_get_shared_ciphers(s, buf, sizeof buf); if (p != NULL) { /* * This works only for SSL 2. In later protocol * versions, the client does not know what other * ciphers (in addition to the one to be used in the * current connection) the server supports. */ BIO_printf(bio, "---\nCiphers common between both SSL endpoints:\n"); j = i = 0; while (*p) { if (*p == ':') { BIO_write(bio, space, 15 - j % 25); i++; j = 0; BIO_write(bio, ((i % 3) ? " " : "\n"), 1); } else { BIO_write(bio, p, 1); j++; } p++; } BIO_write(bio, "\n", 1); } BIO_printf(bio, "---\nSSL handshake has read %ld bytes and written %ld bytes\n", BIO_number_read(SSL_get_rbio(s)), BIO_number_written(SSL_get_wbio(s))); } BIO_printf(bio, (SSL_cache_hit(s) ? "---\nReused, " : "---\nNew, ")); c = SSL_get_current_cipher(s); BIO_printf(bio, "%s, Cipher is %s\n", SSL_CIPHER_get_version(c), SSL_CIPHER_get_name(c)); if (peer != NULL) { EVP_PKEY *pktmp; pktmp = X509_get_pubkey(peer); BIO_printf(bio, "Server public key is %d bit\n", EVP_PKEY_bits(pktmp)); EVP_PKEY_free(pktmp); } BIO_printf(bio, "Secure Renegotiation IS%s supported\n", SSL_get_secure_renegotiation_support(s) ? "" : " NOT"); /* Compression is not supported and will always be none. */ BIO_printf(bio, "Compression: NONE\n"); BIO_printf(bio, "Expansion: NONE\n"); #ifdef SSL_DEBUG { /* Print out local port of connection: useful for debugging */ int sock; struct sockaddr_in ladd; socklen_t ladd_size = sizeof(ladd); sock = SSL_get_fd(s); getsockname(sock, (struct sockaddr *) & ladd, &ladd_size); BIO_printf(bio_c_out, "LOCAL PORT is %u\n", ntohs(ladd.sin_port)); } #endif #if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) if (next_proto.status != -1) { const unsigned char *proto; unsigned int proto_len; SSL_get0_next_proto_negotiated(s, &proto, &proto_len); BIO_printf(bio, "Next protocol: (%d) ", next_proto.status); BIO_write(bio, proto, proto_len); BIO_write(bio, "\n", 1); } #endif #ifndef OPENSSL_NO_SRTP { SRTP_PROTECTION_PROFILE *srtp_profile = SSL_get_selected_srtp_profile(s); if (srtp_profile) BIO_printf(bio, "SRTP Extension negotiated, profile=%s\n", srtp_profile->name); } #endif SSL_SESSION_print(bio, SSL_get_session(s)); if (keymatexportlabel != NULL) { BIO_printf(bio, "Keying material exporter:\n"); BIO_printf(bio, " Label: '%s'\n", keymatexportlabel); BIO_printf(bio, " Length: %i bytes\n", keymatexportlen); exportedkeymat = malloc(keymatexportlen); if (exportedkeymat != NULL) { if (!SSL_export_keying_material(s, exportedkeymat, keymatexportlen, keymatexportlabel, strlen(keymatexportlabel), NULL, 0, 0)) { BIO_printf(bio, " Error\n"); } else { BIO_printf(bio, " Keying material: "); for (i = 0; i < keymatexportlen; i++) BIO_printf(bio, "%02X", exportedkeymat[i]); BIO_printf(bio, "\n"); } free(exportedkeymat); } } BIO_printf(bio, "---\n"); if (peer != NULL) X509_free(peer); /* flush, or debugging output gets mixed with http response */ (void) BIO_flush(bio); }
int krx_udp_receive(udp_conn* c) { socklen_t len = sizeof(c->client); ssize_t nread = recvfrom(c->sock, c->buf, KRX_UDP_BUF_LEN, 0, (struct sockaddr*)&c->client, &len); if(nread < 0) { printf("Error: cannot receive.\n"); return -1; } if(nread < 2) { printf("Only received 2 bytes?\n"); return 0; } if((c->buf[0] == 0x00 || c->buf[0] == 0x01) && (c->buf[1] == 0x00 || c->buf[1] == 0x01) ) { handle_stun(c, c->buf, nread); } else { if(krx_dtls_is_handshake_done(&c->dtls) > 0) { if(c->state == KRX_STATE_NONE) { // when done, we pass on the data libsrtp c->state = KRX_STATE_SSL_INIT_READY; printf("---------------------- finished --------------------------\n"); uint8_t material[KRX_SRTP_MASTER_LEN * 2]; int r = SSL_export_keying_material(c->dtls.ssl, material, KRX_SRTP_MASTER_LEN * 2, "EXTRACTOR-dtls_srtp", 19, NULL, 0, 0); if(r == 0) { printf("Error: cannot export the SSL keying material.\n"); exit(EXIT_FAILURE); } // extracking keying example https://github.com/traviscross/baresip/blob/8974d662c942b10a9bb05223ddc7881896dd4c2f/modules/dtls_srtp/tls_udp.c /* Keys:: http://tools.ietf.org/html/rfc5764#section-4.2, note: client <> server use different keying, we handle server for now. */ uint8_t* remote_key = material; uint8_t* local_key = remote_key + KRX_SRTP_MASTER_KEY_LEN; uint8_t* remote_salt = local_key + KRX_SRTP_MASTER_KEY_LEN; uint8_t* local_salt = remote_salt + KRX_SRTP_MASTER_SALT_LEN;; memcpy(c->srtp.policy.key, remote_key, KRX_SRTP_MASTER_KEY_LEN); memcpy(c->srtp.policy.key + KRX_SRTP_MASTER_KEY_LEN, remote_salt, KRX_SRTP_MASTER_SALT_LEN); SRTP_PROTECTION_PROFILE *p = SSL_get_selected_srtp_profile(c->dtls.ssl); if(!p) { printf("Error: cannot extract the srtp_profile.\n"); exit(EXIT_FAILURE); } printf(">>>>>>> %s <<<<<\n", p->name); // TLS_RSA_WITH_AES_128_CBC_SHA printf("---> cipher: %s\n", SSL_CIPHER_get_name(SSL_get_current_cipher(c->dtls.ssl))); /* create SRTP session */ err_status_t sr = srtp_create(&c->srtp.session, &c->srtp.policy); if(sr != err_status_ok) { printf("Error: cannot create srtp session: %d.\n", sr); exit(EXIT_FAILURE); } /* @TODO --- CLEANUP! - WE NEED TO UNPROTECT THIS DIRECTLY!!! SEE "MARKER-MARKER" below*/ int buflen = nread; sr = srtp_unprotect(c->srtp.session, c->buf, &buflen); if(sr != err_status_ok) { printf("Error: cannot unprotect, err: %d. len: %d <> %d\n", sr, len, buflen); } else { //printf("~ %zd bytes read // buflen: %d.\n", nread, buflen); krx_rtp_decode(&c->rtp, c->buf, buflen); } } else if(c->state == KRX_STATE_SSL_INIT_READY) { /* @TODO --- CLEANUP! duplicate, see a couple of line above */ /* MARKER-MARKER */ int buflen = nread; err_status_t sr = srtp_unprotect(c->srtp.session, c->buf, &buflen); if(sr != err_status_ok) { printf("Error: cannot unprotect, err: %d. len: %d <> %d\n", sr, len, buflen); } else { //printf("~ %zd bytes read // buflen: %d.\n", nread, buflen); krx_rtp_decode(&c->rtp, c->buf, buflen); } } } else { krx_dtls_handle_traffic(&c->dtls, c->buf, nread); } } return 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); } } } }