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_NODE_CRYPTO_CLIENTHELLO_H_ 23 #define SRC_NODE_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 33 // Parse the client hello so we can do async session resumption. OpenSSL's 34 // session resumption uses synchronous callbacks, see SSL_CTX_sess_set_get_cb 35 // and get_session_cb. 36 // 37 // TLS1.3 handshakes masquerade as TLS1.2 session resumption, and to do this, 38 // they always include a session_id in the ClientHello, making up a bogus value 39 // if necessary. The parser can't know if its a bogus id, and will cause a 40 // 'newSession' event to be emitted. This should do no harm, the id won't be 41 // found, and the handshake will continue. 42 class ClientHelloParser { 43 public: 44 inline ClientHelloParser(); 45 46 class ClientHello { 47 public: session_size()48 inline uint8_t session_size() const { return session_size_; } session_id()49 inline const uint8_t* session_id() const { return session_id_; } has_ticket()50 inline bool has_ticket() const { return has_ticket_; } servername_size()51 inline uint8_t servername_size() const { return servername_size_; } servername()52 inline const uint8_t* servername() const { return servername_; } 53 54 private: 55 uint8_t session_size_; 56 const uint8_t* session_id_; 57 bool has_ticket_; 58 uint8_t servername_size_; 59 const uint8_t* servername_; 60 61 friend class ClientHelloParser; 62 }; 63 64 typedef void (*OnHelloCb)(void* arg, const ClientHello& hello); 65 typedef void (*OnEndCb)(void* arg); 66 67 void Parse(const uint8_t* data, size_t avail); 68 69 inline void Reset(); 70 inline void Start(OnHelloCb onhello_cb, OnEndCb onend_cb, void* onend_arg); 71 inline void End(); 72 inline bool IsPaused() const; 73 inline bool IsEnded() const; 74 75 private: 76 static const size_t kMaxTLSFrameLen = 16 * 1024 + 5; 77 static const size_t kMaxSSLExFrameLen = 32 * 1024; 78 static const uint8_t kServernameHostname = 0; 79 static const size_t kMinStatusRequestSize = 5; 80 81 enum ParseState { 82 kWaiting, 83 kTLSHeader, 84 kPaused, 85 kEnded 86 }; 87 88 enum FrameType { 89 kChangeCipherSpec = 20, 90 kAlert = 21, 91 kHandshake = 22, 92 kApplicationData = 23, 93 kOther = 255 94 }; 95 96 enum HandshakeType { 97 kClientHello = 1 98 }; 99 100 enum ExtensionType { 101 kServerName = 0, 102 kTLSSessionTicket = 35 103 }; 104 105 bool ParseRecordHeader(const uint8_t* data, size_t avail); 106 void ParseHeader(const uint8_t* data, size_t avail); 107 void ParseExtension(const uint16_t type, 108 const uint8_t* data, 109 size_t len); 110 bool ParseTLSClientHello(const uint8_t* data, size_t avail); 111 112 ParseState state_; 113 OnHelloCb onhello_cb_; 114 OnEndCb onend_cb_; 115 void* cb_arg_; 116 size_t frame_len_ = 0; 117 size_t body_offset_ = 0; 118 size_t extension_offset_ = 0; 119 uint8_t session_size_ = 0; 120 const uint8_t* session_id_ = nullptr; 121 uint16_t servername_size_ = 0; 122 const uint8_t* servername_ = nullptr; 123 uint16_t tls_ticket_size_ = -1; 124 const uint8_t* tls_ticket_ = nullptr; 125 }; 126 127 } // namespace crypto 128 } // namespace node 129 130 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 131 132 #endif // SRC_NODE_CRYPTO_CLIENTHELLO_H_ 133