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