Botan 2.19.1
Crypto and TLS for C&
tls_session.cpp
Go to the documentation of this file.
1/*
2* TLS Session State
3* (C) 2011-2012,2015,2019 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/tls_session.h>
9#include <botan/loadstor.h>
10#include <botan/der_enc.h>
11#include <botan/ber_dec.h>
12#include <botan/asn1_obj.h>
13#include <botan/pem.h>
14#include <botan/aead.h>
15#include <botan/mac.h>
16#include <botan/rng.h>
17
18namespace Botan {
19
20namespace TLS {
21
22Session::Session(const std::vector<uint8_t>& session_identifier,
23 const secure_vector<uint8_t>& master_secret,
24 Protocol_Version version,
25 uint16_t ciphersuite,
26 Connection_Side side,
27 bool extended_master_secret,
28 bool encrypt_then_mac,
29 const std::vector<X509_Certificate>& certs,
30 const std::vector<uint8_t>& ticket,
31 const Server_Information& server_info,
32 const std::string& srp_identifier,
33 uint16_t srtp_profile) :
34 m_start_time(std::chrono::system_clock::now()),
35 m_identifier(session_identifier),
36 m_session_ticket(ticket),
37 m_master_secret(master_secret),
38 m_version(version),
39 m_ciphersuite(ciphersuite),
40 m_connection_side(side),
41 m_srtp_profile(srtp_profile),
42 m_extended_master_secret(extended_master_secret),
43 m_encrypt_then_mac(encrypt_then_mac),
44 m_peer_certs(certs),
45 m_server_info(server_info),
46 m_srp_identifier(srp_identifier)
47 {
48 }
49
50Session::Session(const std::string& pem)
51 {
53
54 *this = Session(der.data(), der.size());
55 }
56
57Session::Session(const uint8_t ber[], size_t ber_len)
58 {
59 uint8_t side_code = 0;
60
61 ASN1_String server_hostname;
62 ASN1_String server_service;
63 size_t server_port;
64
65 ASN1_String srp_identifier_str;
66
67 uint8_t major_version = 0, minor_version = 0;
68 std::vector<uint8_t> peer_cert_bits;
69
70 size_t start_time = 0;
71 size_t srtp_profile = 0;
72 size_t fragment_size = 0;
73 size_t compression_method = 0;
74
75 BER_Decoder(ber, ber_len)
77 .decode_and_check(static_cast<size_t>(TLS_SESSION_PARAM_STRUCT_VERSION),
78 "Unknown version in serialized TLS session")
80 .decode_integer_type(major_version)
81 .decode_integer_type(minor_version)
82 .decode(m_identifier, OCTET_STRING)
83 .decode(m_session_ticket, OCTET_STRING)
84 .decode_integer_type(m_ciphersuite)
85 .decode_integer_type(compression_method)
86 .decode_integer_type(side_code)
87 .decode_integer_type(fragment_size)
88 .decode(m_extended_master_secret)
89 .decode(m_encrypt_then_mac)
90 .decode(m_master_secret, OCTET_STRING)
91 .decode(peer_cert_bits, OCTET_STRING)
92 .decode(server_hostname)
93 .decode(server_service)
94 .decode(server_port)
95 .decode(srp_identifier_str)
96 .decode(srtp_profile)
97 .end_cons()
98 .verify_end();
99
100 /*
101 * Compression is not supported and must be zero
102 */
103 if(compression_method != 0)
104 {
105 throw Decoding_Error("Serialized TLS session contains non-null compression method");
106 }
107
108 /*
109 Fragment size is not supported anymore, but the field is still
110 set in the session object.
111 */
112 if(fragment_size != 0)
113 {
114 throw Decoding_Error("Serialized TLS session used maximum fragment length which is "
115 " no longer supported");
116 }
117
118 m_version = Protocol_Version(major_version, minor_version);
119 m_start_time = std::chrono::system_clock::from_time_t(start_time);
120 m_connection_side = static_cast<Connection_Side>(side_code);
121 m_srtp_profile = static_cast<uint16_t>(srtp_profile);
122
123 m_server_info = Server_Information(server_hostname.value(),
124 server_service.value(),
125 static_cast<uint16_t>(server_port));
126
127 m_srp_identifier = srp_identifier_str.value();
128
129 if(!peer_cert_bits.empty())
130 {
131 DataSource_Memory certs(peer_cert_bits.data(), peer_cert_bits.size());
132
133 while(!certs.end_of_data())
134 m_peer_certs.push_back(X509_Certificate(certs));
135 }
136 }
137
139 {
140 std::vector<uint8_t> peer_cert_bits;
141 for(size_t i = 0; i != m_peer_certs.size(); ++i)
142 peer_cert_bits += m_peer_certs[i].BER_encode();
143
144 return DER_Encoder()
146 .encode(static_cast<size_t>(TLS_SESSION_PARAM_STRUCT_VERSION))
147 .encode(static_cast<size_t>(std::chrono::system_clock::to_time_t(m_start_time)))
148 .encode(static_cast<size_t>(m_version.major_version()))
149 .encode(static_cast<size_t>(m_version.minor_version()))
150 .encode(m_identifier, OCTET_STRING)
151 .encode(m_session_ticket, OCTET_STRING)
152 .encode(static_cast<size_t>(m_ciphersuite))
153 .encode(static_cast<size_t>(/*old compression method*/0))
154 .encode(static_cast<size_t>(m_connection_side))
155 .encode(static_cast<size_t>(/*old fragment size*/0))
156 .encode(m_extended_master_secret)
157 .encode(m_encrypt_then_mac)
158 .encode(m_master_secret, OCTET_STRING)
159 .encode(peer_cert_bits, OCTET_STRING)
160 .encode(ASN1_String(m_server_info.hostname(), UTF8_STRING))
161 .encode(ASN1_String(m_server_info.service(), UTF8_STRING))
162 .encode(static_cast<size_t>(m_server_info.port()))
163 .encode(ASN1_String(m_srp_identifier, UTF8_STRING))
164 .encode(static_cast<size_t>(m_srtp_profile))
165 .end_cons()
166 .get_contents();
167 }
168
169std::string Session::PEM_encode() const
170 {
171 return PEM_Code::encode(this->DER_encode(), "TLS SESSION");
172 }
173
174std::chrono::seconds Session::session_age() const
175 {
176 return std::chrono::duration_cast<std::chrono::seconds>(
177 std::chrono::system_clock::now() - m_start_time);
178 }
179
180namespace {
181
182// The output length of the HMAC must be a valid keylength for the AEAD
183const char* TLS_SESSION_CRYPT_HMAC = "HMAC(SHA-512-256)";
184// SIV would be better, but we can't assume it is available
185const char* TLS_SESSION_CRYPT_AEAD = "AES-256/GCM";
186const char* TLS_SESSION_CRYPT_KEY_NAME = "BOTAN TLS SESSION KEY NAME";
187const uint64_t TLS_SESSION_CRYPT_MAGIC = 0x068B5A9D396C0000;
188const size_t TLS_SESSION_CRYPT_MAGIC_LEN = 8;
189const size_t TLS_SESSION_CRYPT_KEY_NAME_LEN = 4;
190const size_t TLS_SESSION_CRYPT_AEAD_NONCE_LEN = 12;
191const size_t TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN = 16;
192const size_t TLS_SESSION_CRYPT_AEAD_TAG_SIZE = 16;
193
194const size_t TLS_SESSION_CRYPT_HDR_LEN =
195 TLS_SESSION_CRYPT_MAGIC_LEN +
196 TLS_SESSION_CRYPT_KEY_NAME_LEN +
197 TLS_SESSION_CRYPT_AEAD_NONCE_LEN +
198 TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN;
199
200const size_t TLS_SESSION_CRYPT_OVERHEAD =
201 TLS_SESSION_CRYPT_HDR_LEN + TLS_SESSION_CRYPT_AEAD_TAG_SIZE;
202
203}
204
205std::vector<uint8_t>
207 {
208 auto hmac = MessageAuthenticationCode::create_or_throw(TLS_SESSION_CRYPT_HMAC);
209 hmac->set_key(key);
210
211 // First derive the "key name"
212 std::vector<uint8_t> key_name(hmac->output_length());
213 hmac->update(TLS_SESSION_CRYPT_KEY_NAME);
214 hmac->final(key_name.data());
215 key_name.resize(TLS_SESSION_CRYPT_KEY_NAME_LEN);
216
217 std::vector<uint8_t> aead_nonce;
218 std::vector<uint8_t> key_seed;
219
220 rng.random_vec(aead_nonce, TLS_SESSION_CRYPT_AEAD_NONCE_LEN);
221 rng.random_vec(key_seed, TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN);
222
223 hmac->update(key_seed);
224 const secure_vector<uint8_t> aead_key = hmac->final();
225
226 secure_vector<uint8_t> bits = this->DER_encode();
227
228 // create the header
229 std::vector<uint8_t> buf;
230 buf.reserve(TLS_SESSION_CRYPT_OVERHEAD + bits.size());
231 buf.resize(TLS_SESSION_CRYPT_MAGIC_LEN);
232 store_be(TLS_SESSION_CRYPT_MAGIC, &buf[0]);
233 buf += key_name;
234 buf += key_seed;
235 buf += aead_nonce;
236
237 std::unique_ptr<AEAD_Mode> aead = AEAD_Mode::create_or_throw(TLS_SESSION_CRYPT_AEAD, ENCRYPTION);
238 BOTAN_ASSERT_NOMSG(aead->valid_nonce_length(TLS_SESSION_CRYPT_AEAD_NONCE_LEN));
239 BOTAN_ASSERT_NOMSG(aead->tag_size() == TLS_SESSION_CRYPT_AEAD_TAG_SIZE);
240 aead->set_key(aead_key);
241 aead->set_associated_data_vec(buf);
242 aead->start(aead_nonce);
243 aead->finish(bits, 0);
244
245 // append the ciphertext
246 buf += bits;
247 return buf;
248 }
249
250Session Session::decrypt(const uint8_t in[], size_t in_len, const SymmetricKey& key)
251 {
252 try
253 {
254 const size_t min_session_size = 48 + 4; // serious under-estimate
255 if(in_len < TLS_SESSION_CRYPT_OVERHEAD + min_session_size)
256 throw Decoding_Error("Encrypted session too short to be valid");
257
258 const uint8_t* magic = &in[0];
259 const uint8_t* key_name = magic + TLS_SESSION_CRYPT_MAGIC_LEN;
260 const uint8_t* key_seed = key_name + TLS_SESSION_CRYPT_KEY_NAME_LEN;
261 const uint8_t* aead_nonce = key_seed + TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN;
262 const uint8_t* ctext = aead_nonce + TLS_SESSION_CRYPT_AEAD_NONCE_LEN;
263 const size_t ctext_len = in_len - TLS_SESSION_CRYPT_HDR_LEN; // includes the tag
264
265 if(load_be<uint64_t>(magic, 0) != TLS_SESSION_CRYPT_MAGIC)
266 throw Decoding_Error("Missing expected magic numbers");
267
268 auto hmac = MessageAuthenticationCode::create_or_throw(TLS_SESSION_CRYPT_HMAC);
269 hmac->set_key(key);
270
271 // First derive and check the "key name"
272 std::vector<uint8_t> cmp_key_name(hmac->output_length());
273 hmac->update(TLS_SESSION_CRYPT_KEY_NAME);
274 hmac->final(cmp_key_name.data());
275
276 if(same_mem(cmp_key_name.data(), key_name, TLS_SESSION_CRYPT_KEY_NAME_LEN) == false)
277 throw Decoding_Error("Wrong key name for encrypted session");
278
279 hmac->update(key_seed, TLS_SESSION_CRYPT_AEAD_KEY_SEED_LEN);
280 const secure_vector<uint8_t> aead_key = hmac->final();
281
282 auto aead = AEAD_Mode::create_or_throw(TLS_SESSION_CRYPT_AEAD, DECRYPTION);
283 aead->set_key(aead_key);
284 aead->set_associated_data(in, TLS_SESSION_CRYPT_HDR_LEN);
285 aead->start(aead_nonce, TLS_SESSION_CRYPT_AEAD_NONCE_LEN);
286 secure_vector<uint8_t> buf(ctext, ctext + ctext_len);
287 aead->finish(buf, 0);
288 return Session(buf.data(), buf.size());
289 }
290 catch(std::exception& e)
291 {
292 throw Decoding_Error("Failed to decrypt serialized TLS session: " +
293 std::string(e.what()));
294 }
295 }
296
297}
298
299}
#define BOTAN_ASSERT_NOMSG(expr)
Definition: assert.h:68
static std::unique_ptr< AEAD_Mode > create_or_throw(const std::string &algo, Cipher_Dir direction, const std::string &provider="")
Definition: aead.cpp:50
const std::string & value() const
Definition: asn1_obj.h:400
BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: ber_dec.cpp:290
BER_Decoder & decode(bool &out)
Definition: ber_dec.h:170
BER_Decoder & decode_and_check(const T &expected, const std::string &error_msg)
Definition: ber_dec.h:277
BER_Decoder & verify_end()
Definition: ber_dec.cpp:208
BER_Decoder & end_cons()
Definition: ber_dec.cpp:300
BER_Decoder & decode_integer_type(T &out)
Definition: ber_dec.h:242
secure_vector< uint8_t > get_contents()
Definition: der_enc.cpp:152
DER_Encoder & start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: der_enc.cpp:181
DER_Encoder & end_cons()
Definition: der_enc.cpp:191
DER_Encoder & encode(bool b)
Definition: der_enc.cpp:285
bool end_of_data() const override
Definition: data_src.cpp:90
static std::unique_ptr< MessageAuthenticationCode > create_or_throw(const std::string &algo_spec, const std::string &provider="")
Definition: mac.cpp:141
secure_vector< uint8_t > random_vec(size_t bytes)
Definition: rng.h:143
uint8_t major_version() const
Definition: tls_version.h:79
uint8_t minor_version() const
Definition: tls_version.h:84
std::string hostname() const
secure_vector< uint8_t > DER_encode() const
std::vector< uint8_t > encrypt(const SymmetricKey &key, RandomNumberGenerator &rng) const
std::string PEM_encode() const
std::chrono::system_clock::time_point start_time() const
Definition: tls_session.h:168
std::chrono::seconds session_age() const
static Session decrypt(const uint8_t ctext[], size_t ctext_size, const SymmetricKey &key)
std::string encode(const uint8_t der[], size_t length, const std::string &label, size_t width)
Definition: pem.cpp:43
secure_vector< uint8_t > decode_check_label(DataSource &source, const std::string &label_want)
Definition: pem.cpp:54
secure_vector< uint8_t > BER_encode(const Private_Key &key)
Definition: pkcs8.cpp:139
Definition: alg_id.cpp:13
void store_be(uint16_t in, uint8_t out[2])
Definition: loadstor.h:438
@ DECRYPTION
Definition: cipher_mode.h:23
@ ENCRYPTION
Definition: cipher_mode.h:23
uint64_t load_be< uint64_t >(const uint8_t in[], size_t off)
Definition: loadstor.h:217
bool same_mem(const T *p1, const T *p2, size_t n)
Definition: mem_ops.h:217
@ UTF8_STRING
Definition: asn1_obj.h:45
@ SEQUENCE
Definition: asn1_obj.h:42
@ OCTET_STRING
Definition: asn1_obj.h:38
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:65
Definition: bigint.h:1143