diff options
author | Never <[email protected]> | 2018-03-23 20:09:56 +0100 |
---|---|---|
committer | Never <[email protected]> | 2018-03-27 19:14:48 +0200 |
commit | 899f108970483f8741073c3a7c48bfb71e5c9b27 (patch) | |
tree | b412f112681f0fd1611f9005de2ac8456324e089 | |
parent | b85bab68f917339e406ba64fe3468d681699bca8 (diff) |
add tls-custom-curve documentation + examples
-rw-r--r-- | doc/manual/tls.rst | 400 |
1 files changed, 394 insertions, 6 deletions
diff --git a/doc/manual/tls.rst b/doc/manual/tls.rst index a41245448..e83fdcb24 100644 --- a/doc/manual/tls.rst +++ b/doc/manual/tls.rst @@ -149,6 +149,16 @@ 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 @@ -900,13 +910,18 @@ policy settings from a file. DSA authentication is deprecated and will be removed in a future release. - .. cpp:function:: std::vector<std::string> allowed_ecc_curves() const + .. cpp:function:: std::vector<Group_Params> key_exchange_groups() const - Return a list of ECC curves we are willing to use, in order of preference. + Return a list of ECC curve and DH group TLS identifiers we are willing to use, in order of preference. The default ordering puts the best performing ECC first. - Default: "x25519", "secp256r1", "secp521r1", "secp384r1", - "brainpool256r1", "brainpool384r1", "brainpool512r1" + Default: + Group_Params::X25519, Group_Params::SECP256R1, + Group_Params::SECP521R1, Group_Params::SECP384R1, + Group_Params::BRAINPOOL256R1, Group_Params::BRAINPOOL384R1, + Group_Params::BRAINPOOL512R1, Group_Params::FFDHE_2048, + Group_Params::FFDHE_3072, Group_Params::FFDHE_4096, + Group_Params::FFDHE_6144, Group_Params::FFDHE_8192 No other values are currently defined. @@ -994,10 +1009,10 @@ policy settings from a file. Default: true - .. cpp:function:: std::string dh_group() const + .. cpp:function:: Group_Params default_dh_group() const For ephemeral Diffie-Hellman key exchange, the server sends a - group parameter. Return a string specifying the group parameter a + group parameter. Return the 2 Byte TLS group identifier specifying the group parameter a server should use. Default: 2048 bit IETF IPsec group ("modp/ietf/2048") @@ -1154,3 +1169,376 @@ 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 +---------------------------------------- + +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. + +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. + +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`` +3. Adjustment of the TLS policy by allowing the custom curve + +Client Code Example +^^^^^^^^^^^^ +.. code-block:: cpp + + #include <botan/tls_client.h> + #include <botan/tls_callbacks.h> + #include <botan/tls_session_manager.h> + #include <botan/tls_policy.h> + #include <botan/auto_rng.h> + #include <botan/certstor.h> + + #include <botan/ec_group.h> + #include <botan/oids.h> + + + /** + * @brief Callbacks invoked by TLS::Channel. + * + * Botan::TLS::Callbacks is an abstract class. + * For improved readability, only the functions that are mandatory + * to implement are listed here. See src/lib/tls/tls_callbacks.h. + */ + class Callbacks : public Botan::TLS::Callbacks + { + public: + void tls_emit_data(const uint8_t data[], size_t size) override + { + // send data to tls server, e.g., using BSD sockets or boost asio + } + + void tls_record_received(uint64_t seq_no, const uint8_t data[], size_t size) override + { + // process full TLS record received by tls server, e.g., + // by passing it to the application + } + + void tls_alert(Botan::TLS::Alert alert) override + { + // handle a tls alert received from the tls server + } + + bool tls_session_established(const Botan::TLS::Session& session) override + { + // the session with the tls server was established + // return false to prevent the session from being cached, true to + // cache the session in the configured session manager + return false; + } + 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 + + 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); + } + } + }; + + /** + * @brief Credentials storage for the tls client. + * + * It returns a list of trusted CA certificates from a local directory. + * TLS client authentication is disabled. See src/lib/tls/credentials_manager.h. + */ + class Client_Credentials : public Botan::Credentials_Manager + { + public: + std::vector<Botan::Certificate_Store*> trusted_certificate_authorities( + const std::string& type, + const std::string& context) override + { + // return a list of certificates of CAs we trust for tls server certificates, + // e.g., all the certificates in the local directory "cas" + return { new Botan::Certificate_Store_In_Memory("cas") }; + } + + std::vector<Botan::X509_Certificate> cert_chain( + const std::vector<std::string>& cert_key_types, + const std::string& type, + const std::string& context) override + { + // when using tls client authentication (optional), return + // a certificate chain being sent to the tls server, + // else an empty list + return std::vector<Botan::X509_Certificate>(); + } + + Botan::Private_Key* private_key_for(const Botan::X509_Certificate& cert, + const std::string& type, + const std::string& context) override + { + // when returning a chain in cert_chain(), return the private key + // associated with the leaf certificate here + return nullptr; + } + }; + + class Client_Policy : public Botan::TLS::Strict_Policy + { + public: + std::vector<Botan::TLS::Group_Params> key_exchange_groups() const override + { + // modified strict policy to allow our custom curves + return + { + static_cast<Botan::TLS::Group_Params>(0xFE00) + }; + } + }; + + int main() + { + // prepare rng + Botan::AutoSeeded_RNG rng; + + // prepare custom curve + + // prepare curve parameters + const Botan::BigInt p("0x92309a3e88b94312f36891a2055725bb35ab51af96b3a651d39321b7bbb8c51575a76768c9b6b323"); + const Botan::BigInt a("0x4f30b8e311f6b2dce62078d70b35dacb96aa84b758ab5a8dff0c9f7a2a1ff466c19988aa0acdde69"); + const Botan::BigInt b("0x9045A513CFFF9AE1F1CC84039D852D240344A1D5C9DB203C844089F855C387823EB6FCDDF49C909C"); + + const Botan::BigInt x("0x9120f3779a31296cefcb5a5a08831f1a6d438ad5a3f2ce60585ac19c74eebdc65cadb96bb92622c7"); + const Botan::BigInt y("0x836db8251c152dfee071b72c6b06c5387d82f1b5c30c5a5b65ee9429aa2687e8426d5d61276a4ede"); + const Botan::BigInt order("0x248c268fa22e50c4bcda24688155c96ecd6ad46be5c82d7a6be6e7068cb5d1ca72b2e07e8b90d853"); + + const Botan::BigInt cofactor(4); + + const Botan::OID oid("1.2.3.1"); + + // create EC_Group object to register the curve + Botan::EC_Group testcurve1102(p, a, b, x, y, order, cofactor, oid); + + if(!testcurve1102.verify_group(rng)) + { + // Warning: if verify_group returns false the curve parameters are insecure + } + + // register name to specified oid + Botan::OIDS::add_oid(oid, "testcurve1102"); + + // prepare all the parameters + Callbacks callbacks; + Botan::TLS::Session_Manager_In_Memory session_mgr(rng); + Client_Credentials creds; + Client_Policy policy; + + // open the tls connection + Botan::TLS::Client client(callbacks, + session_mgr, + creds, + policy, + rng, + Botan::TLS::Server_Information("botan.randombit.net", 443), + Botan::TLS::Protocol_Version::TLS_V12); + + + while(!client.is_closed()) + { + // read data received from the tls server, e.g., using BSD sockets or boost asio + // ... + + // send data to the tls server using client.send_data() + + } + } + +Server Code Example +^^^^^^^^^^^^ +.. code-block:: cpp + + #include <botan/tls_server.h> + #include <botan/tls_callbacks.h> + #include <botan/tls_session_manager.h> + #include <botan/tls_policy.h> + #include <botan/auto_rng.h> + #include <botan/certstor.h> + #include <botan/pk_keys.h> + #include <botan/pkcs8.h> + + #include <botan/ec_group.h> + #include <botan/oids.h> + + #include <memory> + + /** + * @brief Callbacks invoked by TLS::Channel. + * + * Botan::TLS::Callbacks is an abstract class. + * For improved readability, only the functions that are mandatory + * to implement are listed here. See src/lib/tls/tls_callbacks.h. + */ + class Callbacks : public Botan::TLS::Callbacks + { + public: + void tls_emit_data(const uint8_t data[], size_t size) override + { + // send data to tls client, e.g., using BSD sockets or boost asio + } + + void tls_record_received(uint64_t seq_no, const uint8_t data[], size_t size) override + { + // process full TLS record received by tls client, e.g., + // by passing it to the application + } + + void tls_alert(Botan::TLS::Alert alert) override + { + // handle a tls alert received from the tls server + } + + bool tls_session_established(const Botan::TLS::Session& session) override + { + // the session with the tls client was established + // return false to prevent the session from being cached, true to + // cache the session in the configured session manager + return false; + } + + 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 + + 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); + } + } + }; + + /** + * @brief Credentials storage for the tls server. + * + * It returns a certificate and the associated private key to + * authenticate the tls server to the client. + * TLS client authentication is not requested. + * See src/lib/tls/credentials_manager.h. + */ + class Server_Credentials : public Botan::Credentials_Manager + { + public: + Server_Credentials() : m_key(Botan::PKCS8::load_key("botan.randombit.net.key") + { + } + + std::vector<Botan::Certificate_Store*> trusted_certificate_authorities( + const std::string& type, + const std::string& context) override + { + // if client authentication is required, this function + // shall return a list of certificates of CAs we trust + // for tls client certificates, otherwise return an empty list + return std::vector<Botan::Certificate_Store*>(); + } + + std::vector<Botan::X509_Certificate> cert_chain( + const std::vector<std::string>& cert_key_types, + const std::string& type, + const std::string& context) override + { + // return the certificate chain being sent to the tls client + // e.g., the certificate file "botan.randombit.net.crt" + return { Botan::X509_Certificate("botan.randombit.net.crt") }; + } + + Botan::Private_Key* private_key_for(const Botan::X509_Certificate& cert, + const std::string& type, + const std::string& context) override + { + // return the private key associated with the leaf certificate, + // in this case the one associated with "botan.randombit.net.crt" + return m_key.get(); + } + + private: + std::unique_ptr<Botan::Private_Key> m_key; + }; + + class Server_Policy : public Botan::TLS::Strict_Policy + { + public: + std::vector<Botan::TLS::Group_Params> key_exchange_groups() const override + { + // modified strict policy to allow our custom curves + return + { + static_cast<Botan::TLS::Group_Params>(0xFE00) + }; + } + }; + + int main() + { + + // prepare rng + Botan::AutoSeeded_RNG rng; + + // prepare custom curve + + // prepare curve parameters + const Botan::BigInt p("0x92309a3e88b94312f36891a2055725bb35ab51af96b3a651d39321b7bbb8c51575a76768c9b6b323"); + const Botan::BigInt a("0x4f30b8e311f6b2dce62078d70b35dacb96aa84b758ab5a8dff0c9f7a2a1ff466c19988aa0acdde69"); + const Botan::BigInt b("0x9045A513CFFF9AE1F1CC84039D852D240344A1D5C9DB203C844089F855C387823EB6FCDDF49C909C"); + + const Botan::BigInt x("0x9120f3779a31296cefcb5a5a08831f1a6d438ad5a3f2ce60585ac19c74eebdc65cadb96bb92622c7"); + const Botan::BigInt y("0x836db8251c152dfee071b72c6b06c5387d82f1b5c30c5a5b65ee9429aa2687e8426d5d61276a4ede"); + const Botan::BigInt order("0x248c268fa22e50c4bcda24688155c96ecd6ad46be5c82d7a6be6e7068cb5d1ca72b2e07e8b90d853"); + + const Botan::BigInt cofactor(4); + + const Botan::OID oid("1.2.3.1"); + + // create EC_Group object to register the curve + Botan::EC_Group testcurve1102(p, a, b, x, y, order, cofactor, oid); + + if(!testcurve1102.verify_group(rng)) + { + // Warning: if verify_group returns false the curve parameters are insecure + } + + // register name to specified oid + Botan::OIDS::add_oid(oid, "testcurve1102"); + + // prepare all the parameters + Callbacks callbacks; + Botan::TLS::Session_Manager_In_Memory session_mgr(rng); + Server_Credentials creds; + Server_Policy policy; + + // accept tls connection from client + Botan::TLS::Server server(callbacks, + session_mgr, + creds, + policy, + rng); + + // read data received from the tls client, e.g., using BSD sockets or boost asio + // and pass it to server.received_data(). + // ... + + // send data to the tls client using server.send_data() + // ... + } |