diff --git a/src/ringdht/ringaccount.cpp b/src/ringdht/ringaccount.cpp index d63a2ecc4b44e2e71ab1a6e7a724835467c5c09d..70e47aa76c6a7599491d935cf94a4f2e1392f9ac 100644 --- a/src/ringdht/ringaccount.cpp +++ b/src/ringdht/ringaccount.cpp @@ -1719,7 +1719,7 @@ RingAccount::doRegister_() dht_.put(h, announce_, dht::DoneCallback{}, {}, true); dht_.listen<DeviceAnnouncement>(h, [shared](DeviceAnnouncement&& dev) { shared->findCertificate(dev.dev, [shared](const std::shared_ptr<dht::crypto::Certificate> crt) { - shared->foundAccountDevice(crt); + shared->foundKnownDevice(crt); }); return true; }); @@ -1739,16 +1739,44 @@ RingAccount::doRegister_() if (msg.from == this_.dht_.getId()) return true; + RING_WARN("ICE candidate from %s.", msg.from.toString().c_str()); + + // quick check in case we already explicilty banned this public key + auto trustStatus = this_.trust_.getCertificateStatus(msg.from.toString()); + if (trustStatus == tls::TrustStore::PermissionStatus::BANNED) { + RING_WARN("Discarding incoming DHT call request from banned peer %s", msg.from.toString().c_str()); + return true; + } + auto res = this_.treatedCalls_.insert(msg.id); this_.saveTreatedCalls(); if (!res.second) return true; - RING_WARN("ICE candidate from %s.", msg.from.toString().c_str()); + this_.findCertificate( msg.from, + [shared, msg, trustStatus](const std::shared_ptr<dht::crypto::Certificate> cert) mutable { + auto& this_ = *shared; + if (not this_.dhtPublicInCalls_ and trustStatus != tls::TrustStore::PermissionStatus::ALLOWED) { + if (!cert or cert->getId() != msg.from) { + RING_WARN("Can't find certificate of %s for incoming call.", + msg.from.toString().c_str()); + return; + } + + tls::CertificateStore::instance().pinCertificate(cert); - this_.onPeerMessage(msg.from, [shared, msg](const std::shared_ptr<dht::crypto::Certificate>& cert, - const dht::InfoHash& /*account*/) mutable - { + auto& this_ = *shared; + if (!this_.trust_.isAllowed(*cert)) { + RING_WARN("Discarding incoming DHT call from untrusted peer %s.", + msg.from.toString().c_str()); + return; + } + } else if (not this_.dhtPublicInCalls_ + or trustStatus == tls::TrustStore::PermissionStatus::BANNED) { + return; + } + + // Peer certificate trusted... go ahead shared->incomingCall(std::move(msg), cert); }); return true; @@ -1799,7 +1827,7 @@ RingAccount::doRegister_() RING_WARN("Can't find certificate for device %s", sync.from.toString().c_str()); return; } - if (not shared->foundAccountDevice(cert)) + if (not shared->foundKnownDevice(cert)) return; shared->onReceiveDeviceSync(std::move(sync)); }); @@ -1817,15 +1845,43 @@ RingAccount::doRegister_() if (!res.second) return true; this_.saveTreatedMessages(); - this_.onPeerMessage(v.from, [shared, v, inboxDeviceKey](const std::shared_ptr<dht::crypto::Certificate>&, - const dht::InfoHash& peer_account) - { + + // quick check in case we already explicilty banned this public key + auto trustStatus = this_.trust_.getCertificateStatus(v.from.toString()); + if (trustStatus == tls::TrustStore::PermissionStatus::BANNED) { + RING_WARN("Discarding incoming DHT message from banned peer %s", v.from.toString().c_str()); + return true; + } + + this_.findCertificate( v.from, + [shared, v, trustStatus, inboxDeviceKey](const std::shared_ptr<dht::crypto::Certificate> cert) mutable { + auto& this_ = *shared; + if (not this_.dhtPublicInCalls_ and trustStatus != tls::TrustStore::PermissionStatus::ALLOWED) { + if (!cert or cert->getId() != v.from) { + RING_WARN("Can't find certificate of %s for incoming message.", v.from.toString().c_str()); + return; + } + + tls::CertificateStore::instance().pinCertificate(cert); + + auto& this_ = *shared; + if (!this_.trust_.isAllowed(*cert)) { + RING_WARN("Discarding incoming DHT message from untrusted peer %s.", v.from.toString().c_str()); + return; + } + } else if (not this_.dhtPublicInCalls_ or trustStatus == tls::TrustStore::PermissionStatus::BANNED) { + RING_WARN("Discarding incoming DHT message from untrusted or banned peer %s.", v.from.toString().c_str()); + return; + } + + auto from_acc_id = cert ? (cert->issuer ? cert->issuer->getId().toString() : cert->getId().toString()) : v.from.toString(); + auto now = system_clock::to_time_t(system_clock::now()); std::map<std::string, std::string> payloads = {{"text/plain", utf8_make_valid(v.msg)}}; - shared->onTextMessage(peer_account.toString(), payloads); + shared->onTextMessage(from_acc_id, payloads); RING_DBG("Sending message confirmation %" PRIu64, v.id); - shared->dht_.putEncrypted(inboxDeviceKey, + this_.dht_.putEncrypted(inboxDeviceKey, v.from, dht::ImMessage(v.id, std::string(), now)); }); @@ -1839,52 +1895,12 @@ RingAccount::doRegister_() } } - -void -RingAccount::onPeerMessage(const dht::InfoHash& peer_device, std::function<void(const std::shared_ptr<dht::crypto::Certificate>& crt, const dht::InfoHash& peer_account)> cb) -{ - // quick check in case we already explicilty banned this public key - auto trustStatus = trust_.getCertificateStatus(peer_device.toString()); - if (trustStatus == tls::TrustStore::PermissionStatus::BANNED) { - RING_WARN("Discarding message from banned peer %s", peer_device.toString().c_str()); - return; - } - - auto shared = std::static_pointer_cast<RingAccount>(shared_from_this()); - findCertificate(peer_device, - [shared, peer_device, trustStatus, cb](const std::shared_ptr<dht::crypto::Certificate>& cert) { - auto& this_ = *shared; - - dht::InfoHash peer_account_id; - if (not this_.foundPeerDevice(cert, peer_account_id)) { - RING_WARN("Discarding message from invalid peer certificate %s.", peer_device.toString().c_str()); - return; - } - - if (not this_.dhtPublicInCalls_ and trustStatus != tls::TrustStore::PermissionStatus::ALLOWED) { - if (!cert or cert->getId() != peer_device) { - RING_WARN("Can't find certificate of %s for incoming message.", peer_device.toString().c_str()); - return; - } - - auto& this_ = *shared; - if (!this_.trust_.isAllowed(*cert)) { - RING_WARN("Discarding message from untrusted peer %s.", peer_device.toString().c_str()); - return; - } - } else if (not this_.dhtPublicInCalls_ or trustStatus == tls::TrustStore::PermissionStatus::BANNED) { - RING_WARN("Discarding message from untrusted or banned peer %s.", peer_device.toString().c_str()); - return; - } - - cb(cert, peer_account_id); - }); -} - void RingAccount::incomingCall(dht::IceCandidates&& msg, std::shared_ptr<dht::crypto::Certificate> from_cert) { - RING_WARN("ICE incoming from DHT peer %s", msg.from.toString().c_str()); + auto from = msg.from.toString(); + RING_WARN("ICE incoming from DHT peer %s\n%s", from.c_str(), + std::string(msg.ice_data.cbegin(), msg.ice_data.cend()).c_str()); auto call = Manager::instance().callFactory.newCall<SIPCall, RingAccount>(*this, Manager::instance().getNewCallID(), Call::CallType::INCOMING); auto ice = createIceTransport(("sip:"+call->getCallId()).c_str(), ICE_COMPONENTS, false, getIceOptions()); @@ -1915,7 +1931,7 @@ RingAccount::incomingCall(dht::IceCandidates&& msg, std::shared_ptr<dht::crypto: } bool -RingAccount::foundAccountDevice(const std::shared_ptr<dht::crypto::Certificate>& crt, const std::string& name) +RingAccount::foundKnownDevice(const std::shared_ptr<dht::crypto::Certificate>& crt, const std::string& name) { if (not crt) return false; @@ -1951,36 +1967,6 @@ RingAccount::foundAccountDevice(const std::shared_ptr<dht::crypto::Certificate>& return true; } -bool -RingAccount::foundPeerDevice(const std::shared_ptr<dht::crypto::Certificate>& crt, dht::InfoHash& account_id) -{ - if (not crt) - return false; - - auto top_issuer = crt; - while (top_issuer->issuer) - top_issuer = top_issuer->issuer; - - // Device certificate can't be self-signed - if (top_issuer == crt) { - RING_WARN("[Account %s] Found invalid peer device: %s", getAccountID().c_str(), crt->getId().toString().c_str()); - return false; - } - - // Check peer certificate chain - // Trust store with top issuer as the only CA - tls::TrustStore peer_trust; - peer_trust.setCertificateStatus(top_issuer, tls::TrustStore::PermissionStatus::ALLOWED, false); - - if (not peer_trust.isAllowed(*crt)) { - RING_WARN("[Account %s] Found invalid peer device: %s", getAccountID().c_str(), crt->getId().toString().c_str()); - return false; - } - - account_id = crt->issuer->getId(); - return true; -} - void RingAccount::replyToIncomingIceMsg(std::shared_ptr<SIPCall> call, std::shared_ptr<IceTransport> ice, @@ -2539,7 +2525,7 @@ RingAccount::onReceiveDeviceSync(DeviceSync&& sync) findCertificate(d.first, [shared,d](const std::shared_ptr<dht::crypto::Certificate> crt) { if (not crt) return; - shared->foundAccountDevice(crt, d.second); + shared->foundKnownDevice(crt, d.second); }); } it->second.last_sync = sync_date; diff --git a/src/ringdht/ringaccount.h b/src/ringdht/ringaccount.h index 37390e139a62979ffa0fac0d6206a642907eac20..6eb828d15784de6695b7048fa59a7b31c749fd76 100644 --- a/src/ringdht/ringaccount.h +++ b/src/ringdht/ringaccount.h @@ -343,26 +343,7 @@ class RingAccount : public SIPAccountBase { */ bool SIPStartCall(const std::shared_ptr<SIPCall>& call, IpAddr target); - /** - * Inform that a potential account device have been found. - * Returns true if the device have been validated to be part of this account - */ - bool foundAccountDevice(const std::shared_ptr<dht::crypto::Certificate>& crt, const std::string& name = {}); - - /** - * Inform that a potential peer device have been found. - * Returns true only if the device certificate is a valid Ring device certificate. - * In that case (true is returned) the account_id parameter is set to the peer account ID. - */ - bool foundPeerDevice(const std::shared_ptr<dht::crypto::Certificate>& crt, dht::InfoHash& account_id); - - /** - * Check that a peer is authorised to talk to us. - * If everything is in order, calls the callback with the - * peer certificate chain (down to the peer device certificate), - * and the peer account id. - */ - void onPeerMessage(const dht::InfoHash& peer_device, std::function<void(const std::shared_ptr<dht::crypto::Certificate>& crt, const dht::InfoHash& account_id)>); + bool foundKnownDevice(const std::shared_ptr<dht::crypto::Certificate>& crt, const std::string& name = {}); /** * Maps require port via UPnP