GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_crypto_clienthello.cc Lines: 80 107 74.8 %
Date: 2019-09-07 22:28:56 Branches: 41 75 54.7 %

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"  // NOLINT(build/include_inline)
23
#include "node_crypto_clienthello-inl.h"
24
25
namespace node {
26
namespace crypto {
27
28
20
void ClientHelloParser::Parse(const uint8_t* data, size_t avail) {
29

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

40
  if (data[0] == kChangeCipherSpec ||
54
40
      data[0] == kAlert ||
55
20
      data[0] == kHandshake ||
56
      data[0] == kApplicationData) {
57
20
    frame_len_ = (data[3] << 8) + data[4];
58
20
    state_ = kTLSHeader;
59
20
    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
20
  if (frame_len_ >= kMaxTLSFrameLen) {
68
    End();
69
    return false;
70
  }
71
72
20
  return true;
73
}
74
75
76
20
void ClientHelloParser::ParseHeader(const uint8_t* data, size_t avail) {
77
  ClientHello hello;
78
79
  // >= 5 + frame size bytes for frame parsing
80
20
  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
  // Note that TLS v1.3 uses a TLS v1.2 handshake so requires no specific
90
  // support here.
91

40
  if (data[body_offset_ + 4] != 0x03 ||
92
40
      data[body_offset_ + 5] < 0x01 ||
93
20
      data[body_offset_ + 5] > 0x03) {
94
    return End();
95
  }
96
97
20
  if (data[body_offset_] == kClientHello) {
98
20
    if (state_ == kTLSHeader) {
99
20
      if (!ParseTLSClientHello(data, avail))
100
        return End();
101
    } else {
102
      // We couldn't get here, but whatever
103
      return End();
104
    }
105
106
    // Check if we overflowed (do not reply with any private data)
107

40
    if (session_id_ == nullptr ||
108
40
        session_size_ > 32 ||
109
20
        session_id_ + session_size_ > data + avail) {
110
      return End();
111
    }
112
  }
113
114
20
  state_ = kPaused;
115
20
  hello.session_id_ = session_id_;
116
20
  hello.session_size_ = session_size_;
117

20
  hello.has_ticket_ = tls_ticket_ != nullptr && tls_ticket_size_ != 0;
118
20
  hello.servername_ = servername_;
119
20
  hello.servername_size_ = static_cast<uint8_t>(servername_size_);
120
20
  onhello_cb_(cb_arg_, hello);
121
}
122
123
124
108
void ClientHelloParser::ParseExtension(const uint16_t type,
125
                                       const uint8_t* data,
126
                                       size_t len) {
127
  // NOTE: In case of anything we're just returning back, ignoring the problem.
128
  // That's because we're heavily relying on OpenSSL to solve any problem with
129
  // incoming data.
130
108
  switch (type) {
131
    case kServerName:
132
      {
133
18
        if (len < 2)
134
          return;
135
18
        uint32_t server_names_len = (data[0] << 8) + data[1];
136
18
        if (server_names_len + 2 > len)
137
          return;
138
54
        for (size_t offset = 2; offset < 2 + server_names_len; ) {
139
18
          if (offset + 3 > len)
140
            return;
141
18
          uint8_t name_type = data[offset];
142
18
          if (name_type != kServernameHostname)
143
            return;
144
18
          uint16_t name_len = (data[offset + 1] << 8) + data[offset + 2];
145
18
          offset += 3;
146
18
          if (offset + name_len > len)
147
            return;
148
18
          servername_ = data + offset;
149
18
          servername_size_ = name_len;
150
18
          offset += name_len;
151
        }
152
      }
153
18
      break;
154
    case kTLSSessionTicket:
155
8
      tls_ticket_size_ = len;
156
8
      tls_ticket_ = data + len;
157
8
      break;
158
    default:
159
      // Ignore
160
82
      break;
161
  }
162
}
163
164
165
20
bool ClientHelloParser::ParseTLSClientHello(const uint8_t* data, size_t avail) {
166
  const uint8_t* body;
167
168
  // Skip frame header, hello header, protocol version and random data
169
20
  size_t session_offset = body_offset_ + 4 + 2 + 32;
170
171
20
  if (session_offset + 1 >= avail)
172
    return false;
173
174
20
  body = data + session_offset;
175
20
  session_size_ = *body;
176
20
  session_id_ = body + 1;
177
178
20
  size_t cipher_offset = session_offset + 1 + session_size_;
179
180
  // Session OOB failure
181
20
  if (cipher_offset + 1 >= avail)
182
    return false;
183
184
  uint16_t cipher_len =
185
20
      (data[cipher_offset] << 8) + data[cipher_offset + 1];
186
20
  size_t comp_offset = cipher_offset + 2 + cipher_len;
187
188
  // Cipher OOB failure
189
20
  if (comp_offset >= avail)
190
    return false;
191
192
20
  uint8_t comp_len = data[comp_offset];
193
20
  size_t extension_offset = comp_offset + 1 + comp_len;
194
195
  // Compression OOB failure
196
20
  if (extension_offset > avail)
197
    return false;
198
199
  // No extensions present
200
20
  if (extension_offset == avail)
201
    return true;
202
203
20
  size_t ext_off = extension_offset + 2;
204
205
  // Parse known extensions
206
148
  while (ext_off < avail) {
207
    // Extension OOB
208
108
    if (ext_off + 4 > avail)
209
      return false;
210
211
108
    uint16_t ext_type = (data[ext_off] << 8) + data[ext_off + 1];
212
108
    uint16_t ext_len = (data[ext_off + 2] << 8) + data[ext_off + 3];
213
108
    ext_off += 4;
214
215
    // Extension OOB
216
108
    if (ext_off + ext_len > avail)
217
      return false;
218
219
    ParseExtension(ext_type,
220
                   data + ext_off,
221
108
                   ext_len);
222
223
108
    ext_off += ext_len;
224
  }
225
226
  // Extensions OOB failure
227
20
  if (ext_off > avail)
228
    return false;
229
230
20
  return true;
231
}
232
233
}  // namespace crypto
234
}  // namespace node