GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/node-core-coverage/node-core-coverage/workdir/node/src/node_crypto_clienthello.cc Lines: 82 82 100.0 %
Date: 2016-07-12 Branches: 42 73 57.5 %

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