GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_clienthello.h Lines: 5 5 100.0 %
Date: 2022-08-06 04:16:36 Branches: 0 0 - %

Line Branch Exec Source
1
// Copyright Joyent, Inc. and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22
#ifndef SRC_CRYPTO_CRYPTO_CLIENTHELLO_H_
23
#define SRC_CRYPTO_CRYPTO_CLIENTHELLO_H_
24
25
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
26
27
#include <cstddef>  // size_t
28
#include <cstdint>
29
30
namespace node {
31
namespace crypto {
32
// Parse the client hello so we can do async session resumption. OpenSSL's
33
// session resumption uses synchronous callbacks, see SSL_CTX_sess_set_get_cb
34
// and get_session_cb.
35
//
36
// TLS1.3 handshakes masquerade as TLS1.2 session resumption, and to do this,
37
// they always include a session_id in the ClientHello, making up a bogus value
38
// if necessary. The parser can't know if its a bogus id, and will cause a
39
// 'newSession' event to be emitted. This should do no harm, the id won't be
40
// found, and the handshake will continue.
41
class ClientHelloParser {
42
 public:
43
  inline ClientHelloParser();
44
45
  class ClientHello {
46
   public:
47
20
    inline uint8_t session_size() const { return session_size_; }
48
20
    inline const uint8_t* session_id() const { return session_id_; }
49
20
    inline bool has_ticket() const { return has_ticket_; }
50
18
    inline uint8_t servername_size() const { return servername_size_; }
51
38
    inline const uint8_t* servername() const { return servername_; }
52
53
   private:
54
    uint8_t session_size_;
55
    const uint8_t* session_id_;
56
    bool has_ticket_;
57
    uint8_t servername_size_;
58
    const uint8_t* servername_;
59
60
    friend class ClientHelloParser;
61
  };
62
63
  typedef void (*OnHelloCb)(void* arg, const ClientHello& hello);
64
  typedef void (*OnEndCb)(void* arg);
65
66
  void Parse(const uint8_t* data, size_t avail);
67
68
  inline void Reset();
69
  inline void Start(OnHelloCb onhello_cb, OnEndCb onend_cb, void* onend_arg);
70
  inline void End();
71
  inline bool IsPaused() const;
72
  inline bool IsEnded() const;
73
74
 private:
75
  static const size_t kMaxTLSFrameLen = 16 * 1024 + 5;
76
  static const size_t kMaxSSLExFrameLen = 32 * 1024;
77
  static const uint8_t kServernameHostname = 0;
78
  static const size_t kMinStatusRequestSize = 5;
79
80
  enum ParseState {
81
    kWaiting,
82
    kTLSHeader,
83
    kPaused,
84
    kEnded
85
  };
86
87
  enum FrameType {
88
    kChangeCipherSpec = 20,
89
    kAlert = 21,
90
    kHandshake = 22,
91
    kApplicationData = 23,
92
    kOther = 255
93
  };
94
95
  enum HandshakeType {
96
    kClientHello = 1
97
  };
98
99
  enum ExtensionType {
100
    kServerName = 0,
101
    kTLSSessionTicket = 35
102
  };
103
104
  bool ParseRecordHeader(const uint8_t* data, size_t avail);
105
  void ParseHeader(const uint8_t* data, size_t avail);
106
  void ParseExtension(const uint16_t type,
107
                      const uint8_t* data,
108
                      size_t len);
109
  bool ParseTLSClientHello(const uint8_t* data, size_t avail);
110
111
  ParseState state_;
112
  OnHelloCb onhello_cb_;
113
  OnEndCb onend_cb_;
114
  void* cb_arg_;
115
  size_t frame_len_ = 0;
116
  size_t body_offset_ = 0;
117
  size_t extension_offset_ = 0;
118
  uint8_t session_size_ = 0;
119
  const uint8_t* session_id_ = nullptr;
120
  uint16_t servername_size_ = 0;
121
  const uint8_t* servername_ = nullptr;
122
  uint16_t tls_ticket_size_ = -1;
123
  const uint8_t* tls_ticket_ = nullptr;
124
};
125
126
}  // namespace crypto
127
}  // namespace node
128
129
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
130
131
#endif  // SRC_CRYPTO_CRYPTO_CLIENTHELLO_H_