From 2b46eabbeda72f68615d0c9cbd6f149c26918eec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Meusel?= Date: Wed, 12 Jun 2024 07:08:15 -0400 Subject: [PATCH] Update various documentation comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was originally done by René in a series of doc updates related to using Breathe for our API reference. I (Jack) am still unconvinced of adopting this for various reasons (build times, limited distro support, apparently abandoned upstream, etc) but the documentation comments themselves are certainly an improvement. --- src/build-data/buildh.in | 21 ++++ src/lib/compression/compression.h | 29 ++++- src/lib/mac/mac.h | 2 +- src/lib/math/numbertheory/numthry.h | 5 + src/lib/modes/aead/aead.h | 26 ++-- src/lib/modes/cipher_mode.h | 49 +++++++- src/lib/passhash/argon2fmt/argon2fmt.h | 9 ++ src/lib/passhash/bcrypt/bcrypt.h | 35 ++++++ src/lib/passhash/passhash9/passhash9.h | 22 +++- src/lib/pbkdf/pwdhash.h | 36 ++++-- src/lib/psk_db/psk_db.h | 72 +++++++---- src/lib/pubkey/ec_group/ec_group.h | 6 +- src/lib/pubkey/ec_group/ec_point.h | 11 ++ src/lib/stream/stream_cipher.h | 28 ++++- src/lib/tls/credentials_manager.h | 73 ++++++++---- src/lib/tls/tls_alert.h | 10 +- src/lib/tls/tls_callbacks.h | 104 +++++++++++----- src/lib/tls/tls_channel.h | 12 +- src/lib/tls/tls_ciphersuite.h | 2 + src/lib/tls/tls_client.h | 48 +++++--- src/lib/tls/tls_policy.h | 159 ++++++++++++++++++++----- src/lib/tls/tls_server.h | 26 +++- src/lib/tls/tls_session.h | 5 + src/lib/tls/tls_version.h | 19 ++- src/lib/utils/version.h | 29 ++++- 25 files changed, 664 insertions(+), 174 deletions(-) diff --git a/src/build-data/buildh.in b/src/build-data/buildh.in index d39b5a62401..dc6409c84cd 100644 --- a/src/build-data/buildh.in +++ b/src/build-data/buildh.in @@ -24,9 +24,18 @@ * @{ */ +/// The major version of the release #define BOTAN_VERSION_MAJOR %{version_major} +/// The minor version of the release #define BOTAN_VERSION_MINOR %{version_minor} +/// The patch version of the release #define BOTAN_VERSION_PATCH %{version_patch} + +/** + * Expands to an integer of the form YYYYMMDD if this is an official + * release, or 0 otherwise. For instance, 2.19.0, which was released + * on January 19, 2022, has a `BOTAN_VERSION_DATESTAMP` of 20220119. + */ #define BOTAN_VERSION_DATESTAMP %{version_datestamp} %{if version_suffix} @@ -36,8 +45,20 @@ #define BOTAN_VERSION_RELEASE_TYPE "%{release_type}" +/** + * A macro expanding to a string that is set to a revision identifier + * corresponding to the source, or "unknown" if this could not be + * determined. It is set for all official releases, and for builds that + * originated from within a git checkout. + */ #define BOTAN_VERSION_VC_REVISION "%{version_vc_rev}" +/** + * A macro expanding to a string that is set at build time using the + * `--distribution-info` option. It allows a packager of the library + * to specify any distribution-specific patches. If no value is given + * at build time, the value is the string "unspecified". + */ #define BOTAN_DISTRIBUTION_INFO "%{distribution_info}" /** diff --git a/src/lib/compression/compression.h b/src/lib/compression/compression.h index 6dfab7369f4..d34cd6f234e 100644 --- a/src/lib/compression/compression.h +++ b/src/lib/compression/compression.h @@ -34,16 +34,26 @@ class BOTAN_PUBLIC_API(2, 0) Compression_Algorithm { /** * Begin compressing. Most compression algorithms offer a tunable - * time/compression tradeoff parameter generally represented by - * an integer in the range of 1 to 9. + * time/compression tradeoff parameter generally represented by an integer + * in the range of 1 to 9. Higher values typically imply better compression + * and more memory and/or CPU time consumed by the compression process. * * If 0 or a value out of range is provided, a compression algorithm * specific default is used. + * + * @param comp_level the desired level of compression (typically from 1 to 9) */ virtual void start(size_t comp_level = 0) = 0; /** * Process some data. + * + * The leading @p offset bytes of @p buf are ignored and remain untouched; + * this can be useful for ignoring packet headers. If @p flush is true, + * the compression state is flushed, allowing the decompressor to recover + * the entire message up to this point without having to see the rest of + * the compressed stream. + * * @param buf in/out parameter which will possibly be resized or swapped * @param offset an offset into blocks to begin processing * @param flush if true the compressor will be told to flush state @@ -53,6 +63,10 @@ class BOTAN_PUBLIC_API(2, 0) Compression_Algorithm { /** * Finish compressing * + * The @p buf and @p offset parameters are treated as in update(). It is + * acceptable to call start() followed by finish() with the entire message, + * without any intervening call to update(). + * * @param final_block in/out parameter * @param offset an offset into final_block to begin processing */ @@ -92,7 +106,10 @@ class BOTAN_PUBLIC_API(2, 0) Decompression_Algorithm { /** * Begin decompressing. - * Decompression does not support levels, as compression does. + * + * This initializes the decompression engine and must be done before + * calling update() or finish(). No level is provided here; the + * decompressor can accept input generated by any compression parameters. */ virtual void start() = 0; @@ -106,6 +123,12 @@ class BOTAN_PUBLIC_API(2, 0) Decompression_Algorithm { /** * Finish decompressing * + * Decompress the material in the in/out parameter @p buf. The leading + * @p offset bytes of @p buf are ignored and remain untouched; this can + * be useful for ignoring packet headers. + * + * This function may throw if the data seems to be invalid. + * * @param final_block in/out parameter * @param offset an offset into final_block to begin processing */ diff --git a/src/lib/mac/mac.h b/src/lib/mac/mac.h index 65dc91bcc49..b48ab69c7e2 100644 --- a/src/lib/mac/mac.h +++ b/src/lib/mac/mac.h @@ -53,7 +53,7 @@ class BOTAN_PUBLIC_API(2, 0) MessageAuthenticationCode : public Buffered_Computa * Prepare for processing a message under the specified nonce * * Most MACs neither require nor support a nonce; for these algorithms - * calling `start_msg` is optional and calling it with anything other than + * calling start() is optional and calling it with anything other than * an empty string is an error. One MAC which *requires* a per-message * nonce be specified is GMAC. * diff --git a/src/lib/math/numbertheory/numthry.h b/src/lib/math/numbertheory/numthry.h index 5d50c4d86ea..21d4ef72f0e 100644 --- a/src/lib/math/numbertheory/numthry.h +++ b/src/lib/math/numbertheory/numthry.h @@ -102,6 +102,11 @@ size_t BOTAN_PUBLIC_API(2, 0) low_zero_bits(const BigInt& x); /** * Check for primality +* +* This uses probabilistic algorithms - there is some non-zero (but very low) +* probability that this function will return true even if *n* is actually +* composite. +* * @param n a positive integer to test for primality * @param rng a random number generator * @param prob chance of false positive is bounded by 1/2**prob diff --git a/src/lib/modes/aead/aead.h b/src/lib/modes/aead/aead.h index 1f252f74a80..3ce49060a8b 100644 --- a/src/lib/modes/aead/aead.h +++ b/src/lib/modes/aead/aead.h @@ -46,13 +46,13 @@ class BOTAN_PUBLIC_API(2, 0) AEAD_Mode : public Cipher_Mode { std::string_view provider = ""); /** - * Set associated data that is not included in the ciphertext but - * that should be authenticated. Must be called after set_key and - * before start. + * Set associated data that is not included in the ciphertext but that + * should be authenticated. Must be called after set_key() and before + * start(). * - * Unless reset by another call, the associated data is kept - * between messages. Thus, if the AD does not change, calling - * once (after set_key) is the optimum. + * Unless reset by another call, the associated data is kept between + * messages. Thus, if the AD does not change, calling once (after + * set_key()) is the optimum. * * @param ad the associated data */ @@ -62,12 +62,12 @@ class BOTAN_PUBLIC_API(2, 0) AEAD_Mode : public Cipher_Mode { /** * Set associated data that is not included in the ciphertext but - * that should be authenticated. Must be called after set_key and - * before start. + * that should be authenticated. Must be called after set_key() and + * before start(). * * Unless reset by another call, the associated data is kept * between messages. Thus, if the AD does not change, calling - * once (after set_key) is the optimum. + * once (after set_key()) is the optimum. * * Some AEADs (namely SIV) support multiple AD inputs. For * all other modes only nominal AD input 0 is supported; all @@ -99,8 +99,8 @@ class BOTAN_PUBLIC_API(2, 0) AEAD_Mode : public Cipher_Mode { /** * Set associated data that is not included in the ciphertext but - * that should be authenticated. Must be called after set_key and - * before start. + * that should be authenticated. Must be called after set_key() and + * before start(). * * See @ref set_associated_data(). * @@ -114,8 +114,8 @@ class BOTAN_PUBLIC_API(2, 0) AEAD_Mode : public Cipher_Mode { /** * Set associated data that is not included in the ciphertext but - * that should be authenticated. Must be called after set_key and - * before start. + * that should be authenticated. Must be called after set_key() and + * before start(). * * See @ref set_associated_data(). * diff --git a/src/lib/modes/cipher_mode.h b/src/lib/modes/cipher_mode.h index 5fe8f7ca159..cef77fd4bef 100644 --- a/src/lib/modes/cipher_mode.h +++ b/src/lib/modes/cipher_mode.h @@ -84,6 +84,15 @@ class BOTAN_PUBLIC_API(2, 0) Cipher_Mode : public SymmetricAlgorithm { public: /** * Begin processing a message with a fresh nonce. + * + * @warning Typically one must not reuse the same nonce for more than one + * message under the same key. For most cipher modes this would + * mean total loss of security and/or authenticity guarantees. + * + * @note If reliably generating unique nonces is difficult in your + * environment, use SIV which retains security even if nonces + * are repeated. + * * @param nonce the per message nonce */ void start(std::span nonce) { start_msg(nonce.data(), nonce.size()); } @@ -125,7 +134,14 @@ class BOTAN_PUBLIC_API(2, 0) Cipher_Mode : public SymmetricAlgorithm { size_t process(uint8_t msg[], size_t msg_len) { return this->process_msg(msg, msg_len); } /** - * Process some data. Input must be in size update_granularity() uint8_t blocks. + * Process some data. Input must be in size update_granularity() uint8_t + * blocks. The @p buffer is an in/out parameter and may be resized. In + * particular, some modes require that all input be consumed before any + * output is produced; with these modes, @p buffer will be returned empty. + * + * The first @p offset bytes of @p buffer will be ignored (this allows in + * place processing of a buffer that contains an initial plaintext header). + * * @param buffer in/out parameter which will possibly be resized * @param offset an offset into blocks to begin processing */ @@ -137,7 +153,25 @@ class BOTAN_PUBLIC_API(2, 0) Cipher_Mode : public SymmetricAlgorithm { } /** - * Complete processing of a message. + * Complete procession of a message with a final input of @p buffer, which + * is treated the same as with update(). If you have the entire message in + * hand, calling finish() without ever calling update() is both efficient + * and convenient. + * + * When using an AEAD_Mode, if the supplied authentication tag does not + * validate, this will throw an instance of Invalid_Authentication_Tag. + * + * If this occurs, all plaintext previously output via calls to update must + * be destroyed and not used in any way that an attacker could observe the + * effects of. This could be anything from echoing the plaintext back + * (perhaps in an error message), or by making an external RPC whose + * destination or contents depend on the plaintext. The only thing you can + * do is buffer it, and in the event of an invalid tag, erase the + * previously decrypted content from memory. + * + * One simple way to assure this could never happen is to never call + * update, and instead always marshal the entire message into a single + * buffer and call finish on it when decrypting. * * @param final_block in/out parameter which must be at least * minimum_final_size() bytes, and will be set to any final output @@ -172,6 +206,10 @@ class BOTAN_PUBLIC_API(2, 0) Cipher_Mode : public SymmetricAlgorithm { virtual size_t output_length(size_t input_length) const = 0; /** + * The :cpp:class:`Cipher_Mode` interface requires message processing in + * multiples of the block size. This returns size of required blocks to + * update. If the mode implementation does not require buffering it will + * return 1. * @return size of required blocks to update */ virtual size_t update_granularity() const = 0; @@ -180,7 +218,7 @@ class BOTAN_PUBLIC_API(2, 0) Cipher_Mode : public SymmetricAlgorithm { * Return an ideal granularity. This will be a multiple of the result of * update_granularity but may be larger. If so it indicates that better * performance may be achieved by providing buffers that are at least that - * size. + * size (due to SIMD execution, etc). */ virtual size_t ideal_granularity() const = 0; @@ -217,8 +255,11 @@ class BOTAN_PUBLIC_API(2, 0) Cipher_Mode : public SymmetricAlgorithm { virtual void reset() = 0; /** + * Return the length in bytes of the authentication tag this algorithm + * generates. If the mode is not authenticated, this will return 0. + * * @return true iff this mode provides authentication as well as - * confidentiality. + * confidentiality. */ bool authenticated() const { return this->tag_size() > 0; } diff --git a/src/lib/passhash/argon2fmt/argon2fmt.h b/src/lib/passhash/argon2fmt/argon2fmt.h index 01b6b472698..aea6ad1687d 100644 --- a/src/lib/passhash/argon2fmt/argon2fmt.h +++ b/src/lib/passhash/argon2fmt/argon2fmt.h @@ -14,6 +14,10 @@ namespace Botan { class RandomNumberGenerator; +/** +* Generate an Argon2 hash of the specified @p password. The @p y parameter +* specifies the variant: 0 for Argon2d, 1 for Argon2i, and 2 for Argon2id. +*/ std::string BOTAN_PUBLIC_API(2, 11) argon2_generate_pwhash(const char* password, size_t password_len, RandomNumberGenerator& rng, @@ -26,6 +30,11 @@ std::string BOTAN_PUBLIC_API(2, 11) argon2_generate_pwhash(const char* password, /** * Check a previously created password hash +* +* Verify an Argon2 password @p hash against the provided @p password. Returns +* false if the input hash seems malformed or if the computed hash does not +* match. +* * @param password the password to check against * @param password_len the length of password * @param hash the stored hash to check against diff --git a/src/lib/passhash/bcrypt/bcrypt.h b/src/lib/passhash/bcrypt/bcrypt.h index 68f8e6d7e58..1a7c308b2cc 100644 --- a/src/lib/passhash/bcrypt/bcrypt.h +++ b/src/lib/passhash/bcrypt/bcrypt.h @@ -18,6 +18,37 @@ class RandomNumberGenerator; /** * Create a password hash using Bcrypt * +* Takes the @p password to hash, a @p rng, and a @p work_factor. The resulting +* password hash is returned as a string. +* +* Higher work factors increase the amount of time the algorithm runs, increasing +* the cost of cracking attempts. The increase is exponential, so a work factor +* of 12 takes roughly twice as long as work factor 11. The default work factor +* was set to 10 up until the 2.8.0 release. +* +* It is recommended to set the work factor as high as your system can tolerate +* (from a performance and latency perspective) since higher work factors greatly +* improve the security against GPU-based attacks. For example, for protecting +* high value administrator passwords, consider using work factor 15 or 16; at +* these work factors each bcrypt computation takes several seconds. Since admin +* logins will be relatively uncommon, it might be acceptable for each login +* attempt to take some time. As of 2018, a good password cracking rig (with 8 +* NVIDIA 1080 cards) can attempt about 1 billion bcrypt computations per month +* for work factor 13. For work factor 12, it can do twice as many. For work +* factor 15, it can do only one quarter as many attempts. +* +* Due to bugs affecting various implementations of bcrypt, several different +* variants of the algorithm are defined. As of 2.7.0 Botan supports generating +* (or checking) the 2a, 2b, and 2y variants. Since Botan has never been +* affected by any of the bugs which necessitated these version upgrades, all +* three versions are identical beyond the version identifier. Which variant to +* use is controlled by the @p version argument. +* +* The bcrypt @p work_factor must be at least 4 (though at this work factor +* bcrypt is not very secure). The bcrypt format allows up to 31, but Botan +* currently rejects all work factors greater than 18 since even that work factor +* requires roughly 15 seconds of computation on a fast machine. +* * @warning The password is truncated at at most 72 characters; characters after * that do not have any effect on the resulting hash. To support longer * passwords, consider pre-hashing the password, for example by using @@ -38,6 +69,10 @@ std::string BOTAN_PUBLIC_API(2, 0) generate_bcrypt(std::string_view password, /** * Check a previously created password hash +* +* Takes a @p password and a bcrypt @p hash and returns true if the password is +* the same as the one that was used to generate the bcrypt hash. +* * @param password the password to check against * @param hash the stored hash to check against */ diff --git a/src/lib/passhash/passhash9/passhash9.h b/src/lib/passhash/passhash9/passhash9.h index f06919020a7..75bd58bf94f 100644 --- a/src/lib/passhash/passhash9/passhash9.h +++ b/src/lib/passhash/passhash9/passhash9.h @@ -17,15 +17,25 @@ class RandomNumberGenerator; /** * Create a password hash using PBKDF2 +* +* Functions much like generate_bcrypt(). The last parameter, +* @p alg_id, specifies which PRF to use. Currently defined values are: +* +* - 0: HMAC(SHA-1) +* - 1: HMAC(SHA-256) +* - 2: CMAC(Blowfish) +* - 3: HMAC(SHA-384) +* - 4: HMAC(SHA-512) +* +* The @p work_factor must be greater than zero and less than 512. This performs +* 10000 * @p work_factor PBKDF2 iterations, using 96 bits of salt taken from +* @p rng. Using work factor of 10 or more is recommended. +* * @param password the password * @param rng a random number generator * @param work_factor how much work to do to slow down guessing attacks -* @param alg_id specifies which PRF to use with PBKDF2 -* 0 is HMAC(SHA-1) -* 1 is HMAC(SHA-256) -* 2 is CMAC(Blowfish) -* 3 is HMAC(SHA-384) -* 4 is HMAC(SHA-512) +* @param alg_id specifies which PRF to use with PBKDF2 0 is HMAC(SHA-1) 1 is +* HMAC(SHA-256) 2 is CMAC(Blowfish) 3 is HMAC(SHA-384) 4 is HMAC(SHA-512) * all other values are currently undefined */ std::string BOTAN_PUBLIC_API(2, 0) generate_passhash9(std::string_view password, diff --git a/src/lib/pbkdf/pwdhash.h b/src/lib/pbkdf/pwdhash.h index 4ca467864d2..9d0de5b25ab 100644 --- a/src/lib/pbkdf/pwdhash.h +++ b/src/lib/pbkdf/pwdhash.h @@ -59,18 +59,21 @@ class BOTAN_PUBLIC_API(2, 8) PasswordHash { virtual size_t total_memory_usage() const { return 0; } /** - * Returns true if this password hash supports supplying a key + * @returns true if this password hash supports supplying a key */ virtual bool supports_keyed_operation() const { return false; } /** - * Returns true if this password hash supports supplying associated data + * @returns true if this password hash supports supplying associated data */ virtual bool supports_associated_data() const { return false; } /** * Hash a password into a bitstring * + * Derive a key from the specified @p password and @p salt, placing it into + * @p out. + * * @param out a span where the derived key will be placed * @param password the password to derive the key from * @param salt a randomly chosen salt @@ -85,6 +88,11 @@ class BOTAN_PUBLIC_API(2, 8) PasswordHash { /** * Hash a password into a bitstring * + * Derive a key from the specified @p password, @p salt, @p + * associated_data, and secret @p key, placing it into @p out. The + * @p associated_data and @p key are both allowed to be empty. Currently + * non-empty AD/key is only supported with Argon2. + * * @param out a span where the derived key will be placed * @param password the password to derive the key from * @param salt a randomly chosen salt @@ -196,14 +204,28 @@ class BOTAN_PUBLIC_API(2, 8) PasswordHashFamily { /** * Return a new parameter set tuned for this machine + * + * Return a password hash instance tuned to run for approximately @p msec + * milliseconds when producing an output of length @p output_length. + * (Accuracy may vary, use the command line utility ``botan pbkdf_tune`` to + * check.) + * + * The parameters will be selected to use at most @p max_memory_usage_mb + * megabytes of memory, or if left as zero any size is allowed. + * + * This function works by runing a short tuning loop to estimate the + * performance of the algorithm, then scaling the parameters appropriately + * to hit the target size. The length of time the tuning loop runs can be + * controlled using the @p tuning_msec parameter. + * * @param output_length how long the output length will be * @param msec the desired execution time in milliseconds * - * @param max_memory_usage_mb some password hash functions can use a tunable - * amount of memory, in this case max_memory_usage limits the amount of RAM - * the returned parameters will require, in mebibytes (2**20 bytes). It may - * require some small amount above the request. Set to zero to place no - * limit at all. + * @param max_memory_usage_mb some password hash functions can use a + * tunable amount of memory, in this case max_memory_usage limits the + * amount of RAM the returned parameters will require, in mebibytes (2**20 + * bytes). It may require some small amount above the request. Set to zero + * to place no limit at all. * @param tuning_msec how long to run the tuning loop */ virtual std::unique_ptr tune( diff --git a/src/lib/psk_db/psk_db.h b/src/lib/psk_db/psk_db.h index eccdf51a3c3..1ace3a7660c 100644 --- a/src/lib/psk_db/psk_db.h +++ b/src/lib/psk_db/psk_db.h @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace Botan { @@ -25,12 +26,12 @@ class MessageAuthenticationCode; class BOTAN_PUBLIC_API(2, 4) PSK_Database { public: /** - * Return the set of names for which get() will return a value. + * @returns the set of names for which get() will return a value. */ virtual std::set list_names() const = 0; /** - * Return the value associated with the specified @param name or otherwise + * @returns the value associated with the specified @p name or otherwise * throw an exception. */ virtual secure_vector get(std::string_view name) const = 0; @@ -42,13 +43,13 @@ class BOTAN_PUBLIC_API(2, 4) PSK_Database { virtual void set(std::string_view name, const uint8_t psk[], size_t psk_len) = 0; /** - * Remove a PSK from the database + * Remove the PSK with the given @p name from the database */ virtual void remove(std::string_view name) = 0; /** - * Returns if the values in the PSK database are encrypted. If - * false, saved values are being stored in plaintext. + * @returns true if the values in the PSK database are encrypted. If false, + * saved values are being stored in plaintext. */ virtual bool is_encrypted() const = 0; @@ -57,34 +58,59 @@ class BOTAN_PUBLIC_API(2, 4) PSK_Database { */ std::string get_str(std::string_view name) const; + /** + * Like set() but accepts the PSK as a string (eg for a password). + */ void set_str(std::string_view name, std::string_view psk); - template - void set_vec(std::string_view name, const std::vector& psk) { - set(name, psk.data(), psk.size()); - } + /** + * Like set() but accepting an arbitrary contiguous byte array. + */ + void set_vec(std::string_view name, std::span psk) { set(name, psk.data(), psk.size()); } virtual ~PSK_Database() = default; }; /** * A mixin for an encrypted PSK database. -* Both keys and values are encrypted with NIST AES-256 key wrapping. -* Values are padded to obscure their length before encryption, allowing -* it to be used as a password vault. * -* Subclasses must implement the virtual calls to handle storing and -* getting raw (base64 encoded) values. +* Both names and values are encrypted using NIST key wrapping (see NIST +* SP800-38F) with AES-256. First the master key is used with HMAC(SHA-256) to +* derive two 256-bit keys, one for encrypting all names and the other to key an +* instance of HMAC(SHA-256). Values are each encrypted under an individual key +* created by hashing the encrypted name with HMAC. This associates the encrypted +* key with the name, and prevents an attacker with write access to the data +* store from taking an encrypted key associated with one entity and copying it +* to another entity. +* +* Names and PSKs are both padded to the next multiple of 8 bytes, providing some +* obfuscation of the length. +* +* Subclasses must implement the virtual calls to handle storing and getting raw +* (base64 encoded) values. */ class BOTAN_PUBLIC_API(2, 4) Encrypted_PSK_Database : public PSK_Database { public: /** + * Initializes or opens a PSK database. The @p master_key is used to secure + * the contents. It may be of any length. If encrypting PSKs under a + * passphrase, use a suitable key derivation scheme (such as Argon2id) to + * derive the secret key. If the master key is lost, all PSKs stored are + * unrecoverable. + * + * One artifact of the names being encrypted is that is is possible to use + * multiple different master keys with the same underlying storage. Each + * master key will be responsible for a subset of the keys. An attacker who + * knows one of the keys will be able to tell there are other values + * encrypted under another key, but will not be able to tell how many other + * master keys are in use. + * * @param master_key specifies the master key used to encrypt all * keys and value. It can be of any length, but should be at least 256 bits. * * Subkeys for the cryptographic algorithms used are derived from this * master key. No key stretching is performed; if encrypting a PSK database - * using a password, it is recommended to use PBKDF2 to derive the database + * using a password, it is recommended to use Argon2id to derive the database * master key. */ Encrypted_PSK_Database(const secure_vector& master_key); @@ -103,23 +129,25 @@ class BOTAN_PUBLIC_API(2, 4) Encrypted_PSK_Database : public PSK_Database { protected: /** - * Save a encrypted (name.value) pair to the database. Both will be base64 encoded strings. + * Save a encrypted (name/value) pair to the database. Both will be base64 + * encoded strings. */ virtual void kv_set(std::string_view index, std::string_view value) = 0; /** - * Get a value previously saved with set_raw_value. Should return an empty - * string if index is not found. + * Get a value previously saved with kv_set(). Should return an empty + * string if @p index is not found. */ virtual std::string kv_get(std::string_view index) const = 0; /** - * Remove an index + * Remove an @p index */ virtual void kv_del(std::string_view index) = 0; /** - * Return all indexes in the table. + * Return all indexes in the table (ie values for which ``kv_get`` will + * return a non-empty string) */ virtual std::set kv_get_all() const = 0; @@ -133,6 +161,10 @@ class SQL_Database; class BOTAN_PUBLIC_API(2, 4) Encrypted_PSK_Database_SQL : public Encrypted_PSK_Database { public: + /** + * Creates or uses the named table in @p db. The SQL schema of the table is + * `(psk_name TEXT PRIMARY KEY, psk_value TEXT)`. + */ Encrypted_PSK_Database_SQL(const secure_vector& master_key, std::shared_ptr db, std::string_view table_name); diff --git a/src/lib/pubkey/ec_group/ec_group.h b/src/lib/pubkey/ec_group/ec_group.h index 46ade067628..4c4fa9f28c9 100644 --- a/src/lib/pubkey/ec_group/ec_group.h +++ b/src/lib/pubkey/ec_group/ec_group.h @@ -53,6 +53,8 @@ class BOTAN_PUBLIC_API(2, 0) EC_Group final { /** * Construct elliptic curve from the specified parameters * + * This is used for example to create custom (application-specific) curves. + * * @param p the elliptic curve p * @param a the elliptic curve a param * @param b the elliptic curve b param @@ -85,6 +87,8 @@ class BOTAN_PUBLIC_API(2, 0) EC_Group final { /** * Construct elliptic curve from the specified parameters * + * This is used for example to create custom (application-specific) curves. + * * Unlike the deprecated constructor, this constructor imposes * additional restrictions on the parameters, namely: * @@ -133,7 +137,7 @@ class BOTAN_PUBLIC_API(2, 0) EC_Group final { BOTAN_DEPRECATED("Use EC_Group::from_OID") explicit EC_Group(const OID& oid) { *this = EC_Group::from_OID(oid); } /** - * Create an EC domain from PEM encoding (as from PEM_encode), or + * Create an EC domain from PEM encoding (as from PEM_encode()), or * from an OID name (eg "secp256r1", or "1.2.840.10045.3.1.7") * @param pem_or_oid PEM-encoded data, or an OID * diff --git a/src/lib/pubkey/ec_group/ec_point.h b/src/lib/pubkey/ec_group/ec_point.h index 7083703c970..72b9b6ef0e7 100644 --- a/src/lib/pubkey/ec_group/ec_point.h +++ b/src/lib/pubkey/ec_group/ec_point.h @@ -139,11 +139,18 @@ class BOTAN_PUBLIC_API(2, 0) EC_Point final { /** * Force this point to affine coordinates + * + * Convert the point to its equivalent affine coordinates. Throws if this + * is the point at infinity. */ void force_affine(); /** * Force all points on the list to affine coordinates + * + * Force several points to be affine at once. Uses Montgomery's trick to + * reduce number of inversions required, so this is much faster than + * calling ``force_affine`` on each point in sequence. */ static void force_all_affine(std::span points, secure_vector& ws); @@ -295,6 +302,10 @@ class BOTAN_PUBLIC_API(2, 0) EC_Point final { /** * Point addition - mixed J+A + * + * @warning This function assumes that @p other is affine, if this is not + * correct the result will be invalid. + * * @param other affine point to add - assumed to be affine! * @param workspace temp space, at least WORKSPACE_SIZE elements */ diff --git a/src/lib/stream/stream_cipher.h b/src/lib/stream/stream_cipher.h index e59575c9f66..229f59f340d 100644 --- a/src/lib/stream/stream_cipher.h +++ b/src/lib/stream/stream_cipher.h @@ -49,6 +49,10 @@ class BOTAN_PUBLIC_API(2, 0) StreamCipher : public SymmetricAlgorithm { /** * Encrypt or decrypt a message + * + * Processes all bytes plain/ciphertext from @p in and writes the result to + * @p out. + * * @param in the plaintext * @param out the byte array to hold the output, i.e. the ciphertext * @param len the length of both in and out in bytes @@ -89,6 +93,8 @@ class BOTAN_PUBLIC_API(2, 0) StreamCipher : public SymmetricAlgorithm { /** * Get @p bytes from the keystream * + * The bytes are written into a continous byte buffer of your choosing. + * * @param bytes The number of bytes to be produced */ template > @@ -151,6 +157,14 @@ class BOTAN_PUBLIC_API(2, 0) StreamCipher : public SymmetricAlgorithm { /** * Resync the cipher using the IV + * + * Load @p IV into the stream cipher state. This should happen after the + * key is set (set_key()) and before any operation (encrypt(), decrypt() or + * seek()) is called. + * + * If the cipher does not support IVs, then a call with an empty IV will be + * accepted and any other length will cause an Invalid_IV_Length exception. + * * @param iv the initialization vector * @param iv_len the length of the IV in bytes */ @@ -159,12 +173,15 @@ class BOTAN_PUBLIC_API(2, 0) StreamCipher : public SymmetricAlgorithm { /** * Resync the cipher using the IV * @param iv the initialization vector + * @throws Invalid_IV_Length if an incompatible IV was passed. */ void set_iv(std::span iv) { set_iv_bytes(iv.data(), iv.size()); } /** * Return the default (preferred) nonce length - * If this function returns 0, then this cipher does not support nonces + * + * If this function returns zero, then this cipher does not support nonces; + * in this case any call to set_iv with a (non-empty) value will fail. * * Default implementation returns 0 */ @@ -188,6 +205,15 @@ class BOTAN_PUBLIC_API(2, 0) StreamCipher : public SymmetricAlgorithm { /** * Set the offset and the state used later to generate the keystream + * + * Sets the state of the stream cipher and keystream according to the + * passed @p offset, exactly as if @p offset bytes had first been + * encrypted. The key and (if required) the IV have to be set before this + * can be called. + * + * @note Not all ciphers support seeking; such objects will throw + * Not_Implemented in this case. + * * @param offset the offset where we begin to generate the keystream */ virtual void seek(uint64_t offset) = 0; diff --git a/src/lib/tls/credentials_manager.h b/src/lib/tls/credentials_manager.h index 1f388e2f187..ab531f2f4d7 100644 --- a/src/lib/tls/credentials_manager.h +++ b/src/lib/tls/credentials_manager.h @@ -93,46 +93,55 @@ class BOTAN_PUBLIC_API(2, 0) Credentials_Manager { const std::string& context); /** - * Return a cert chain we can use, ordered from leaf to root, - * or else an empty vector. + * Return a certificate chain we can use to identify ourselves, ordered + * from leaf to root, or else an empty vector. * * This virtual function is deprecated, and will be removed in a - * future release. Use (and override) find_cert_chain instead. + * future release. Use (and override) find_cert_chain() instead. * - * It is assumed that the caller can get the private key of the - * leaf with private_key_for + * It is assumed that the caller can get the private key of the leaf with + * private_key_for() * - * @param cert_key_types specifies the key types desired ("RSA", - * "DSA", "ECDSA", etc), or empty if there - * is no preference by the caller. - * @param cert_signature_schemes specifies the signature types desired - * as signatures in the certificate(s) itself, + * @param cert_key_types specifies the key types desired ("RSA", "DSA", + * "ECDSA", etc), or empty if there is no preference + * by the caller. + * @param cert_signature_schemes specifies the signature types desired as + * signatures in the certificate(s) itself, * or empty for no preference by the caller. - * * @param type specifies the type of operation occurring - * * @param context specifies a context relative to type. */ + BOTAN_DEPRECATED("Do not define or use this function; use find_cert_chain") virtual std::vector cert_chain(const std::vector& cert_key_types, const std::vector& cert_signature_schemes, const std::string& type, const std::string& context); /** - * Return a cert chain we can use, ordered from leaf to root, - * or else an empty vector. + * Return a certificate chain we can use to identify ourselves, ordered + * from leaf to root, or else an empty vector. Override this if we have one + * certificate of type @p cert_key_type and we would like to use a + * certificate in this type and context. * - * It is assumed that the caller can get the private key of the - * leaf with private_key_for + * For servers @p type will be "tls-server" and the @p context will be the + * server name that the client requested via SNI (or empty, if the client + * did not send SNI). * - * @param cert_key_type specifies the type of key requested - * ("RSA", "DSA", "ECDSA", etc) - * @param cert_signature_schemes specifies the signature types desired - * as signatures in the certificate(s) itself, - * or empty for no preference by the caller. + * @warning To avoid cross-protocol attacks it is recommended that if a + * server receives an SNI request for a name it does not expect, + * it should close the connection with an alert. This can be done + * by throwing an exception from the implementation of this + * function. * - * @param type specifies the type of operation occurring + * It is assumed that the caller can get the private key of the leaf with + * private_key_for() * + * @param cert_key_type specifies the type of key requested ("RSA", "DSA", + * "ECDSA", etc) + * @param cert_signature_schemes specifies the signature types desired as + * signatures in the certificate(s) itself, + * or empty for no preference by the caller. + * @param type specifies the type of operation occurring * @param context specifies a context relative to type. */ std::vector cert_chain_single_type( @@ -142,10 +151,15 @@ class BOTAN_PUBLIC_API(2, 0) Credentials_Manager { const std::string& context); /** - * @return private key associated with this certificate if we should - * use it with this context. cert was returned by cert_chain - * This function should either return null or throw an exception if - * the key is unavailable. + * Return a `shared_ptr` to the private key for this certificate. The + * @p cert will be the leaf cert of a chain returned previously by + * find_cert_chain() or cert_chain_single_type(). + * + * This function should either return nullptr or throw an exception if + * the matching private key is unavailable. + * + * @return private key associated with this certificate if we should use it + * in this context. */ virtual std::shared_ptr private_key_for(const X509_Certificate& cert, const std::string& type, @@ -184,6 +198,9 @@ class BOTAN_PUBLIC_API(2, 0) Credentials_Manager { virtual secure_vector dtls_cookie_secret(); /** + * Returns an identity hint which may be provided to the client. This can + * help a client understand what PSK to use. + * * @param type specifies the type of operation occurring * @param context specifies a context relative to type. * @return the PSK identity hint for this type/context @@ -191,6 +208,10 @@ class BOTAN_PUBLIC_API(2, 0) Credentials_Manager { virtual std::string psk_identity_hint(const std::string& type, const std::string& context); /** + * Returns the identity we would like to use given this @p type and + * @p context and the optional @p identity_hint. Not all servers or + * protocols will provide a hint. + * * @param type specifies the type of operation occurring * @param context specifies a context relative to type. * @param identity_hint was passed by the server (but may be empty) diff --git a/src/lib/tls/tls_alert.h b/src/lib/tls/tls_alert.h index 61d7cbf6bb9..276208e6ffa 100644 --- a/src/lib/tls/tls_alert.h +++ b/src/lib/tls/tls_alert.h @@ -77,22 +77,30 @@ class BOTAN_PUBLIC_API(2, 0) Alert final { bool is_valid() const { return (m_type_code != AlertType::None); } /** - * @return if this alert is fatal or not + * Return true if this alert is fatal. A fatal alert causes the connection + * to be immediately disconnected. Otherwise, the alert is a warning and + * the connection remains valid. * * Note: * RFC 8446 6. * In TLS 1.3, the severity is implicit in the type of alert being sent, * and the "level" field can safely be ignored. * Everything is considered fatal except for UserCanceled and CloseNotify (RFC 8446 6.1) + * + * @return if this alert is fatal or not */ bool is_fatal() const { return m_fatal; } /** + * Returns the type of the alert as an enum + * * @return type of alert */ Type type() const { return m_type_code; } /** + * Returns the type of the alert as a string + * * @return type of alert */ std::string type_string() const; diff --git a/src/lib/tls/tls_callbacks.h b/src/lib/tls/tls_callbacks.h index 1aeb7d7ba6a..d5a89e8ef9d 100644 --- a/src/lib/tls/tls_callbacks.h +++ b/src/lib/tls/tls_callbacks.h @@ -46,49 +46,97 @@ class BOTAN_PUBLIC_API(2, 0) Callbacks { virtual ~Callbacks() = default; /** - * Mandatory callback: output function - * The channel will call this with data which needs to be sent to the peer - * (eg, over a socket or some other form of IPC). The array will be overwritten - * when the function returns so a copy must be made if the data cannot be - * sent immediately. + * @name Mandatory * - * @param data a contiguous data buffer to send + * Those callbacks must be implemented by all applications that use TLS. + * @{ */ + + /** + * Mandatory callback: output function + * + * The channel will call this with data which needs to be sent to the peer + * (eg, over a socket or some other form of IPC). The array will be overwritten + * when the function returns so a copy must be made if the data cannot be + * sent immediately. + * + * As an example you could use the syscall ``send`` to perform a blocking + * write on a socket, or append the data to a queue managed by your + * application and initiate an asynchronous write. + * + * For TLS all writes must occur *in the order requested*. For DTLS this + * ordering is not strictly required, but is still recommended. + * + * @param data a contiguous data buffer to send + */ virtual void tls_emit_data(std::span data) = 0; /** - * Mandatory callback: process application data - * Called when application data record is received from the peer. - * Again the array is overwritten immediately after the function returns. - * - * @param seq_no the underlying TLS/DTLS record sequence number - * - * @param data a contiguous data buffer containing the received record - */ + * Mandatory callback: process application data + * + * Called when application data record is received from the peer. The + * array is overwritten immediately after the function returns. + * + * Currently empty records are ignored and do not instigate a callback, + * but this may change in a future release. + * + * For TLS the record number will always increase. For DTLS, it is + * possible to receive records with the @p seq_no field out of order, or + * with gaps, corresponding to reordered or lost datagrams. + * + * @param seq_no the underlying TLS/DTLS record sequence number + * + * @param data a contiguous data buffer containing the received record + */ virtual void tls_record_received(uint64_t seq_no, std::span data) = 0; /** - * Mandatory callback: alert received - * Called when an alert is received from the peer - * If fatal, the connection is closing. If not fatal, the connection may - * still be closing (depending on the error and the peer). - * - * @param alert the source of the alert - */ + * Mandatory callback: alert received + * + * Called when an alert is received from the peer. If fatal, the + * connection is closing. If not fatal, the connection may still be + * closing (depending on the error and the peer). + * + * Note that alerts received before the handshake is complete are not + * authenticated and could have been inserted by a MITM attacker. + */ virtual void tls_alert(Alert alert) = 0; + /// @} + // End of mandatory callbacks + /** - * Optional callback: session established - * Called when a session is established. Throw an exception to abort - * the connection. - * - * @param session the session descriptor - */ + * @name Informational + * + * Override these to obtain deeper insights into the TLS connection. + * Throwing from any of these callbacks will result in the termination of + * the TLS connection. + * @{ + */ + + /** + * Optional callback: session established + * + * Called whenever a negotiation completes. This can happen more than once + * on TLS 1.2 connections, if renegotiation occurs. The @p session + * parameter provides information about the session which was just + * established. + * + * If this function wishes to cancel the handshake, it can throw an + * exception which will send a close message to the counterparty and reset + * the connection state. + * + * @param session the session descriptor + */ virtual void tls_session_established(const Session_Summary& session) { BOTAN_UNUSED(session); } /** * Optional callback: session activated - * Called when a session is active and can be written to + * + * By default does nothing. This is called when the session is activated, + * that is once it is possible to send or receive data on the channel. In + * particular it is possible for an implementation of this function to + * perform an initial write on the channel. */ virtual void tls_session_activated() {} diff --git a/src/lib/tls/tls_channel.h b/src/lib/tls/tls_channel.h index 6276a3989d8..01e1f806b74 100644 --- a/src/lib/tls/tls_channel.h +++ b/src/lib/tls/tls_channel.h @@ -181,10 +181,14 @@ class BOTAN_PUBLIC_API(2, 0) Channel { virtual bool secure_renegotiation_supported() const = 0; /** - * Perform a handshake timeout check. This does nothing unless - * this is a DTLS channel with a pending handshake state, in - * which case we check for timeout and potentially retransmit - * handshake packets. + * Perform a handshake timeout check. + * + * This function does nothing unless the channel represents a DTLS + * connection and a handshake is actively in progress. In this case it will + * check the current timeout state and potentially initiate retransmission + * of handshake packets. + * + * @returns true if a timeout condition occurred */ virtual bool timeout_check() = 0; diff --git a/src/lib/tls/tls_ciphersuite.h b/src/lib/tls/tls_ciphersuite.h index 7c4d9b28826..12722145f1c 100644 --- a/src/lib/tls/tls_ciphersuite.h +++ b/src/lib/tls/tls_ciphersuite.h @@ -50,6 +50,8 @@ class BOTAN_PUBLIC_API(2, 0) Ciphersuite final { /** * Formats the ciphersuite back to an RFC-style ciphersuite string + * + * e.g "RSA_WITH_RC4_128_SHA" or "ECDHE_RSA_WITH_AES_128_GCM_SHA256" * @return RFC ciphersuite string identifier */ std::string to_string() const { return (!m_iana_id) ? "unknown cipher suite" : m_iana_id; } diff --git a/src/lib/tls/tls_client.h b/src/lib/tls/tls_client.h index 63aec226d59..f4821259522 100644 --- a/src/lib/tls/tls_client.h +++ b/src/lib/tls/tls_client.h @@ -28,29 +28,49 @@ class Handshake_IO; class BOTAN_PUBLIC_API(2, 0) Client final : public Channel { public: /** - * Set up a new TLS client session + * Initialize a new TLS client. The constructor will immediately initiate a + * new session. * - * @param callbacks contains a set of callback function references - * required by the TLS client. + * The @p callbacks parameter specifies the various application callbacks + * which pertain to this particular client connection. * - * @param session_manager manages session state + * The @p session_manager is an interface for storing TLS sessions, which + * allows for session resumption upon reconnecting to a server. In the + * absence of a need for persistent sessions, use + * TLS::Session_Manager_In_Memory which caches connections for the lifetime + * of a single process. * - * @param creds manages application/user credentials + * The @p credentials_manager is an interface that will be called to + * retrieve any certificates, private keys, or pre-shared keys. * - * @param policy specifies other connection policy information + * Use the optional @p server_info to specify the DNS name of the server + * you are attempting to connect to, if you know it. This helps the server + * select what certificate to use and helps the client validate the + * connection. * - * @param rng a random number generator + * Use the optional @p offer_version to control the version of TLS you wish + * the client to offer. Normally, you'll want to offer the most recent + * version of (D)TLS that is available, however some broken servers are + * intolerant of certain versions being offered, and for classes of + * applications that have to deal with such servers (typically web + * browsers) it may be necessary to implement a version backdown strategy + * if the initial attempt fails. * - * @param server_info is identifying information about the TLS server + * @warning Implementing such a backdown strategy allows an attacker to + * downgrade your connection to the weakest protocol that both you + * and the server support. * - * @param offer_version specifies which version we will offer - * to the TLS server. + * Setting @p offer_version is also used to offer DTLS instead of TLS; use + * TLS::Protocol_Version::latest_dtls_version(). * - * @param next_protocols specifies protocols to advertise with ALPN + * Optionally, the client will advertise @p next_protocols to the server + * using the ALPN extension. * - * @param reserved_io_buffer_size This many bytes of memory will - * be preallocated for the read and write buffers. Smaller - * values just mean reallocations and copies are more likely. + * The optional @p reserved_io_buffer_size specifies how many bytes to + * pre-allocate in the I/O buffers. Use this if you want to control how + * much memory the channel uses initially (the buffers will be resized as + * needed to process inputs). Otherwise some reasonable default is used. + * The TLS 1.3 implementation ignores this. */ Client(const std::shared_ptr& callbacks, const std::shared_ptr& session_manager, diff --git a/src/lib/tls/tls_policy.h b/src/lib/tls/tls_policy.h index 259af56cf24..a15d3ed7b47 100644 --- a/src/lib/tls/tls_policy.h +++ b/src/lib/tls/tls_policy.h @@ -75,21 +75,36 @@ class BOTAN_PUBLIC_API(2, 0) Policy { */ virtual std::vector acceptable_signature_schemes() const; + /** + * Return a list of schemes we are willing to accept for signatures in + * certificates. + * + * By default, the same restrictions as in acceptable_signature_schemes() + * apply. + * + * @return std::nullopt if the same restrictions as defined in + * acceptable_signature_schemes() should apply + */ virtual std::optional> acceptable_certificate_signature_schemes() const; /** * The minimum signature strength we will accept - * Returning 80 allows RSA 1024 and SHA-1. Values larger than 80 disable SHA-1 support. - * Returning 110 allows RSA 2048. - * Return 128 to force ECC (P-256) or large (~3000 bit) RSA keys. + * + * Returning 80 allows RSA 1024 and SHA-1. Values larger than 80 disable + * SHA-1 support. Returning 110 allows RSA 2048. Return 128 to force ECC + * (P-256) or large (~3000 bit) RSA keys. + * * Default is 110 */ virtual size_t minimum_signature_strength() const; /** - * Return if cert revocation info (CRL/OCSP) is required - * If true, validation will fail unless a valid CRL or OCSP response - * was examined. + * Return if certificate revocation info (CRL/OCSP) is required + * + * If true, certificates won't be trusted unless a valid CRL or OCSP + * response was examined. + * + * Default: true */ virtual bool require_cert_revocation_info() const; @@ -97,19 +112,30 @@ class BOTAN_PUBLIC_API(2, 0) Policy { bool allowed_signature_hash(std::string_view hash) const; /** - * Return list of ECC curves and FFDHE groups 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: Group_Params::X25519, Group_Params::SECP256R1, + * Group_Params::BRAINPOOL256R1, Group_Params::SECP384R1, + * Group_Params::BRAINPOOL384R1, Group_Params::SECP521R1, + * 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. */ virtual std::vector key_exchange_groups() const; /** * Return a list of groups to provide prepared key share offers in the * initial client hello for. Groups in this list must be reflected in - * key_exchange_groups() and in the same order. By default this returns - * the most preferred group from key_exchange_groups(). + * key_exchange_groups() and in the same order. * If an empty list is returned, no prepared key share offers are sent * and the decision of the group to use is left to the server. * + * Default: the most preferred group from key_exchange_groups(). + * * @note Has an effect on TLS 1.3 clients, only. */ virtual std::vector key_exchange_groups_to_offer() const; @@ -117,11 +143,16 @@ class BOTAN_PUBLIC_API(2, 0) Policy { /** * Request that ECC curve points are sent compressed * - * @note Has no effect for TLS 1.3 connections. - * RFC 8446 4.2.8.2 - * Versions of TLS prior to 1.3 permitted point format - * negotiation; TLS 1.3 removes this feature in favor of a single - * point format for each curve. + * Signals that we prefer ECC points to be compressed when transmitted to + * us. The other party may not support ECC point compression and therefore + * may still send points uncompressed. + * + * Note that the certificate used during authentication must also follow + * the other party's preference. + * + * @note Support for EC point compression is deprecated and will be removed + * in a future major release. TLS 1.3 does not support point compression + * at all (see RFC 8446 4.2.8.2) */ virtual bool use_ecc_point_compression() const; @@ -139,11 +170,13 @@ class BOTAN_PUBLIC_API(2, 0) Policy { const std::vector& offered_by_peer) const; /** - * Allow renegotiation even if the counterparty doesn't - * support the secure renegotiation extension. + * Allow renegotiation even if the counterparty doesn't support the secure + * renegotiation extension. + * + * Default: false * - * @warning Changing this to true exposes you to injected - * plaintext attacks. Read RFC 5746 for background. + * @warning Changing this to true exposes you to injected plaintext + * attacks. Read RFC 5746 for background. * * @note Has no effect for TLS 1.3 connections. */ @@ -154,18 +187,34 @@ class BOTAN_PUBLIC_API(2, 0) Policy { * field are the current time in seconds. However this allows * client fingerprinting attacks. Set to false to disable, in * which case random bytes will be used instead. + * + * Default: true */ virtual bool include_time_in_hello_random() const; /** - * Consulted by server side. If true, allows clients to initiate a new handshake + * Consulted by server side. If true, allows clients to initiate a new + * handshake + * + * If this function returns true, a server will accept a client-initiated + * renegotiation attempt. Otherwise it will send the client a non-fatal + * TLS::AlertType::NoRenegotiation alert. + * + * Default: false * * @note Has no effect for TLS 1.3 connections. */ virtual bool allow_client_initiated_renegotiation() const; /** - * Consulted by client side. If true, allows servers to initiate a new handshake + * Consulted by client side. If true, allows servers to initiate a new + * handshake + * + * If this function returns true, a client will accept a server-initiated + * renegotiation attempt. Otherwise it will send the server a non-fatal + * TLS::AlertType::NoRenegotiation alert. + * + * Default: false * * @note Has no effect for TLS 1.3 connections. */ @@ -175,10 +224,21 @@ class BOTAN_PUBLIC_API(2, 0) Policy { * If true, a request to renegotiate will close the connection with * a fatal alert. Otherwise, a warning alert is sent. * + * @sa allow_client_initiated_renegotiation + * @sa allow_server_initiated_renegotiation + * + * Default: false + * * @note Has no effect for TLS 1.3 connections. */ virtual bool abort_connection_on_undesired_renegotiation() const; + /** + * Only resume sessions when their original protocol version matches + * the current version exactly. + * + * Default: true + */ virtual bool only_resume_with_exact_version() const; /** @@ -197,13 +257,25 @@ class BOTAN_PUBLIC_API(2, 0) Policy { virtual bool allow_dtls12() const; /** + * For ephemeral Diffie-Hellman key exchange, the server sends 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") + * * @note Has no effect for TLS 1.3 connections. */ virtual Group_Params default_dh_group() const; /** * Return the minimum DH group size we're willing to use - * Default is currently 1024 (insecure), should be 2048 + * + * Return the minimum size in bits for a Diffie-Hellman group that a client + * will accept. Due to the design of the protocol the client has only two + * options - accept the group, or reject it with a fatal alert then attempt + * to reconnect after disabling ephemeral Diffie-Hellman. + * + * Default: 2048 bits */ virtual size_t minimum_dh_group_size() const; @@ -211,6 +283,8 @@ class BOTAN_PUBLIC_API(2, 0) Policy { * For ECDSA authenticated ciphersuites, the smallest key size the * client will accept. * This policy is currently only enforced on the server by the client. + * + * Default: 256 */ virtual size_t minimum_ecdsa_group_size() const; @@ -238,21 +312,28 @@ class BOTAN_PUBLIC_API(2, 0) Policy { virtual size_t minimum_rsa_bits() const; /** - * Throw an exception if you don't like the peer's key. - * Default impl checks the key size against minimum_rsa_bits, minimum_ecdsa_group_size, - * or minimum_ecdh_group_size depending on the key's type. - * Override if you'd like to perform some other kind of test on - * (or logging of) the peer's keys. + * Allows the policy to examine peer public keys. Throw an exception if the + * key should be rejected. Default implementation checks against policy + * values minimum_dh_group_size(), minimum_rsa_bits(), + * minimum_ecdsa_group_size(), and minimum_ecdh_group_size(). + * + * Override if you'd like to perform some other kind of test on (or logging + * of) the peer's keys. */ virtual void check_peer_key_acceptable(const Public_Key& public_key) const; /** - * If this function returns false, unknown PSK identifiers - * will be rejected with an unknown_psk_identifier alert as soon - * as the non-existence is identified. Otherwise, a false - * identifier value will be used and the protocol allowed to - * proceed, causing the handshake to eventually fail without - * revealing that the username does not exist on this system. + * The PSK suites work using an identifier along with a shared secret. If + * this function returns true, when an identifier that the server does not + * recognize is provided by a client, a random shared secret will be + * generated in such a way that a client should not be able to tell the + * difference between the identifier not being known and the secret being + * wrong. This can help protect against some username probing attacks. If + * it returns false, the server will instead send an + * TLS::AlertType::UnknownPSKIdentity alert when an unknown identifier is + * used. + * + * Default: false */ virtual bool hide_unknown_users() const; @@ -264,6 +345,8 @@ class BOTAN_PUBLIC_API(2, 0) Policy { * exactly one ticket per handshake. RFC 8446 allows for * an arbitrary amount, though. * + * Default: 1 + * * @note Has an effect on TLS 1.3 connections, only. */ virtual size_t maximum_session_tickets_per_client_hello() const; @@ -274,6 +357,8 @@ class BOTAN_PUBLIC_API(2, 0) Policy { * For TLS 1.3 session tickets the lifetime must not be longer than * seven days. Expired session tickets cannot be used to resume a * session. + * + * Default: 1 day */ virtual std::chrono::seconds session_ticket_lifetime() const; @@ -283,6 +368,8 @@ class BOTAN_PUBLIC_API(2, 0) Policy { * observers to correlate connections (RFC 8446 Appendix C.4). This * has no effect on TLS 1.2 resumptions based on session IDs as those * are negotiated in the clear anyway. + * + * Default: false */ virtual bool reuse_session_tickets() const; @@ -326,6 +413,8 @@ class BOTAN_PUBLIC_API(2, 0) Policy { virtual bool acceptable_ciphersuite(const Ciphersuite& suite) const; /** + * Default: true + * * @return true if servers should choose the ciphersuite matching * their highest preference, rather than the clients. * Has no effect on client side. @@ -443,6 +532,8 @@ class BOTAN_PUBLIC_API(2, 0) Policy { * [This makes] the TLS 1.3 handshake resemble TLS 1.2 session resumption, * which improves the chance of successfully connecting through middleboxes. * + * Default: true + * * @note Has an effect on TLS 1.3 connections, only. */ virtual bool tls_13_middlebox_compatibility_mode() const; @@ -453,6 +544,8 @@ class BOTAN_PUBLIC_API(2, 0) Policy { * * There's not normally a reason to disable this, except when deterministic output * is required for testing. + * + * Default: true */ virtual bool hash_hello_random() const; diff --git a/src/lib/tls/tls_server.h b/src/lib/tls/tls_server.h index e45d6f54e99..2041a72a904 100644 --- a/src/lib/tls/tls_server.h +++ b/src/lib/tls/tls_server.h @@ -28,8 +28,24 @@ class BOTAN_PUBLIC_API(2, 0) Server final : public Channel { /** * Server initialization * - * @param callbacks contains a set of callback function references - * required by the TLS server. + * The first 5 arguments as well as the final argument + * @p reserved_io_buffer_size, are treated similarly to the TLS::Client(). + * + * If a client sends the ALPN extension, the + * TLS::Callbacks::tls_server_choose_app_protocol() will be called and the + * result sent back to the client. If the empty string is returned, the + * server will not send an ALPN response. The function can also throw an + * exception to abort the handshake entirely, the ALPN specification says + * that if this occurs the alert should be of type + * TLS::AlertType::NoApplicationProtocol. + * + * The optional argument @p is_datagram specifies if this is a TLS or DTLS + * server; unlike clients, which know what type of protocol (TLS vs DTLS) + * they are negotiating from the start via the @p offer_version, servers + * would not until they actually received a client hello. + * + * @param callbacks contains a set of callback function references required + * by the TLS server. * * @param session_manager manages session state * @@ -42,9 +58,9 @@ class BOTAN_PUBLIC_API(2, 0) Server final : public Channel { * @param is_datagram set to true if this server should expect DTLS * connections. Otherwise TLS connections are expected. * - * @param reserved_io_buffer_size This many bytes of memory will - * be preallocated for the read and write buffers. Smaller - * values just mean reallocations and copies are more likely. + * @param reserved_io_buffer_size This many bytes of memory will be + * preallocated for the read and write buffers. Smaller values just + * mean reallocations and copies are more likely. */ Server(const std::shared_ptr& callbacks, const std::shared_ptr& session_manager, diff --git a/src/lib/tls/tls_session.h b/src/lib/tls/tls_session.h index cf4f6220b39..f3a4c803548 100644 --- a/src/lib/tls/tls_session.h +++ b/src/lib/tls/tls_session.h @@ -215,6 +215,11 @@ class BOTAN_PUBLIC_API(3, 0) Session_Base { /** * Get information about the TLS server + * + * Returns information that identifies the server side of the connection. + * This is useful for the client in that it identifies what was originally + * passed to the constructor. For the server, it includes the name the + * client specified in the server name indicator extension. */ const Server_Information& server_info() const { return m_server_info; } diff --git a/src/lib/tls/tls_version.h b/src/lib/tls/tls_version.h index 880cae422da..3116aadd751 100644 --- a/src/lib/tls/tls_version.h +++ b/src/lib/tls/tls_version.h @@ -16,11 +16,16 @@ namespace Botan::TLS { enum class Version_Code : uint16_t { - TLS_V11 = 0x0302, // not supported by Botan + /// TLSv1.1 (no longer supported) + TLS_V11 = 0x0302, + /// TLSv1.2 TLS_V12 = 0x0303, + /// TLSv1.3 TLS_V13 = 0x0304, + /// DTLSv1.2 DTLS_V12 = 0xFEFD, - DTLS_V13 = 0xFEFC, // not supported by Botan + /// DTLSv1.3 (not supported yet) + DTLS_V13 = 0xFEFC, }; /** @@ -31,6 +36,9 @@ class BOTAN_PUBLIC_API(2, 0) Protocol_Version final { using enum Version_Code; /** + * Returns the latest version of the TLS protocol known to the library + * (currently TLS v1.3) + * * @return latest known TLS version */ static Protocol_Version latest_tls_version() { @@ -42,6 +50,9 @@ class BOTAN_PUBLIC_API(2, 0) Protocol_Version final { } /** + * Returns the latest version of the DTLS protocol known to the library + * (currently DTLS v1.2) + * * @return latest known DTLS version */ static Protocol_Version latest_dtls_version() { return Protocol_Version(DTLS_V12); } @@ -88,6 +99,10 @@ class BOTAN_PUBLIC_API(2, 0) Protocol_Version final { uint16_t version_code() const { return m_version; } /** + * Generate a human readable version string. + * + * for instance "TLS v1.1" or "DTLS v1.0". + * * @return human-readable description of this version */ std::string to_string() const; diff --git a/src/lib/utils/version.h b/src/lib/utils/version.h index 596b68917ea..e2eadc1d456 100644 --- a/src/lib/utils/version.h +++ b/src/lib/utils/version.h @@ -18,7 +18,7 @@ namespace Botan { */ /** -* Get a human-readable string identifying the version of Botan. +* Get a human-readable single-line string identifying the version of Botan. * No particular format should be assumed. * @return version string */ @@ -71,15 +71,34 @@ BOTAN_PUBLIC_API(2, 0) uint32_t version_minor(); BOTAN_PUBLIC_API(2, 0) uint32_t version_patch(); /** -* Usable for checking that the DLL version loaded at runtime exactly -* matches the compile-time version. Call using BOTAN_VERSION_* macro -* values. Returns the empty string if an exact match, otherwise an -* appropriate message. Added with 1.11.26. +* Usable for checking that the DLL version loaded at runtime exactly matches the +* compile-time version. Call using BOTAN_VERSION_* macro values, like so: +* +* ``` +* Botan::runtime_version_check(BOTAN_VERSION_MAJOR, BOTAN_VERSION_MINOR, BOTAN_VERSION_PATCH); +* ``` +* +* It will return an empty string if the versions match, or otherwise an error +* message indicating the discrepancy. This only is useful in dynamic libraries, +* where it is possible to compile and run against different versions. */ BOTAN_PUBLIC_API(2, 0) std::string runtime_version_check(uint32_t major, uint32_t minor, uint32_t patch); /* * Macros for compile-time version checks +* +* Return a value that can be used to compare versions. The current +* (compile-time) version is available as the macro BOTAN_VERSION_CODE. For +* instance, to choose one code path for version 3.1.0 and later, and another +* code path for older releases: +* +* ``` +* #if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(3,1,0) +* // 3.1+ code path +* #else +* // code path for older versions +* #endif +* ``` */ #define BOTAN_VERSION_CODE_FOR(a, b, c) ((a << 16) | (b << 8) | (c))