|
| 1 | +/* |
| 2 | + * Copyright 2018- The Pixie Authors. |
| 3 | + * |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | + * you may not use this file except in compliance with the License. |
| 6 | + * You may obtain a copy of the License at |
| 7 | + * |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | + * |
| 10 | + * Unless required by applicable law or agreed to in writing, software |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | + * See the License for the specific language governing permissions and |
| 14 | + * limitations under the License. |
| 15 | + * |
| 16 | + * SPDX-License-Identifier: Apache-2.0 |
| 17 | + */ |
| 18 | +#include "src/stirling/source_connectors/socket_tracer/protocols/tls/parse.h" |
| 19 | + |
| 20 | +#include <map> |
| 21 | +#include <string> |
| 22 | +#include <utility> |
| 23 | +#include <vector> |
| 24 | + |
| 25 | +#include <magic_enum.hpp> |
| 26 | + |
| 27 | +#include "src/stirling/utils/binary_decoder.h" |
| 28 | + |
| 29 | +namespace px { |
| 30 | +namespace stirling { |
| 31 | +namespace protocols { |
| 32 | +namespace tls { |
| 33 | + |
| 34 | +constexpr size_t kTLSRecordHeaderLength = 5; |
| 35 | +constexpr size_t kExtensionMinimumLength = 4; |
| 36 | +constexpr size_t kSNIExtensionMinimumLength = 3; |
| 37 | + |
| 38 | +// In TLS 1.3, Random is 32 bytes. |
| 39 | +// In TLS 1.2 and earlier, gmt_unix_time is 4 bytes and Random is 28 bytes. |
| 40 | +constexpr size_t kRandomStructLength = 32; |
| 41 | + |
| 42 | +StatusOr<ParseState> ExtractSNIExtension(std::map<std::string, std::string>* exts, |
| 43 | + BinaryDecoder* decoder) { |
| 44 | + PX_ASSIGN_OR(auto server_name_list_length, decoder->ExtractBEInt<uint16_t>(), |
| 45 | + return ParseState::kInvalid); |
| 46 | + std::vector<std::string> server_names; |
| 47 | + while (server_name_list_length > 0) { |
| 48 | + PX_ASSIGN_OR(auto server_name_type, decoder->ExtractBEInt<uint8_t>(), |
| 49 | + return error::Internal("Failed to extract server name type")); |
| 50 | + |
| 51 | + // This is the only valid value for server_name_type and corresponds to host_name. |
| 52 | + DCHECK_EQ(server_name_type, 0); |
| 53 | + |
| 54 | + PX_ASSIGN_OR(auto server_name_length, decoder->ExtractBEInt<uint16_t>(), |
| 55 | + return error::Internal("Failed to extract server name length")); |
| 56 | + PX_ASSIGN_OR(auto server_name, decoder->ExtractString(server_name_length), |
| 57 | + return error::Internal("Failed to extract server name")); |
| 58 | + |
| 59 | + server_names.push_back(std::string(server_name)); |
| 60 | + server_name_list_length -= kSNIExtensionMinimumLength + server_name_length; |
| 61 | + } |
| 62 | + exts->insert({"server_name", ToJSONString(server_names)}); |
| 63 | + return ParseState::kSuccess; |
| 64 | +} |
| 65 | + |
| 66 | +/* |
| 67 | + * The TLS wire protocol is best described in each of the RFCs for the protocol |
| 68 | + * SSL v3.0: https://tools.ietf.org/html/rfc6101 |
| 69 | + * TLS v1.0: https://tools.ietf.org/html/rfc2246 |
| 70 | + * TLS v1.1: https://tools.ietf.org/html/rfc4346 |
| 71 | + * TLS v1.2: https://tools.ietf.org/html/rfc5246 |
| 72 | + * TLS v1.3: https://tools.ietf.org/html/rfc8446 |
| 73 | + * |
| 74 | + * These specs have c struct style definitions of the wire protocol. The wikipedia |
| 75 | + * page is also a good resource to see it explained in a more typical ascii binary format |
| 76 | + * diagram: https://en.wikipedia.org/wiki/Transport_Layer_Security#TLS_record |
| 77 | + */ |
| 78 | + |
| 79 | +ParseState ParseFullFrame(BinaryDecoder* decoder, Frame* frame) { |
| 80 | + PX_ASSIGN_OR(auto raw_content_type, decoder->ExtractBEInt<uint8_t>(), |
| 81 | + return ParseState::kInvalid); |
| 82 | + auto content_type = magic_enum::enum_cast<tls::ContentType>(raw_content_type); |
| 83 | + if (!content_type.has_value()) { |
| 84 | + return ParseState::kInvalid; |
| 85 | + } |
| 86 | + frame->content_type = content_type.value(); |
| 87 | + |
| 88 | + PX_ASSIGN_OR(auto legacy_version, decoder->ExtractBEInt<uint16_t>(), return ParseState::kInvalid); |
| 89 | + auto lv = magic_enum::enum_cast<tls::LegacyVersion>(legacy_version); |
| 90 | + if (!lv.has_value()) { |
| 91 | + return ParseState::kInvalid; |
| 92 | + } |
| 93 | + frame->legacy_version = lv.value(); |
| 94 | + |
| 95 | + PX_ASSIGN_OR(frame->length, decoder->ExtractBEInt<uint16_t>(), return ParseState::kInvalid); |
| 96 | + |
| 97 | + if (frame->content_type == tls::ContentType::kApplicationData || |
| 98 | + frame->content_type == tls::ContentType::kChangeCipherSpec || |
| 99 | + frame->content_type == tls::ContentType::kAlert || |
| 100 | + frame->content_type == tls::ContentType::kHeartbeat) { |
| 101 | + if (!decoder->ExtractBufIgnore(frame->length).ok()) { |
| 102 | + return ParseState::kInvalid; |
| 103 | + } |
| 104 | + return ParseState::kSuccess; |
| 105 | + } |
| 106 | + |
| 107 | + PX_ASSIGN_OR(auto raw_handshake_type, decoder->ExtractBEInt<uint8_t>(), |
| 108 | + return ParseState::kInvalid); |
| 109 | + auto handshake_type = magic_enum::enum_cast<tls::HandshakeType>(raw_handshake_type); |
| 110 | + if (!handshake_type.has_value()) { |
| 111 | + return ParseState::kInvalid; |
| 112 | + } |
| 113 | + frame->handshake_type = handshake_type.value(); |
| 114 | + |
| 115 | + PX_ASSIGN_OR(auto handshake_length, decoder->ExtractBEInt<uint24_t>(), |
| 116 | + return ParseState::kInvalid); |
| 117 | + frame->handshake_length = handshake_length; |
| 118 | + |
| 119 | + PX_ASSIGN_OR(auto raw_handshake_version, decoder->ExtractBEInt<uint16_t>(), |
| 120 | + return ParseState::kInvalid); |
| 121 | + auto handshake_version = magic_enum::enum_cast<tls::LegacyVersion>(raw_handshake_version); |
| 122 | + if (!handshake_version.has_value()) { |
| 123 | + return ParseState::kInvalid; |
| 124 | + } |
| 125 | + frame->handshake_version = handshake_version.value(); |
| 126 | + |
| 127 | + // Skip the random struct. |
| 128 | + if (!decoder->ExtractBufIgnore(kRandomStructLength).ok()) { |
| 129 | + return ParseState::kInvalid; |
| 130 | + } |
| 131 | + |
| 132 | + PX_ASSIGN_OR(auto session_id_len, decoder->ExtractBEInt<uint8_t>(), return ParseState::kInvalid); |
| 133 | + if (session_id_len > 32) { |
| 134 | + return ParseState::kInvalid; |
| 135 | + } |
| 136 | + |
| 137 | + if (session_id_len > 0) { |
| 138 | + PX_ASSIGN_OR(frame->session_id, decoder->ExtractString(session_id_len), |
| 139 | + return ParseState::kInvalid); |
| 140 | + } |
| 141 | + |
| 142 | + PX_ASSIGN_OR(auto cipher_suite_length, decoder->ExtractBEInt<uint16_t>(), |
| 143 | + return ParseState::kInvalid); |
| 144 | + if (frame->handshake_type == HandshakeType::kClientHello) { |
| 145 | + if (!decoder->ExtractBufIgnore(cipher_suite_length).ok()) { |
| 146 | + return ParseState::kInvalid; |
| 147 | + } |
| 148 | + } |
| 149 | + |
| 150 | + PX_ASSIGN_OR(auto compression_methods_length, decoder->ExtractBEInt<uint8_t>(), |
| 151 | + return ParseState::kInvalid); |
| 152 | + if (frame->handshake_type == HandshakeType::kClientHello) { |
| 153 | + if (!decoder->ExtractBufIgnore(compression_methods_length).ok()) { |
| 154 | + return ParseState::kInvalid; |
| 155 | + } |
| 156 | + } |
| 157 | + |
| 158 | + // TODO(ddelnano): Test TLS 1.2 and earlier where extensions are not present |
| 159 | + PX_ASSIGN_OR(auto extensions_length, decoder->ExtractBEInt<uint16_t>(), |
| 160 | + return ParseState::kInvalid); |
| 161 | + if (extensions_length == 0) { |
| 162 | + return ParseState::kSuccess; |
| 163 | + } |
| 164 | + |
| 165 | + while (extensions_length > 0) { |
| 166 | + PX_ASSIGN_OR(auto extension_type, decoder->ExtractBEInt<uint16_t>(), |
| 167 | + return ParseState::kInvalid); |
| 168 | + PX_ASSIGN_OR(auto extension_length, decoder->ExtractBEInt<uint16_t>(), |
| 169 | + return ParseState::kInvalid); |
| 170 | + |
| 171 | + if (extension_length > 0) { |
| 172 | + if (extension_type == 0x00) { |
| 173 | + if (!ExtractSNIExtension(&frame->extensions, decoder).ok()) { |
| 174 | + return ParseState::kInvalid; |
| 175 | + } |
| 176 | + } else { |
| 177 | + if (!decoder->ExtractBufIgnore(extension_length).ok()) { |
| 178 | + return ParseState::kInvalid; |
| 179 | + } |
| 180 | + } |
| 181 | + } |
| 182 | + |
| 183 | + extensions_length -= kExtensionMinimumLength + extension_length; |
| 184 | + } |
| 185 | + |
| 186 | + return ParseState::kSuccess; |
| 187 | +} |
| 188 | + |
| 189 | +} // namespace tls |
| 190 | + |
| 191 | +template <> |
| 192 | +ParseState ParseFrame(message_type_t, std::string_view* buf, tls::Frame* frame, NoState*) { |
| 193 | + // TLS record header is 5 bytes. The size of the record is in bytes 4 and 5. |
| 194 | + if (buf->length() < tls::kTLSRecordHeaderLength) { |
| 195 | + return ParseState::kNeedsMoreData; |
| 196 | + } |
| 197 | + uint16_t length = static_cast<uint8_t>((*buf)[3]) << 8 | static_cast<uint8_t>((*buf)[4]); |
| 198 | + if (buf->length() < length + tls::kTLSRecordHeaderLength) { |
| 199 | + return ParseState::kNeedsMoreData; |
| 200 | + } |
| 201 | + |
| 202 | + BinaryDecoder decoder(*buf); |
| 203 | + auto parse_result = tls::ParseFullFrame(&decoder, frame); |
| 204 | + if (parse_result == ParseState::kSuccess) { |
| 205 | + buf->remove_prefix(length + tls::kTLSRecordHeaderLength); |
| 206 | + } |
| 207 | + return parse_result; |
| 208 | +} |
| 209 | + |
| 210 | +template <> |
| 211 | +size_t FindFrameBoundary<tls::Frame>(message_type_t, std::string_view, size_t, NoState*) { |
| 212 | + // Not implemented. |
| 213 | + return std::string::npos; |
| 214 | +} |
| 215 | + |
| 216 | +} // namespace protocols |
| 217 | +} // namespace stirling |
| 218 | +} // namespace px |
0 commit comments