• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/core/tsi/ssl/key_logging/ssl_key_logging.h"
16 
17 #include <grpc/support/port_platform.h>
18 
19 #include <map>
20 
21 #include "absl/log/check.h"
22 #include "absl/log/log.h"
23 #include "src/core/lib/iomgr/error.h"
24 #include "src/core/lib/slice/slice_internal.h"
25 #include "src/core/util/crash.h"
26 #include "src/core/util/sync.h"
27 
28 using TlsSessionKeyLogger = tsi::TlsSessionKeyLoggerCache::TlsSessionKeyLogger;
29 
30 namespace tsi {
31 
32 namespace {
33 
34 gpr_once g_cache_mutex_init = GPR_ONCE_INIT;
35 grpc_core::Mutex* g_tls_session_key_log_cache_mu = nullptr;
36 // A pointer to a global singleton instance.
37 TlsSessionKeyLoggerCache* g_cache_instance
38     ABSL_GUARDED_BY(g_tls_session_key_log_cache_mu) = nullptr;
39 
do_cache_mutex_init(void)40 void do_cache_mutex_init(void) {
41   g_tls_session_key_log_cache_mu = new grpc_core::Mutex();
42 }
43 
44 }  // namespace
45 
TlsSessionKeyLogger(std::string tls_session_key_log_file_path,grpc_core::RefCountedPtr<TlsSessionKeyLoggerCache> cache)46 TlsSessionKeyLoggerCache::TlsSessionKeyLogger::TlsSessionKeyLogger(
47     std::string tls_session_key_log_file_path,
48     grpc_core::RefCountedPtr<TlsSessionKeyLoggerCache> cache)
49     : tls_session_key_log_file_path_(std::move(tls_session_key_log_file_path)),
50       cache_(std::move(cache)) {
51   CHECK(!tls_session_key_log_file_path_.empty());
52   CHECK(cache_ != nullptr);
53   fd_ = fopen(tls_session_key_log_file_path_.c_str(), "a");
54   if (fd_ == nullptr) {
55     grpc_error_handle error = GRPC_OS_ERROR(errno, "fopen");
56     LOG(ERROR) << "Ignoring TLS Key logging. ERROR Opening TLS Keylog file: "
57                << grpc_core::StatusToString(error);
58   }
59   cache_->tls_session_key_logger_map_.emplace(tls_session_key_log_file_path_,
60                                               this);
61 };
62 
~TlsSessionKeyLogger()63 TlsSessionKeyLoggerCache::TlsSessionKeyLogger::~TlsSessionKeyLogger() {
64   {
65     grpc_core::MutexLock lock(&lock_);
66     if (fd_ != nullptr) fclose(fd_);
67   }
68   {
69     grpc_core::MutexLock lock(g_tls_session_key_log_cache_mu);
70     auto it = cache_->tls_session_key_logger_map_.find(
71         tls_session_key_log_file_path_);
72     if (it != cache_->tls_session_key_logger_map_.end() && it->second == this) {
73       cache_->tls_session_key_logger_map_.erase(it);
74     }
75   }
76 }
77 
LogSessionKeys(SSL_CTX *,const std::string & session_keys_info)78 void TlsSessionKeyLoggerCache::TlsSessionKeyLogger::LogSessionKeys(
79     SSL_CTX* /* ssl_context */, const std::string& session_keys_info) {
80   grpc_core::MutexLock lock(&lock_);
81   if (fd_ == nullptr || session_keys_info.empty()) return;
82   // Append to key log file under lock
83   bool err =
84       fwrite((session_keys_info + "\n").c_str(), sizeof(char),
85              session_keys_info.length() + 1, fd_) < session_keys_info.length();
86 
87   if (err) {
88     grpc_error_handle error = GRPC_OS_ERROR(errno, "fwrite");
89     LOG(ERROR) << "Error Appending to TLS session key log file: "
90                << grpc_core::StatusToString(error);
91     fclose(fd_);
92     fd_ = nullptr;  // disable future attempts to write to this file
93   } else {
94     fflush(fd_);
95   }
96 }
97 
TlsSessionKeyLoggerCache()98 TlsSessionKeyLoggerCache::TlsSessionKeyLoggerCache()
99     ABSL_EXCLUSIVE_LOCKS_REQUIRED(g_tls_session_key_log_cache_mu) {
100   g_cache_instance = this;
101 }
102 
~TlsSessionKeyLoggerCache()103 TlsSessionKeyLoggerCache::~TlsSessionKeyLoggerCache() {
104   grpc_core::MutexLock lock(g_tls_session_key_log_cache_mu);
105   g_cache_instance = nullptr;
106 }
107 
Get(std::string tls_session_key_log_file_path)108 grpc_core::RefCountedPtr<TlsSessionKeyLogger> TlsSessionKeyLoggerCache::Get(
109     std::string tls_session_key_log_file_path) {
110   gpr_once_init(&g_cache_mutex_init, do_cache_mutex_init);
111   DCHECK_NE(g_tls_session_key_log_cache_mu, nullptr);
112   if (tls_session_key_log_file_path.empty()) {
113     return nullptr;
114   }
115   {
116     grpc_core::MutexLock lock(g_tls_session_key_log_cache_mu);
117     grpc_core::RefCountedPtr<TlsSessionKeyLoggerCache> cache;
118     if (g_cache_instance == nullptr) {
119       // This will automatically set g_cache_instance.
120       // Not using MakeRefCounted because to the thread safety analysis, which
121       // cannot see through calls, it would look like MakeRefCounted was
122       // calling TlsSessionKeyLoggerCache without holding a lock on
123       // g_tls_session_key_log_cache_mu.
124       cache.reset(new TlsSessionKeyLoggerCache());
125     } else {
126       cache = g_cache_instance->Ref();
127     }
128     // Check cache for entry.
129     auto it =
130         cache->tls_session_key_logger_map_.find(tls_session_key_log_file_path);
131     if (it != cache->tls_session_key_logger_map_.end()) {
132       // Avoid a race condition if the destructor of the tls key logger
133       // of interest is currently executing.
134       auto key_logger = it->second->RefIfNonZero();
135       if (key_logger != nullptr) return key_logger;
136     }
137     // Not found in cache, so create new entry.
138     // This will automatically add itself to tls_session_key_logger_map_.
139     return grpc_core::MakeRefCounted<TlsSessionKeyLogger>(
140         std::move(tls_session_key_log_file_path), std::move(cache));
141   }
142 }
143 
144 };  // namespace tsi
145