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: session_size()47 inline uint8_t session_size() const { return session_size_; } session_id()48 inline const uint8_t* session_id() const { return session_id_; } has_ticket()49 inline bool has_ticket() const { return has_ticket_; } servername_size()50 inline uint8_t servername_size() const { return servername_size_; } servername()51 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* cb_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_ 132