1
#include "source/common/tls/connection_info_impl_base.h"
2

            
3
#include <openssl/stack.h>
4

            
5
#include "source/common/common/hex.h"
6
#include "source/common/http/utility.h"
7
#include "source/common/tls/cert_validator/san_matcher.h"
8

            
9
#include "absl/strings/str_replace.h"
10
#include "openssl/err.h"
11
#include "openssl/safestack.h"
12
#include "openssl/x509v3.h"
13
#include "utility.h"
14

            
15
namespace Envoy {
16
namespace Extensions {
17
namespace TransportSockets {
18
namespace Tls {
19

            
20
namespace {
21
// There must be an version of this function for each type possible in variant `CachedValue`.
22
194
bool shouldRecalculateCachedEntry(const std::string& str) { return str.empty(); }
23
330
bool shouldRecalculateCachedEntry(const std::vector<std::string>& vec) { return vec.empty(); }
24
3
bool shouldRecalculateCachedEntry(const Ssl::ParsedX509NamePtr& ptr) { return ptr == nullptr; }
25
3
bool shouldRecalculateCachedEntry(const bssl::UniquePtr<GENERAL_NAMES>& ptr) {
26
3
  return ptr == nullptr;
27
3
}
28
} // namespace
29

            
30
template <typename ValueType>
31
const ValueType&
32
ConnectionInfoImplBase::getCachedValueOrCreate(CachedValueTag tag,
33
1645
                                               std::function<ValueType(SSL* ssl)> create) const {
34
1645
  auto it = cached_values_.find(tag);
35
1645
  if (it != cached_values_.end()) {
36
530
    const ValueType* val = absl::get_if<ValueType>(&it->second);
37
530
    ASSERT(val != nullptr, "Incorrect type in variant");
38
530
    if (val != nullptr) {
39

            
40
      // Some values are retrieved too early, for example if properties of a peer certificate are
41
      // retrieved before the handshake is complete, an empty value is cached. The value must be
42
      // in the cache, so that we can return a valid reference, but in those cases if another caller
43
      // later retrieves the same value, we must recalculate the value.
44
530
      if (shouldRecalculateCachedEntry(*val)) {
45
381
        it->second = create(ssl());
46
381
        val = &absl::get<ValueType>(it->second);
47
381
      }
48

            
49
530
      return *val;
50
530
    }
51
530
  }
52

            
53
1115
  auto [inserted_it, inserted] = cached_values_.emplace(tag, create(ssl()));
54
1115
  return absl::get<ValueType>(inserted_it->second);
55
1645
}
56

            
57
23
bool ConnectionInfoImplBase::peerCertificatePresented() const {
58
23
  const STACK_OF(CRYPTO_BUFFER)* cert(SSL_get0_peer_certificates(ssl()));
59
23
  return cert != nullptr;
60
23
}
61

            
62
51
absl::Span<const std::string> ConnectionInfoImplBase::uriSanLocalCertificate() const {
63
51
  return getCachedValueOrCreate<std::vector<std::string>>(
64
51
      CachedValueTag::UriSanLocalCertificate, [](SSL* ssl) {
65
        // The cert object is not owned.
66
50
        X509* cert = SSL_get_certificate(ssl);
67
50
        if (!cert) {
68
1
          return std::vector<std::string>{};
69
1
        }
70
49
        return Utility::getSubjectAltNames(*cert, GEN_URI);
71
50
      });
72
51
}
73

            
74
49
absl::Span<const std::string> ConnectionInfoImplBase::dnsSansLocalCertificate() const {
75
49
  return getCachedValueOrCreate<std::vector<std::string>>(
76
49
      CachedValueTag::DnsSansLocalCertificate, [](SSL* ssl) {
77
46
        X509* cert = SSL_get_certificate(ssl);
78
46
        if (!cert) {
79
1
          return std::vector<std::string>{};
80
1
        }
81
45
        return Utility::getSubjectAltNames(*cert, GEN_DNS);
82
46
      });
83
49
}
84

            
85
7
absl::Span<const std::string> ConnectionInfoImplBase::ipSansLocalCertificate() const {
86
7
  return getCachedValueOrCreate<std::vector<std::string>>(
87
7
      CachedValueTag::IpSansLocalCertificate, [](SSL* ssl) {
88
4
        X509* cert = SSL_get_certificate(ssl);
89
4
        if (!cert) {
90
1
          return std::vector<std::string>{};
91
1
        }
92
3
        return Utility::getSubjectAltNames(*cert, GEN_IPADD);
93
4
      });
94
7
}
95

            
96
3
absl::Span<const std::string> ConnectionInfoImplBase::emailSansLocalCertificate() const {
97
3
  return getCachedValueOrCreate<std::vector<std::string>>(
98
3
      CachedValueTag::EmailSansLocalCertificate, [](SSL* ssl) {
99
2
        X509* cert = SSL_get_certificate(ssl);
100
2
        if (!cert) {
101
1
          return std::vector<std::string>{};
102
1
        }
103
1
        return Utility::getSubjectAltNames(*cert, GEN_EMAIL);
104
2
      });
105
3
}
106

            
107
3
absl::Span<const std::string> ConnectionInfoImplBase::othernameSansLocalCertificate() const {
108
3
  return getCachedValueOrCreate<std::vector<std::string>>(
109
3
      CachedValueTag::OthernameSansLocalCertificate, [](SSL* ssl) {
110
2
        X509* cert = SSL_get_certificate(ssl);
111
2
        if (!cert) {
112
1
          return std::vector<std::string>{};
113
1
        }
114
1
        return Utility::getSubjectAltNames(*cert, GEN_OTHERNAME);
115
2
      });
116
3
}
117

            
118
54
const std::string& ConnectionInfoImplBase::sha256PeerCertificateDigest() const {
119
54
  return getCachedValueOrCreate<std::string>(
120
54
      CachedValueTag::Sha256PeerCertificateDigest, [](SSL* ssl) {
121
49
        bssl::UniquePtr<X509> cert(SSL_get_peer_certificate(ssl));
122
49
        if (!cert) {
123
8
          return std::string{};
124
8
        }
125

            
126
41
        std::vector<uint8_t> computed_hash(SHA256_DIGEST_LENGTH);
127
41
        unsigned int n;
128
41
        X509_digest(cert.get(), EVP_sha256(), computed_hash.data(), &n);
129
41
        RELEASE_ASSERT(n == computed_hash.size(), "");
130
41
        return Hex::encode(computed_hash);
131
41
      });
132
54
}
133

            
134
2
absl::Span<const std::string> ConnectionInfoImplBase::sha256PeerCertificateChainDigests() const {
135
2
  return getCachedValueOrCreate<std::vector<std::string>>(
136
2
      CachedValueTag::Sha256PeerCertificateChainDigests, [](SSL* ssl) {
137
1
        STACK_OF(X509)* cert_chain = SSL_get_peer_full_cert_chain(ssl);
138
1
        if (cert_chain == nullptr) {
139
          return std::vector<std::string>{};
140
        }
141

            
142
2
        return Utility::mapX509Stack(*cert_chain, [](X509& cert) -> std::string {
143
2
          std::vector<uint8_t> computed_hash(SHA256_DIGEST_LENGTH);
144
2
          unsigned int n;
145
2
          X509_digest(&cert, EVP_sha256(), computed_hash.data(), &n);
146
2
          RELEASE_ASSERT(n == computed_hash.size(), "");
147
2
          return Hex::encode(computed_hash);
148
2
        });
149
1
      });
150
2
}
151

            
152
21
const std::string& ConnectionInfoImplBase::sha1PeerCertificateDigest() const {
153
21
  return getCachedValueOrCreate<std::string>(
154
21
      CachedValueTag::Sha1PeerCertificateDigest, [](SSL* ssl) {
155
16
        bssl::UniquePtr<X509> cert(SSL_get_peer_certificate(ssl));
156
16
        if (!cert) {
157
7
          return std::string{};
158
7
        }
159

            
160
9
        std::vector<uint8_t> computed_hash(SHA_DIGEST_LENGTH);
161
9
        unsigned int n;
162
9
        X509_digest(cert.get(), EVP_sha1(), computed_hash.data(), &n);
163
9
        RELEASE_ASSERT(n == computed_hash.size(), "");
164
9
        return Hex::encode(computed_hash);
165
9
      });
166
21
}
167

            
168
2
absl::Span<const std::string> ConnectionInfoImplBase::sha1PeerCertificateChainDigests() const {
169
2
  return getCachedValueOrCreate<std::vector<std::string>>(
170
2
      CachedValueTag::Sha1PeerCertificateChainDigests, [](SSL* ssl) {
171
1
        STACK_OF(X509)* cert_chain = SSL_get_peer_full_cert_chain(ssl);
172
1
        if (cert_chain == nullptr) {
173
          return std::vector<std::string>{};
174
        }
175

            
176
2
        return Utility::mapX509Stack(*cert_chain, [](X509& cert) -> std::string {
177
2
          std::vector<uint8_t> computed_hash(SHA_DIGEST_LENGTH);
178
2
          unsigned int n;
179
2
          X509_digest(&cert, EVP_sha1(), computed_hash.data(), &n);
180
2
          RELEASE_ASSERT(n == computed_hash.size(), "");
181
2
          return Hex::encode(computed_hash);
182
2
        });
183
1
      });
184
2
}
185

            
186
11
const std::string& ConnectionInfoImplBase::urlEncodedPemEncodedPeerCertificate() const {
187
11
  return getCachedValueOrCreate<std::string>(
188
11
      CachedValueTag::UrlEncodedPemEncodedPeerCertificate, [](SSL* ssl) {
189
9
        bssl::UniquePtr<X509> cert(SSL_get_peer_certificate(ssl));
190
9
        if (!cert) {
191
7
          return std::string{};
192
7
        }
193

            
194
2
        bssl::UniquePtr<BIO> buf(BIO_new(BIO_s_mem()));
195
2
        RELEASE_ASSERT(buf != nullptr, "");
196
2
        RELEASE_ASSERT(PEM_write_bio_X509(buf.get(), cert.get()) == 1, "");
197
2
        const uint8_t* output;
198
2
        size_t length;
199
2
        RELEASE_ASSERT(BIO_mem_contents(buf.get(), &output, &length) == 1, "");
200
2
        absl::string_view pem(reinterpret_cast<const char*>(output), length);
201
2
        return Envoy::Http::Utility::PercentEncoding::urlEncode(pem);
202
2
      });
203
11
}
204

            
205
9
const std::string& ConnectionInfoImplBase::urlEncodedPemEncodedPeerCertificateChain() const {
206
9
  return getCachedValueOrCreate<std::string>(
207
9
      CachedValueTag::UrlEncodedPemEncodedPeerCertificateChain, [](SSL* ssl) {
208
8
        STACK_OF(X509)* cert_chain = SSL_get_peer_full_cert_chain(ssl);
209
8
        if (cert_chain == nullptr) {
210
7
          return std::string{};
211
7
        }
212

            
213
1
        std::string result;
214
3
        for (uint64_t i = 0; i < sk_X509_num(cert_chain); i++) {
215
2
          X509* cert = sk_X509_value(cert_chain, i);
216

            
217
2
          bssl::UniquePtr<BIO> buf(BIO_new(BIO_s_mem()));
218
2
          RELEASE_ASSERT(buf != nullptr, "");
219
2
          RELEASE_ASSERT(PEM_write_bio_X509(buf.get(), cert) == 1, "");
220
2
          const uint8_t* output;
221
2
          size_t length;
222
2
          RELEASE_ASSERT(BIO_mem_contents(buf.get(), &output, &length) == 1, "");
223

            
224
2
          absl::string_view pem(reinterpret_cast<const char*>(output), length);
225
2
          absl::StrAppend(&result, Envoy::Http::Utility::PercentEncoding::urlEncode(pem));
226
2
        }
227
1
        return result;
228
1
      });
229
9
}
230

            
231
61
bool ConnectionInfoImplBase::peerCertificateSanMatches(const Ssl::SanMatcher& matcher) const {
232
61
  const bssl::UniquePtr<GENERAL_NAMES>& sans =
233
61
      getCachedValueOrCreate<bssl::UniquePtr<GENERAL_NAMES>>(
234
61
          CachedValueTag::PeerCertificateSanMatches,
235
61
          [](SSL* ssl) -> bssl::UniquePtr<GENERAL_NAMES> {
236
58
            bssl::UniquePtr<X509> cert(SSL_get_peer_certificate(ssl));
237
58
            if (!cert) {
238
35
              return nullptr;
239
35
            }
240
23
            return bssl::UniquePtr<GENERAL_NAMES>(static_cast<GENERAL_NAMES*>(
241
23
                X509_get_ext_d2i(cert.get(), NID_subject_alt_name, nullptr, nullptr)));
242
58
          });
243

            
244
61
  if (sans != nullptr) {
245
12
    for (const GENERAL_NAME* san : sans.get()) {
246
12
      if (matcher.match(san)) {
247
3
        return true;
248
3
      }
249
12
    }
250
12
  }
251

            
252
58
  return false;
253
61
}
254

            
255
271
absl::Span<const std::string> ConnectionInfoImplBase::uriSanPeerCertificate() const {
256
271
  return getCachedValueOrCreate<std::vector<std::string>>(
257
271
      CachedValueTag::UriSanPeerCertificate, [](SSL* ssl) {
258
247
        bssl::UniquePtr<X509> cert(SSL_get_peer_certificate(ssl));
259
247
        if (!cert) {
260
154
          return std::vector<std::string>{};
261
154
        }
262
93
        return Utility::getSubjectAltNames(*cert, GEN_URI);
263
247
      });
264
271
}
265

            
266
14
absl::Span<const std::string> ConnectionInfoImplBase::dnsSansPeerCertificate() const {
267
14
  return getCachedValueOrCreate<std::vector<std::string>>(
268
14
      CachedValueTag::DnsSansPeerCertificate, [](SSL* ssl) {
269
14
        bssl::UniquePtr<X509> cert(SSL_get_peer_certificate(ssl));
270
14
        if (!cert) {
271
7
          return std::vector<std::string>{};
272
7
        }
273
7
        return Utility::getSubjectAltNames(*cert, GEN_DNS);
274
14
      });
275
14
}
276

            
277
136
absl::Span<const std::string> ConnectionInfoImplBase::ipSansPeerCertificate() const {
278
136
  return getCachedValueOrCreate<std::vector<std::string>>(
279
136
      CachedValueTag::IpSansPeerCertificate, [](SSL* ssl) {
280
135
        bssl::UniquePtr<X509> cert(SSL_get_peer_certificate(ssl));
281
135
        if (!cert) {
282
85
          return std::vector<std::string>{};
283
85
        }
284
50
        return Utility::getSubjectAltNames(*cert, GEN_IPADD);
285
135
      });
286
136
}
287

            
288
135
absl::Span<const std::string> ConnectionInfoImplBase::emailSansPeerCertificate() const {
289
135
  return getCachedValueOrCreate<std::vector<std::string>>(
290
135
      CachedValueTag::EmailSansPeerCertificate, [](SSL* ssl) {
291
134
        bssl::UniquePtr<X509> cert(SSL_get_peer_certificate(ssl));
292
134
        if (!cert) {
293
85
          return std::vector<std::string>{};
294
85
        }
295
49
        return Utility::getSubjectAltNames(*cert, GEN_EMAIL);
296
134
      });
297
135
}
298

            
299
135
absl::Span<const std::string> ConnectionInfoImplBase::othernameSansPeerCertificate() const {
300
135
  return getCachedValueOrCreate<std::vector<std::string>>(
301
135
      CachedValueTag::OthernameSansPeerCertificate, [](SSL* ssl) {
302
134
        bssl::UniquePtr<X509> cert(SSL_get_peer_certificate(ssl));
303
134
        if (!cert) {
304
85
          return std::vector<std::string>{};
305
85
        }
306
49
        return Utility::getSubjectAltNames(*cert, GEN_OTHERNAME);
307
134
      });
308
135
}
309

            
310
9
absl::Span<const std::string> ConnectionInfoImplBase::oidsPeerCertificate() const {
311
9
  return getCachedValueOrCreate<std::vector<std::string>>(
312
9
      CachedValueTag::OidsPeerCertificate, [](SSL* ssl) {
313
8
        bssl::UniquePtr<X509> cert(SSL_get_peer_certificate(ssl));
314
8
        if (!cert) {
315
7
          return std::vector<std::string>{};
316
7
        }
317
1
        return Utility::getCertificateExtensionOids(*cert);
318
8
      });
319
9
}
320

            
321
3
absl::Span<const std::string> ConnectionInfoImplBase::oidsLocalCertificate() const {
322
3
  return getCachedValueOrCreate<std::vector<std::string>>(
323
3
      CachedValueTag::OidsLocalCertificate, [](SSL* ssl) {
324
2
        X509* cert = SSL_get_certificate(ssl);
325
2
        if (!cert) {
326
1
          return std::vector<std::string>{};
327
1
        }
328
1
        return Utility::getCertificateExtensionOids(*cert);
329
2
      });
330
3
}
331

            
332
12
uint16_t ConnectionInfoImplBase::ciphersuiteId() const {
333
12
  const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl());
334
12
  if (cipher == nullptr) {
335
4
    return 0xffff;
336
4
  }
337

            
338
  // From the OpenSSL docs:
339
  //    SSL_CIPHER_get_id returns |cipher|'s id. It may be cast to a |uint16_t| to
340
  //    get the cipher suite value.
341
8
  return static_cast<uint16_t>(SSL_CIPHER_get_id(cipher));
342
12
}
343

            
344
4
std::string ConnectionInfoImplBase::ciphersuiteString() const {
345
4
  const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl());
346
4
  if (cipher == nullptr) {
347
    return {};
348
  }
349

            
350
4
  return SSL_CIPHER_get_name(cipher);
351
4
}
352

            
353
33
const std::string& ConnectionInfoImplBase::tlsVersion() const {
354
33
  return getCachedValueOrCreate<std::string>(
355
33
      CachedValueTag::TlsVersion, [](SSL* ssl) { return std::string(SSL_get_version(ssl)); });
356
33
}
357

            
358
215
const std::string& ConnectionInfoImplBase::alpn() const {
359
215
  return getCachedValueOrCreate<std::string>(CachedValueTag::Alpn, [](SSL* ssl) {
360
195
    const unsigned char* proto;
361
195
    unsigned int proto_len;
362
195
    SSL_get0_alpn_selected(ssl, &proto, &proto_len);
363
195
    if (proto != nullptr) {
364
89
      return std::string(reinterpret_cast<const char*>(proto), proto_len);
365
89
    }
366
106
    return std::string{};
367
195
  });
368
215
}
369

            
370
59
const std::string& ConnectionInfoImplBase::sni() const {
371
59
  return getCachedValueOrCreate<std::string>(CachedValueTag::Sni, [](SSL* ssl) {
372
41
    const char* proto = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
373
41
    if (proto != nullptr) {
374
41
      return std::string(proto);
375
41
    }
376
    return std::string{};
377
41
  });
378
59
}
379

            
380
116
const std::string& ConnectionInfoImplBase::serialNumberPeerCertificate() const {
381
116
  return getCachedValueOrCreate<std::string>(
382
116
      CachedValueTag::SerialNumberPeerCertificate, [](SSL* ssl) {
383
93
        bssl::UniquePtr<X509> cert(SSL_get_peer_certificate(ssl));
384
93
        if (!cert) {
385
70
          return std::string{};
386
70
        }
387
23
        return Utility::getSerialNumberFromCertificate(*cert.get());
388
93
      });
389
116
}
390

            
391
2
absl::Span<const std::string> ConnectionInfoImplBase::serialNumbersPeerCertificates() const {
392
2
  return getCachedValueOrCreate<std::vector<std::string>>(
393
2
      CachedValueTag::SerialNumbersPeerCertificates, [](SSL* ssl) {
394
1
        STACK_OF(X509)* cert_chain = SSL_get_peer_full_cert_chain(ssl);
395
1
        if (cert_chain == nullptr) {
396
          return std::vector<std::string>{};
397
        }
398

            
399
2
        return Utility::mapX509Stack(*cert_chain, [](X509& cert) -> std::string {
400
2
          return Utility::getSerialNumberFromCertificate(cert);
401
2
        });
402
1
      });
403
2
}
404

            
405
16
const std::string& ConnectionInfoImplBase::issuerPeerCertificate() const {
406
16
  return getCachedValueOrCreate<std::string>(CachedValueTag::IssuerPeerCertificate, [](SSL* ssl) {
407
13
    bssl::UniquePtr<X509> cert(SSL_get_peer_certificate(ssl));
408
13
    if (!cert) {
409
4
      return std::string{};
410
4
    }
411
9
    return Utility::getIssuerFromCertificate(*cert);
412
13
  });
413
16
}
414

            
415
31
const std::string& ConnectionInfoImplBase::subjectPeerCertificate() const {
416
31
  return getCachedValueOrCreate<std::string>(CachedValueTag::SubjectPeerCertificate, [](SSL* ssl) {
417
28
    bssl::UniquePtr<X509> cert(SSL_get_peer_certificate(ssl));
418
28
    if (!cert) {
419
11
      return std::string{};
420
11
    }
421
17
    return Utility::getSubjectFromCertificate(*cert);
422
28
  });
423
31
}
424

            
425
13
Ssl::ParsedX509NameOptConstRef ConnectionInfoImplBase::parsedSubjectPeerCertificate() const {
426
13
  const auto& parsedName = getCachedValueOrCreate<Ssl::ParsedX509NamePtr>(
427
13
      CachedValueTag::ParsedSubjectPeerCertificate, [](SSL* ssl) {
428
10
        bssl::UniquePtr<X509> cert(SSL_get_peer_certificate(ssl));
429
10
        if (!cert) {
430
7
          return Ssl::ParsedX509NamePtr();
431
7
        }
432
3
        return Utility::parseSubjectFromCertificate(*cert);
433
10
      });
434

            
435
13
  if (parsedName) {
436
6
    return {*parsedName};
437
6
  }
438
7
  return absl::nullopt;
439
13
}
440

            
441
17
const std::string& ConnectionInfoImplBase::subjectLocalCertificate() const {
442
17
  return getCachedValueOrCreate<std::string>(CachedValueTag::SubjectLocalCertificate, [](SSL* ssl) {
443
14
    X509* cert = SSL_get_certificate(ssl);
444
14
    if (!cert) {
445
1
      return std::string{};
446
1
    }
447
13
    return Utility::getSubjectFromCertificate(*cert);
448
14
  });
449
17
}
450

            
451
8
absl::optional<SystemTime> ConnectionInfoImplBase::validFromPeerCertificate() const {
452
8
  bssl::UniquePtr<X509> cert(SSL_get_peer_certificate(ssl()));
453
8
  if (!cert) {
454
7
    return absl::nullopt;
455
7
  }
456
1
  return Utility::getValidFrom(*cert);
457
8
}
458

            
459
8
absl::optional<SystemTime> ConnectionInfoImplBase::expirationPeerCertificate() const {
460
8
  bssl::UniquePtr<X509> cert(SSL_get_peer_certificate(ssl()));
461
8
  if (!cert) {
462
7
    return absl::nullopt;
463
7
  }
464
1
  return Utility::getExpirationTime(*cert);
465
8
}
466

            
467
167
const std::string& ConnectionInfoImplBase::sessionId() const {
468
167
  return getCachedValueOrCreate<std::string>(CachedValueTag::SessionId, [](SSL* ssl) {
469
159
    SSL_SESSION* session = SSL_get_session(ssl);
470
159
    if (session == nullptr) {
471
4
      return std::string{};
472
4
    }
473

            
474
155
    unsigned int session_id_length = 0;
475
155
    const uint8_t* session_id = SSL_SESSION_get_id(session, &session_id_length);
476
155
    return Hex::encode(session_id, session_id_length);
477
159
  });
478
167
}
479

            
480
} // namespace Tls
481
} // namespace TransportSockets
482
} // namespace Extensions
483
} // namespace Envoy