Botan 2.19.5 Crypto and TLS for C&

Public Member Functions | List of all members
Botan::TLS::Client_Key_Exchange Class Referencefinal

`#include <tls_messages.h>`

Inheritance diagram for Botan::TLS::Client_Key_Exchange:

## Public Member Functions
| Client_Key_Exchange (const std::vector< uint8_t > &buf, const Handshake_State &state, const Private_Key *server_rsa_kex_key, Credentials_Manager &creds, const Policy &policy, RandomNumberGenerator &rng)
| Client_Key_Exchange (Handshake_IO &io, Handshake_State &state, const Policy &policy, Credentials_Manager &creds, const Public_Key *server_public_key, const std::string &hostname, RandomNumberGenerator &rng)
const secure_vector< uint8_t > & | pre_master_secret () const
Handshake_Type | type () const override
std::string | type_string () const

## Detailed Description

Client Key Exchange Message

Definition at line 338 of file tls_messages.h.

## Constructor & Destructor Documentation

## ◆ Client_Key_Exchange() [1/2]

Botan::TLS::Client_Key_Exchange::Client_Key_Exchange | ( | Handshake_IO & | io,
|  | Handshake_State & | state,
|  | const Policy & | policy,
|  | Credentials_Manager & | creds,
|  | const Public_Key * | server_public_key,
|  | const std::string & | hostname,
|  | RandomNumberGenerator & | rng
| ) |  |

Definition at line 37 of file msg_client_kex.cpp.

44 {
45 const Kex_Algo kex_algo = state.ciphersuite().kex_method();
46
47 if(kex_algo == Kex_Algo::PSK)
48 {
49 std::string identity_hint = "";
50
51 if(state.server_kex())
52 {
53 TLS_Data_Reader reader("ClientKeyExchange", state.server_kex()->params());
54 identity_hint = reader.get_string(2, 0, 65535);
55 }
56
57 const std::string psk_identity =
58 creds.psk_identity("tls-client", hostname, identity_hint);
59
60 append_tls_length_value(m_key_material, psk_identity, 2);
61
62 SymmetricKey psk = creds.psk("tls-client", hostname, psk_identity);
63
64 std::vector<uint8_t> zeros(psk.length());
65
66 append_tls_length_value(m_pre_master, zeros, 2);
67 append_tls_length_value(m_pre_master, psk.bits_of(), 2);
68 }
69 else if(state.server_kex())
70 {
71 TLS_Data_Reader reader("ClientKeyExchange", state.server_kex()->params());
72
73 SymmetricKey psk;
74
75 if(kex_algo == Kex_Algo::DHE_PSK ||
76 kex_algo == Kex_Algo::ECDHE_PSK)
77 {
78 std::string identity_hint = reader.get_string(2, 0, 65535);
79
80 const std::string psk_identity =
81 creds.psk_identity("tls-client", hostname, identity_hint);
82
83 append_tls_length_value(m_key_material, psk_identity, 2);
84
85 psk = creds.psk("tls-client", hostname, psk_identity);
86 }
87
88 if(kex_algo == Kex_Algo::DH ||
89 kex_algo == Kex_Algo::DHE_PSK)
90 {
91 const std::vector<uint8_t> modulus = reader.get_range<uint8_t>(2, 1, 65535);
92 const std::vector<uint8_t> generator = reader.get_range<uint8_t>(2, 1, 65535);
93 const std::vector<uint8_t> peer_public_value = reader.get_range<uint8_t>(2, 1, 65535);
94
95 if(reader.remaining_bytes())
96 throw Decoding_Error("Bad params size for DH key exchange");
97
98 const std::pair<secure_vector<uint8_t>, std::vector<uint8_t>> dh_result =
99 state.callbacks().tls_dh_agree(modulus, generator, peer_public_value, policy, rng);
100
101 if(kex_algo == Kex_Algo::DH)
102 m_pre_master = dh_result.first;
103 else
104 {
105 append_tls_length_value(m_pre_master, dh_result.first, 2);
106 append_tls_length_value(m_pre_master, psk.bits_of(), 2);
107 }
108
109 append_tls_length_value(m_key_material, dh_result.second, 2);
110 }
111 else if(kex_algo == Kex_Algo::ECDH ||
112 kex_algo == Kex_Algo::ECDHE_PSK)
113 {
114 const uint8_t curve_type = reader.get_byte();
115 if(curve_type != 3)
116 throw Decoding_Error("Server sent non-named ECC curve");
117
118 const Group_Params curve_id = static_cast<Group_Params>(reader.get_uint16_t());
119 const std::vector<uint8_t> peer_public_value = reader.get_range<uint8_t>(1, 1, 255);
120
121 if(policy.choose_key_exchange_group({curve_id}) != curve_id)
122 {
123 throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
124 "Server sent ECC curve prohibited by policy");
125 }
126
127 const std::string curve_name = state.callbacks().tls_decode_group_param(curve_id);
128
129 if(curve_name == "")
130 throw Decoding_Error("Server sent unknown named curve " +
131 std::to_string(static_cast<uint16_t>(curve_id)));
132
133 const std::pair<secure_vector<uint8_t>, std::vector<uint8_t>> ecdh_result =
134 state.callbacks().tls_ecdh_agree(curve_name, peer_public_value, policy, rng,
135 state.server_hello()->prefers_compressed_ec_points());
136
137 if(kex_algo == Kex_Algo::ECDH)
138 {
139 m_pre_master = ecdh_result.first;
140 }
141 else
142 {
143 append_tls_length_value(m_pre_master, ecdh_result.first, 2);
144 append_tls_length_value(m_pre_master, psk.bits_of(), 2);
145 }
146
147 append_tls_length_value(m_key_material, ecdh_result.second, 1);
148 }
149#if defined(BOTAN_HAS_SRP6)
150 else if(kex_algo == Kex_Algo::SRP_SHA)
151 {
152 const BigInt N = BigInt::decode(reader.get_range<uint8_t>(2, 1, 65535));
153 const BigInt g = BigInt::decode(reader.get_range<uint8_t>(2, 1, 65535));
154 std::vector<uint8_t> salt = reader.get_range<uint8_t>(1, 1, 255);
155 const BigInt B = BigInt::decode(reader.get_range<uint8_t>(2, 1, 65535));
156
157 const std::string srp_group = srp6_group_identifier(N, g);
158
159 const std::string srp_identifier =
160 creds.srp_identifier("tls-client", hostname);
161
162 const std::string srp_password =
163 creds.srp_password("tls-client", hostname, srp_identifier);
164
165 std::pair<BigInt, SymmetricKey> srp_vals =
166 srp6_client_agree(srp_identifier,
167 srp_password,
168 srp_group,
169 "SHA-1",
170 salt,
171 B,
172 rng);
173
174 append_tls_length_value(m_key_material, BigInt::encode(srp_vals.first), 2);
175 m_pre_master = srp_vals.second.bits_of();
176 }
177#endif
178
179#if defined(BOTAN_HAS_CECPQ1)
180 else if(kex_algo == Kex_Algo::CECPQ1)
181 {
182 const std::vector<uint8_t> cecpq1_offer = reader.get_range<uint8_t>(2, 1, 65535);
183
184 if(cecpq1_offer.size() != CECPQ1_OFFER_BYTES)
185 throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Invalid CECPQ1 key size");
186
187 std::vector<uint8_t> newhope_accept(CECPQ1_ACCEPT_BYTES);
188 secure_vector<uint8_t> shared_secret(CECPQ1_SHARED_KEY_BYTES);
189 CECPQ1_accept(shared_secret.data(), newhope_accept.data(), cecpq1_offer.data(), rng);
190 append_tls_length_value(m_key_material, newhope_accept, 2);
191 m_pre_master = shared_secret;
192 }
193#endif
194 else
195 {
196 throw Internal_Error("Client_Key_Exchange: Unknown key exchange method was negotiated");
197 }
198
199 reader.assert_done();
200 }
201 else
202 {
203 // No server key exchange msg better mean RSA kex + RSA key in cert
204
205 if(kex_algo != Kex_Algo::STATIC_RSA)
206 throw Unexpected_Message("No server kex message, but negotiated a key exchange that required it");
207
208 if(!server_public_key)
209 throw Internal_Error("No server public key for RSA exchange");
210
211 if(auto rsa_pub = dynamic_cast<const RSA_PublicKey*>(server_public_key))
212 {
213 const Protocol_Version offered_version = state.client_hello()->version();
214
215 rng.random_vec(m_pre_master, 48);
216 m_pre_master[0] = offered_version.major_version();
217 m_pre_master[1] = offered_version.minor_version();
218
219 PK_Encryptor_EME encryptor(*rsa_pub, rng, "PKCS1v15");
220
221 const std::vector<uint8_t> encrypted_key = encryptor.encrypt(m_pre_master, rng);
222
223 append_tls_length_value(m_key_material, encrypted_key, 2);
224 }
225 else
226 throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
227 "Expected a RSA key in server cert but got " +
228 server_public_key->algo_name());
229 }
230
231 state.hash().update(io.send(*this));
232 }
Botan::BigInt::decode
static BigInt decode(const uint8_t buf[], size_t length)
Definition: bigint.h:817
Botan::BigInt::encode
static std::vector< uint8_t > encode(const BigInt &n)
Definition: bigint.h:782
Botan::TLS::Alert::HANDSHAKE_FAILURE
@ HANDSHAKE_FAILURE
Definition: tls_alert.h:34
Botan::ASN1::to_string
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:213
Botan::OCSP::Response_Status_Code::Internal_Error
@ Internal_Error
Botan::TLS::Group_Params
Group_Params
Definition: tls_algos.h:123
Botan::TLS::append_tls_length_value
void append_tls_length_value(std::vector< uint8_t, Alloc > &buf, const T *vals, size_t vals_size, size_t tag_size)
Definition: tls_reader.h:185
Botan::TLS::Kex_Algo
Kex_Algo
Definition: tls_algos.h:146
Botan::TLS::Kex_Algo::ECDH
@ ECDH
Botan::TLS::Kex_Algo::PSK
@ PSK
Botan::TLS::Kex_Algo::DHE_PSK
@ DHE_PSK
Botan::TLS::Kex_Algo::ECDHE_PSK
@ ECDHE_PSK
Botan::TLS::Kex_Algo::SRP_SHA
@ SRP_SHA
Botan::TLS::Kex_Algo::CECPQ1
@ CECPQ1
Botan::TLS::Kex_Algo::STATIC_RSA
@ STATIC_RSA
Botan::TLS::Kex_Algo::DH
@ DH
Botan::srp6_client_agree
std::pair< BigInt, SymmetricKey > srp6_client_agree(const std::string &identifier, const std::string &password, const std::string &group_id, const std::string &hash_id, const std::vector< uint8_t > &salt, const BigInt &B, RandomNumberGenerator &rng)
Definition: srp6.cpp:77
Botan::CECPQ1_ACCEPT_BYTES
@ CECPQ1_ACCEPT_BYTES
Definition: newhope.h:48
Botan::CECPQ1_SHARED_KEY_BYTES
@ CECPQ1_SHARED_KEY_BYTES
Definition: newhope.h:49
Botan::CECPQ1_OFFER_BYTES
@ CECPQ1_OFFER_BYTES
Definition: newhope.h:47
Botan::SymmetricKey
OctetString SymmetricKey
Definition: symkey.h:141
Botan::srp6_group_identifier
std::string srp6_group_identifier(const BigInt &N, const BigInt &g)
Definition: srp6.cpp:53
Botan::CECPQ1_accept
void CECPQ1_accept(uint8_t shared_key[CECPQ1_SHARED_KEY_BYTES], uint8_t send[CECPQ1_ACCEPT_BYTES], const uint8_t received[CECPQ1_OFFER_BYTES], RandomNumberGenerator &rng)
Definition: cecpq1.cpp:26
server_public_key
std::unique_ptr< Public_Key > server_public_key
Definition: tls_client.cpp:53

References Botan::TLS::append_tls_length_value(), Botan::OctetString::bits_of(), Botan::TLS::Handshake_State::callbacks(), Botan::TLS::CECPQ1, Botan::CECPQ1_accept(), Botan::CECPQ1_ACCEPT_BYTES, Botan::CECPQ1_OFFER_BYTES, Botan::CECPQ1_SHARED_KEY_BYTES, Botan::TLS::Policy::choose_key_exchange_group(), Botan::TLS::Handshake_State::ciphersuite(), Botan::BigInt::decode(), Botan::TLS::DH, Botan::TLS::DHE_PSK, Botan::TLS::ECDH, Botan::TLS::ECDHE_PSK, Botan::BigInt::encode(), Botan::TLS::TLS_Data_Reader::get_byte(), Botan::TLS::TLS_Data_Reader::get_range(), Botan::TLS::TLS_Data_Reader::get_string(), Botan::TLS::TLS_Data_Reader::get_uint16_t(), Botan::TLS::Alert::HANDSHAKE_FAILURE, Botan::TLS::Ciphersuite::kex_method(), Botan::OctetString::length(), Botan::Credentials_Manager::psk(), Botan::TLS::PSK, Botan::Credentials_Manager::psk_identity(), Botan::TLS::TLS_Data_Reader::remaining_bytes(), Botan::TLS::Handshake_State::server_hello(), Botan::TLS::Handshake_State::server_kex(), Botan::srp6_client_agree(), Botan::srp6_group_identifier(), Botan::Credentials_Manager::srp_identifier(), Botan::Credentials_Manager::srp_password(), Botan::TLS::SRP_SHA, Botan::TLS::Callbacks::tls_decode_group_param(), Botan::TLS::Callbacks::tls_dh_agree(), Botan::TLS::Callbacks::tls_ecdh_agree(), and Botan::ASN1::to_string().

## ◆ Client_Key_Exchange() [2/2]

Botan::TLS::Client_Key_Exchange::Client_Key_Exchange | ( | const std::vector< uint8_t > & | buf,
|  | const Handshake_State & | state,
|  | const Private_Key * | server_rsa_kex_key,
|  | Credentials_Manager & | creds,
|  | const Policy & | policy,
|  | RandomNumberGenerator & | rng
| ) |  |

Definition at line 237 of file msg_client_kex.cpp.

243 {
244 const Kex_Algo kex_algo = state.ciphersuite().kex_method();
245
246 if(kex_algo == Kex_Algo::STATIC_RSA)
247 {
248 BOTAN_ASSERT(state.server_certs() && !state.server_certs()->cert_chain().empty(),
249 "RSA key exchange negotiated so server sent a certificate");
250
251 if(!server_rsa_kex_key)
252 throw Internal_Error("Expected RSA kex but no server kex key set");
253
254 if(!dynamic_cast<const RSA_PrivateKey*>(server_rsa_kex_key))
255 throw Internal_Error("Expected RSA key but got " + server_rsa_kex_key->algo_name());
256
257 TLS_Data_Reader reader("ClientKeyExchange", contents);
258 const std::vector<uint8_t> encrypted_pre_master = reader.get_range<uint8_t>(2, 0, 65535);
259 reader.assert_done();
260
261 PK_Decryptor_EME decryptor(*server_rsa_kex_key, rng, "PKCS1v15");
262
263 const uint8_t client_major = state.client_hello()->version().major_version();
264 const uint8_t client_minor = state.client_hello()->version().minor_version();
265
266 /*
267 * PK_Decryptor::decrypt_or_random will return a random value if
268 * either the length does not match the expected value or if the
269 * version number embedded in the PMS does not match the one sent
270 * in the client hello.
271 */
272 const size_t expected_plaintext_size = 48;
273 const size_t expected_content_size = 2;
274 const uint8_t expected_content_bytes[expected_content_size] = { client_major, client_minor };
275 const uint8_t expected_content_pos[expected_content_size] = { 0, 1 };
276
277 m_pre_master =
278 decryptor.decrypt_or_random(encrypted_pre_master.data(),
279 encrypted_pre_master.size(),
280 expected_plaintext_size,
281 rng,
282 expected_content_bytes,
283 expected_content_pos,
284 expected_content_size);
285 }
286 else
287 {
288 TLS_Data_Reader reader("ClientKeyExchange", contents);
289
290 SymmetricKey psk;
291
292 if(key_exchange_is_psk(kex_algo))
293 {
294 const std::string psk_identity = reader.get_string(2, 0, 65535);
295
296 psk = creds.psk("tls-server",
297 state.client_hello()->sni_hostname(),
298 psk_identity);
299
300 if(psk.length() == 0)
301 {
302 if(policy.hide_unknown_users())
303 psk = SymmetricKey(rng, 16);
304 else
305 throw TLS_Exception(Alert::UNKNOWN_PSK_IDENTITY,
306 "No PSK for identifier " + psk_identity);
307 }
308 }
309
310 if(kex_algo == Kex_Algo::PSK)
311 {
312 std::vector<uint8_t> zeros(psk.length());
313 append_tls_length_value(m_pre_master, zeros, 2);
314 append_tls_length_value(m_pre_master, psk.bits_of(), 2);
315 }
316#if defined(BOTAN_HAS_SRP6)
317 else if(kex_algo == Kex_Algo::SRP_SHA)
318 {
319 SRP6_Server_Session& srp = state.server_kex()->server_srp_params();
320
321 m_pre_master = srp.step2(BigInt::decode(reader.get_range<uint8_t>(2, 0, 65535))).bits_of();
322 }
323#endif
324#if defined(BOTAN_HAS_CECPQ1)
325 else if(kex_algo == Kex_Algo::CECPQ1)
326 {
327 const CECPQ1_key& cecpq1_offer = state.server_kex()->cecpq1_key();
328
329 const std::vector<uint8_t> cecpq1_accept = reader.get_range<uint8_t>(2, 0, 65535);
330 if(cecpq1_accept.size() != CECPQ1_ACCEPT_BYTES)
331 throw Decoding_Error("Invalid size for CECPQ1 accept message");
332
333 m_pre_master.resize(CECPQ1_SHARED_KEY_BYTES);
334 CECPQ1_finish(m_pre_master.data(), cecpq1_offer, cecpq1_accept.data());
335 }
336#endif
337 else if(kex_algo == Kex_Algo::DH ||
338 kex_algo == Kex_Algo::DHE_PSK ||
339 kex_algo == Kex_Algo::ECDH ||
340 kex_algo == Kex_Algo::ECDHE_PSK)
341 {
342 const Private_Key& private_key = state.server_kex()->server_kex_key();
343
344 const PK_Key_Agreement_Key* ka_key =
345 dynamic_cast<const PK_Key_Agreement_Key*>(&private_key);
346
347 if(!ka_key)
348 throw Internal_Error("Expected key agreement key type but got " +
349 private_key.algo_name());
350
351 std::vector<uint8_t> client_pubkey;
352
353 if(ka_key->algo_name() == "DH")
354 {
355 client_pubkey = reader.get_range<uint8_t>(2, 0, 65535);
356 }
357 else
358 {
359 client_pubkey = reader.get_range<uint8_t>(1, 1, 255);
360 }
361
362 try
363 {
364 PK_Key_Agreement ka(*ka_key, rng, "Raw");
365
366 secure_vector<uint8_t> shared_secret = ka.derive_key(0, client_pubkey).bits_of();
367
368 if(ka_key->algo_name() == "DH")
369 shared_secret = CT::strip_leading_zeros(shared_secret);
370
371 if(kex_algo == Kex_Algo::DHE_PSK ||
372 kex_algo == Kex_Algo::ECDHE_PSK)
373 {
374 append_tls_length_value(m_pre_master, shared_secret, 2);
375 append_tls_length_value(m_pre_master, psk.bits_of(), 2);
376 }
377 else
378 m_pre_master = shared_secret;
379 }
380 catch(Invalid_Argument& e)
381 {
382 throw TLS_Exception(Alert::ILLEGAL_PARAMETER, e.what());
383 }
384 catch(std::exception&)
385 {
386 /*
387 * Something failed in the DH/ECDH computation. To avoid possible
388 * attacks which are based on triggering and detecting some edge
389 * failure condition, randomize the pre-master output and carry on,
390 * allowing the protocol to fail later in the finished checks.
391 */
392 rng.random_vec(m_pre_master, ka_key->public_value().size());
393 }
394
395 reader.assert_done();
396 }
397 else
398 throw Internal_Error("Client_Key_Exchange: Unknown key exchange negotiated");
399 }
400 }
BOTAN_ASSERT
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:55
Botan::TLS::Alert::UNKNOWN_PSK_IDENTITY
@ UNKNOWN_PSK_IDENTITY
Definition: tls_alert.h:58
Botan::TLS::Alert::ILLEGAL_PARAMETER
@ ILLEGAL_PARAMETER
Definition: tls_alert.h:41
Botan::CT::strip_leading_zeros
secure_vector< uint8_t > strip_leading_zeros(const uint8_t in[], size_t length)
Definition: ct_utils.cpp:66
Botan::TLS::key_exchange_is_psk
bool key_exchange_is_psk(Kex_Algo m)
Definition: tls_algos.h:160
Botan::CECPQ1_finish
void CECPQ1_finish(uint8_t shared_key[CECPQ1_SHARED_KEY_BYTES], const CECPQ1_key &offer_key, const uint8_t received[CECPQ1_ACCEPT_BYTES])
Definition: cecpq1.cpp:41

References Botan::Public_Key::algo_name(), Botan::TLS::append_tls_length_value(), Botan::TLS::TLS_Data_Reader::assert_done(), Botan::OctetString::bits_of(), BOTAN_ASSERT, Botan::CECPQ1_ACCEPT_BYTES, Botan::CECPQ1_finish(), Botan::CECPQ1_SHARED_KEY_BYTES, Botan::TLS::Handshake_State::ciphersuite(), Botan::TLS::Handshake_State::client_hello(), Botan::BigInt::decode(), Botan::PK_Decryptor::decrypt_or_random(), Botan::PK_Key_Agreement::derive_key(), Botan::TLS::TLS_Data_Reader::get_range(), Botan::TLS::TLS_Data_Reader::get_string(), Botan::TLS::Policy::hide_unknown_users(), Botan::TLS::Ciphersuite::kex_method(), Botan::TLS::key_exchange_is_psk(), Botan::OctetString::length(), Botan::Credentials_Manager::psk(), Botan::PK_Key_Agreement_Key::public_value(), Botan::RandomNumberGenerator::random_vec(), Botan::TLS::Handshake_State::server_certs(), Botan::TLS::Handshake_State::server_kex(), Botan::SRP6_Server_Session::step2(), Botan::CT::strip_leading_zeros(), and Botan::Exception::what().

## Member Function Documentation

## ◆ pre_master_secret()

const secure_vector< uint8_t > & Botan::TLS::Client_Key_Exchange::pre_master_secret | ( |  | ) | const
| inline

Definition at line 343 of file tls_messages.h.

344 { return m_pre_master; }

## ◆ type()

Handshake_Type Botan::TLS::Client_Key_Exchange::type | ( |  | ) | const
| inline override virtual

Returns
  the message type

Implements Botan::TLS::Handshake_Message.

Definition at line 341 of file tls_messages.h.

341{ return CLIENT_KEX; }
Botan::TLS::CLIENT_KEX
@ CLIENT_KEX
Definition: tls_magic.h:56

References Botan::TLS::CLIENT_KEX.

## ◆ type_string()

std::string Botan::TLS::Handshake_Message::type_string | ( |  | ) | const
| inherited

Returns
  string representation of this message type

Definition at line 19 of file tls_handshake_state.cpp.

20 {
21 return handshake_type_to_string(type());
22 }
Botan::TLS::Handshake_Message::type
virtual Handshake_Type type() const =0
Botan::TLS::handshake_type_to_string
const char * handshake_type_to_string(Handshake_Type type)
Definition: tls_handshake_state.cpp:24

References Botan::TLS::handshake_type_to_string(), and Botan::TLS::Handshake_Message::type().

The documentation for this class was generated from the following files:

- src/lib/tls/tls_messages.h
- src/lib/tls/msg_client_kex.cpp