Allow remote fingerprint update during a call
Changes include the following
1. modify FakeDtlsIdentityStore to support alternate certificate so we could have a different fingerprint in test case.
2. dtlstransportchannel can accept a new fingerprint and trigger DTLS handshake.
3. #2 will trigger new signal on the media side to reset SRTP context. Only reset SRTP context when we are using DTLS (not SDES).
4. Test cases for caller or callee are transfees.
TBR=pthatcher@webrtc.org
BUG=webrtc:3618
This is a reland of https://codereview.webrtc.org/1453523002
Review URL: https://codereview.webrtc.org/1505573002 .
Cr-Commit-Position: refs/heads/master@{#10903}
diff --git a/talk/app/webrtc/peerconnection_unittest.cc b/talk/app/webrtc/peerconnection_unittest.cc
index 7edd039..9ecf080 100644
--- a/talk/app/webrtc/peerconnection_unittest.cc
+++ b/talk/app/webrtc/peerconnection_unittest.cc
@@ -145,18 +145,31 @@
public SignalingMessageReceiver,
public ObserverInterface {
public:
- static PeerConnectionTestClient* CreateClient(
+ static PeerConnectionTestClient* CreateClientWithDtlsIdentityStore(
const std::string& id,
const MediaConstraintsInterface* constraints,
- const PeerConnectionFactory::Options* options) {
+ const PeerConnectionFactory::Options* options,
+ rtc::scoped_ptr<webrtc::DtlsIdentityStoreInterface> dtls_identity_store) {
PeerConnectionTestClient* client(new PeerConnectionTestClient(id));
- if (!client->Init(constraints, options)) {
+ if (!client->Init(constraints, options, dtls_identity_store.Pass())) {
delete client;
return nullptr;
}
return client;
}
+ static PeerConnectionTestClient* CreateClient(
+ const std::string& id,
+ const MediaConstraintsInterface* constraints,
+ const PeerConnectionFactory::Options* options) {
+ rtc::scoped_ptr<FakeDtlsIdentityStore> dtls_identity_store(
+ rtc::SSLStreamAdapter::HaveDtlsSrtp() ? new FakeDtlsIdentityStore()
+ : nullptr);
+
+ return CreateClientWithDtlsIdentityStore(id, constraints, options,
+ dtls_identity_store.Pass());
+ }
+
~PeerConnectionTestClient() {
while (!fake_video_renderers_.empty()) {
RenderMap::iterator it = fake_video_renderers_.begin();
@@ -704,8 +717,10 @@
explicit PeerConnectionTestClient(const std::string& id) : id_(id) {}
- bool Init(const MediaConstraintsInterface* constraints,
- const PeerConnectionFactory::Options* options) {
+ bool Init(
+ const MediaConstraintsInterface* constraints,
+ const PeerConnectionFactory::Options* options,
+ rtc::scoped_ptr<webrtc::DtlsIdentityStoreInterface> dtls_identity_store) {
EXPECT_TRUE(!peer_connection_);
EXPECT_TRUE(!peer_connection_factory_);
allocator_factory_ = webrtc::FakePortAllocatorFactory::Create();
@@ -729,23 +744,21 @@
if (options) {
peer_connection_factory_->SetOptions(*options);
}
- peer_connection_ = CreatePeerConnection(allocator_factory_.get(),
- constraints);
+ peer_connection_ = CreatePeerConnection(
+ allocator_factory_.get(), constraints, dtls_identity_store.Pass());
return peer_connection_.get() != nullptr;
}
rtc::scoped_refptr<webrtc::PeerConnectionInterface> CreatePeerConnection(
webrtc::PortAllocatorFactoryInterface* factory,
- const MediaConstraintsInterface* constraints) {
+ const MediaConstraintsInterface* constraints,
+ rtc::scoped_ptr<webrtc::DtlsIdentityStoreInterface> dtls_identity_store) {
// CreatePeerConnection with IceServers.
webrtc::PeerConnectionInterface::IceServers ice_servers;
webrtc::PeerConnectionInterface::IceServer ice_server;
ice_server.uri = "stun:stun.l.google.com:19302";
ice_servers.push_back(ice_server);
- rtc::scoped_ptr<webrtc::DtlsIdentityStoreInterface> dtls_identity_store(
- rtc::SSLStreamAdapter::HaveDtlsSrtp() ? new FakeDtlsIdentityStore()
- : nullptr);
return peer_connection_factory_->CreatePeerConnection(
ice_servers, constraints, factory, dtls_identity_store.Pass(), this);
}
@@ -979,6 +992,11 @@
nullptr);
}
+ void SetSignalingReceivers() {
+ initiating_client_->set_signaling_message_receiver(receiving_client_.get());
+ receiving_client_->set_signaling_message_receiver(initiating_client_.get());
+ }
+
bool CreateTestClients(MediaConstraintsInterface* init_constraints,
PeerConnectionFactory::Options* init_options,
MediaConstraintsInterface* recv_constraints,
@@ -990,8 +1008,7 @@
if (!initiating_client_ || !receiving_client_) {
return false;
}
- initiating_client_->set_signaling_message_receiver(receiving_client_.get());
- receiving_client_->set_signaling_message_receiver(initiating_client_.get());
+ SetSignalingReceivers();
return true;
}
@@ -1068,6 +1085,31 @@
kMaxWaitForFramesMs);
}
+ void SetupAndVerifyDtlsCall() {
+ MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp);
+ FakeConstraints setup_constraints;
+ setup_constraints.AddMandatory(MediaConstraintsInterface::kEnableDtlsSrtp,
+ true);
+ ASSERT_TRUE(CreateTestClients(&setup_constraints, &setup_constraints));
+ LocalP2PTest();
+ VerifyRenderedSize(640, 480);
+ }
+
+ PeerConnectionTestClient* CreateDtlsClientWithAlternateKey() {
+ FakeConstraints setup_constraints;
+ setup_constraints.AddMandatory(MediaConstraintsInterface::kEnableDtlsSrtp,
+ true);
+
+ rtc::scoped_ptr<FakeDtlsIdentityStore> dtls_identity_store(
+ rtc::SSLStreamAdapter::HaveDtlsSrtp() ? new FakeDtlsIdentityStore()
+ : nullptr);
+ dtls_identity_store->use_alternate_key();
+
+ // Make sure the new client is using a different certificate.
+ return PeerConnectionTestClient::CreateClientWithDtlsIdentityStore(
+ "New Peer: ", &setup_constraints, nullptr, dtls_identity_store.Pass());
+ }
+
void SendRtpData(webrtc::DataChannelInterface* dc, const std::string& data) {
// Messages may get lost on the unreliable DataChannel, so we send multiple
// times to avoid test flakiness.
@@ -1081,10 +1123,29 @@
PeerConnectionTestClient* initializing_client() {
return initiating_client_.get();
}
+
+ // Set the |initiating_client_| to the |client| passed in and return the
+ // original |initiating_client_|.
+ PeerConnectionTestClient* set_initializing_client(
+ PeerConnectionTestClient* client) {
+ PeerConnectionTestClient* old = initiating_client_.release();
+ initiating_client_.reset(client);
+ return old;
+ }
+
PeerConnectionTestClient* receiving_client() {
return receiving_client_.get();
}
+ // Set the |receiving_client_| to the |client| passed in and return the
+ // original |receiving_client_|.
+ PeerConnectionTestClient* set_receiving_client(
+ PeerConnectionTestClient* client) {
+ PeerConnectionTestClient* old = receiving_client_.release();
+ receiving_client_.reset(client);
+ return old;
+ }
+
private:
rtc::scoped_ptr<rtc::PhysicalSocketServer> pss_;
rtc::scoped_ptr<rtc::VirtualSocketServer> ss_;
@@ -1146,13 +1207,7 @@
// This test sets up a call between two endpoints that are configured to use
// DTLS key agreement. As a result, DTLS is negotiated and used for transport.
TEST_F(MAYBE_JsepPeerConnectionP2PTestClient, LocalP2PTestDtls) {
- MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp);
- FakeConstraints setup_constraints;
- setup_constraints.AddMandatory(MediaConstraintsInterface::kEnableDtlsSrtp,
- true);
- ASSERT_TRUE(CreateTestClients(&setup_constraints, &setup_constraints));
- LocalP2PTest();
- VerifyRenderedSize(640, 480);
+ SetupAndVerifyDtlsCall();
}
// This test sets up a audio call initially and then upgrades to audio/video,
@@ -1169,6 +1224,42 @@
receiving_client()->Negotiate();
}
+// This test sets up a call transfer to a new caller with a different DTLS
+// fingerprint.
+TEST_F(MAYBE_JsepPeerConnectionP2PTestClient, LocalP2PTestDtlsTransferCallee) {
+ MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp);
+ SetupAndVerifyDtlsCall();
+
+ // Keeping the original peer around which will still send packets to the
+ // receiving client. These SRTP packets will be dropped.
+ rtc::scoped_ptr<PeerConnectionTestClient> original_peer(
+ set_initializing_client(CreateDtlsClientWithAlternateKey()));
+ original_peer->pc()->Close();
+
+ SetSignalingReceivers();
+ receiving_client()->SetExpectIceRestart(true);
+ LocalP2PTest();
+ VerifyRenderedSize(640, 480);
+}
+
+// This test sets up a call transfer to a new callee with a different DTLS
+// fingerprint.
+TEST_F(MAYBE_JsepPeerConnectionP2PTestClient, LocalP2PTestDtlsTransferCaller) {
+ MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp);
+ SetupAndVerifyDtlsCall();
+
+ // Keeping the original peer around which will still send packets to the
+ // receiving client. These SRTP packets will be dropped.
+ rtc::scoped_ptr<PeerConnectionTestClient> original_peer(
+ set_receiving_client(CreateDtlsClientWithAlternateKey()));
+ original_peer->pc()->Close();
+
+ SetSignalingReceivers();
+ initializing_client()->IceRestart();
+ LocalP2PTest();
+ VerifyRenderedSize(640, 480);
+}
+
// This test sets up a call between two endpoints that are configured to use
// DTLS key agreement. The offerer don't support SDES. As a result, DTLS is
// negotiated and used for transport.
diff --git a/talk/app/webrtc/test/fakedtlsidentitystore.h b/talk/app/webrtc/test/fakedtlsidentitystore.h
index 0f9bdb9..5e596ca 100644
--- a/talk/app/webrtc/test/fakedtlsidentitystore.h
+++ b/talk/app/webrtc/test/fakedtlsidentitystore.h
@@ -34,36 +34,67 @@
#include "talk/app/webrtc/peerconnectioninterface.h"
#include "webrtc/base/rtccertificate.h"
-static const char kRSA_PRIVATE_KEY_PEM[] =
- "-----BEGIN RSA PRIVATE KEY-----\n"
- "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMYRkbhmI7kVA/rM\n"
- "czsZ+6JDhDvnkF+vn6yCAGuRPV03zuRqZtDy4N4to7PZu9PjqrRl7nDMXrG3YG9y\n"
- "rlIAZ72KjcKKFAJxQyAKLCIdawKRyp8RdK3LEySWEZb0AV58IadqPZDTNHHRX8dz\n"
- "5aTSMsbbkZ+C/OzTnbiMqLL/vg6jAgMBAAECgYAvgOs4FJcgvp+TuREx7YtiYVsH\n"
- "mwQPTum2z/8VzWGwR8BBHBvIpVe1MbD/Y4seyI2aco/7UaisatSgJhsU46/9Y4fq\n"
- "2TwXH9QANf4at4d9n/R6rzwpAJOpgwZgKvdQjkfrKTtgLV+/dawvpxUYkRH4JZM1\n"
- "CVGukMfKNrSVH4Ap4QJBAOJmGV1ASPnB4r4nc99at7JuIJmd7fmuVUwUgYi4XgaR\n"
- "WhScBsgYwZ/JoywdyZJgnbcrTDuVcWG56B3vXbhdpMsCQQDf9zeJrjnPZ3Cqm79y\n"
- "kdqANep0uwZciiNiWxsQrCHztywOvbFhdp8iYVFG9EK8DMY41Y5TxUwsHD+67zao\n"
- "ZNqJAkEA1suLUP/GvL8IwuRneQd2tWDqqRQ/Td3qq03hP7e77XtF/buya3Ghclo5\n"
- "54czUR89QyVfJEC6278nzA7n2h1uVQJAcG6mztNL6ja/dKZjYZye2CY44QjSlLo0\n"
- "MTgTSjdfg/28fFn2Jjtqf9Pi/X+50LWI/RcYMC2no606wRk9kyOuIQJBAK6VSAim\n"
- "1pOEjsYQn0X5KEIrz1G3bfCbB848Ime3U2/FWlCHMr6ch8kCZ5d1WUeJD3LbwMNG\n"
- "UCXiYxSsu20QNVw=\n"
- "-----END RSA PRIVATE KEY-----\n";
-
-static const char kCERT_PEM[] =
- "-----BEGIN CERTIFICATE-----\n"
- "MIIBmTCCAQKgAwIBAgIEbzBSAjANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDEwZX\n"
- "ZWJSVEMwHhcNMTQwMTAyMTgyNDQ3WhcNMTQwMjAxMTgyNDQ3WjARMQ8wDQYDVQQD\n"
- "EwZXZWJSVEMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMYRkbhmI7kVA/rM\n"
- "czsZ+6JDhDvnkF+vn6yCAGuRPV03zuRqZtDy4N4to7PZu9PjqrRl7nDMXrG3YG9y\n"
- "rlIAZ72KjcKKFAJxQyAKLCIdawKRyp8RdK3LEySWEZb0AV58IadqPZDTNHHRX8dz\n"
- "5aTSMsbbkZ+C/OzTnbiMqLL/vg6jAgMBAAEwDQYJKoZIhvcNAQELBQADgYEAUflI\n"
- "VUe5Krqf5RVa5C3u/UTAOAUJBiDS3VANTCLBxjuMsvqOG0WvaYWP3HYPgrz0jXK2\n"
- "LJE/mGw3MyFHEqi81jh95J+ypl6xKW6Rm8jKLR87gUvCaVYn/Z4/P3AqcQTB7wOv\n"
- "UD0A8qfhfDM+LK6rPAnCsVN0NRDY3jvd6rzix9M=\n"
- "-----END CERTIFICATE-----\n";
+static const struct {
+ const char* rsa_private_key_pem;
+ const char* cert_pem;
+} kKeysAndCerts[] = {
+ {"-----BEGIN RSA PRIVATE KEY-----\n"
+ "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMYRkbhmI7kVA/rM\n"
+ "czsZ+6JDhDvnkF+vn6yCAGuRPV03zuRqZtDy4N4to7PZu9PjqrRl7nDMXrG3YG9y\n"
+ "rlIAZ72KjcKKFAJxQyAKLCIdawKRyp8RdK3LEySWEZb0AV58IadqPZDTNHHRX8dz\n"
+ "5aTSMsbbkZ+C/OzTnbiMqLL/vg6jAgMBAAECgYAvgOs4FJcgvp+TuREx7YtiYVsH\n"
+ "mwQPTum2z/8VzWGwR8BBHBvIpVe1MbD/Y4seyI2aco/7UaisatSgJhsU46/9Y4fq\n"
+ "2TwXH9QANf4at4d9n/R6rzwpAJOpgwZgKvdQjkfrKTtgLV+/dawvpxUYkRH4JZM1\n"
+ "CVGukMfKNrSVH4Ap4QJBAOJmGV1ASPnB4r4nc99at7JuIJmd7fmuVUwUgYi4XgaR\n"
+ "WhScBsgYwZ/JoywdyZJgnbcrTDuVcWG56B3vXbhdpMsCQQDf9zeJrjnPZ3Cqm79y\n"
+ "kdqANep0uwZciiNiWxsQrCHztywOvbFhdp8iYVFG9EK8DMY41Y5TxUwsHD+67zao\n"
+ "ZNqJAkEA1suLUP/GvL8IwuRneQd2tWDqqRQ/Td3qq03hP7e77XtF/buya3Ghclo5\n"
+ "54czUR89QyVfJEC6278nzA7n2h1uVQJAcG6mztNL6ja/dKZjYZye2CY44QjSlLo0\n"
+ "MTgTSjdfg/28fFn2Jjtqf9Pi/X+50LWI/RcYMC2no606wRk9kyOuIQJBAK6VSAim\n"
+ "1pOEjsYQn0X5KEIrz1G3bfCbB848Ime3U2/FWlCHMr6ch8kCZ5d1WUeJD3LbwMNG\n"
+ "UCXiYxSsu20QNVw=\n"
+ "-----END RSA PRIVATE KEY-----\n",
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIBmTCCAQKgAwIBAgIEbzBSAjANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDEwZX\n"
+ "ZWJSVEMwHhcNMTQwMTAyMTgyNDQ3WhcNMTQwMjAxMTgyNDQ3WjARMQ8wDQYDVQQD\n"
+ "EwZXZWJSVEMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMYRkbhmI7kVA/rM\n"
+ "czsZ+6JDhDvnkF+vn6yCAGuRPV03zuRqZtDy4N4to7PZu9PjqrRl7nDMXrG3YG9y\n"
+ "rlIAZ72KjcKKFAJxQyAKLCIdawKRyp8RdK3LEySWEZb0AV58IadqPZDTNHHRX8dz\n"
+ "5aTSMsbbkZ+C/OzTnbiMqLL/vg6jAgMBAAEwDQYJKoZIhvcNAQELBQADgYEAUflI\n"
+ "VUe5Krqf5RVa5C3u/UTAOAUJBiDS3VANTCLBxjuMsvqOG0WvaYWP3HYPgrz0jXK2\n"
+ "LJE/mGw3MyFHEqi81jh95J+ypl6xKW6Rm8jKLR87gUvCaVYn/Z4/P3AqcQTB7wOv\n"
+ "UD0A8qfhfDM+LK6rPAnCsVN0NRDY3jvd6rzix9M=\n"
+ "-----END CERTIFICATE-----\n"},
+ {"-----BEGIN RSA PRIVATE KEY-----\n"
+ "MIICXQIBAAKBgQDeYqlyJ1wuiMsi905e3X81/WA/G3ym50PIDZBVtSwZi7JVQPgj\n"
+ "Bl8CPZMvDh9EwB4Ji9ytA8dZZbQ4WbJWPr73zPpJSCvQqz6sOXSlenBRi72acNaQ\n"
+ "sOR/qPvviJx5I6Hqo4qemfnjZhAW85a5BpgrAwKgMLIQTHCTLWwVSyrDrwIDAQAB\n"
+ "AoGARni9eY8/hv+SX+I+05EdXt6MQXNUbQ+cSykBNCfVccLzIFEWUQMT2IHqwl6X\n"
+ "ShIXcq7/n1QzOAEiuzixauM3YHg4xZ1Um2Ha9a7ig5Xg4v6b43bmMkNE6LkoAtYs\n"
+ "qnQdfMh442b1liDud6IMb1Qk0amt3fSrgRMc547TZQVx4QECQQDxUeDm94r3p4ng\n"
+ "5rCLLC1K5/6HSTZsh7jatKPlz7GfP/IZlYV7iE5784/n0wRiCjZOS7hQRy/8m2Gp\n"
+ "pf4aZq+DAkEA6+np4d36FYikydvUrupLT3FkdRHGn/v83qOll/VmeNh+L1xMZlIP\n"
+ "tM26hAXCcQb7O5+J9y3cx2CAQsBS11ZXZQJAfGgTo76WG9p5UEJdXUInD2jOZPwv\n"
+ "XIATolxh6kXKcijLLLlSmT7KB0inNYIpzkkpee+7U1d/u6B3FriGaSHq9QJBAM/J\n"
+ "ICnDdLCgwNvWVraVQC3BpwSB2pswvCFwq7py94V60XFvbw80Ogc6qIv98qvQxVlX\n"
+ "hJIEgA/PjEi+0ng94Q0CQQDm8XSDby35gmjO+6eRmJtAjtB7nguLvrPXM6CPXRmD\n"
+ "sRoBocpHw6j9UdzZ6qYG0FkdXZghezXFY58ro2BYYRR3\n"
+ "-----END RSA PRIVATE KEY-----\n",
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIICWDCCAcGgAwIBAgIJALgDjxMbBOhbMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV\n"
+ "BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX\n"
+ "aWRnaXRzIFB0eSBMdGQwHhcNMTUxMTEzMjIzMjEzWhcNMTYxMTEyMjIzMjEzWjBF\n"
+ "MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50\n"
+ "ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n"
+ "gQDeYqlyJ1wuiMsi905e3X81/WA/G3ym50PIDZBVtSwZi7JVQPgjBl8CPZMvDh9E\n"
+ "wB4Ji9ytA8dZZbQ4WbJWPr73zPpJSCvQqz6sOXSlenBRi72acNaQsOR/qPvviJx5\n"
+ "I6Hqo4qemfnjZhAW85a5BpgrAwKgMLIQTHCTLWwVSyrDrwIDAQABo1AwTjAdBgNV\n"
+ "HQ4EFgQUx2tbJdlcSTCepn09UdYORXKuSTAwHwYDVR0jBBgwFoAUx2tbJdlcSTCe\n"
+ "pn09UdYORXKuSTAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQAmp9Id\n"
+ "E716gHMqeBG4S2FCgVFCr0a0ugkaneQAN/c2L9CbMemEN9W6jvucUIVOtYd90dDW\n"
+ "lXuowWmT/JctPe3D2qt4yvYW3puECHk2tVQmrJOZiZiTRtWm6HxkmoUYHYp/DtaS\n"
+ "1Xe29gSTnZtI5sQCrGMzk3SGRSSs7ejLKiVDBQ==\n"
+ "-----END CERTIFICATE-----\n"}};
class FakeDtlsIdentityStore : public webrtc::DtlsIdentityStoreInterface,
public rtc::MessageHandler {
@@ -77,6 +108,9 @@
should_fail_ = should_fail;
}
+ void use_original_key() { key_index_ = 0; }
+ void use_alternate_key() { key_index_ = 1; }
+
void RequestIdentity(
rtc::KeyType key_type,
const rtc::scoped_refptr<webrtc::DtlsIdentityRequestObserver>&
@@ -92,8 +126,9 @@
static rtc::scoped_refptr<rtc::RTCCertificate> GenerateCertificate() {
std::string cert;
std::string key;
- rtc::SSLIdentity::PemToDer("CERTIFICATE", kCERT_PEM, &cert);
- rtc::SSLIdentity::PemToDer("RSA PRIVATE KEY", kRSA_PRIVATE_KEY_PEM, &key);
+ rtc::SSLIdentity::PemToDer("CERTIFICATE", kKeysAndCerts[0].cert_pem, &cert);
+ rtc::SSLIdentity::PemToDer("RSA PRIVATE KEY",
+ kKeysAndCerts[0].rsa_private_key_pem, &key);
std::string pem_cert = rtc::SSLIdentity::DerToPem(
rtc::kPemTypeCertificate,
@@ -115,6 +150,11 @@
MSG_FAILURE,
};
+ const char* get_key() {
+ return kKeysAndCerts[key_index_].rsa_private_key_pem;
+ }
+ const char* get_cert() { return kKeysAndCerts[key_index_].cert_pem; }
+
// rtc::MessageHandler implementation.
void OnMessage(rtc::Message* msg) {
MessageData* message_data = static_cast<MessageData*>(msg->pdata);
@@ -124,9 +164,8 @@
case MSG_SUCCESS: {
std::string cert;
std::string key;
- rtc::SSLIdentity::PemToDer("CERTIFICATE", kCERT_PEM, &cert);
- rtc::SSLIdentity::PemToDer("RSA PRIVATE KEY", kRSA_PRIVATE_KEY_PEM,
- &key);
+ rtc::SSLIdentity::PemToDer("CERTIFICATE", get_cert(), &cert);
+ rtc::SSLIdentity::PemToDer("RSA PRIVATE KEY", get_key(), &key);
observer->OnSuccess(cert, key);
break;
}
@@ -138,6 +177,7 @@
}
bool should_fail_;
+ int key_index_ = 0;
};
#endif // TALK_APP_WEBRTC_TEST_FAKEDTLSIDENTITYSERVICE_H_
diff --git a/talk/session/media/channel.cc b/talk/session/media/channel.cc
index f83afa1..a25ab7d 100644
--- a/talk/session/media/channel.cc
+++ b/talk/session/media/channel.cc
@@ -249,6 +249,13 @@
return true;
}
+ // When using DTLS-SRTP, we must reset the SrtpFilter every time the transport
+ // changes and wait until the DTLS handshake is complete to set the newly
+ // negotiated parameters.
+ if (ShouldSetupDtlsSrtp()) {
+ srtp_filter_.ResetParams();
+ }
+
set_transport_channel(transport_controller_->CreateTransportChannel_w(
transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP));
if (!transport_channel()) {
@@ -318,6 +325,9 @@
rtcp_transport_channel_ = new_tc;
if (new_tc) {
+ RTC_CHECK(!(ShouldSetupDtlsSrtp() && srtp_filter_.IsActive()))
+ << "Setting RTCP for DTLS/SRTP after SrtpFilter is active "
+ << "should never happen.";
ConnectToTransportChannel(new_tc);
for (const auto& pair : rtcp_socket_options_) {
new_tc->SetOption(pair.first, pair.second);
@@ -336,6 +346,7 @@
tc->SignalWritableState.connect(this, &BaseChannel::OnWritableState);
tc->SignalReadPacket.connect(this, &BaseChannel::OnChannelRead);
tc->SignalReadyToSend.connect(this, &BaseChannel::OnReadyToSend);
+ tc->SignalDtlsState.connect(this, &BaseChannel::OnDtlsState);
}
void BaseChannel::DisconnectFromTransportChannel(TransportChannel* tc) {
@@ -344,6 +355,7 @@
tc->SignalWritableState.disconnect(this);
tc->SignalReadPacket.disconnect(this);
tc->SignalReadyToSend.disconnect(this);
+ tc->SignalDtlsState.disconnect(this);
}
bool BaseChannel::Enable(bool enable) {
@@ -416,10 +428,10 @@
bool BaseChannel::IsReadyToSend() const {
// Send outgoing data if we are enabled, have local and remote content,
// and we have had some form of connectivity.
- return enabled() &&
- IsReceiveContentDirection(remote_content_direction_) &&
+ return enabled() && IsReceiveContentDirection(remote_content_direction_) &&
IsSendContentDirection(local_content_direction_) &&
- was_ever_writable();
+ was_ever_writable() &&
+ (srtp_filter_.IsActive() || !ShouldSetupDtlsSrtp());
}
bool BaseChannel::SendPacket(rtc::Buffer* packet,
@@ -474,6 +486,22 @@
SetReadyToSend(channel == rtcp_transport_channel_, true);
}
+void BaseChannel::OnDtlsState(TransportChannel* channel,
+ DtlsTransportState state) {
+ if (!ShouldSetupDtlsSrtp()) {
+ return;
+ }
+
+ // Reset the srtp filter if it's not the CONNECTED state. For the CONNECTED
+ // state, setting up DTLS-SRTP context is deferred to ChannelWritable_w to
+ // cover other scenarios like the whole channel is writable (not just this
+ // TransportChannel) or when TransportChannel is attached after DTLS is
+ // negotiated.
+ if (state != DTLS_TRANSPORT_CONNECTED) {
+ srtp_filter_.ResetParams();
+ }
+}
+
void BaseChannel::SetReadyToSend(bool rtcp, bool ready) {
if (rtcp) {
rtcp_ready_to_send_ = ready;
@@ -761,8 +789,9 @@
void BaseChannel::ChannelWritable_w() {
ASSERT(worker_thread_ == rtc::Thread::Current());
- if (writable_)
+ if (writable_) {
return;
+ }
LOG(LS_INFO) << "Channel writable (" << content_name_ << ")"
<< (was_ever_writable_ ? "" : " for the first time");
@@ -778,22 +807,8 @@
}
}
- // If we're doing DTLS-SRTP, now is the time.
- if (!was_ever_writable_ && ShouldSetupDtlsSrtp()) {
- if (!SetupDtlsSrtp(false)) {
- SignalDtlsSetupFailure_w(false);
- return;
- }
-
- if (rtcp_transport_channel_) {
- if (!SetupDtlsSrtp(true)) {
- SignalDtlsSetupFailure_w(true);
- return;
- }
- }
- }
-
was_ever_writable_ = true;
+ MaybeSetupDtlsSrtp_w();
writable_ = true;
ChangeState();
}
@@ -822,7 +837,8 @@
}
bool BaseChannel::ShouldSetupDtlsSrtp() const {
- return true;
+ // Since DTLS is applied to all channels, checking RTP should be enough.
+ return transport_channel_ && transport_channel_->IsDtlsActive();
}
// This function returns true if either DTLS-SRTP is not in use
@@ -833,9 +849,7 @@
TransportChannel* channel =
rtcp_channel ? rtcp_transport_channel_ : transport_channel_;
- // No DTLS
- if (!channel->IsDtlsActive())
- return true;
+ RTC_DCHECK(channel->IsDtlsActive());
int selected_crypto_suite;
@@ -915,6 +929,28 @@
return ret;
}
+void BaseChannel::MaybeSetupDtlsSrtp_w() {
+ if (srtp_filter_.IsActive()) {
+ return;
+ }
+
+ if (!ShouldSetupDtlsSrtp()) {
+ return;
+ }
+
+ if (!SetupDtlsSrtp(false)) {
+ SignalDtlsSetupFailure_w(false);
+ return;
+ }
+
+ if (rtcp_transport_channel_) {
+ if (!SetupDtlsSrtp(true)) {
+ SignalDtlsSetupFailure_w(true);
+ return;
+ }
+ }
+}
+
void BaseChannel::ChannelNotWritable_w() {
ASSERT(worker_thread_ == rtc::Thread::Current());
if (!writable_)
@@ -2263,7 +2299,7 @@
}
bool DataChannel::ShouldSetupDtlsSrtp() const {
- return (data_channel_type_ == DCT_RTP);
+ return (data_channel_type_ == DCT_RTP) && BaseChannel::ShouldSetupDtlsSrtp();
}
void DataChannel::OnStreamClosedRemotely(uint32_t sid) {
diff --git a/talk/session/media/channel.h b/talk/session/media/channel.h
index ef0eb56..1140954 100644
--- a/talk/session/media/channel.h
+++ b/talk/session/media/channel.h
@@ -213,6 +213,8 @@
int flags);
void OnReadyToSend(TransportChannel* channel);
+ void OnDtlsState(TransportChannel* channel, DtlsTransportState state);
+
bool PacketIsRtcp(const TransportChannel* channel, const char* data,
size_t len);
bool SendPacket(bool rtcp,
@@ -235,6 +237,7 @@
// Do the DTLS key expansion and impose it on the SRTP/SRTCP filters.
// |rtcp_channel| indicates whether to set up the RTP or RTCP filter.
bool SetupDtlsSrtp(bool rtcp_channel);
+ void MaybeSetupDtlsSrtp_w();
// Set the DTLS-SRTP cipher policy on this channel as appropriate.
bool SetDtlsSrtpCryptoSuites(TransportChannel* tc, bool rtcp);
diff --git a/talk/session/media/srtpfilter.h b/talk/session/media/srtpfilter.h
index d30cee6..6b941f3 100644
--- a/talk/session/media/srtpfilter.h
+++ b/talk/session/media/srtpfilter.h
@@ -138,6 +138,8 @@
// Update the silent threshold (in ms) for signaling errors.
void set_signal_silent_time(uint32_t signal_silent_time_in_ms);
+ bool ResetParams();
+
sigslot::repeater3<uint32_t, Mode, Error> SignalSrtpError;
protected:
@@ -153,7 +155,6 @@
CryptoParams* selected_params);
bool ApplyParams(const CryptoParams& send_params,
const CryptoParams& recv_params);
- bool ResetParams();
static bool ParseKeyParams(const std::string& params, uint8_t* key, int len);
private:
diff --git a/webrtc/p2p/base/dtlstransportchannel.cc b/webrtc/p2p/base/dtlstransportchannel.cc
index fff24f3..95014f9 100644
--- a/webrtc/p2p/base/dtlstransportchannel.cc
+++ b/webrtc/p2p/base/dtlstransportchannel.cc
@@ -199,6 +199,8 @@
size_t digest_len) {
rtc::Buffer remote_fingerprint_value(digest, digest_len);
+ // Once we have the local certificate, the same remote fingerprint can be set
+ // multiple times.
if (dtls_active_ && remote_fingerprint_value_ == remote_fingerprint_value &&
!digest_alg.empty()) {
// This may happen during renegotiation.
@@ -206,28 +208,36 @@
return true;
}
- // Allow SetRemoteFingerprint with a NULL digest even if SetLocalCertificate
- // hasn't been called.
- if (dtls_ || (!dtls_active_ && !digest_alg.empty())) {
- LOG_J(LS_ERROR, this) << "Can't set DTLS remote settings in this state.";
- return false;
- }
-
+ // If the other side doesn't support DTLS, turn off |dtls_active_|.
if (digest_alg.empty()) {
+ RTC_DCHECK(!digest_len);
LOG_J(LS_INFO, this) << "Other side didn't support DTLS.";
dtls_active_ = false;
return true;
}
+ // Otherwise, we must have a local certificate before setting remote
+ // fingerprint.
+ if (!dtls_active_) {
+ LOG_J(LS_ERROR, this) << "Can't set DTLS remote settings in this state.";
+ return false;
+ }
+
// At this point we know we are doing DTLS
remote_fingerprint_value_ = remote_fingerprint_value.Pass();
remote_fingerprint_algorithm_ = digest_alg;
+ bool reconnect = dtls_;
+
if (!SetupDtls()) {
set_dtls_state(DTLS_TRANSPORT_FAILED);
return false;
}
+ if (reconnect) {
+ Reconnect();
+ }
+
return true;
}
@@ -616,4 +626,12 @@
SignalConnectionRemoved(this);
}
+void DtlsTransportChannelWrapper::Reconnect() {
+ set_dtls_state(DTLS_TRANSPORT_NEW);
+ set_writable(false);
+ if (channel_->writable()) {
+ OnWritableState(channel_);
+ }
+}
+
} // namespace cricket
diff --git a/webrtc/p2p/base/dtlstransportchannel.h b/webrtc/p2p/base/dtlstransportchannel.h
index 71f6887..955b963 100644
--- a/webrtc/p2p/base/dtlstransportchannel.h
+++ b/webrtc/p2p/base/dtlstransportchannel.h
@@ -216,6 +216,7 @@
void OnRoleConflict(TransportChannelImpl* channel);
void OnRouteChange(TransportChannel* channel, const Candidate& candidate);
void OnConnectionRemoved(TransportChannelImpl* channel);
+ void Reconnect();
Transport* transport_; // The transport_ that created us.
rtc::Thread* worker_thread_; // Everything should occur on this thread.
diff --git a/webrtc/p2p/base/transportchannel.cc b/webrtc/p2p/base/transportchannel.cc
index f497bce..6cbe2b7 100644
--- a/webrtc/p2p/base/transportchannel.cc
+++ b/webrtc/p2p/base/transportchannel.cc
@@ -51,7 +51,7 @@
LOG_J(LS_VERBOSE, this) << "set_dtls_state from:" << dtls_state_ << " to "
<< state;
dtls_state_ = state;
- SignalDtlsState(this);
+ SignalDtlsState(this, state);
}
bool TransportChannel::SetSrtpCryptoSuites(const std::vector<int>& ciphers) {
diff --git a/webrtc/p2p/base/transportchannel.h b/webrtc/p2p/base/transportchannel.h
index de0bd45..b91af13 100644
--- a/webrtc/p2p/base/transportchannel.h
+++ b/webrtc/p2p/base/transportchannel.h
@@ -79,8 +79,9 @@
// Emitted when the TransportChannel's ability to send has changed.
sigslot::signal1<TransportChannel*> SignalReadyToSend;
sigslot::signal1<TransportChannel*> SignalReceivingState;
- // Emitted when the DtlsTransportState has changed.
- sigslot::signal1<TransportChannel*> SignalDtlsState;
+ // Emitted whenever DTLS-SRTP is setup which will require setting up a new
+ // SRTP context.
+ sigslot::signal2<TransportChannel*, DtlsTransportState> SignalDtlsState;
// Attempts to send the given packet. The return value is < 0 on failure.
// TODO: Remove the default argument once channel code is updated.