Commit 1047c18b authored by Mickaël Turnel's avatar Mickaël Turnel
Browse files

The tunnel now supports client certificate verification

parent 40738c1d
......@@ -157,6 +157,94 @@ RtpTransport *TunnelManager::createRtpTransport(int port){
return t;
}
void TunnelManager::setUsername(const char* username) {
mUsername = std::string(username == NULL ? "" : username);
}
const std::string& TunnelManager::getUsername() const {
return mUsername;
}
void TunnelManager::setDomain(const char *domain) {
mDomain = std::string(domain == NULL ? "" : domain);
}
const std::string& TunnelManager::getDomain() const {
return mDomain;
}
bctbx_x509_certificate_t *TunnelManager::getCertificate() const {
return mCertificate;
}
void TunnelManager::setCertificate(bctbx_x509_certificate_t *certificate) {
mCertificate = certificate;
}
bctbx_signing_key_t *TunnelManager::getKey() const {
return mKey;
}
void TunnelManager::setKey(bctbx_signing_key_t *key) {
mKey = key;
}
int TunnelManager::tlsCallbackClientCertificate(void *data, bctbx_ssl_context_t *ctx, unsigned char *dn, size_t dn_length) {
TunnelManager *zis = static_cast<TunnelManager*>(data);
if (!zis->getCertificate() || !zis->getKey()) {
const LinphoneAuthInfo *authInfo = _linphone_core_find_indexed_tls_auth_info(zis->getLinphoneCore(), zis->getUsername().c_str(), zis->getDomain().c_str());
if (authInfo == NULL) {
ms_error("TunnelManager: Cannot find auth info for user '%s'", zis->getUsername().c_str());
return -1;
}
if (!zis->getCertificate()) {
bctbx_x509_certificate_t *cert = bctbx_x509_certificate_new();
if (linphone_auth_info_get_tls_cert(authInfo)) {
const char *cert_buffer = linphone_auth_info_get_tls_cert(authInfo);
bctbx_x509_certificate_parse(cert, cert_buffer, strlen(cert_buffer));
} else if (linphone_auth_info_get_tls_cert_path(authInfo)) {
bctbx_x509_certificate_parse_file(cert, linphone_auth_info_get_tls_cert_path(authInfo));
} else {
ms_error("TunnelManager: Cannot find TLS cert in auth info for user '%s'", zis->getUsername().c_str());
bctbx_x509_certificate_free(cert);
return -1;
}
zis->setCertificate(cert);
}
if (!zis->getKey()) {
bctbx_signing_key_t *key = bctbx_signing_key_new();
if (linphone_auth_info_get_tls_key(authInfo)) {
const char *key_buffer = linphone_auth_info_get_tls_key(authInfo);
const char *passwd = linphone_auth_info_get_password(authInfo);
bctbx_signing_key_parse(key, key_buffer, strlen(key_buffer), (const unsigned char *)passwd, passwd ? strlen(passwd) : 0);
} else if (linphone_auth_info_get_tls_key_path(authInfo)) {
bctbx_signing_key_parse_file(key, linphone_auth_info_get_tls_key_path(authInfo), linphone_auth_info_get_password(authInfo));
} else {
ms_error("TunnelManager: Cannot find TLS key in auth info for user '%s'", zis->getUsername().c_str());
bctbx_signing_key_free(key);
return -1;
}
zis->setKey(key);
}
}
int err;
char tmp[512] = {0};
if ((err = bctbx_ssl_set_hs_own_cert(ctx, zis->getCertificate(), zis->getKey()))) {
bctbx_strerror(err, tmp, sizeof(tmp) -1 );
ms_error("TunnelManager: Cannot set retrieved TLS certificate [%s]", tmp);
return -1;
}
return 0;
}
void TunnelManager::startClient() {
ms_message("TunnelManager: Starting tunnel client");
if (!mTunnelClient) {
......@@ -168,9 +256,11 @@ void TunnelManager::startClient() {
mCore->sal->setTunnel(mTunnelClient);
if (!mUseDualClient) {
static_cast<TunnelClient*>(mTunnelClient)->setCallback(tunnelCallback,this);
static_cast<TunnelClient*>(mTunnelClient)->setStateCallback(tunnelCallback,this);
if (!mUsername.empty()) static_cast<TunnelClient*>(mTunnelClient)->setClientCertificateCallback(tlsCallbackClientCertificate, this);
} else {
static_cast<DualTunnelClient*>(mTunnelClient)->setCallback(tunnelCallback2,this);
static_cast<DualTunnelClient*>(mTunnelClient)->setStateCallback(tunnelCallback2,this);
if (!mUsername.empty()) static_cast<DualTunnelClient*>(mTunnelClient)->setClientCertificateCallback(tlsCallbackClientCertificate, this);
}
}
......@@ -277,6 +367,8 @@ TunnelManager::TunnelManager(LinphoneCore* lc) :
mTargetState = Off;
mStarted = false;
mTunnelizeSipPackets = true;
mCertificate = NULL;
mKey = NULL;
}
void TunnelManager::unlinkLinphoneCore() {
if (mCore) {
......@@ -299,6 +391,8 @@ TunnelManager::~TunnelManager(){
for(UdpMirrorClientList::iterator udpMirror = mUdpMirrorClients.begin(); udpMirror != mUdpMirrorClients.end(); udpMirror++) {
udpMirror->stop();
}
if (mCertificate) bctbx_x509_certificate_free(mCertificate);
if (mKey) bctbx_signing_key_free(mKey);
unlinkLinphoneCore();
}
......
......@@ -16,6 +16,7 @@
#include <tunnel/udp_mirror.hh>
#include "linphone/core.h"
#include "linphone/tunnel.h"
#include "bctoolbox/crypto.h"
#ifndef USE_BELLESIP
extern "C" {
......@@ -188,6 +189,11 @@ namespace belledonnecomm {
void simulateUdpLoss(bool enabled);
void setUsername(const char* username);
const std::string& getUsername() const;
void setDomain(const char *domain);
const std::string& getDomain() const;
private:
enum EventType{
UdpMirrorClientEvent,
......@@ -209,6 +215,7 @@ namespace belledonnecomm {
static void sUdpMirrorClientCallback(bool result, void* data);
static void networkReachableCb(LinphoneCore *lc, bool_t reachable);
static void globalStateChangedCb(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message);
static int tlsCallbackClientCertificate(void *data, bctbx_ssl_context_t *ctx, unsigned char *dn, size_t dn_length);
private:
......@@ -233,6 +240,10 @@ namespace belledonnecomm {
void tunnelizeLiblinphone();
void untunnelizeLiblinphone();
void unlinkLinphoneCore();
bctbx_x509_certificate_t *getCertificate() const;
void setCertificate(bctbx_x509_certificate_t *certificate);
bctbx_signing_key_t *getKey() const;
void setKey(bctbx_signing_key_t *key);
private:
LinphoneCore* mCore;
......@@ -260,6 +271,10 @@ namespace belledonnecomm {
bool mTunnelizeSipPackets;
bool mSimulateUdpLoss;
bool mUseDualClient;
std::string mUsername;
std::string mDomain;
bctbx_x509_certificate_t *mCertificate;
bctbx_signing_key_t *mKey;
};
/**
......
......@@ -406,10 +406,15 @@ void linphone_tunnel_configure(LinphoneTunnel *tunnel){
bool_t tunnelizeSIPPackets = (bool_t)lp_config_get_int(config(tunnel), "tunnel", "sip", TRUE);
bool_t tunnelVerifyServerCertificate = (bool_t)lp_config_get_int(config(tunnel), "tunnel", "verify_cert", FALSE);
bool_t useDualMode = (bool_t)lp_config_get_int(config(tunnel), "tunnel", "dual_mode", FALSE);
const char *username = lp_config_get_string(config(tunnel), "tunnel", "username", NULL);
const char *domain = lp_config_get_string(config(tunnel), "tunnel", "domain", NULL);
const char *http_host, *http_username, *http_passwd;
int http_port;
linphone_tunnel_get_http_proxy(tunnel,&http_host, &http_port, &http_username, &http_passwd);
bcTunnel(tunnel)->setHttpProxy(http_host, http_port, http_username, http_passwd);
bcTunnel(tunnel)->setUsername(username);
bcTunnel(tunnel)->setDomain(domain);
linphone_tunnel_enable_dual_mode(tunnel, useDualMode);
linphone_tunnel_load_config(tunnel);
......@@ -440,6 +445,24 @@ bool_t linphone_tunnel_auto_detect_enabled(LinphoneTunnel *tunnel) {
return linphone_tunnel_get_mode(tunnel) == LinphoneTunnelModeAuto;
}
void linphone_tunnel_set_username(LinphoneTunnel *tunnel, const char *username) {
bcTunnel(tunnel)->setUsername(username);
lp_config_set_string(config(tunnel), "tunnel", "username", username);
}
const char *linphone_tunnel_get_username(LinphoneTunnel *tunnel) {
return lp_config_get_string(config(tunnel), "tunnel", "username", NULL);
}
void linphone_tunnel_set_domain(LinphoneTunnel *tunnel, const char *domain) {
bcTunnel(tunnel)->setDomain(domain);
lp_config_set_string(config(tunnel), "tunnel", "domain", domain);
}
const char *linphone_tunnel_get_domain(LinphoneTunnel *tunnel) {
return lp_config_get_string(config(tunnel), "tunnel", "domain", NULL);
}
void linphone_tunnel_simulate_udp_loss(LinphoneTunnel *tunnel, bool_t enabled) {
bcTunnel(tunnel)->simulateUdpLoss(enabled == FALSE ? false : true);
}
......@@ -122,9 +122,8 @@ int linphone_tunnel_config_get_delay(const LinphoneTunnelConfig *tunnel) {
}
static void _linphone_tunnel_config_destroy(LinphoneTunnelConfig *tunnel) {
if(tunnel->host != NULL) {
ms_free(tunnel->host);
}
if (tunnel->host) ms_free(tunnel->host);
if (tunnel->host2) ms_free(tunnel->host2);
}
LinphoneTunnelConfig * linphone_tunnel_config_ref(LinphoneTunnelConfig *cfg){
......
......@@ -127,3 +127,9 @@ bool_t linphone_tunnel_enabled(const LinphoneTunnel *tunnel) { return FALSE; }
void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel) {}
bool_t linphone_tunnel_auto_detect_enabled(LinphoneTunnel *tunnel) { return FALSE; }
void linphone_tunnel_simulate_udp_loss(LinphoneTunnel *tunnel, bool_t enabled) {}
void linphone_tunnel_set_username(LinphoneTunnel *tunnel, const char *username) {}
const char *linphone_tunnel_get_username(LinphoneTunnel *tunnel) { return NULL; }
void linphone_tunnel_set_domain(LinphoneTunnel *tunnel, const char *domain) {}
const char *linphone_tunnel_get_domain(LinphoneTunnel *tunnel) { return NULL; }
......@@ -404,6 +404,39 @@ LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_tunnel_auto_detect(LinphoneTun
*/
LINPHONE_PUBLIC LINPHONE_DEPRECATED bool_t linphone_tunnel_auto_detect_enabled(LinphoneTunnel *tunnel);
/**
* Set the username.
* Required for tunnel TLS client authentification.
* Certificate Altname or CName should be sip:<tunnel_username>@<tunnel_domain>
* @param tunnel #LinphoneTunnel object
* @param username The username
*/
LINPHONE_PUBLIC void linphone_tunnel_set_username(LinphoneTunnel *tunnel, const char *username);
/**
* Get the username.
* @param tunnel #LinphoneTunnel object
* @return The username
*/
LINPHONE_PUBLIC const char *linphone_tunnel_get_username(LinphoneTunnel *tunnel);
/**
* Set the domain.
* Required for tunnel TLS client authentification.
* Certificate Altname or CName should be sip:<tunnel_username>@<tunnel_domain>
* @param tunnel #LinphoneTunnel object
* @param domain The domain
*/
LINPHONE_PUBLIC void linphone_tunnel_set_domain(LinphoneTunnel *tunnel, const char *domain);
/**
* Get the domain.
* @param tunnel #LinphoneTunnel object
* @return The domain
*/
LINPHONE_PUBLIC const char *linphone_tunnel_get_domain(LinphoneTunnel *tunnel);
LINPHONE_PUBLIC void linphone_tunnel_simulate_udp_loss(LinphoneTunnel *tunnel, bool_t enabled);
/**
......
......@@ -61,6 +61,16 @@ static void call_with_tunnel_base(LinphoneTunnelMode tunnel_mode, bool_t with_si
char *public_ip = NULL, *public_ip2 = NULL;
BC_ASSERT_FALSE(get_ip_from_hostname("tunnel.linphone.org",tunnel_ip,sizeof(tunnel_ip)));
#if 0
// This code is here in case we want to test the client certificate verification by the tunnel server
LinphoneAuthInfo *info = linphone_auth_info_clone(linphone_core_find_auth_info(pauline->lc, NULL, linphone_address_get_username(pauline->identity), NULL));
linphone_auth_info_set_tls_cert_path(info, PATH_TO_CERT);
linphone_auth_info_set_tls_key_path(info, PATH_TO_KEY);
linphone_core_clear_all_auth_info(pauline->lc);
linphone_core_add_auth_info(pauline->lc, info);
linphone_auth_info_unref(info);
#endif
if (!gruu) {
linphone_core_remove_supported_tag(pauline->lc,"gruu"); /*with gruu, we have no access to the "public IP from contact*/
linphone_core_remove_supported_tag(marie->lc,"gruu");
......@@ -107,6 +117,13 @@ static void call_with_tunnel_base(LinphoneTunnelMode tunnel_mode, bool_t with_si
linphone_tunnel_config_set_remote_udp_mirror_port(config, -1);
linphone_tunnel_enable_dual_mode(tunnel, TRUE);
}
#if 0
// This code is here in case we want to test the client certificate verification by the tunnel server
linphone_tunnel_set_username(tunnel, linphone_address_get_username(pauline->identity));
linphone_tunnel_set_domain(tunnel, linphone_address_get_domain(pauline->identity));
#endif
linphone_tunnel_add_server(tunnel, config);
linphone_tunnel_set_mode(tunnel, tunnel_mode);
linphone_tunnel_enable_sip(tunnel, with_sip);
......
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