| /* |
| * Copyright (C) 2004-2023 Savoir-faire Linux Inc. |
| * |
| * 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, see <https://www.gnu.org/licenses/>. |
| */ |
| #pragma once |
| |
| #include <opendht/crypto.h> |
| |
| #include <string> |
| #include <vector> |
| #include <map> |
| #include <set> |
| #include <future> |
| #include <mutex> |
| #include <filesystem> |
| |
| namespace crypto = ::dht::crypto; |
| |
| namespace dht { |
| namespace log { |
| struct Logger; |
| } |
| } |
| |
| namespace dhtnet { |
| |
| using Logger = dht::log::Logger; |
| namespace tls { |
| |
| enum class TrustStatus { UNTRUSTED = 0, TRUSTED }; |
| TrustStatus trustStatusFromStr(const char* str); |
| const char* statusToStr(TrustStatus s); |
| |
| /** |
| * Global certificate store. |
| * Stores system root CAs and any other encountred certificate |
| */ |
| class CertificateStore |
| { |
| public: |
| explicit CertificateStore(const std::filesystem::path& path, std::shared_ptr<Logger> logger); |
| |
| std::vector<std::string> getPinnedCertificates() const; |
| /** |
| * Return certificate (with full chain) |
| */ |
| std::shared_ptr<crypto::Certificate> getCertificate(const std::string& cert_id); |
| std::shared_ptr<crypto::Certificate> getCertificateLegacy(const std::string& dataDir, const std::string& cert_id); |
| |
| std::shared_ptr<crypto::Certificate> findCertificateByName( |
| const std::string& name, crypto::NameType type = crypto::NameType::UNKNOWN) const; |
| std::shared_ptr<crypto::Certificate> findCertificateByUID(const std::string& uid) const; |
| std::shared_ptr<crypto::Certificate> findIssuer( |
| const std::shared_ptr<crypto::Certificate>& crt) const; |
| |
| 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(const std::shared_ptr<crypto::Certificate>& crt, |
| bool local = true); |
| bool unpinCertificate(const std::string&); |
| |
| void pinCertificatePath(const std::string& path, |
| std::function<void(const std::vector<std::string>&)> cb = {}); |
| unsigned unpinCertificatePath(const std::string&); |
| |
| bool setTrustedCertificate(const std::string& id, TrustStatus status); |
| std::vector<gnutls_x509_crt_t> getTrustedCertificates() const; |
| |
| void pinRevocationList(const std::string& id, |
| const std::shared_ptr<dht::crypto::RevocationList>& crl); |
| void pinRevocationList(const std::string& id, dht::crypto::RevocationList&& crl) |
| { |
| pinRevocationList(id, |
| std::make_shared<dht::crypto::RevocationList>( |
| std::forward<dht::crypto::RevocationList>(crl))); |
| } |
| void pinOcspResponse(const dht::crypto::Certificate& cert); |
| |
| void loadRevocations(crypto::Certificate& crt) const; |
| |
| const std::shared_ptr<Logger>& logger() const { |
| return logger_; |
| } |
| |
| private: |
| //NON_COPYABLE(CertificateStore); |
| |
| |
| unsigned loadLocalCertificates(); |
| void pinRevocationList(const std::string& id, const dht::crypto::RevocationList& crl); |
| std::shared_ptr<Logger> logger_; |
| |
| const std::filesystem::path certPath_; |
| const std::filesystem::path crlPath_; |
| const std::filesystem::path ocspPath_; |
| |
| mutable std::mutex lock_; |
| std::map<std::string, std::shared_ptr<crypto::Certificate>> certs_; |
| std::map<std::string, std::vector<std::weak_ptr<crypto::Certificate>>> paths_; |
| |
| // globally trusted certificates (root CAs) |
| std::vector<std::shared_ptr<crypto::Certificate>> trustedCerts_; |
| }; |
| |
| /** |
| * Keeps track of the allowed and trust status of certificates |
| * Trusted is the status of top certificates we trust to build our |
| * certificate chain: root CAs and other configured CAs. |
| * |
| * Allowed is the status of certificates we accept for incoming |
| * connections. |
| */ |
| class TrustStore |
| { |
| public: |
| explicit TrustStore(CertificateStore& certStore) |
| : certStore_(certStore) |
| {} |
| |
| enum class PermissionStatus { UNDEFINED = 0, ALLOWED, BANNED }; |
| |
| static PermissionStatus statusFromStr(const char* str); |
| static const char* statusToStr(PermissionStatus s); |
| |
| bool addRevocationList(dht::crypto::RevocationList&& crl); |
| |
| bool setCertificateStatus(const std::string& cert_id, const PermissionStatus status); |
| bool setCertificateStatus(const std::shared_ptr<crypto::Certificate>& cert, |
| PermissionStatus status, |
| bool local = true); |
| |
| PermissionStatus getCertificateStatus(const std::string& cert_id) const; |
| |
| std::vector<std::string> getCertificatesByStatus(PermissionStatus status) const; |
| |
| /** |
| * Check that the certificate is allowed (valid and permited) for contact. |
| * Valid means the certificate chain matches with our CA list, |
| * has valid signatures, expiration dates etc. |
| * Permited means at least one of the certificate in the chain is |
| * ALLOWED (if allowPublic is false), and none is BANNED. |
| * |
| * @param crt the end certificate of the chain to check |
| * @param allowPublic if false, requires at least one ALLOWED certificate. |
| * (not required otherwise). In any case a BANNED |
| * certificate means permission refusal. |
| * @return true if the certificate is valid and permitted. |
| */ |
| bool isAllowed(const crypto::Certificate& crt, bool allowPublic = false); |
| |
| private: |
| TrustStore(const TrustStore& o) = delete; |
| TrustStore& operator=(const TrustStore& o) = delete; |
| TrustStore(TrustStore&& o) = delete; |
| TrustStore& operator=(TrustStore&& o) = delete; |
| |
| void updateKnownCerts(); |
| bool setCertificateStatus(std::shared_ptr<crypto::Certificate> cert, |
| const std::string& cert_id, |
| const TrustStore::PermissionStatus status, |
| bool local); |
| void setStoreCertStatus(const crypto::Certificate& crt, bool status); |
| void rebuildTrust(); |
| |
| struct Status |
| { |
| bool allowed; |
| }; |
| |
| // unknown certificates with known status |
| mutable std::recursive_mutex mutex_; |
| std::map<std::string, Status> unknownCertStatus_; |
| std::map<std::string, std::pair<std::shared_ptr<crypto::Certificate>, Status>> certStatus_; |
| dht::crypto::TrustList allowed_; |
| CertificateStore& certStore_; |
| }; |
| |
| } // namespace tls |
| } // namespace dhtnet |