Commit ff118009 authored by Adrien Béraud's avatar Adrien Béraud Committed by Guillaume Roguez

ringdht: TLS/ICE sip transport

Refs #66173

Change-Id: Icdaccc782d7e70b490051832f016b434e391fe26
Signed-off-by: Guillaume Roguez's avatarGuillaume Roguez <guillaume.roguez@savoirfairelinux.com>
parent fe3d0f80
# OPENDHT
OPENDHT_VERSION := 29f5d8c68ec363899373469c0af2ba86ceb75dac
OPENDHT_VERSION := b5d93471747ad08254806843253e27e5ae9b9372
OPENDHT_URL := https://github.com/savoirfairelinux/opendht/archive/$(OPENDHT_VERSION).tar.gz
PKGS += opendht
......@@ -8,7 +8,7 @@ PKGS_FOUND += opendht
endif
# Avoid building distro-provided dependencies in case opendht was built manually
ifneq ($(call need_pkg,"gnutls >= 3.0.20"),)
ifneq ($(call need_pkg,"gnutls >= 3.1"),)
DEPS_opendht = gnutls $(DEPS_gnutls)
endif
......
......@@ -189,8 +189,6 @@ constexpr static const char NEGOTIATION_TIMEOUT_SEC [] = "TLS.negotiationTime
namespace DHT {
constexpr static const char PORT [] = "DHT.port" ;
constexpr static const char PRIVATE_PATH [] = "DHT.privkeyPath" ;
constexpr static const char CERT_PATH [] = "DHT.certificatePath" ;
} //namespace DRing::Account::DHT
......
......@@ -241,6 +241,14 @@ IceTransport::setSlaveSession()
createIceSession(PJ_ICE_SESS_ROLE_CONTROLLED);
}
bool
IceTransport::isInitiator() const
{
if (isInitialized())
return pj_ice_strans_get_role(icest_.get()) == PJ_ICE_SESS_ROLE_CONTROLLING;
return initiator_session_;
}
bool
IceTransport::start(const Attribute& rem_attrs,
const std::vector<IceCandidate>& rem_candidates)
......
......@@ -91,6 +91,11 @@ class IceTransport {
*/
bool setSlaveSession();
/**
* Get current state
*/
bool isInitiator() const;
/**
* Start tranport negociation between local candidates and given remote
* to find the right candidate pair.
......
......@@ -11,6 +11,8 @@ libringacc_la_SOURCES = \
ringaccount.cpp \
ringaccount.h \
sip_transport_ice.cpp \
sip_transport_ice.h
sip_transport_ice.h \
sips_transport_ice.cpp \
sips_transport_ice.h
endif
This diff is collapsed.
......@@ -48,6 +48,7 @@
#include <vector>
#include <map>
#include <chrono>
#include <list>
/**
* @file sipaccount.h
......@@ -63,10 +64,6 @@ namespace ring {
namespace Conf {
const char *const DHT_PORT_KEY = "dhtPort";
const char *const DHT_PRIVKEY_PATH_KEY = "dhtPrivkeyPath";
const char *const DHT_PRIVKEY_PASSWORD_KEY = "dhtPrivkeyPassword";
const char *const DHT_CERT_PATH_KEY = "dhtCertificatePath";
const char *const DHT_CA_CERT_PATH_KEY = "dhtCACertificatePath";
const char *const DHT_VALUES_PATH_KEY = "dhtValuesPath";
}
......@@ -235,11 +232,11 @@ class RingAccount : public SIPAccountBase {
newIncomingCall(const std::string& from = {});
virtual bool isTlsEnabled() const {
return false;
return true;
}
virtual bool getSrtpEnabled() const {
return false;
return true;
}
virtual sip_utils::KeyExchangeProtocol getSrtpKeyExchange() const {
......@@ -287,15 +284,6 @@ class RingAccount : public SIPAccountBase {
*/
bool mapPortUPnP();
/**
* @return pjsip_tls_setting structure, filled from the configuration
* file, that can be used directly by PJSIP to initialize
* TLS transport.
*/
pjsip_tls_setting * getTlsSetting() {
return &tlsSetting_;
}
dht::DhtRunner dht_ {};
struct PendingCall {
......@@ -318,11 +306,7 @@ class RingAccount : public SIPAccountBase {
std::set<dht::Value::Id> treatedCalls_ {};
mutable std::mutex callsMutex_ {};
std::string cacertPath_ {};
std::string privkeyPath_ {};
std::string certPath_ {};
std::string idPath_ {};
std::string cachePath_ {};
std::string dataPath_ {};
std::string caPath_ {};
......@@ -371,7 +355,10 @@ class RingAccount : public SIPAccountBase {
/**
* The TLS settings, used only if tls is chosen as a sip transport.
*/
pjsip_tls_setting tlsSetting_;
void generateDhParams();
std::shared_ptr<gnutls_dh_params_int> dhParams_;
std::mutex dhParamsMtx_;
std::condition_variable dhParamsCv_;
/**
* Optional: "received" parameter from VIA header
......
This diff is collapsed.
/*
* Copyright (C) 2004-2015 Savoir-Faire Linux Inc.
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Additional permission under GNU GPL version 3 section 7:
*
* If you modify this program, or any covered work, by linking or
* combining it with the OpenSSL project's OpenSSL library (or a
* modified version of that library), containing parts covered by the
* terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
* grants you additional permission to convey the resulting work.
* Corresponding Source for a non-source form of such a combination
* shall include the source code for the parts of OpenSSL used as well
* as that of the covered work.
*/
#pragma once
#include "ip_utils.h"
#include "threadloop.h"
#include <opendht/crypto.h>
#include <pjsip.h>
#include <pj/pool.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <gnutls/dtls.h>
#include <gnutls/abstract.h>
#include <list>
#include <functional>
#include <memory>
#include <mutex>
#include <condition_variable>
#include <chrono>
namespace ring {
class IceTransport;
} // namespace ring
namespace ring { namespace tls {
enum class TlsConnectionState {
DISCONNECTED,
COOKIE,
HANDSHAKING,
ESTABLISHED
};
struct TlsParams {
std::string ca_list;
dht::crypto::Identity id;
std::shared_ptr<gnutls_dh_params_int> dh_params;
std::chrono::steady_clock::duration timeout;
std::function<pj_status_t(unsigned status,
const gnutls_datum_t* cert_list,
unsigned cert_list_size)> cert_check;
};
struct SipsIceTransport
{
using clock = std::chrono::steady_clock;
using TransportData = struct {
pjsip_transport base; // do not move, SHOULD be the fist member
SipsIceTransport* self {nullptr};
};
static_assert(std::is_standard_layout<TransportData>::value,
"TranportData requires standard-layout");
SipsIceTransport(pjsip_endpoint* endpt, const TlsParams& param,
const std::shared_ptr<IceTransport>& ice, int comp_id);
~SipsIceTransport();
void reset();
IpAddr getLocalAddress() const;
std::shared_ptr<IceTransport> getIceTransport() const {
return ice_;
}
pjsip_transport* getTransportBase() {
return &trData_.base;
}
private:
std::unique_ptr<pj_pool_t, decltype(pj_pool_release)&> pool_;
std::unique_ptr<pj_pool_t, decltype(pj_pool_release)&> rxPool_;
using DelayedTxData = struct {
pjsip_tx_data_op_key *tdata_op_key;
clock::time_point timeout;
};
TransportData trData_;
bool is_registered_ {false};
const std::shared_ptr<IceTransport> ice_;
const int comp_id_;
TlsParams param_;
bool is_server_ {false};
//bool has_pending_connect_ {false};
IpAddr local_ {};
IpAddr remote_ {};
ThreadLoop tlsThread_;
std::condition_variable_any cv_;
std::atomic<bool> canRead_ {false};
std::atomic<bool> canWrite_ {false};
// TODO
pj_status_t verify_status_;
int last_err_;
pj_ssl_cert_info local_cert_info_;
pj_ssl_cert_info remote_cert_info_;
std::atomic<TlsConnectionState> state_ {TlsConnectionState::DISCONNECTED};
clock::time_point handshakeStart_;
gnutls_session_t session_ {nullptr};
gnutls_certificate_credentials_t xcred_;
gnutls_priority_t priority_cache;
gnutls_datum_t cookie_key_;
gnutls_dtls_prestate_st prestate_;
/**
* To be called on a regular basis to receive packets
*/
bool setup();
void loop();
void clean();
// SIP transport <-> GnuTLS
pj_status_t send(pjsip_tx_data *tdata, const pj_sockaddr_t *rem_addr,
int addr_len, void *token,
pjsip_transport_callback callback);
ssize_t trySend(pjsip_tx_data_op_key *tdata);
pj_status_t flushOutputBuff();
std::list<DelayedTxData> outputBuff_ {};
std::mutex outputBuffMtx_ {};
pjsip_rx_data rdata_;
// GnuTLS <-> ICE
ssize_t tlsSend(const void*, size_t);
ssize_t tlsRecv(void* d , size_t s);
int waitForTlsData(unsigned ms);
std::mutex inputBuffMtx_ {};
std::list<std::vector<uint8_t>> tlsInputBuff_ {};
pj_status_t startTlsSession();
pj_status_t tryHandshake();
void certGetCn(const pj_str_t *gen_name, pj_str_t *cn);
void certGetInfo(pj_pool_t *pool, pj_ssl_cert_info *ci,
gnutls_x509_crt_t cert);
void certUpdate();
pj_bool_t onHandshakeComplete(pj_status_t status);
int verifyCertificate();
pj_status_t getInfo (pj_ssl_sock_info *info);
void close();
};
}} // namespace ring::tls
......@@ -124,10 +124,6 @@ SIPAccount::SIPAccount(const std::string& accountID, bool presenceEnabled)
, cred_()
, tlsSetting_()
, ciphers_(100)
, tlsCaListFile_()
, tlsCertificateFile_()
, tlsPrivateKeyFile_()
, tlsPassword_()
, tlsMethod_("TLSv1")
, tlsCiphers_()
, tlsServerName_(0, 0)
......@@ -397,12 +393,8 @@ void SIPAccount::serialize(YAML::Emitter &out)
out << YAML::Key << Conf::VERIFY_SERVER_KEY << YAML::Value << tlsVerifyServer_;
out << YAML::Key << Conf::REQUIRE_CERTIF_KEY << YAML::Value << tlsRequireClientCertificate_;
out << YAML::Key << Conf::TIMEOUT_KEY << YAML::Value << tlsNegotiationTimeoutSec_;
out << YAML::Key << Conf::CALIST_KEY << YAML::Value << tlsCaListFile_;
out << YAML::Key << Conf::CERTIFICATE_KEY << YAML::Value << tlsCertificateFile_;
out << YAML::Key << Conf::CIPHERS_KEY << YAML::Value << tlsCiphers_;
out << YAML::Key << Conf::METHOD_KEY << YAML::Value << tlsMethod_;
out << YAML::Key << Conf::TLS_PASSWORD_KEY << YAML::Value << tlsPassword_;
out << YAML::Key << Conf::PRIVATE_KEY_KEY << YAML::Value << tlsPrivateKeyFile_;
out << YAML::Key << Conf::SERVER_KEY << YAML::Value << tlsServerName_;
out << YAML::EndMap;
......@@ -498,16 +490,12 @@ void SIPAccount::unserialize(const YAML::Node &node)
const auto &tlsMap = node[Conf::TLS_KEY];
parseValue(tlsMap, Conf::TLS_ENABLE_KEY, tlsEnable_);
parseValue(tlsMap, Conf::CERTIFICATE_KEY, tlsCertificateFile_);
parseValue(tlsMap, Conf::CALIST_KEY, tlsCaListFile_);
parseValue(tlsMap, Conf::CIPHERS_KEY, tlsCiphers_);
std::string tmpMethod(tlsMethod_);
parseValue(tlsMap, Conf::METHOD_KEY, tmpMethod);
validate(tlsMethod_, tmpMethod, VALID_TLS_METHODS);
parseValue(tlsMap, Conf::TLS_PASSWORD_KEY, tlsPassword_);
parseValue(tlsMap, Conf::PRIVATE_KEY_KEY, tlsPrivateKeyFile_);
parseValue(tlsMap, Conf::SERVER_KEY, tlsServerName_);
parseValue(tlsMap, Conf::REQUIRE_CERTIF_KEY, tlsRequireClientCertificate_);
parseValue(tlsMap, Conf::VERIFY_CLIENT_KEY, tlsVerifyClient_);
......@@ -567,12 +555,6 @@ void SIPAccount::setAccountDetails(const std::map<std::string, std::string> &det
// TLS settings
parseBool(details, Conf::CONFIG_TLS_ENABLE, tlsEnable_);
parseInt(details, Conf::CONFIG_TLS_LISTENER_PORT, tlsListenerPort_);
parseString(details, Conf::CONFIG_TLS_CA_LIST_FILE, tlsCaListFile_);
parseString(details, Conf::CONFIG_TLS_CERTIFICATE_FILE, tlsCertificateFile_);
parseString(details, Conf::CONFIG_TLS_PRIVATE_KEY_FILE, tlsPrivateKeyFile_);
parseString(details, Conf::CONFIG_TLS_PASSWORD, tlsPassword_);
auto iter = details.find(Conf::CONFIG_TLS_METHOD);
if (iter != details.end())
validate(tlsMethod_, iter->second, VALID_TLS_METHODS);
......@@ -673,10 +655,6 @@ std::map<std::string, std::string> SIPAccount::getAccountDetails() const
// TLS listener is unique and parameters are modified through IP2IP_PROFILE
a[Conf::CONFIG_TLS_ENABLE] = tlsEnable_ ? TRUE_STR : FALSE_STR;
a[Conf::CONFIG_TLS_CA_LIST_FILE] = tlsCaListFile_;
a[Conf::CONFIG_TLS_CERTIFICATE_FILE] = tlsCertificateFile_;
a[Conf::CONFIG_TLS_PRIVATE_KEY_FILE] = tlsPrivateKeyFile_;
a[Conf::CONFIG_TLS_PASSWORD] = tlsPassword_;
a[Conf::CONFIG_TLS_METHOD] = tlsMethod_;
a[Conf::CONFIG_TLS_CIPHERS] = tlsCiphers_;
a[Conf::CONFIG_TLS_SERVER_NAME] = tlsServerName_;
......
......@@ -644,10 +644,6 @@ class SIPAccount : public SIPAccountBase {
pj_uint16_t stunPort_ {PJ_STUN_PORT};
bool tlsEnable_ {false};
std::string tlsCaListFile_;
std::string tlsCertificateFile_;
std::string tlsPrivateKeyFile_;
std::string tlsPassword_;
std::string tlsMethod_;
std::string tlsCiphers_;
std::string tlsServerName_;
......
......@@ -121,6 +121,10 @@ void SIPAccountBase::serialize(YAML::Emitter &out)
void SIPAccountBase::serializeTls(YAML::Emitter &out)
{
out << YAML::Key << Conf::TLS_PORT_KEY << YAML::Value << tlsListenerPort_;
out << YAML::Key << Conf::CALIST_KEY << YAML::Value << tlsCaListFile_;
out << YAML::Key << Conf::CERTIFICATE_KEY << YAML::Value << tlsCertificateFile_;
out << YAML::Key << Conf::TLS_PASSWORD_KEY << YAML::Value << tlsPassword_;
out << YAML::Key << Conf::PRIVATE_KEY_KEY << YAML::Value << tlsPrivateKeyFile_;
}
void SIPAccountBase::unserialize(const YAML::Node &node)
......@@ -171,6 +175,10 @@ void SIPAccountBase::unserialize(const YAML::Node &node)
// get tls submap
const auto &tlsMap = node[Conf::TLS_KEY];
parseValue(tlsMap, Conf::TLS_PORT_KEY, tlsListenerPort_);
parseValue(tlsMap, Conf::CERTIFICATE_KEY, tlsCertificateFile_);
parseValue(tlsMap, Conf::CALIST_KEY, tlsCaListFile_);
parseValue(tlsMap, Conf::TLS_PASSWORD_KEY, tlsPassword_);
parseValue(tlsMap, Conf::PRIVATE_KEY_KEY, tlsPrivateKeyFile_);
unserializeRange(node, Conf::AUDIO_PORT_MIN_KEY, Conf::AUDIO_PORT_MAX_KEY, audioPortRange_);
unserializeRange(node, Conf::VIDEO_PORT_MIN_KEY, Conf::VIDEO_PORT_MAX_KEY, videoPortRange_);
......@@ -207,6 +215,10 @@ void SIPAccountBase::setAccountDetails(const std::map<std::string, std::string>
// TLS
parseInt(details, Conf::CONFIG_TLS_LISTENER_PORT, tlsListenerPort_);
parseString(details, Conf::CONFIG_TLS_CA_LIST_FILE, tlsCaListFile_);
parseString(details, Conf::CONFIG_TLS_CERTIFICATE_FILE, tlsCertificateFile_);
parseString(details, Conf::CONFIG_TLS_PRIVATE_KEY_FILE, tlsPrivateKeyFile_);
parseString(details, Conf::CONFIG_TLS_PASSWORD, tlsPassword_);
}
std::map<std::string, std::string>
......@@ -240,6 +252,10 @@ SIPAccountBase::getAccountDetails() const
std::stringstream tlslistenerport;
tlslistenerport << tlsListenerPort_;
a[Conf::CONFIG_TLS_LISTENER_PORT] = tlslistenerport.str();
a[Conf::CONFIG_TLS_CA_LIST_FILE] = tlsCaListFile_;
a[Conf::CONFIG_TLS_CERTIFICATE_FILE] = tlsCertificateFile_;
a[Conf::CONFIG_TLS_PRIVATE_KEY_FILE] = tlsPrivateKeyFile_;
a[Conf::CONFIG_TLS_PASSWORD] = tlsPassword_;
return a;
}
......
......@@ -336,9 +336,13 @@ protected:
pj_uint16_t publishedPort_ {DEFAULT_SIP_PORT};
/**
* The global TLS listener port which can be configured through the IP2IP_PROFILE
* The TLS listener port
*/
pj_uint16_t tlsListenerPort_ {DEFAULT_SIP_TLS_PORT};
std::string tlsCaListFile_;
std::string tlsCertificateFile_;
std::string tlsPrivateKeyFile_;
std::string tlsPassword_;
/**
* DTMF type used for this account SIPINFO or RTP
......
......@@ -35,6 +35,7 @@
#include "ip_utils.h"
#include "ringdht/sip_transport_ice.h"
#include "ringdht/sips_transport_ice.h"
#include "array_size.h"
#include "intrin.h"
......@@ -163,14 +164,14 @@ SipTransport::removeStateListener(uintptr_t lid)
}
SipTransportBroker::SipTransportBroker(pjsip_endpoint *endpt,
pj_caching_pool& cp, pj_pool_t& pool)
: cp_(cp), pool_(pool), endpt_(endpt)
pj_caching_pool& cp, pj_pool_t& pool) :
cp_(cp), pool_(pool), endpt_(endpt)
{
#if HAVE_DHT
/*#if HAVE_DHT
pjsip_transport_register_type(PJSIP_TRANSPORT_DATAGRAM, "ICE",
pjsip_transport_get_default_port_for_type(PJSIP_TRANSPORT_UDP),
&ice_pj_transport_type_);
#endif
#endif*/
RING_DBG("SipTransportBroker@%p", this);
}
......@@ -412,15 +413,34 @@ std::shared_ptr<SipTransport>
SipTransportBroker::getIceTransport(const std::shared_ptr<IceTransport> ice,
unsigned comp_id)
{
auto sip_ice_tr = std::unique_ptr<SipIceTransport>(new SipIceTransport(endpt_, pool_,
ice_pj_transport_type_,
ice, comp_id));
auto sip_ice_tr = std::unique_ptr<SipIceTransport>(
new SipIceTransport(endpt_, pool_, ice_pj_transport_type_, ice, comp_id));
auto tr = sip_ice_tr->getTransportBase();
auto sip_tr = std::make_shared<SipTransport>(tr);
sip_ice_tr.release(); // managed by PJSIP now
{
std::lock_guard<std::mutex> lock(transportMapMutex_);
// we do not check for key existance as we've just created it
// (member of new SipIceTransport instance)
transports_.emplace(std::make_pair(tr, sip_tr));
}
return sip_tr;
}
std::shared_ptr<SipTransport>
SipTransportBroker::getTlsIceTransport(const std::shared_ptr<ring::IceTransport> ice,
unsigned comp_id,
const tls::TlsParams& params)
{
auto sip_ice_tr = std::unique_ptr<tls::SipsIceTransport>(
new tls::SipsIceTransport(endpt_, params, ice, comp_id));
auto tr = sip_ice_tr->getTransportBase();
auto sip_tr = std::make_shared<SipTransport>(tr);
sip_ice_tr.release(); // managed by PJSIP now
{
std::unique_lock<std::mutex> lock(transportMapMutex_);
std::lock_guard<std::mutex> lock(transportMapMutex_);
// we do not check for key existance as we've just created it
// (member of new SipIceTransport instance)
transports_.emplace(std::make_pair(tr, sip_tr));
......
......@@ -145,8 +145,10 @@ class SipTransport
};
class IpAddr;
class SipIceTransport;
class IceTransport;
namespace tls {
struct TlsParams;
};
/**
* Manages the transports and receive callbacks from PJSIP
......@@ -160,13 +162,20 @@ public:
std::shared_ptr<SipTransport> getUdpTransport(const SipTransportDescr&);
#if HAVE_TLS
std::shared_ptr<TlsListener> getTlsListener(const SipTransportDescr&, const pjsip_tls_setting*);
std::shared_ptr<TlsListener>
getTlsListener(const SipTransportDescr&, const pjsip_tls_setting*);
std::shared_ptr<SipTransport> getTlsTransport(const std::shared_ptr<TlsListener>&, const IpAddr& remote);
std::shared_ptr<SipTransport>
getTlsTransport(const std::shared_ptr<TlsListener>&, const IpAddr& remote);
#endif
#if HAVE_DHT
std::shared_ptr<SipTransport> getIceTransport(const std::shared_ptr<IceTransport>, unsigned comp_id);
std::shared_ptr<SipTransport>
getIceTransport(const std::shared_ptr<IceTransport>, unsigned comp_id);
std::shared_ptr<SipTransport>
getTlsIceTransport(const std::shared_ptr<IceTransport>, unsigned comp_id,
const tls::TlsParams&);
#endif
std::shared_ptr<SipTransport> addTransport(pjsip_transport*);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment