From: Thomas Pornin Date: Wed, 23 Nov 2016 15:59:44 +0000 (+0100) Subject: More Doxygen-compatible documentation (SSL API). X-Git-Tag: v0.4~42 X-Git-Url: https://bearssl.org/gitweb//home/git/?a=commitdiff_plain;h=298ce6530ef1981072716139905b625dda76d618;p=BearSSL More Doxygen-compatible documentation (SSL API). --- diff --git a/Doxyfile b/Doxyfile index dd0a60f..8d0030e 100644 --- a/Doxyfile +++ b/Doxyfile @@ -771,7 +771,7 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = inc/bearssl.h inc/bearssl_block.h inc/bearssl_ec.h inc/bearssl_hash.h inc/bearssl_hmac.h inc/bearssl_pem.h inc/bearssl_prf.h inc/bearssl_rand.h inc/bearssl_rsa.h inc/bearssl_x509.h +INPUT = inc/bearssl.h inc/bearssl_block.h inc/bearssl_ec.h inc/bearssl_hash.h inc/bearssl_hmac.h inc/bearssl_pem.h inc/bearssl_prf.h inc/bearssl_rand.h inc/bearssl_rsa.h inc/bearssl_ssl.h inc/bearssl_x509.h # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/inc/bearssl_ssl.h b/inc/bearssl_ssl.h index 0876ff9..463e616 100644 --- a/inc/bearssl_ssl.h +++ b/inc/bearssl_ssl.h @@ -35,24 +35,36 @@ #include "bearssl_rand.h" #include "bearssl_x509.h" -/* - * SSL - * --- +/** \file bearssl_ssl.h + * + * # SSL + * + * For an overview of the SSL/TLS API, see [the BearSSL Web + * site](https://www.bearssl.org/api1.html). + * + * The `BR_TLS_*` constants correspond to the standard cipher suites and + * their values in the [IANA + * registry](http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4). * + * The `BR_ALERT_*` constants are for standard TLS alert messages. When + * a fatal alert message is sent of received, then the SSL engine context + * status is set to the sum of that alert value (an integer in the 0..255 + * range) and a fixed offset (`BR_ERR_SEND_FATAL_ALERT` for a sent alert, + * `BR_ERR_RECV_FATAL_ALERT` for a received alert). */ -/* Optimal input buffer size. */ +/** \brief Optimal input buffer size. */ #define BR_SSL_BUFSIZE_INPUT (16384 + 325) -/* Optimal output buffer size. */ +/** \brief Optimal output buffer size. */ #define BR_SSL_BUFSIZE_OUTPUT (16384 + 85) -/* Optimal buffer size for monodirectional engine - (shared input/output buffer). */ +/** \brief Optimal buffer size for monodirectional engine + (shared input/output buffer). */ #define BR_SSL_BUFSIZE_MONO BR_SSL_BUFSIZE_INPUT -/* Optimal buffer size for bidirectional engine - (single buffer split into two separate input/output buffers). */ +/** \brief Optimal buffer size for bidirectional engine + (single buffer split into two separate input/output buffers). */ #define BR_SSL_BUFSIZE_BIDI (BR_SSL_BUFSIZE_INPUT + BR_SSL_BUFSIZE_OUTPUT) /* @@ -60,9 +72,14 @@ * and TLS 1.2). Note that though there is a constant for SSL 3.0, that * protocol version is not actually supported. */ + +/** \brief Protocol version: SSL 3.0 (unsupported). */ #define BR_SSL30 0x0300 +/** \brief Protocol version: TLS 1.0. */ #define BR_TLS10 0x0301 +/** \brief Protocol version: TLS 1.1. */ #define BR_TLS11 0x0302 +/** \brief Protocol version: TLS 1.2. */ #define BR_TLS12 0x0303 /* @@ -74,203 +91,288 @@ * errors. Received fatal alerts imply an error code in the 256..511 range. */ -/* No error so far (0). */ +/** \brief SSL status: no error so far (0). */ #define BR_ERR_OK 0 -/* Caller-provided parameter is incorrect. */ +/** \brief SSL status: caller-provided parameter is incorrect. */ #define BR_ERR_BAD_PARAM 1 -/* Operation requested by the caller cannot be applied with the current - context state (e.g. reading data while outgoing data is waiting to - be sent). */ +/** \brief SSL status: operation requested by the caller cannot be applied + with the current context state (e.g. reading data while outgoing data + is waiting to be sent). */ #define BR_ERR_BAD_STATE 2 -/* Incoming protocol or record version is unsupported. */ +/** \brief SSL status: incoming protocol or record version is unsupported. */ #define BR_ERR_UNSUPPORTED_VERSION 3 -/* Incoming record version does not match the expected version. */ +/** \brief SSL status: incoming record version does not match the expected + version. */ #define BR_ERR_BAD_VERSION 4 -/* Incoming record length is invalid. */ +/** \brief SSL status: incoming record length is invalid. */ #define BR_ERR_BAD_LENGTH 5 -/* Incoming record is too large to be processed, or buffer is too small - for the handshake message to send. */ +/** \brief SSL status: incoming record is too large to be processed, or + buffer is too small for the handshake message to send. */ #define BR_ERR_TOO_LARGE 6 -/* Decryption found an invalid padding, or the record MAC is not correct. */ +/** \brief SSL status: decryption found an invalid padding, or the record + MAC is not correct. */ #define BR_ERR_BAD_MAC 7 -/* No initial entropy was provided, and none can be obtained from the OS. */ +/** \brief SSL status: no initial entropy was provided, and none can be + obtained from the OS. */ #define BR_ERR_NO_RANDOM 8 -/* Incoming record type is unknown. */ +/** \brief SSL status: incoming record type is unknown. */ #define BR_ERR_UNKNOWN_TYPE 9 -/* Incoming record or message has wrong type with regards to the - current engine state. */ +/** \brief SSL status: incoming record or message has wrong type with + regards to the current engine state. */ #define BR_ERR_UNEXPECTED 10 -/* ChangeCipherSpec message from the peer has invalid contents. */ +/** \brief SSL status: ChangeCipherSpec message from the peer has invalid + contents. */ #define BR_ERR_BAD_CCS 12 -/* Alert message from the peer has invalid contents (odd length). */ +/** \brief SSL status: alert message from the peer has invalid contents + (odd length). */ #define BR_ERR_BAD_ALERT 13 -/* Incoming handshake message decoding failed. */ +/** \brief SSL status: incoming handshake message decoding failed. */ #define BR_ERR_BAD_HANDSHAKE 14 -/* ServerHello contains a session ID which is larger than 32 bytes. */ +/** \brief SSL status: ServerHello contains a session ID which is larger + than 32 bytes. */ #define BR_ERR_OVERSIZED_ID 15 -/* Server wants to use a cipher suite that we did not claim to support. - This is also reported if we tried to advertise a cipher suite that - we do not support. */ +/** \brief SSL status: server wants to use a cipher suite that we did + not claim to support. This is also reported if we tried to advertise + a cipher suite that we do not support. */ #define BR_ERR_BAD_CIPHER_SUITE 16 -/* Server wants to use a compression that we did not claim to support. */ +/** \brief SSL status: server wants to use a compression that we did not + claim to support. */ #define BR_ERR_BAD_COMPRESSION 17 -/* Server's max fragment length does not match client's. */ +/** \brief SSL status: server's max fragment length does not match + client's. */ #define BR_ERR_BAD_FRAGLEN 18 -/* Secure renegotiation failed. */ +/** \brief SSL status: secure renegotiation failed. */ #define BR_ERR_BAD_SECRENEG 19 -/* Server sent an extension type that we did not announce, or used the - same extension type several times in a single ServerHello. */ +/** \brief SSL status: server sent an extension type that we did not + announce, or used the same extension type several times in a single + ServerHello. */ #define BR_ERR_EXTRA_EXTENSION 20 -/* Invalid Server Name Indication contents (when used by the server, - this extension shall be empty). */ +/** \brief SSL status: invalid Server Name Indication contents (when + used by the server, this extension shall be empty). */ #define BR_ERR_BAD_SNI 21 -/* Invalid ServerHelloDone from the server (length is not 0). */ +/** \brief SSL status: invalid ServerHelloDone from the server (length + is not 0). */ #define BR_ERR_BAD_HELLO_DONE 22 -/* Internal limit exceeded (e.g. server's public key is too large). */ +/** \brief SSL status: internal limit exceeded (e.g. server's public key + is too large). */ #define BR_ERR_LIMIT_EXCEEDED 23 -/* Finished message from peer does not match the expected value. */ +/** \brief SSL status: Finished message from peer does not match the + expected value. */ #define BR_ERR_BAD_FINISHED 24 -/* Session resumption attempt with distinct version or cipher suite. */ +/** \brief SSL status: session resumption attempt with distinct version + or cipher suite. */ #define BR_ERR_RESUME_MISMATCH 25 -/* Unsupported or invalid algorithm (ECDHE curve, signature algorithm, - hash function). */ +/** \brief SSL status: unsupported or invalid algorithm (ECDHE curve, + signature algorithm, hash function). */ #define BR_ERR_INVALID_ALGORITHM 26 -/* Invalid signature on ServerKeyExchange message. */ +/** \brief SSL status: invalid signature on ServerKeyExchange message. */ #define BR_ERR_BAD_SIGNATURE 27 -/* I/O error or premature close on underlying transport stream. This - error code is set only by the simplified I/O API ("br_sslio_*"). */ +/** \brief SSL status: I/O error or premature close on underlying + transport stream. This error code is set only by the simplified + I/O API ("br_sslio_*"). */ #define BR_ERR_IO 31 -/* When a fatal alert is received from the peer, the alert value is added - to this constant. */ +/** \brief SSL status: base value for a received fatal alert. + + When a fatal alert is received from the peer, the alert value + is added to this constant. */ #define BR_ERR_RECV_FATAL_ALERT 256 -/* When a fatal alert is sent to the peer, the alert value is added - to this constant. */ +/** \brief SSL status: base value for a sent fatal alert. + + When a fatal alert is sent to the peer, the alert value is added + to this constant. */ #define BR_ERR_SEND_FATAL_ALERT 512 /* ===================================================================== */ -/* - * The decryption engine for incoming records is an object that implements - * the following functions: +/** + * \brief Decryption engine for SSL. * - * check_length test whether the provided record length is valid - * decrypt decrypt and verify the provided record + * When processing incoming records, the SSL engine will use a decryption + * engine that uses a specific context structure, and has a set of + * methods (a vtable) that follows this template. * - * The decrypt() function receives as parameters a pointer to its context - * structure, the record type, the record version, a pointer to the - * start of the record payload, and a pointer to a word containing the - * payload length. The decrypt() function may assume that the length is - * proper (check_length() was called and returned 1). On success, a - * pointer to the first plaintext byte is returned, and *len is adjusted - * to contain the plaintext length; on error, NULL is returned. - * - * The decryption engine is responsible for keeping track of the record - * sequence number. + * The decryption engine is responsible for applying decryption, verifying + * MAC, and keeping track of the record sequence number. */ typedef struct br_sslrec_in_class_ br_sslrec_in_class; struct br_sslrec_in_class_ { + /** + * \brief Context size (in bytes). + */ size_t context_size; + + /** + * \brief Test validity of the incoming record length. + * + * This function returns 1 if the announced length for an + * incoming record is valid, 0 otherwise, + * + * \param ctx decryption engine context. + * \param record_len incoming record length. + * \return 1 of a valid length, 0 otherwise. + */ int (*check_length)(const br_sslrec_in_class *const *ctx, size_t record_len); + + /** + * \brief Decrypt the incoming record. + * + * This function may assume that the record length is valid + * (it has been previously tested with `check_length()`). + * Decryption is done in place; `*len` is updated with the + * cleartext length, and the address of the first plaintext + * byte is returned. If the record is correct but empty, then + * `*len` is set to 0 and a non-`NULL` pointer is returned. + * + * On decryption/MAC error, `NULL` is returned. + * + * \param ctx decryption engine context. + * \param record_type record type (23 for application data, etc). + * \param version record version. + * \param payload address of encrypted payload. + * \param len pointer to payload length (updated). + * \return pointer to plaintext, or `NULL` on error. + */ unsigned char *(*decrypt)(const br_sslrec_in_class **ctx, int record_type, unsigned version, void *payload, size_t *len); }; -/* - * The encryption engine for outgoing records is an object that implements - * the following functions: - * - * max_plaintext get start and end offsets for payload - * encrypt encrypt and apply MAC on current record - * - * The max_plaintext() function receives as inputs the start and end - * of the buffer where the payload will be stored; this function assumes - * that there will be room for a record header (5 bytes) BEFORE the - * offset specified by *start. The max_plaintext() function then adjusts - * the two offsets to designate the area for the plaintext. - * - * The encrypt() function assumes that the provided plaintext data is - * in a buffer with enough room before and after the data chunk to - * receive the needed headers (i.e. the plaintext is at offsets which - * were computed by an earlier call to max_plaintext()). It returns - * a pointer to the start of the encrypted record, and writes the - * encrypted record length in '*len' (that length includes the record - * header). - * - * The encryption engine MUST fill the record header. If the engine - * performs a "split" into several records, then the successive records - * MUST be consecutive in RAM; the returned length is thus the sum of - * the individual record lengths. - * - * The encryption engine is responsible for keeping track of the record - * sequence number. +/** + * \brief Encryption engine for SSL. + * + * When building outgoing records, the SSL engine will use an encryption + * engine that uses a specific context structure, and has a set of + * methods (a vtable) that follows this template. + * + * The encryption engine is responsible for applying encryption and MAC, + * and keeping track of the record sequence number. */ typedef struct br_sslrec_out_class_ br_sslrec_out_class; struct br_sslrec_out_class_ { + /** + * \brief Context size (in bytes). + */ size_t context_size; + + /** + * \brief Compute maximum plaintext sizes and offsets. + * + * When this function is called, the `*start` and `*end` + * values contain offsets designating the free area in the + * outgoing buffer for plaintext data; that free area is + * preceded by a 5-byte space which will receive the record + * header. + * + * The `max_plaintext()` function is responsible for adjusting + * both `*start` and `*end` to make room for any record-specific + * header, MAC, padding, and possible split. + * + * \param ctx encryption engine context. + * \param start pointer to start of plaintext offset (updated). + * \param end pointer to start of plaintext offset (updated). + */ void (*max_plaintext)(const br_sslrec_out_class *const *ctx, size_t *start, size_t *end); + + /** + * \brief Perform record encryption. + * + * This function encrypts the record. The plaintext address and + * length are provided. Returned value is the start of the + * encrypted record (or sequence of records, if a split was + * performed), _including_ the 5-byte header, and `*len` is + * adjusted to the total size of the record(s), there again + * including the header(s). + * + * \param ctx decryption engine context. + * \param record_type record type (23 for application data, etc). + * \param version record version. + * \param plaintext address of plaintext. + * \param len pointer to plaintext length (updated). + * \return pointer to start of built record. + */ unsigned char *(*encrypt)(const br_sslrec_out_class **ctx, int record_type, unsigned version, void *plaintext, size_t *len); }; -/* - * An outgoing no-encryption engine is defined, to process outgoing - * records before completion of the initial handshake. +/** + * \brief Context for a no-encryption engine. + * + * The no-encryption engine processes outgoing records during the initial + * handshake, before encryption is applied. */ typedef struct { + /** \brief No-encryption engine vtable. */ const br_sslrec_out_class *vtable; } br_sslrec_out_clear_context; + +/** \brief Static, constant vtable for the no-encryption engine. */ extern const br_sslrec_out_class br_sslrec_out_clear_vtable; /* ===================================================================== */ -/* - * An engine for processing incoming records with a block cipher in - * CBC mode has an extra initialization function, that takes as inputs: - * -- a block cipher (CBC decryption) and its key; - * -- a hash function for HMAC, with the MAC key and output length; - * -- an optional initial IV. - * If the IV is not provided (the 'iv' parameter is NULL), then the - * engine will use an explicit per-record IV (as is mandated in TLS 1.1+). +/** + * \brief Record decryption engine class, for CBC mode. * - * The initialization function is responsible for setting the 'vtable' - * field of the context. + * This class type extends the decryption engine class with an + * initialisation method that receives the parameters needed + * for CBC processing: block cipher implementation, block cipher key, + * HMAC parameters (hash function, key, MAC length), and IV. If the + * IV is `NULL`, then a per-record IV will be used (TLS 1.1+). */ typedef struct br_sslrec_in_cbc_class_ br_sslrec_in_cbc_class; struct br_sslrec_in_cbc_class_ { + /** + * \brief Superclass, as first vtable field. + */ br_sslrec_in_class inner; + + /** + * \brief Engine initialisation method. + * + * This method sets the vtable field in the context. + * + * \param ctx context to initialise. + * \param bc_impl block cipher implementation (CBC decryption). + * \param bc_key block cipher key. + * \param bc_key_len block cipher key length (in bytes). + * \param dig_impl hash function for HMAC. + * \param mac_key HMAC key. + * \param mac_key_len HMAC key length (in bytes). + * \param mac_out_len HMAC output length (in bytes). + * \param iv initial IV (or `NULL`). + */ void (*init)(const br_sslrec_in_cbc_class **ctx, const br_block_cbcdec_class *bc_impl, const void *bc_key, size_t bc_key_len, @@ -279,21 +381,37 @@ struct br_sslrec_in_cbc_class_ { const void *iv); }; -/* - * An engine for processing outgoing records with a block cipher in - * CBC mode has an extra initialization function, that takes as inputs: - * -- a block cipher (CBC encryption) and its key; - * -- a hash function for HMAC, with the MAC key and output length; - * -- an optional initial IV. - * If the IV is not provided (the 'iv' parameter is NULL), then the - * engine will use an explicit per-record IV (as is mandated in TLS 1.1+). +/** + * \brief Record encryption engine class, for CBC mode. * - * The initialization function is responsible for setting the 'vtable' - * field of the context. + * This class type extends the encryption engine class with an + * initialisation method that receives the parameters needed + * for CBC processing: block cipher implementation, block cipher key, + * HMAC parameters (hash function, key, MAC length), and IV. If the + * IV is `NULL`, then a per-record IV will be used (TLS 1.1+). */ typedef struct br_sslrec_out_cbc_class_ br_sslrec_out_cbc_class; struct br_sslrec_out_cbc_class_ { + /** + * \brief Superclass, as first vtable field. + */ br_sslrec_out_class inner; + + /** + * \brief Engine initialisation method. + * + * This method sets the vtable field in the context. + * + * \param ctx context to initialise. + * \param bc_impl block cipher implementation (CBC encryption). + * \param bc_key block cipher key. + * \param bc_key_len block cipher key length (in bytes). + * \param dig_impl hash function for HMAC. + * \param mac_key HMAC key. + * \param mac_key_len HMAC key length (in bytes). + * \param mac_out_len HMAC output length (in bytes). + * \param iv initial IV (or `NULL`). + */ void (*init)(const br_sslrec_out_cbc_class **ctx, const br_block_cbcenc_class *bc_impl, const void *bc_key, size_t bc_key_len, @@ -302,11 +420,17 @@ struct br_sslrec_out_cbc_class_ { const void *iv); }; -/* - * Context structure for decrypting incoming records with CBC + HMAC. +/** + * \brief Context structure for decrypting incoming records with + * CBC + HMAC. + * + * The first field points to the vtable. The other fields are opaque + * and shall not be accessed directly. */ typedef struct { + /** \brief Pointer to vtable. */ const br_sslrec_in_cbc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE uint64_t seq; union { const br_block_cbcdec_class *vtable; @@ -317,14 +441,25 @@ typedef struct { size_t mac_len; unsigned char iv[16]; int explicit_IV; +#endif } br_sslrec_in_cbc_context; + +/** + * \brief Static, constant vtable for record decryption with CBC. + */ extern const br_sslrec_in_cbc_class br_sslrec_in_cbc_vtable; -/* - * Context structure for encrypting outgoing records with CBC + HMAC. +/** + * \brief Context structure for encrypting outgoing records with + * CBC + HMAC. + * + * The first field points to the vtable. The other fields are opaque + * and shall not be accessed directly. */ typedef struct { + /** \brief Pointer to vtable. */ const br_sslrec_out_cbc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE uint64_t seq; union { const br_block_cbcenc_class *vtable; @@ -335,24 +470,43 @@ typedef struct { size_t mac_len; unsigned char iv[16]; int explicit_IV; +#endif } br_sslrec_out_cbc_context; + +/** + * \brief Static, constant vtable for record encryption with CBC. + */ extern const br_sslrec_out_cbc_class br_sslrec_out_cbc_vtable; /* ===================================================================== */ -/* - * An engine for processing incoming records with a block cipher in - * GCM mode has an extra initialization function, that takes as inputs: - * -- a block cipher (CTR) and its key; - * -- a GHASH implementation; - * -- an initial IV (4 bytes). +/** + * \brief Record decryption engine class, for GCM mode. * - * The initialization function is responsible for setting the 'vtable' - * field of the context. + * This class type extends the decryption engine class with an + * initialisation method that receives the parameters needed + * for GCM processing: block cipher implementation, block cipher key, + * GHASH implementtion, and 4-byte IV. */ typedef struct br_sslrec_in_gcm_class_ br_sslrec_in_gcm_class; struct br_sslrec_in_gcm_class_ { + /** + * \brief Superclass, as first vtable field. + */ br_sslrec_in_class inner; + + /** + * \brief Engine initialisation method. + * + * This method sets the vtable field in the context. + * + * \param ctx context to initialise. + * \param bc_impl block cipher implementation (CTR). + * \param key block cipher key. + * \param key_len block cipher key length (in bytes). + * \param gh_impl GHASH implementation. + * \param iv static IV (4 bytes). + */ void (*init)(const br_sslrec_in_gcm_class **ctx, const br_block_ctr_class *bc_impl, const void *key, size_t key_len, @@ -360,19 +514,33 @@ struct br_sslrec_in_gcm_class_ { const void *iv); }; -/* - * An engine for processing outgoing records with a block cipher in - * GCM mode has an extra initialization function, that takes as inputs: - * -- a block cipher (CTR) and its key; - * -- a GHASH implementation; - * -- an initial IV (4 bytes). +/** + * \brief Record decryption engine class, for GCM mode. * - * The initialization function is responsible for setting the 'vtable' - * field of the context. + * This class type extends the decryption engine class with an + * initialisation method that receives the parameters needed + * for GCM processing: block cipher implementation, block cipher key, + * GHASH implementtion, and 4-byte IV. */ typedef struct br_sslrec_out_gcm_class_ br_sslrec_out_gcm_class; struct br_sslrec_out_gcm_class_ { + /** + * \brief Superclass, as first vtable field. + */ br_sslrec_out_class inner; + + /** + * \brief Engine initialisation method. + * + * This method sets the vtable field in the context. + * + * \param ctx context to initialise. + * \param bc_impl block cipher implementation (CTR). + * \param key block cipher key. + * \param key_len block cipher key length (in bytes). + * \param gh_impl GHASH implementation. + * \param iv static IV (4 bytes). + */ void (*init)(const br_sslrec_out_gcm_class **ctx, const br_block_ctr_class *bc_impl, const void *key, size_t key_len, @@ -380,16 +548,22 @@ struct br_sslrec_out_gcm_class_ { const void *iv); }; -/* - * We use the same context structure for incoming and outgoing records - * with GCM, because it allows internal code sharing. +/** + * \brief Context structure for processing records with GCM. + * + * The same context structure is used for encrypting and decrypting. + * + * The first field points to the vtable. The other fields are opaque + * and shall not be accessed directly. */ typedef struct { + /** \brief Pointer to vtable. */ union { const void *gen; const br_sslrec_in_gcm_class *in; const br_sslrec_out_gcm_class *out; } vtable; +#ifndef BR_DOXYGEN_IGNORE uint64_t seq; union { const br_block_ctr_class *vtable; @@ -398,39 +572,61 @@ typedef struct { br_ghash gh; unsigned char iv[4]; unsigned char h[16]; +#endif } br_sslrec_gcm_context; +/** + * \brief Static, constant vtable for record decryption with GCM. + */ extern const br_sslrec_in_gcm_class br_sslrec_in_gcm_vtable; + +/** + * \brief Static, constant vtable for record encryption with GCM. + */ extern const br_sslrec_out_gcm_class br_sslrec_out_gcm_vtable; /* ===================================================================== */ -/* - * Type for session parameters, to be saved for session resumption. +/** + * \brief Type for session parameters, to be saved for session resumption. */ typedef struct { + /** \brief Session ID buffer. */ unsigned char session_id[32]; + /** \brief Session ID length (in bytes, at most 32). */ unsigned char session_id_len; + /** \brief Protocol version. */ uint16_t version; + /** \brief Cipher suite. */ uint16_t cipher_suite; + /** \brief Master secret. */ unsigned char master_secret[48]; } br_ssl_session_parameters; +#ifndef BR_DOXYGEN_IGNORE /* * Maximum numnber of cipher suites supported by a client or server. */ #define BR_MAX_CIPHER_SUITES 40 +#endif -/* - * Context structure for SSL engine. This is common to the client and - * server; the engine manages records, including alerts, closures, and +/** + * \brief Context structure for SSL engine. + * + * This strucuture is common to the client and server; both the client + * context (`br_ssl_client_context`) and the server context + * (`br_ssl_server_context`) include a `br_ssl_engine_context` as their + * first field. + * + * The engine context manages records, including alerts, closures, and * transitions to new encryption/MAC algorithms. Processing of handshake * records is delegated to externally provided code. This structure - * should not be used directly, but is meant to be included as first - * field of the context structures for SSL clients and servers. + * should not be used directly. + * + * Structure contents are opaque and shall not be accessed directly. */ typedef struct { - +#ifndef BR_DOXYGEN_IGNORE /* * The error code. When non-zero, then the state is "failed" and * no I/O may occur until reset. @@ -648,11 +844,14 @@ typedef struct { const br_sslrec_in_gcm_class *igcm_in; const br_sslrec_out_gcm_class *igcm_out; const br_ec_impl *iec; - +#endif } br_ssl_engine_context; -/* - * Get currently defined engine behavioural flags. +/** + * \brief Get currently defined engine behavioural flags. + * + * \param cc SSL engine context. + * \return the flags. */ static inline uint32_t br_ssl_engine_get_flags(br_ssl_engine_context *cc) @@ -660,9 +859,11 @@ br_ssl_engine_get_flags(br_ssl_engine_context *cc) return cc->flags; } -/* - * Set all engine flags. Flags which are not in the 'flags' argument - * are cleared. +/** + * \brief Set all engine behavioural flags. + * + * \param cc SSL engine context. + * \param flags new value for all flags. */ static inline void br_ssl_engine_set_all_flags(br_ssl_engine_context *cc, uint32_t flags) @@ -670,9 +871,14 @@ br_ssl_engine_set_all_flags(br_ssl_engine_context *cc, uint32_t flags) cc->flags = flags; } -/* - * Add some engine flags. The provided flags are set in the engine context, - * but other flags are untouched. +/** + * \brief Set some engine behavioural flags. + * + * The flags set in the `flags` parameter are set in the context; other + * flags are untouched. + * + * \param cc SSL engine context. + * \param flags additional set flags. */ static inline void br_ssl_engine_add_flags(br_ssl_engine_context *cc, uint32_t flags) @@ -680,9 +886,14 @@ br_ssl_engine_add_flags(br_ssl_engine_context *cc, uint32_t flags) cc->flags |= flags; } -/* - * Remove some engine flags. The provided flags are cleared from the - * engine context, but other flags are untouched. +/** + * \brief Clear some engine behavioural flags. + * + * The flags set in the `flags` parameter are cleared from the context; other + * flags are untouched. + * + * \param cc SSL engine context. + * \param flags flags to remove. */ static inline void br_ssl_engine_remove_flags(br_ssl_engine_context *cc, uint32_t flags) @@ -690,8 +901,33 @@ br_ssl_engine_remove_flags(br_ssl_engine_context *cc, uint32_t flags) cc->flags &= ~flags; } +/** + * \brief Behavioural flag: enforce server preferences. + * + * If this flag is set, then the server will enforce its own cipher suite + * preference order; otherwise, it follows the client preferences. + */ +#define BR_OPT_ENFORCE_SERVER_PREFERENCES ((uint32_t)1 << 0) + /* - * Set the minimum and maximum supported protocol versions. + * \brief Behavioural flag: disable renegotiation. + * + * If this flag is set, then renegotiations are rejected unconditionally: + * they won't be honoured if asked for programmatically, and requests from + * the peer are rejected. + */ +#define BR_OPT_NO_RENEGOTIATION ((uint32_t)1 << 1) + +/** + * \brief Set the minimum and maximum supported protocol versions. + * + * The two provided versions MUST be supported by the implementation + * (i.e. TLS 1.0, 1.1 and 1.2), and `version_max` MUST NOT be lower + * than `version_min`. + * + * \param cc SSL engine context. + * \param version_min minimum supported TLS version. + * \param version_max maximum supported TLS version. */ static inline void br_ssl_engine_set_versions(br_ssl_engine_context *cc, @@ -701,17 +937,35 @@ br_ssl_engine_set_versions(br_ssl_engine_context *cc, cc->version_max = version_max; } -/* - * Set the list of cipher suites advertised by this context. The provided - * array is copied into the context. It is the caller responsibility - * to ensure that all provided suites will be supported by the context. +/** + * \brief Set the list of cipher suites advertised by this context. + * + * The provided array is copied into the context. It is the caller + * responsibility to ensure that all provided suites will be supported + * by the context. The engine context has enough room to receive _all_ + * suites supported by the implementation. The provided array MUST NOT + * contain duplicates. + * + * If the engine is for a client, the "signaling" pseudo-cipher suite + * `TLS_FALLBACK_SCSV` can be added at the end of the list, if the + * calling application is performing a voluntary downgrade (voluntary + * downgrades are not recommended, but if such a downgrade is done, then + * adding the fallback pseudo-suite is a good idea). + * + * \param cc SSL engine context. + * \param suites cipher suites. + * \param suites_num number of cipher suites. */ void br_ssl_engine_set_suites(br_ssl_engine_context *cc, const uint16_t *suites, size_t suites_num); -/* - * Set the X.509 engine. The context should be already initialized and - * ready to process a new chain. +/** + * \brief Set the X.509 engine. + * + * The caller shall ensure that the X.509 engine is properly initialised. + * + * \param cc SSL engine context. + * \param x509ctx X.509 certificate validation context. */ static inline void br_ssl_engine_set_x509(br_ssl_engine_context *cc, const br_x509_class **x509ctx) @@ -719,8 +973,17 @@ br_ssl_engine_set_x509(br_ssl_engine_context *cc, const br_x509_class **x509ctx) cc->x509ctx = x509ctx; } -/* - * Set a hash function implementation (by ID). +/** + * \brief Set a hash function implementation (by ID). + * + * Hash functions set with this call will be used for SSL/TLS specific + * usages, not X.509 certificate validation. Only "standard" hash functions + * may be set (MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512). If `impl` + * is `NULL`, then the hash function support is removed, not added. + * + * \param ctx SSL engine context. + * \param id hash function identifier. + * \param impl hash function implementation (or `NULL`). */ static inline void br_ssl_engine_set_hash(br_ssl_engine_context *ctx, @@ -729,8 +992,15 @@ br_ssl_engine_set_hash(br_ssl_engine_context *ctx, br_multihash_setimpl(&ctx->mhash, id, impl); } -/* - * Get a hash function implementation (by ID). +/** + * \brief Get a hash function implementation (by ID). + * + * This function retrieves a hash function implementation which was + * set with `br_ssl_engine_set_hash()`. + * + * \param ctx SSL engine context. + * \param id hash function identifier. + * \return the hash function implementation (or `NULL`). */ static inline const br_hash_class * br_ssl_engine_get_hash(br_ssl_engine_context *ctx, int id) @@ -738,8 +1008,14 @@ br_ssl_engine_get_hash(br_ssl_engine_context *ctx, int id) return br_multihash_getimpl(&ctx->mhash, id); } -/* - * Set the PRF implementation (for TLS 1.0 and 1.1). +/** + * \brief Set the PRF implementation (for TLS 1.0 and 1.1). + * + * This function sets (or removes, if `impl` is `NULL`) the implemenation + * for the PRF used in TLS 1.0 and 1.1. + * + * \param cc SSL engine context. + * \param impl PRF implementation (or `NULL`). */ static inline void br_ssl_engine_set_prf10(br_ssl_engine_context *cc, br_tls_prf_impl impl) @@ -747,8 +1023,14 @@ br_ssl_engine_set_prf10(br_ssl_engine_context *cc, br_tls_prf_impl impl) cc->prf10 = impl; } -/* - * Set the PRF implementation (for TLS 1.2, with SHA-256). +/** + * \brief Set the PRF implementation with SHA-256 (for TLS 1.2). + * + * This function sets (or removes, if `impl` is `NULL`) the implemenation + * for the SHA-256 variant of the PRF used in TLS 1.2. + * + * \param cc SSL engine context. + * \param impl PRF implementation (or `NULL`). */ static inline void br_ssl_engine_set_prf_sha256(br_ssl_engine_context *cc, br_tls_prf_impl impl) @@ -756,8 +1038,14 @@ br_ssl_engine_set_prf_sha256(br_ssl_engine_context *cc, br_tls_prf_impl impl) cc->prf_sha256 = impl; } -/* - * Set the PRF implementation (for TLS 1.2, with SHA-384). +/** + * \brief Set the PRF implementation with SHA-384 (for TLS 1.2). + * + * This function sets (or removes, if `impl` is `NULL`) the implemenation + * for the SHA-384 variant of the PRF used in TLS 1.2. + * + * \param cc SSL engine context. + * \param impl PRF implementation (or `NULL`). */ static inline void br_ssl_engine_set_prf_sha384(br_ssl_engine_context *cc, br_tls_prf_impl impl) @@ -765,8 +1053,12 @@ br_ssl_engine_set_prf_sha384(br_ssl_engine_context *cc, br_tls_prf_impl impl) cc->prf_sha384 = impl; } -/* - * Set the AES/CBC implementations. +/** + * \brief Set the AES/CBC implementations. + * + * \param cc SSL engine context. + * \param impl_enc AES/CBC encryption implementation (or `NULL`). + * \param impl_dec AES/CBC decryption implementation (or `NULL`). */ static inline void br_ssl_engine_set_aes_cbc(br_ssl_engine_context *cc, @@ -777,8 +1069,11 @@ br_ssl_engine_set_aes_cbc(br_ssl_engine_context *cc, cc->iaes_cbcdec = impl_dec; } -/* - * Set the AES/CTR implementation. +/** + * \brief Set the AES/CTR implementation. + * + * \param cc SSL engine context. + * \param impl AES/CTR encryption/decryption implementation (or `NULL`). */ static inline void br_ssl_engine_set_aes_ctr(br_ssl_engine_context *cc, @@ -787,8 +1082,12 @@ br_ssl_engine_set_aes_ctr(br_ssl_engine_context *cc, cc->iaes_ctr = impl; } -/* - * Set the 3DES/CBC implementations. +/** + * \brief Set the DES/CBC implementations. + * + * \param cc SSL engine context. + * \param impl_enc DES/CBC encryption implementation (or `NULL`). + * \param impl_dec DES/CBC decryption implementation (or `NULL`). */ static inline void br_ssl_engine_set_des_cbc(br_ssl_engine_context *cc, @@ -799,8 +1098,11 @@ br_ssl_engine_set_des_cbc(br_ssl_engine_context *cc, cc->ides_cbcdec = impl_dec; } -/* - * Set the GHASH implementation (for GCM). +/** + * \brief Set the GHASH implementation (used in GCM mode). + * + * \param cc SSL engine context. + * \param impl GHASH implementation (or `NULL`). */ static inline void br_ssl_engine_set_ghash(br_ssl_engine_context *cc, br_ghash impl) @@ -808,8 +1110,12 @@ br_ssl_engine_set_ghash(br_ssl_engine_context *cc, br_ghash impl) cc->ighash = impl; } -/* - * Set the CBC+HMAC record processor implementations. +/** + * \brief Set the record encryption and decryption engines for CBC + HMAC. + * + * \param cc SSL engine context. + * \param impl_in record CBC decryption implementation (or `NULL`). + * \param impl_out record CBC encryption implementation (or `NULL`). */ static inline void br_ssl_engine_set_cbc(br_ssl_engine_context *cc, @@ -820,8 +1126,12 @@ br_ssl_engine_set_cbc(br_ssl_engine_context *cc, cc->icbc_out = impl_out; } -/* - * Set the GCM record processor implementations. +/** + * \brief Set the record encryption and decryption engines for GCM. + * + * \param cc SSL engine context. + * \param impl_in record GCM decryption implementation (or `NULL`). + * \param impl_out record GCM encryption implementation (or `NULL`). */ static inline void br_ssl_engine_set_gcm(br_ssl_engine_context *cc, @@ -832,9 +1142,14 @@ br_ssl_engine_set_gcm(br_ssl_engine_context *cc, cc->igcm_out = impl_out; } -/* - * Set the ECC core operations implementation. The 'iec' parameter - * points to the core EC code used for both ECDHE and ECDSA. +/** + * \brief Set the EC implementation. + * + * The elliptic curve implementation will be used for ECDH and ECDHE + * cipher suites, and for ECDSA support. + * + * \param cc SSL engine context. + * \param iec EC implementation (or `NULL`). */ static inline void br_ssl_engine_set_ec(br_ssl_engine_context *cc, const br_ec_impl *iec) @@ -842,44 +1157,67 @@ br_ssl_engine_set_ec(br_ssl_engine_context *cc, const br_ec_impl *iec) cc->iec = iec; } -/* - * Set the I/O buffer for a SSL engine. Once this call has been made, - * br_ssl_client_reset() or br_ssl_server_reset() must be called before - * using the context. - * - * If 'bidi' is 1, then the buffer will be internally split to support - * concurrent input and output; otherwise, the caller will be responsible - * for reading all buffered incoming data before writing. The latter - * case makes support of HTTPS pipelining difficult, thus bidirectional - * buffering is recommended if the RAM can be spared. - * - * The BR_SSL_BUFSIZE_MONO and BR_SSL_BUFSIZE_BIDI macros yield optimal - * buffer sizes for the monodirectional and bidirectional cases, - * respectively. If using optimal sizes (or larger), then records with - * the maximum length supported by the TLS standard will be accepted - * and emitted. +/** + * \brief Set the I/O buffer for the SSL engine. + * + * Once this call has been made, `br_ssl_client_reset()` or + * `br_ssl_server_reset()` MUST be called before using the context. + * + * The provided buffer will be used as long as the engine context is + * used. The caller is responsible for keeping it available. + * + * If `bidi` is 0, then the engine will operate in half-duplex mode + * (it won't be able to send data while there is unprocessed incoming + * data in the buffer, and it won't be able to receive data while there + * is unsent data in the buffer). The optimal buffer size in half-duplex + * mode is `BR_SSL_BUFSIZE_MONO`; if the buffer is larger, then extra + * bytes are ignored. If the buffer is smaller, then this limits the + * capacity of the engine to support all allowed record sizes. + * + * If `bidi` is 1, then the engine will split the buffer into two + * parts, for separate handling of outgoing and incoming data. This + * enables full-duplex processing, but requires more RAM. The optimal + * buffer size in full-duplex mode is `BR_SSL_BUFSIZE_BIDI`; if the + * buffer is larger, then extra bytes are ignored. If the buffer is + * smaller, then the split will favour the incoming part, so that + * interoperability is maximised. + * + * \param cc SSL engine context + * \param iobuf I/O buffer. + * \param iobuf_len I/O buffer length (in bytes). + * \param bidi non-zero for full-duplex mode. */ void br_ssl_engine_set_buffer(br_ssl_engine_context *cc, void *iobuf, size_t iobuf_len, int bidi); -/* - * Set the I/O buffers for a SSL engine. This call sets two buffers, for - * concurrent input and output. The two buffers MUST be disjoint. Once - * this call has been made, br_ssl_client_reset() or - * br_ssl_server_reset() must be called before using the context. +/** + * \brief Set the I/O buffers for the SSL engine. + * + * Once this call has been made, `br_ssl_client_reset()` or + * `br_ssl_server_reset()` MUST be called before using the context. + * + * This function is similar to `br_ssl_engine_set_buffer()`, except + * that it enforces full-duplex mode, and the two I/O buffers are + * provided as separate chunks. * - * The BR_SSL_BUFSIZE_INPUT and BR_SSL_BUFSIZE_OUTPUT macros evaluate to - * optimal sizes for the input and output buffers, respectively. If - * using optimal sizes (or larger), then records with the maximum length - * supported by the TLS standard will be accepted and emitted. + * The macros `BR_SSL_BUFSIZE_INPUT` and `BR_SSL_BUFSIZE_OUTPUT` + * evaluate to the optimal (maximum) sizes for the input and output + * buffer, respectively. + * + * \param cc SSL engine context + * \param ibuf input buffer. + * \param ibuf_len input buffer length (in bytes). + * \param obuf output buffer. + * \param obuf_len output buffer length (in bytes). */ void br_ssl_engine_set_buffers_bidi(br_ssl_engine_context *cc, void *ibuf, size_t ibuf_len, void *obuf, size_t obuf_len); -/* - * Inject some "initial entropy" in the context. This entropy will be added - * to what can be obtained from the underlying operating system, if that - * OS is supported. +/** + * \brief Inject some "initial entropy" in the context. + * + * This entropy will be added to what can be obtained from the + * underlying operating system, if that OS is supported. * * This function may be called several times; all injected entropy chunks * are cumulatively mixed. @@ -901,28 +1239,66 @@ void br_ssl_engine_set_buffers_bidi(br_ssl_engine_context *cc, * asymmetric private key that you also store on the system) AND a * non-repeating value (e.g. current time, provided that the local clock * cannot be reset or altered by the attacker). + * + * \param cc SSL engine context. + * \param data extra entropy to inject. + * \param len length of the extra data (in bytes). */ void br_ssl_engine_inject_entropy(br_ssl_engine_context *cc, const void *data, size_t len); -/* - * Get the "server name" in this engine. For clients, this is the name - * provided with br_ssl_client_reset(); for servers, this is the name - * received from the client as part of the ClientHello message. If there - * is no such name (e.g. the client did not send an SNI extension) then - * the returned string is empty (returned pointer points to a byte of - * value 0). +/** + * \brief Get the "server name" in this engine. + * + * For clients, this is the name provided with `br_ssl_client_reset()`; + * for servers, this is the name received from the client as part of the + * ClientHello message. If there is no such name (e.g. the client did + * not send an SNI extension) then the returned string is empty + * (returned pointer points to a byte of value 0). + * + * The returned pointer refers to a buffer inside the context, which may + * be overwritten as part of normal SSL activity (even within the same + * connection, if a renegotiation occurs). + * + * \param cc SSL engine context. + * \return the server name (possibly empty). */ static inline const char * -br_ssl_engine_get_server_name(br_ssl_engine_context *cc) +br_ssl_engine_get_server_name(const br_ssl_engine_context *cc) { return cc->server_name; } -/* - * Get a copy of the session parameters. The session parameters are - * filled during the handshake, so this function shall not be called - * before completion of the handshake. +/** + * \brief Get the protocol version. + * + * This function returns the protocol version that is used by the + * engine. That value is set after sending (for a server) or receiving + * (for a client) the ServerHello message. + * + * \param cc SSL engine context. + * \return the protocol version. + */ +static inline unsigned +br_ssl_engine_get_version(const br_ssl_engine_context *cc) +{ + return cc->session.version; +} + +/** + * \brief Get a copy of the session parameters. + * + * The session parameters are filled during the handshake, so this + * function shall not be called before completion of the handshake. + * The initial handshake is completed when the context first allows + * application data to be injected. + * + * This function copies the current session parameters into the provided + * structure. Beware that the session parameters include the master + * secret, which is sensitive data, to handle with great care. + * + * \param cc SSL engine context. + * \param pp destination structure for the session parameters. */ static inline void br_ssl_engine_get_session_parameters(const br_ssl_engine_context *cc, @@ -931,11 +1307,15 @@ br_ssl_engine_get_session_parameters(const br_ssl_engine_context *cc, memcpy(pp, &cc->session, sizeof *pp); } -/* - * Set the session parameters to the provided value. This function - * is meant to be used in the client, before doing a new handshake; - * a session resumption will be attempted with these parameters. In - * the server, this function has no effect. +/** + * \brief Set the session parameters to the provided values. + * + * This function is meant to be used in the client, before doing a new + * handshake; a session resumption will be attempted with these + * parameters. In the server, this function has no effect. + * + * \param cc SSL engine context. + * \param pp source structure for the session parameters. */ static inline void br_ssl_engine_set_session_parameters(br_ssl_engine_context *cc, @@ -944,46 +1324,73 @@ br_ssl_engine_set_session_parameters(br_ssl_engine_context *cc, memcpy(&cc->session, pp, sizeof *pp); } -/* +/** + * \brief Get the current engine state. + * * An SSL engine (client or server) has, at any time, a state which is * the combination of zero, one or more of these flags: * - * BR_SSL_CLOSED engine is finished, no more I/O (until next reset) - * BR_SSL_SENDREC engine has some bytes to send to the peer - * BR_SSL_RECVREC engine expects some bytes from the peer - * BR_SSL_SENDAPP engine may receive application data to send (or flush) - * BR_SSL_RECVAPP engine has obtained some application data from the peer, - * that should be read by the caller + * - `BR_SSL_CLOSED` + * + * Engine is finished, no more I/O (until next reset). + * + * - `BR_SSL_SENDREC` + * + * Engine has some bytes to send to the peer. + * + * - `BR_SSL_RECVREC` + * + * Engine expects some bytes from the peer. + * + * - `BR_SSL_SENDAPP` + * + * Engine may receive application data to send (or flush). + * + * - `BR_SSL_RECVAPP` + * + * Engine has obtained some application data from the peer, + * that should be read by the caller. * * If no flag at all is set (state value is 0), then the engine is not - * fully initialized yet. + * fully initialised yet. * - * The BR_SSL_CLOSED flag is exclusive; when it is set, no other flag is set. - * To distinguish between a normal closure and an error, use - * br_ssl_engine_last_error(). + * The `BR_SSL_CLOSED` flag is exclusive; when it is set, no other flag + * is set. To distinguish between a normal closure and an error, use + * `br_ssl_engine_last_error()`. * - * Generally speaking, BR_SSL_SENDREC and BR_SSL_SENDAPP are mutually + * Generally speaking, `BR_SSL_SENDREC` and `BR_SSL_SENDAPP` are mutually * exclusive: the input buffer, at any point, either accumulates * plaintext data, or contains an assembled record that is being sent. - * Similarly, BR_SSL_RECVREC and BR_SSL_RECVAPP are mutually exclusive. + * Similarly, `BR_SSL_RECVREC` and `BR_SSL_RECVAPP` are mutually exclusive. * This may change in a future library version. + * + * \param cc SSL engine context. + * \return the current engine state. */ +unsigned br_ssl_engine_current_state(const br_ssl_engine_context *cc); +/** \brief SSL engine state: closed or failed. */ #define BR_SSL_CLOSED 0x0001 +/** \brief SSL engine state: record data is ready to be sent to the peer. */ #define BR_SSL_SENDREC 0x0002 +/** \brief SSL engine state: engine may receive records from the peer. */ #define BR_SSL_RECVREC 0x0004 +/** \brief SSL engine state: engine may accept application data to send. */ #define BR_SSL_SENDAPP 0x0008 +/** \brief SSL engine state: engine has received application data. */ #define BR_SSL_RECVAPP 0x0010 -/* - * Get the current engine state. - */ -unsigned br_ssl_engine_current_state(const br_ssl_engine_context *cc); - -/* - * Get the engine error indicator. This is BR_ERR_OK (0) if no error was - * encountered since the last call to br_ssl_client_reset() or - * br_ssl_server_reset(). Only these calls clear the error indicator. +/** + * \brief Get the engine error indicator. + * + * The error indicator is `BR_ERR_OK` (0) if no error was encountered + * since the last call to `br_ssl_client_reset()` or + * `br_ssl_server_reset()`. Other status values are "sticky": they + * remain set, and prevent all I/O activity, until cleared. Only the + * reset calls clear the error indicator. + * + * \param cc SSL engine context. + * \return 0, or a non-zero error code. */ static inline int br_ssl_engine_last_error(const br_ssl_engine_context *cc) @@ -1027,61 +1434,184 @@ br_ssl_engine_last_error(const br_ssl_engine_context *cc) * call. */ +/** + * \brief Get buffer for application data to send. + * + * If the engine is ready to accept application data to send to the + * peer, then this call returns a pointer to the buffer where such + * data shall be written, and its length is written in `*len`. + * Otherwise, `*len` is set to 0 and `NULL` is returned. + * + * \param cc SSL engine context. + * \param len receives the application data output buffer length, or 0. + * \return the application data output buffer, or `NULL`. + */ unsigned char *br_ssl_engine_sendapp_buf( const br_ssl_engine_context *cc, size_t *len); + +/** + * \brief Inform the engine of some new application data. + * + * After writing `len` bytes in the buffer returned by + * `br_ssl_engine_sendapp_buf()`, the application shall call this + * function to trigger any relevant processing. The `len` parameter + * MUST NOT be 0, and MUST NOT exceed the value obtained in the + * `br_ssl_engine_sendapp_buf()` call. + * + * \param cc SSL engine context. + * \param len number of bytes pushed (not zero). + */ void br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len); +/** + * \brief Get buffer for received application data. + * + * If the engine has received application data from the peer, hen this + * call returns a pointer to the buffer from where such data shall be + * read, and its length is written in `*len`. Otherwise, `*len` is set + * to 0 and `NULL` is returned. + * + * \param cc SSL engine context. + * \param len receives the application data input buffer length, or 0. + * \return the application data input buffer, or `NULL`. + */ unsigned char *br_ssl_engine_recvapp_buf( const br_ssl_engine_context *cc, size_t *len); + +/** + * \brief Acknowledge some received application data. + * + * After reading `len` bytes from the buffer returned by + * `br_ssl_engine_recvapp_buf()`, the application shall call this + * function to trigger any relevant processing. The `len` parameter + * MUST NOT be 0, and MUST NOT exceed the value obtained in the + * `br_ssl_engine_recvapp_buf()` call. + * + * \param cc SSL engine context. + * \param len number of bytes read (not zero). + */ void br_ssl_engine_recvapp_ack(br_ssl_engine_context *cc, size_t len); +/** + * \brief Get buffer for record data to send. + * + * If the engine has prepared some records to send to the peer, then this + * call returns a pointer to the buffer from where such data shall be + * read, and its length is written in `*len`. Otherwise, `*len` is set + * to 0 and `NULL` is returned. + * + * \param cc SSL engine context. + * \param len receives the record data output buffer length, or 0. + * \return the record data output buffer, or `NULL`. + */ unsigned char *br_ssl_engine_sendrec_buf( const br_ssl_engine_context *cc, size_t *len); + +/** + * \brief Acknowledge some sent record data. + * + * After reading `len` bytes from the buffer returned by + * `br_ssl_engine_sendrec_buf()`, the application shall call this + * function to trigger any relevant processing. The `len` parameter + * MUST NOT be 0, and MUST NOT exceed the value obtained in the + * `br_ssl_engine_sendrec_buf()` call. + * + * \param cc SSL engine context. + * \param len number of bytes read (not zero). + */ void br_ssl_engine_sendrec_ack(br_ssl_engine_context *cc, size_t len); +/** + * \brief Get buffer for incoming records. + * + * If the engine is ready to accept records from the peer, then this + * call returns a pointer to the buffer where such data shall be + * written, and its length is written in `*len`. Otherwise, `*len` is + * set to 0 and `NULL` is returned. + * + * \param cc SSL engine context. + * \param len receives the record data input buffer length, or 0. + * \return the record data input buffer, or `NULL`. + */ unsigned char *br_ssl_engine_recvrec_buf( const br_ssl_engine_context *cc, size_t *len); + +/** + * \brief Inform the engine of some new record data. + * + * After writing `len` bytes in the buffer returned by + * `br_ssl_engine_recvrec_buf()`, the application shall call this + * function to trigger any relevant processing. The `len` parameter + * MUST NOT be 0, and MUST NOT exceed the value obtained in the + * `br_ssl_engine_recvrec_buf()` call. + * + * \param cc SSL engine context. + * \param len number of bytes pushed (not zero). + */ void br_ssl_engine_recvrec_ack(br_ssl_engine_context *cc, size_t len); -/* +/** + * \brief Flush buffered application data. + * * If some application data has been buffered in the engine, then wrap * it into a record and mark it for sending. If no application data has * been buffered but the engine would be ready to accept some, AND the - * 'force' parameter is non-zero, then an empty record is assembled and + * `force` parameter is non-zero, then an empty record is assembled and * marked for sending. In all other cases, this function does nothing. * * Empty records are technically legal, but not all existing SSL/TLS * implementations support them. Empty records can be useful as a * transparent "keep-alive" mechanism to maintain some low-level * network activity. + * + * \param cc SSL engine context. + * \param force non-zero to force sending an empty record. */ void br_ssl_engine_flush(br_ssl_engine_context *cc, int force); -/* - * Close the context. If, at that point, the context is open and in - * ready state, then a close_notify alert is assembled and marked for - * sending. Otherwise, no such alert is assembled. +/** + * \brief Initiate a closure. + * + * If, at that point, the context is open and in ready state, then a + * `close_notify` alert is assembled and marked for sending; this + * triggers the closure protocol. Otherwise, no such alert is assembled. + * + * \param cc SSL engine context. */ void br_ssl_engine_close(br_ssl_engine_context *cc); -/* - * Initiate a renegotiation. If the engine is failed or closed, or if - * the peer is known not to support secure renegotiation (RFC 5746), - * then this function returns 0. Otherwise, this function returns 1 and - * a renegotiation attempt is triggered, unless a handshake is already - * taking place, in which case the call is ignored. +/** + * \brief Initiate a renegotiation. + * + * If the engine is failed or closed, or if the peer is known not to + * support secure renegotiation (RFC 5746), or if renegotiations have + * been disabled with the `BR_OPT_NO_RENEGOTIATION` flag, then this + * function returns 0 and nothing else happens. + * + * Otherwise, this function returns 1, and a renegotiation attempt is + * triggered (if a handshake is already ongoing at that point, then + * no new handshake is triggered). + * + * \param cc SSL engine context. + * \return 1 on success, 0 on error. */ int br_ssl_engine_renegotiate(br_ssl_engine_context *cc); -/* - * Context structure for a SSL client. +/** + * \brief Context structure for a SSL client. + * + * The first field (called `eng`) is the SSL engine; all functions that + * work on a `br_ssl_engine_context` structure shall take as parameter + * a pointer to that field. The other structure fields are opaque and + * must not be accessed directly. */ typedef struct { - /* - * The encapsulated engine context. + /** + * \brief The encapsulated engine context. */ br_ssl_engine_context eng; +#ifndef BR_DOXYGEN_IGNORE /* * Minimum ClientHello length; padding with an extension (RFC * 7685) is added if necessary to match at least that length. @@ -1096,7 +1626,7 @@ typedef struct { br_rsa_public irsapub; br_rsa_pkcs1_vrfy irsavrfy; br_ecdsa_vrfy iecdsa; - +#endif } br_ssl_client_context; /* @@ -1105,24 +1635,46 @@ typedef struct { * name 'xxx'. Defined profile names are: * * full all supported versions and suites; constant-time implementations - * FIXME: add other profiles + * TODO: add other profiles */ +/** + * \brief SSL client profile: full. + * + * This function initialises the provided SSL client context with + * all supported algorithms and cipher suites. It also initialises + * a companion X.509 validation engine with all supported algorithms, + * and the provided trust anchors; the X.509 engine will be used by + * the client context to validate the server's certificate. + * + * \param cc client context to initialise. + * \param xc X.509 validation context to initialise. + * \param trust_anchors trust anchors to use. + * \param trust_anchors_num number of trust anchors. + */ void br_ssl_client_init_full(br_ssl_client_context *cc, br_x509_minimal_context *xc, const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num); -/* - * Clear the complete contents of a SSL client context, including the - * reference to the configured buffer, implementations, cipher suites - * and state. +/** + * \brief Clear the complete contents of a SSL client context. + * + * Everything is cleared, including the reference to the configured buffer, + * implementations, cipher suites and state. This is a preparatory step + * to assembling a custom profile. + * + * \param cc client context to clear. */ void br_ssl_client_zero(br_ssl_client_context *cc); -/* - * Set the RSA public-key operations implementation. This will be used - * to encrypt the pre-master secret with the server's RSA public key - * (RSA-encryption cipher suites only). +/** + * \brief Set the RSA public-key operations implementation. + * + * This will be used to encrypt the pre-master secret with the server's + * RSA public key (RSA-encryption cipher suites only). + * + * \param cc client context. + * \param irsapub RSA public-key encryption implementation. */ static inline void br_ssl_client_set_rsapub(br_ssl_client_context *cc, br_rsa_public irsapub) @@ -1130,10 +1682,14 @@ br_ssl_client_set_rsapub(br_ssl_client_context *cc, br_rsa_public irsapub) cc->irsapub = irsapub; } -/* - * Set the RSA signature verification implementation. This will be used - * to verify the server's signature on its ServerKeyExchange message - * (ECDHE_RSA cipher suites only). +/** + * \brief Set the RSA signature verification implementation. + * + * This will be used to verify the server's signature on its + * ServerKeyExchange message (ECDHE_RSA cipher suites only). + * + * \param cc client context. + * \param irsavrfy RSA signature verification implementation. */ static inline void br_ssl_client_set_rsavrfy(br_ssl_client_context *cc, br_rsa_pkcs1_vrfy irsavrfy) @@ -1142,8 +1698,13 @@ br_ssl_client_set_rsavrfy(br_ssl_client_context *cc, br_rsa_pkcs1_vrfy irsavrfy) } /* - * Set the ECDSA implementation (signature verification). The ECC core - * implementation must also have been set. + * \brief Set the ECDSA implementation (signature verification). + * + * The ECDSA implementation will use the EC core implementation configured + * in the engine context. + * + * \param cc client context. + * \param iecdsa ECDSA verification implementation. */ static inline void br_ssl_client_set_ecdsa(br_ssl_client_context *cc, br_ecdsa_vrfy iecdsa) @@ -1151,8 +1712,22 @@ br_ssl_client_set_ecdsa(br_ssl_client_context *cc, br_ecdsa_vrfy iecdsa) cc->iecdsa = iecdsa; } -/* - * Set the minimum ClientHello length (RFC 7685 padding). +/** + * \brief Set the minimum ClientHello length (RFC 7685 padding). + * + * If this value is set and the ClientHello would be shorter, then + * the Pad ClientHello extension will be added with enough padding bytes + * to reach the target size. Because of the extension header, the resulting + * size will sometimes be slightly more than `len` bytes if the target + * size cannot be exactly met. + * + * The target length relates to the _contents_ of the ClientHello, not + * counting its 4-byte header. For instance, if `len` is set to 512, + * then the padding will bring the ClientHello size to 516 bytes with its + * header, and 521 bytes when counting the 5-byte record header. + * + * \param cc client context. + * \param len minimum ClientHello length (in bytes). */ static inline void br_ssl_client_set_min_clienthello_len(br_ssl_client_context *cc, uint16_t len) @@ -1160,29 +1735,47 @@ br_ssl_client_set_min_clienthello_len(br_ssl_client_context *cc, uint16_t len) cc->min_clienthello_len = len; } -/* - * Prepare or reset a client context for connecting with a server of - * name 'server_name'. The 'server_name' parameter is used to fill the - * SNI extension; if the parameter is NULL then no SNI extension will - * be sent. +/** + * \brief Prepare or reset a client context for a new connection. + * + * The `server_name` parameter is used to fill the SNI extension; the + * X.509 "minimal" engine will also match that name against the server + * names included in the server's certificate. If the parameter is + * `NULL` then no SNI extension will be sent, and the X.509 "minimal" + * engine (if used for server certificate validation) will not check + * presence of any specific name in the received certificate. * - * If 'resume_session' is non-zero and the context was previously used + * Therefore, setting the `server_name` to `NULL` shall be reserved + * to cases where alternate or additional methods are used to ascertain + * that the right server public key is used (e.g. a "known key" model). + * + * If `resume_session` is non-zero and the context was previously used * then the session parameters may be reused (depending on whether the * server previously sent a non-empty session ID, and accepts the session - * resumption). + * resumption). The session parameters for session resumption can also + * be set explicitly with `br_ssl_engine_set_session_parameters()`. * * On failure, the context is marked as failed, and this function * returns 0. A possible failure condition is when no initial entropy * was injected, and none could be obtained from the OS (either OS * randomness gathering is not supported, or it failed). + * + * \param cc client context. + * \param server_name target server name, or `NULL`. + * \param resume_session non-zero to try session resumption. + * \return 0 on failure, 1 on success. */ int br_ssl_client_reset(br_ssl_client_context *cc, const char *server_name, int resume_session); -/* - * Forget any session in the context. This means that the next handshake - * that uses this context will necessarily be a full handshake (this - * applies both to new connections and to renegotiations). +/** + * \brief Forget any session in the context. + * + * This means that the next handshake that uses this context will + * necessarily be a full handshake (this applies both to new connections + * and to renegotiations). + * + * \param cc client context. */ static inline void br_ssl_client_forget_session(br_ssl_client_context *cc) @@ -1190,40 +1783,64 @@ br_ssl_client_forget_session(br_ssl_client_context *cc) cc->eng.session.session_id_len = 0; } -/* - * Type for a "translated cipher suite", as an array of 16-bit integers: - * first element is the cipher suite identifier (as used on the wire), - * and the second element is the concatenation of four 4-bit elements which +/** + * \brief Type for a "translated cipher suite", as an array of two + * 16-bit integers. + * + * The first element is the cipher suite identifier (as used on the wire). + * The second element is the concatenation of four 4-bit elements which * characterise the cipher suite contents. In most to least significant * order, these 4-bit elements are: * - * Bits 12 to 15: key exchange + server key type - * 0 RSA RSA key exchange, key is RSA (encryption) - * 1 ECDHE-RSA ECDHE key exchange, key is RSA (signature) - * 2 ECDHE-ECDSA ECDHE key exchange, key is EC (signature) - * 3 ECDH-RSA Key is EC (key exchange), cert is signed with RSA - * 4 ECDH-ECDSA Key is EC (key exchange), cert is signed with ECDSA - * - * Bits 8 to 11: symmetric encryption algorithm - * 0 3DES/CBC - * 1 AES-128/CBC - * 2 AES-256/CBC - * 3 AES-128/GCM - * 4 AES-256/GCM - * 5 ChaCha20/Poly1305 - * - * Bits 4 to 7: MAC algorithm - * 0 AEAD No dedicated MAC because encryption is AEAD - * 2 HMAC/SHA-1 Value matches br_sha1_ID - * 4 HMAC/SHA-256 Value matches br_sha256_ID - * 5 HMAC/SHA-384 Value matches br_sha384_ID - * - * Bits 0 to 3: hash function for PRF when used with TLS-1.2 - * 4 SHA-256 Value matches br_sha256_ID - * 5 SHA-384 Value matches br_sha384_ID + * - Bits 12 to 15: key exchange + server key type + * + * | val | symbolic constant | suite type | details | + * | :-- | :----------------------- | :---------- | :----------------------------------------------- | + * | 0 | `BR_SSLKEYX_RSA` | RSA | RSA key exchange, key is RSA (encryption) | + * | 1 | `BR_SSLKEYX_ECDHE_RSA` | ECDHE_RSA | ECDHE key exchange, key is RSA (signature) | + * | 2 | `BR_SSLKEYX_ECDHE_ECDSA` | ECDHE_ECDSA | ECDHE key exchange, key is EC (signature) | + * | 3 | `BR_SSLKEYX_ECDH_RSA` | ECDH_RSA | Key is EC (key exchange), cert signed with RSA | + * | 4 | `BR_SSLKEYX_ECDH_ECDSA` | ECDH_ECDSA | Key is EC (key exchange), cert signed with ECDSA | + * + * - Bits 8 to 11: symmetric encryption algorithm + * + * | val | symbolic constant | symmetric encryption | key strength (bits) | + * | :-- | :--------------------- | :------------------- | :------------------ | + * | 0 | `BR_SSLENC_3DES_CBC` | 3DES/CBC | 168 | + * | 1 | `BR_SSLENC_AES128_CBC` | AES-128/CBC | 128 | + * | 2 | `BR_SSLENC_AES256_CBC` | AES-256/CBC | 256 | + * | 3 | `BR_SSLENC_AES128_GCM` | AES-128/GCM | 128 | + * | 4 | `BR_SSLENC_AES256_GCM` | AES-256/GCM | 256 | + * | 5 | `BR_SSLENC_CHACHA20` | ChaCha20/Poly1305 | 256 | + * + * - Bits 4 to 7: MAC algorithm + * + * | val | symbolic constant | MAC type | details | + * | :-- | :----------------- | :----------- | :------------------------------------ | + * | 0 | `BR_SSLMAC_AEAD` | AEAD | No dedicated MAC (encryption is AEAD) | + * | 2 | `BR_SSLMAC_SHA1` | HMAC/SHA-1 | Value matches `br_sha1_ID` | + * | 4 | `BR_SSLMAC_SHA256` | HMAC/SHA-256 | Value matches `br_sha256_ID` | + * | 5 | `BR_SSLMAC_SHA384` | HMAC/SHA-384 | Value matches `br_sha384_ID` | + * + * - Bits 0 to 3: hash function for PRF when used with TLS-1.2 + * + * | val | symbolic constant | hash function | details | + * | :-- | :----------------- | :------------ | :----------------------------------- | + * | 4 | `BR_SSLPRF_SHA256` | SHA-256 | Value matches `br_sha256_ID` | + * | 5 | `BR_SSLPRF_SHA384` | SHA-384 | Value matches `br_sha384_ID` | + * + * For instance, cipher suite `TLS_RSA_WITH_AES_128_GCM_SHA256` has + * standard identifier 0x009C, and is translated to 0x0304, for, in + * that order: RSA key exchange (0), AES-128/GCM (3), AEAD integrity (0), + * SHA-256 in the TLS PRF (4). */ typedef uint16_t br_suite_translated[2]; +#ifndef BR_DOXYGEN_IGNORE +/* + * Constants are already documented in the br_suite_translated type. + */ + #define BR_SSLKEYX_RSA 0 #define BR_SSLKEYX_ECDHE_RSA 1 #define BR_SSLKEYX_ECDHE_ECDSA 2 @@ -1245,122 +1862,234 @@ typedef uint16_t br_suite_translated[2]; #define BR_SSLPRF_SHA256 br_sha256_ID #define BR_SSLPRF_SHA384 br_sha384_ID +#endif + /* * Pre-declaration for the SSL server context. */ typedef struct br_ssl_server_context_ br_ssl_server_context; -/* - * Type for the server policy choices, taken after analysis of the client - * message: - * - * cipher_suite Cipher suite to use. - * - * hash_id Signature hash function identifier (hash function - * to use for signing the ServerKeyExchange, when the - * suite uses ECDHE). - * - * chain The certificate chain to send (number of certificates - * chain_len is in chain_length). The certificates are send "as is" - * and shall be in standard SSL/TLS order (i.e. end-entity - * first, each subsequent certificate signs the previous). +/** + * \brief Type for the server policy choices, taken after analysis of + * the client message (ClientHello). */ typedef struct { + /** + * \brief Cipher suite to use with that client. + */ uint16_t cipher_suite; + + /** + * \brief Hash function for signing the ServerKeyExchange. + * + * This is the symbolic identifier for the hash function that + * will be used to sign the ServerKeyExchange message, for ECDHE + * cipher suites. This is ignored for RSA and ECDH cipher suites. + * + * Take care that with TLS 1.0 and 1.1, that value MUST match + * the protocol requirements: value must be 0 (MD5+SHA-1) for + * a RSA signature, or 2 (SHA-1) for an ECDSA signature. Only + * TLS 1.2 allows for other hash functions. + */ int hash_id; + + /** + * \brief Certificate chain to send to the client. + * + * This is an array of `br_x509_certificate` objects, each + * normally containing a DER-encoded certificate. The server + * code does not try to decode these elements. + */ const br_x509_certificate *chain; + + /** + * \brief Certificate chain length (number of certificates). + */ size_t chain_len; } br_ssl_server_choices; -/* - * Type for the certificate and private key handler on the server: an - * object with the following methods: - * - * choose Select the parameters for this connection (cipher suite, - * certificate chain...). The selection is written into the - * '*choices' structure. Returned value is 1 on success, or - * 0 on error (an error here means that the handshake will - * fail, and a handshake_failure alert will be sent to the - * client). - * - * do_keyx Perform the server-side key exchange operation. Returned - * value is 1 on success, 0 on error (see below). This is - * called only when the selected cipher suite calls for a - * RSA or ECDH key exchange involving the server key. - * - * do_sign Perform the server-side signature operation. Returned - * value is the signature length, or 0 on error (see below). - * This is called only when the selected cipher suite calls - * for an ECDHE key exchange, signed by the server with its key. - * - * - * The do_keyx() method shall apply the following semantics: - * - * -- For RSA key exchange, it shall decrypt the incoming data along - * the rules of PKCS#1 v1.5. The method must verify the proper padding - * and also that the decrypted message length is exactly 48 bytes. - * IMPORTANT: these operations MUST be constant-time (or adequatly blinded). - * The decrypted message is written in the first 48 bytes of data[]. The - * caller makes sure that the data[] buffer is large enough, and that 'len' - * is at least 59 bytes. - * - * -- For ECDH key exchange, the provided data is an EC point (uncompressed - * format); the method shall multiply that point with the server private - * key, and write the X coordinate of the resulting point in the data[] - * buffer, starting at offset 1 (so if the method produces a compressed or - * uncompressed point, form offset 0, then everything is fine). - * - * In both cases, returned value is 1 on success, 0 on error. +/** + * \brief Class type for a policy handler (server side). * + * A policy handler selects the policy parameters for a connection + * (cipher suite and other algorithms, and certificate chain to send to + * the client); it also performs the server-side computations involving + * its permanent private key. * - * The do_sign() method shall compute the signature on the hash value - * provided in the data[] buffer. The 'hv_len' value contains the hash - * value length, while the 'len' parameter is the total size of the - * buffer. The method must verify that the signature length is no more - * than 'len' bytes, and report an error otherwise. - * - * The hash identifier is either 0 for the MD5+SHA-1 method in TLS-1.0 and - * 1.1, or a non-zero hash function identifier in TLS-1.2 and later. In - * the MD5+SHA-1 method, the hash value has length 36 bytes and there is - * no hash function identifying header to add in the padding. - * - * Returned value is the signature length (in bytes). On error, this method - * shall return 0. + * The SSL server engine will invoke first `choose()`, once the + * ClientHello message has been received, then either `do_keyx()` + * `do_sign()`, depending on the cipher suite. */ typedef struct br_ssl_server_policy_class_ br_ssl_server_policy_class; struct br_ssl_server_policy_class_ { + /** + * \brief Context size (in bytes). + */ size_t context_size; + + /** + * \brief Select algorithms and certificates for this connection. + * + * This callback function shall fill the provided `choices` + * structure with the policy choices for this connection. This + * entails selecting the cipher suite, hash function for signing + * the ServerKeyExchange (applicable only to ECDHE cipher suites), + * and certificate chain to send. + * + * The callback receives a pointer to the server context that + * contains the relevant data. In particular, the functions + * `br_ssl_server_get_client_suites()`, + * `br_ssl_server_get_client_hashes()` and + * `br_ssl_server_get_client_curves()` can be used to obtain + * the cipher suites, hash functions and elliptic curves + * supported by both the client and server, respectively. The + * `br_ssl_engine_get_version()` and `br_ssl_engine_get_server_name()` + * functions yield the protocol version and requested server name + * (SNI), respectively. + * + * This function may modify its context structure (`pctx`) in + * arbitrary ways to keep track of its own choices. + * + * This function shall return 1 if appropriate policy choices + * could be made, or 0 if this connection cannot be pursued. + * + * \param pctx policy context. + * \param cc SSL server context. + * \param choices destination structure for the policy choices. + * \return 1 on success, 0 on error. + */ int (*choose)(const br_ssl_server_policy_class **pctx, const br_ssl_server_context *cc, br_ssl_server_choices *choices); + + /** + * \brief Perform key exchange (server part). + * + * This callback is invoked to perform the server-side cryptographic + * operation for a key exchange that is not ECDHE. This callback + * uses the private key. + * + * **For RSA key exchange**, the provided `data` (of length `len` + * bytes) shall be decrypted with the server's private key, and + * the 48-byte premaster secret copied back to the first 48 bytes + * of `data`. + * + * - The caller makes sure that `len` is at least 59 bytes. + * + * - This callback MUST check that the provided length matches + * that of the key modulus; it shall report an error otherwise. + * + * - If the length matches that of the RSA key modulus, then + * processing MUST be constant-time, even if decryption fails, + * or the padding is incorrect, or the plaintext message length + * is not exactly 48 bytes. + * + * - This callback needs not check the two first bytes of the + * obtained pre-master secret (the caller will do that). + * + * - If an error is reported (0), then what the callback put + * in the first 48 bytes of `data` is unimportant (the caller + * will use random bytes instead). + * + * **For ECDH key exchange**, the provided `data` (of length `len` + * bytes) is the elliptic curve point from the client. The + * callback shall multiply it with its private key, and store + * the resulting X coordinate in `data`, starting at offset 1 + * (thus, simply encoding the point in compressed or uncompressed + * format in `data` is fine). + * + * - If the input array does not have the proper length for + * an encoded curve point, then an error (0) shall be reported. + * + * - If the input array has the proper length, then processing + * MUST be constant-time, even if the data is not a valid + * encoded point. + * + * - This callback MUST check that the input point is valid. + * + * Returned value is 1 on success, 0 on error. + * + * \param pctx policy context. + * \param data key exchange data from the client. + * \param len key exchange data length (in bytes). + * \return 1 on success, 0 on error. + */ uint32_t (*do_keyx)(const br_ssl_server_policy_class **pctx, unsigned char *data, size_t len); + + /** + * \brief Perform a signature (for a ServerKeyExchange message). + * + * This callback function is invoked for ECDHE cipher suites. + * On input, the hash value to sign is in `data`, of size + * `hv_len`; the involved hash function is identified by + * `hash_id`. The signature shall be computed and written + * back into `data`; the total size of that buffer is `len` + * bytes. + * + * This callback shall verify that the signature length does not + * exceed `len` bytes, and abstain from writing the signature if + * it does not fit. + * + * For RSA signatures, the `hash_id` may be 0, in which case + * this is the special header-less signature specified in TLS 1.0 + * and 1.1, with a 36-byte hash value. Otherwise, normal PKCS#1 + * v1.5 signatures shall be computed. + * + * Returned value is the signature length (in bytes), or 0 on error. + * + * \param pctx policy context. + * \param hash_id hash function identifier. + * \param hv_len hash value length (in bytes). + * \param data input/output buffer (hash value, then signature). + * \param len total buffer length (in bytes). + * \return signature length (in bytes) on success, or 0 on error. + */ size_t (*do_sign)(const br_ssl_server_policy_class **pctx, int hash_id, size_t hv_len, unsigned char *data, size_t len); }; -/* - * A single-chain RSA policy handler, that always uses a single chain and - * a RSA key. It may be restricted to do only signatures or only key - * exchange. +/** + * \brief A single-chain RSA policy handler. + * + * This policy context uses a single certificate chain, and a RSA + * private key. The context can be restricted to only signatures or + * only key exchange. + * + * Apart from the first field (vtable pointer), its contents are + * opaque and shall not be accessed directly. */ typedef struct { + /** \brief Pointer to vtable. */ const br_ssl_server_policy_class *vtable; +#ifndef BR_DOXYGEN_IGNORE const br_x509_certificate *chain; size_t chain_len; const br_rsa_private_key *sk; unsigned allowed_usages; br_rsa_private irsacore; br_rsa_pkcs1_sign irsasign; +#endif } br_ssl_server_policy_rsa_context; -/* - * A single-chain EC policy handler, that always uses a single chain and - * an EC key. It may be restricted to do only signatures or only key - * exchange. +/** + * \brief A single-chain EC policy handler. + * + * This policy context uses a single certificate chain, and an EC + * private key. The context can be restricted to only signatures or + * only key exchange. + * + * Due to how TLS is defined, this context must be made aware whether + * the server certificate was itself signed with RSA or ECDSA. The code + * does not try to decode the certificate to obtain that information. + * + * Apart from the first field (vtable pointer), its contents are + * opaque and shall not be accessed directly. */ typedef struct { + /** \brief Pointer to vtable. */ const br_ssl_server_policy_class *vtable; +#ifndef BR_DOXYGEN_IGNORE const br_x509_certificate *chain; size_t chain_len; const br_ec_private_key *sk; @@ -1369,69 +2098,117 @@ typedef struct { const br_multihash_context *mhash; const br_ec_impl *iec; br_ecdsa_sign iecdsa; +#endif } br_ssl_server_policy_ec_context; -/* - * Class type for a session parameter cache. +/** + * \brief Class type for a session parameter cache. * - * save Record session parameters. The session ID has been randomly - * generated, and the session ID length is always 32 bytes. - * The method shall copy the provided information (the structure - * is transient). - * - * load Find session parameters by ID. The session ID is in the relevant - * field in the '*params' structure, and has always length exactly - * 32 bytes. The method shall fill in the other field with the - * session data, if found. Returned value is 1 when the session was - * found, 0 otherwise. - * - * Note that the requesting server context is provided. Implementations - * may used some of the resources of that context, e.g. random number - * generator or implementations of some cryptographic algorithms. + * Session parameters are saved in the cache with `save()`, and + * retrieved with `load()`. The cache implementation can apply any + * storage and eviction strategy that it sees fit. The SSL server + * context that performs the request is provided, so that its + * functionalities may be used by the implementation (e.g. hash + * functions or random number generation). */ typedef struct br_ssl_session_cache_class_ br_ssl_session_cache_class; struct br_ssl_session_cache_class_ { + /** + * \brief Context size (in bytes). + */ size_t context_size; + + /** + * \brief Record a session. + * + * This callback should record the provided session parameters. + * The `params` structure is transient, so its contents shall + * be copied into the cache. The session ID has been randomly + * generated and always has length exactly 32 bytes. + * + * \param ctx session cache context. + * \param server_ctx SSL server context. + * \param params session parameters to save. + */ void (*save)(const br_ssl_session_cache_class **ctx, br_ssl_server_context *server_ctx, const br_ssl_session_parameters *params); + + /** + * \brief Lookup a session in the cache. + * + * The session ID to lookup is in `params` and always has length + * exactly 32 bytes. If the session parameters are found in the + * cache, then the parameters shall be copied into the `params` + * structure. Returned value is 1 on successful lookup, 0 + * otherwise. + * + * \param ctx session cache context. + * \param server_ctx SSL server context. + * \param params destination for session parameters. + * \return 1 if found, 0 otherwise. + */ int (*load)(const br_ssl_session_cache_class **ctx, br_ssl_server_context *server_ctx, br_ssl_session_parameters *params); }; -/* - * Context for a very basic cache system that uses a linked list, managed - * with an LRU algorithm (when the cache is full and a new set of parameters - * must be saved, the least recently used entry is evicted). The storage - * buffer is externally provided. Internally, an index tree is used to - * speed up operations. +/** + * \brief Context for a basic cache system. + * + * The system stores session parameters in a buffer provided at + * initialisation time. Each entry uses exactly 100 bytes, and + * buffer sizes up to 4294967295 bytes are supported. + * + * Entries are evicted with a LRU (Least Recently Used) policy. A + * search tree is maintained to keep lookups fast even with large + * caches. + * + * Apart from the first field (vtable pointer), the structure + * contents are opaque and shall not be accessed directly. */ typedef struct { + /** \brief Pointer to vtable. */ const br_ssl_session_cache_class *vtable; +#ifndef BR_DOXYGEN_IGNORE unsigned char *store; size_t store_len, store_ptr; unsigned char index_key[32]; const br_hash_class *hash; int init_done; uint32_t head, tail, root; +#endif } br_ssl_session_cache_lru; -/* - * Initialise a LRU session cache with the provided storage space. +/** + * \brief Initialise a LRU session cache with the provided storage space. + * + * The provided storage space must remain valid as long as the cache + * is used. Arbitrary lengths are supported, up to 4294967295 bytes; + * each entry uses up exactly 100 bytes. + * + * \param cc session cache context. + * \param store storage space for cached entries. + * \param store_len storage space length (in bytes). */ void br_ssl_session_cache_lru_init(br_ssl_session_cache_lru *cc, unsigned char *store, size_t store_len); -/* - * Context structure for a SSL server. +/** + * \brief Context structure for a SSL server. + * + * The first field (called `eng`) is the SSL engine; all functions that + * work on a `br_ssl_engine_context` structure shall take as parameter + * a pointer to that field. The other structure fields are opaque and + * must not be accessed directly. */ struct br_ssl_server_context_ { - /* - * The encapsulated engine context. + /** + * \brief The encapsulated engine context. */ br_ssl_engine_context eng; +#ifndef BR_DOXYGEN_IGNORE /* * Maximum version from the client. */ @@ -1491,22 +2268,11 @@ struct br_ssl_server_context_ { /* * Server-specific implementations. + * (none for now) */ +#endif }; -/* - * If this flag is set, then the server will enforce its own cipher suite - * preference order; otherwise, it follows the client preferences. - */ -#define BR_OPT_ENFORCE_SERVER_PREFERENCES ((uint32_t)1 << 0) - -/* - * If this flag is set, then renegotiations are rejected unconditionally: - * they won't be honoured if asked for programmatically, and requests from - * the peer are rejected. - */ -#define BR_OPT_NO_RENEGOTIATION ((uint32_t)1 << 1) - /* * Each br_ssl_server_init_xxx() function sets the list of supported * cipher suites and used implementations, as specified by the profile @@ -1514,7 +2280,7 @@ struct br_ssl_server_context_ { * * full_rsa all supported algorithm, server key type is RSA * full_ec all supported algorithm, server key type is EC - * FIXME: add other profiles + * TODO: add other profiles * * Naming scheme for "minimal" profiles: min123 * @@ -1534,33 +2300,156 @@ struct br_ssl_server_context_ { * d = 3DES/CBC */ +/** + * \brief SSL server profile: full_rsa. + * + * This function initialises the provided SSL server context with + * all supported algorithms and cipher suites that rely on a RSA + * key pair. + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len certificate chain length (number of certificate). + * \param sk RSA private key. + */ void br_ssl_server_init_full_rsa(br_ssl_server_context *cc, const br_x509_certificate *chain, size_t chain_len, const br_rsa_private_key *sk); +/** + * \brief SSL server profile: full_ec. + * + * This function initialises the provided SSL server context with + * all supported algorithms and cipher suites that rely on an EC + * key pair. + * + * The key type of the CA that issued the server's certificate must + * be provided, since it matters for ECDH cipher suites (ECDH_RSA + * suites require a RSA-powered CA). The key type is either + * `BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`. + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len chain length (number of certificates). + * \param cert_issuer_key_type certificate issuer's key type. + * \param sk EC private key. + */ void br_ssl_server_init_full_ec(br_ssl_server_context *cc, const br_x509_certificate *chain, size_t chain_len, unsigned cert_issuer_key_type, const br_ec_private_key *sk); +/** + * \brief SSL server profile: minr2g. + * + * This profile uses only TLS_RSA_WITH_AES_128_GCM_SHA256. Server key is + * RSA, and RSA key exchange is used (not forward secure, but uses little + * CPU in the client). + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len certificate chain length (number of certificate). + * \param sk RSA private key. + */ void br_ssl_server_init_minr2g(br_ssl_server_context *cc, const br_x509_certificate *chain, size_t chain_len, const br_rsa_private_key *sk); + +/** + * \brief SSL server profile: mine2g. + * + * This profile uses only TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256. Server key + * is RSA, and ECDHE key exchange is used. This suite provides forward + * security, with a higher CPU expense on the client, and a somewhat + * larger code footprint (compared to "minr2g"). + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len certificate chain length (number of certificate). + * \param sk RSA private key. + */ void br_ssl_server_init_mine2g(br_ssl_server_context *cc, const br_x509_certificate *chain, size_t chain_len, const br_rsa_private_key *sk); + +/** + * \brief SSL server profile: minf2g. + * + * This profile uses only TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256. + * Server key is EC, and ECDHE key exchange is used. This suite provides + * forward security, with a higher CPU expense on the client and server + * (by a factor of about 3 to 4), and a somewhat larger code footprint + * (compared to "minu2g" and "minv2g"). + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len certificate chain length (number of certificate). + * \param sk EC private key. + */ void br_ssl_server_init_minf2g(br_ssl_server_context *cc, const br_x509_certificate *chain, size_t chain_len, const br_ec_private_key *sk); + +/** + * \brief SSL server profile: minu2g. + * + * This profile uses only TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256. + * Server key is EC, and ECDH key exchange is used; the issuing CA used + * a RSA key. + * + * The "minu2g" and "minv2g" profiles do not provide forward secrecy, + * but are the lightest on the server (for CPU usage), and are rather + * inexpensive on the client as well. + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len certificate chain length (number of certificate). + * \param sk EC private key. + */ void br_ssl_server_init_minu2g(br_ssl_server_context *cc, const br_x509_certificate *chain, size_t chain_len, const br_ec_private_key *sk); + +/** + * \brief SSL server profile: minv2g. + * + * This profile uses only TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256. + * Server key is EC, and ECDH key exchange is used; the issuing CA used + * an EC key. + * + * The "minu2g" and "minv2g" profiles do not provide forward secrecy, + * but are the lightest on the server (for CPU usage), and are rather + * inexpensive on the client as well. + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len certificate chain length (number of certificate). + * \param sk EC private key. + */ void br_ssl_server_init_minv2g(br_ssl_server_context *cc, const br_x509_certificate *chain, size_t chain_len, const br_ec_private_key *sk); -/* - * Get the supported client suites. The returned array is ordered by - * client or server preferences, depending on the relevant flag. +/** + * \brief Get the supported client suites. + * + * This function shall be called only after the ClientHello has been + * processed, typically from the policy engine. The returned array + * contains the cipher suites that are supported by both the client + * and the server; these suites are in client preference order, unless + * the `BR_OPT_ENFORCE_SERVER_PREFERENCES` flag was set, in which case + * they are in server preference order. + * + * The suites are _translated_, which means that each suite is given + * as two 16-bit integers: the standard suite identifier, and its + * translated version, broken down into its individual components, + * as explained with the `br_suite_translated` type. + * + * The returned array is allocated in the context and will be rewritten + * by each handshake. + * + * \param cc server context. + * \param num receives the array size (number of suites). + * \return the translated common cipher suites, in preference order. */ static inline const br_suite_translated * br_ssl_server_get_client_suites(const br_ssl_server_context *cc, size_t *num) @@ -1569,10 +2458,15 @@ br_ssl_server_get_client_suites(const br_ssl_server_context *cc, size_t *num) return cc->client_suites; } -/* - * Get the hash functions supported by the client. This is a field of - * bits: for hash function of ID x, bit x is set if the hash function - * is supported in RSA signatures, 8+x if it is supported with ECDSA. +/** + * \brief Get the hash functions supported by the client. + * + * This is a field of bits: for hash function of ID x, bit x is set if + * the hash function is supported in RSA signatures, 8+x if it is supported + * with ECDSA. + * + * \param cc server context. + * \return the client-supported hash functions (for signatures). */ static inline uint16_t br_ssl_server_get_client_hashes(const br_ssl_server_context *cc) @@ -1580,9 +2474,13 @@ br_ssl_server_get_client_hashes(const br_ssl_server_context *cc) return cc->hashes; } -/* - * Get the elliptic curves supported by the client. This is a bit field - * (bit x is set if curve of ID x is supported). +/** + * \brief Get the elliptic curves supported by the client. + * + * This is a bit field (bit x is set if curve of ID x is supported). + * + * \param cc server context. + * \return the client-supported elliptic curves. */ static inline uint32_t br_ssl_server_get_client_curves(const br_ssl_server_context *cc) @@ -1590,15 +2488,26 @@ br_ssl_server_get_client_curves(const br_ssl_server_context *cc) return cc->curves; } -/* - * Clear the complete contents of a SSL server context, including the - * reference to the configured buffer, implementations, cipher suites - * and state. +/** + * \brief Clear the complete contents of a SSL server context. + * + * Everything is cleared, including the reference to the configured buffer, + * implementations, cipher suites and state. This is a preparatory step + * to assembling a custom profile. + * + * \param cc server context to clear. */ void br_ssl_server_zero(br_ssl_server_context *cc); -/* - * Set an externally provided policy context. +/** + * \brief Set an externally provided policy context. + * + * The policy context's methods are invoked to decide the cipher suite + * and certificate chain, and to perform operations involving the server's + * private key. + * + * \param cc server context. + * \param pctx policy context (pointer to its vtable field). */ static inline void br_ssl_server_set_policy(br_ssl_server_context *cc, @@ -1607,30 +2516,67 @@ br_ssl_server_set_policy(br_ssl_server_context *cc, cc->policy_vtable = pctx; } -/* - * Set the server certificate chain and key (single RSA case). - * The 'allowed_usages' is a combination of usages, namely - * BR_KEYTYPE_KEYX and/or BR_KEYTYPE_SIGN. +/** + * \brief Set the server certificate chain and key (single RSA case). + * + * This function uses a policy context included in the server context. + * It configures use of a single server certificate chain with a RSA + * private key. The `allowed_usages` is a combination of usages, namely + * `BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`; this enables or disables + * the corresponding cipher suites (i.e. `TLS_RSA_*` use the RSA key for + * key exchange, while `TLS_ECDHE_RSA_*` use the RSA key for signatures). + * + * \param cc server context. + * \param chain server certificate chain to send to the client. + * \param chain_len chain length (number of certificates). + * \param sk server private key (RSA). + * \param allowed_usages allowed private key usages. + * \param irsacore RSA core implementation. + * \param irsasign RSA signature implementation (PKCS#1 v1.5). */ void br_ssl_server_set_single_rsa(br_ssl_server_context *cc, - const br_x509_certificate *chain, size_t chain_length, + const br_x509_certificate *chain, size_t chain_len, const br_rsa_private_key *sk, unsigned allowed_usages, br_rsa_private irsacore, br_rsa_pkcs1_sign irsasign); /* - * Set the server certificate chain and key (single EC case). - * The 'allowed_usages' is a combination of usages, namely - * BR_KEYTYPE_KEYX and/or BR_KEYTYPE_SIGN. + * \brief Set the server certificate chain and key (single EC case). + * + * This function uses a policy context included in the server context. + * It configures use of a single server certificate chain with an EC + * private key. The `allowed_usages` is a combination of usages, namely + * `BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`; this enables or disables + * the corresponding cipher suites (i.e. `TLS_ECDH_*` use the EC key for + * key exchange, while `TLS_ECDHE_ECDSA_*` use the EC key for signatures). + * + * In order to support `TLS_ECDH_*` cipher suites (non-ephemeral ECDH), + * the algorithm type of the key used by the issuing CA to sign the + * server's certificate must be provided, as `cert_issuer_key_type` + * parameter (this value is either `BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`). + * + * \param cc server context. + * \param chain server certificate chain to send. + * \param chain_len chain length (number of certificates). + * \param sk server private key (EC). + * \param allowed_usages allowed private key usages. + * \param cert_issuer_key_type issuing CA's key type. + * \param iec EC core implementation. + * \param iecdsa ECDSA signature implementation ("asn1" format). */ void br_ssl_server_set_single_ec(br_ssl_server_context *cc, - const br_x509_certificate *chain, size_t chain_length, + const br_x509_certificate *chain, size_t chain_len, const br_ec_private_key *sk, unsigned allowed_usages, unsigned cert_issuer_key_type, const br_ec_impl *iec, br_ecdsa_sign iecdsa); -/* - * Configure the server context to use the provided cache for session - * parameters. +/** + * \brief Configure the cache for session parameters. + * + * The cache context is provided as a pointer to its first field (vtable + * pointer). + * + * \param cc server context. + * \param vtable session cache context. */ static inline void br_ssl_server_set_cache(br_ssl_server_context *cc, @@ -1639,8 +2585,11 @@ br_ssl_server_set_cache(br_ssl_server_context *cc, cc->cache_vtable = vtable; } -/* - * Prepare or reset a server context for handling an incoming client. +/** + * \brief Prepare or reset a server context for handling an incoming client. + * + * \param cc server context. + * \return 1 on success, 0 on error. */ int br_ssl_server_reset(br_ssl_server_context *cc); @@ -1672,7 +2621,14 @@ int br_ssl_server_reset(br_ssl_server_context *cc); * The SSL engine naturally applies some buffering, so the callbacks need * not apply buffers of their own. */ +/** + * \brief Context structure for the simplified SSL I/O wrapper. + * + * This structure is initialised with `br_sslio_init()`. Its contents + * are opaque and shall not be accessed directly. + */ typedef struct { +#ifndef BR_DOXYGEN_IGNORE br_ssl_engine_context *engine; int (*low_read)(void *read_context, unsigned char *data, size_t len); @@ -1680,11 +2636,55 @@ typedef struct { int (*low_write)(void *write_context, const unsigned char *data, size_t len); void *write_context; +#endif } br_sslio_context; -/* - * Initialise a simplified I/O context over the provided engine and - * I/O callbacks. +/** + * \brief Initialise a simplified I/O wrapper context. + * + * The simplified I/O wrapper offers a simpler read/write API for a SSL + * engine (client or server), using the provided callback functions for + * reading data from, or writing data to, the transport medium. + * + * The callback functions have the following semantics: + * + * - Each callback receives an opaque context value (of type `void *`) + * that the callback may use arbitrarily (or possibly ignore). + * + * - `low_read()` reads at least one byte, at most `len` bytes, from + * the transport medium. Read bytes shall be written in `data`. + * + * - `low_write()` writes at least one byte, at most `len` bytes, unto + * the transport medium. The bytes to write are read from `data`. + * + * - The `len` parameter is never zero, and is always lower than 20000. + * + * - The number of processed bytes (read or written) is returned. Since + * that number is less than 20000, it always fits on an `int`. + * + * - On error, the callbacks return -1. Reaching end-of-stream is an + * error. Errors are permanent: the SSL connection is terminated. + * + * - Callbacks SHOULD NOT return 0. This is tolerated, as long as + * callbacks endeavour to block for some non-negligible amount of + * time until at least one byte can be sent or received (if a + * callback returns 0, then the wrapper invokes it again + * immediately). + * + * - Callbacks MAY return as soon as at least one byte is processed; + * they MAY also insist on reading or writing _all_ requested bytes. + * Since SSL is a self-terminated protocol (each record has a length + * header), this does not change semantics. + * + * - Callbacks need not apply any buffering (for performance) since SSL + * itself uses buffers. + * + * \param ctx wrapper context to initialise. + * \param engine SSL engine to wrap. + * \param low_read callback for reading data from the transport. + * \param read_context context pointer for `low_read()`. + * \param low_write callback for writing data on the transport. + * \param write_context context pointer for `low_write()`. */ void br_sslio_init(br_sslio_context *ctx, br_ssl_engine_context *engine, @@ -1695,64 +2695,123 @@ void br_sslio_init(br_sslio_context *ctx, const unsigned char *data, size_t len), void *write_context); -/* - * Read some application data from a SSL connection. This call returns - * only when at least one byte has been obtained. Returned value is - * the number of bytes read, or -1 on error. The number of bytes - * always fits on an 'int' (data from a single SSL/TLS record is - * returned). +/** + * \brief Read some application data from a SSL connection. + * + * If `len` is zero, then this function returns 0 immediately. In + * all other cases, it never returns 0. + * + * This call returns only when at least one byte has been obtained. + * Returned value is the number of bytes read, or -1 on error. The + * number of bytes always fits on an 'int' (data from a single SSL/TLS + * record is returned). * * On error or SSL closure, this function returns -1. The caller should * inspect the error status on the SSL engine to distinguish between * normal closure and error. + * + * \param cc SSL wrapper context. + * \param dst destination buffer for application data. + * \param len maximum number of bytes to obtain. + * \return number of bytes obtained, or -1 on error. */ int br_sslio_read(br_sslio_context *cc, void *dst, size_t len); -/* - * Read some application data from a SSL connection. This call returns - * only when ALL requested bytes have been read. Returned value is 0 - * on success, -1 on error. A normal SSL closure before that many bytes - * are obtained is reported as an error by this function. +/** + * \brief Read application data from a SSL connection. + * + * This calls returns only when _all_ requested `len` bytes are read, + * or an error is reached. Returned value is 0 on success, -1 on error. + * A normal (verified) SSL closure before that many bytes are obtained + * is reported as an error by this function. + * + * \param cc SSL wrapper context. + * \param dst destination buffer for application data. + * \param len number of bytes to obtain. + * \return 0 on success, or -1 on error. */ int br_sslio_read_all(br_sslio_context *cc, void *dst, size_t len); -/* - * Write some application data onto a SSL connection. This call returns - * only when at least one byte had been written onto the connection (but - * not necessarily flushed). Returned value is the number of written - * bytes, or -1 on error (error conditions include a closed connection). - * It is guaranteed that the number of bytes written by such a call will - * fit in an 'int' on all architectures. +/** + * \brief Write some application data unto a SSL connection. + * + * If `len` is zero, then this function returns 0 immediately. In + * all other cases, it never returns 0. + * + * This call returns only when at least one byte has been written. + * Returned value is the number of bytes written, or -1 on error. The + * number of bytes always fits on an 'int' (less than 20000). + * + * On error or SSL closure, this function returns -1. The caller should + * inspect the error status on the SSL engine to distinguish between + * normal closure and error. + * + * **Important:** SSL is buffered; a "written" byte is a byte that was + * injected into the wrapped SSL engine, but this does not necessarily mean + * that it has been scheduled for sending. Use `br_sslio_flush()` to + * ensure that all pending data has been sent to the transport medium. * - * Note that some written bytes may be buffered; use br_sslio_flush() - * to make sure that the data is sent to the transport stream. + * \param cc SSL wrapper context. + * \param src source buffer for application data. + * \param len maximum number of bytes to write. + * \return number of bytes written, or -1 on error. */ int br_sslio_write(br_sslio_context *cc, const void *src, size_t len); -/* - * Write some application data onto a SSL connection. This call returns - * only when ALL the bytes have been written onto the connection (but - * not necessarily flushed). Returned value is 0 on success, -1 on error. - * - * Note that some written bytes may be buffered; use br_sslio_flush() - * to make sure that the data is sent to the transport stream. +/** + * \brief Write application data unto a SSL connection. + * + * This calls returns only when _all_ requested `len` bytes have been + * written, or an error is reached. Returned value is 0 on success, -1 + * on error. A normal (verified) SSL closure before that many bytes are + * written is reported as an error by this function. + * + * **Important:** SSL is buffered; a "written" byte is a byte that was + * injected into the wrapped SSL engine, but this does not necessarily mean + * that it has been scheduled for sending. Use `br_sslio_flush()` to + * ensure that all pending data has been sent to the transport medium. + * + * \param cc SSL wrapper context. + * \param src source buffer for application data. + * \param len number of bytes to write. + * \return 0 on success, or -1 on error. */ int br_sslio_write_all(br_sslio_context *cc, const void *src, size_t len); -/* - * Make sure that any buffered application data in the provided context - * get packed up and sent unto the low_write() callback method. If that - * callback method represents a buffered system, it is up to the caller - * to then "flush" that system too. +/** + * \brief Flush pending data. + * + * This call makes sure that any buffered application data in the + * provided context (including the wrapped SSL engine) has been sent + * to the transport medium (i.e. accepted by the `low_write()` callback + * method). If there is no such pending data, then this function does + * nothing (and returns a success, i.e. 0). + * + * If the underlying transport medium has its own buffers, then it is + * up to the caller to ensure the corresponding flushing. * * Returned value is 0 on success, -1 on error. + * + * \param cc SSL wrapper context. + * \return 0 on success, or -1 on error. */ int br_sslio_flush(br_sslio_context *cc); -/* - * Perform a SSL close. This implies sending a close_notify, and reading - * the response from the server. Returned value is 0 on success, -1 on - * error. +/** + * \brief Close the SSL connection. + * + * This call runs the SSL closure protocol (sending a `close_notify`, + * receiving the response `close_notify`). When it returns, the SSL + * connection is finished. It is still up to the caller to manage the + * possible transport-level termination, if applicable (alternatively, + * the underlying transport stream may be reused for non-SSL messages). + * + * Returned value is 0 on success, -1 on error. A failure by the peer + * to process the complete closure protocol (i.e. sending back the + * `close_notify`) is an error. + * + * \param cc SSL wrapper context. + * \return 0 on success, or -1 on error. */ int br_sslio_close(br_sslio_context *cc); @@ -1869,6 +2928,9 @@ int br_sslio_close(br_sslio_context *cc); #define BR_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAD #define BR_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAE +/* From RFC 7507 */ +#define BR_TLS_FALLBACK_SCSV 0x5600 + /* * Symbolic constants for alerts. */ diff --git a/src/ssl/ssl_io.c b/src/ssl/ssl_io.c index b409636..1952615 100644 --- a/src/ssl/ssl_io.c +++ b/src/ssl/ssl_io.c @@ -149,6 +149,9 @@ br_sslio_read(br_sslio_context *ctx, void *dst, size_t len) unsigned char *buf; size_t alen; + if (len == 0) { + return 0; + } if (run_until(ctx, BR_SSL_RECVAPP) < 0) { return -1; } @@ -188,6 +191,9 @@ br_sslio_write(br_sslio_context *ctx, const void *src, size_t len) unsigned char *buf; size_t alen; + if (len == 0) { + return 0; + } if (run_until(ctx, BR_SSL_SENDAPP) < 0) { return -1; } diff --git a/tools/server.c b/tools/server.c index ea247ab..b81ce07 100644 --- a/tools/server.c +++ b/tools/server.c @@ -334,7 +334,9 @@ sp_choose(const br_ssl_server_policy_class **pctx, case BR_SSLKEYX_ECDHE_RSA: if (pc->sk->key_type == BR_KEYTYPE_RSA) { choices->cipher_suite = st[u][0]; - if (cc->eng.session.version < BR_TLS12) { + if (br_ssl_engine_get_version(&cc->eng) + < BR_TLS12) + { hash_id = 0; } choices->hash_id = hash_id; @@ -344,7 +346,9 @@ sp_choose(const br_ssl_server_policy_class **pctx, case BR_SSLKEYX_ECDHE_ECDSA: if (pc->sk->key_type == BR_KEYTYPE_EC) { choices->cipher_suite = st[u][0]; - if (cc->eng.session.version < BR_TLS12) { + if (br_ssl_engine_get_version(&cc->eng) + < BR_TLS12) + { hash_id = br_sha1_ID; } choices->hash_id = hash_id; @@ -507,7 +511,7 @@ sp_do_sign(const br_ssl_server_policy_class **pctx, hc = get_hash_impl(hash_id); if (hc == NULL) { if (pc->verbose) { - fprintf(stderr, "ERROR: cannot RSA-sign with" + fprintf(stderr, "ERROR: cannot ECDSA-sign with" " unknown hash function: %d\n", hash_id); }