| // Copyright Joyent, Inc. and other Node contributors. |
| // |
| // Permission is hereby granted, free of charge, to any person obtaining a |
| // copy of this software and associated documentation files (the |
| // "Software"), to deal in the Software without restriction, including |
| // without limitation the rights to use, copy, modify, merge, publish, |
| // distribute, sublicense, and/or sell copies of the Software, and to permit |
| // persons to whom the Software is furnished to do so, subject to the |
| // following conditions: |
| // |
| // The above copyright notice and this permission notice shall be included |
| // in all copies or substantial portions of the Software. |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
| // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
| // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
| // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
| // USE OR OTHER DEALINGS IN THE SOFTWARE. |
| |
| #ifndef SRC_NODE_CRYPTO_CLIENTHELLO_H_ |
| #define SRC_NODE_CRYPTO_CLIENTHELLO_H_ |
| |
| #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
| |
| #include <cstddef> // size_t |
| #include <cstdint> |
| |
| namespace node { |
| namespace crypto { |
| |
| // Parse the client hello so we can do async session resumption. OpenSSL's |
| // session resumption uses synchronous callbacks, see SSL_CTX_sess_set_get_cb |
| // and get_session_cb. |
| // |
| // TLS1.3 handshakes masquerade as TLS1.2 session resumption, and to do this, |
| // they always include a session_id in the ClientHello, making up a bogus value |
| // if necessary. The parser can't know if its a bogus id, and will cause a |
| // 'newSession' event to be emitted. This should do no harm, the id won't be |
| // found, and the handshake will continue. |
| class ClientHelloParser { |
| public: |
| inline ClientHelloParser(); |
| |
| class ClientHello { |
| public: |
| inline uint8_t session_size() const { return session_size_; } |
| inline const uint8_t* session_id() const { return session_id_; } |
| inline bool has_ticket() const { return has_ticket_; } |
| inline uint8_t servername_size() const { return servername_size_; } |
| inline const uint8_t* servername() const { return servername_; } |
| |
| private: |
| uint8_t session_size_; |
| const uint8_t* session_id_; |
| bool has_ticket_; |
| uint8_t servername_size_; |
| const uint8_t* servername_; |
| |
| friend class ClientHelloParser; |
| }; |
| |
| typedef void (*OnHelloCb)(void* arg, const ClientHello& hello); |
| typedef void (*OnEndCb)(void* arg); |
| |
| void Parse(const uint8_t* data, size_t avail); |
| |
| inline void Reset(); |
| inline void Start(OnHelloCb onhello_cb, OnEndCb onend_cb, void* onend_arg); |
| inline void End(); |
| inline bool IsPaused() const; |
| inline bool IsEnded() const; |
| |
| private: |
| static const size_t kMaxTLSFrameLen = 16 * 1024 + 5; |
| static const size_t kMaxSSLExFrameLen = 32 * 1024; |
| static const uint8_t kServernameHostname = 0; |
| static const size_t kMinStatusRequestSize = 5; |
| |
| enum ParseState { |
| kWaiting, |
| kTLSHeader, |
| kPaused, |
| kEnded |
| }; |
| |
| enum FrameType { |
| kChangeCipherSpec = 20, |
| kAlert = 21, |
| kHandshake = 22, |
| kApplicationData = 23, |
| kOther = 255 |
| }; |
| |
| enum HandshakeType { |
| kClientHello = 1 |
| }; |
| |
| enum ExtensionType { |
| kServerName = 0, |
| kTLSSessionTicket = 35 |
| }; |
| |
| bool ParseRecordHeader(const uint8_t* data, size_t avail); |
| void ParseHeader(const uint8_t* data, size_t avail); |
| void ParseExtension(const uint16_t type, |
| const uint8_t* data, |
| size_t len); |
| bool ParseTLSClientHello(const uint8_t* data, size_t avail); |
| |
| ParseState state_; |
| OnHelloCb onhello_cb_; |
| OnEndCb onend_cb_; |
| void* cb_arg_; |
| size_t frame_len_ = 0; |
| size_t body_offset_ = 0; |
| size_t extension_offset_ = 0; |
| uint8_t session_size_ = 0; |
| const uint8_t* session_id_ = nullptr; |
| uint16_t servername_size_ = 0; |
| const uint8_t* servername_ = nullptr; |
| uint16_t tls_ticket_size_ = -1; |
| const uint8_t* tls_ticket_ = nullptr; |
| }; |
| |
| } // namespace crypto |
| } // namespace node |
| |
| #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
| |
| #endif // SRC_NODE_CRYPTO_CLIENTHELLO_H_ |