From 9d03db688b7ad4332a25895382123929a51440ae Mon Sep 17 00:00:00 2001 From: achingbrain Date: Sun, 9 Jun 2024 10:27:35 +0100 Subject: [PATCH 1/2] feat: add remoteFingerprints method to PeerConnection Returns a vector that contains the certificate fingerprints used by the connection to the remote peer. Closes #1203 Refs #1166 --- include/rtc/peerconnection.hpp | 6 ++++++ src/impl/peerconnection.cpp | 31 +++++++++++++++++++++++++------ src/impl/peerconnection.hpp | 6 +++++- src/peerconnection.cpp | 4 ++++ 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/include/rtc/peerconnection.hpp b/include/rtc/peerconnection.hpp index 9e49f80e1..e07ad4461 100644 --- a/include/rtc/peerconnection.hpp +++ b/include/rtc/peerconnection.hpp @@ -35,6 +35,11 @@ struct RTC_CPP_EXPORT DataChannelInit { string protocol = ""; }; +struct RTC_CPP_EXPORT RemoteFingerprint { + string value; + CertificateFingerprint::Algorithm algorithm; +}; + class RTC_CPP_EXPORT PeerConnection final : CheshireCat { public: enum class State : int { @@ -113,6 +118,7 @@ class RTC_CPP_EXPORT PeerConnection final : CheshireCat { void onSignalingStateChange(std::function callback); void resetCallbacks(); + std::vector remoteFingerprints(); // Stats void clearStats(); diff --git a/src/impl/peerconnection.cpp b/src/impl/peerconnection.cpp index 1d3611b2b..4f83e96f5 100644 --- a/src/impl/peerconnection.cpp +++ b/src/impl/peerconnection.cpp @@ -239,7 +239,7 @@ shared_ptr PeerConnection::initDtlsTransport() { throw std::logic_error("No underlying ICE transport for DTLS transport"); auto certificate = mCertificate.get(); - auto verifierCallback = weak_bind(&PeerConnection::checkFingerprint, this, _1); + auto verifierCallback = weak_bind(&PeerConnection::checkFingerprint, this, _1, fingerprintAlgorithm); auto dtlsStateChangeCallback = [this, weak_this = weak_from_this()](DtlsTransport::State transportState) { auto shared_this = weak_this.lock(); @@ -439,17 +439,15 @@ void PeerConnection::rollbackLocalDescription() { } } -bool PeerConnection::checkFingerprint(const std::string &fingerprint) const { +bool PeerConnection::checkFingerprint(const std::string &fingerprint, const CertificateFingerprint::Algorithm &algorithm) { std::lock_guard lock(mRemoteDescriptionMutex); if (!mRemoteDescription || !mRemoteDescription->fingerprint()) return false; - if (config.disableFingerprintVerification) - return true; - auto expectedFingerprint = mRemoteDescription->fingerprint()->value; - if (expectedFingerprint == fingerprint) { + if (config.disableFingerprintVerification || expectedFingerprint == fingerprint) { PLOG_VERBOSE << "Valid fingerprint \"" << fingerprint << "\""; + storeRemoteFingerprint(fingerprint, algorithm); return true; } @@ -457,6 +455,20 @@ bool PeerConnection::checkFingerprint(const std::string &fingerprint) const { return false; } +void PeerConnection::storeRemoteFingerprint(const std::string &value, const CertificateFingerprint::Algorithm &algorithm) { + auto iter = std::find_if(rFingerprints.begin(), rFingerprints.end(), [&](const RemoteFingerprint& existing){return existing.value == value;}); + bool seenPreviously = iter != rFingerprints.end(); + + if (seenPreviously) { + return; + } + + rFingerprints.push_back({ + value, + algorithm + }); +} + void PeerConnection::forwardMessage(message_ptr message) { if (!message) { remoteCloseDataChannels(); @@ -1301,6 +1313,13 @@ void PeerConnection::resetCallbacks() { trackCallback = nullptr; } +std::vector PeerConnection::remoteFingerprints() { + std::vector ret; + ret = rFingerprints; + + return ret; +} + void PeerConnection::updateTrackSsrcCache(const Description &description) { std::unique_lock lock(mTracksMutex); // for safely writing to mTracksBySsrc diff --git a/src/impl/peerconnection.hpp b/src/impl/peerconnection.hpp index 33dba4408..4fd611939 100644 --- a/src/impl/peerconnection.hpp +++ b/src/impl/peerconnection.hpp @@ -53,7 +53,7 @@ struct PeerConnection : std::enable_shared_from_this { void endLocalCandidates(); void rollbackLocalDescription(); - bool checkFingerprint(const std::string &fingerprint) const; + bool checkFingerprint(const std::string &fingerprint, const CertificateFingerprint::Algorithm &algorithm); void forwardMessage(message_ptr message); void forwardMedia(message_ptr message); void forwardBufferedAmount(uint16_t stream, size_t amount); @@ -98,6 +98,7 @@ struct PeerConnection : std::enable_shared_from_this { bool changeSignalingState(SignalingState newState); void resetCallbacks(); + std::vector remoteFingerprints(); // Helper method for asynchronous callback invocation template void trigger(synchronized_callback *cb, Args... args) { @@ -129,6 +130,7 @@ struct PeerConnection : std::enable_shared_from_this { private: void dispatchMedia(message_ptr message); void updateTrackSsrcCache(const Description &description); + void storeRemoteFingerprint(const std::string &fingerprint, const CertificateFingerprint::Algorithm &algorithm); const init_token mInitToken = Init::Instance().token(); future_certificate_ptr mCertificate; @@ -157,6 +159,8 @@ struct PeerConnection : std::enable_shared_from_this { Queue> mPendingDataChannels; Queue> mPendingTracks; + + std::vector rFingerprints; }; } // namespace rtc::impl diff --git a/src/peerconnection.cpp b/src/peerconnection.cpp index 0e146834b..caaef24bb 100644 --- a/src/peerconnection.cpp +++ b/src/peerconnection.cpp @@ -367,6 +367,10 @@ optional PeerConnection::rtt() { return sctpTransport ? sctpTransport->rtt() : nullopt; } +std::vector PeerConnection::remoteFingerprints() { + return impl()->remoteFingerprints(); +} + std::ostream &operator<<(std::ostream &out, PeerConnection::State state) { using State = PeerConnection::State; const char *str; From 1923c379d4b23965d2e10a74913f89576697a615 Mon Sep 17 00:00:00 2001 From: achingbrain Date: Tue, 11 Jun 2024 11:24:46 +0100 Subject: [PATCH 2/2] chore: pr comments --- include/rtc/peerconnection.hpp | 7 +----- src/impl/peerconnection.cpp | 40 +++++++++++++++------------------- src/impl/peerconnection.hpp | 8 +++---- src/peerconnection.cpp | 4 ++-- 4 files changed, 24 insertions(+), 35 deletions(-) diff --git a/include/rtc/peerconnection.hpp b/include/rtc/peerconnection.hpp index e07ad4461..597d792c4 100644 --- a/include/rtc/peerconnection.hpp +++ b/include/rtc/peerconnection.hpp @@ -35,11 +35,6 @@ struct RTC_CPP_EXPORT DataChannelInit { string protocol = ""; }; -struct RTC_CPP_EXPORT RemoteFingerprint { - string value; - CertificateFingerprint::Algorithm algorithm; -}; - class RTC_CPP_EXPORT PeerConnection final : CheshireCat { public: enum class State : int { @@ -118,7 +113,7 @@ class RTC_CPP_EXPORT PeerConnection final : CheshireCat { void onSignalingStateChange(std::function callback); void resetCallbacks(); - std::vector remoteFingerprints(); + CertificateFingerprint remoteFingerprint(); // Stats void clearStats(); diff --git a/src/impl/peerconnection.cpp b/src/impl/peerconnection.cpp index 4f83e96f5..c305384aa 100644 --- a/src/impl/peerconnection.cpp +++ b/src/impl/peerconnection.cpp @@ -234,12 +234,14 @@ shared_ptr PeerConnection::initDtlsTransport() { fingerprintAlgorithm = remote->fingerprint()->algorithm; } + mRemoteFingerprintAlgorithm = fingerprintAlgorithm; + auto lower = std::atomic_load(&mIceTransport); if (!lower) throw std::logic_error("No underlying ICE transport for DTLS transport"); auto certificate = mCertificate.get(); - auto verifierCallback = weak_bind(&PeerConnection::checkFingerprint, this, _1, fingerprintAlgorithm); + auto verifierCallback = weak_bind(&PeerConnection::checkFingerprint, this, _1); auto dtlsStateChangeCallback = [this, weak_this = weak_from_this()](DtlsTransport::State transportState) { auto shared_this = weak_this.lock(); @@ -439,15 +441,21 @@ void PeerConnection::rollbackLocalDescription() { } } -bool PeerConnection::checkFingerprint(const std::string &fingerprint, const CertificateFingerprint::Algorithm &algorithm) { +bool PeerConnection::checkFingerprint(const std::string &fingerprint) { std::lock_guard lock(mRemoteDescriptionMutex); if (!mRemoteDescription || !mRemoteDescription->fingerprint()) return false; + if (config.disableFingerprintVerification) { + PLOG_VERBOSE << "Skipping fingerprint validation"; + mRemoteFingerprint = fingerprint; + return true; + } + auto expectedFingerprint = mRemoteDescription->fingerprint()->value; - if (config.disableFingerprintVerification || expectedFingerprint == fingerprint) { + if (expectedFingerprint == fingerprint) { PLOG_VERBOSE << "Valid fingerprint \"" << fingerprint << "\""; - storeRemoteFingerprint(fingerprint, algorithm); + mRemoteFingerprint = fingerprint; return true; } @@ -455,20 +463,6 @@ bool PeerConnection::checkFingerprint(const std::string &fingerprint, const Cert return false; } -void PeerConnection::storeRemoteFingerprint(const std::string &value, const CertificateFingerprint::Algorithm &algorithm) { - auto iter = std::find_if(rFingerprints.begin(), rFingerprints.end(), [&](const RemoteFingerprint& existing){return existing.value == value;}); - bool seenPreviously = iter != rFingerprints.end(); - - if (seenPreviously) { - return; - } - - rFingerprints.push_back({ - value, - algorithm - }); -} - void PeerConnection::forwardMessage(message_ptr message) { if (!message) { remoteCloseDataChannels(); @@ -1313,11 +1307,11 @@ void PeerConnection::resetCallbacks() { trackCallback = nullptr; } -std::vector PeerConnection::remoteFingerprints() { - std::vector ret; - ret = rFingerprints; - - return ret; +CertificateFingerprint PeerConnection::remoteFingerprint() { + if (mRemoteFingerprint) + return {CertificateFingerprint{mRemoteFingerprintAlgorithm, *mRemoteFingerprint}}; + else + return {}; } void PeerConnection::updateTrackSsrcCache(const Description &description) { diff --git a/src/impl/peerconnection.hpp b/src/impl/peerconnection.hpp index 4fd611939..37e07cbd7 100644 --- a/src/impl/peerconnection.hpp +++ b/src/impl/peerconnection.hpp @@ -53,7 +53,7 @@ struct PeerConnection : std::enable_shared_from_this { void endLocalCandidates(); void rollbackLocalDescription(); - bool checkFingerprint(const std::string &fingerprint, const CertificateFingerprint::Algorithm &algorithm); + bool checkFingerprint(const std::string &fingerprint); void forwardMessage(message_ptr message); void forwardMedia(message_ptr message); void forwardBufferedAmount(uint16_t stream, size_t amount); @@ -98,7 +98,7 @@ struct PeerConnection : std::enable_shared_from_this { bool changeSignalingState(SignalingState newState); void resetCallbacks(); - std::vector remoteFingerprints(); + CertificateFingerprint remoteFingerprint(); // Helper method for asynchronous callback invocation template void trigger(synchronized_callback *cb, Args... args) { @@ -130,7 +130,6 @@ struct PeerConnection : std::enable_shared_from_this { private: void dispatchMedia(message_ptr message); void updateTrackSsrcCache(const Description &description); - void storeRemoteFingerprint(const std::string &fingerprint, const CertificateFingerprint::Algorithm &algorithm); const init_token mInitToken = Init::Instance().token(); future_certificate_ptr mCertificate; @@ -160,7 +159,8 @@ struct PeerConnection : std::enable_shared_from_this { Queue> mPendingDataChannels; Queue> mPendingTracks; - std::vector rFingerprints; + CertificateFingerprint::Algorithm mRemoteFingerprintAlgorithm = CertificateFingerprint::Algorithm::Sha256; + optional mRemoteFingerprint; }; } // namespace rtc::impl diff --git a/src/peerconnection.cpp b/src/peerconnection.cpp index caaef24bb..495cd1c3d 100644 --- a/src/peerconnection.cpp +++ b/src/peerconnection.cpp @@ -367,8 +367,8 @@ optional PeerConnection::rtt() { return sctpTransport ? sctpTransport->rtt() : nullopt; } -std::vector PeerConnection::remoteFingerprints() { - return impl()->remoteFingerprints(); +CertificateFingerprint PeerConnection::remoteFingerprint() { + return impl()->remoteFingerprint(); } std::ostream &operator<<(std::ostream &out, PeerConnection::State state) {