CommunicationSecrets.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 #include "squid.h"
10 #include "base/CharacterSet.h"
11 #include "base/IoManip.h"
13 #include "security/Session.h"
14 
15 #include <ostream>
16 
17 // TODO: Support SSL_CTX_set_keylog_callback() available since OpenSSL v1.1.1.
18 
20 {
21 #if USE_OPENSSL
22  getClientRandom(sconn);
23 
24  if (const auto session = SSL_get_session(&sconn)) {
25  getMasterKey(*session);
26  getSessionId(*session);
27  }
28 #else
29  // Secret extraction is not supported in builds using other TLS libraries.
30  // Secret extraction is impractical in builds without TLS libraries.
31  (void)sconn;
32 #endif
33 }
34 
35 bool
37 {
38  return !id.isEmpty() && !random.isEmpty() && !key.isEmpty();
39 }
40 
41 bool
43 {
44  auto sawChange = false;
45 
46  if (id != news.id && !news.id.isEmpty()) {
47  id = news.id;
48  sawChange = true;
49  }
50 
51  if (random != news.random && !news.random.isEmpty()) {
52  random = news.random;
53  sawChange = true;
54  }
55 
56  if (key != news.key && !news.key.isEmpty()) {
57  key = news.key;
58  sawChange = true;
59  }
60 
61  return sawChange;
62 }
63 
65 static void
66 PrintSecret(std::ostream &os, const SBuf &secret)
67 {
68  if (!secret.isEmpty())
69  PrintHex(os, secret.rawContent(), secret.length());
70  else
71  os << '-';
72 }
73 
74 void
75 Security::CommunicationSecrets::record(std::ostream &os) const {
76  // Print SSLKEYLOGFILE blobs that contain at least one known secret.
77  // See Wireshark tls_keylog_process_lines() source code for format details.
78 
79  // RSA Session-ID:... Master-Key:...
80  if (id.length() || key.length()) {
81  os << "RSA";
82  PrintSecret(os << " Session-ID:", id);
83  PrintSecret(os << " Master-Key:", key);
84  os << "\n";
85  }
86 
87  // CLIENT_RANDOM ... ...
88  if (random.length() || key.length()) {
89  os << "CLIENT_RANDOM ";
90  PrintSecret(os, random);
91  os << ' ';
92  // we may have already printed the key on a separate Master-Key: line above,
93  // but the CLIENT_RANDOM line format includes the same key info
94  PrintSecret(os, key);
95  os << "\n";
96  }
97 }
98 
99 #if USE_OPENSSL
100 static void
105 {
106  static const auto NulChar = CharacterSet("NUL").add('\0');
107  if (secret.findFirstNotOf(NulChar) == SBuf::npos) // all zeros
108  secret.clear();
109 }
110 
111 void
113 {
114  random.clear();
115  const auto expectedLength = SSL_get_client_random(&sconn, nullptr, 0);
116  if (!expectedLength)
117  return;
118 
119  // no auto due to reinterpret_casting of the result below
120  char * const space = random.rawAppendStart(expectedLength);
121  const auto actualLength = SSL_get_client_random(&sconn,
122  reinterpret_cast<unsigned char*>(space), expectedLength);
123  random.rawAppendFinish(space, actualLength);
124 
125  IgnorePlaceholder(random);
126 }
127 
128 void
130 {
131  id.clear();
132  unsigned int idLength = 0;
133  // no auto due to reinterpret_casting of the result below
134  const unsigned char * const idStart = SSL_SESSION_get_id(&session, &idLength);
135  if (idStart && idLength)
136  id.assign(reinterpret_cast<const char *>(idStart), idLength);
137 
138  IgnorePlaceholder(id);
139 }
140 
141 void
143 {
144  key.clear();
145  const auto expectedLength = SSL_SESSION_get_master_key(&session, nullptr, 0);
146  if (!expectedLength)
147  return;
148 
149  // no auto due to reinterpret_casting of the result below
150  char * const space = key.rawAppendStart(expectedLength);
151  const auto actualLength = SSL_SESSION_get_master_key(&session,
152  reinterpret_cast<unsigned char*>(space), expectedLength);
153  key.rawAppendFinish(space, actualLength);
154 
155  IgnorePlaceholder(key);
156 }
157 #endif /* USE_OPENSSL */
158 
bool gotAll() const
whether we know all the secrets that could be extracted
void getSessionId(const Session &session)
void record(std::ostream &) const
logs all known secrets using a (multiline) SSLKEYLOGFILE format
static void PrintSecret(std::ostream &os, const SBuf &secret)
writes the given secret (in hex) or, if there is no secret, a placeholder
bool isEmpty() const
Definition: SBuf.h:435
Definition: SBuf.h:93
void getClientRandom(const Connection &sconn)
bool learnNew(const CommunicationSecrets &news)
static void IgnorePlaceholder(SBuf &secret)
CharacterSet & add(const unsigned char c)
add a given character to the character set
Definition: CharacterSet.cc:47
void clear()
Definition: SBuf.cc:175
SBuf random
CLIENT_RANDOM from the TLS connection.
SBuf key
TLS session (pre-)master key.
const char * rawContent() const
Definition: SBuf.cc:509
void PrintHex(std::ostream &os, const char *const data, const size_t n)
Prints the first n data bytes using hex notation. Does nothing if n is 0.
Definition: IoManip.cc:16
size_t SSL_SESSION_get_master_key(const SSL_SESSION *session, unsigned char *outStart, size_t outSizeMax)
Definition: openssl.h:178
SSL Connection
Definition: Session.h:49
size_type length() const
Returns the number of bytes stored in SBuf.
Definition: SBuf.h:419
static const size_type npos
Definition: SBuf.h:100
size_type findFirstNotOf(const CharacterSet &set, size_type startPos=0) const
Definition: SBuf.cc:746
void getMasterKey(const Session &session)
const unsigned char * SSL_SESSION_get_id(const SSL_SESSION *s, unsigned int *len)
Definition: openssl.h:147
size_t SSL_get_client_random(const SSL *ssl, unsigned char *outStart, size_t outSizeMax)
Definition: openssl.h:157
optimized set of C chars, with quick membership test and merge support
Definition: CharacterSet.h:17
SSL_SESSION Session
Definition: Session.h:51

 

Introduction

Documentation

Support

Miscellaneous