GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/node_crypto_clienthello.cc Lines: 87 114 76.3 %
Date: 2017-10-21 Branches: 44 80 55.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
#include "node_crypto_clienthello.h"
23
#include "node_crypto_clienthello-inl.h"
24
25
namespace node {
26
namespace crypto {
27
28
23
void ClientHelloParser::Parse(const uint8_t* data, size_t avail) {
29

23
  switch (state_) {
30
    case kWaiting:
31
23
      if (!ParseRecordHeader(data, avail))
32
        break;
33
      // Fall through
34
    case kTLSHeader:
35
23
      ParseHeader(data, avail);
36
23
      break;
37
    case kPaused:
38
      // Just nop
39
    case kEnded:
40
      // Already ended, just ignore it
41
      break;
42
    default:
43
      break;
44
  }
45
23
}
46
47
48
23
bool ClientHelloParser::ParseRecordHeader(const uint8_t* data, size_t avail) {
49
  // >= 5 bytes for header parsing
50
23
  if (avail < 5)
51
    return false;
52
53

46
  if (data[0] == kChangeCipherSpec ||
54
46
      data[0] == kAlert ||
55
23
      data[0] == kHandshake ||
56
      data[0] == kApplicationData) {
57
23
    frame_len_ = (data[3] << 8) + data[4];
58
23
    state_ = kTLSHeader;
59
23
    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
23
  if (frame_len_ >= kMaxTLSFrameLen) {
68
    End();
69
    return false;
70
  }
71
72
23
  return true;
73
}
74
75
76
23
void ClientHelloParser::ParseHeader(const uint8_t* data, size_t avail) {
77
  ClientHello hello;
78
79
  // >= 5 + frame size bytes for frame parsing
80
23
  if (body_offset_ + frame_len_ > avail)
81
23
    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

46
  if (data[body_offset_ + 4] != 0x03 ||
90
46
      data[body_offset_ + 5] < 0x01 ||
91
23
      data[body_offset_ + 5] > 0x03) {
92
    goto fail;
93
  }
94
95
23
  if (data[body_offset_] == kClientHello) {
96
23
    if (state_ == kTLSHeader) {
97
23
      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

46
    if (session_id_ == nullptr ||
106
46
        session_size_ > 32 ||
107
23
        session_id_ + session_size_ > data + avail) {
108
      goto fail;
109
    }
110
  }
111
112
23
  state_ = kPaused;
113
23
  hello.session_id_ = session_id_;
114
23
  hello.session_size_ = session_size_;
115

23
  hello.has_ticket_ = tls_ticket_ != nullptr && tls_ticket_size_ != 0;
116
23
  hello.ocsp_request_ = ocsp_request_;
117
23
  hello.servername_ = servername_;
118
23
  hello.servername_size_ = static_cast<uint8_t>(servername_size_);
119
23
  onhello_cb_(cb_arg_, hello);
120
23
  return;
121
122
 fail:
123
  End();
124
}
125
126
127
92
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

92
  switch (type) {
134
    case kServerName:
135
      {
136
20
        if (len < 2)
137
          return;
138
20
        uint32_t server_names_len = (data[0] << 8) + data[1];
139
20
        if (server_names_len + 2 > len)
140
          return;
141
60
        for (size_t offset = 2; offset < 2 + server_names_len; ) {
142
20
          if (offset + 3 > len)
143
            return;
144
20
          uint8_t name_type = data[offset];
145
20
          if (name_type != kServernameHostname)
146
            return;
147
20
          uint16_t name_len = (data[offset + 1] << 8) + data[offset + 2];
148
20
          offset += 3;
149
20
          if (offset + name_len > len)
150
            return;
151
20
          servername_ = data + offset;
152
20
          servername_size_ = name_len;
153
20
          offset += name_len;
154
        }
155
      }
156
20
      break;
157
    case kStatusRequest:
158
      // We are ignoring any data, just indicating the presence of extension
159
1
      if (len < kMinStatusRequestSize)
160
        return;
161
162
      // Unknown type, ignore it
163
1
      if (data[0] != kStatusRequestOCSP)
164
        break;
165
166
      // Ignore extensions, they won't work with caching on backend anyway
167
1
      ocsp_request_ = 1;
168
1
      break;
169
    case kTLSSessionTicket:
170
11
      tls_ticket_size_ = len;
171
11
      tls_ticket_ = data + len;
172
11
      break;
173
    default:
174
      // Ignore
175
60
      break;
176
  }
177
}
178
179
180
23
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
23
  size_t session_offset = body_offset_ + 4 + 2 + 32;
185
186
23
  if (session_offset + 1 >= avail)
187
    return false;
188
189
23
  body = data + session_offset;
190
23
  session_size_ = *body;
191
23
  session_id_ = body + 1;
192
193
23
  size_t cipher_offset = session_offset + 1 + session_size_;
194
195
  // Session OOB failure
196
23
  if (cipher_offset + 1 >= avail)
197
    return false;
198
199
  uint16_t cipher_len =
200
23
      (data[cipher_offset] << 8) + data[cipher_offset + 1];
201
23
  size_t comp_offset = cipher_offset + 2 + cipher_len;
202
203
  // Cipher OOB failure
204
23
  if (comp_offset >= avail)
205
    return false;
206
207
23
  uint8_t comp_len = data[comp_offset];
208
23
  size_t extension_offset = comp_offset + 1 + comp_len;
209
210
  // Compression OOB failure
211
23
  if (extension_offset > avail)
212
    return false;
213
214
  // No extensions present
215
23
  if (extension_offset == avail)
216
    return true;
217
218
23
  size_t ext_off = extension_offset + 2;
219
220
  // Parse known extensions
221
138
  while (ext_off < avail) {
222
    // Extension OOB
223
92
    if (ext_off + 4 > avail)
224
      return false;
225
226
92
    uint16_t ext_type = (data[ext_off] << 8) + data[ext_off + 1];
227
92
    uint16_t ext_len = (data[ext_off + 2] << 8) + data[ext_off + 3];
228
92
    ext_off += 4;
229
230
    // Extension OOB
231
92
    if (ext_off + ext_len > avail)
232
      return false;
233
234
    ParseExtension(ext_type,
235
                   data + ext_off,
236
92
                   ext_len);
237
238
92
    ext_off += ext_len;
239
  }
240
241
  // Extensions OOB failure
242
23
  if (ext_off > avail)
243
    return false;
244
245
23
  return true;
246
}
247
248
}  // namespace crypto
249
}  // namespace node