Botan 3.0.0-alpha0
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:
Botan::TLS::Handshake_Message

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
 
virtual Handshake_Type wire_type () const
 

Detailed Description

Client Key Exchange Message

Definition at line 433 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 31 of file msg_client_kex.cpp.

38 {
39 const Kex_Algo kex_algo = state.ciphersuite().kex_method();
40
41 if(kex_algo == Kex_Algo::PSK)
42 {
43 std::string identity_hint = "";
44
45 if(state.server_kex())
46 {
47 TLS_Data_Reader reader("ClientKeyExchange", state.server_kex()->params());
48 identity_hint = reader.get_string(2, 0, 65535);
49 }
50
51 const std::string psk_identity =
52 creds.psk_identity("tls-client", hostname, identity_hint);
53
54 append_tls_length_value(m_key_material, psk_identity, 2);
55
56 SymmetricKey psk = creds.psk("tls-client", hostname, psk_identity);
57
58 std::vector<uint8_t> zeros(psk.length());
59
60 append_tls_length_value(m_pre_master, zeros, 2);
61 append_tls_length_value(m_pre_master, psk.bits_of(), 2);
62 }
63 else if(state.server_kex())
64 {
65 TLS_Data_Reader reader("ClientKeyExchange", state.server_kex()->params());
66
67 SymmetricKey psk;
68
69 if(kex_algo == Kex_Algo::ECDHE_PSK)
70 {
71 std::string identity_hint = reader.get_string(2, 0, 65535);
72
73 const std::string psk_identity =
74 creds.psk_identity("tls-client", hostname, identity_hint);
75
76 append_tls_length_value(m_key_material, psk_identity, 2);
77
78 psk = creds.psk("tls-client", hostname, psk_identity);
79 }
80
81 if(kex_algo == Kex_Algo::DH)
82 {
83 const std::vector<uint8_t> modulus = reader.get_range<uint8_t>(2, 1, 65535);
84 const std::vector<uint8_t> generator = reader.get_range<uint8_t>(2, 1, 65535);
85 const std::vector<uint8_t> peer_public_value = reader.get_range<uint8_t>(2, 1, 65535);
86
87 if(reader.remaining_bytes())
88 throw Decoding_Error("Bad params size for DH key exchange");
89
90 const std::pair<secure_vector<uint8_t>, std::vector<uint8_t>> dh_result =
91 state.callbacks().tls_dh_agree(modulus, generator, peer_public_value, policy, rng);
92
93 if(kex_algo == Kex_Algo::DH)
94 m_pre_master = dh_result.first;
95 else
96 {
97 append_tls_length_value(m_pre_master, dh_result.first, 2);
98 append_tls_length_value(m_pre_master, psk.bits_of(), 2);
99 }
100
101 append_tls_length_value(m_key_material, dh_result.second, 2);
102 }
103 else if(kex_algo == Kex_Algo::ECDH ||
104 kex_algo == Kex_Algo::ECDHE_PSK)
105 {
106 const uint8_t curve_type = reader.get_byte();
107 if(curve_type != 3)
108 throw Decoding_Error("Server sent non-named ECC curve");
109
110 const Group_Params curve_id = static_cast<Group_Params>(reader.get_uint16_t());
111 const std::vector<uint8_t> peer_public_value = reader.get_range<uint8_t>(1, 1, 255);
112
113 if(policy.choose_key_exchange_group({curve_id}) != curve_id)
114 {
115 throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
116 "Server sent ECC curve prohibited by policy");
117 }
118
119 const std::string curve_name = state.callbacks().tls_decode_group_param(curve_id);
120
121 if(curve_name.empty())
122 throw Decoding_Error("Server sent unknown named curve " +
123 std::to_string(static_cast<uint16_t>(curve_id)));
124
125 const std::pair<secure_vector<uint8_t>, std::vector<uint8_t>> ecdh_result =
126 state.callbacks().tls_ecdh_agree(curve_name, peer_public_value, policy, rng,
127 state.server_hello()->prefers_compressed_ec_points());
128
129 if(kex_algo == Kex_Algo::ECDH)
130 {
131 m_pre_master = ecdh_result.first;
132 }
133 else
134 {
135 append_tls_length_value(m_pre_master, ecdh_result.first, 2);
136 append_tls_length_value(m_pre_master, psk.bits_of(), 2);
137 }
138
139 append_tls_length_value(m_key_material, ecdh_result.second, 1);
140 }
141#if defined(BOTAN_HAS_CECPQ1)
142 else if(kex_algo == Kex_Algo::CECPQ1)
143 {
144 const std::vector<uint8_t> cecpq1_offer = reader.get_range<uint8_t>(2, 1, 65535);
145
146 if(cecpq1_offer.size() != CECPQ1_OFFER_BYTES)
147 throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Invalid CECPQ1 key size");
148
149 std::vector<uint8_t> newhope_accept(CECPQ1_ACCEPT_BYTES);
150 secure_vector<uint8_t> shared_secret(CECPQ1_SHARED_KEY_BYTES);
151 CECPQ1_accept(shared_secret.data(), newhope_accept.data(), cecpq1_offer.data(), rng);
152 append_tls_length_value(m_key_material, newhope_accept, 2);
153 m_pre_master = shared_secret;
154 }
155#endif
156 else
157 {
158 throw Internal_Error("Client_Key_Exchange: Unknown key exchange method was negotiated");
159 }
160
161 reader.assert_done();
162 }
163 else
164 {
165 // No server key exchange msg better mean RSA kex + RSA key in cert
166
167 if(kex_algo != Kex_Algo::STATIC_RSA)
168 throw Unexpected_Message("No server kex message, but negotiated a key exchange that required it");
169
171 throw Internal_Error("No server public key for RSA exchange");
172
173 if(auto rsa_pub = dynamic_cast<const RSA_PublicKey*>(server_public_key))
174 {
175 const Protocol_Version offered_version = state.client_hello()->legacy_version();
176
177 rng.random_vec(m_pre_master, 48);
178 m_pre_master[0] = offered_version.major_version();
179 m_pre_master[1] = offered_version.minor_version();
180
181 PK_Encryptor_EME encryptor(*rsa_pub, rng, "PKCS1v15");
182
183 const std::vector<uint8_t> encrypted_key = encryptor.encrypt(m_pre_master, rng);
184
185 append_tls_length_value(m_key_material, encrypted_key, 2);
186 }
187 else
188 throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
189 "Expected a RSA key in server cert but got " +
190 server_public_key->algo_name());
191 }
192
193 state.hash().update(io.send(*this));
194 }
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:209
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:212
@ CECPQ1_ACCEPT_BYTES
Definition: newhope.h:48
@ CECPQ1_SHARED_KEY_BYTES
Definition: newhope.h:49
@ CECPQ1_OFFER_BYTES
Definition: newhope.h:47
OctetString SymmetricKey
Definition: symkey.h:143
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
std::unique_ptr< Public_Key > server_public_key

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::TLS::DH, Botan::TLS::ECDH, Botan::TLS::ECDHE_PSK, 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::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 199 of file msg_client_kex.cpp.

205 {
206 const Kex_Algo kex_algo = state.ciphersuite().kex_method();
207
208 if(kex_algo == Kex_Algo::STATIC_RSA)
209 {
210 BOTAN_ASSERT(state.server_certs() && !state.server_certs()->cert_chain().empty(),
211 "RSA key exchange negotiated so server sent a certificate");
212
213 if(!server_rsa_kex_key)
214 throw Internal_Error("Expected RSA kex but no server kex key set");
215
216 if(server_rsa_kex_key->algo_name() != "RSA")
217 throw Internal_Error("Expected RSA key but got " + server_rsa_kex_key->algo_name());
218
219 TLS_Data_Reader reader("ClientKeyExchange", contents);
220 const std::vector<uint8_t> encrypted_pre_master = reader.get_range<uint8_t>(2, 0, 65535);
221 reader.assert_done();
222
223 PK_Decryptor_EME decryptor(*server_rsa_kex_key, rng, "PKCS1v15");
224
225 const uint8_t client_major = state.client_hello()->legacy_version().major_version();
226 const uint8_t client_minor = state.client_hello()->legacy_version().minor_version();
227
228 /*
229 * PK_Decryptor::decrypt_or_random will return a random value if
230 * either the length does not match the expected value or if the
231 * version number embedded in the PMS does not match the one sent
232 * in the client hello.
233 */
234 const size_t expected_plaintext_size = 48;
235 const size_t expected_content_size = 2;
236 const uint8_t expected_content_bytes[expected_content_size] = { client_major, client_minor };
237 const uint8_t expected_content_pos[expected_content_size] = { 0, 1 };
238
239 m_pre_master =
240 decryptor.decrypt_or_random(encrypted_pre_master.data(),
241 encrypted_pre_master.size(),
242 expected_plaintext_size,
243 rng,
244 expected_content_bytes,
245 expected_content_pos,
246 expected_content_size);
247 }
248 else
249 {
250 TLS_Data_Reader reader("ClientKeyExchange", contents);
251
252 SymmetricKey psk;
253
254 if(key_exchange_is_psk(kex_algo))
255 {
256 const std::string psk_identity = reader.get_string(2, 0, 65535);
257
258 psk = creds.psk("tls-server",
259 state.client_hello()->sni_hostname(),
260 psk_identity);
261
262 if(psk.length() == 0)
263 {
264 if(policy.hide_unknown_users())
265 psk = SymmetricKey(rng, 16);
266 else
267 throw TLS_Exception(Alert::UNKNOWN_PSK_IDENTITY,
268 "No PSK for identifier " + psk_identity);
269 }
270 }
271
272 if(kex_algo == Kex_Algo::PSK)
273 {
274 std::vector<uint8_t> zeros(psk.length());
275 append_tls_length_value(m_pre_master, zeros, 2);
276 append_tls_length_value(m_pre_master, psk.bits_of(), 2);
277 }
278#if defined(BOTAN_HAS_CECPQ1)
279 else if(kex_algo == Kex_Algo::CECPQ1)
280 {
281 const CECPQ1_key& cecpq1_offer = state.server_kex()->cecpq1_key();
282
283 const std::vector<uint8_t> cecpq1_accept = reader.get_range<uint8_t>(2, 0, 65535);
284 if(cecpq1_accept.size() != CECPQ1_ACCEPT_BYTES)
285 throw Decoding_Error("Invalid size for CECPQ1 accept message");
286
287 m_pre_master.resize(CECPQ1_SHARED_KEY_BYTES);
288 CECPQ1_finish(m_pre_master.data(), cecpq1_offer, cecpq1_accept.data());
289 }
290#endif
291 else if(kex_algo == Kex_Algo::DH ||
292 kex_algo == Kex_Algo::ECDH ||
293 kex_algo == Kex_Algo::ECDHE_PSK)
294 {
295 const Private_Key& private_key = state.server_kex()->server_kex_key();
296
297 const PK_Key_Agreement_Key* ka_key =
298 dynamic_cast<const PK_Key_Agreement_Key*>(&private_key);
299
300 if(!ka_key)
301 throw Internal_Error("Expected key agreement key type but got " +
302 private_key.algo_name());
303
304 std::vector<uint8_t> client_pubkey;
305
306 if(ka_key->algo_name() == "DH")
307 {
308 client_pubkey = reader.get_range<uint8_t>(2, 0, 65535);
309 }
310 else
311 {
312 client_pubkey = reader.get_range<uint8_t>(1, 1, 255);
313 }
314
315 try
316 {
317 PK_Key_Agreement ka(*ka_key, rng, "Raw");
318
319 secure_vector<uint8_t> shared_secret = ka.derive_key(0, client_pubkey).bits_of();
320
321 if(ka_key->algo_name() == "DH")
322 shared_secret = CT::strip_leading_zeros(shared_secret);
323
324 if(kex_algo == Kex_Algo::ECDHE_PSK)
325 {
326 append_tls_length_value(m_pre_master, shared_secret, 2);
327 append_tls_length_value(m_pre_master, psk.bits_of(), 2);
328 }
329 else
330 m_pre_master = shared_secret;
331 }
332 catch(Invalid_Argument& e)
333 {
334 throw TLS_Exception(Alert::ILLEGAL_PARAMETER, e.what());
335 }
336 catch(std::exception&)
337 {
338 /*
339 * Something failed in the DH/ECDH computation. To avoid possible
340 * attacks which are based on triggering and detecting some edge
341 * failure condition, randomize the pre-master output and carry on,
342 * allowing the protocol to fail later in the finished checks.
343 */
344 rng.random_vec(m_pre_master, ka_key->public_value().size());
345 }
346
347 reader.assert_done();
348 }
349 else
350 throw Internal_Error("Client_Key_Exchange: Unknown key exchange negotiated");
351 }
352 }
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:54
secure_vector< uint8_t > strip_leading_zeros(const uint8_t in[], size_t length)
Definition: ct_utils.cpp:87
bool key_exchange_is_psk(Kex_Algo m)
Definition: tls_algos.h:121
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::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::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 438 of file tls_messages.h.

439 { return m_pre_master; }

◆ type()

Handshake_Type Botan::TLS::Client_Key_Exchange::type ( ) const
inlineoverridevirtual
Returns
the message type

Implements Botan::TLS::Handshake_Message.

Definition at line 436 of file tls_messages.h.

436{ return CLIENT_KEX; }
@ CLIENT_KEX
Definition: tls_magic.h:78

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 18 of file tls_handshake_state.cpp.

19 {
21 }
virtual Handshake_Type type() const =0
const char * handshake_type_to_string(Handshake_Type type)

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

◆ wire_type()

virtual Handshake_Type Botan::TLS::Handshake_Message::wire_type ( ) const
inlinevirtualinherited
Returns
the wire representation of the message's type

Definition at line 42 of file tls_handshake_msg.h.

43 {
44 // Usually equal to the Handshake_Type enum value,
45 // with the exception of TLS 1.3 Hello Retry Request.
46 return type();
47 }

References type.

Referenced by Botan::TLS::Stream_Handshake_IO::send().


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