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