security: Change the API so it can express a certificate chain

The old API could only represent a single certificate, making
it useless to properly validate the assets.

This commit also fix many little issues that prevented
correct validation.

WARNING: This commit break the API

Refs #76889

Change-Id: I953f62ae359b9754895c72fb2e9a2bffee32eb8d
parent 5d6c36b6
......@@ -633,14 +633,9 @@
<method name="validateCertificate" tp:name-for-bindings="validateCertificate">
<arg type="s" name="accountId" direction="in"></arg>
<arg type="s" name="certificatePath" direction="in">
<tp:docstring>
<p>A certificate path</p>
</tp:docstring>
</arg>
<arg type="s" name="privateKeyPath" direction="in">
<arg type="s" name="certificate" direction="in">
<tp:docstring>
<p>An optional path a the private key for the certificate</p>
<p>A certificate ID</p>
</tp:docstring>
</arg>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="MapStringString"/>
......@@ -652,11 +647,21 @@
</arg>
</method>
<method name="validateCertificateRaw" tp:name-for-bindings="validateCertificateRaw">
<method name="validateCertificatePath" tp:name-for-bindings="validateCertificate">
<arg type="s" name="accountId" direction="in"></arg>
<arg type="ay" name="certificateRaw" direction="in">
<arg type="s" name="certificatePath" direction="in">
<tp:docstring>
<p>A certificate path</p>
<p>A certificate path.</p>
</tp:docstring>
</arg>
<arg type="s" name="privateKeyPath" direction="in">
<tp:docstring>
<p>An optional path a the private key for the certificate</p>
</tp:docstring>
</arg>
<arg type="s" name="caListPath" direction="in">
<tp:docstring>
<p>An optional path to an assumed valid ca list</p>
</tp:docstring>
</arg>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="MapStringString"/>
......@@ -669,9 +674,9 @@
</method>
<method name="getCertificateDetails" tp:name-for-bindings="getCertificateDetails">
<arg type="s" name="certificatePath" direction="in">
<arg type="s" name="certificate" direction="in">
<tp:docstring>
<p>A certificate path</p>
<p>A certificate ID</p>
</tp:docstring>
</arg>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="MapStringString"/>
......@@ -683,10 +688,10 @@
</arg>
</method>
<method name="getCertificateDetailsRaw" tp:name-for-bindings="getCertificateDetailsRaw">
<arg type="ay" name="certificateRaw" direction="in">
<method name="getCertificateDetailsPath" tp:name-for-bindings="getCertificateDetails">
<arg type="s" name="certificatePath" direction="in">
<tp:docstring>
<p>A raw certificate</p>
<p>A certificate path</p>
</tp:docstring>
</arg>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="MapStringString"/>
......@@ -720,10 +725,10 @@
<p>True to save the certificate in the daemon local store.</p>
</tp:docstring>
</arg>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="String"/>
<arg type="s" name="certId" direction="out">
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="VectorString"/>
<arg type="as" name="certId" direction="out">
<tp:docstring>
<p>ID of the pinned certificate or empty string on failure.</p>
<p>IDs of the pinned certificate chain (from subject to issuer) or empty string on failure.</p>
</tp:docstring>
</arg>
</method>
......
......@@ -365,15 +365,15 @@ DBusConfigurationManager::setHookSettings(const std::map<std::string, std::strin
}
auto
DBusConfigurationManager::validateCertificate(const std::string& accountId, const std::string& certificate, const std::string& privateKey) -> decltype(DRing::validateCertificate(accountId, certificate, privateKey))
DBusConfigurationManager::validateCertificate(const std::string& accountId, const std::string& certificate) -> decltype(DRing::validateCertificate(accountId, certificate))
{
return DRing::validateCertificate(accountId, certificate, privateKey);
return DRing::validateCertificate(accountId, certificate);
}
std::map<std::string, std::string>
DBusConfigurationManager::validateCertificateRaw(const std::string& accountId, const std::vector<uint8_t>& certificate)
auto
DBusConfigurationManager::validateCertificatePath(const std::string& accountId, const std::string& certificate, const std::string& privateKey, const std::string& caList) -> decltype(DRing::validateCertificatePath(accountId, certificate, privateKey, caList))
{
return DRing::validateCertificateRaw(accountId, certificate);
return DRing::validateCertificatePath(accountId, certificate, privateKey, caList);
}
auto
......@@ -383,9 +383,9 @@ DBusConfigurationManager::getCertificateDetails(const std::string& certificate)
}
auto
DBusConfigurationManager::getCertificateDetailsRaw(const std::vector<uint8_t>& certificate) -> decltype(DRing::getCertificateDetailsRaw(certificate))
DBusConfigurationManager::getCertificateDetailsPath(const std::string& certificate) -> decltype(DRing::getCertificateDetailsPath(certificate))
{
return DRing::getCertificateDetailsRaw(certificate);
return DRing::getCertificateDetailsPath(certificate);
}
auto
......
......@@ -128,12 +128,12 @@ 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);
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> validateCertificateRaw(const std::string& accountId, const std::vector<uint8_t>& certificate);
std::map<std::string, std::string> validateCertificate(const std::string& accountId, const std::string& certificate);
std::map<std::string, std::string> validateCertificatePath(const std::string& accountId, const std::string& certificatePath, const std::string& privateKey, const std::string& caList);
std::map<std::string, std::string> getCertificateDetails(const std::string& certificate);
std::map<std::string, std::string> getCertificateDetailsRaw(const std::vector<uint8_t>& certificate);
std::map<std::string, std::string> getCertificateDetailsPath(const std::string& certificatePath);
std::vector<std::string> getPinnedCertificates();
std::string pinCertificate(const std::vector<uint8_t>& certificate, const bool& local);
std::vector<std::string> pinCertificate(const std::vector<uint8_t>& certificate, const bool& local);
bool unpinCertificate(const std::string& certId);
void pinCertificatePath(const std::string& path);
unsigned unpinCertificatePath(const std::string& path);
......
......@@ -26,6 +26,6 @@ opendht: opendht-$(OPENDHT_VERSION).tar.gz .sum-opendht
.opendht: opendht
mkdir -p $</m4 && $(RECONF)
cd $< && $(HOSTVARS) ./configure --disable-tools $(HOSTCONF)
cd $< && $(HOSTVARS) ./configure --disable-tools --disable-python --disable-doc $(HOSTCONF)
cd $< && $(MAKE) install
touch $@
......@@ -133,14 +133,13 @@ getTlsDefaultSettings()
std::map<std::string, std::string>
validateCertificate(const std::string&,
const std::string& certificate,
const std::string& privateKey)
const std::string& certificate)
{
#if HAVE_TLS && HAVE_DHT
try {
return TlsValidator{certificate, privateKey}.getSerializedChecks();
return TlsValidator{CertificateStore::instance().getCertificate(certificate)}.getSerializedChecks();
} catch(const std::runtime_error& e) {
RING_WARN("Certificate loading failed");
RING_WARN("Certificate loading failed: %s", e.what());
return {{Certificate::ChecksNames::EXIST, Certificate::CheckValuesNames::FAILED}};
}
#else
......@@ -150,14 +149,16 @@ validateCertificate(const std::string&,
}
std::map<std::string, std::string>
validateCertificateRaw(const std::string&,
const std::vector<uint8_t>& certificate_raw)
validateCertificatePath(const std::string&,
const std::string& certificate,
const std::string& privateKey,
const std::string& caList)
{
#if HAVE_TLS && HAVE_DHT
try {
return TlsValidator{certificate_raw}.getSerializedChecks();
return TlsValidator{certificate, privateKey, caList}.getSerializedChecks();
} catch(const std::runtime_error& e) {
RING_WARN("Certificate loading failed");
RING_WARN("Certificate loading failed: %s", e.what());
return {{Certificate::ChecksNames::EXIST, Certificate::CheckValuesNames::FAILED}};
}
#else
......@@ -173,7 +174,7 @@ getCertificateDetails(const std::string& certificate)
try {
return TlsValidator{CertificateStore::instance().getCertificate(certificate)}.getSerializedDetails();
} catch(const std::runtime_error& e) {
RING_WARN("Certificate loading failed");
RING_WARN("Certificate loading failed: %s", e.what());
}
#else
RING_WARN("TLS not supported");
......@@ -182,11 +183,13 @@ getCertificateDetails(const std::string& certificate)
}
std::map<std::string, std::string>
getCertificateDetailsRaw(const std::vector<uint8_t>& certificate_raw)
getCertificateDetailsPath(const std::string& certificate)
{
#if HAVE_TLS && HAVE_DHT
try {
return TlsValidator{certificate_raw}.getSerializedDetails();
auto crt = std::make_shared<dht::crypto::Certificate>(ring::fileutils::loadFile(certificate));
CertificateStore::instance().pinCertificate(crt, false);
return TlsValidator{crt}.getSerializedDetails();
} catch(const std::runtime_error& e) {
RING_WARN("Certificate loading failed");
}
......@@ -207,7 +210,7 @@ getPinnedCertificates()
return {};
}
std::string
std::vector<std::string>
pinCertificate(const std::vector<uint8_t>& certificate, bool local)
{
return ring::tls::CertificateStore::instance().pinCertificate(certificate, local);
......
......@@ -132,15 +132,16 @@ double getVolume(const std::string& device);
* Security
*/
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> validateCertificateRaw(const std::string& accountId,
const std::vector<uint8_t>& certificate);
const std::string& certificate/*, const std::vector<std::string>& caList*/);
std::map<std::string, std::string> validateCertificatePath(const std::string& accountId,
const std::string& certificatePath, const std::string& privateKey, const std::string& caList);
std::map<std::string, std::string> getCertificateDetails(const std::string& certificate);
std::map<std::string, std::string> getCertificateDetailsRaw(const std::vector<uint8_t>& certificate);
std::map<std::string, std::string> getCertificateDetailsPath(const std::string& certificatePath);
std::vector<std::string> getPinnedCertificates();
std::string pinCertificate(const std::vector<uint8_t>& certificate, bool local);
std::vector<std::string> pinCertificate(const std::vector<uint8_t>& certificate, bool local);
bool unpinCertificate(const std::string& certId);
void pinCertificatePath(const std::string& path);
......
......@@ -89,6 +89,7 @@ namespace DetailsNames {
constexpr static char ISSUER_DN [] = "ISSUER_DN" ;
constexpr static char NEXT_EXPECTED_UPDATE_DATE [] = "NEXT_EXPECTED_UPDATE_DATE" ;
constexpr static char OUTGOING_SERVER [] = "OUTGOING_SERVER" ;
constexpr static char IS_CA [] = "IS_CA" ;
} //namespace DRing::Certificate::CheckValuesNames
/**
......
......@@ -54,12 +54,18 @@ CertificateStore::loadLocalCertificates(const std::string& path)
unsigned n = 0;
for (const auto& f : dir_content) {
try {
auto crt = crypto::Certificate(fileutils::loadFile(path+DIR_SEPARATOR_CH+f));
auto id = crt.getId().toString();
auto crt = std::make_shared<crypto::Certificate>(fileutils::loadFile(path+DIR_SEPARATOR_CH+f));
auto id = crt->getId().toString();
if (id != f)
throw std::logic_error({});
certs_.emplace(id, std::make_shared<crypto::Certificate>(std::move(crt)));
certs_.emplace(id, crt);
++n;
crt = crt->issuer;
while (crt) {
certs_.emplace(crt->getId().toString(), crt);
crt = crt->issuer;
++n;
}
} catch (const std::exception& e) {
remove((path+DIR_SEPARATOR_CH+f).c_str());
}
......@@ -87,12 +93,7 @@ CertificateStore::getCertificate(const std::string& k) const
auto cit = certs_.find(k);
if (cit == certs_.cend()) {
l.unlock();
try {
return std::make_shared<crypto::Certificate>(fileutils::loadFile(k));
} catch (const std::exception& e) {
return {};
}
return {};
}
return cit->second;
}
......@@ -168,7 +169,7 @@ CertificateStore::unpinCertificatePath(const std::string& path)
return n;
}
std::string
std::vector<std::string>
CertificateStore::pinCertificate(const std::vector<uint8_t>& cert,
bool local) noexcept
{
......@@ -178,29 +179,36 @@ CertificateStore::pinCertificate(const std::vector<uint8_t>& cert,
return {};
}
std::string
std::vector<std::string>
CertificateStore::pinCertificate(crypto::Certificate&& cert, bool local)
{
return pinCertificate(std::make_shared<crypto::Certificate>(std::move(cert)), local);
}
std::string
std::vector<std::string>
CertificateStore::pinCertificate(std::shared_ptr<crypto::Certificate> cert,
bool local)
{
auto id = cert->getId().toString();
bool sig {false};
std::vector<std::string> ids {};
{
std::lock_guard<std::mutex> l(lock_);
decltype(certs_)::iterator it;
std::tie(it, sig) = certs_.emplace(id, std::move(cert));
auto c = cert;
while (c) {
bool inserted;
auto id = c->getId().toString();
decltype(certs_)::iterator it;
std::tie(it, inserted) = certs_.emplace(id, c);
ids.emplace_back(id);
c = c->issuer;
sig |= inserted;
}
if (sig and local)
fileutils::saveFile(certPath_+DIR_SEPARATOR_CH+id, it->second->getPacked());
fileutils::saveFile(certPath_+DIR_SEPARATOR_CH+ids.front(), cert->getPacked());
}
if (sig)
for (const auto& id : ids)
emitSignal<DRing::ConfigurationSignal::CertificatePinned>(id);
return id;
return ids;
}
bool
......
......@@ -46,11 +46,10 @@ public:
std::vector<std::string> getPinnedCertificates() const;
std::shared_ptr<crypto::Certificate> getCertificate(const std::string& cert_id) const;
//std::shared_ptr<crypto::Certificate> getCertificateByPublicKey(const std::string& pk_id) const;
std::string pinCertificate(const std::vector<uint8_t>& crt, bool local = true) noexcept;
std::string pinCertificate(crypto::Certificate&& crt, bool local = true);
std::string pinCertificate(std::shared_ptr<crypto::Certificate> crt, bool local = true);
std::vector<std::string> pinCertificate(const std::vector<uint8_t>& crt, bool local = true) noexcept;
std::vector<std::string> pinCertificate(crypto::Certificate&& crt, bool local = true);
std::vector<std::string> pinCertificate(std::shared_ptr<crypto::Certificate> crt, bool local = true);
bool unpinCertificate(const std::string&);
void pinCertificatePath(const std::string& path);
......
This diff is collapsed.
......@@ -118,6 +118,7 @@ public:
ISSUER_DN ,
NEXT_EXPECTED_UPDATE_DATE ,
OUTGOING_SERVER , /** The hostname/outgoing server used for this certificate */
IS_CA ,
COUNT__
};
......@@ -167,7 +168,9 @@ public:
* @param privatekey An optional private key file path
*/
TlsValidator(const std::string& certificate,
const std::string& privatekey = "");
const std::string& privatekey = "", const std::string& caList = "");
TlsValidator(const std::vector<std::vector<uint8_t>>& certificate_chain_raw);
TlsValidator(const std::vector<uint8_t>& certificate_raw);
......@@ -220,6 +223,7 @@ public:
CheckResult getPublicKeyId();
CheckResult getIssuerDN();
CheckResult outgoingServer();
CheckResult isCA();
void setCaTlsValidator(const TlsValidator& validator);
......@@ -257,11 +261,14 @@ private:
std::string certificatePath_;
std::string privateKeyPath_;
std::string caListPath_ {};
std::vector<uint8_t> certificateContent_;
std::vector<uint8_t> privateKeyContent_;
std::shared_ptr<dht::crypto::Certificate> x509crt_;
bool certificateFileFound_ {false};
bool certificateFound_;
bool privateKeyFound_ {false};
TlsValidator* caCert_ {nullptr};
......
......@@ -59,6 +59,7 @@
#include "logger.h"
#include "manager.h"
#include "client/ring_signal.h"
#include "dring/account_const.h"
#ifdef RING_VIDEO
#include "libav_utils.h"
......@@ -72,16 +73,12 @@
#include <unistd.h>
#include <algorithm>
#include <array>
#include <memory>
#include <sstream>
#include <cstdlib>
#include "upnp/upnp_control.h"
#include "ip_utils.h"
#ifdef _WIN32
#include <lmcons.h>
#else
......
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