diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f368571..01f734de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,6 +111,7 @@ target_sources(sora src/sora_signaling.cpp src/sora_video_decoder_factory.cpp src/sora_video_encoder_factory.cpp + src/srtp_keying_material_exporter.cpp src/ssl_verifier.cpp src/url_parts.cpp src/version.cpp diff --git a/include/sora/sora_signaling.h b/include/sora/sora_signaling.h index c9682842..0721887c 100644 --- a/include/sora/sora_signaling.h +++ b/include/sora/sora_signaling.h @@ -262,6 +262,7 @@ class SoraSignaling : public std::enable_shared_from_this, std::lock_guard lock(m); this->s = s; } + private: std::string s; mutable std::mutex m; diff --git a/include/sora/srtp_keying_material_exporter.h b/include/sora/srtp_keying_material_exporter.h new file mode 100644 index 00000000..becc844d --- /dev/null +++ b/include/sora/srtp_keying_material_exporter.h @@ -0,0 +1,24 @@ +#ifndef SORA_SRTP_KEYING_MATERIAL_EXPORTER_H_ +#define SORA_SRTP_KEYING_MATERIAL_EXPORTER_H_ + +#include + +#include +#include + +namespace sora { + +struct KeyingMaterial { + std::vector client_write_key; + std::vector server_write_key; + std::vector client_write_salt; + std::vector server_write_salt; +}; + +absl::optional ExportKeyingMaterial( + rtc::scoped_refptr pc, + const std::string& mid); + +} // namespace sora + +#endif diff --git a/src/sora_signaling.cpp b/src/sora_signaling.cpp index d1ea023e..d5e61205 100644 --- a/src/sora_signaling.cpp +++ b/src/sora_signaling.cpp @@ -9,6 +9,7 @@ #include "sora/rtc_ssl_verifier.h" #include "sora/rtc_stats.h" #include "sora/session_description.h" +#include "sora/srtp_keying_material_exporter.h" #include "sora/url_parts.h" #include "sora/version.h" #include "sora/zlib_helper.h" @@ -1470,6 +1471,30 @@ void SoraSignaling::OnConnectionChange( SoraSignalingErrorCode::PEER_CONNECTION_STATE_FAILED, "PeerConnectionState::kFailed"); } + + if (new_state == + webrtc::PeerConnectionInterface::PeerConnectionState::kConnected) { + auto km = ExportKeyingMaterial(self->pc_, self->video_mid_); + if (!km) { + RTC_LOG(LS_ERROR) << "Failed to ExportKeyingMaterial"; + } else { + auto to_hex = [](const std::vector& buf) { + std::string str; + const char hex[] = "0123456789abcdef"; + for (auto n : buf) { + str += hex[(n >> 4) & 0xf]; + str += hex[n & 0xf]; + } + return str; + }; + std::stringstream ss; + ss << "SRTP_CLIENT_KEY " << to_hex(km->client_write_key) << "\n"; + ss << "SRTP_CLIENT_SALT " << to_hex(km->client_write_salt) << "\n"; + ss << "SRTP_SERVER_KEY " << to_hex(km->server_write_key) << "\n"; + ss << "SRTP_SERVER_SALT " << to_hex(km->server_write_salt) << "\n"; + printf("%s", ss.str().c_str()); + } + } }); } diff --git a/src/srtp_keying_material_exporter.cpp b/src/srtp_keying_material_exporter.cpp new file mode 100644 index 00000000..f21a4d25 --- /dev/null +++ b/src/srtp_keying_material_exporter.cpp @@ -0,0 +1,78 @@ +#include "sora/srtp_keying_material_exporter.h" + +#include +#include +#include +#include + +namespace sora { + +// Value specified in RFC 5764. +static const char kDtlsSrtpExporterLabel[] = "EXTRACTOR-dtls_srtp"; + +absl::optional ExportKeyingMaterial( + rtc::scoped_refptr pc, + const std::string& mid) { + rtc::scoped_refptr dtls_interface = + pc->LookupDtlsTransportByMid(mid); + if (dtls_interface == nullptr) { + RTC_LOG(LS_ERROR) << "Failed to lookup DtlsTransportInterface"; + return absl::nullopt; + } + + // shiguredo-webrtc-build/webrtc-build の libwebrtc は + // RTTI を有効にしてるので dynamic_cast ができる + webrtc::DtlsTransport* dtls_impl = + dynamic_cast(dtls_interface.get()); + if (dtls_impl == nullptr) { + RTC_LOG(LS_ERROR) << "Failed to cast webrtc::DtlsTransport"; + return absl::nullopt; + } + + cricket::DtlsTransport* dtls = + dynamic_cast(dtls_impl->internal()); + if (dtls == nullptr) { + RTC_LOG(LS_ERROR) << "Failed to cast cricket::DtlsTransport"; + return absl::nullopt; + } + + int crypto_suite; + if (!dtls->GetSrtpCryptoSuite(&crypto_suite)) { + RTC_LOG(LS_ERROR) << "Failed to get SrtpCryptoSuite"; + return absl::nullopt; + } + + int key_len; + int salt_len; + if (!rtc::GetSrtpKeyAndSaltLengths(crypto_suite, &key_len, &salt_len)) { + RTC_LOG(LS_ERROR) << "Failed to get SrtpKeyAndSaltLengths"; + return absl::nullopt; + } + + std::vector buf(key_len * 2 + salt_len * 2); + + if (!dtls->ExportKeyingMaterial(kDtlsSrtpExporterLabel, nullptr, 0, false, + buf.data(), buf.size())) { + RTC_LOG(LS_ERROR) << "Failed to ExportKeyingMaterial"; + return absl::nullopt; + }; + + KeyingMaterial km; + km.client_write_key.resize(key_len); + km.server_write_key.resize(key_len); + km.client_write_salt.resize(salt_len); + km.server_write_salt.resize(salt_len); + int n = 0; + memcpy(km.client_write_key.data(), buf.data() + n, key_len); + n += key_len; + memcpy(km.server_write_key.data(), buf.data() + n, key_len); + n += key_len; + memcpy(km.client_write_salt.data(), buf.data() + n, salt_len); + n += salt_len; + memcpy(km.server_write_salt.data(), buf.data() + n, salt_len); + n += salt_len; + + return km; +} + +} // namespace sora \ No newline at end of file