mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 05:40:42 +01:00
Implement crypto stats on DTLS transport
Bug: chromium:1018077 Change-Id: I585d4064f39e5f9d268b408ebf6ae13a056c778a Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/158403 Reviewed-by: Henrik Boström <hbos@webrtc.org> Reviewed-by: Steve Anton <steveanton@webrtc.org> Commit-Queue: Harald Alvestrand <hta@webrtc.org> Cr-Commit-Position: refs/heads/master@{#29628}
This commit is contained in:
parent
a81e2b4510
commit
5cb7807a36
16 changed files with 143 additions and 7 deletions
|
@ -600,6 +600,9 @@ class RTC_EXPORT RTCTransportStats final : public RTCStats {
|
|||
RTCStatsMember<std::string> selected_candidate_pair_id;
|
||||
RTCStatsMember<std::string> local_certificate_id;
|
||||
RTCStatsMember<std::string> remote_certificate_id;
|
||||
RTCStatsMember<std::string> tls_version;
|
||||
RTCStatsMember<std::string> dtls_cipher;
|
||||
RTCStatsMember<std::string> srtp_cipher;
|
||||
RTCStatsMember<uint32_t> selected_candidate_pair_changes;
|
||||
};
|
||||
|
||||
|
|
|
@ -380,6 +380,14 @@ bool DtlsTransport::GetSrtpCryptoSuite(int* cipher) {
|
|||
return dtls_->GetDtlsSrtpCryptoSuite(cipher);
|
||||
}
|
||||
|
||||
bool DtlsTransport::GetSslVersionBytes(int* version) const {
|
||||
if (dtls_state() != DTLS_TRANSPORT_CONNECTED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return dtls_->GetSslVersionBytes(version);
|
||||
}
|
||||
|
||||
// Called from upper layers to send a media packet.
|
||||
int DtlsTransport::SendPacket(const char* data,
|
||||
size_t size,
|
||||
|
|
|
@ -142,6 +142,8 @@ class DtlsTransport : public DtlsTransportInternal {
|
|||
|
||||
bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) override;
|
||||
|
||||
// Find out which TLS version was negotiated
|
||||
bool GetSslVersionBytes(int* version) const override;
|
||||
// Find out which DTLS-SRTP cipher was negotiated
|
||||
bool GetSrtpCryptoSuite(int* cipher) override;
|
||||
|
||||
|
|
|
@ -74,6 +74,8 @@ class DtlsTransportInternal : public rtc::PacketTransportInternal {
|
|||
|
||||
virtual bool SetDtlsRole(rtc::SSLRole role) = 0;
|
||||
|
||||
// Finds out which TLS/DTLS version is running.
|
||||
virtual bool GetSslVersionBytes(int* version) const = 0;
|
||||
// Finds out which DTLS-SRTP cipher was negotiated.
|
||||
// TODO(zhihuang): Remove this once all dependencies implement this.
|
||||
virtual bool GetSrtpCryptoSuite(int* cipher) = 0;
|
||||
|
|
|
@ -168,6 +168,13 @@ class FakeDtlsTransport : public DtlsTransportInternal {
|
|||
remote_cert_ = cert;
|
||||
}
|
||||
bool IsDtlsActive() const override { return do_dtls_; }
|
||||
bool GetSslVersionBytes(int* version) const override {
|
||||
if (!do_dtls_) {
|
||||
return false;
|
||||
}
|
||||
*version = 0x0102;
|
||||
return true;
|
||||
}
|
||||
bool GetSrtpCryptoSuite(int* crypto_suite) override {
|
||||
if (!do_dtls_) {
|
||||
return false;
|
||||
|
|
|
@ -66,6 +66,9 @@ bool NoOpDtlsTransport::GetDtlsRole(rtc::SSLRole* role) const {
|
|||
bool NoOpDtlsTransport::SetDtlsRole(rtc::SSLRole role) {
|
||||
return false;
|
||||
}
|
||||
bool NoOpDtlsTransport::GetSslVersionBytes(int* version) const {
|
||||
return false;
|
||||
}
|
||||
bool NoOpDtlsTransport::GetSrtpCryptoSuite(int* cipher) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ class NoOpDtlsTransport : public DtlsTransportInternal {
|
|||
bool IsDtlsActive() const override;
|
||||
bool GetDtlsRole(rtc::SSLRole* role) const override;
|
||||
bool SetDtlsRole(rtc::SSLRole role) override;
|
||||
bool GetSslVersionBytes(int* version) const override;
|
||||
bool GetSrtpCryptoSuite(int* cipher) override;
|
||||
bool GetSslCipherSuite(int* cipher) override;
|
||||
rtc::scoped_refptr<rtc::RTCCertificate> GetLocalCertificate() const override;
|
||||
|
|
|
@ -772,6 +772,7 @@ bool JsepTransport::GetTransportStats(DtlsTransportInternal* dtls_transport,
|
|||
} else {
|
||||
substats.component = ICE_CANDIDATE_COMPONENT_RTP;
|
||||
}
|
||||
dtls_transport->GetSslVersionBytes(&substats.ssl_version_bytes);
|
||||
dtls_transport->GetSrtpCryptoSuite(&substats.srtp_crypto_suite);
|
||||
dtls_transport->GetSslCipherSuite(&substats.ssl_cipher_suite);
|
||||
substats.dtls_state = dtls_transport->dtls_state();
|
||||
|
|
|
@ -1721,6 +1721,26 @@ void RTCStatsCollector::ProduceTransportStats_n(
|
|||
transport_stats->local_certificate_id = local_certificate_id;
|
||||
if (!remote_certificate_id.empty())
|
||||
transport_stats->remote_certificate_id = remote_certificate_id;
|
||||
// Crypto information
|
||||
if (channel_stats.ssl_version_bytes) {
|
||||
char bytes[5];
|
||||
snprintf(bytes, sizeof(bytes), "%04X", channel_stats.ssl_version_bytes);
|
||||
transport_stats->tls_version = bytes;
|
||||
}
|
||||
if (channel_stats.ssl_cipher_suite != rtc::TLS_NULL_WITH_NULL_NULL &&
|
||||
rtc::SSLStreamAdapter::SslCipherSuiteToName(
|
||||
channel_stats.ssl_cipher_suite)
|
||||
.length()) {
|
||||
transport_stats->dtls_cipher =
|
||||
rtc::SSLStreamAdapter::SslCipherSuiteToName(
|
||||
channel_stats.ssl_cipher_suite);
|
||||
}
|
||||
if (channel_stats.srtp_crypto_suite != rtc::SRTP_INVALID_CRYPTO_SUITE &&
|
||||
rtc::SrtpCryptoSuiteToName(channel_stats.srtp_crypto_suite)
|
||||
.length()) {
|
||||
transport_stats->srtp_cipher =
|
||||
rtc::SrtpCryptoSuiteToName(channel_stats.srtp_crypto_suite);
|
||||
}
|
||||
report->AddStats(std::move(transport_stats));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2202,6 +2202,68 @@ TEST_F(RTCStatsCollectorTest, CollectRTCTransportStats) {
|
|||
report->Get(expected_rtcp_transport.id())->cast_to<RTCTransportStats>());
|
||||
}
|
||||
|
||||
TEST_F(RTCStatsCollectorTest, CollectRTCTransportStatsWithCrypto) {
|
||||
const char kTransportName[] = "transport";
|
||||
|
||||
pc_->AddVoiceChannel("audio", kTransportName);
|
||||
|
||||
std::unique_ptr<cricket::Candidate> rtp_local_candidate =
|
||||
CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
|
||||
cricket::LOCAL_PORT_TYPE, 42);
|
||||
std::unique_ptr<cricket::Candidate> rtp_remote_candidate =
|
||||
CreateFakeCandidate("42.42.42.42", 42, "protocol",
|
||||
rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
|
||||
42);
|
||||
std::unique_ptr<cricket::Candidate> rtcp_local_candidate =
|
||||
CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
|
||||
cricket::LOCAL_PORT_TYPE, 42);
|
||||
std::unique_ptr<cricket::Candidate> rtcp_remote_candidate =
|
||||
CreateFakeCandidate("42.42.42.42", 42, "protocol",
|
||||
rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
|
||||
42);
|
||||
|
||||
cricket::ConnectionInfo rtp_connection_info;
|
||||
rtp_connection_info.best_connection = false;
|
||||
rtp_connection_info.local_candidate = *rtp_local_candidate.get();
|
||||
rtp_connection_info.remote_candidate = *rtp_remote_candidate.get();
|
||||
rtp_connection_info.sent_total_bytes = 42;
|
||||
rtp_connection_info.recv_total_bytes = 1337;
|
||||
cricket::TransportChannelStats rtp_transport_channel_stats;
|
||||
rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
|
||||
rtp_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
|
||||
rtp_connection_info);
|
||||
// The state must be connected in order for crypto parameters to show up.
|
||||
rtp_transport_channel_stats.dtls_state = cricket::DTLS_TRANSPORT_CONNECTED;
|
||||
rtp_transport_channel_stats.ice_transport_stats
|
||||
.selected_candidate_pair_changes = 1;
|
||||
rtp_transport_channel_stats.ssl_version_bytes = 0x0203;
|
||||
// 0x2F is TLS_RSA_WITH_AES_128_CBC_SHA according to IANA
|
||||
rtp_transport_channel_stats.ssl_cipher_suite = 0x2F;
|
||||
rtp_transport_channel_stats.srtp_crypto_suite = rtc::SRTP_AES128_CM_SHA1_80;
|
||||
pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats});
|
||||
|
||||
// Get stats
|
||||
rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
|
||||
|
||||
RTCTransportStats expected_rtp_transport(
|
||||
"RTCTransport_transport_" +
|
||||
rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTP),
|
||||
report->timestamp_us());
|
||||
expected_rtp_transport.bytes_sent = 42;
|
||||
expected_rtp_transport.bytes_received = 1337;
|
||||
expected_rtp_transport.dtls_state = RTCDtlsTransportState::kConnected;
|
||||
expected_rtp_transport.selected_candidate_pair_changes = 1;
|
||||
// Crypto parameters
|
||||
expected_rtp_transport.tls_version = "0203";
|
||||
expected_rtp_transport.dtls_cipher = "TLS_RSA_WITH_AES_128_CBC_SHA";
|
||||
expected_rtp_transport.srtp_cipher = "AES_CM_128_HMAC_SHA1_80";
|
||||
|
||||
ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
|
||||
EXPECT_EQ(
|
||||
expected_rtp_transport,
|
||||
report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
|
||||
}
|
||||
|
||||
TEST_F(RTCStatsCollectorTest, CollectNoStreamRTCOutboundRTPStreamStats_Audio) {
|
||||
cricket::VoiceMediaInfo voice_media_info;
|
||||
|
||||
|
|
|
@ -973,6 +973,9 @@ class RTCStatsReportVerifier {
|
|||
RTCCertificateStats::kType);
|
||||
verifier.TestMemberIsIDReference(transport.remote_certificate_id,
|
||||
RTCCertificateStats::kType);
|
||||
verifier.TestMemberIsDefined(transport.tls_version);
|
||||
verifier.TestMemberIsDefined(transport.dtls_cipher);
|
||||
verifier.TestMemberIsDefined(transport.srtp_cipher);
|
||||
verifier.TestMemberIsPositive<uint32_t>(
|
||||
transport.selected_candidate_pair_changes);
|
||||
return verifier.ExpectAllMembersSuccessfullyTested();
|
||||
|
|
|
@ -27,6 +27,7 @@ struct TransportChannelStats {
|
|||
~TransportChannelStats();
|
||||
|
||||
int component = 0;
|
||||
int ssl_version_bytes = 0;
|
||||
int srtp_crypto_suite = rtc::SRTP_INVALID_CRYPTO_SUITE;
|
||||
int ssl_cipher_suite = rtc::TLS_NULL_WITH_NULL_NULL;
|
||||
DtlsTransportState dtls_state = DTLS_TRANSPORT_NEW;
|
||||
|
|
|
@ -373,9 +373,9 @@ bool OpenSSLStreamAdapter::GetSslCipherSuite(int* cipher_suite) {
|
|||
return true;
|
||||
}
|
||||
|
||||
int OpenSSLStreamAdapter::GetSslVersion() const {
|
||||
SSLProtocolVersion OpenSSLStreamAdapter::GetSslVersion() const {
|
||||
if (state_ != SSL_CONNECTED) {
|
||||
return -1;
|
||||
return SSL_PROTOCOL_NOT_GIVEN;
|
||||
}
|
||||
|
||||
int ssl_version = SSL_version(ssl_);
|
||||
|
@ -395,7 +395,15 @@ int OpenSSLStreamAdapter::GetSslVersion() const {
|
|||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
return SSL_PROTOCOL_NOT_GIVEN;
|
||||
}
|
||||
|
||||
bool OpenSSLStreamAdapter::GetSslVersionBytes(int* version) const {
|
||||
if (state_ != SSL_CONNECTED) {
|
||||
return false;
|
||||
}
|
||||
*version = SSL_version(ssl_);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Key Extractor interface
|
||||
|
|
|
@ -96,8 +96,8 @@ class OpenSSLStreamAdapter final : public SSLStreamAdapter {
|
|||
|
||||
bool GetSslCipherSuite(int* cipher) override;
|
||||
|
||||
int GetSslVersion() const override;
|
||||
|
||||
SSLProtocolVersion GetSslVersion() const override;
|
||||
bool GetSslVersionBytes(int* version) const override;
|
||||
// Key Extractor interface
|
||||
bool ExportKeyingMaterial(const std::string& label,
|
||||
const uint8_t* context,
|
||||
|
|
|
@ -91,7 +91,8 @@ bool IsGcmCryptoSuiteName(const std::string& crypto_suite);
|
|||
enum SSLRole { SSL_CLIENT, SSL_SERVER };
|
||||
enum SSLMode { SSL_MODE_TLS, SSL_MODE_DTLS };
|
||||
enum SSLProtocolVersion {
|
||||
SSL_PROTOCOL_TLS_10,
|
||||
SSL_PROTOCOL_NOT_GIVEN = -1,
|
||||
SSL_PROTOCOL_TLS_10 = 0,
|
||||
SSL_PROTOCOL_TLS_11,
|
||||
SSL_PROTOCOL_TLS_12,
|
||||
SSL_PROTOCOL_DTLS_10 = SSL_PROTOCOL_TLS_11,
|
||||
|
@ -187,7 +188,12 @@ class SSLStreamAdapter : public StreamAdapterInterface {
|
|||
// connection (e.g. 0x2F for "TLS_RSA_WITH_AES_128_CBC_SHA").
|
||||
virtual bool GetSslCipherSuite(int* cipher_suite);
|
||||
|
||||
virtual int GetSslVersion() const = 0;
|
||||
// Retrieves the enum value for SSL version.
|
||||
// Will return -1 until the version has been negotiated.
|
||||
virtual SSLProtocolVersion GetSslVersion() const = 0;
|
||||
// Retrieves the 2-byte version from the TLS protocol.
|
||||
// Will return false until the version has been negotiated.
|
||||
virtual bool GetSslVersionBytes(int* version) const = 0;
|
||||
|
||||
// Key Exporter interface from RFC 5705
|
||||
// Arguments are:
|
||||
|
|
|
@ -883,6 +883,9 @@ WEBRTC_RTCSTATS_IMPL(RTCTransportStats, RTCStats, "transport",
|
|||
&selected_candidate_pair_id,
|
||||
&local_certificate_id,
|
||||
&remote_certificate_id,
|
||||
&tls_version,
|
||||
&dtls_cipher,
|
||||
&srtp_cipher,
|
||||
&selected_candidate_pair_changes)
|
||||
// clang-format on
|
||||
|
||||
|
@ -899,6 +902,9 @@ RTCTransportStats::RTCTransportStats(std::string&& id, int64_t timestamp_us)
|
|||
selected_candidate_pair_id("selectedCandidatePairId"),
|
||||
local_certificate_id("localCertificateId"),
|
||||
remote_certificate_id("remoteCertificateId"),
|
||||
tls_version("tlsVersion"),
|
||||
dtls_cipher("dtlsCipher"),
|
||||
srtp_cipher("srtpCipher"),
|
||||
selected_candidate_pair_changes("selectedCandidatePairChanges") {}
|
||||
|
||||
RTCTransportStats::RTCTransportStats(const RTCTransportStats& other)
|
||||
|
@ -910,6 +916,9 @@ RTCTransportStats::RTCTransportStats(const RTCTransportStats& other)
|
|||
selected_candidate_pair_id(other.selected_candidate_pair_id),
|
||||
local_certificate_id(other.local_certificate_id),
|
||||
remote_certificate_id(other.remote_certificate_id),
|
||||
tls_version(other.tls_version),
|
||||
dtls_cipher(other.dtls_cipher),
|
||||
srtp_cipher(other.srtp_cipher),
|
||||
selected_candidate_pair_changes(other.selected_candidate_pair_changes) {}
|
||||
|
||||
RTCTransportStats::~RTCTransportStats() {}
|
||||
|
|
Loading…
Reference in a new issue