summaryrefslogtreecommitdiff
path: root/cpputil/tls_parser.h
blob: 6636b3c6a73cd99da64e92a7aba5c24ce68d23e6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef tls_parser_h_
#define tls_parser_h_

#include <cstdint>
#include <cstring>
#include <memory>
#if defined(WIN32) || defined(WIN64)
#include <winsock2.h>
#else
#include <arpa/inet.h>
#endif
#include "databuffer.h"
#include "sslt.h"

namespace nss_test {

const uint8_t kTlsHandshakeClientHello = 1;
const uint8_t kTlsHandshakeServerHello = 2;
const uint8_t kTlsHandshakeNewSessionTicket = 4;
const uint8_t kTlsHandshakeHelloRetryRequest = 6;
const uint8_t kTlsHandshakeEncryptedExtensions = 8;
const uint8_t kTlsHandshakeCertificate = 11;
const uint8_t kTlsHandshakeServerKeyExchange = 12;
const uint8_t kTlsHandshakeCertificateRequest = 13;
const uint8_t kTlsHandshakeCertificateVerify = 15;
const uint8_t kTlsHandshakeClientKeyExchange = 16;
const uint8_t kTlsHandshakeFinished = 20;
const uint8_t kTlsHandshakeKeyUpdate = 24;

const uint8_t kTlsAlertWarning = 1;
const uint8_t kTlsAlertFatal = 2;

const uint8_t kTlsAlertCloseNotify = 0;
const uint8_t kTlsAlertUnexpectedMessage = 10;
const uint8_t kTlsAlertBadRecordMac = 20;
const uint8_t kTlsAlertRecordOverflow = 22;
const uint8_t kTlsAlertHandshakeFailure = 40;
const uint8_t kTlsAlertBadCertificate = 42;
const uint8_t kTlsAlertCertificateRevoked = 44;
const uint8_t kTlsAlertCertificateExpired = 45;
const uint8_t kTlsAlertIllegalParameter = 47;
const uint8_t kTlsAlertDecodeError = 50;
const uint8_t kTlsAlertDecryptError = 51;
const uint8_t kTlsAlertProtocolVersion = 70;
const uint8_t kTlsAlertInsufficientSecurity = 71;
const uint8_t kTlsAlertInternalError = 80;
const uint8_t kTlsAlertInappropriateFallback = 86;
const uint8_t kTlsAlertMissingExtension = 109;
const uint8_t kTlsAlertUnsupportedExtension = 110;
const uint8_t kTlsAlertUnrecognizedName = 112;
const uint8_t kTlsAlertCertificateRequired = 116;
const uint8_t kTlsAlertNoApplicationProtocol = 120;

const uint8_t kTlsFakeChangeCipherSpec[] = {
    ssl_ct_change_cipher_spec,  // Type
    0xfe,
    0xff,  // Version
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x10,  // Fictitious sequence #
    0x00,
    0x01,  // Length
    0x01   // Value
};

const uint8_t kCtDtlsCiphertext = 0x20;
const uint8_t kCtDtlsCiphertextMask = 0xE0;
const uint8_t kCtDtlsCiphertext16bSeqno = 0x08;
const uint8_t kCtDtlsCiphertextLengthPresent = 0x04;

static const uint8_t kTls13PskKe = 0;
static const uint8_t kTls13PskDhKe = 1;
static const uint8_t kTls13PskAuth = 0;
static const uint8_t kTls13PskSignAuth = 1;

inline std::ostream& operator<<(std::ostream& os, SSLProtocolVariant v) {
  return os << ((v == ssl_variant_stream) ? "TLS" : "DTLS");
}

inline std::ostream& operator<<(std::ostream& os, SSLContentType v) {
  switch (v) {
    case ssl_ct_change_cipher_spec:
      return os << "CCS";
    case ssl_ct_alert:
      return os << "alert";
    case ssl_ct_handshake:
      return os << "handshake";
    case ssl_ct_application_data:
      return os << "application data";
    case ssl_ct_ack:
      return os << "ack";
  }
  return os << "UNKNOWN content type " << static_cast<int>(v);
}

inline std::ostream& operator<<(std::ostream& os, SSLSecretDirection v) {
  switch (v) {
    case ssl_secret_read:
      return os << "read";
    case ssl_secret_write:
      return os << "write";
  }
  return os << "UNKNOWN secret direction " << static_cast<int>(v);
}

inline bool IsDtls(uint16_t version) { return (version & 0x8000) == 0x8000; }

inline uint16_t NormalizeTlsVersion(uint16_t version) {
  if (version == 0xfeff) {
    return 0x0302;  // special: DTLS 1.0 == TLS 1.1
  }
  if (IsDtls(version)) {
    return (version ^ 0xffff) + 0x0201;
  }
  return version;
}

inline uint16_t TlsVersionToDtlsVersion(uint16_t version) {
  if (version == 0x0302) {
    return 0xfeff;
  }
  if (version == 0x0304) {
    return version;
  }
  return 0xffff - version + 0x0201;
}

inline size_t WriteVariable(DataBuffer* target, size_t index,
                            const DataBuffer& buf, size_t len_size) {
  index = target->Write(index, static_cast<uint32_t>(buf.len()), len_size);
  return target->Write(index, buf.data(), buf.len());
}

class TlsParser {
 public:
  TlsParser(const uint8_t* data, size_t len) : buffer_(data, len), offset_(0) {}
  explicit TlsParser(const DataBuffer& buf) : buffer_(buf), offset_(0) {}

  bool Read(uint8_t* val);
  // Read an integral type of specified width.
  bool Read(uint32_t* val, size_t size);
  // Reads len bytes into dest buffer, overwriting it.
  bool Read(DataBuffer* dest, size_t len);
  bool ReadFromMark(DataBuffer* val, size_t len, size_t mark);
  // Reads bytes into dest buffer, overwriting it.  The number of bytes is
  // determined by reading from len_size bytes from the stream first.
  bool ReadVariable(DataBuffer* dest, size_t len_size);

  bool Skip(size_t len);
  bool SkipVariable(size_t len_size);

  size_t consumed() const { return offset_; }
  size_t remaining() const { return buffer_.len() - offset_; }

 private:
  void consume(size_t len) { offset_ += len; }
  const uint8_t* ptr() const { return buffer_.data() + offset_; }

  DataBuffer buffer_;
  size_t offset_;
};

}  // namespace nss_test

#endif