Botan  2.4.0
Crypto and TLS for C++11
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 (Handshake_IO &io, Handshake_State &state, const Policy &policy, Credentials_Manager &creds, const Public_Key *server_public_key, const std::string &hostname, RandomNumberGenerator &rng)
 
 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)
 
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 326 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.

References Botan::Public_Key::algo_name(), Botan::TLS::Policy::allowed_ecc_curve(), Botan::TLS::append_tls_length_value(), Botan::OctetString::bits_of(), Botan::TLS::Handshake_State::callbacks(), Botan::CECPQ1_accept(), Botan::CECPQ1_ACCEPT_BYTES, Botan::CECPQ1_OFFER_BYTES, Botan::CECPQ1_SHARED_KEY_BYTES, Botan::TLS::Handshake_State::ciphersuite(), Botan::TLS::Handshake_State::client_hello(), Botan::TLS::Supported_Groups::curve_id_to_name(), Botan::BigInt::decode(), Botan::BigInt::encode(), Botan::PK_Encryptor::encrypt(), Botan::TLS::TLS_Data_Reader::get_string(), Botan::TLS::Alert::HANDSHAKE_FAILURE, Botan::TLS::Handshake_State::hash(), Botan::TLS::Ciphersuite::kex_algo(), Botan::OctetString::length(), Botan::TLS::Protocol_Version::major_version(), Botan::TLS::Protocol_Version::minor_version(), Botan::Credentials_Manager::psk(), Botan::Credentials_Manager::psk_identity(), Botan::RandomNumberGenerator::random_vec(), Botan::TLS::Handshake_IO::send(), 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::Callbacks::tls_dh_agree(), Botan::TLS::Callbacks::tls_ecdh_agree(), Botan::ASN1::to_string(), and Botan::TLS::Handshake_Hash::update().

44  {
45  const std::string kex_algo = state.ciphersuite().kex_algo();
46 
47  if(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 == "DHE_PSK" || kex_algo == "ECDHE_PSK")
76  {
77  std::string identity_hint = reader.get_string(2, 0, 65535);
78 
79  const std::string psk_identity =
80  creds.psk_identity("tls-client", hostname, identity_hint);
81 
82  append_tls_length_value(m_key_material, psk_identity, 2);
83 
84  psk = creds.psk("tls-client", hostname, psk_identity);
85  }
86 
87  if(kex_algo == "DH" || kex_algo == "DHE_PSK")
88  {
89  const std::vector<uint8_t> modulus = reader.get_range<uint8_t>(2, 1, 65535);
90  const std::vector<uint8_t> generator = reader.get_range<uint8_t>(2, 1, 65535);
91  const std::vector<uint8_t> peer_public_value = reader.get_range<uint8_t>(2, 1, 65535);
92 
93  if(reader.remaining_bytes())
94  throw Decoding_Error("Bad params size for DH key exchange");
95 
96  const std::pair<secure_vector<uint8_t>, std::vector<uint8_t>> dh_result =
97  state.callbacks().tls_dh_agree(modulus, generator, peer_public_value, policy, rng);
98 
99  if(kex_algo == "DH")
100  m_pre_master = dh_result.first;
101  else
102  {
103  append_tls_length_value(m_pre_master, dh_result.first, 2);
104  append_tls_length_value(m_pre_master, psk.bits_of(), 2);
105  }
106 
107  append_tls_length_value(m_key_material, dh_result.second, 2);
108  }
109  else if(kex_algo == "ECDH" || kex_algo == "ECDHE_PSK")
110  {
111  const uint8_t curve_type = reader.get_byte();
112 
113  if(curve_type != 3)
114  throw Decoding_Error("Server sent non-named ECC curve");
115 
116  const uint16_t curve_id = reader.get_uint16_t();
117 
118  const std::string curve_name = Supported_Elliptic_Curves::curve_id_to_name(curve_id);
119 
120  if(curve_name == "")
121  throw Decoding_Error("Server sent unknown named curve " + std::to_string(curve_id));
122 
123  if(!policy.allowed_ecc_curve(curve_name))
124  {
125  throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
126  "Server sent ECC curve prohibited by policy");
127  }
128 
129  const std::vector<uint8_t> peer_public_value = reader.get_range<uint8_t>(1, 1, 255);
130  const std::pair<secure_vector<uint8_t>, std::vector<uint8_t>> ecdh_result =
131  state.callbacks().tls_ecdh_agree(curve_name, peer_public_value, policy, rng,
132  state.server_hello()->prefers_compressed_ec_points());
133 
134  if(kex_algo == "ECDH")
135  m_pre_master = ecdh_result.first;
136  else
137  {
138  append_tls_length_value(m_pre_master, ecdh_result.first, 2);
139  append_tls_length_value(m_pre_master, psk.bits_of(), 2);
140  }
141 
142  append_tls_length_value(m_key_material, ecdh_result.second, 1);
143  }
144 #if defined(BOTAN_HAS_SRP6)
145  else if(kex_algo == "SRP_SHA")
146  {
147  const BigInt N = BigInt::decode(reader.get_range<uint8_t>(2, 1, 65535));
148  const BigInt g = BigInt::decode(reader.get_range<uint8_t>(2, 1, 65535));
149  std::vector<uint8_t> salt = reader.get_range<uint8_t>(1, 1, 255);
150  const BigInt B = BigInt::decode(reader.get_range<uint8_t>(2, 1, 65535));
151 
152  const std::string srp_group = srp6_group_identifier(N, g);
153 
154  const std::string srp_identifier =
155  creds.srp_identifier("tls-client", hostname);
156 
157  const std::string srp_password =
158  creds.srp_password("tls-client", hostname, srp_identifier);
159 
160  std::pair<BigInt, SymmetricKey> srp_vals =
161  srp6_client_agree(srp_identifier,
162  srp_password,
163  srp_group,
164  "SHA-1",
165  salt,
166  B,
167  rng);
168 
169  append_tls_length_value(m_key_material, BigInt::encode(srp_vals.first), 2);
170  m_pre_master = srp_vals.second.bits_of();
171  }
172 #endif
173 
174 #if defined(BOTAN_HAS_CECPQ1)
175  else if(kex_algo == "CECPQ1")
176  {
177  const std::vector<uint8_t> cecpq1_offer = reader.get_range<uint8_t>(2, 1, 65535);
178 
179  if(cecpq1_offer.size() != CECPQ1_OFFER_BYTES)
180  throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Invalid CECPQ1 key size");
181 
182  std::vector<uint8_t> newhope_accept(CECPQ1_ACCEPT_BYTES);
183  secure_vector<uint8_t> shared_secret(CECPQ1_SHARED_KEY_BYTES);
184  CECPQ1_accept(shared_secret.data(), newhope_accept.data(), cecpq1_offer.data(), rng);
185  append_tls_length_value(m_key_material, newhope_accept, 2);
186  m_pre_master = shared_secret;
187  }
188 #endif
189  else
190  {
191  throw Internal_Error("Client_Key_Exchange: Unknown kex " + kex_algo);
192  }
193 
194  reader.assert_done();
195  }
196  else
197  {
198  // No server key exchange msg better mean RSA kex + RSA key in cert
199 
200  if(kex_algo != "RSA")
201  throw Unexpected_Message("No server kex but negotiated kex " + kex_algo);
202 
203  if(!server_public_key)
204  throw Internal_Error("No server public key for RSA exchange");
205 
206  if(auto rsa_pub = dynamic_cast<const RSA_PublicKey*>(server_public_key))
207  {
208  const Protocol_Version offered_version = state.client_hello()->version();
209 
210  m_pre_master = rng.random_vec(48);
211  m_pre_master[0] = offered_version.major_version();
212  m_pre_master[1] = offered_version.minor_version();
213 
214  PK_Encryptor_EME encryptor(*rsa_pub, rng, "PKCS1v15");
215 
216  const std::vector<uint8_t> encrypted_key = encryptor.encrypt(m_pre_master, rng);
217 
218  append_tls_length_value(m_key_material, encrypted_key, 2);
219  }
220  else
221  throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
222  "Expected a RSA key in server cert but got " +
223  server_public_key->algo_name());
224  }
225 
226  state.hash().update(io.send(*this));
227  }
static std::string curve_id_to_name(uint16_t id)
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
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:108
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
OctetString SymmetricKey
Definition: symkey.h:136
std::unique_ptr< Public_Key > server_public_key
Definition: tls_client.cpp:38
static std::vector< uint8_t > encode(const BigInt &n, Base base=Binary)
Definition: big_code.cpp:54
std::string srp6_group_identifier(const BigInt &N, const BigInt &g)
Definition: srp6.cpp:53
static BigInt decode(const uint8_t buf[], size_t length, Base base=Binary)
Definition: big_code.cpp:114
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

◆ 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 232 of file msg_client_kex.cpp.

References Botan::Public_Key::algo_name(), Botan::TLS::append_tls_length_value(), 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_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_algo(), 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::TLS::Alert::UNKNOWN_PSK_IDENTITY.

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

Member Function Documentation

◆ pre_master_secret()

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

Definition at line 331 of file tls_messages.h.

References server_public_key.

332  { 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 329 of file tls_messages.h.

References Botan::TLS::CLIENT_KEX.

329 { return 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.

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

20  {
22  }
virtual Handshake_Type type() const =0
const char * handshake_type_to_string(Handshake_Type type)

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