LCOV - code coverage report
Current view: top level - common - monero_c_tls.h (source / functions) Hit Total Coverage
Test: monero-c coverage @ 3fdc3a1 Lines: 21 22 95.5 %
Date: 2026-10-18 16:42:22 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /**
       2             :  * Copyright (c) Libmonero
       3             :  *
       4             :  * Permission is hereby granted, free of charge, to any person obtaining a copy
       5             :  * of this software and associated documentation files (the "Software"), to deal
       6             :  * in the Software without restriction, including without limitation the rights
       7             :  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8             :  * copies of the Software, and to permit persons to whom the Software is
       9             :  * furnished to do so, subject to the following conditions:
      10             :  *
      11             :  * The above copyright notice and this permission notice shall be included in all
      12             :  * copies or substantial portions of the Software.
      13             :  *
      14             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17             :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19             :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      20             :  * SOFTWARE.
      21             :  */
      22             : 
      23             : #ifndef MONERO_C_TLS_H
      24             : #define MONERO_C_TLS_H
      25             : 
      26             : #include <cctype>
      27             : #include <functional>
      28             : #include <string>
      29             : 
      30             : // where OpenSSL finds the CA certificates of the system. Not part of the public ABI, and it needs no OpenSSL header, so a test
      31             : // can run it on a fake file system
      32             : namespace monero_c {
      33             : 
      34             : // what to export as SSL_CERT_FILE and SSL_CERT_DIR. An empty string leaves the variable as it is
      35             : struct ca_paths {
      36             :   std::string file;
      37             :   std::string dir;
      38             : };
      39             : 
      40             : // the bundles of the CA certificates of the common systems, in the order that they are tried: Debian and Ubuntu, Fedora and RHEL,
      41             : // openSUSE, then Alpine and macOS
      42             : static const char* const CA_FILES[] = {
      43             :   "/etc/ssl/certs/ca-certificates.crt",
      44             :   "/etc/pki/tls/certs/ca-bundle.crt",
      45             :   "/etc/ssl/ca-bundle.pem",
      46             :   "/etc/ssl/cert.pem",
      47             : };
      48             : 
      49             : // the directories of certificates by hashed name (5ad8a5d6.0), the one of Android included
      50             : static const char* const CA_DIRS[] = {
      51             :   "/etc/ssl/certs",
      52             :   "/etc/pki/tls/certs",
      53             :   "/system/etc/security/cacerts",
      54             : };
      55             : 
      56             : // true if the name is a certificate by its hashed name, which is 8 hex digits, a dot and a number, such as 5ad8a5d6.0
      57          52 : inline bool is_hashed_certificate_name(const std::string& name) {
      58          52 :   if (name.size() < 10 || name[8] != '.') return false;
      59         170 :   for (size_t i = 0; i < 8; i++) {
      60         152 :     if (!std::isxdigit(static_cast<unsigned char>(name[i]))) return false;
      61             :   }
      62          36 :   for (size_t i = 9; i < name.size(); i++) {
      63          20 :     if (!std::isdigit(static_cast<unsigned char>(name[i]))) return false;
      64             :   }
      65          16 :   return true;
      66             : }
      67             : 
      68             : // chooses what to export so that OpenSSL finds the CA certificates. The OpenSSL in the library has the directory of the machine
      69             : // that built it in its code, and it looks for the certificates there, so a connection with a certificate of a CA fails where that
      70             : // directory isn't, such as a Mac without Homebrew. Nothing is chosen if the caller set SSL_CERT_FILE or SSL_CERT_DIR, or if
      71             : // OpenSSL finds the certificates by itself: its default file is there, or its default directory has certificates by hashed name.
      72             : // A directory that exists proves nothing, since the one of Homebrew exists and is empty. is_file tells that a path is a file with
      73             : // content, and has_certificates that a path is a directory with certificates by hashed name
      74          24 : inline ca_paths find_ca_paths(const char* env_file, const char* env_dir, const std::string& default_file, const std::string& default_dir,
      75             :                               const std::function<bool(const std::string&)>& is_file, const std::function<bool(const std::string&)>& has_certificates) {
      76          24 :   ca_paths paths;
      77          24 :   if ((env_file != nullptr && env_file[0] != '\0') || (env_dir != nullptr && env_dir[0] != '\0')) return paths;
      78          22 :   if (!default_file.empty() && is_file(default_file)) return paths;
      79          21 :   if (!default_dir.empty() && has_certificates(default_dir)) return paths;
      80          24 :   for (const char* file : CA_FILES) {
      81          22 :     if (is_file(file)) {
      82           5 :       paths.file = file;
      83           5 :       break;
      84             :     }
      85             :   }
      86          24 :   for (const char* dir : CA_DIRS) {
      87          19 :     if (has_certificates(dir)) {
      88           2 :       paths.dir = dir;
      89           2 :       break;
      90             :     }
      91             :   }
      92           7 :   return paths;
      93           0 : }
      94             : 
      95             : } // namespace monero_c
      96             : 
      97             : #endif // MONERO_C_TLS_H

Generated by: LCOV version 1.16