Commit f8258757 authored by Guillaume Roguez's avatar Guillaume Roguez

dring: remove dead/deprecated API (TLS validation)

Refs #65511

Change-Id: Ic9026eea08456f6d94e93edbbc6ea13b3aea3735
parent 8f3f8223
......@@ -716,31 +716,5 @@
<arg type="a{ss}" name="shortcutsMap" direction="in">
</arg>
</method>
<!-- Security Methods -->
<method name="checkForPrivateKey" tp:name-for-bindings="checkForPrivateKey">
<arg type="s" name="pemPath" direction="in">
</arg>
<arg type="b" name="containPrivateKey" direction="out">
</arg>
</method>
<method name="checkCertificateValidity" tp:name-for-bindings="checkCertificateValidity">
<arg type="s" name="caPath" direction="in">
</arg>
<arg type="s" name="pemPath" direction="in">
</arg>
<arg type="b" name="isValid" direction="out">
</arg>
</method>
<method name="checkHostnameCertificate" tp:name-for-bindings="checkHostnameCertificate">
<arg type="s" name="host" direction="in">
</arg>
<arg type="s" name="port" direction="in">
</arg>
<arg type="b" name="isValid" direction="out">
</arg>
</method>
</interface>
</node>
......@@ -371,18 +371,3 @@ double DBusConfigurationManager::getVolume(const std::string& device)
{
return ring_config_get_volume(device);
}
bool DBusConfigurationManager::checkForPrivateKey(const std::string& pemPath)
{
return ring_config_check_for_private_key(pemPath);
}
bool DBusConfigurationManager::checkCertificateValidity(const std::string& caPath, const std::string& pemPath)
{
return ring_config_check_certificate_validity(caPath, pemPath);
}
bool DBusConfigurationManager::checkHostnameCertificate(const std::string& host, const std::string& port)
{
return ring_config_check_hostname_certificate(host, port);
}
......@@ -132,9 +132,6 @@ class DBusConfigurationManager :
void setShortcuts(const std::map<std::string, std::string> &shortcutsMap);
void setVolume(const std::string& device, const double& value);
double getVolume(const std::string& device);
bool checkForPrivateKey(const std::string& pemPath);
bool checkCertificateValidity(const std::string& caPath, const std::string& pemPath);
bool checkHostnameCertificate(const std::string& host, const std::string& port);
std::map<std::string, std::string> validateCertificate(const std::string& accountId,
const std::string& certificate, const std::string& privateKey);
std::map<std::string, std::string> getCertificateDetails(const std::string& certificate);
......
......@@ -39,7 +39,6 @@
#include "manager.h"
#if HAVE_TLS && HAVE_DHT
#include "sip/tlsvalidator.h"
#include "sip/tlsvalidation.h"
#endif
#include "logger.h"
#include "fileutils.h"
......@@ -617,41 +616,6 @@ void ConfigurationManager::setCredentials(const std::string& accountID,
sipaccount->setCredentials(details);
}
bool ConfigurationManager::checkForPrivateKey(const std::string& pemPath)
{
#if HAVE_TLS && HAVE_DHT
return containsPrivateKey(pemPath.c_str()) == 0;
#else
RING_WARN("TLS not supported");
return false;
#endif
}
bool ConfigurationManager::checkCertificateValidity(const std::string& caPath,
const std::string& pemPath)
{
#if HAVE_TLS && HAVE_DHT
return certificateIsValid(caPath.size() > 0 ? caPath.c_str() : NULL,
pemPath.c_str()) == 0;
#else
RING_WARN("TLS not supported");
return false;
#endif
}
bool ConfigurationManager::checkHostnameCertificate(const std::string& host,
const std::string& port)
{
#if HAVE_TLS && HAVE_DHT
return verifyHostnameCertificate(host.c_str(),
strtol(port.c_str(), NULL, 10)) == 0;
#else
RING_WARN("TLS not supported");
return false;
#endif
}
void ConfigurationManager::volumeChanged(const std::string& device, double value)
{
if (evHandlers_.on_volume_change) {
......
......@@ -141,11 +141,6 @@ class ConfigurationManager
/*
* Security
*/
bool checkForPrivateKey(const std::string& pemPath);
bool checkCertificateValidity(const std::string& caPath,
const std::string& pemPath);
bool checkHostnameCertificate(const std::string& host,
const std::string& port);
std::map<std::string, std::string> validateCertificate(const std::string& accountId,
const std::string& certificate, const std::string& privateKey);
std::map<std::string, std::string> getCertificateDetails(const std::string& certificate);
......
......@@ -261,9 +261,6 @@ std::map<std::string, std::string> ring_config_get_shortcuts();
void ring_config_set_shortcuts(const std::map<std::string, std::string>& shortcuts);
void ring_config_set_volume(const std::string& device, double value);
double ring_config_get_volume(const std::string& device);
bool ring_config_check_for_private_key(const std::string& pem_path);
bool ring_config_check_certificate_validity(const std::string& ca_path, const std::string& pem_path);
bool ring_config_check_hostname_certificate(const std::string& host, const std::string& port);
/* presence API */
void ring_pres_publish(const std::string& account_id, int status, const std::string& note);
......
......@@ -670,21 +670,6 @@ double ring_config_get_volume(const std::string& device)
return getConfigurationManager()->getVolume(device);
}
bool ring_config_check_for_private_key(const std::string& pem_path)
{
return getConfigurationManager()->checkForPrivateKey(pem_path);
}
bool ring_config_check_certificate_validity(const std::string& ca_path, const std::string& pem_path)
{
return getConfigurationManager()->checkCertificateValidity(ca_path, pem_path);
}
bool ring_config_check_hostname_certificate(const std::string& host, const std::string& port)
{
return getConfigurationManager()->checkHostnameCertificate(host, port);
}
std::map<std::string, std::string> ring_config_validate_certificate(const std::string& accountId, const std::string& certificate, const std::string& private_key)
{
return getConfigurationManager()->validateCertificate(accountId,certificate,private_key);
......
......@@ -20,8 +20,6 @@ libsiplink_la_SOURCES = \
sip_utils.h
if BUILD_TLS
libsiplink_la_SOURCES += tlsvalidation.c \
tlsvalidation.h
# These files depend on opendht
if USE_DHT
libsiplink_la_SOURCES += tlsvalidator.cpp \
......
/*
* Copyright (C) 2004-2015 Savoir-Faire Linux Inc.
*
* Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
* Vittorio Giovara <vittorio.giovara@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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <limits.h>
#include <errno.h>
#include <dirent.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <gnutls/abstract.h>
#include "logger.h"
#include "tlsvalidation.h"
/**
* Load the content of a file and return the data pointer to it.
*/
static unsigned char *crypto_file_read(const char *path, size_t *out_len)
{
struct stat st;
int fd;
ssize_t bytes_read;
size_t file_size;
unsigned char *data = NULL;
*out_len = 0;
fd = open(path, O_RDONLY);
if (fd < 0) {
RING_ERR("Failed to open file '%s'.", path);
return NULL;
}
if (fstat(fd, &st) < 0) {
RING_ERR("Failed to stat file '%s'.", path);
goto out;
}
if (st.st_size <= 0 || st.st_size > INT_MAX) {
RING_ERR("Invalid file '%s' length %ld.", path, st.st_size);
goto out;
}
file_size = st.st_size;
data = (unsigned char *)malloc(file_size);
if (!data) {
RING_ERR("Not enough memory to read file '%s'.", path);
goto out;
}
do {
bytes_read = read(fd, &(data[*out_len]), (st.st_size - *out_len));
if (bytes_read < 0) {
free(data);
data = NULL;
*out_len = 0;
RING_ERR("Failed to read file '%s'.", path);
goto out;
}
*out_len += bytes_read;
} while ((bytes_read > 0) && (*out_len < file_size));
out:
close(fd);
return data;
}
/**
* Check the validity date of a given certificate.
*/
static int crypto_cert_check_date(gnutls_x509_crt_t cert)
{
time_t now = time(0);
time_t activationTime, expirationTime;
activationTime = gnutls_x509_crt_get_activation_time(cert);
if (activationTime == -1) {
RING_ERR("Could not retrieve activation time.");
return -1;
}
if (now < activationTime) {
RING_ERR("Certificate not yet activated.");
return -1;
}
expirationTime = gnutls_x509_crt_get_expiration_time(cert);
if (expirationTime == -1) {
RING_ERR("Could not errrieve expiration time.");
return -2;
}
if (now > expirationTime) {
RING_ERR("Certificate expired.");
return -2;
}
return 0;
}
/**
* Load the content of a certificate file and return the data pointer to it.
*/
static unsigned char *crypto_cert_read(const char *path, size_t *out_len)
{
gnutls_x509_crt_t cert;
unsigned char *data = NULL;
gnutls_datum_t dt;
size_t fsize = 0;
int err;
dt.data = crypto_file_read(path, &fsize);
if (!dt.data)
return NULL;
dt.size = (unsigned int) fsize;
if (gnutls_x509_crt_init(&cert) != GNUTLS_E_SUCCESS) {
RING_ERR("Not enough memory for certificate.");
goto out;
}
err = gnutls_x509_crt_import(cert, &dt, GNUTLS_X509_FMT_PEM);
if (err != GNUTLS_E_SUCCESS)
err = gnutls_x509_crt_import(cert, &dt, GNUTLS_X509_FMT_DER);
if (err != GNUTLS_E_SUCCESS) {
RING_ERR("Could not import certificate %s - %s", path, gnutls_strerror(err));
goto out;
}
/* check if cert date is valid */
err = crypto_cert_check_date(cert);
if (err < 0)
goto out;
*out_len = 10000;
data = (unsigned char *)malloc(*out_len);
if (!data)
goto out;
err = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, data, out_len);
if (err != GNUTLS_E_SUCCESS) {
free(data);
data = NULL;
*out_len = 0;
RING_ERR("Certificate %s could not be exported - %s.\n",
path, gnutls_strerror(err));
}
out:
if (dt.data)
gnutls_free(dt.data);
gnutls_x509_crt_deinit(cert);
return data;
}
/**
* Load all root CAs present in the system.
* Normally we should use gnutls_certificate_set_x509_system_trust(), but it requires
* GnuTLS 3.0 or later. As a workaround we iterate on the system trusted store folder
* and load every certificate available there.
*/
static int crypto_cert_load_trusted(gnutls_certificate_credentials_t cred)
{
DIR *trust_store;
struct dirent *trust_ca;
struct stat statbuf;
int err, res = -1;
char ca_file[512];
trust_store = opendir("/etc/ssl/certs/");
if (!trust_store) {
RING_ERR("Failed to open system trusted store.");
goto out;
}
while ((trust_ca = readdir(trust_store)) != NULL) {
/* Prepare the string and check it is a regular file. */
err = snprintf(ca_file, sizeof(ca_file), "/etc/ssl/certs/%s", trust_ca->d_name);
if (err < 0) {
RING_ERR("snprintf() error");
goto out;
} else if (err >= sizeof(ca_file)) {
RING_ERR("File name too long '%s'.", trust_ca->d_name);
goto out;
}
err = stat(ca_file, &statbuf);
if (err < 0) {
RING_ERR("Failed to stat file '%s'.", ca_file);
goto out;
}
if (!S_ISREG(statbuf.st_mode))
continue;
/* Load the root CA. */
err = gnutls_certificate_set_x509_trust_file(cred, ca_file, GNUTLS_X509_FMT_PEM);
if (err == 0) {
RING_WARN("No trusted certificates found - %s", gnutls_strerror(err));
} else if (err < 0) {
RING_ERR("Could not load trusted certificates - %s", gnutls_strerror(err));
goto out;
}
}
res = 0;
out:
closedir(trust_store);
return res;
}
/**
* Print the Subject, the Issuer and the Verification status of a given certificate.
*/
static int crypto_cert_print_issuer(gnutls_x509_crt_t cert,
gnutls_x509_crt_t issuer)
{
char name[512];
char issuer_name[512];
size_t name_size;
size_t issuer_name_size;
issuer_name_size = sizeof(issuer_name);
gnutls_x509_crt_get_issuer_dn(cert, issuer_name,
&issuer_name_size);
name_size = sizeof(name);
gnutls_x509_crt_get_dn(cert, name, &name_size);
RING_DBG("Subject: %s", name);
RING_DBG("Issuer: %s", issuer_name);
if (issuer != NULL) {
issuer_name_size = sizeof(issuer_name);
gnutls_x509_crt_get_dn(issuer, issuer_name, &issuer_name_size);
RING_DBG("Verified against: %s", issuer_name);
}
return 0;
}
int containsPrivateKey(const char *pemPath)
{
gnutls_datum_t dt;
gnutls_x509_privkey_t key;
size_t bufsize;
int err, res = -1;
dt.data = crypto_file_read(pemPath, &bufsize);
if (!dt.data)
return res;
dt.size = bufsize;
err = gnutls_global_init();
if (err != GNUTLS_E_SUCCESS) {
RING_ERR("Could not init GnuTLS - %s", gnutls_strerror(err));
free(dt.data);
return res;
}
err = gnutls_x509_privkey_init(&key);
if (err != GNUTLS_E_SUCCESS) {
RING_ERR("Could not init key - %s", gnutls_strerror(err));
free(dt.data);
gnutls_global_deinit();
return res;
}
err = gnutls_x509_privkey_import(key, &dt, GNUTLS_X509_FMT_PEM);
if (err != GNUTLS_E_SUCCESS)
err = gnutls_x509_privkey_import(key, &dt, GNUTLS_X509_FMT_DER);
if (err != GNUTLS_E_SUCCESS) {
RING_ERR("Could not read key - %s", gnutls_strerror(err));
goto out;
}
res = 0;
RING_DBG("Key from %s seems valid.", pemPath);
out:
free(dt.data);
gnutls_x509_privkey_deinit(key);
gnutls_global_deinit();
return res;
}
int certificateIsValid(const char *caPath, const char *certPath)
{
gnutls_x509_crt_t ca = NULL;
gnutls_x509_crt_t cert = NULL;
gnutls_datum_t ca_dt = {}, cert_dt = {};
size_t bufsize;
unsigned int output;
int err, self_signed;
int res = -1;
err = gnutls_global_init();
if (err != GNUTLS_E_SUCCESS) {
RING_ERR("Could not init GnuTLS - %s", gnutls_strerror(err));
goto out;
}
cert_dt.data = crypto_cert_read(certPath, &bufsize);
cert_dt.size = bufsize;
if (!cert_dt.data)
goto out;
err = gnutls_x509_crt_init(&cert);
if (err != GNUTLS_E_SUCCESS) {
RING_ERR("Could not init certificate - %s", gnutls_strerror(err));
goto out;
}
err = gnutls_x509_crt_import(cert, &cert_dt, GNUTLS_X509_FMT_PEM);
if (err != GNUTLS_E_SUCCESS)
err = gnutls_x509_crt_import(cert, &cert_dt, GNUTLS_X509_FMT_DER);
if (err != GNUTLS_E_SUCCESS) {
RING_ERR("Could not read certificate - %s", gnutls_strerror(err));
goto out;
}
free(cert_dt.data);
cert_dt.data = NULL;
/* check if cert is self signed */
self_signed = gnutls_x509_crt_check_issuer(cert, cert);
if (!self_signed && !caPath) {
RING_ERR("Certificate is not self-signed, and CA is not provided.");
goto out;
}
if (caPath) {
ca_dt.data = crypto_cert_read(caPath, &bufsize);
ca_dt.size = bufsize;
if (!ca_dt.data)
goto out;
err = gnutls_x509_crt_init(&ca);
if (err != GNUTLS_E_SUCCESS) {
RING_ERR("Could not init CA - %s", gnutls_strerror(err));
goto out;
}
err = gnutls_x509_crt_import(ca, &ca_dt, GNUTLS_X509_FMT_PEM);
if (err != GNUTLS_E_SUCCESS)
err = gnutls_x509_crt_import(ca, &ca_dt, GNUTLS_X509_FMT_DER);
if (err != GNUTLS_E_SUCCESS) {
RING_ERR("Could not read CA - %s", gnutls_strerror(err));
goto out;
}
free(ca_dt.data);
ca_dt.data = NULL;
/* Check if the CA is the issuer of certificate. */
self_signed = gnutls_x509_crt_check_issuer(cert, ca);
if (!self_signed) {
RING_ERR("Certificate is not issued by the provided CA.");
goto out;
}
/* Verify the certificate with its issuer. */
err = gnutls_x509_crt_verify(cert, &ca, 1, 0, &output);
if (err < 0) {
RING_ERR("Could not verify cert: %s", gnutls_strerror(err));
goto out;
}
if (output & GNUTLS_CERT_INVALID) {
RING_ERR("Verification failed.");
if (output & GNUTLS_CERT_SIGNER_NOT_FOUND)
RING_ERR("The certificate hasn't got a known issuer.");
if (output & GNUTLS_CERT_SIGNER_NOT_CA)
RING_ERR("The certificate issuer is not a CA.");
if (output & GNUTLS_CERT_REVOKED)
RING_ERR("The certificate has been revoked.");
if (output & GNUTLS_CERT_EXPIRED)
RING_ERR("The certificate has expired.");
if (output & GNUTLS_CERT_NOT_ACTIVATED)
RING_ERR("The certificate is not yet activated.");
goto out;
}
}
RING_DBG("Certificate from %s seems valid.", certPath);
crypto_cert_print_issuer(cert, ca);
res = 0;
out:
if (ca_dt.data)
free(ca_dt.data);
if (cert_dt.data)
free(cert_dt.data);
if (ca)
gnutls_x509_crt_deinit(ca);
gnutls_x509_crt_deinit(cert);
gnutls_global_deinit();
return res;
}
/* mainly based on Fedora Defensive Coding tutorial
* https://docs.fedoraproject.org/en-US/Fedora_Security_Team/html/Defensive_Coding/sect-Defensive_Coding-TLS-Client-GNUTLS.html
*/