Node.js  v8.x
Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine
node_crypto_clienthello.cc
Go to the documentation of this file.
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 
24 
25 namespace node {
26 namespace crypto {
27 
28 void ClientHelloParser::Parse(const uint8_t* data, size_t avail) {
29  switch (state_) {
30  case kWaiting:
31  if (!ParseRecordHeader(data, avail))
32  break;
33  // Fall through
34  case kTLSHeader:
35  ParseHeader(data, avail);
36  break;
37  case kPaused:
38  // Just nop
39  case kEnded:
40  // Already ended, just ignore it
41  break;
42  default:
43  break;
44  }
45 }
46 
47 
48 bool ClientHelloParser::ParseRecordHeader(const uint8_t* data, size_t avail) {
49  // >= 5 bytes for header parsing
50  if (avail < 5)
51  return false;
52 
53  if (data[0] == kChangeCipherSpec ||
54  data[0] == kAlert ||
55  data[0] == kHandshake ||
56  data[0] == kApplicationData) {
57  frame_len_ = (data[3] << 8) + data[4];
58  state_ = kTLSHeader;
59  body_offset_ = 5;
60  } else {
61  End();
62  return false;
63  }
64 
65  // Sanity check (too big frame, or too small)
66  // Let OpenSSL handle it
67  if (frame_len_ >= kMaxTLSFrameLen) {
68  End();
69  return false;
70  }
71 
72  return true;
73 }
74 
75 
76 void ClientHelloParser::ParseHeader(const uint8_t* data, size_t avail) {
77  ClientHello hello;
78 
79  // >= 5 + frame size bytes for frame parsing
80  if (body_offset_ + frame_len_ > avail)
81  return;
82 
83  // Check hello protocol version. Protocol tuples that we know about:
84  //
85  // (3,1) TLS v1.0
86  // (3,2) TLS v1.1
87  // (3,3) TLS v1.2
88  //
89  if (data[body_offset_ + 4] != 0x03 ||
90  data[body_offset_ + 5] < 0x01 ||
91  data[body_offset_ + 5] > 0x03) {
92  goto fail;
93  }
94 
95  if (data[body_offset_] == kClientHello) {
96  if (state_ == kTLSHeader) {
97  if (!ParseTLSClientHello(data, avail))
98  goto fail;
99  } else {
100  // We couldn't get here, but whatever
101  goto fail;
102  }
103 
104  // Check if we overflowed (do not reply with any private data)
105  if (session_id_ == nullptr ||
106  session_size_ > 32 ||
107  session_id_ + session_size_ > data + avail) {
108  goto fail;
109  }
110  }
111 
112  state_ = kPaused;
113  hello.session_id_ = session_id_;
114  hello.session_size_ = session_size_;
115  hello.has_ticket_ = tls_ticket_ != nullptr && tls_ticket_size_ != 0;
116  hello.ocsp_request_ = ocsp_request_;
117  hello.servername_ = servername_;
118  hello.servername_size_ = static_cast<uint8_t>(servername_size_);
119  onhello_cb_(cb_arg_, hello);
120  return;
121 
122  fail:
123  End();
124 }
125 
126 
127 void ClientHelloParser::ParseExtension(const uint16_t type,
128  const uint8_t* data,
129  size_t len) {
130  // NOTE: In case of anything we're just returning back, ignoring the problem.
131  // That's because we're heavily relying on OpenSSL to solve any problem with
132  // incoming data.
133  switch (type) {
134  case kServerName:
135  {
136  if (len < 2)
137  return;
138  uint32_t server_names_len = (data[0] << 8) + data[1];
139  if (server_names_len + 2 > len)
140  return;
141  for (size_t offset = 2; offset < 2 + server_names_len; ) {
142  if (offset + 3 > len)
143  return;
144  uint8_t name_type = data[offset];
145  if (name_type != kServernameHostname)
146  return;
147  uint16_t name_len = (data[offset + 1] << 8) + data[offset + 2];
148  offset += 3;
149  if (offset + name_len > len)
150  return;
151  servername_ = data + offset;
152  servername_size_ = name_len;
153  offset += name_len;
154  }
155  }
156  break;
157  case kStatusRequest:
158  // We are ignoring any data, just indicating the presence of extension
159  if (len < kMinStatusRequestSize)
160  return;
161 
162  // Unknown type, ignore it
163  if (data[0] != kStatusRequestOCSP)
164  break;
165 
166  // Ignore extensions, they won't work with caching on backend anyway
167  ocsp_request_ = 1;
168  break;
169  case kTLSSessionTicket:
170  tls_ticket_size_ = len;
171  tls_ticket_ = data + len;
172  break;
173  default:
174  // Ignore
175  break;
176  }
177 }
178 
179 
180 bool ClientHelloParser::ParseTLSClientHello(const uint8_t* data, size_t avail) {
181  const uint8_t* body;
182 
183  // Skip frame header, hello header, protocol version and random data
184  size_t session_offset = body_offset_ + 4 + 2 + 32;
185 
186  if (session_offset + 1 >= avail)
187  return false;
188 
189  body = data + session_offset;
190  session_size_ = *body;
191  session_id_ = body + 1;
192 
193  size_t cipher_offset = session_offset + 1 + session_size_;
194 
195  // Session OOB failure
196  if (cipher_offset + 1 >= avail)
197  return false;
198 
199  uint16_t cipher_len =
200  (data[cipher_offset] << 8) + data[cipher_offset + 1];
201  size_t comp_offset = cipher_offset + 2 + cipher_len;
202 
203  // Cipher OOB failure
204  if (comp_offset >= avail)
205  return false;
206 
207  uint8_t comp_len = data[comp_offset];
208  size_t extension_offset = comp_offset + 1 + comp_len;
209 
210  // Compression OOB failure
211  if (extension_offset > avail)
212  return false;
213 
214  // No extensions present
215  if (extension_offset == avail)
216  return true;
217 
218  size_t ext_off = extension_offset + 2;
219 
220  // Parse known extensions
221  while (ext_off < avail) {
222  // Extension OOB
223  if (ext_off + 4 > avail)
224  return false;
225 
226  uint16_t ext_type = (data[ext_off] << 8) + data[ext_off + 1];
227  uint16_t ext_len = (data[ext_off + 2] << 8) + data[ext_off + 3];
228  ext_off += 4;
229 
230  // Extension OOB
231  if (ext_off + ext_len > avail)
232  return false;
233 
234  ParseExtension(ext_type,
235  data + ext_off,
236  ext_len);
237 
238  ext_off += ext_len;
239  }
240 
241  // Extensions OOB failure
242  if (ext_off > avail)
243  return false;
244 
245  return true;
246 }
247 
248 } // namespace crypto
249 } // namespace node
int len
Definition: cares_wrap.cc:485
union node::cares_wrap::@8::CaresAsyncData::@0 data