Skip to content

Commit

Permalink
Showcase _hex literal in the TLS implementation
Browse files Browse the repository at this point in the history
This is a small drive-by modernization to showcase the _hex literal
in some places of the TLS 1.2/1.3 implementation.

There are probably many more locations where this could be useful, but
we have to start somewhere.
  • Loading branch information
reneme committed Dec 23, 2024
1 parent b883e84 commit dd0613f
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 58 deletions.
1 change: 1 addition & 0 deletions src/lib/tls/info.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ tls_reader.h
</header:internal>

<requires>
literals
rng
tls12
</requires>
18 changes: 7 additions & 11 deletions src/lib/tls/msg_finished.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <botan/kdf.h>
#include <botan/internal/ct_utils.h>
#include <botan/internal/literals.h>
#include <botan/internal/tls_handshake_io.h>
#include <botan/internal/tls_handshake_state.h>

Expand All @@ -26,22 +27,17 @@ namespace {
* Compute the verify_data for TLS 1.2
*/
std::vector<uint8_t> finished_compute_verify_12(const Handshake_State& state, Connection_Side side) {
const uint8_t TLS_CLIENT_LABEL[] = {
0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x20, 0x66, 0x69, 0x6E, 0x69, 0x73, 0x68, 0x65, 0x64};
using namespace literals;

const uint8_t TLS_SERVER_LABEL[] = {
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x66, 0x69, 0x6E, 0x69, 0x73, 0x68, 0x65, 0x64};
constexpr auto TLS_CLIENT_LABEL = "636C69656E742066696E6973686564"_hex;
constexpr auto TLS_SERVER_LABEL = "7365727665722066696E6973686564"_hex;

auto prf = state.protocol_specific_prf();

std::vector<uint8_t> input;
std::vector<uint8_t> label;
label += (side == Connection_Side::Client) ? std::make_pair(TLS_CLIENT_LABEL, sizeof(TLS_CLIENT_LABEL))
: std::make_pair(TLS_SERVER_LABEL, sizeof(TLS_SERVER_LABEL));
const auto input = state.hash().final(state.ciphersuite().prf_algo());
const auto label = (side == Connection_Side::Client) ? TLS_CLIENT_LABEL : TLS_SERVER_LABEL;

input += state.hash().final(state.ciphersuite().prf_algo());

return unlock(prf->derive_key(12, state.session_keys().master_secret(), input, label));
return prf->derive_key<std::vector<uint8_t>>(12, state.session_keys().master_secret(), input, label);
}

} // namespace
Expand Down
22 changes: 12 additions & 10 deletions src/lib/tls/msg_server_hello.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <botan/tls_extensions.h>
#include <botan/tls_session_manager.h>
#include <botan/internal/ct_utils.h>
#include <botan/internal/literals.h>
#include <botan/internal/stl_util.h>
#include <botan/internal/tls_handshake_hash.h>
#include <botan/internal/tls_handshake_io.h>
Expand All @@ -33,9 +34,9 @@ const uint64_t DOWNGRADE_TLS11 = 0x444F574E47524400;
const uint64_t DOWNGRADE_TLS12 = 0x444F574E47524401;

// SHA-256("HelloRetryRequest")
const std::vector<uint8_t> HELLO_RETRY_REQUEST_MARKER = {
0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, 0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91,
0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C};
using namespace literals;
constexpr auto HELLO_RETRY_REQUEST_MARKER =
"CF:21:AD:74:E5:9A:61:11:BE:1D:8C:02:1E:65:B8:91:C2:A2:11:16:7A:BB:8C:5E:07:9E:09:E2:C8:A8:33:9C"_hex;

bool random_signals_hello_retry_request(const std::vector<uint8_t>& random) {
return CT::is_equal(random.data(), HELLO_RETRY_REQUEST_MARKER.data(), HELLO_RETRY_REQUEST_MARKER.size()).as_bool();
Expand Down Expand Up @@ -789,13 +790,14 @@ Hello_Retry_Request::Hello_Retry_Request(const Client_Hello_13& ch,
Named_Group selected_group,
const Policy& policy,
Callbacks& cb) :
Server_Hello_13(std::make_unique<Server_Hello_Internal>(Protocol_Version::TLS_V12 /* legacy_version */,
ch.session_id(),
HELLO_RETRY_REQUEST_MARKER,
choose_ciphersuite(ch, policy),
uint8_t(0) /* compression method */,
true /* is Hello Retry Request */
),
Server_Hello_13(std::make_unique<Server_Hello_Internal>(
Protocol_Version::TLS_V12 /* legacy_version */,
ch.session_id(),
std::vector(HELLO_RETRY_REQUEST_MARKER.begin(), HELLO_RETRY_REQUEST_MARKER.end()),
choose_ciphersuite(ch, policy),
uint8_t(0) /* compression method */,
true /* is Hello Retry Request */
),
as_new_hello_retry_request) {
// RFC 8446 4.1.4
// As with the ServerHello, a HelloRetryRequest MUST NOT contain any
Expand Down
69 changes: 32 additions & 37 deletions src/lib/tls/tls12/tls_session_key.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

#include <botan/kdf.h>
#include <botan/tls_messages.h>
#include <botan/internal/literals.h>
#include <botan/internal/stl_util.h>
#include <botan/internal/tls_handshake_state.h>

namespace Botan::TLS {
Expand All @@ -19,66 +21,59 @@ namespace Botan::TLS {
Session_Keys::Session_Keys(const Handshake_State* state,
const secure_vector<uint8_t>& pre_master_secret,
bool resuming) {
using namespace literals;

const size_t cipher_keylen = state->ciphersuite().cipher_keylen();
const size_t mac_keylen = state->ciphersuite().mac_keylen();
const size_t cipher_nonce_bytes = state->ciphersuite().nonce_bytes_from_handshake();

const bool extended_master_secret = state->server_hello()->supports_extended_master_secret();

const size_t prf_gen = 2 * (mac_keylen + cipher_keylen + cipher_nonce_bytes);

const uint8_t MASTER_SECRET_MAGIC[] = {0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74};

const uint8_t EXT_MASTER_SECRET_MAGIC[] = {0x65, 0x78, 0x74, 0x65, 0x6E, 0x64, 0x65, 0x64, 0x20, 0x6D, 0x61,
0x73, 0x74, 0x65, 0x72, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74};

const uint8_t KEY_GEN_MAGIC[] = {0x6B, 0x65, 0x79, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6E, 0x73, 0x69, 0x6F, 0x6E};
constexpr auto MASTER_SECRET_MAGIC = "6D617374657220736563726574"_hex;
constexpr auto EXT_MASTER_SECRET_MAGIC = "657874656E646564206D617374657220736563726574"_hex;
constexpr auto KEY_GEN_MAGIC = "6B657920657870616E73696F6E"_hex;

auto prf = state->protocol_specific_prf();

if(resuming) {
// This is actually the master secret saved as part of the session
m_master_sec = pre_master_secret;
} else {
std::vector<uint8_t> salt;
std::vector<uint8_t> label;
if(extended_master_secret) {
label.assign(EXT_MASTER_SECRET_MAGIC, EXT_MASTER_SECRET_MAGIC + sizeof(EXT_MASTER_SECRET_MAGIC));
salt += state->hash().final(state->ciphersuite().prf_algo());
} else {
label.assign(MASTER_SECRET_MAGIC, MASTER_SECRET_MAGIC + sizeof(MASTER_SECRET_MAGIC));
salt += state->client_hello()->random();
salt += state->server_hello()->random();
}
const auto [salt, label] = [&]() -> std::pair<secure_vector<uint8_t>, std::span<const uint8_t>> {
if(state->server_hello()->supports_extended_master_secret()) {
return {
state->hash().final(state->ciphersuite().prf_algo()),
EXT_MASTER_SECRET_MAGIC,
};
} else {
return {
concat<secure_vector<uint8_t>>(state->client_hello()->random(), state->server_hello()->random()),
MASTER_SECRET_MAGIC,
};
}
}();

m_master_sec = prf->derive_key(48, pre_master_secret, salt, label);
}

std::vector<uint8_t> salt;
std::vector<uint8_t> label;
label.assign(KEY_GEN_MAGIC, KEY_GEN_MAGIC + sizeof(KEY_GEN_MAGIC));
salt += state->server_hello()->random();
salt += state->client_hello()->random();

const secure_vector<uint8_t> prf_output = prf->derive_key(
prf_gen, m_master_sec.data(), m_master_sec.size(), salt.data(), salt.size(), label.data(), label.size());

const uint8_t* key_data = prf_output.data();
const auto salt = concat(state->server_hello()->random(), state->client_hello()->random());
const auto prf_output = prf->derive_key(prf_gen, m_master_sec, salt, KEY_GEN_MAGIC);

m_c_aead.resize(mac_keylen + cipher_keylen);
m_s_aead.resize(mac_keylen + cipher_keylen);

copy_mem(&m_c_aead[0], key_data, mac_keylen);
copy_mem(&m_s_aead[0], key_data + mac_keylen, mac_keylen);
BufferSlicer key_material(prf_output);

copy_mem(&m_c_aead[mac_keylen], key_data + 2 * mac_keylen, cipher_keylen);
copy_mem(&m_s_aead[mac_keylen], key_data + 2 * mac_keylen + cipher_keylen, cipher_keylen);
const auto c_aead_mac = key_material.take(mac_keylen);
const auto s_aead_mac = key_material.take(mac_keylen);
const auto c_aead_cipher = key_material.take(cipher_keylen);
const auto s_aead_cipher = key_material.take(cipher_keylen);

m_c_nonce.resize(cipher_nonce_bytes);
m_s_nonce.resize(cipher_nonce_bytes);
m_c_aead = concat<secure_vector<uint8_t>>(c_aead_mac, c_aead_cipher);
m_s_aead = concat<secure_vector<uint8_t>>(s_aead_mac, s_aead_cipher);
m_c_nonce = key_material.copy_as_vector(cipher_nonce_bytes);
m_s_nonce = key_material.copy_as_vector(cipher_nonce_bytes);

copy_mem(&m_c_nonce[0], key_data + 2 * (mac_keylen + cipher_keylen), cipher_nonce_bytes);
copy_mem(&m_s_nonce[0], key_data + 2 * (mac_keylen + cipher_keylen) + cipher_nonce_bytes, cipher_nonce_bytes);
BOTAN_ASSERT_NOMSG(key_material.empty());
}

} // namespace Botan::TLS

0 comments on commit dd0613f

Please sign in to comment.