Botan 3.9.0
Crypto and TLS for C&
msg_server_kex.cpp
Go to the documentation of this file.
1/*
2* Server Key Exchange Message
3* (C) 2004-2010,2012,2015,2016 Jack Lloyd
4* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/tls_messages.h>
10
11#include <botan/credentials_manager.h>
12#include <botan/pubkey.h>
13#include <botan/tls_extensions.h>
14#include <botan/internal/loadstor.h>
15#include <botan/internal/target_info.h>
16#include <botan/internal/tls_handshake_io.h>
17#include <botan/internal/tls_handshake_state.h>
18#include <botan/internal/tls_reader.h>
19
20#include <botan/dh.h>
21#include <botan/ecdh.h>
22
23namespace Botan::TLS {
24
25/**
26* Create a new Server Key Exchange message
27*/
29 Handshake_State& state,
30 const Policy& policy,
33 const Private_Key* signing_key) {
34 const std::string hostname = state.client_hello()->sni_hostname();
35 const Kex_Algo kex_algo = state.ciphersuite().kex_method();
36
37 if(kex_algo == Kex_Algo::PSK || kex_algo == Kex_Algo::ECDHE_PSK) {
38 std::string identity_hint = creds.psk_identity_hint("tls-server", hostname);
39
40 append_tls_length_value(m_params, identity_hint, 2);
41 }
42
43 if(kex_algo == Kex_Algo::DH) {
44 const std::vector<Group_Params> dh_groups = state.client_hello()->supported_dh_groups();
45
46 m_shared_group = Group_Params::NONE;
47
48 /*
49 RFC 7919 requires that if the client sends any groups in the FFDHE
50 range, that we must select one of these. If this is not possible,
51 then we are required to reject the connection.
52
53 If the client did not send any DH groups, but did offer DH ciphersuites
54 and we selected one, then consult the policy for which DH group to pick.
55 */
56
57 if(dh_groups.empty()) {
58 m_shared_group = policy.default_dh_group();
59 } else {
60 m_shared_group = policy.choose_key_exchange_group(dh_groups, {});
61 }
62
63 if(m_shared_group.value() == Group_Params::NONE) {
64 throw TLS_Exception(Alert::HandshakeFailure, "Could not agree on a DH group with the client");
65 }
66
67 // The policy had better return a group we know about:
68 BOTAN_ASSERT(m_shared_group.value().is_dh_named_group(), "DH ciphersuite is using a known finite field group");
69
70 // Note: TLS 1.2 allows defining and using arbitrary DH groups (additional
71 // to the named and standardized ones). This API doesn't allow the
72 // server to make use of that at the moment. TLS 1.3 does not
73 // provide this flexibility!
74 //
75 // A possible implementation strategy in case one would ever need that:
76 // `Policy::default_dh_group()` could return a `std::variant<Group_Params,
77 // DL_Group>`, allowing it to define arbitrary groups.
78 m_kex_key = state.callbacks().tls_generate_ephemeral_key(m_shared_group.value(), rng);
79 auto* dh = dynamic_cast<DH_PrivateKey*>(m_kex_key.get());
80 if(dh == nullptr) {
81 throw TLS_Exception(Alert::InternalError, "Application did not provide a Diffie-Hellman key");
82 }
83
84 append_tls_length_value(m_params, dh->get_int_field("p").serialize(), 2);
85 append_tls_length_value(m_params, dh->get_int_field("g").serialize(), 2);
86 append_tls_length_value(m_params, dh->public_value(), 2);
87 } else if(kex_algo == Kex_Algo::ECDH || kex_algo == Kex_Algo::ECDHE_PSK) {
88 const std::vector<Group_Params> ec_groups = state.client_hello()->supported_ecc_curves();
89
90 if(ec_groups.empty()) {
91 throw Internal_Error("Client sent no ECC extension but we negotiated ECDH");
92 }
93
94 m_shared_group = policy.choose_key_exchange_group(ec_groups, {});
95
96 if(m_shared_group.value() == Group_Params::NONE) {
97 throw TLS_Exception(Alert::HandshakeFailure, "No shared ECC group with client");
98 }
99
100 std::vector<uint8_t> ecdh_public_val;
101
102 if(m_shared_group.value() == Group_Params::X25519 || m_shared_group.value() == Group_Params::X448) {
103 m_kex_key = state.callbacks().tls_generate_ephemeral_key(m_shared_group.value(), rng);
104 if(!m_kex_key) {
105 throw TLS_Exception(Alert::InternalError, "Application did not provide an EC key");
106 }
107 ecdh_public_val = m_kex_key->public_value();
108 } else {
109 m_kex_key = state.callbacks().tls_generate_ephemeral_key(m_shared_group.value(), rng);
110 auto* ecdh = dynamic_cast<ECDH_PrivateKey*>(m_kex_key.get());
111 if(ecdh == nullptr) {
112 throw TLS_Exception(Alert::InternalError, "Application did not provide a EC-Diffie-Hellman key");
113 }
114
115 // follow client's preference for point compression
116 ecdh_public_val =
117 ecdh->public_value(state.client_hello()->prefers_compressed_ec_points() ? EC_Point_Format::Compressed
119 }
120
121 const uint16_t named_curve_id = m_shared_group.value().wire_code();
122 m_params.push_back(3); // named curve
123 m_params.push_back(get_byte<0>(named_curve_id));
124 m_params.push_back(get_byte<1>(named_curve_id));
125
126 append_tls_length_value(m_params, ecdh_public_val, 1);
127 } else if(kex_algo != Kex_Algo::PSK) {
128 throw Internal_Error("Server_Key_Exchange: Unknown kex type " + kex_method_to_string(kex_algo));
129 }
130
131 if(state.ciphersuite().signature_used()) {
132 BOTAN_ASSERT(signing_key, "Signing key was set");
133
134 std::pair<std::string, Signature_Format> format = state.choose_sig_format(*signing_key, m_scheme, false, policy);
135
136 std::vector<uint8_t> buf = state.client_hello()->random();
137
138 buf += state.server_hello()->random();
139 buf += params();
140
141 m_signature = state.callbacks().tls_sign_message(*signing_key, rng, format.first, format.second, buf);
142 }
143
144 state.hash().update(io.send(*this));
145}
146
147/**
148* Deserialize a Server Key Exchange message
149*/
150Server_Key_Exchange::Server_Key_Exchange(const std::vector<uint8_t>& buf,
151 const Kex_Algo kex_algo,
152 const Auth_Method auth_method,
153 Protocol_Version version) {
154 BOTAN_UNUSED(version); // remove this
155 TLS_Data_Reader reader("ServerKeyExchange", buf);
156
157 /*
158 * Here we are deserializing enough to find out what offset the
159 * signature is at. All processing is done when the Client Key Exchange
160 * is prepared.
161 */
162
163 if(kex_algo == Kex_Algo::PSK || kex_algo == Kex_Algo::ECDHE_PSK) {
164 reader.get_string(2, 0, 65535); // identity hint
165 }
166
167 if(kex_algo == Kex_Algo::DH) {
168 // 3 bigints, DH p, g, Y
169
170 for(size_t i = 0; i != 3; ++i) {
171 reader.get_range<uint8_t>(2, 1, 65535);
172 }
173 } else if(kex_algo == Kex_Algo::ECDH || kex_algo == Kex_Algo::ECDHE_PSK) {
174 reader.get_byte(); // curve type
175 reader.get_uint16_t(); // curve id
176 reader.get_range<uint8_t>(1, 1, 255); // public key
177 } else if(kex_algo != Kex_Algo::PSK) {
178 throw Decoding_Error("Server_Key_Exchange: Unsupported kex type " + kex_method_to_string(kex_algo));
179 }
180
181 m_params.assign(buf.data(), buf.data() + reader.read_so_far());
182
183 if(auth_method != Auth_Method::IMPLICIT) {
184 m_scheme = Signature_Scheme(reader.get_uint16_t());
185 m_signature = reader.get_range<uint8_t>(2, 0, 65535);
186 }
187
188 reader.assert_done();
189}
190
191/**
192* Serialize a Server Key Exchange message
193*/
194std::vector<uint8_t> Server_Key_Exchange::serialize() const {
195 std::vector<uint8_t> buf = params();
196
197 if(!m_signature.empty()) {
198 if(m_scheme.is_set()) {
199 buf.push_back(get_byte<0>(m_scheme.wire_code()));
200 buf.push_back(get_byte<1>(m_scheme.wire_code()));
201 }
202
203 append_tls_length_value(buf, m_signature, 2);
204 }
205
206 return buf;
207}
208
209/**
210* Verify a Server Key Exchange message
211*/
213 const Handshake_State& state,
214 const Policy& policy) const {
215 policy.check_peer_key_acceptable(server_key);
216
217 std::pair<std::string, Signature_Format> format =
218 state.parse_sig_format(server_key, m_scheme, state.client_hello()->signature_schemes(), false, policy);
219
220 std::vector<uint8_t> buf = state.client_hello()->random();
221
222 buf += state.server_hello()->random();
223 buf += params();
224
225 const bool signature_valid =
226 state.callbacks().tls_verify_message(server_key, format.first, format.second, buf, m_signature);
227
228#if defined(BOTAN_UNSAFE_FUZZER_MODE)
229 BOTAN_UNUSED(signature_valid);
230 return true;
231#else
232 return signature_valid;
233#endif
234}
235
237 BOTAN_ASSERT_NONNULL(m_kex_key);
238 return *m_kex_key;
239}
240
241} // namespace Botan::TLS
#define BOTAN_UNUSED
Definition assert.h:144
#define BOTAN_ASSERT_NONNULL(ptr)
Definition assert.h:114
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:62
virtual std::string psk_identity_hint(const std::string &type, const std::string &context)
std::vector< uint8_t > public_value() const override
Definition ecdh.h:115
virtual std::vector< uint8_t > tls_sign_message(const Private_Key &key, RandomNumberGenerator &rng, std::string_view padding, Signature_Format format, const std::vector< uint8_t > &msg)
virtual std::unique_ptr< PK_Key_Agreement_Key > tls_generate_ephemeral_key(const std::variant< TLS::Group_Params, DL_Group > &group, RandomNumberGenerator &rng)
virtual bool tls_verify_message(const Public_Key &key, std::string_view padding, Signature_Format format, const std::vector< uint8_t > &msg, const std::vector< uint8_t > &sig)
Kex_Algo kex_method() const
constexpr uint16_t wire_code() const
Definition tls_algos.h:165
void update(const uint8_t in[], size_t length)
virtual std::vector< uint8_t > send(const Handshake_Message &msg)=0
virtual std::vector< uint8_t > serialize() const =0
std::pair< std::string, Signature_Format > parse_sig_format(const Public_Key &key, Signature_Scheme scheme, const std::vector< Signature_Scheme > &offered_schemes, bool for_client_auth, const Policy &policy) const
void client_hello(std::unique_ptr< Client_Hello_12 > client_hello)
void server_hello(std::unique_ptr< Server_Hello_12 > server_hello)
const Ciphersuite & ciphersuite() const
std::pair< std::string, Signature_Format > choose_sig_format(const Private_Key &key, Signature_Scheme &scheme, bool for_client_auth, const Policy &policy) const
virtual void check_peer_key_acceptable(const Public_Key &public_key) const
virtual Group_Params default_dh_group() const
virtual Group_Params choose_key_exchange_group(const std::vector< Group_Params > &supported_by_peer, const std::vector< Group_Params > &offered_by_peer) const
bool verify(const Public_Key &server_key, const Handshake_State &state, const Policy &policy) const
const PK_Key_Agreement_Key & server_kex_key() const
const std::vector< uint8_t > & params() const
Server_Key_Exchange(Handshake_IO &io, Handshake_State &state, const Policy &policy, Credentials_Manager &creds, RandomNumberGenerator &rng, const Private_Key *signing_key=nullptr)
Signature_Scheme::Code wire_code() const noexcept
std::string get_string(size_t len_bytes, size_t min_bytes, size_t max_bytes)
Definition tls_reader.h:123
size_t read_so_far() const
Definition tls_reader.h:36
std::vector< T > get_range(size_t len_bytes, size_t min_elems, size_t max_elems)
Definition tls_reader.h:110
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:184
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