Browse Source

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
achingbrain 1 year ago
parent
commit
9d03db688b

+ 6 - 0
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<impl::PeerConnection> {
 public:
 	enum class State : int {
@@ -113,6 +118,7 @@ public:
 	void onSignalingStateChange(std::function<void(SignalingState state)> callback);
 
 	void resetCallbacks();
+	std::vector<struct RemoteFingerprint> remoteFingerprints();
 
 	// Stats
 	void clearStats();

+ 25 - 6
src/impl/peerconnection.cpp

@@ -239,7 +239,7 @@ shared_ptr<DtlsTransport> 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<struct RemoteFingerprint> PeerConnection::remoteFingerprints() {
+	std::vector<struct RemoteFingerprint> ret;
+	ret = rFingerprints;
+
+	return ret;
+}
+
 void PeerConnection::updateTrackSsrcCache(const Description &description) {
 	std::unique_lock lock(mTracksMutex); // for safely writing to mTracksBySsrc
 

+ 5 - 1
src/impl/peerconnection.hpp

@@ -53,7 +53,7 @@ struct PeerConnection : std::enable_shared_from_this<PeerConnection> {
 
 	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<PeerConnection> {
 	bool changeSignalingState(SignalingState newState);
 
 	void resetCallbacks();
+	std::vector<struct RemoteFingerprint> remoteFingerprints();
 
 	// Helper method for asynchronous callback invocation
 	template <typename... Args> void trigger(synchronized_callback<Args...> *cb, Args... args) {
@@ -129,6 +130,7 @@ struct PeerConnection : std::enable_shared_from_this<PeerConnection> {
 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 @@ private:
 
 	Queue<shared_ptr<DataChannel>> mPendingDataChannels;
 	Queue<shared_ptr<Track>> mPendingTracks;
+
+	std::vector<struct RemoteFingerprint> rFingerprints;
 };
 
 } // namespace rtc::impl

+ 4 - 0
src/peerconnection.cpp

@@ -367,6 +367,10 @@ optional<std::chrono::milliseconds> PeerConnection::rtt() {
 	return sctpTransport ? sctpTransport->rtt() : nullopt;
 }
 
+std::vector<struct RemoteFingerprint> PeerConnection::remoteFingerprints() {
+	return impl()->remoteFingerprints();
+}
+
 std::ostream &operator<<(std::ostream &out, PeerConnection::State state) {
 	using State = PeerConnection::State;
 	const char *str;