Skip to content

Commit

Permalink
Merge pull request #3322 from randombit/tls13/crypto_callbacks
Browse files Browse the repository at this point in the history
[TLS 1.3] Generalize ephemeral key handling callbacks
  • Loading branch information
reneme authored Mar 22, 2023
2 parents 88eaa00 + b32701c commit 33c6ad9
Show file tree
Hide file tree
Showing 13 changed files with 352 additions and 469 deletions.
42 changes: 16 additions & 26 deletions doc/api_ref/tls.rst
Original file line number Diff line number Diff line change
Expand Up @@ -188,16 +188,6 @@ information about the connection.

Optional logging for an debug value. (Not currently used)

.. cpp:function:: std::string tls_decode_group_param(TLS::Group_Params group_param)

Optional. Called by the server when a client hello includes a list of supported groups in the
supported_groups extension and by the client when decoding the server key exchange including the selected curve identifier.
The function should return the name of the DH group or elliptic curve the passed
TLS group identifier should be mapped to. Therefore this callback enables the use of custom
elliptic curves or DH groups in TLS, if both client and server map the custom identifiers correctly.
Please note that it is required to allow the group TLS identifier in
in the used :cpp:class:`TLS::Policy`.

Versions from 1.11.0 to 1.11.30 did not have ``TLS::Callbacks`` and instead
used independent std::functions to pass the various callback functions.
This interface is currently still included but is deprecated and will be removed
Expand Down Expand Up @@ -1009,36 +999,36 @@ The ``TLS::Protocol_Version`` class represents a specific version:
Returns the latest version of the DTLS protocol known to the
library (currently DTLS v1.2)

TLS Custom Curves
TLS Custom Key Exchange Mechanisms
----------------------------------------

The supported_groups TLS extension is used in the client hello to advertise a list of supported elliptic curves
and DH groups. The server subsequently selects one of the groups, which is supported by both endpoints.
The groups are represented by their TLS identifier. This 2 Byte identifier is standardized for commonly used groups and curves.
In addition, the standard reserves the identifiers 0xFE00 to 0xFEFF for custom groups or curves.
Applications can override the ephemeral key exchange mechanism used in TLS.
This is not necessary for typical applications and might pose a serious security risk.
Though, it allows the usage of custom groups or curves, offloading of cryptographic calculations to
special hardware or the addition of entirely different algorithms (e.g. for post-quantum resilience).

Using non standardized custom curves is however not recommended and can be a serious risk if an
insecure curve is used. Still, it might be desired in some scenarios to use custom curves or groups in the TLS handshake.
From a technical point of view, the supported_groups TLS extension is used in the client hello to
advertise a list of supported elliptic curves and DH groups. The server subsequently selects one of
the groups, which is supported by both endpoints. Groups are represented by their TLS identifier.
This two-byte identifier is standardized for commonly used groups and curves. In addition, the standard
reserves the identifiers 0xFE00 to 0xFEFF for custom groups, curves or other algorithms.

To use custom curves with the Botan :cpp:class:`TLS::Client` or :cpp:class:`TLS::Server` the following additional adjustments have to be implemented
as shown in the following code examples.
To use custom curves with the Botan :cpp:class:`TLS::Client` or :cpp:class:`TLS::Server` the following
additional adjustments have to be implemented as shown in the following code examples.

1. Registration of the custom curve
2. Implementation TLS callback ``tls_decode_group_param``
2. Implementation TLS callbacks ``tls_generate_ephemeral_key`` and ``tls_ephemeral_key_agreement``
3. Adjustment of the TLS policy by allowing the custom curve

Below is a code example for a TLS client using a custom curve.
For servers, it works exactly the same.

Client Code Example
^^^^^^^^^^^^^^^^^^^^

.. literalinclude:: /../src/examples/tls_custom_curves_client.cpp
:language: cpp

Server Code Example
^^^^^^^^^^^^^^^^^^^^^

.. literalinclude:: /../src/examples/tls_custom_curves_server.cpp
:language: cpp

TLS Stream
----------------------------------------

Expand Down
13 changes: 13 additions & 0 deletions doc/migration_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,19 @@ identify the TLS handshake message the extensions in question are residing in.
TLS 1.3 makes much heavier use of such extensions in a wider range of messages
to implement core protocol functionality.

tls_dh_agree() / tls_ecdh_agree() / tls_decode_group_param()
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

These callbacks were used as customization points for the TLS 1.2 key exchange
in the TLS client. To allow similar (and more) customizations with the
introduction of TLS 1.3, these callbacks were replaced with a more generic
approach.

Key agreement is split into two callbacks, namely `tls_generate_ephemeral_key()`
and `tls_ephemeral_key_agreement()`. Those are used in both clients and servers
and in all protocol versions. `tls_decode_group_param()` is removed as it became
obsolete by the replacement of the other two callbacks.

Policy
^^^^^^

Expand Down
2 changes: 1 addition & 1 deletion src/examples/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ clean:

PKCS11_EXAMPLES = pkcs11_low_level pkcs11_module pkcs11_slot pkcs11_session pkcs11_objects pkcs11_rsa pkcs11_ecdsa pkcs11_ecdh pkcs11_rng pkcs11_token_management pkcs11_x509

EXAMPLES = aes aes_cbc chacha check_key cmac dl_group ecdh ecdsa encrypt_with_pkcs8_key gmac hash hmac tls_client tls_custom_curves_client tls_custom_curves_server tls_proxy tls_stream_client xmss $(PKCS11_EXAMPLES)
EXAMPLES = aes aes_cbc chacha check_key cmac dl_group ecdh ecdsa encrypt_with_pkcs8_key gmac hash hmac tls_client tls_custom_curves_client tls_proxy tls_stream_client xmss $(PKCS11_EXAMPLES)

examples: $(addprefix build/, $(EXAMPLES))

Expand Down
40 changes: 29 additions & 11 deletions src/examples/tls_custom_curves_client.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#include <botan/auto_rng.h>
#include <botan/certstor.h>
#include <botan/ecdh.h>
#include <botan/oids.h>
#include <botan/tls_callbacks.h>
#include <botan/tls_client.h>
#include <botan/tls_policy.h>
#include <botan/tls_session_manager_memory.h>
#include <botan/ec_group.h>
#include <botan/oids.h>

/**
* @brief Callbacks invoked by TLS::Channel.
Expand All @@ -29,16 +29,34 @@ class Callbacks : public Botan::TLS::Callbacks {
// handle a tls alert received from the tls server
}

std::string tls_decode_group_param(Botan::TLS::Group_Params group_param) override {
// handle TLS group identifier decoding and return name as string
// return empty string to indicate decoding failure
std::unique_ptr<Botan::PK_Key_Agreement_Key>
tls_generate_ephemeral_key(std::variant<Botan::TLS::Group_Params, Botan::DL_Group> group,
Botan::RandomNumberGenerator &rng) override {
if (std::holds_alternative<Botan::TLS::Group_Params>(group) &&
std::get<Botan::TLS::Group_Params>(group) == Botan::TLS::Group_Params(0xFE00)) {
// generate a private key of my custom curve
const Botan::EC_Group ec_group("testcurve1102");
return std::make_unique<Botan::ECDH_PrivateKey>(rng, ec_group);
} else {
// no custom curve used: up-call the default implementation
return tls_generate_ephemeral_key(group, rng);
}
}

switch (static_cast<uint16_t>(group_param)) {
case 0xFE00:
return "testcurve1102";
default:
// decode non-custom groups
return Botan::TLS::Callbacks::tls_decode_group_param(group_param);
Botan::secure_vector<uint8_t> tls_ephemeral_key_agreement(
std::variant<Botan::TLS::Group_Params, Botan::DL_Group> group,
const Botan::PK_Key_Agreement_Key &private_key, const std::vector<uint8_t> &public_value,
Botan::RandomNumberGenerator &rng, const Botan::TLS::Policy &policy) override {
if (std::holds_alternative<Botan::TLS::Group_Params>(group) &&
std::get<Botan::TLS::Group_Params>(group) == Botan::TLS::Group_Params(0xFE00)) {
// perform a key agreement on my custom curve
const Botan::EC_Group ec_group("testcurve1102");
Botan::ECDH_PublicKey peer_key(ec_group, ec_group.OS2ECP(public_value));
Botan::PK_Key_Agreement ka(private_key, rng, "Raw");
return ka.derive_key(0, peer_key.public_value()).bits_of();
} else {
// no custom curve used: up-call the default implementation
return tls_ephemeral_key_agreement(group, private_key, public_value, rng, policy);
}
}
};
Expand Down
165 changes: 0 additions & 165 deletions src/examples/tls_custom_curves_server.cpp

This file was deleted.

Loading

0 comments on commit 33c6ad9

Please sign in to comment.