LCOV - code coverage report
Current view: top level - asio/ssl - certificate_manager.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 86.3 % 51 44
Test Date: 2026-02-20 15:38:22 Functions: 100.0 % 8 8

            Line data    Source code
       1              : #ifndef THINGER_ASIO_SSL_CERTIFICATE_MANAGER_HPP
       2              : #define THINGER_ASIO_SSL_CERTIFICATE_MANAGER_HPP
       3              : 
       4              : #include <memory>
       5              : #include <unordered_map>
       6              : #include <string>
       7              : #include <set>
       8              : #include <regex>
       9              : #include <mutex>
      10              : #include <optional>
      11              : #include <boost/asio/ssl/context.hpp>
      12              : 
      13              : namespace thinger::asio {
      14              : 
      15              : // Forward declaration
      16              : template<typename T>
      17              : class regex_map;
      18              : 
      19              : class certificate_manager {
      20              : private:
      21              :     // Private constructor for singleton
      22              :     certificate_manager();
      23              :     
      24              :     // Delete copy and move operations
      25              :     certificate_manager(const certificate_manager&) = delete;
      26              :     certificate_manager& operator=(const certificate_manager&) = delete;
      27              :     certificate_manager(certificate_manager&&) = delete;
      28              :     certificate_manager& operator=(certificate_manager&&) = delete;
      29              :     
      30              :     // Create base SSL context with common settings
      31              :     std::shared_ptr<boost::asio::ssl::context> create_base_ssl_context();
      32              :     
      33              :     // Create SSL context from certificate and key strings
      34              :     std::shared_ptr<boost::asio::ssl::context> create_ssl_context(
      35              :         const std::string& cert_chain,
      36              :         const std::string& private_key);
      37              :     
      38              :     // Certificate storage with regex support for wildcards
      39              :     std::unique_ptr<regex_map<std::shared_ptr<boost::asio::ssl::context>>> ssl_contexts_;
      40              :     
      41              :     // Default certificate context
      42              :     std::shared_ptr<boost::asio::ssl::context> default_context_;
      43              :     
      44              :     // Default hostname
      45              :     std::string default_host_;
      46              :     
      47              :     // SSL/TLS configuration
      48              :     std::string server_ciphers_;
      49              :     bool prefer_server_ciphers_ = false;
      50              :     bool enable_legacy_protocols_ = false;
      51              :     
      52              :     // Thread safety
      53              :     mutable std::mutex mutex_;
      54              :     
      55              :     // Generate self-signed certificate for development
      56              :     void generate_self_signed_certificate();
      57              :     
      58              : public:
      59              :     // Singleton instance
      60              :     static certificate_manager& instance();
      61              :     
      62              :     // Certificate management
      63              :     bool set_certificate(const std::string& hostname, 
      64              :                         const std::string& certificate, 
      65              :                         const std::string& private_key);
      66              :     
      67              :     bool set_certificate(const std::string& hostname,
      68              :                         std::shared_ptr<boost::asio::ssl::context> ssl_context);
      69              :     
      70              :     std::shared_ptr<boost::asio::ssl::context> get_certificate(const std::string& hostname) const;
      71              :     
      72              :     bool has_certificate(const std::string& hostname) const;
      73              :     
      74              :     bool remove_certificate(const std::string& hostname);
      75              :     
      76              :     // Default certificate management
      77              :     void set_default_certificate(std::shared_ptr<boost::asio::ssl::context> ssl_context);
      78              :     void set_default_certificate(const std::string& certificate, const std::string& private_key);
      79              :     std::shared_ptr<boost::asio::ssl::context> get_default_certificate() const;
      80              :     void set_default_host(const std::string& host);
      81              :     const std::string& get_default_host() const;
      82              :     
      83              :     // Get all registered hostnames
      84              :     std::set<std::string> get_registered_hosts() const;
      85              :     
      86              :     // SSL/TLS configuration
      87              :     void set_server_ciphers(const std::string& ciphers, bool prefer_server_ciphers);
      88              :     void enable_legacy_protocols(bool enable);
      89              :     
      90              :     // SNI callback for SSL handshake
      91              :     static int sni_callback(SSL* ssl, int* al, void* arg);
      92              : };
      93              : 
      94              : // Simple regex map implementation for certificate hostname matching
      95              : template<typename T>
      96              : class regex_map {
      97              : private:
      98              :     struct regex_entry {
      99              :         std::string key;
     100              :         T value;
     101              :         std::regex pattern;
     102              :         
     103          369 :         regex_entry(const std::string& k, const T& v, const std::regex& p) 
     104          369 :             : key(k), value(v), pattern(p) {}
     105              :     };
     106              :     
     107              :     std::vector<regex_entry> regex_items_;
     108              :     std::unordered_map<std::string, T> non_regex_items_;
     109              :     mutable std::mutex mutex_;
     110              :     
     111              : public:
     112          369 :     void set(const std::string& key, const T& value, const std::string& original = "") {
     113          369 :         std::lock_guard<std::mutex> lock(mutex_);
     114              :         
     115              :         // Store the original key
     116          369 :         std::string store_key = original.empty() ? key : original;
     117              :         
     118              :         // Check if key contains regex patterns
     119          369 :         bool has_regex_chars = key.find_first_of("^$.*+?{}[]|()\\") != std::string::npos;
     120              :         
     121          369 :         if (!has_regex_chars) {
     122              :             // Store as non-regex item
     123            0 :             non_regex_items_[store_key] = value;
     124              :         } else {
     125              :             // Remove any existing regex entry with the same original key
     126          738 :             regex_items_.erase(
     127          369 :                 std::remove_if(regex_items_.begin(), regex_items_.end(),
     128        14883 :                     [&store_key](const regex_entry& e) { return e.key == store_key; }),
     129          369 :                 regex_items_.end()
     130              :             );
     131              :             
     132              :             // Treat as regex pattern
     133              :             try {
     134          369 :                 regex_items_.emplace_back(store_key, value, std::regex(key));
     135            0 :             } catch (const std::regex_error& e) {
     136              :                 // If regex compilation fails, skip this entry
     137            0 :                 return;
     138              :             }
     139              :         }
     140          369 :     }
     141              :     
     142          196 :     std::optional<T> get(const std::string& key) const {
     143          196 :         std::lock_guard<std::mutex> lock(mutex_);
     144              :         
     145              :         // First try exact match in non-regex items
     146          196 :         auto it = non_regex_items_.find(key);
     147          196 :         if (it != non_regex_items_.end()) {
     148            0 :             return it->second;
     149              :         }
     150              :         
     151              :         // Check if the key itself is a stored regex pattern (like *.example.com)
     152          337 :         for (const auto& item : regex_items_) {
     153          177 :             if (item.key == key) {
     154           36 :                 return item.value;
     155              :             }
     156              :         }
     157              :         
     158              :         // Then try regex matches
     159          214 :         for (const auto& item : regex_items_) {
     160          108 :             if (std::regex_match(key, item.pattern)) {
     161           54 :                 return item.value;
     162              :             }
     163              :         }
     164              :         
     165          106 :         return std::nullopt;
     166          196 :     }
     167              :     
     168           33 :     bool has(const std::string& key) const {
     169           33 :         return get(key).has_value();
     170              :     }
     171              :     
     172          363 :     void erase(const std::string& key) {
     173          363 :         std::lock_guard<std::mutex> lock(mutex_);
     174              :         
     175              :         // Try to erase from non-regex items first
     176          363 :         auto it = non_regex_items_.find(key);
     177          363 :         if (it != non_regex_items_.end()) {
     178            0 :             non_regex_items_.erase(it);
     179            0 :             return;
     180              :         }
     181              :         
     182              :         // Then try regex items
     183          726 :         regex_items_.erase(
     184          363 :             std::remove_if(regex_items_.begin(), regex_items_.end(),
     185        15240 :                 [&key](const regex_entry& e) { return e.key == key; }),
     186          363 :             regex_items_.end()
     187              :         );
     188          363 :     }
     189              :     
     190          141 :     std::set<std::string> keys() const {
     191          141 :         std::lock_guard<std::mutex> lock(mutex_);
     192          141 :         std::set<std::string> result;
     193              :         
     194              :         // Add non-regex keys
     195          141 :         for (const auto& pair : non_regex_items_) {
     196            0 :             result.insert(pair.first);
     197              :         }
     198              :         
     199              :         // Add regex keys
     200          807 :         for (const auto& entry : regex_items_) {
     201          666 :             result.insert(entry.key);
     202              :         }
     203              :         
     204          282 :         return result;
     205          141 :     }
     206              : };
     207              : 
     208              : } // namespace thinger::asio
     209              : 
     210              : #endif // THINGER_ASIO_SSL_CERTIFICATE_MANAGER_HPP
        

Generated by: LCOV version 2.0-1