Botan  2.1.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 397 of file tls_messages.h.

Constructor & Destructor Documentation

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 44 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::CECPQ1_accept(), Botan::CECPQ1_ACCEPT_BYTES, Botan::CECPQ1_OFFER_BYTES, Botan::CECPQ1_SHARED_KEY_BYTES, Botan::TLS::Policy::check_peer_key_acceptable(), Botan::TLS::Handshake_State::ciphersuite(), Botan::TLS::Handshake_State::client_hello(), Botan::PointGFp::COMPRESSED, Botan::TLS::Supported_Elliptic_Curves::curve_id_to_name(), Botan::BigInt::decode(), Botan::PK_Key_Agreement::derive_key(), Botan::BigInt::encode(), Botan::PK_Encryptor::encrypt(), Botan::EC_Group::get_curve(), Botan::TLS::TLS_Data_Reader::get_string(), Botan::TLS::Alert::HANDSHAKE_FAILURE, Botan::TLS::Handshake_State::hash(), Botan::TLS::Alert::INSUFFICIENT_SECURITY, Botan::TLS::Ciphersuite::kex_algo(), Botan::OctetString::length(), Botan::TLS::Protocol_Version::major_version(), Botan::TLS::Protocol_Version::minor_version(), Botan::OS2ECP(), Botan::Credentials_Manager::psk(), Botan::Credentials_Manager::psk_identity(), Botan::DH_PublicKey::public_value(), Botan::Curve25519_PublicKey::public_value(), Botan::ECDH_PublicKey::public_value(), Botan::DH_PrivateKey::public_value(), Botan::Curve25519_PrivateKey::public_value(), Botan::ECDH_PrivateKey::public_value(), 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::CT::strip_leading_zeros(), Botan::ASN1::to_string(), Botan::PointGFp::UNCOMPRESSED, Botan::TLS::Handshake_Hash::update(), and Botan::DL_Group::verify_group().

51  {
52  const std::string kex_algo = state.ciphersuite().kex_algo();
53 
54  if(kex_algo == "PSK")
55  {
56  std::string identity_hint = "";
57 
58  if(state.server_kex())
59  {
60  TLS_Data_Reader reader("ClientKeyExchange", state.server_kex()->params());
61  identity_hint = reader.get_string(2, 0, 65535);
62  }
63 
64  const std::string psk_identity =
65  creds.psk_identity("tls-client", hostname, identity_hint);
66 
67  append_tls_length_value(m_key_material, psk_identity, 2);
68 
69  SymmetricKey psk = creds.psk("tls-client", hostname, psk_identity);
70 
71  std::vector<uint8_t> zeros(psk.length());
72 
73  append_tls_length_value(m_pre_master, zeros, 2);
74  append_tls_length_value(m_pre_master, psk.bits_of(), 2);
75  }
76  else if(state.server_kex())
77  {
78  TLS_Data_Reader reader("ClientKeyExchange", state.server_kex()->params());
79 
80  SymmetricKey psk;
81 
82  if(kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK")
83  {
84  std::string identity_hint = reader.get_string(2, 0, 65535);
85 
86  const std::string psk_identity =
87  creds.psk_identity("tls-client", hostname, identity_hint);
88 
89  append_tls_length_value(m_key_material, psk_identity, 2);
90 
91  psk = creds.psk("tls-client", hostname, psk_identity);
92  }
93 
94  if(kex_algo == "DH" || kex_algo == "DHE_PSK")
95  {
96  BigInt p = BigInt::decode(reader.get_range<uint8_t>(2, 1, 65535));
97  BigInt g = BigInt::decode(reader.get_range<uint8_t>(2, 1, 65535));
98  BigInt Y = BigInt::decode(reader.get_range<uint8_t>(2, 1, 65535));
99 
100  if(reader.remaining_bytes())
101  throw Decoding_Error("Bad params size for DH key exchange");
102 
103  /*
104  * A basic check for key validity. As we do not know q here we
105  * cannot check that Y is in the right subgroup. However since
106  * our key is ephemeral there does not seem to be any
107  * advantage to bogus keys anyway.
108  */
109  if(Y <= 1 || Y >= p - 1)
110  throw TLS_Exception(Alert::INSUFFICIENT_SECURITY,
111  "Server sent bad DH key for DHE exchange");
112 
113  DL_Group group(p, g);
114 
115  if(!group.verify_group(rng, false))
116  throw TLS_Exception(Alert::INSUFFICIENT_SECURITY,
117  "DH group validation failed");
118 
119  DH_PublicKey counterparty_key(group, Y);
120 
121  policy.check_peer_key_acceptable(counterparty_key);
122 
123  DH_PrivateKey priv_key(rng, group);
124 
125  PK_Key_Agreement ka(priv_key, rng, "Raw");
126 
127  secure_vector<uint8_t> dh_secret = CT::strip_leading_zeros(
128  ka.derive_key(0, counterparty_key.public_value()).bits_of());
129 
130  if(kex_algo == "DH")
131  m_pre_master = dh_secret;
132  else
133  {
134  append_tls_length_value(m_pre_master, dh_secret, 2);
135  append_tls_length_value(m_pre_master, psk.bits_of(), 2);
136  }
137 
138  append_tls_length_value(m_key_material, priv_key.public_value(), 2);
139  }
140  else if(kex_algo == "ECDH" || kex_algo == "ECDHE_PSK")
141  {
142  const uint8_t curve_type = reader.get_byte();
143 
144  if(curve_type != 3)
145  throw Decoding_Error("Server sent non-named ECC curve");
146 
147  const uint16_t curve_id = reader.get_uint16_t();
148 
149  const std::string curve_name = Supported_Elliptic_Curves::curve_id_to_name(curve_id);
150 
151  if(curve_name == "")
152  throw Decoding_Error("Server sent unknown named curve " + std::to_string(curve_id));
153 
154  if(!policy.allowed_ecc_curve(curve_name))
155  {
156  throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
157  "Server sent ECC curve prohibited by policy");
158  }
159 
160  const std::vector<uint8_t> ecdh_key = reader.get_range<uint8_t>(1, 1, 255);
161  std::vector<uint8_t> our_ecdh_public;
162  secure_vector<uint8_t> ecdh_secret;
163 
164  if(curve_name == "x25519")
165  {
166 #if defined(BOTAN_HAS_CURVE_25519)
167  if(ecdh_key.size() != 32)
168  throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Invalid X25519 key size");
169 
170  Curve25519_PublicKey counterparty_key(ecdh_key);
171  policy.check_peer_key_acceptable(counterparty_key);
172  Curve25519_PrivateKey priv_key(rng);
173  PK_Key_Agreement ka(priv_key, rng, "Raw");
174  ecdh_secret = ka.derive_key(0, counterparty_key.public_value()).bits_of();
175 
176  // X25519 is always compressed but sent as "uncompressed" in TLS
177  our_ecdh_public = priv_key.public_value();
178 #else
179  throw Internal_Error("Negotiated X25519 somehow, but it is disabled");
180 #endif
181  }
182  else
183  {
184  EC_Group group(curve_name);
185  ECDH_PublicKey counterparty_key(group, OS2ECP(ecdh_key, group.get_curve()));
186  policy.check_peer_key_acceptable(counterparty_key);
187  ECDH_PrivateKey priv_key(rng, group);
188  PK_Key_Agreement ka(priv_key, rng, "Raw");
189  ecdh_secret = ka.derive_key(0, counterparty_key.public_value()).bits_of();
190 
191  // follow server's preference for point compression
192  our_ecdh_public = priv_key.public_value(
193  state.server_hello()->prefers_compressed_ec_points() ? PointGFp::COMPRESSED : PointGFp::UNCOMPRESSED);
194  }
195 
196  if(kex_algo == "ECDH")
197  m_pre_master = ecdh_secret;
198  else
199  {
200  append_tls_length_value(m_pre_master, ecdh_secret, 2);
201  append_tls_length_value(m_pre_master, psk.bits_of(), 2);
202  }
203 
204  append_tls_length_value(m_key_material, our_ecdh_public, 1);
205  }
206 #if defined(BOTAN_HAS_SRP6)
207  else if(kex_algo == "SRP_SHA")
208  {
209  const BigInt N = BigInt::decode(reader.get_range<uint8_t>(2, 1, 65535));
210  const BigInt g = BigInt::decode(reader.get_range<uint8_t>(2, 1, 65535));
211  std::vector<uint8_t> salt = reader.get_range<uint8_t>(1, 1, 255);
212  const BigInt B = BigInt::decode(reader.get_range<uint8_t>(2, 1, 65535));
213 
214  const std::string srp_group = srp6_group_identifier(N, g);
215 
216  const std::string srp_identifier =
217  creds.srp_identifier("tls-client", hostname);
218 
219  const std::string srp_password =
220  creds.srp_password("tls-client", hostname, srp_identifier);
221 
222  std::pair<BigInt, SymmetricKey> srp_vals =
223  srp6_client_agree(srp_identifier,
224  srp_password,
225  srp_group,
226  "SHA-1",
227  salt,
228  B,
229  rng);
230 
231  append_tls_length_value(m_key_material, BigInt::encode(srp_vals.first), 2);
232  m_pre_master = srp_vals.second.bits_of();
233  }
234 #endif
235 
236 #if defined(BOTAN_HAS_CECPQ1)
237  else if(kex_algo == "CECPQ1")
238  {
239  const std::vector<uint8_t> cecpq1_offer = reader.get_range<uint8_t>(2, 1, 65535);
240 
241  if(cecpq1_offer.size() != CECPQ1_OFFER_BYTES)
242  throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Invalid CECPQ1 key size");
243 
244  std::vector<uint8_t> newhope_accept(CECPQ1_ACCEPT_BYTES);
245  secure_vector<uint8_t> shared_secret(CECPQ1_SHARED_KEY_BYTES);
246  CECPQ1_accept(shared_secret.data(), newhope_accept.data(), cecpq1_offer.data(), rng);
247  append_tls_length_value(m_key_material, newhope_accept, 2);
248  m_pre_master = shared_secret;
249  }
250 #endif
251  else
252  {
253  throw Internal_Error("Client_Key_Exchange: Unknown kex " + kex_algo);
254  }
255 
256  reader.assert_done();
257  }
258  else
259  {
260  // No server key exchange msg better mean RSA kex + RSA key in cert
261 
262  if(kex_algo != "RSA")
263  throw Unexpected_Message("No server kex but negotiated kex " + kex_algo);
264 
265  if(!server_public_key)
266  throw Internal_Error("No server public key for RSA exchange");
267 
268  if(auto rsa_pub = dynamic_cast<const RSA_PublicKey*>(server_public_key))
269  {
270  const Protocol_Version offered_version = state.client_hello()->version();
271 
272  m_pre_master = rng.random_vec(48);
273  m_pre_master[0] = offered_version.major_version();
274  m_pre_master[1] = offered_version.minor_version();
275 
276  PK_Encryptor_EME encryptor(*rsa_pub, rng, "PKCS1v15");
277 
278  const std::vector<uint8_t> encrypted_key = encryptor.encrypt(m_pre_master, rng);
279 
280  append_tls_length_value(m_key_material, encrypted_key, 2);
281  }
282  else
283  throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
284  "Expected a RSA key in server cert but got " +
285  server_public_key->algo_name());
286  }
287 
288  state.hash().update(io.send(*this));
289  }
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:47
static std::string curve_id_to_name(uint16_t id)
PointGFp OS2ECP(const uint8_t data[], size_t data_len, const CurveGFp &curve)
Definition: point_gfp.cpp:544
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:25
OctetString SymmetricKey
Definition: symkey.h:136
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:76
std::unique_ptr< Public_Key > server_public_key
Definition: tls_client.cpp:40
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:52
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:186
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::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 294 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.

300  {
301  const std::string kex_algo = state.ciphersuite().kex_algo();
302 
303  if(kex_algo == "RSA")
304  {
305  BOTAN_ASSERT(state.server_certs() && !state.server_certs()->cert_chain().empty(),
306  "RSA key exchange negotiated so server sent a certificate");
307 
308  if(!server_rsa_kex_key)
309  throw Internal_Error("Expected RSA kex but no server kex key set");
310 
311  if(!dynamic_cast<const RSA_PrivateKey*>(server_rsa_kex_key))
312  throw Internal_Error("Expected RSA key but got " + server_rsa_kex_key->algo_name());
313 
314  TLS_Data_Reader reader("ClientKeyExchange", contents);
315  const std::vector<uint8_t> encrypted_pre_master = reader.get_range<uint8_t>(2, 0, 65535);
316 
317  PK_Decryptor_EME decryptor(*server_rsa_kex_key, rng, "PKCS1v15");
318 
319  const uint8_t client_major = state.client_hello()->version().major_version();
320  const uint8_t client_minor = state.client_hello()->version().minor_version();
321 
322  /*
323  * PK_Decryptor::decrypt_or_random will return a random value if
324  * either the length does not match the expected value or if the
325  * version number embedded in the PMS does not match the one sent
326  * in the client hello.
327  */
328  const size_t expected_plaintext_size = 48;
329  const size_t expected_content_size = 2;
330  const uint8_t expected_content_bytes[expected_content_size] = { client_major, client_minor };
331  const uint8_t expected_content_pos[expected_content_size] = { 0, 1 };
332 
333  m_pre_master =
334  decryptor.decrypt_or_random(encrypted_pre_master.data(),
335  encrypted_pre_master.size(),
336  expected_plaintext_size,
337  rng,
338  expected_content_bytes,
339  expected_content_pos,
340  expected_content_size);
341  }
342  else
343  {
344  TLS_Data_Reader reader("ClientKeyExchange", contents);
345 
346  SymmetricKey psk;
347 
348  if(kex_algo == "PSK" || kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK")
349  {
350  const std::string psk_identity = reader.get_string(2, 0, 65535);
351 
352  psk = creds.psk("tls-server",
353  state.client_hello()->sni_hostname(),
354  psk_identity);
355 
356  if(psk.length() == 0)
357  {
358  if(policy.hide_unknown_users())
359  psk = SymmetricKey(rng, 16);
360  else
361  throw TLS_Exception(Alert::UNKNOWN_PSK_IDENTITY,
362  "No PSK for identifier " + psk_identity);
363  }
364  }
365 
366  if(kex_algo == "PSK")
367  {
368  std::vector<uint8_t> zeros(psk.length());
369  append_tls_length_value(m_pre_master, zeros, 2);
370  append_tls_length_value(m_pre_master, psk.bits_of(), 2);
371  }
372 #if defined(BOTAN_HAS_SRP6)
373  else if(kex_algo == "SRP_SHA")
374  {
375  SRP6_Server_Session& srp = state.server_kex()->server_srp_params();
376 
377  m_pre_master = srp.step2(BigInt::decode(reader.get_range<uint8_t>(2, 0, 65535))).bits_of();
378  }
379 #endif
380 #if defined(BOTAN_HAS_CECPQ1)
381  else if(kex_algo == "CECPQ1")
382  {
383  const CECPQ1_key& cecpq1_offer = state.server_kex()->cecpq1_key();
384 
385  const std::vector<uint8_t> cecpq1_accept = reader.get_range<uint8_t>(2, 0, 65535);
386  if(cecpq1_accept.size() != CECPQ1_ACCEPT_BYTES)
387  throw Decoding_Error("Invalid size for CECPQ1 accept message");
388 
389  m_pre_master.resize(CECPQ1_SHARED_KEY_BYTES);
390  CECPQ1_finish(m_pre_master.data(), cecpq1_offer, cecpq1_accept.data());
391  }
392 #endif
393  else if(kex_algo == "DH" || kex_algo == "DHE_PSK" ||
394  kex_algo == "ECDH" || kex_algo == "ECDHE_PSK")
395  {
396  const Private_Key& private_key = state.server_kex()->server_kex_key();
397 
398  const PK_Key_Agreement_Key* ka_key =
399  dynamic_cast<const PK_Key_Agreement_Key*>(&private_key);
400 
401  if(!ka_key)
402  throw Internal_Error("Expected key agreement key type but got " +
403  private_key.algo_name());
404 
405  try
406  {
407  PK_Key_Agreement ka(*ka_key, rng, "Raw");
408 
409  std::vector<uint8_t> client_pubkey;
410 
411  if(ka_key->algo_name() == "DH")
412  client_pubkey = reader.get_range<uint8_t>(2, 0, 65535);
413  else
414  client_pubkey = reader.get_range<uint8_t>(1, 0, 255);
415 
416  secure_vector<uint8_t> shared_secret = ka.derive_key(0, client_pubkey).bits_of();
417 
418  if(ka_key->algo_name() == "DH")
419  shared_secret = CT::strip_leading_zeros(shared_secret);
420 
421  if(kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK")
422  {
423  append_tls_length_value(m_pre_master, shared_secret, 2);
424  append_tls_length_value(m_pre_master, psk.bits_of(), 2);
425  }
426  else
427  m_pre_master = shared_secret;
428  }
429  catch(std::exception &)
430  {
431  /*
432  * Something failed in the DH computation. To avoid possible
433  * timing attacks, randomize the pre-master output and carry
434  * on, allowing the protocol to fail later in the finished
435  * checks.
436  */
437  m_pre_master = rng.random_vec(ka_key->public_value().size());
438  }
439  }
440  else
441  throw Internal_Error("Client_Key_Exchange: Unknown kex type " + kex_algo);
442  }
443  }
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:40
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:27
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:186
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

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

Definition at line 402 of file tls_messages.h.

403  { return m_pre_master; }
Handshake_Type Botan::TLS::Client_Key_Exchange::type ( ) const
inlineoverridevirtual
Returns
the message type

Implements Botan::TLS::Handshake_Message.

Definition at line 400 of file tls_messages.h.

References Botan::TLS::CLIENT_KEX.

400 { return CLIENT_KEX; }
std::string Botan::TLS::Handshake_Message::type_string ( ) const
inherited
Returns
string representation of this message type

Definition at line 17 of file tls_handshake_state.cpp.

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

18  {
20  }
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: