Botan 3.8.1
Crypto and TLS for C&
Botan::TLS::Server_Key_Exchange Class Referencefinal

#include <tls_messages.h>

Inheritance diagram for Botan::TLS::Server_Key_Exchange:
Botan::TLS::Handshake_Message

Public Member Functions

const std::vector< uint8_t > & params () const
 
const PK_Key_Agreement_Keyserver_kex_key () const
 
 Server_Key_Exchange (const std::vector< uint8_t > &buf, Kex_Algo kex_alg, Auth_Method sig_alg, Protocol_Version version)
 
 Server_Key_Exchange (Handshake_IO &io, Handshake_State &state, const Policy &policy, Credentials_Manager &creds, RandomNumberGenerator &rng, const Private_Key *signing_key=nullptr)
 
const std::optional< Group_Params > & shared_group () const
 
Handshake_Type type () const override
 
std::string type_string () const
 
bool verify (const Public_Key &server_key, const Handshake_State &state, const Policy &policy) const
 
virtual Handshake_Type wire_type () const
 

Detailed Description

Server Key Exchange Message

Definition at line 881 of file tls_messages.h.

Constructor & Destructor Documentation

◆ Server_Key_Exchange() [1/2]

Botan::TLS::Server_Key_Exchange::Server_Key_Exchange ( Handshake_IO & io,
Handshake_State & state,
const Policy & policy,
Credentials_Manager & creds,
RandomNumberGenerator & rng,
const Private_Key * signing_key = nullptr )

Create a new Server Key Exchange message

Definition at line 36 of file msg_server_kex.cpp.

41 {
42 const std::string hostname = state.client_hello()->sni_hostname();
43 const Kex_Algo kex_algo = state.ciphersuite().kex_method();
44
45 if(kex_algo == Kex_Algo::PSK || kex_algo == Kex_Algo::ECDHE_PSK) {
46 std::string identity_hint = creds.psk_identity_hint("tls-server", hostname);
47
48 append_tls_length_value(m_params, identity_hint, 2);
49 }
50
51 if(kex_algo == Kex_Algo::DH) {
52 const std::vector<Group_Params> dh_groups = state.client_hello()->supported_dh_groups();
53
54 m_shared_group = Group_Params::NONE;
55
56 /*
57 RFC 7919 requires that if the client sends any groups in the FFDHE
58 range, that we must select one of these. If this is not possible,
59 then we are required to reject the connection.
60
61 If the client did not send any DH groups, but did offer DH ciphersuites
62 and we selected one, then consult the policy for which DH group to pick.
63 */
64
65 if(dh_groups.empty()) {
66 m_shared_group = policy.default_dh_group();
67 } else {
68 m_shared_group = policy.choose_key_exchange_group(dh_groups, {});
69 }
70
71 if(m_shared_group.value() == Group_Params::NONE) {
72 throw TLS_Exception(Alert::HandshakeFailure, "Could not agree on a DH group with the client");
73 }
74
75 // The policy had better return a group we know about:
76 BOTAN_ASSERT(m_shared_group.value().is_dh_named_group(), "DH ciphersuite is using a known finite field group");
77
78 // Note: TLS 1.2 allows defining and using arbitrary DH groups (additional
79 // to the named and standardized ones). This API doesn't allow the
80 // server to make use of that at the moment. TLS 1.3 does not
81 // provide this flexibility!
82 //
83 // A possible implementation strategy in case one would ever need that:
84 // `Policy::default_dh_group()` could return a `std::variant<Group_Params,
85 // DL_Group>`, allowing it to define arbitrary groups.
86 m_kex_key = state.callbacks().tls_generate_ephemeral_key(m_shared_group.value(), rng);
87 auto dh = dynamic_cast<DH_PrivateKey*>(m_kex_key.get());
88 if(!dh) {
89 throw TLS_Exception(Alert::InternalError, "Application did not provide a Diffie-Hellman key");
90 }
91
92 append_tls_length_value(m_params, dh->get_int_field("p").serialize(), 2);
93 append_tls_length_value(m_params, dh->get_int_field("g").serialize(), 2);
94 append_tls_length_value(m_params, dh->public_value(), 2);
95 } else if(kex_algo == Kex_Algo::ECDH || kex_algo == Kex_Algo::ECDHE_PSK) {
96 const std::vector<Group_Params> ec_groups = state.client_hello()->supported_ecc_curves();
97
98 if(ec_groups.empty()) {
99 throw Internal_Error("Client sent no ECC extension but we negotiated ECDH");
100 }
101
102 m_shared_group = policy.choose_key_exchange_group(ec_groups, {});
103
104 if(m_shared_group.value() == Group_Params::NONE) {
105 throw TLS_Exception(Alert::HandshakeFailure, "No shared ECC group with client");
106 }
107
108 std::vector<uint8_t> ecdh_public_val;
109
110 if(m_shared_group.value() == Group_Params::X25519 || m_shared_group.value() == Group_Params::X448) {
111 m_kex_key = state.callbacks().tls_generate_ephemeral_key(m_shared_group.value(), rng);
112 if(!m_kex_key) {
113 throw TLS_Exception(Alert::InternalError, "Application did not provide an EC key");
114 }
115 ecdh_public_val = m_kex_key->public_value();
116 } else {
117 m_kex_key = state.callbacks().tls_generate_ephemeral_key(m_shared_group.value(), rng);
118 auto ecdh = dynamic_cast<ECDH_PrivateKey*>(m_kex_key.get());
119 if(!ecdh) {
120 throw TLS_Exception(Alert::InternalError, "Application did not provide a EC-Diffie-Hellman key");
121 }
122
123 // follow client's preference for point compression
124 ecdh_public_val =
125 ecdh->public_value(state.client_hello()->prefers_compressed_ec_points() ? EC_Point_Format::Compressed
127 }
128
129 const uint16_t named_curve_id = m_shared_group.value().wire_code();
130 m_params.push_back(3); // named curve
131 m_params.push_back(get_byte<0>(named_curve_id));
132 m_params.push_back(get_byte<1>(named_curve_id));
133
134 append_tls_length_value(m_params, ecdh_public_val, 1);
135 } else if(kex_algo != Kex_Algo::PSK) {
136 throw Internal_Error("Server_Key_Exchange: Unknown kex type " + kex_method_to_string(kex_algo));
137 }
138
139 if(state.ciphersuite().signature_used()) {
140 BOTAN_ASSERT(signing_key, "Signing key was set");
141
142 std::pair<std::string, Signature_Format> format = state.choose_sig_format(*signing_key, m_scheme, false, policy);
143
144 std::vector<uint8_t> buf = state.client_hello()->random();
145
146 buf += state.server_hello()->random();
147 buf += params();
148
149 m_signature = state.callbacks().tls_sign_message(*signing_key, rng, format.first, format.second, buf);
150 }
151
152 state.hash().update(io.send(*this));
153}
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:52
const std::vector< uint8_t > & params() const
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:180
std::string kex_method_to_string(Kex_Algo method)
Definition tls_algos.cpp:28
constexpr uint8_t get_byte(T input)
Definition loadstor.h:79

References Botan::TLS::append_tls_length_value(), BOTAN_ASSERT, Botan::TLS::Handshake_State::callbacks(), Botan::TLS::Policy::choose_key_exchange_group(), Botan::TLS::Handshake_State::choose_sig_format(), Botan::TLS::Handshake_State::ciphersuite(), Botan::TLS::Handshake_State::client_hello(), Botan::Compressed, Botan::TLS::Policy::default_dh_group(), Botan::TLS::DH, Botan::TLS::ECDH, Botan::TLS::ECDHE_PSK, Botan::get_byte(), Botan::TLS::Handshake_State::hash(), Botan::TLS::Ciphersuite::kex_method(), Botan::TLS::kex_method_to_string(), params(), Botan::TLS::PSK, Botan::Credentials_Manager::psk_identity_hint(), Botan::ECDH_PrivateKey::public_value(), Botan::TLS::Handshake_IO::send(), Botan::TLS::Handshake_State::server_hello(), Botan::TLS::Ciphersuite::signature_used(), Botan::TLS::Callbacks::tls_generate_ephemeral_key(), Botan::TLS::Callbacks::tls_sign_message(), Botan::Uncompressed, Botan::TLS::Handshake_Hash::update(), and Botan::TLS::Group_Params::wire_code().

◆ Server_Key_Exchange() [2/2]

Botan::TLS::Server_Key_Exchange::Server_Key_Exchange ( const std::vector< uint8_t > & buf,
Kex_Algo kex_alg,
Auth_Method sig_alg,
Protocol_Version version )

Deserialize a Server Key Exchange message

Definition at line 158 of file msg_server_kex.cpp.

161 {
162 BOTAN_UNUSED(version); // remove this
163 TLS_Data_Reader reader("ServerKeyExchange", buf);
164
165 /*
166 * Here we are deserializing enough to find out what offset the
167 * signature is at. All processing is done when the Client Key Exchange
168 * is prepared.
169 */
170
171 if(kex_algo == Kex_Algo::PSK || kex_algo == Kex_Algo::ECDHE_PSK) {
172 reader.get_string(2, 0, 65535); // identity hint
173 }
174
175 if(kex_algo == Kex_Algo::DH) {
176 // 3 bigints, DH p, g, Y
177
178 for(size_t i = 0; i != 3; ++i) {
179 reader.get_range<uint8_t>(2, 1, 65535);
180 }
181 } else if(kex_algo == Kex_Algo::ECDH || kex_algo == Kex_Algo::ECDHE_PSK) {
182 reader.get_byte(); // curve type
183 reader.get_uint16_t(); // curve id
184 reader.get_range<uint8_t>(1, 1, 255); // public key
185 } else if(kex_algo != Kex_Algo::PSK) {
186 throw Decoding_Error("Server_Key_Exchange: Unsupported kex type " + kex_method_to_string(kex_algo));
187 }
188
189 m_params.assign(buf.data(), buf.data() + reader.read_so_far());
190
191 if(auth_method != Auth_Method::IMPLICIT) {
192 m_scheme = Signature_Scheme(reader.get_uint16_t());
193 m_signature = reader.get_range<uint8_t>(2, 0, 65535);
194 }
195
196 reader.assert_done();
197}
#define BOTAN_UNUSED
Definition assert.h:120

References Botan::TLS::TLS_Data_Reader::assert_done(), BOTAN_UNUSED, 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::IMPLICIT, Botan::TLS::kex_method_to_string(), Botan::TLS::PSK, and Botan::TLS::TLS_Data_Reader::read_so_far().

Member Function Documentation

◆ params()

const std::vector< uint8_t > & Botan::TLS::Server_Key_Exchange::params ( ) const
inline

Definition at line 885 of file tls_messages.h.

885{ return m_params; }

Referenced by Server_Key_Exchange(), and verify().

◆ server_kex_key()

const PK_Key_Agreement_Key & Botan::TLS::Server_Key_Exchange::server_kex_key ( ) const

Definition at line 244 of file msg_server_kex.cpp.

244 {
245 BOTAN_ASSERT_NONNULL(m_kex_key);
246 return *m_kex_key;
247}
#define BOTAN_ASSERT_NONNULL(ptr)
Definition assert.h:88

References BOTAN_ASSERT_NONNULL.

◆ shared_group()

const std::optional< Group_Params > & Botan::TLS::Server_Key_Exchange::shared_group ( ) const
inline
Returns
the agreed upon KEX group or std::nullopt if the KEX type does not depend on a group

Definition at line 896 of file tls_messages.h.

896{ return m_shared_group; }

◆ type()

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

Implements Botan::TLS::Handshake_Message.

Definition at line 883 of file tls_messages.h.

References Botan::TLS::ServerKeyExchange.

◆ 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.

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 type().

◆ verify()

bool Botan::TLS::Server_Key_Exchange::verify ( const Public_Key & server_key,
const Handshake_State & state,
const Policy & policy ) const

Verify a Server Key Exchange message

Definition at line 220 of file msg_server_kex.cpp.

222 {
223 policy.check_peer_key_acceptable(server_key);
224
225 std::pair<std::string, Signature_Format> format =
226 state.parse_sig_format(server_key, m_scheme, state.client_hello()->signature_schemes(), false, policy);
227
228 std::vector<uint8_t> buf = state.client_hello()->random();
229
230 buf += state.server_hello()->random();
231 buf += params();
232
233 const bool signature_valid =
234 state.callbacks().tls_verify_message(server_key, format.first, format.second, buf, m_signature);
235
236#if defined(BOTAN_UNSAFE_FUZZER_MODE)
237 BOTAN_UNUSED(signature_valid);
238 return true;
239#else
240 return signature_valid;
241#endif
242}

References BOTAN_UNUSED, Botan::TLS::Handshake_State::callbacks(), Botan::TLS::Policy::check_peer_key_acceptable(), Botan::TLS::Handshake_State::client_hello(), params(), Botan::TLS::Handshake_State::parse_sig_format(), Botan::TLS::Handshake_State::server_hello(), and Botan::TLS::Callbacks::tls_verify_message().

◆ wire_type()

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

Reimplemented in Botan::TLS::Hello_Retry_Request.

Definition at line 39 of file tls_handshake_msg.h.

39 {
40 // Usually equal to the Handshake_Type enum value,
41 // with the exception of TLS 1.3 Hello Retry Request.
42 return type();
43 }

References type().

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


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