From 3cbf34f214d0bf7f48719362fc78bd5e21a73c8a Mon Sep 17 00:00:00 2001 From: Appelmans Date: Tue, 21 Nov 2023 12:20:02 -0800 Subject: [PATCH 1/7] Reordered Usage Guide --- docs/BUILD.md | 16 +- docs/USAGE-GUIDE.md | 1047 --------------------- docs/usage-guide/book.toml | 5 + docs/usage-guide/src/SUMMARY.md | 17 + docs/usage-guide/src/api.md | 32 + docs/usage-guide/src/certificates.md | 103 ++ docs/usage-guide/src/client_hello.md | 40 + docs/usage-guide/src/config.md | 14 + docs/usage-guide/src/connection.md | 26 + docs/usage-guide/src/early_data.md | 131 +++ docs/usage-guide/src/error_handling.md | 77 ++ docs/usage-guide/src/initialization.md | 8 + docs/usage-guide/src/introduction.md | 2 + docs/usage-guide/src/io.md | 229 +++++ docs/usage-guide/src/preshared_keys.md | 59 ++ docs/usage-guide/src/private_key_ops.md | 77 ++ docs/usage-guide/src/record_sizes.md | 50 + docs/usage-guide/src/resumption.md | 46 + docs/usage-guide/src/security_policies.md | 115 +++ 19 files changed, 1046 insertions(+), 1048 deletions(-) delete mode 100644 docs/USAGE-GUIDE.md create mode 100644 docs/usage-guide/book.toml create mode 100644 docs/usage-guide/src/SUMMARY.md create mode 100644 docs/usage-guide/src/api.md create mode 100644 docs/usage-guide/src/certificates.md create mode 100644 docs/usage-guide/src/client_hello.md create mode 100644 docs/usage-guide/src/config.md create mode 100644 docs/usage-guide/src/connection.md create mode 100644 docs/usage-guide/src/early_data.md create mode 100644 docs/usage-guide/src/error_handling.md create mode 100644 docs/usage-guide/src/initialization.md create mode 100644 docs/usage-guide/src/introduction.md create mode 100644 docs/usage-guide/src/io.md create mode 100644 docs/usage-guide/src/preshared_keys.md create mode 100644 docs/usage-guide/src/private_key_ops.md create mode 100644 docs/usage-guide/src/record_sizes.md create mode 100644 docs/usage-guide/src/resumption.md create mode 100644 docs/usage-guide/src/security_policies.md diff --git a/docs/BUILD.md b/docs/BUILD.md index a522251991a..bb9ee69bace 100644 --- a/docs/BUILD.md +++ b/docs/BUILD.md @@ -68,7 +68,21 @@ cmake --install build Note that we currently do not support building on Windows. See https://github.com/aws/s2n-tls/issues/497 for more information. -See the [s2n-tls usage guide](USAGE-GUIDE.md#consuming-s2n-tls-via-cmake) for instructions on how to include s2n-tls in your CMake project. +## Consuming s2n-tls via. CMake + +s2n-tls ships with modern CMake finder scripts if CMake is used for the build. To take advantage of this from your CMake script, all you need to do to compile and link against s2n-tls in your project is: + +````bash +find_package(s2n) + +.... + +target_link_libraries(yourExecutableOrLibrary AWS::s2n) +```` + +And when invoking CMake for your project, do one of two things: + 1. Set the `CMAKE_INSTALL_PREFIX` variable with the path to your s2n-tls build. + 2. If you have globally installed s2n-tls, do nothing, it will automatically be found. ## Configuring the s2n-tls build diff --git a/docs/USAGE-GUIDE.md b/docs/USAGE-GUIDE.md deleted file mode 100644 index 377b132bd90..00000000000 --- a/docs/USAGE-GUIDE.md +++ /dev/null @@ -1,1047 +0,0 @@ -# Using s2n-tls - -## Building s2n-tls - -See the [s2n-tls build documentation](BUILD.md) for guidance on building s2n-tls for your platform. - -## Consuming s2n-tls via. CMake - -s2n-tls ships with modern CMake finder scripts if CMake is used for the build. To take advantage of this from your CMake script, all you need to do to compile and link against s2n-tls in your project is: - -````bash -find_package(s2n) - -.... - -target_link_libraries(yourExecutableOrLibrary AWS::s2n) -```` - -And when invoking CMake for your project, do one of two things: - 1. Set the `CMAKE_INSTALL_PREFIX` variable with the path to your s2n-tls build. - 2. If you have globally installed s2n-tls, do nothing, it will automatically be found. - -# s2n-tls API - -The API exposed by s2n-tls is the set of functions and declarations that -are in the [s2n.h](../api/s2n.h) header file. Any functions and declarations that are in the [s2n.h](../api/s2n.h) file -are intended to be stable (API and ABI) within major version numbers of s2n-tls releases. Other functions -and structures used in s2n-tls internally can not be considered stable and their parameters, names, and -sizes may change. - -The [VERSIONING.rst](../VERSIONING.rst) document contains more details about s2n's approach to versions and API changes. - -## API Reference - -s2n-tls uses [Doxygen](https://doxygen.nl/index.html) to document its public API. The latest s2n-tls documentation can be found on [GitHub pages](https://aws.github.io/s2n-tls/doxygen/). - -Documentation for older versions or branches of s2n-tls can be generated locally. To generate the documentation, install doxygen and run `doxygen docs/doxygen/Doxyfile`. The doxygen documentation can now be found at `docs/doxygen/output/html/index.html`. - -Doxygen installation instructions are available at the [Doxygen](https://doxygen.nl/download.html) webpage. - -The doxygen documentation should be used in conjunction with this guide. - -## Supported TLS Versions - -Currently TLS 1.2 is our default version, but we recommend TLS 1.3 where possible. To use TLS 1.3 you need a security policy that supports TLS 1.3. See the [Security Policies](#security-policies) section for more information. - -**Note:** s2n-tls does not support SSL2.0 for sending and receiving encrypted data, but does accept SSL2.0 hello messages. - -## Error handling - -s2n-tls functions that return 'int' return 0 to indicate success and -1 to indicate -failure. s2n-tls functions that return pointer types return NULL in the case of -failure. When an s2n-tls function returns a failure, s2n_errno will be set to a value -corresponding to the error. This error value can be translated into a string -explaining the error in English by calling `s2n_strerror(s2n_errno, "EN")`. -A string containing human readable error name, can be generated with `s2n_strerror_name`. -A string containing internal debug information, including filename and line number, can be generated with `s2n_strerror_debug`. -This string is useful to include when reporting issues to the s2n-tls development team. - -Example: - -``` -if (s2n_config_set_cipher_preferences(config, prefs) < 0) { - printf("Setting cipher prefs failed! %s : %s", s2n_strerror(s2n_errno, "EN"), s2n_strerror_debug(s2n_errno, "EN")); - return -1; -} -``` - -**NOTE**: To avoid possible confusion, s2n_errno should be cleared after processing an error: `s2n_errno = S2N_ERR_T_OK` - -When using s2n-tls outside of `C`, the address of the thread-local `s2n_errno` may be obtained by calling the `s2n_errno_location` function. -This will ensure that the same TLS mechanisms are used with which s2n-tls was compiled. - -### Error Types - -s2n-tls organizes errors into different "types" to allow applications to handle error values without catching all possibilities. -Applications using non-blocking I/O should check the error type to determine if the I/O operation failed because it would block or for some other error. To retrieve the type for a given error use `s2n_error_get_type()`. -Applications should perform any error handling logic using these high level types: - -Here's an example that handles errors based on type: - -```c -#define SUCCESS 0 -#define FAILURE 1 -#define RETRY 2 - -s2n_errno = S2N_ERR_T_OK; -if (s2n_negotiate(conn, &blocked) < 0) { - switch(s2n_error_get_type(s2n_errno)) { - case S2N_ERR_T_BLOCKED: - /* Blocked, come back later */ - return RETRY; - case S2N_ERR_T_CLOSED: - return SUCCESS; - case S2N_ERR_T_IO: - handle_io_err(errno); - return FAILURE; - case S2N_ERR_T_PROTO: - handle_proto_err(); - return FAILURE; - case S2N_ERR_T_ALERT: - log_alert(s2n_connection_get_alert(conn)); - return FAILURE; - /* Everything else */ - default: - log_other_error(); - return FAILURE; - } -} -``` - -### Blinding - -Blinding is a mitigation against timing side-channels which in some cases can leak information about encrypted data. By default s2n-tls will cause a thread to sleep between 10 and 30 seconds whenever tampering is detected. - -Setting the `S2N_SELF_SERVICE_BLINDING` option with `s2n_connection_set_blinding()` turns off this behavior. This is useful for applications that are handling many connections in a single thread. In that case, if `s2n_recv()` or `s2n_negotiate()` return an error, self-service applications must call `s2n_connection_get_delay()` and pause activity on the connection for the specified number of nanoseconds before calling `close()` or `shutdown()`. `s2n_shutdown()` will fail if called before the blinding delay elapses. - -### Stacktraces -s2n-tls has an mechanism to capture stacktraces when errors occur. -This mechanism is off by default, but can be enabled in code by calling `s2n_stack_traces_enabled_set()`. -It can be enabled globally by setting the environment variable `S2N_PRINT_STACKTRACE=1`. - -Call `s2n_print_stacktrace()` to print your stacktrace. - -**Note:** Enabling stacktraces can significantly slow down unit tests, causing failures on tests (such as `s2n_cbc_verify`) that measure the timing of events. - - -## Initialization and Teardown - -The s2n-tls library must be initialized with `s2n_init()` before calling most library functions. `s2n_init()` MUST NOT be called more than once, even when an application uses multiple threads or processes. s2n attempts to clean up its thread-local memory at thread-exit and all other memory at process-exit. However, this may not work if you are using a thread library other than pthreads. In that case you should call `s2n_cleanup()` from every thread or process created after `s2n_init()`. - -Initialization can be modified by calling `s2n_crypto_disable_init()` or `s2n_disable_atexit()` before `s2n_init()`. - -An application can override s2n-tls’s internal memory management by calling `s2n_mem_set_callbacks` before calling s2n_init. - -If you are trying to use FIPS mode, you must enable FIPS in your libcrypto library (probably by calling `FIPS_mode_set(1)`) before calling `s2n_init()`. - -## Connection - -Users will need to create a `s2n_connection` struct to store all of the state necessary for a TLS connection. Call `s2n_connection_new()` to create a new server or client connection. Call `s2n_connection_free()` to free the memory allocated for this struct when no longer needed. - -### Connection Memory - -The connection struct is roughly 4KB with some variation depending on how it is configured. Maintainers of the s2n-tls library carefully consider increases to the size of the connection struct as they are aware some users are memory-constrained. - -A connection struct has memory allocated specifically for the TLS handshake. Memory-constrained users can free that memory by calling `s2n_connection_free_handshake()` after the handshake is successfully negotiated. Note that the handshake memory can be reused for another connection if `s2n_connection_wipe()` is called, so freeing it may result in more memory allocations later. Additionally some functions that print information about the handshake may not produce meaningful results after the handshake memory is freed. - -The input and output buffers consume the most memory on the connection after the handshake. It may not be necessary to keep these buffers allocated when a connection is in a keep-alive or idle state. Call `s2n_connection_release_buffers()` to wipe and free the `in` and `out` buffers associated with a connection to reduce memory overhead of long-lived connections. - -### Connection Reuse - -Connection objects can be re-used across many connections to reduce memory allocation. Calling `s2n_connection_wipe()` will wipe an individual connection's state and allow the connection object to be re-used for a new TLS connection. - -### Connection Info - -s2n-tls provides many methods to retrieve details about the handshake and connection, such as the parameters negotiated with the peer. For a full list, see our [doxygen guide](https://aws.github.io/s2n-tls/doxygen/). - -#### Protocol Version - -s2n-tls provides multiple different methods to get the TLS protocol version of the connection. They should be called after the handshake has completed. -* `s2n_connection_get_actual_protocol_version()`: The actual TLS protocol version negotiated during the handshake. This is the primary value referred to as "protocol_version", and the most commonly used. -* `s2n_connection_get_server_protocol_version()`: The highest TLS protocol version the server supports. -* `s2n_connection_get_client_protocol_version()`: The highest TLS protocol version the client advertised. - -## Config - -`s2n_config` objects are used to change the default settings of a s2n-tls connection. Use `s2n_config_new()` to create a new config object. To associate a config with a connection call `s2n_connection_set_config()`. A config should not be altered once it is associated with a connection as this will produce undefined behavior. It is not necessary to create a config object per connection; one config object should be used for many connections. Call `s2n_config_free()` to free the object when no longer needed. _Only_ free the config object when all connections using it have been freed. - -Calling `s2n_config_new()` can have a performance cost during config creation due to loading -default system certificates into the trust store (see [Configuring the Trust Store](#configuring-the-trust-store)). -For increased performance, use `s2n_config_new_minimal()` when system certificates are not needed -for certificate validation. - -Most commonly, a `s2n_config` object is used to set the certificate key pair for authentication and change the default security policy. See the sections for [certificates](#certificates-and-authentication) and [security policies](#security-policies) for more information on those settings. - -### Overriding the Config - -Some `s2n_config` settings can be overridden on a specific connection if desired. For example, `s2n_config_append_protocol_preference()` appends a list of ALPN protocols to a `s2n_config`. Calling the `s2n_connection_append_protocol_preference()` API will override the list of ALPN protocols for an individual connection. Not all config APIs have a corresponding connection API so if there is one missing contact us with an explanation on why it is required for your use-case. - -## Security Policies - -s2n-tls uses pre-made security policies to help avoid common misconfiguration mistakes for TLS. - -`s2n_config_set_cipher_preferences()` sets a security policy, which includes the cipher/kem/signature/ecc preferences and protocol version. - -### Chart: Security Policy Version To Protocol Version And Ciphersuites - -The following chart maps the security policy version to protocol version and ciphersuites supported. - -| version | TLS1.0 | TLS1.1 | TLS1.2 | TLS1.3 | AES-CBC | AES-GCM | CHACHAPOLY | 3DES | RC4 | DHE | ECDHE | RSA kx | -|---------------|--------|--------|--------|--------|---------|---------|------------|------|-----|-----|-------|--------| -| 20230317 | | | X | X | X | X | | | | | X | | -| default | X | X | X | | X | X | X | | | | X | X | -| default_tls13 | X | X | X | X | X | X | X | | | | X | X | -| default_fips | | | X | | X | X | | | | X | X | | -| 20190214 | X | X | X | | X | X | | X | | X | X | X | -| 20170718 | X | X | X | | X | X | | | | | X | X | -| 20170405 | X | X | X | | X | X | | X | | | X | X | -| 20170328 | X | X | X | | X | X | | X | | X | X | X | -| 20170210 | X | X | X | | X | X | X | | | | X | X | -| 20160824 | X | X | X | | X | X | | | | | X | X | -| 20160804 | X | X | X | | X | X | | X | | | X | X | -| 20160411 | X | X | X | | X | X | | X | | | X | X | -| 20150306 | X | X | X | | X | X | | X | | | X | X | -| 20150214 | X | X | X | | X | X | | X | | X | | X | -| 20150202 | X | X | X | | X | | | X | | X | | X | -| 20141001 | X | X | X | | X | | | X | X | X | | X | -| 20190120 | X | X | X | | X | X | X | X | | | X | X | -| 20190121 | X | X | X | | X | X | X | X | | | X | X | -| 20190122 | X | X | X | | X | X | X | X | | | X | X | -| 20190801 | X | X | X | X | X | X | X | | | | X | X | -| 20190802 | X | X | X | X | X | X | X | | | | X | X | -| 20200207 | | | | X | | X | X | | | | X | | -| rfc9151 | | | X | X | | X | | | | X | X | X | - -The "default", "default_tls13", and "default_fips" versions are special in that they will be updated with future s2n-tls changes and ciphersuites and protocol versions may be added and removed, or their internal order of preference might change. Numbered versions are fixed and will never change. -In general, customers prefer to use numbered versions for production use cases to prevent impact from library updates. - -"20230317" is a FIPS compliant policy. It offers more limited but more secure options than "default". It only supports TLS1.2 and TLS1.3. Consider this policy if you plan to enable FIPS mode or don't need or want to support less secure legacy options like TLS1.1 or SHA1. - -"20160411" follows the same general preference order as "default". The main difference is it has a CBC cipher suite at the top. This is to accommodate certain Java clients that have poor GCM implementations. Users of s2n-tls who have found GCM to be hurting performance for their clients should consider this version. - -"rfc9151" is derived from [Commercial National Security Algorithm (CNSA) Suite Profile for TLS and DTLS 1.2 and 1.3](https://datatracker.ietf.org/doc/html/rfc9151). This policy restricts the algorithms allowed for signatures on certificates in the certificate chain to RSA or ECDSA with sha384, which may require you to update your certificates. - -s2n-tls does not expose an API to control the order of preference for each ciphersuite or protocol version. s2n-tls follows the following order: - -*NOTE*: All ChaCha20-Poly1305 cipher suites will not be available if s2n-tls is not built with an Openssl 1.1.1 libcrypto. The underlying encrypt/decrypt functions are not available in older versions. - -1. Always prefer the highest protocol version supported -2. Always use forward secrecy where possible. Prefer ECDHE over DHE. -3. Prefer encryption ciphers in the following order: AES128, AES256, ChaCha20, 3DES, RC4. -4. Prefer record authentication modes in the following order: GCM, Poly1305, SHA256, SHA1, MD5. - -#### ChaCha20 Boosting - -s2n-tls usually prefers AES over ChaCha20. However, some clients-- particularly mobile or IOT devices-- do not support AES hardware acceleration, making AES less efficient and performant than ChaCha20. In this case, clients will indicate their preference for ChaCha20 by listing it first during cipher suite negotiation. Usually s2n-tls servers ignore client preferences, but s2n-tls offers "ChaCha20 boosted" security policies that will choose ChaCha20 over AES if the client indicates a preference for ChaCha20. This is available in the "CloudFront-TLS-1-2-2021-ChaCha20-Boosted" policy, which is identical to the "CloudFront-TLS-1-2-2021" policy listed above but with ChaCha20 Boosting enabled. - -### Chart: Security Policy Version To Supported Signature Schemes - -| version | RSA PKCS1 | ECDSA | SHA-1 Legacy | RSA PSS | -|---------------|-----------|-------|--------------|---------| -| 20230317 | X | X | | X | -| default | X | | X | | -| default_tls13 | X | X | X | X | -| default_fips | X | X | | | -| 20190214 | X | X | X | | -| 20170718 | X | | X | | -| 20170405 | X | | X | | -| 20170328 | X | | X | | -| 20170210 | X | | X | | -| 20160824 | X | | X | | -| 20160804 | X | | X | | -| 20160411 | X | | X | | -| 20150306 | X | | X | | -| 20150214 | X | | X | | -| 20150202 | X | | X | | -| 20141001 | X | | X | | -| 20190120 | X | | X | | -| 20190121 | X | | X | | -| 20190122 | X | | X | | -| 20190801 | X | X | X | X | -| 20190802 | X | X | X | X | -| 20200207 | | X | | X | -| rfc9151 | X | X | | X | - -Note that legacy SHA-1 algorithms are not supported in TLS1.3. Legacy SHA-1 algorithms will be supported only if TLS1.2 has been negotiated and the security policy allows them. - -### Chart: Security policy version to supported curves/groups - -| version | secp256r1 | secp384r1 | x25519 | -|---------------|-----------|-----------|--------| -| 20230317 | X | X | | -| default | X | X | | -| default_tls13 | X | X | X | -| default_fips | X | X | | -| 20190214 | X | X | | -| 20170718 | X | X | | -| 20170405 | X | X | | -| 20170328 | X | X | | -| 20170210 | X | X | | -| 20160824 | X | X | | -| 20160804 | X | X | | -| 20160411 | X | X | | -| 20150306 | X | X | | -| 20150214 | | | | -| 20150202 | | | | -| 20141001 | | | | -| 20190120 | X | X | | -| 20190121 | X | X | | -| 20190122 | X | X | | -| 20190801 | X | X | X | -| 20190802 | X | X | | -| 20200207 | X | X | X | -| rfc9151 | | X | | - -## Sending and Receiving - -### Basic IO setup - -By default, s2n-tls sends and receives data using a provided file descriptor -(usually a socket) and the read/write system calls. The file descriptor can be set with -`s2n_connection_set_fd()`, or separate read and write file descriptors can be -set with `s2n_connection_set_read_fd()` and `s2n_connection_set_write_fd()`. -The provided file descriptor should be active and connected. - -In general the application is free to configure the file descriptor as preferred, -including socket options. s2n-tls itself sets a few socket options: -* If available, TCP_QUICKACK is used during the TLS handshake -* If available and enabled via `s2n_connection_use_corked_io()`, TCP_CORK is -used during the TLS handshake. TCP_NOPUSH or TCP_NODELAY may be used if TCP_CORK -is not available. - -**Important Note:** -If the read end of the pipe is closed unexpectedly, writing to the pipe will raise -a SIGPIPE signal. **s2n-tls does NOT handle SIGPIPE.** A SIGPIPE signal will cause -the process to terminate unless it is handled or ignored by the application. -See the [signal man page](https://linux.die.net/man/2/signal) for instructions on -how to handle C signals, or simply ignore the SIGPIPE signal by calling -`signal(SIGPIPE, SIG_IGN)` before calling any s2n-tls IO methods. - -### Blocking or Non-Blocking? - -s2n-tls supports both blocking and non-blocking I/O. -* In blocking mode, each s2n-tls I/O function will not return until it has completed -the requested IO operation. -* In non-blocking mode, s2n-tls I/O functions will immediately return, even if the socket couldn't -send or receive all the requested data. In this case, the I/O function will return `S2N_FAILURE`, -and `s2n_error_get_type()` will return `S2N_ERR_T_BLOCKED`. The I/O operation will have to be -called again in order to send or receive the remaining requested data. - -Some s2n-tls I/O functions take a `blocked` argument. If an I/O function returns an -`S2N_ERR_T_BLOCKED` error, the `blocked` argument will be set to a `s2n_blocked_status` value, -indicating what s2n-tls is currently blocked on. Note that unless an I/O function returns -`S2N_FAILURE` with an `S2N_ERR_T_BLOCKED` error, the `blocked` argument is meaningless, and should -not be used in any application logic. - -Servers in particular usually prefer non-blocking mode. In blocking mode, a single connection -blocks the thread while waiting for more IO. In non-blocking mode, multiple connections -can make progress by returning control while waiting for more IO using methods like -[`poll`](https://linux.die.net/man/2/poll) or [`select`](https://linux.die.net/man/2/select). - -To use s2n-tls in non-blocking mode, set the underlying file descriptors as non-blocking. -For example: -```c -int flags = fcntl(fd, F_GETFL, 0); -if (flags < 0) return S2N_FAILURE; -if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) return S2N_FAILURE; -``` - -### Errors and Alerts - -If the peer sends an alert, the next call to a read IO method will report **S2N_FAILURE** and -`s2n_error_get_type()` will return **S2N_ERR_T_ALERT**. The specific alert received -is available by calling `s2n_connection_get_alert()`. - -In TLS1.3, all alerts are fatal. s2n-tls also treats all alerts as fatal in earlier -versions of TLS by default. `s2n_config_set_alert_behavior()` can be called to -force s2n-tls to treat pre-TLS1.3 warning alerts as not fatal, but that behavior -is not recommended unless required for compatibility. In the past, attacks against -TLS have involved manipulating the alert level to disguise fatal alerts as warnings. - -If s2n-tls encounters a fatal error, the next call to a write IO method will send -a close_notify alert to the peer. Except for a few exceptions, s2n-tls does not -send specific alerts in order to avoid leaking information that could be used for -a sidechannel attack. To ensure that the alert is sent, `s2n_shutdown()` should -be called after an error. - -### Performing the TLS Handshake - -Before application data can be sent or received, an application must perform a handshake -to establish a TLS connection with the peer. - -To perform the handshake, call `s2n_negotiate()` until it either returns **S2N_SUCCESS** -or returns **S2N_FAILURE** without a **S2N_ERR_T_BLOCKED** error. - -For an example of how to perform a basic handshake, see [examples/s2n_negotiate.c](https://github.com/aws/s2n-tls/blob/main/docs/examples/s2n_negotiate.c) - -### Application Data - -After the TLS handshake, an application can send and receive encrypted data. - -Although most s2n-tls APIs are not thread-safe, `s2n_send()` and `s2n_recv()` -may be called simultaneously from two different threads. This means that an -application may have one thread calling `s2n_send()` and one thread calling `s2n_recv()`, -but NOT multiple threads calling `s2n_recv()` or multiple threads calling `s2n_send()`. - -Even if an application only intends to send data or only intends to receive data, -it should implement both send and receive in order to handle alerts and post-handshake -TLS control messages like session tickets. - -#### Sending Application Data - -`s2n_send()` and its variants encrypt and send application data to the peer. -The sending methods return the number of bytes written and may indicate a partial -write. Partial writes are possible not just for non-blocking I/O, but also for -connections aborted while active. - -A single call to `s2n_send()` may involve multiple system calls to write the -provided application data. s2n-tls breaks the application data into fixed-sized -records before encryption, and calls write for each record. -[See the record size documentation for how record size may impact performance](https://github.com/aws/s2n-tls/blob/main/docs/USAGE-GUIDE.md#record-sizes). - -In non-blocking mode, `s2n_send()` will send data from the provided buffer and return the number of -bytes sent, as long as the socket was able to send at least 1 byte. If no bytes could be sent on the -socket, `s2n_send()` will return `S2N_FAILURE`, and `s2n_error_get_type()` will return -`S2N_ERR_T_BLOCKED`. To ensure that all the provided data gets sent, applications should continue -calling `s2n_send()` until the return values across all calls have added up to the length of the -data, or until `s2n_send()` returns an `S2N_ERR_T_BLOCKED` error. After an `S2N_ERR_T_BLOCKED` -error is returned, applications should call `s2n_send()` again only after the socket is -able to send more data. This can be determined by using methods like -[`poll`](https://linux.die.net/man/2/poll) or [`select`](https://linux.die.net/man/2/select). - -Unlike OpenSSL, repeated calls to `s2n_send()` should not duplicate the original -parameters, but should update the inputs per the indication of size written. - -`s2n_sendv_with_offset()` behaves like `s2n_send()`, but supports vectorized buffers. -The offset input should be updated between calls to reflect the data already written. - -`s2n_sendv()` also supports vectorized buffers, but assumes an offset of 0. -Because of this assumption, a caller would have to make sure that the input vectors -are updated to account for a partial write. Therefore `s2n_sendv_with_offset()` -is preferred. - -For examples of how to send `data` of length `data_size` with `s2n_send()` -or `s2n_sendv_with_offset()`, see [examples/s2n_send.c](https://github.com/aws/s2n-tls/blob/main/docs/examples/s2n_send.c) - -#### Receiving Application Data - -`s2n_recv()` reads and decrypts application data from the peer, copying it into -the application-provided output buffer. It returns the number of bytes read, and -may indicate a partial read even if blocking IO is used. -It returns "0" to indicate that the peer has shutdown the connection. - -By default, `s2n_recv()` will return after reading a single TLS record. `s2n_recv()` can be called -repeatedly to read multiple records. To allow `s2n_recv()` to read multiple records with a single -call, use `s2n_config_set_recv_multi_record()`. - -In non-blocking mode, `s2n_recv()` will read data into the provided buffer and return the number of -bytes read, as long as at least 1 byte was read from the socket. If no bytes could be read from the -socket, `s2n_recv()` will return `S2N_FAILURE`, and `s2n_error_get_type()` will return -`S2N_ERR_T_BLOCKED`. To ensure that all data on the socket is properly received, applications -should continue calling `s2n_recv()` until it returns an `S2N_ERR_T_BLOCKED` error. After an -`S2N_ERR_T_BLOCKED` error is returned, applications should call `s2n_recv()` again only after the -socket has received more data. This can be determined by using methods like -[`poll`](https://linux.die.net/man/2/poll) or [`select`](https://linux.die.net/man/2/select). - -Unlike OpenSSL, repeated calls to `s2n_recv()` should not duplicate the original parameters, -but should update the inputs per the indication of size read. - -For an example of how to read all the data sent by the peer into one buffer, -see `s2n_example_recv()` in [examples/s2n_recv.c](https://github.com/aws/s2n-tls/blob/main/docs/examples/s2n_recv.c) - -For an example of how to echo any data sent by the peer, -see `s2n_example_recv_echo()` in [examples/s2n_recv.c](https://github.com/aws/s2n-tls/blob/main/docs/examples/s2n_recv.c) - -`s2n_peek()` can be used to check if more application data may be returned -from `s2n_recv()` without performing another read from the file descriptor. -This is useful when using `select()` on the underlying s2n-tls file descriptor, because -a call to `s2n_recv()` may read more data into s2n-tls's internal buffer than -was requested or can fit into the application-provided output buffer. This extra -application data will be returned by the next call to `s2n_recv()`, but `select()` -will be unable to tell the application that there is more data available and that -`s2n_recv()` should be called again. An application can solve this problem by -calling `s2n_peek()` to determine if `s2n_recv()` needs to be called again. - -### Closing the Connection - -`s2n_shutdown()` attempts a graceful closure at the TLS layer. It does not close the -underlying transport. The call may block on either reading or writing. - -`s2n_shutdown()` should be called after an error in order to ensure that s2n-tls -sends an alert to notify the peer of the failure. - -`s2n_shutdown()` will discard any application data received from the peer. This -can lead to data truncation, so `s2n_shutdown_send()` may be preferred for TLS1.3 -connections where the peer continues sending after the application initiates -shutdown. See [Closing the connection for writes](#closing-the-connection-for-writes) -below. - -Because `s2n_shutdown()` attempts a graceful shutdown, it will not return success -unless a close_notify alert is successfully both sent and received. As a result, -`s2n_shutdown()` may fail when interacting with a non-conformant TLS implementation -or if called on a connection in a bad state. - -Once `s2n_shutdown()` is complete: -* The s2n_connection handle cannot be used for reading or writing. -* The underlying transport can be closed, most likely via `shutdown()` or `close()`. -* The s2n_connection handle can be freed via `s2n_connection_free()` or reused -via `s2n_connection_wipe()` - -#### Closing the connection for writes - -TLS1.3 supports closing the write side of a TLS connection while leaving the read -side unaffected. This indicates "end-of-data" to the peer without preventing -future reads. This feature is usually referred to as "half-close". - -s2n-tls offers the `s2n_shutdown_send()` method to close the write side of -a connection. Unlike `s2n_shutdown()`, it does not wait for the peer to respond -with a close_notify alert and does not discard any incoming application data. An -application can continue to call `s2n_recv()` after a call to `s2n_shutdown_send()`. - -`s2n_shutdown_send()` may still be called for earlier TLS versions, but most -TLS implementations will react by immediately discarding any pending writes and -closing the connection. - -If `s2n_shutdown_send()` is used, the application should still call `s2n_shutdown()` -or wait for `s2n_recv()` to return 0 to indicate end-of-data before cleaning up -the connection or closing the read side of the underlying transport. - -### Custom IO Callbacks - -By default, s2n-tls sends and receives data using a provided file descriptor -(usually a socket) and the read/write system calls. To change this default behavior, -an application can implement custom send and receive methods using `s2n_connection_set_recv_cb()` -and `s2n_connection_set_send_cb()`. -The application can pass inputs (such as a file descriptor or destination buffer) -to the custom IO methods by using `s2n_connection_set_recv_ctx()` and `s2n_connection_set_send_ctx()`. -s2n-tls will call the custom IO methods with the custom context instead of calling -the default implementation. - -The custom IO methods may send or receive less than the requested length. They -should return the number of bytes sent/received, or set errno and return an error code < 0. -s2n-tls will interpret errno set to EWOULDBLOCK or EAGAIN as indicating a retriable -blocking error, and set **s2n_errno** and the s2n_blocked_status appropriately. -s2n-tls will interpret a return value of 0 as a closed connection. - -## Certificates and Authentication - -TLS uses certificates to authenticate the server (and optionally the client). The handshake will fail if the client cannot verify the server’s certificate. - -Authentication is usually the most expensive part of the handshake. To avoid the cost, consider using [session resumption](#session-resumption) or [pre-shared keys](#tls13-pre-shared-key-related-calls). - -### Configuring the Trust Store - -To validate the peer’s certificate, a config's local “trust store” must contain a certificate -that can authenticate the peer’s certificate. To add certificates to the trust store, call -`s2n_config_set_verification_ca_location()` or `s2n_config_add_pem_to_trust_store()`. - -`s2n_config_new()` initializes the trust store with the default system certificates, which may -include public CAs or other unexpected certificates. If s2n-tls is verifying certificates and does -not require these default system certificates, they should be cleared with -`s2n_config_wipe_trust_store()` before calling `s2n_config_set_verification_ca_location()` or -`s2n_config_add_pem_to_trust_store()`. - -Note that the `s2n_verify_host_fn` callback must be implemented to validate the identity of all -received certificates. A client implementation is set by default. If the identity of the received -certificates are implicit (i.e. the certificates are self-signed, or signed by a privately owned -CA), the `s2n_verify_host_fn` callback need not perform any additional validation. However, -`s2n_config_wipe_trust_store()` should be called before adding certificates to the trust store in -this case, in order to avoid implicitly trusting the identity of peers that may present -certificates trusted via an unexpected default system certificate. - -Configs created with `s2n_config_new_minimal()` are initialized with empty trust stores. To add -default system certificates to these configs, call `s2n_config_load_system_certs()`. - -### Server Authentication - -A server must have a certificate and private key pair to prove its identity. s2n-tls supports RSA, RSA-PSS, and ECDSA certificates, and allows one of each type to be added to a config. - -Create a new certificate and key pair by calling `s2n_cert_chain_and_key_new()`, then load the pem-encoded data with `s2n_cert_chain_and_key_load_pem_bytes()`. Call `s2n_config_add_cert_chain_and_key_to_store()` to add the certificate and key pair to the config. When a certificate and key pair is no longer needed, it must be cleaned up with `s2n_cert_chain_and_key_free()`. - -A client can add restrictions on the certificate’s hostname by setting a custom `s2n_verify_host_fn` with `s2n_config_set_verify_host_callback()` or `s2n_connection_set_verify_host_callback()`. The default behavior is to require that the hostname match the server name set with `s2n_set_server_name()`. - -### Client / Mutual Authentication - -Client authentication is not enabled by default. However, the server can require that the client also provide a certificate, if the server needs to authenticate clients before accepting connections. - -Client authentication can be configured by calling `s2n_config_set_client_auth_type()` or `s2n_connection_set_client_auth_type()` for both the client and server. Additionally, the client will need to load a certificate and key pair as described for the server in [Server Authentication](#server-authentication) and the server will need to configure its trust store as described in [Configuring the Trust Store](#configuring-the-trust-store). - -When using client authentication, the server MUST implement the `s2n_verify_host_fn`, because the default behavior will likely reject all client certificates. - -When using client authentication with TLS1.3, `s2n_negotiate` will report a successful -handshake to clients before the server validates the client certificate. If the server then -rejects the client certificate, the client may later receive an alert while calling `s2n_recv`, -potentially after already having sent application data with `s2n_send`. This is a quirk of the -TLS1.3 protocol message ordering: the server does not send any more handshake messages -after the client sends the client certificate (see the [TLS1.3 state machine](https://www.rfc-editor.org/rfc/rfc8446.html#appendix-A.2)). -There is no security risk, since the client has already authenticated the server, -but it could make handshake failures and authentication errors more difficult to handle. - -### Certificate Inspection - -Applications may want to know which certificate was used by a server for authentication during a connection, since servers can set multiple certificates. `s2n_connection_get_selected_cert()` will return the local certificate chain object used to authenticate. `s2n_connection_get_peer_cert_chain()` will provide the peer's certificate chain, if they sent one. Use `s2n_cert_chain_get_length()` and `s2n_cert_chain_get_cert()` to parse the certificate chain object and get a single certificate from the chain. Use `s2n_cert_get_der()` to get the DER encoded certificate if desired. - -Additionally s2n-tls has functions for parsing certificate extensions on a certificate. Use `s2n_cert_get_x509_extension_value_length()` and `s2n_cert_get_x509_extension_value()` to obtain a specific DER encoded certificate extension from a certificate. `s2n_cert_get_utf8_string_from_extension_data_length()` and `s2n_cert_get_utf8_string_from_extension_data()` can be used to obtain a specific UTF8 string representation of a certificate extension instead. These functions will work for both RFC-defined certificate extensions and custom certificate extensions. - -### Certificate Revocation - -Certificate revocation is how CAs inform validators that an active certificate should not be trusted. This commonly occurs when a private key has been leaked and the identity of the certificate's owner can no longer be trusted. - -s2n-tls supports two methods of certificate revocation: OCSP stapling and CRLs. A fundamental difference between the two is that with OCSP stapling, the peer offering the certificate validates the revocation status of its own certificate. This peer can choose not to send a certificate status response, and applications will have to decide whether or not to fail certificate validation in this case. With CRLs, the application checks the revocation status of the certificate itself, without relying on the peer. However, CRLs must be retrieved and stored by the application, which requires more network and memory utilization than OCSP stapling. - -Users who want certificate revocation should look closely at their use-case and decide which method is more appropriate. We suggest using OCSP stapling if you're sure your peer supports OCSP stapling. CRLs should be used if this assumption can't be made. However, s2n-tls does not enable applications to fetch CRLs for received certificates in real-time. This method should only be used if you're able to obtain CRLs in advance for all certificates you expect to encounter. - -#### OCSP Stapling - -Online Certificate Status Protocol (OCSP) is a protocol to establish whether or not a certificate has been revoked. The requester (usually a client), asks the responder (usually a server), to ‘staple’ the certificate status information along with the certificate itself. The certificate status sent back will be either expired, current, or unknown, which the requester can use to determine whether or not to accept the certificate. - -OCSP stapling can be applied to both client and server certificates when using TLS1.3, but only to server certificates when using TLS1.2. - -To use OCSP stapling, the requester must call `s2n_config_set_status_request_type()` with S2N_STATUS_REQUEST_OCSP. The responder will need to call `s2n_cert_chain_and_key_set_ocsp_data()` to set the raw bytes of the OCSP stapling data. - -The OCSP stapling information will be automatically validated if the underlying libcrypto supports OCSP validation. `s2n_config_set_check_stapled_ocsp_response()` can be called with "0" to turn this off. Call `s2n_connection_get_ocsp_response()` to retrieve the received OCSP stapling information for manual verification. - -#### CRL Validation - -> Note: the CRL validation feature in s2n-tls is currently considered unstable, meaning the CRL APIs are subject to change in a future release. To access the CRL APIs, include `api/unstable/crl.h`. - -Certificate Revocation Lists (CRLs) are lists of issued, unexpired certificates that have been revoked by the CA. CAs publish updated versions of these lists periodically. A validator wishing to verify a certificate obtains a CRL from the CA, validates the CRL, and checks to ensure the certificate is not contained in the list, and therefore has not been revoked by the CA. - -The s2n CRL lookup callback must be implemented and set via `s2n_config_set_crl_lookup_cb()` to enable CRL validation in s2n-tls. This callback will be triggered once for each certificate in the certificate chain. - -The CRLs for all certificates received in the handshake must be obtained in advance of the CRL lookup callback, outside of s2n-tls. It is not possible in s2n-tls to obtain CRLs in real-time. Applications should load these CRLs into memory, by creating `s2n_crl`s via `s2n_crl_new()`, and adding the obtained CRL data via `s2n_crl_load_pem()`. The `s2n_crl` should be freed via `s2n_crl_free()` when no longer needed. - -The application must implement a way to look up the correct CRL for a given certificate. This can be done by comparing the hash of the received certificate's issuer with the hash of the CRL's issuer. The certificate's issuer hash is retrieved via `s2n_crl_lookup_get_cert_issuer_hash()`, and the CRL's issuer hash is retrieved via `s2n_crl_get_issuer_hash()`. Once a CRL is found with a matching issuer hash, call `s2n_crl_lookup_set()` to provide s2n-tls with this CRL. - -Call `s2n_crl_lookup_ignore()` to ignore a received certificate if its CRL can't be found. This will cause the certificate validation logic to fail with a `S2N_ERR_CRL_LOOKUP_FAILED` error if the certificate is needed in the chain of trust. The certificate validation logic will not fail if the ignored certificate ends up not being included in the chain of trust. - -By default, the CRL validation logic will not fail on CRLs that are not yet active, or are expired. Timestamp validation can optionally be performed in the CRL lookup callback by calling `s2n_crl_validate_active()` and `s2n_crl_validate_not_expired()`. - -### Certificate Transparency - -Certificate transparency is a framework to store public logs of CA-issued certificates. If requested, certificate owners can send a signed certificate timestamp (SCT) to prove that their certificate exists in these logs. The requester can choose whether or not to accept a certificate based on this information. - -Certificate transparency information can be applied to both client and server certificates when using TLS1.3, but only to server certificates when using TLS1.2. - -To use certificate transparency, the requester (usually the client) must call `s2n_config_set_ct_support_level()` with S2N_CT_SUPPORT_REQUEST. The responder (usually the server) must call `s2n_cert_chain_and_key_set_sct_list()` to set the raw bytes of the transparency information. - -Call `s2n_connection_get_sct_list()` to retrieve the received certificate transparency information. The format of this data is the SignedCertificateTimestampList structure defined in section 3.3 of RFC 6962. - -## Session Resumption - -TLS handshake sessions are CPU-heavy due to the calculations involved in authenticating a certificate. These calculations can be skipped after the first connection by turning on session resumption. This mechanism stores state from the previous session and uses it to establish the next session, allowing the handshake to skip the costly authentication step while keeping the same cryptographic guarantees. The authentication step can be skipped because both the server and client will use their possession of the key from the previous session to prove who they are. We usually refer to the stored session state as a "session ticket". Note that this session ticket is encrypted by the server, so a server will have to set up an external key in order to do session resumption. - -### Session Ticket Key - -The key that encrypts and decrypts the session state is not related to the keys negotiated as part of the TLS handshake and has to be set by the server by calling `s2n_config_add_ticket_crypto_key()`. See [RFC5077](https://www.rfc-editor.org/rfc/rfc5077#section-5.5) for guidelines on securely generating keys. - -Each key has two different expiration dates. The first expiration date signifies the time that the key can be used for both encryption and decryption. The second expiration date signifies the time that the key can be used only for decryption. This mechanism is to ensure that a session ticket can be successfully decrypted if it was encrypted by a key that was about to expire. The full lifetime of the key is therefore the encrypt-decrypt lifetime plus the decrypt-only lifetime. To alter the default key lifetime call `s2n_config_set_ticket_encrypt_decrypt_key_lifetime()` and `s2n_config_set_ticket_decrypt_key_lifetime()`. - -The server will stop issuing session resumption tickets if a user doesn't set up a new key before the previous key passes through its encrypt-decrypt lifetime. Therefore it is recommended to add a new key when half of the previous key's encrypt-decrypt lifetime has passed. - -### Stateless Session Resumption - -In stateless session resumption the server sends a session ticket to a client after a successful handshake, and the client can send that ticket back to the server during a new connection to skip the authentication step. This mechanism allows servers to avoid storing individual state for each client, and for that reason is the preferred method for resuming a session. - -Servers should call `s2n_config_set_session_tickets_onoff()` to enable stateless session resumption. Additionally the server needs to set up an encryption key using `s2n_config_add_ticket_crypto_key()`. - -Clients should call `s2n_config_set_session_tickets_onoff()` to enable stateless session resumption and set a session ticket callback function using `s2n_config_set_session_ticket_cb()`, which will allow clients to receive a session ticket when it arrives. Then `s2n_connection_set_session()` should be called with that saved ticket when attempting to resume a new connection. - -### Stateful Session Resumption - -In stateful session resumption, also known as session caching, the server caches the session state per client and resumes a session based on the client's session ID. Note that session caching has not been implemented for > TLS1.2. If stateful session resumption is turned on and a TLS1.3 handshake is negotiated, the caching mechanism will not store that session and resumption will not be available the next time the client connects. - -Servers should set the three caching callback functions: `s2n_config_set_cache_store_callback()`, `s2n_config_set_cache_retrieve_callback()`, and `s2n_config_set_cache_delete_callback()` and then call `s2n_config_set_session_cache_onoff()` to enable stateful session resumption. Session caching will not be turned on unless all three session cache callbacks are set prior to calling `s2n_config_set_session_cache_onoff()`. Additionally, the server needs to set up an encryption key using `s2n_config_add_ticket_crypto_key()`. - -Clients should call `s2n_connection_get_session()` to retrieve some serialized state about the session. Then `s2n_connection_set_session()` should be called with that saved state when attempting to resume a new connection. - -### Session Resumption in TLS1.2 and TLS1.3 - -In TLS1.2, session ticket messages are sent during the handshake and are automatically received as part of calling `s2n_negotiate()`. They will be available as soon as negotiation is complete. - -In TLS1.3, session ticket messages are sent after the handshake as "post-handshake" messages, and may not be received as part of calling `s2n_negotiate()`. A s2n-tls server will send tickets immediately after the handshake, so clients can receive them by calling `s2n_recv()` immediately after the handshake completes. However, other server implementations may send their session tickets later, at any time during the connection. - -Additionally, in TLS1.3, multiple session tickets may be issued for the same connection. Servers can call `s2n_config_set_initial_ticket_count()` to set the number of tickets they want to send and `s2n_connection_add_new_tickets_to_send()` to increase the number of tickets to send during a connection. - -### Session Resumption Forward Secrecy - -In TLS1.2, the secret stored inside the ticket is the original session's master secret. Because of this, TLS1.2 session tickets are not forward secret, meaning that compromising the resumed session's secret exposes the original session's encrypted data. - -In contrast, in TLS1.3 the secret stored inside the ticket is _derived_ from the original session's master secret. The derivation uses a cryptographic operation that can't be reversed by an attacker to retrieve the original master secret. Therefore, TLS1.3 session tickets are forward secret, meaning compromising the resumed session's secret will not expose the original session's encrypted data. - -### Keying Material Lifetimes in TLS1.2 and TLS1.3 - -In TLS1.2, a full handshake can issue a session ticket encrypted with a specific session ticket encryption key. Connections that resume using that session ticket will not issue new session tickets. Therefore, the lifetime of the original "keying material"-- meaning the lifetime of any secret derived from the original full handshake-- is limited by the lifetime of the session ticket encryption key. Applications can set the session ticket encryption key lifetime with `s2n_config_set_ticket_encrypt_decrypt_key_lifetime()`. - -In TLS1.3, connections that resume using a session ticket CAN issue new session tickets. This is because TLS1.3 tickets are intended to be single-use, and each ticket contains a different secret: see [Session Resumption Forward Secrecy](#session-resumption-forward-secrecy). These new session tickets may be encrypted with newer session ticket encryption keys, allowing the original "keying material" to outlive the original session ticket encryption key. However, TLS1.3 enforces a specific separate "keying material" lifetime, which servers can configure with `s2n_connection_set_server_keying_material_lifetime()`. This effectively places a limit on how long sessions can be resumed before a new full handshake is required. - -## Examining the Client Hello - -s2n-tls stores the received Client Hello and makes it available to the application. Call `s2n_connection_get_client_hello()` to get a pointer to the `s2n_client_hello` struct storing the Client Hello message. A NULL value will be returned if the connection has not yet received the Client Hello. The earliest point in the handshake when this struct is available is during the [Client Hello Callback](#client-hello-callback). The stored Client Hello message will not be available after calling `s2n_connection_free_handshake()`. - -Call `s2n_client_hello_get_raw_message()` to retrieve the complete Client Hello message with the random bytes on it zeroed out. - -Call `s2n_client_hello_get_cipher_suites()` to retrieve the list of cipher suites sent by the client. - -Call `s2n_client_hello_get_session_id()` to retrieve the session ID sent by the client in the ClientHello message. Note that this value may not be the session ID eventually associated with this particular connection since the session ID can change when the server sends the Server Hello. The official session ID can be retrieved with `s2n_connection_get_session_id()`after the handshake completes. - -Call `s2n_client_hello_get_extensions()` to retrieve the entire list of extensions sent in the Client Hello. Calling `s2n_client_hello_get_extension_by_id()` allows you to interrogate the `s2n_client_hello` struct for a specific extension. - -### SSLv2 -s2n-tls will not negotiate SSLv2, but will accept SSLv2 ClientHellos advertising a -higher protocol version like SSLv3 or TLS1.0. This was a backwards compatibility -strategy used by some old clients when connecting to a server that might only support SSLv2. - -You can determine whether an SSLv2 ClientHello was received by checking the value -of `s2n_connection_get_client_hello_version()`. If an SSLv2 ClientHello was -received, then `s2n_connection_get_client_protocol_version()` will still report -the real protocol version requested by the client. - -SSLv2 ClientHellos are formatted differently than ClientHellos in later versions. -`s2n_client_hello_get_raw_message()` and `s2n_client_hello_get_cipher_suites()` -will produce differently formatted data. See the documentation for those methods -for details about proper SSLv2 ClientHello parsing. - -### Client Hello Callback - -Users can access the Client Hello during the handshake by setting the callback `s2n_config_set_client_hello_cb()`. A possible use-case for this is to modify the `s2n_connection` based on information in the Client Hello. This should be done carefully, as modifying the connection in response to untrusted input can be dangerous. In particular, switching from an `s2n_config` that supports TLS1.3 to one that does not opens the server up to a possible version downgrade attack. - -`s2n_connection_server_name_extension_used()` MUST be invoked before exiting the callback if any of the connection properties were changed on the basis of the Server Name extension. If desired, the callback can return a negative value to make s2n-tls terminate the handshake early with a fatal handshake failure alert. - -#### Callback Modes - -The callback can be invoked in two modes: **S2N_CLIENT_HELLO_CB_BLOCKING** or **S2N_CLIENT_HELLO_CB_NONBLOCKING**. Use `s2n_config_set_client_hello_cb_mode()` to set the desired mode. - -The default mode, "blocking mode", will wait for the Client Hello callback to succeed and then continue the handshake. Use this mode for light-weight callbacks that won't slow down the handshake or block the main thread, like logging or simple configuration changes. - -In contrast, "non-blocking mode" will wait for the ClientHello callback to succeed and then pause the handshake, immediately returning from s2n_negotiate with an error indicating that the handshake is blocked on application input. This allows the application to do expensive or time-consuming work like network calls outside of the callback without blocking the main thread. Only when the application calls `s2n_client_hello_cb_done()` will the handshake be able to resume. - -## Record sizes - -### Throughput vs Latency - -When sending data, s2n-tls uses a default maximum record size which experimentation -has suggested provides a reasonable balance of performance and throughput. - -**s2n_connection_prefer_throughput** can be called to increase the record size, which -minimizes overhead. It also increases s2n-tls's memory usage. - -**s2n_connection_prefer_low_latency** can be called to decrease the record size, which -allows the receiver to decrypt the data faster. It also decreases s2n-tls's memory usage. - -These options only affect the size of the records that s2n-tls sends, not the behavior -of the peer. - -### Maximum Fragment Length - -The maximum number of bytes that can be sent in a TLS record is called the "maximum fragment length", -and is set to 2^14 bytes by default. Regardless of the maximum record size that s2n-tls -uses when sending, it may receive records containing up to 2^14 bytes of plaintext. - -A client can request a lower maximum fragment length by calling **s2n_config_send_max_fragment_length**, -reducing the size of TLS records sent and providing benefits similar to **s2n_connection_prefer_low_latency**. -However, many TLS servers either ignore these requests or handle them incorrectly, so a client should -never assume that a lower maximum fragment length will be honored. If a server accepts the requested -maximum fragment length, the client will respect that maximum when sending. - -By default, an s2n-tls server will ignore a client's requested maximum fragment length. -If **s2n_config_accept_max_fragment_length** is called, the server will respect the client's requested -maximum fragment length when sending, but will not reject client records with a larger fragment size. - -If a maximum fragment length is negotiated during the connection, it will override the behavior -configured by **s2n_connection_prefer_throughput** and **s2n_connection_prefer_low_latency**. - -### Dynamic Record Sizing - -Sending smaller records at the beginning of a connection can decrease first byte latency, -particularly if TCP slow start is used. - -**s2n_connection_set_dynamic_record_threshold** can be called to initially send smaller records. -The connection will send the first **resize_threshold** bytes in records small enough to -fit in a single standard 1500 byte ethernet frame. Whenever **timeout_threshold** seconds -pass without sending data, the connection will revert to this behavior and send small records again. - -Dynamic record sizing doesn't completely override **s2n_connection_prefer_throughput**, -**s2n_connection_prefer_low_latency**, or the negotiated maximum fragment length. -Once **resize_threshold** is hit, records return to the maximum size configured for the connection. -And if the maximum fragment length negotiated with the peer is lower than what dynamic record sizing -would normally produce, the lower value will be used. - -## Private Key Operation Related Calls - -By default, s2n-tls automatically uses the configured private key to synchronously perform the signature -and decryption operations required for a tls handshake. However, this default behavior may not -work for some situations. - -For example: -* An application may want to perform the CPU-expensive signature and decryption operations -asynchronously to avoid blocking the main event loop. -See [Asynchronous private key operations](#Asynchronous-private-key-operations) -* An application may not have direct access to the private key, such as when using PKCS#11. -See [Offloading private key operations](#Offloading-private-key-operations) - -To handle these use cases, s2n-tls provides a callback to allow users to control how these operations -are performed. The callback is set via **s2n_config_set_async_pkey_callback** and is triggered -every time **s2n_negotiate** performs an action involving the private key. The callback is passed -**op**, an opaque object representing the private key operation. To avoid memory leaks, **op** must -always eventually be freed by calling **s2n_async_pkey_op_free**. - -The private key operation can be performed by calling **s2n_async_pkey_op_perform** -(or **s2n_async_pkey_op_set_output**: see [Offloading private key operations](#Offloading-private-key-operations)). -The required private key can be retrieved using the **s2n_connection_get_selected_cert** and **s2n_cert_chain_and_key_get_private_key** calls. The operation can then be finalized with **s2n_async_pkey_op_apply** to continue the handshake. - -### Asynchronous Private Key Operations - -When s2n-tls is used in non-blocking mode, private key operations can be completed -asynchronously. This model can be useful to move execution of -CPU-heavy private key operations out of the main -event loop, preventing **s2n_negotiate** from blocking the loop for a few -milliseconds each time the private key operation needs to be performed. - -To handle private key operations asynchronously, return from the callback without calling -**s2n_async_pkey_op_perform** or **s2n_async_pkey_op_apply**. Usually the user would do this -by spawning a separate thread to perform **op** and immediately returning **S2N_SUCCESS** -from the callback without waiting for that separate thread to complete. In response, -**s2n_negotiate** will return **S2N_FAILURE** with an error of type **S2N_ERR_T_BLOCKED** -and **s2n_blocked_status** set to **S2N_BLOCKED_ON_APPLICATION_INPUT**. -All subsequent calls to **s2n_negotiate** will produce the same result until **s2n_async_pkey_op_apply** -is called to finalize the **op**. - -Note: It is not safe to call multiple functions on the same **conn** or -**op** objects from 2 different threads at the same time. Doing so will -produce undefined behavior. However it is safe to have a call to a -function involving only **conn** at the same time as a call to a -function involving only **op**, as those objects are not coupled with -each other. It is also safe to free **conn** or **op** at any moment with -respective function calls, with the exception that **conn** cannot -be freed inside the **s2n_async_pkey_fn** callback. - -### Synchronous Private Key Operations - -Despite the "async" in the function names, private key operations can also be completed synchronously using the callback. -To complete an operation synchronously, simply call **s2n_async_pkey_op_perform** and **s2n_async_pkey_op_apply** inside the callback. -If the callback succeeds, the handshake will continue uninterrupted. -If the callback fails, **s2n_negotiate** will fail with an error of type **S2N_ERR_T_INTERNAL**. - -### Offloading Private Key Operations - -The **s2n_async_pkey_op_perform** call used to perform a private key operation requires -direct access to the private key. In some cases, like when using PKCS#11, users may not -have access to the private key. In these cases, we can substitute **s2n_async_pkey_op_set_output** -for **s2n_async_pkey_op_perform** to tell s2n-tls the result of the operation rather than -having s2n-tls perform the operation itself. - -s2n-tls provides a number of calls to gather the information necessary for -an outside module or library to perform the operation. The application can query the type of private -key operation by calling **s2n_async_pkey_op_get_op_type**. In order to perform -an operation, the application must ask s2n-tls to copy the operation's input into an -application supplied buffer. The appropriate buffer size can be determined by calling -**s2n_async_pkey_op_get_input_size**. Once a buffer of the proper size is -allocated, the application can request the input data by calling **s2n_async_pkey_op_get_input**. -After the operation is completed, the finished output can be copied back to S2N by calling **s2n_async_pkey_op_set_output**. -Once the output is set, the private key operation can be completed by calling **s2n_async_pkey_op_apply** as usual. - -Offloading can be performed either synchronously or asynchronously. If the offloaded operation -fails synchronously, simply return S2N_FAILURE from the callback. If the offloaded operation -fails asynchronously, s2n-tls does not provide a way to communicate that result. Instead, -simply shutdown and cleanup the connection as you would for any other error. - -## TLS1.3 Pre-Shared Keys - -s2n-tls supports pre-shared keys (PSKs) as of TLS1.3. PSKs allow users to establish secrets outside of the handshake, skipping certificate exchange and authentication. - -### Benefits of Using Pre-Shared Keys - -Using pre-shared keys can avoid the need for public key operations. This is useful in performance-constrained environments with limited CPU power. PSKs may also be more convenient from a key management point of view: If the system already has a mechanism for sharing secrets, that mechanism can be reused for TLS PSKs. - -### Security Considerations - -A PSK must not be shared between more than one server and one client. An entity that acts as both a server and a client should not use the same PSK for both roles. For more information see: [Selfie: reflections on TLS 1.3 with PSK.](https://eprint.iacr.org/2019/347.pdf) - - -### Configuring External Pre-Shared Keys - -Both clients and servers will need to create and append a PSK to a connection in order to negotiate that PSK. Call `s2n_external_psk_new()` to allocate memory for a PSK object. Call `s2n_psk_set_identity()` to set a unique identifier for the PSK. Note that this identity will be transmitted over the network unencrypted, so do not include any confidential information in it. Call `s2n_psk_set_secret()` to set the secret value for a given PSK. Deriving a shared secret from a password or other low-entropy source is _not_ secure and is subject to dictionary attacks. See [this RFC](https://www.rfc-editor.org/rfc/rfc9257.html#name-recommendations-for-externa) for more guidelines on creating a secure PSK secret. Call `s2n_psk_set_hmac()` to change the hmac algorithm (defaults to **S2N_PSK_HMAC_SHA256**) for a given PSK. Note that the hmac algorithm may influence server cipher-suite selection. - -Call `s2n_connection_append_psk()` to append the newly created PSK to the connection. Both the server and client should call this API to add PSKs to their connection. PSKs that are appended first will be preferred over PSKs appended last unless custom PSK selection logic is implemented. Use `s2n_psk_free()` to free the memory allocated for a PSK once you have associated it with a connection. - -External PSKs and Session Resumption cannot both be used in TLS13. Therefore, users must pick which mode they are using by calling `s2n_config_set_psk_mode()` prior to the handshake. Additionally, `s2n_connection_set_psk_mode()` overrides the PSK mode set on the config for a particular connection. - -### Selecting a Pre-Shared Key - -By default, a server chooses the first identity in its PSK list that also appears in the client's PSK list. The `s2n_psk_selection_callback` is available if you would like to implement your own PSK selection logic. Currently, this callback is not asynchronous. Call `s2n_config_set_psk_selection_callback()` to associate your `s2n_psk_selection_callback` with a config. - -The `s2n_psk_selection_callback` will provide the list of PSK identities sent by the client in the **psk_list** input parameter. You will need to create an offered PSK object by calling `s2n_offered_psk_new()` and pass this object as a parameter in `s2n_offered_psk_list_next()` in order to populate the offered PSK object. Call `s2n_offered_psk_list_has_next()` prior to calling `s2n_offered_psk_list_next()` to determine if there exists another PSK in the **psk_list**. Call `s2n_offered_psk_get_identity()` to get the identity of a particular **s2n_offered_psk**. - -Call `s2n_offered_psk_list_choose_psk()` to choose a particular **s2n_offered_psk** to be used for the connection. Note that the server must have already configured the corresponding PSK on the connection using `s2n_connection_append_psk()`. To disable PSKs for the connection and perform a full handshake instead, set the PSK identity to NULL. Call `s2n_offered_psk_free()` once you have chosen a particular PSK to free the memory allocated. - -If desired, `s2n_offered_psk_list_reread()` returns the offered PSK list to its original read state. After `s2n_offered_psk_list_reread()` is called, the next call to `s2n_offered_psk_list_next()` will return the first PSK in the offered PSK list. - -Use `s2n_connection_get_negotiated_psk_identity()` to retrieve the PSK identity selected by the server for the connection. - -In the following example, `s2n_psk_selection_callback` chooses the first client offered PSK identity present in an external store. - -```c -int s2n_psk_selection_callback(struct s2n_connection *conn, void *context, - struct s2n_offered_psk_list *psk_list) -{ - struct s2n_offered_psk *offered_psk = s2n_offered_psk_new(); - - while (s2n_offered_psk_list_has_next(psk_list)) { - uint8_t *client_psk_id = NULL; - uint16_t client_psk_id_len = 0; - - s2n_offered_psk_list_next(psk_list, offered_psk); - s2n_offered_psk_get_identity(offered_psk, &client_psk_id, &client_psk_id_len); - struct s2n_psk *psk = user_lookup_identity_db(client_psk_id, client_psk_id_len); - - if (psk) { - s2n_connection_append_psk(conn, psk); - s2n_offered_psk_list_choose_psk(psk_list, offered_psk); - break; - } - } - s2n_offered_psk_free(&offered_psk); - return S2N_SUCCESS; -} -``` - -## Using Early Data / 0RTT - -TLS1.3 introduced the ability for clients to send data before completing the handshake when using external pre-shared keys or session resumption. - -**WARNING:** Early data does not have the same security properties as regular data sent after a successful handshake. -* It is not forward secret. If the PSK or session resumption secret is compromised, then the early data is also compromised. -* It is susceptible to replay attacks unless proper precautions are taken. Early data can be captured and successfully resent by an attacker. See https://tools.ietf.org/rfc/rfc8446#appendix-E.5 for more details, and ["Adding anti-replay protection"](#adding-anti-replay-protection) for how to implement counter measures. - -_**Do not enable early data for your application unless you have understood and mitigated the risks.**_ - -### Configuring session resumption for early data - -To use early data with session tickets, early data must be enabled on a server by setting the maximum early data allowed to a non-zero value with **s2n_config_set_server_max_early_data_size** or **s2n_connection_set_server_max_early_data_size**. The server then begins issuing tickets that support early data, and clients can use early data when they use those tickets. - -### Configuring external pre-shared keys for early data - -To use early data with pre-shared keys, individual pre-shared keys must support early data. In addition to configuring the maximum early data allowed, each pre-shared key needs an associated cipher suite and if applicable, application protocol. The server only accepts early data if the pre-shared key's associated cipher suite and application protocol match the cipher suite and the application protocol negotiated during the handshake. - -The maximum early data allowed and cipher suite can be set with **s2n_psk_configure_early_data**. If the connection will negotiate an application protocol then the expected application protocol can be set with **s2n_psk_set_application_protocol**. - -### Sending early data - -To send early data, your application should call **s2n_send_early_data** before it calls **s2n_negotiate**. - -**s2n_connection_get_remaining_early_data_size** can be called to check how much more early data the client is allowed to send. If **s2n_send_early_data** exceeds the allowed maximum, s2n-tls returns a usage error. - -Like other IO functions, **s2n_send_early_data** can potentially fail repeatedly with a blocking error before it eventually succeeds: see [I/O Functions](#io-functions) for more information. An application can stop calling **s2n_send_early_data** at any time, even if the function has not returned success yet. If **s2n_send_early_data** does return success, the connection is ready to complete the handshake and begin sending normal data. However, **s2n_send_early_data** can continue to be called to send more early data if desired. - -Once a client finishes sending early data, you should call **s2n_negotiate** to complete the handshake just as you would for a handshake that did not include early data. - -For example: -``` -uint8_t early_data[] = "early data to send"; -ssize_t total_data_sent = 0, len = sizeof(early_data); -while (total_data_sent < len) { - ssize_t data_sent = 0; - int r = s2n_send_early_data(client_conn, early_data + total_data_sent, - len - total_data_sent, &data_sent, &blocked); - total_data_sent += data_sent; - if (r == S2N_SUCCESS) { - break; - } else if (s2n_error_get_type(s2n_errno) != S2N_ERR_T_BLOCKED) { - exit(1); - } -} -while (s2n_negotiate(client_conn, &blocked) != S2N_SUCCESS) { - if (s2n_error_get_type(s2n_errno) != S2N_ERR_T_BLOCKED) { - exit(1); - } -} -``` - -### Receiving early data - -To receive early data, your application should call **s2n_recv_early_data** before it calls **s2n_negotiate**. - -Like other S2N IO functions, **s2n_recv_early_data** can potentially fail repeatedly with a blocking error before it eventually succeeds: see [I/O Functions](#io-functions) for more information. Once **s2n_recv_early_data** has been called, it must be called until it returns success. If an application stops calling **s2n_recv_early_data** early, some early data may be left unread and cause later calls to **s2n_negotiate** to return fatal errors. Calling **s2n_recv_early_data** again after it returns success is possible but has no effect on the connection. - -Once a server has read all early data, you should call **s2n_negotiate** to complete the handshake just as you would for a handshake that did not include early data. - -For example: -``` -uint8_t early_data[MAX_EARLY_DATA] = { 0 }; -ssize_t total_data_recv = 0, data_recv = 0; -while (s2n_recv_early_data(conn, early_data + total_data_recv, MAX_EARLY_DATA - total_data_recv, - &data_recv, &blocked) != S2N_SUCCESS) { - total_data_recv += data_recv; - if (s2n_error_get_type(s2n_errno) != S2N_ERR_T_BLOCKED) { - exit(1); - } -} -while (s2n_negotiate(conn, &blocked) != S2N_SUCCESS) { - if (s2n_error_get_type(s2n_errno) != S2N_ERR_T_BLOCKED) { - exit(1); - } -} -``` - -### Adding anti-replay protection -**s2n-tls does not include anti-replay protection automatically.** Effective anti-replay protection for a multi-server application requires an external state shared by all servers. Without shared state, an attacker can capture early data originally sent to server A and successfully replay it against server B. - -The TLS1.3 specification suggests two possible anti-replay solutions that a user can implement: -1. Single-Use Tickets (https://tools.ietf.org/rfc/rfc8446#section-8.1): Valid tickets are stored in a shared database and deleted after use. **s2n_connection_get_negotiated_psk_identity_length** and **s2n_connection_get_negotiated_psk_identity** can be used to get the ticket identifier, or "pre-shared key identity", associated with offered early data. -2. Client Hello Recording (https://tools.ietf.org/rfc/rfc8446#section-8.2): Instead of recording outstanding valid tickets, unique values from recent ClientHellos can be stored. The client hello message can be retrieved with **s2n_connection_get_client_hello** and the pre-shared key identity can be retrieved with **s2n_connection_get_negotiated_psk_identity_length** and **s2n_connection_get_negotiated_psk_identity**, but s2n-tls does not currently provide methods to retrieve the validated binders or the ClientHello.random. - -The **s2n_early_data_cb** can be used to hook an anti-replay solution into s2n-tls. The callback can be configured by using **s2n_config_set_early_data_cb**. Using the **s2n_offered_early_data** pointer offered by the callback, **s2n_offered_early_data_reject** or **s2n_offered_early_data_accept** can accept or reject the client request to use early data. - -An example implementation: -``` -int s2n_early_data_cb_impl(struct s2n_connection *conn, struct s2n_offered_early_data *early_data) -{ - uint16_t identity_size = 0; - s2n_connection_get_negotiated_psk_identity_length(conn, &identity_size); - uint8_t *identity = malloc(identity_size); - s2n_connection_get_negotiated_psk_identity(conn, identity, identity_size); - - if (user_verify_single_use_ticket(identity)) { - s2n_offered_early_data_accept(early_data); - } else { - s2n_offered_early_data_reject(early_data); - } - - free(identity); - return S2N_SUCCESS; -} -``` - -The callback can also be implemented asynchronously by returning **S2N_SUCCESS** without either accepting or rejecting the early data. The handshake will then fail with an **S2N_ERR_T_BLOCKED** error type and **s2n_blocked_status** set to **S2N_BLOCKED_ON_APPLICATION_INPUT** until **s2n_offered_early_data_reject** or **s2n_offered_early_data_accept** is called asynchronously. - -An example asynchronous implementation: -``` -void *user_accept_or_reject_early_data(void *arg) -{ - struct s2n_offered_early_data *early_data = (struct s2n_offered_early_data *) arg; - if (user_slowly_verify_early_data(early_data)) { - s2n_offered_early_data_accept(early_data); - } else { - s2n_offered_early_data_reject(early_data); - } - return NULL; -} - -int s2n_early_data_cb_async_impl(struct s2n_connection *conn, struct s2n_offered_early_data *early_data) -{ - pthread_t thread_id; - pthread_create(&thread_id, NULL, user_accept_or_reject_early_data, (void *) early_data); - return S2N_SUCCESS; -} -``` - -**s2n_offered_early_data_get_context_length** and **s2n_offered_early_data_get_context** can be called to examine the optional user context associated with the early data. Unlike most s2n-tls callbacks, the context is not configured when the callback is set. Instead, the context is associated with the specific pre-shared key or session ticket used for early data. The context can be set for external pre-shared keys by calling **s2n_psk_set_early_data_context**. For session tickets, **s2n_connection_set_server_early_data_context** can be used to set the context the server includes on its new session tickets. Because the server needs to serialize the context when creating a new session ticket, the context is a byte buffer instead of the usual void pointer. - -# Examples - -To understand the API it may be easiest to see examples in action. s2n-tls's [bin/](https://github.com/aws/s2n-tls/blob/main/bin/) directory -includes an example client (`s2nc`) and server (`s2nd`). - -**Note:** `s2nc` and `s2nd` are intended for testing purposes only, and should not be used in production. diff --git a/docs/usage-guide/book.toml b/docs/usage-guide/book.toml new file mode 100644 index 00000000000..d34134a466f --- /dev/null +++ b/docs/usage-guide/book.toml @@ -0,0 +1,5 @@ +[book] +authors = [] +language = "en" +multilingual = false +src = "src" diff --git a/docs/usage-guide/src/SUMMARY.md b/docs/usage-guide/src/SUMMARY.md new file mode 100644 index 00000000000..74823cd703d --- /dev/null +++ b/docs/usage-guide/src/SUMMARY.md @@ -0,0 +1,17 @@ +# Summary + +[Introduction](./introduction.md) +- [s2n-tls API](./api.md) +- [Initialization and Teardown](./initialization.md) +- [Error Handling](./error_handling.md) +- [TLS Connections](./connection.md) +- [Configuring the Connection](./config.md) +- [Security Policies](./security_policies.md) +- [IO](./io.md) +- [TLS Record Sizes](./record_sizes.md) +- [Certificates and Authentication](./certificates.md) +- [Examining the Client Hello](./client_hello.md) +- [Session Resumption](./resumption.md) +- [Offloading Private Key Operations](./private_key_ops.md) +- [Pre-shared Keys](./preshared_keys.md) +- [Early Data](./early_data.md) diff --git a/docs/usage-guide/src/api.md b/docs/usage-guide/src/api.md new file mode 100644 index 00000000000..d1f1943d9d1 --- /dev/null +++ b/docs/usage-guide/src/api.md @@ -0,0 +1,32 @@ +# s2n-tls API + +The API exposed by s2n-tls is the set of functions and declarations that +are in the [s2n.h](https://github.com/aws/s2n-tls/blob/main/api/s2n.h) header file. Any functions and declarations that are in the [s2n.h](https://github.com/aws/s2n-tls/blob/main/api/s2n.h) file +are intended to be stable (API and ABI) within major version numbers of s2n-tls releases. Other functions +and structures used in s2n-tls internally can not be considered stable and their parameters, names, and +sizes may change. + +The [VERSIONING.rst](https://github.com/aws/s2n-tls/blob/main/VERSIONING.rst) document contains more details about s2n's approach to versions and API changes. + +## API Reference + +s2n-tls uses [Doxygen](https://doxygen.nl/index.html) to document its public API. The latest s2n-tls documentation can be found on [GitHub pages](https://aws.github.io/s2n-tls/doxygen/). + +Documentation for older versions or branches of s2n-tls can be generated locally. To generate the documentation, install doxygen and run `doxygen docs/doxygen/Doxyfile`. The doxygen documentation can now be found at `docs/doxygen/output/html/index.html`. + +Doxygen installation instructions are available at the [Doxygen](https://doxygen.nl/download.html) webpage. + +The doxygen documentation should be used in conjunction with this guide. + +## Supported TLS Versions + +Currently TLS 1.2 is our default version, but we recommend TLS 1.3 where possible. To use TLS 1.3 you need a security policy that supports TLS 1.3. See the [Security Policies](#security-policies) section for more information. + +**Note:** s2n-tls does not support SSL2.0 for sending and receiving encrypted data, but does accept SSL2.0 hello messages. + +## Examples + +To understand the API it may be easiest to see examples in action. s2n-tls's [bin](https://github.com/aws/s2n-tls/blob/main/bin/) directory +includes an example client (`s2nc`) and server (`s2nd`). + +**Note:** `s2nc` and `s2nd` are intended for testing purposes only, and should not be used in production. diff --git a/docs/usage-guide/src/certificates.md b/docs/usage-guide/src/certificates.md new file mode 100644 index 00000000000..2266d59fd2b --- /dev/null +++ b/docs/usage-guide/src/certificates.md @@ -0,0 +1,103 @@ +# Certificates and Authentication + +TLS uses certificates to authenticate the server (and optionally the client). The handshake will fail if the client cannot verify the server’s certificate. + +Authentication is usually the most expensive part of the handshake. To avoid the cost, consider using [session resumption](./resumption.md) or [pre-shared keys](./preshared_keys.md). + +## Configuring the Trust Store + +To validate the peer’s certificate, a config's local “trust store” must contain a certificate +that can authenticate the peer’s certificate. To add certificates to the trust store, call +`s2n_config_set_verification_ca_location()` or `s2n_config_add_pem_to_trust_store()`. + +`s2n_config_new()` initializes the trust store with the default system certificates, which may +include public CAs or other unexpected certificates. If s2n-tls is verifying certificates and does +not require these default system certificates, they should be cleared with +`s2n_config_wipe_trust_store()` before calling `s2n_config_set_verification_ca_location()` or +`s2n_config_add_pem_to_trust_store()`. + +Note that the `s2n_verify_host_fn` callback must be implemented to validate the identity of all +received certificates. A client implementation is set by default. If the identity of the received +certificates are implicit (i.e. the certificates are self-signed, or signed by a privately owned +CA), the `s2n_verify_host_fn` callback need not perform any additional validation. However, +`s2n_config_wipe_trust_store()` should be called before adding certificates to the trust store in +this case, in order to avoid implicitly trusting the identity of peers that may present +certificates trusted via an unexpected default system certificate. + +Configs created with `s2n_config_new_minimal()` are initialized with empty trust stores. To add +default system certificates to these configs, call `s2n_config_load_system_certs()`. + +## Server Authentication + +A server must have a certificate and private key pair to prove its identity. s2n-tls supports RSA, RSA-PSS, and ECDSA certificates, and allows one of each type to be added to a config. + +Create a new certificate and key pair by calling `s2n_cert_chain_and_key_new()`, then load the pem-encoded data with `s2n_cert_chain_and_key_load_pem_bytes()`. Call `s2n_config_add_cert_chain_and_key_to_store()` to add the certificate and key pair to the config. When a certificate and key pair is no longer needed, it must be cleaned up with `s2n_cert_chain_and_key_free()`. + +A client can add restrictions on the certificate’s hostname by setting a custom `s2n_verify_host_fn` with `s2n_config_set_verify_host_callback()` or `s2n_connection_set_verify_host_callback()`. The default behavior is to require that the hostname match the server name set with `s2n_set_server_name()`. + +## Client / Mutual Authentication + +Client authentication is not enabled by default. However, the server can require that the client also provide a certificate, if the server needs to authenticate clients before accepting connections. + +Client authentication can be configured by calling `s2n_config_set_client_auth_type()` or `s2n_connection_set_client_auth_type()` for both the client and server. Additionally, the client will need to load a certificate and key pair as described for the server in [Server Authentication](#server-authentication) and the server will need to configure its trust store as described in [Configuring the Trust Store](#configuring-the-trust-store). + +When using client authentication, the server MUST implement the `s2n_verify_host_fn`, because the default behavior will likely reject all client certificates. + +When using client authentication with TLS1.3, `s2n_negotiate` will report a successful +handshake to clients before the server validates the client certificate. If the server then +rejects the client certificate, the client may later receive an alert while calling `s2n_recv`, +potentially after already having sent application data with `s2n_send`. This is a quirk of the +TLS1.3 protocol message ordering: the server does not send any more handshake messages +after the client sends the client certificate (see the [TLS1.3 state machine](https://www.rfc-editor.org/rfc/rfc8446.html#appendix-A.2)). +There is no security risk, since the client has already authenticated the server, +but it could make handshake failures and authentication errors more difficult to handle. + +## Certificate Inspection + +Applications may want to know which certificate was used by a server for authentication during a connection, since servers can set multiple certificates. `s2n_connection_get_selected_cert()` will return the local certificate chain object used to authenticate. `s2n_connection_get_peer_cert_chain()` will provide the peer's certificate chain, if they sent one. Use `s2n_cert_chain_get_length()` and `s2n_cert_chain_get_cert()` to parse the certificate chain object and get a single certificate from the chain. Use `s2n_cert_get_der()` to get the DER encoded certificate if desired. + +Additionally s2n-tls has functions for parsing certificate extensions on a certificate. Use `s2n_cert_get_x509_extension_value_length()` and `s2n_cert_get_x509_extension_value()` to obtain a specific DER encoded certificate extension from a certificate. `s2n_cert_get_utf8_string_from_extension_data_length()` and `s2n_cert_get_utf8_string_from_extension_data()` can be used to obtain a specific UTF8 string representation of a certificate extension instead. These functions will work for both RFC-defined certificate extensions and custom certificate extensions. + +## Certificate Revocation + +Certificate revocation is how CAs inform validators that an active certificate should not be trusted. This commonly occurs when a private key has been leaked and the identity of the certificate's owner can no longer be trusted. + +s2n-tls supports two methods of certificate revocation: OCSP stapling and CRLs. A fundamental difference between the two is that with OCSP stapling, the peer offering the certificate validates the revocation status of its own certificate. This peer can choose not to send a certificate status response, and applications will have to decide whether or not to fail certificate validation in this case. With CRLs, the application checks the revocation status of the certificate itself, without relying on the peer. However, CRLs must be retrieved and stored by the application, which requires more network and memory utilization than OCSP stapling. + +Users who want certificate revocation should look closely at their use-case and decide which method is more appropriate. We suggest using OCSP stapling if you're sure your peer supports OCSP stapling. CRLs should be used if this assumption can't be made. However, s2n-tls does not enable applications to fetch CRLs for received certificates in real-time. This method should only be used if you're able to obtain CRLs in advance for all certificates you expect to encounter. + +### OCSP Stapling + +Online Certificate Status Protocol (OCSP) is a protocol to establish whether or not a certificate has been revoked. The requester (usually a client), asks the responder (usually a server), to ‘staple’ the certificate status information along with the certificate itself. The certificate status sent back will be either expired, current, or unknown, which the requester can use to determine whether or not to accept the certificate. + +OCSP stapling can be applied to both client and server certificates when using TLS1.3, but only to server certificates when using TLS1.2. + +To use OCSP stapling, the requester must call `s2n_config_set_status_request_type()` with S2N_STATUS_REQUEST_OCSP. The responder will need to call `s2n_cert_chain_and_key_set_ocsp_data()` to set the raw bytes of the OCSP stapling data. + +The OCSP stapling information will be automatically validated if the underlying libcrypto supports OCSP validation. `s2n_config_set_check_stapled_ocsp_response()` can be called with "0" to turn this off. Call `s2n_connection_get_ocsp_response()` to retrieve the received OCSP stapling information for manual verification. + +## CRL Validation + +> Note: the CRL validation feature in s2n-tls is currently considered unstable, meaning the CRL APIs are subject to change in a future release. To access the CRL APIs, include `api/unstable/crl.h`. + +Certificate Revocation Lists (CRLs) are lists of issued, unexpired certificates that have been revoked by the CA. CAs publish updated versions of these lists periodically. A validator wishing to verify a certificate obtains a CRL from the CA, validates the CRL, and checks to ensure the certificate is not contained in the list, and therefore has not been revoked by the CA. + +The s2n CRL lookup callback must be implemented and set via `s2n_config_set_crl_lookup_cb()` to enable CRL validation in s2n-tls. This callback will be triggered once for each certificate in the certificate chain. + +The CRLs for all certificates received in the handshake must be obtained in advance of the CRL lookup callback, outside of s2n-tls. It is not possible in s2n-tls to obtain CRLs in real-time. Applications should load these CRLs into memory, by creating `s2n_crl`s via `s2n_crl_new()`, and adding the obtained CRL data via `s2n_crl_load_pem()`. The `s2n_crl` should be freed via `s2n_crl_free()` when no longer needed. + +The application must implement a way to look up the correct CRL for a given certificate. This can be done by comparing the hash of the received certificate's issuer with the hash of the CRL's issuer. The certificate's issuer hash is retrieved via `s2n_crl_lookup_get_cert_issuer_hash()`, and the CRL's issuer hash is retrieved via `s2n_crl_get_issuer_hash()`. Once a CRL is found with a matching issuer hash, call `s2n_crl_lookup_set()` to provide s2n-tls with this CRL. + +Call `s2n_crl_lookup_ignore()` to ignore a received certificate if its CRL can't be found. This will cause the certificate validation logic to fail with a `S2N_ERR_CRL_LOOKUP_FAILED` error if the certificate is needed in the chain of trust. The certificate validation logic will not fail if the ignored certificate ends up not being included in the chain of trust. + +By default, the CRL validation logic will not fail on CRLs that are not yet active, or are expired. Timestamp validation can optionally be performed in the CRL lookup callback by calling `s2n_crl_validate_active()` and `s2n_crl_validate_not_expired()`. + +## Certificate Transparency + +Certificate transparency is a framework to store public logs of CA-issued certificates. If requested, certificate owners can send a signed certificate timestamp (SCT) to prove that their certificate exists in these logs. The requester can choose whether or not to accept a certificate based on this information. + +Certificate transparency information can be applied to both client and server certificates when using TLS1.3, but only to server certificates when using TLS1.2. + +To use certificate transparency, the requester (usually the client) must call `s2n_config_set_ct_support_level()` with S2N_CT_SUPPORT_REQUEST. The responder (usually the server) must call `s2n_cert_chain_and_key_set_sct_list()` to set the raw bytes of the transparency information. + +Call `s2n_connection_get_sct_list()` to retrieve the received certificate transparency information. The format of this data is the SignedCertificateTimestampList structure defined in section 3.3 of RFC 6962. diff --git a/docs/usage-guide/src/client_hello.md b/docs/usage-guide/src/client_hello.md new file mode 100644 index 00000000000..ac90da8cad0 --- /dev/null +++ b/docs/usage-guide/src/client_hello.md @@ -0,0 +1,40 @@ +# Examining the Client Hello + +s2n-tls stores the received Client Hello and makes it available to the application. Call `s2n_connection_get_client_hello()` to get a pointer to the `s2n_client_hello` struct storing the Client Hello message. A NULL value will be returned if the connection has not yet received the Client Hello. The earliest point in the handshake when this struct is available is during the [Client Hello Callback](#client-hello-callback). The stored Client Hello message will not be available after calling `s2n_connection_free_handshake()`. + +Call `s2n_client_hello_get_raw_message()` to retrieve the complete Client Hello message with the random bytes on it zeroed out. + +Call `s2n_client_hello_get_cipher_suites()` to retrieve the list of cipher suites sent by the client. + +Call `s2n_client_hello_get_session_id()` to retrieve the session ID sent by the client in the ClientHello message. Note that this value may not be the session ID eventually associated with this particular connection since the session ID can change when the server sends the Server Hello. The official session ID can be retrieved with `s2n_connection_get_session_id()`after the handshake completes. + +Call `s2n_client_hello_get_extensions()` to retrieve the entire list of extensions sent in the Client Hello. Calling `s2n_client_hello_get_extension_by_id()` allows you to interrogate the `s2n_client_hello` struct for a specific extension. + +## SSLv2 +s2n-tls will not negotiate SSLv2, but will accept SSLv2 ClientHellos advertising a +higher protocol version like SSLv3 or TLS1.0. This was a backwards compatibility +strategy used by some old clients when connecting to a server that might only support SSLv2. + +You can determine whether an SSLv2 ClientHello was received by checking the value +of `s2n_connection_get_client_hello_version()`. If an SSLv2 ClientHello was +received, then `s2n_connection_get_client_protocol_version()` will still report +the real protocol version requested by the client. + +SSLv2 ClientHellos are formatted differently than ClientHellos in later versions. +`s2n_client_hello_get_raw_message()` and `s2n_client_hello_get_cipher_suites()` +will produce differently formatted data. See the documentation for those methods +for details about proper SSLv2 ClientHello parsing. + +## Client Hello Callback + +Users can access the Client Hello during the handshake by setting the callback `s2n_config_set_client_hello_cb()`. A possible use-case for this is to modify the `s2n_connection` based on information in the Client Hello. This should be done carefully, as modifying the connection in response to untrusted input can be dangerous. In particular, switching from an `s2n_config` that supports TLS1.3 to one that does not opens the server up to a possible version downgrade attack. + +`s2n_connection_server_name_extension_used()` MUST be invoked before exiting the callback if any of the connection properties were changed on the basis of the Server Name extension. If desired, the callback can return a negative value to make s2n-tls terminate the handshake early with a fatal handshake failure alert. + +### Callback Modes + +The callback can be invoked in two modes: **S2N_CLIENT_HELLO_CB_BLOCKING** or **S2N_CLIENT_HELLO_CB_NONBLOCKING**. Use `s2n_config_set_client_hello_cb_mode()` to set the desired mode. + +The default mode, "blocking mode", will wait for the Client Hello callback to succeed and then continue the handshake. Use this mode for light-weight callbacks that won't slow down the handshake or block the main thread, like logging or simple configuration changes. + +In contrast, "non-blocking mode" will wait for the ClientHello callback to succeed and then pause the handshake, immediately returning from s2n_negotiate with an error indicating that the handshake is blocked on application input. This allows the application to do expensive or time-consuming work like network calls outside of the callback without blocking the main thread. Only when the application calls `s2n_client_hello_cb_done()` will the handshake be able to resume. diff --git a/docs/usage-guide/src/config.md b/docs/usage-guide/src/config.md new file mode 100644 index 00000000000..67d908c27f2 --- /dev/null +++ b/docs/usage-guide/src/config.md @@ -0,0 +1,14 @@ +# Configuring the Connection + +`s2n_config` objects are used to change the default settings of a s2n-tls connection. Use `s2n_config_new()` to create a new config object. To associate a config with a connection call `s2n_connection_set_config()`. A config should not be altered once it is associated with a connection as this will produce undefined behavior. It is not necessary to create a config object per connection; one config object should be used for many connections. Call `s2n_config_free()` to free the object when no longer needed. _Only_ free the config object when all connections using it have been freed. + +Calling `s2n_config_new()` can have a performance cost during config creation due to loading +default system certificates into the trust store (see [Configuring the Trust Store](./certificates.md#configuring-the-trust-store)). +For increased performance, use `s2n_config_new_minimal()` when system certificates are not needed +for certificate validation. + +Most commonly, a `s2n_config` object is used to set the certificate key pair for authentication and change the default security policy. See the sections for [certificates](./certificates.md) and [security policies](./security_policies.md) for more information on those settings. + +## Overriding the Config + +Some `s2n_config` settings can be overridden on a specific connection if desired. For example, `s2n_config_append_protocol_preference()` appends a list of ALPN protocols to a `s2n_config`. Calling the `s2n_connection_append_protocol_preference()` API will override the list of ALPN protocols for an individual connection. Not all config APIs have a corresponding connection API so if there is one missing contact us with an explanation on why it is required for your use-case. diff --git a/docs/usage-guide/src/connection.md b/docs/usage-guide/src/connection.md new file mode 100644 index 00000000000..e9896c5a43e --- /dev/null +++ b/docs/usage-guide/src/connection.md @@ -0,0 +1,26 @@ +# TLS Connections + +Users will need to create a `s2n_connection` struct to store all of the state necessary for a TLS connection. Call `s2n_connection_new()` to create a new server or client connection. Call `s2n_connection_free()` to free the memory allocated for this struct when no longer needed. + +## Connection Memory + +The connection struct is roughly 4KB with some variation depending on how it is configured. Maintainers of the s2n-tls library carefully consider increases to the size of the connection struct as they are aware some users are memory-constrained. + +A connection struct has memory allocated specifically for the TLS handshake. Memory-constrained users can free that memory by calling `s2n_connection_free_handshake()` after the handshake is successfully negotiated. Note that the handshake memory can be reused for another connection if `s2n_connection_wipe()` is called, so freeing it may result in more memory allocations later. Additionally some functions that print information about the handshake may not produce meaningful results after the handshake memory is freed. + +The input and output buffers consume the most memory on the connection after the handshake. It may not be necessary to keep these buffers allocated when a connection is in a keep-alive or idle state. Call `s2n_connection_release_buffers()` to wipe and free the `in` and `out` buffers associated with a connection to reduce memory overhead of long-lived connections. + +## Connection Reuse + +Connection objects can be re-used across many connections to reduce memory allocation. Calling `s2n_connection_wipe()` will wipe an individual connection's state and allow the connection object to be re-used for a new TLS connection. + +## Connection Info + +s2n-tls provides many methods to retrieve details about the handshake and connection, such as the parameters negotiated with the peer. For a full list, see our [doxygen guide](https://aws.github.io/s2n-tls/doxygen/). + +### Protocol Version + +s2n-tls provides multiple different methods to get the TLS protocol version of the connection. They should be called after the handshake has completed. +* `s2n_connection_get_actual_protocol_version()`: The actual TLS protocol version negotiated during the handshake. This is the primary value referred to as "protocol_version", and the most commonly used. +* `s2n_connection_get_server_protocol_version()`: The highest TLS protocol version the server supports. +* `s2n_connection_get_client_protocol_version()`: The highest TLS protocol version the client advertised. diff --git a/docs/usage-guide/src/early_data.md b/docs/usage-guide/src/early_data.md new file mode 100644 index 00000000000..29024d70e7e --- /dev/null +++ b/docs/usage-guide/src/early_data.md @@ -0,0 +1,131 @@ +# Early Data or 0-RTT Data + +TLS1.3 introduced the ability for clients to send data before completing the handshake when using external pre-shared keys or session resumption. + +**WARNING:** Early data does not have the same security properties as regular data sent after a successful handshake. +* It is not forward secret. If the PSK or session resumption secret is compromised, then the early data is also compromised. +* It is susceptible to replay attacks unless proper precautions are taken. Early data can be captured and successfully resent by an attacker. See [the TLS1.3 RFC section on replay attacks](https://tools.ietf.org/rfc/rfc8446#appendix-E.5) for more details, and [Adding anti-replay protection](#adding-anti-replay-protection) for how to implement counter measures. + +_**Do not enable early data for your application unless you have understood and mitigated the risks.**_ + +## Configuring Session Resumption for Early Data + +To use early data with session tickets, early data must be enabled on a server by setting the maximum early data allowed to a non-zero value with `s2n_config_set_server_max_early_data_size()` or `s2n_connection_set_server_max_early_data_size()`. The server then begins issuing tickets that support early data, and clients can use early data when they use those tickets. + +## Configuring External Pre-shared Keys for Early Data + +To use early data with pre-shared keys, individual pre-shared keys must support early data. In addition to configuring the maximum early data allowed, each pre-shared key needs an associated cipher suite and if applicable, application protocol. The server only accepts early data if the pre-shared key's associated cipher suite and application protocol match the cipher suite and the application protocol negotiated during the handshake. + +The maximum early data allowed and cipher suite can be set with `s2n_psk_configure_early_data()`. If the connection will negotiate an application protocol then the expected application protocol can be set with `s2n_psk_set_application_protocol()`. + +## Sending Early Data + +To send early data, your application should call `s2n_send_early_data()` before it calls `s2n_negotiate()`. + +`s2n_connection_get_remaining_early_data_size()` can be called to check how much more early data the client is allowed to send. If `s2n_send_early_data()` exceeds the allowed maximum, s2n-tls returns a usage error. + +Like other IO functions, `s2n_send_early_data()` can potentially fail repeatedly with a blocking error before it eventually succeeds: see [I/O Functions](./io.md) for more information. An application can stop calling `s2n_send_early_data()` at any time, even if the function has not returned success yet. If `s2n_send_early_data()` does return success, the connection is ready to complete the handshake and begin sending normal data. However, `s2n_send_early_data()` can continue to be called to send more early data if desired. + +Once a client finishes sending early data, you should call `s2n_negotiate()` to complete the handshake just as you would for a handshake that did not include early data. + +For example: +``` +uint8_t early_data[] = "early data to send"; +ssize_t total_data_sent = 0, len = sizeof(early_data); +while (total_data_sent < len) { + ssize_t data_sent = 0; + int r = s2n_send_early_data(client_conn, early_data + total_data_sent, + len - total_data_sent, &data_sent, &blocked); + total_data_sent += data_sent; + if (r == S2N_SUCCESS) { + break; + } else if (s2n_error_get_type(s2n_errno) != S2N_ERR_T_BLOCKED) { + exit(1); + } +} +while (s2n_negotiate(client_conn, &blocked) != S2N_SUCCESS) { + if (s2n_error_get_type(s2n_errno) != S2N_ERR_T_BLOCKED) { + exit(1); + } +} +``` + +## Receiving Early Data + +To receive early data, your application should call `s2n_recv_early_data()` before it calls `s2n_negotiate()`. + +Like other S2N IO functions, `s2n_recv_early_data()` can potentially fail repeatedly with a blocking error before it eventually succeeds: see [I/O Functions](./io.md) for more information. Once `s2n_recv_early_data()` has been called, it must be called until it returns success. If an application stops calling `s2n_recv_early_data()` early, some early data may be left unread and cause later calls to `s2n_negotiate()` to return fatal errors. Calling `s2n_recv_early_data()` again after it returns success is possible but has no effect on the connection. + +Once a server has read all early data, you should call `s2n_negotiate()` to complete the handshake just as you would for a handshake that did not include early data. + +For example: +``` +uint8_t early_data[MAX_EARLY_DATA] = { 0 }; +ssize_t total_data_recv = 0, data_recv = 0; +while (s2n_recv_early_data(conn, early_data + total_data_recv, MAX_EARLY_DATA - total_data_recv, + &data_recv, &blocked) != S2N_SUCCESS) { + total_data_recv += data_recv; + if (s2n_error_get_type(s2n_errno) != S2N_ERR_T_BLOCKED) { + exit(1); + } +} +while (s2n_negotiate(conn, &blocked) != S2N_SUCCESS) { + if (s2n_error_get_type(s2n_errno) != S2N_ERR_T_BLOCKED) { + exit(1); + } +} +``` + +## Adding Anti-replay Protection +**s2n-tls does not include anti-replay protection automatically.** Effective anti-replay protection for a multi-server application requires an external state shared by all servers. Without shared state, an attacker can capture early data originally sent to server A and successfully replay it against server B. + +The TLS1.3 specification suggests two possible anti-replay solutions that a user can implement: +1. [Single-Use Tickets](https://tools.ietf.org/rfc/rfc8446#section-8.1): Valid tickets are stored in a shared database and deleted after use. `s2n_connection_get_negotiated_psk_identity_length()` and `s2n_connection_get_negotiated_psk_identity()` can be used to get the ticket identifier, or "pre-shared key identity", associated with offered early data. +2. [Client Hello Recording](https://tools.ietf.org/rfc/rfc8446#section-8.2): Instead of recording outstanding valid tickets, unique values from recent ClientHellos can be stored. The client hello message can be retrieved with `s2n_connection_get_client_hello()` and the pre-shared key identity can be retrieved with `s2n_connection_get_negotiated_psk_identity_length()` and `s2n_connection_get_negotiated_psk_identity()`, but s2n-tls does not currently provide methods to retrieve the validated binders or the ClientHello.random. + +The `s2n_early_data_cb()` can be used to hook an anti-replay solution into s2n-tls. The callback can be configured by using `s2n_config_set_early_data_cb()`. Using the **s2n_offered_early_data** pointer offered by the callback, `s2n_offered_early_data_reject()` or `s2n_offered_early_data_accept()` can accept or reject the client request to use early data. + +An example implementation: +``` +int s2n_early_data_cb_impl(struct s2n_connection *conn, struct s2n_offered_early_data *early_data) +{ + uint16_t identity_size = 0; + s2n_connection_get_negotiated_psk_identity_length(conn, &identity_size); + uint8_t *identity = malloc(identity_size); + s2n_connection_get_negotiated_psk_identity(conn, identity, identity_size); + + if (user_verify_single_use_ticket(identity)) { + s2n_offered_early_data_accept(early_data); + } else { + s2n_offered_early_data_reject(early_data); + } + + free(identity); + return S2N_SUCCESS; +} +``` + +The callback can also be implemented asynchronously by returning **S2N_SUCCESS** without either accepting or rejecting the early data. The handshake will then fail with an **S2N_ERR_T_BLOCKED** error type and **s2n_blocked_status** set to **S2N_BLOCKED_ON_APPLICATION_INPUT** until `s2n_offered_early_data_reject()` or `s2n_offered_early_data_accept()` is called asynchronously. + +An example asynchronous implementation: +``` +void *user_accept_or_reject_early_data(void *arg) +{ + struct s2n_offered_early_data *early_data = (struct s2n_offered_early_data *) arg; + if (user_slowly_verify_early_data(early_data)) { + s2n_offered_early_data_accept(early_data); + } else { + s2n_offered_early_data_reject(early_data); + } + return NULL; +} + +int s2n_early_data_cb_async_impl(struct s2n_connection *conn, struct s2n_offered_early_data *early_data) +{ + pthread_t thread_id; + pthread_create(&thread_id, NULL, user_accept_or_reject_early_data, (void *) early_data); + return S2N_SUCCESS; +} +``` + +`s2n_offered_early_data_get_context_length()` and `s2n_offered_early_data_get_context()` can be called to examine the optional user context associated with the early data. Unlike most s2n-tls callbacks, the context is not configured when the callback is set. Instead, the context is associated with the specific pre-shared key or session ticket used for early data. The context can be set for external pre-shared keys by calling `s2n_psk_set_early_data_context()`. For session tickets, `s2n_connection_set_server_early_data_context()` can be used to set the context the server includes on its new session tickets. Because the server needs to serialize the context when creating a new session ticket, the context is a byte buffer instead of the usual void pointer. diff --git a/docs/usage-guide/src/error_handling.md b/docs/usage-guide/src/error_handling.md new file mode 100644 index 00000000000..f32641175a7 --- /dev/null +++ b/docs/usage-guide/src/error_handling.md @@ -0,0 +1,77 @@ +# Error Handling + +s2n-tls functions that return 'int' return 0 to indicate success and -1 to indicate +failure. s2n-tls functions that return pointer types return NULL in the case of +failure. When an s2n-tls function returns a failure, s2n_errno will be set to a value +corresponding to the error. This error value can be translated into a string +explaining the error in English by calling `s2n_strerror(s2n_errno, "EN")`. +A string containing human readable error name, can be generated with `s2n_strerror_name()`. +A string containing internal debug information, including filename and line number, can be generated with `s2n_strerror_debug()`. +This string is useful to include when reporting issues to the s2n-tls development team. + +Example: + +``` +if (s2n_config_set_cipher_preferences(config, prefs) < 0) { + printf("Setting cipher prefs failed! %s : %s", s2n_strerror(s2n_errno, "EN"), s2n_strerror_debug(s2n_errno, "EN")); + return -1; +} +``` + +**NOTE**: To avoid possible confusion, s2n_errno should be cleared after processing an error: `s2n_errno = S2N_ERR_T_OK` + +When using s2n-tls outside of `C`, the address of the thread-local `s2n_errno` may be obtained by calling the `s2n_errno_location()` function. +This will ensure that the same TLS mechanisms are used with which s2n-tls was compiled. + +## Error Types + +s2n-tls organizes errors into different "types" to allow applications to handle error values without catching all possibilities. +Applications using non-blocking I/O should check the error type to determine if the I/O operation failed because it would block or for some other error. To retrieve the type for a given error use `s2n_error_get_type()`. +Applications should perform any error handling logic using these high level types: + +Here's an example that handles errors based on type: + +```c +#define SUCCESS 0 +#define FAILURE 1 +#define RETRY 2 + +s2n_errno = S2N_ERR_T_OK; +if (s2n_negotiate(conn, &blocked) < 0) { + switch(s2n_error_get_type(s2n_errno)) { + case S2N_ERR_T_BLOCKED: + /* Blocked, come back later */ + return RETRY; + case S2N_ERR_T_CLOSED: + return SUCCESS; + case S2N_ERR_T_IO: + handle_io_err(errno); + return FAILURE; + case S2N_ERR_T_PROTO: + handle_proto_err(); + return FAILURE; + case S2N_ERR_T_ALERT: + log_alert(s2n_connection_get_alert(conn)); + return FAILURE; + /* Everything else */ + default: + log_other_error(); + return FAILURE; + } +} +``` + +### Blinding + +Blinding is a mitigation against timing side-channels which in some cases can leak information about encrypted data. By default s2n-tls will cause a thread to sleep between 10 and 30 seconds whenever tampering is detected. + +Setting the `S2N_SELF_SERVICE_BLINDING` option with `s2n_connection_set_blinding()` turns off this behavior. This is useful for applications that are handling many connections in a single thread. In that case, if `s2n_recv()` or `s2n_negotiate()` return an error, self-service applications must call `s2n_connection_get_delay()` and pause activity on the connection for the specified number of nanoseconds before calling `close()` or `shutdown()`. `s2n_shutdown()` will fail if called before the blinding delay elapses. + +### Stacktraces +s2n-tls has an mechanism to capture stacktraces when errors occur. +This mechanism is off by default, but can be enabled in code by calling `s2n_stack_traces_enabled_set()`. +It can be enabled globally by setting the environment variable `S2N_PRINT_STACKTRACE=1`. + +Call `s2n_print_stacktrace()` to print your stacktrace. + +**Note:** Enabling stacktraces can significantly slow down unit tests, causing failures on tests (such as `s2n_cbc_verify`) that measure the timing of events. diff --git a/docs/usage-guide/src/initialization.md b/docs/usage-guide/src/initialization.md new file mode 100644 index 00000000000..3fd7e317024 --- /dev/null +++ b/docs/usage-guide/src/initialization.md @@ -0,0 +1,8 @@ +# Initialization and Teardown +The s2n-tls library must be initialized with `s2n_init()` before calling most library functions. `s2n_init()` MUST NOT be called more than once, even when an application uses multiple threads or processes. s2n attempts to clean up its thread-local memory at thread-exit and all other memory at process-exit. However, this may not work if you are using a thread library other than pthreads. In that case you should call `s2n_cleanup()` from every thread or process created after `s2n_init()`. + +Initialization can be modified by calling `s2n_crypto_disable_init()` or `s2n_disable_atexit()` before `s2n_init()`. + +An application can override s2n-tls’s internal memory management by calling `s2n_mem_set_callbacks` before calling s2n_init. + +If you are trying to use FIPS mode, you must enable FIPS in your libcrypto library (probably by calling `FIPS_mode_set(1)`) before calling `s2n_init()`. diff --git a/docs/usage-guide/src/introduction.md b/docs/usage-guide/src/introduction.md new file mode 100644 index 00000000000..dc8d7a9646c --- /dev/null +++ b/docs/usage-guide/src/introduction.md @@ -0,0 +1,2 @@ +# Introduction +This guide provides an overview of how to use the s2n-tls library. Chapters in this guide go over important concepts in the s2n-tls library and include explanations for how to use s2n-tls APIs to configure specific TLS features. diff --git a/docs/usage-guide/src/io.md b/docs/usage-guide/src/io.md new file mode 100644 index 00000000000..85368e21e35 --- /dev/null +++ b/docs/usage-guide/src/io.md @@ -0,0 +1,229 @@ +# Sending and Receiving +## Basic IO setup + +By default, s2n-tls sends and receives data using a provided file descriptor +(usually a socket) and the read/write system calls. The file descriptor can be set with +`s2n_connection_set_fd()`, or separate read and write file descriptors can be +set with `s2n_connection_set_read_fd()` and `s2n_connection_set_write_fd()`. +The provided file descriptor should be active and connected. + +In general the application is free to configure the file descriptor as preferred, +including socket options. s2n-tls itself sets a few socket options: +* If available, TCP_QUICKACK is used during the TLS handshake +* If available and enabled via `s2n_connection_use_corked_io()`, TCP_CORK is +used during the TLS handshake. TCP_NOPUSH or TCP_NODELAY may be used if TCP_CORK +is not available. + +**Important Note:** +If the read end of the pipe is closed unexpectedly, writing to the pipe will raise +a SIGPIPE signal. **s2n-tls does NOT handle SIGPIPE.** A SIGPIPE signal will cause +the process to terminate unless it is handled or ignored by the application. +See the [signal man page](https://linux.die.net/man/2/signal) for instructions on +how to handle C signals, or simply ignore the SIGPIPE signal by calling +`signal(SIGPIPE, SIG_IGN)` before calling any s2n-tls IO methods. + +## Blocking or Non-Blocking? + +s2n-tls supports both blocking and non-blocking I/O. +* In blocking mode, each s2n-tls I/O function will not return until it has completed +the requested IO operation. +* In non-blocking mode, s2n-tls I/O functions will immediately return, even if the socket couldn't +send or receive all the requested data. In this case, the I/O function will return `S2N_FAILURE`, +and `s2n_error_get_type()` will return `S2N_ERR_T_BLOCKED`. The I/O operation will have to be +called again in order to send or receive the remaining requested data. + +Some s2n-tls I/O functions take a `blocked` argument. If an I/O function returns an +`S2N_ERR_T_BLOCKED` error, the `blocked` argument will be set to a `s2n_blocked_status` value, +indicating what s2n-tls is currently blocked on. Note that unless an I/O function returns +`S2N_FAILURE` with an `S2N_ERR_T_BLOCKED` error, the `blocked` argument is meaningless, and should +not be used in any application logic. + +Servers in particular usually prefer non-blocking mode. In blocking mode, a single connection +blocks the thread while waiting for more IO. In non-blocking mode, multiple connections +can make progress by returning control while waiting for more IO using methods like +[`poll`](https://linux.die.net/man/2/poll) or [`select`](https://linux.die.net/man/2/select). + +To use s2n-tls in non-blocking mode, set the underlying file descriptors as non-blocking. +For example: +```c +int flags = fcntl(fd, F_GETFL, 0); +if (flags < 0) return S2N_FAILURE; +if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) return S2N_FAILURE; +``` + +## Errors and Alerts + +If the peer sends an alert, the next call to a read IO method will report **S2N_FAILURE** and +`s2n_error_get_type()` will return **S2N_ERR_T_ALERT**. The specific alert received +is available by calling `s2n_connection_get_alert()`. + +In TLS1.3, all alerts are fatal. s2n-tls also treats all alerts as fatal in earlier +versions of TLS by default. `s2n_config_set_alert_behavior()` can be called to +force s2n-tls to treat pre-TLS1.3 warning alerts as not fatal, but that behavior +is not recommended unless required for compatibility. In the past, attacks against +TLS have involved manipulating the alert level to disguise fatal alerts as warnings. + +If s2n-tls encounters a fatal error, the next call to a write IO method will send +a close_notify alert to the peer. Except for a few exceptions, s2n-tls does not +send specific alerts in order to avoid leaking information that could be used for +a sidechannel attack. To ensure that the alert is sent, `s2n_shutdown()` should +be called after an error. + +## Performing the TLS Handshake + +Before application data can be sent or received, an application must perform a handshake +to establish a TLS connection with the peer. + +To perform the handshake, call `s2n_negotiate()` until it either returns **S2N_SUCCESS** +or returns **S2N_FAILURE** without a **S2N_ERR_T_BLOCKED** error. + +For an example of how to perform a basic handshake, see [examples/s2n_negotiate.c](https://github.com/aws/s2n-tls/blob/main/docs/examples/s2n_negotiate.c) + +## Application Data + +After the TLS handshake, an application can send and receive encrypted data. + +Although most s2n-tls APIs are not thread-safe, `s2n_send()` and `s2n_recv()` +may be called simultaneously from two different threads. This means that an +application may have one thread calling `s2n_send()` and one thread calling `s2n_recv()`, +but NOT multiple threads calling `s2n_recv()` or multiple threads calling `s2n_send()`. + +Even if an application only intends to send data or only intends to receive data, +it should implement both send and receive in order to handle alerts and post-handshake +TLS control messages like session tickets. + +### Sending Application Data + +`s2n_send()` and its variants encrypt and send application data to the peer. +The sending methods return the number of bytes written and may indicate a partial +write. Partial writes are possible not just for non-blocking I/O, but also for +connections aborted while active. + +A single call to `s2n_send()` may involve multiple system calls to write the +provided application data. s2n-tls breaks the application data into fixed-sized +records before encryption, and calls write for each record. +[See the record size documentation for how record size may impact performance](https://github.com/aws/s2n-tls/blob/main/docs/USAGE-GUIDE.md#record-sizes). + +In non-blocking mode, `s2n_send()` will send data from the provided buffer and return the number of +bytes sent, as long as the socket was able to send at least 1 byte. If no bytes could be sent on the +socket, `s2n_send()` will return `S2N_FAILURE`, and `s2n_error_get_type()` will return +`S2N_ERR_T_BLOCKED`. To ensure that all the provided data gets sent, applications should continue +calling `s2n_send()` until the return values across all calls have added up to the length of the +data, or until `s2n_send()` returns an `S2N_ERR_T_BLOCKED` error. After an `S2N_ERR_T_BLOCKED` +error is returned, applications should call `s2n_send()` again only after the socket is +able to send more data. This can be determined by using methods like +[`poll`](https://linux.die.net/man/2/poll) or [`select`](https://linux.die.net/man/2/select). + +Unlike OpenSSL, repeated calls to `s2n_send()` should not duplicate the original +parameters, but should update the inputs per the indication of size written. + +`s2n_sendv_with_offset()` behaves like `s2n_send()`, but supports vectorized buffers. +The offset input should be updated between calls to reflect the data already written. + +`s2n_sendv()` also supports vectorized buffers, but assumes an offset of 0. +Because of this assumption, a caller would have to make sure that the input vectors +are updated to account for a partial write. Therefore `s2n_sendv_with_offset()` +is preferred. + +For examples of how to send `data` of length `data_size` with `s2n_send()` +or `s2n_sendv_with_offset()`, see [examples/s2n_send.c](https://github.com/aws/s2n-tls/blob/main/docs/examples/s2n_send.c) + +### Receiving Application Data + +`s2n_recv()` reads and decrypts application data from the peer, copying it into +the application-provided output buffer. It returns the number of bytes read, and +may indicate a partial read even if blocking IO is used. +It returns "0" to indicate that the peer has shutdown the connection. + +By default, `s2n_recv()` will return after reading a single TLS record. `s2n_recv()` can be called +repeatedly to read multiple records. To allow `s2n_recv()` to read multiple records with a single +call, use `s2n_config_set_recv_multi_record()`. + +In non-blocking mode, `s2n_recv()` will read data into the provided buffer and return the number of +bytes read, as long as at least 1 byte was read from the socket. If no bytes could be read from the +socket, `s2n_recv()` will return `S2N_FAILURE`, and `s2n_error_get_type()` will return +`S2N_ERR_T_BLOCKED`. To ensure that all data on the socket is properly received, applications +should continue calling `s2n_recv()` until it returns an `S2N_ERR_T_BLOCKED` error. After an +`S2N_ERR_T_BLOCKED` error is returned, applications should call `s2n_recv()` again only after the +socket has received more data. This can be determined by using methods like +[`poll`](https://linux.die.net/man/2/poll) or [`select`](https://linux.die.net/man/2/select). + +Unlike OpenSSL, repeated calls to `s2n_recv()` should not duplicate the original parameters, +but should update the inputs per the indication of size read. + +For an example of how to read all the data sent by the peer into one buffer, +see `s2n_example_recv()` in [examples/s2n_recv.c](https://github.com/aws/s2n-tls/blob/main/docs/examples/s2n_recv.c) + +For an example of how to echo any data sent by the peer, +see `s2n_example_recv_echo()` in [examples/s2n_recv.c](https://github.com/aws/s2n-tls/blob/main/docs/examples/s2n_recv.c) + +`s2n_peek()` can be used to check if more application data may be returned +from `s2n_recv()` without performing another read from the file descriptor. +This is useful when using `select()` on the underlying s2n-tls file descriptor, because +a call to `s2n_recv()` may read more data into s2n-tls's internal buffer than +was requested or can fit into the application-provided output buffer. This extra +application data will be returned by the next call to `s2n_recv()`, but `select()` +will be unable to tell the application that there is more data available and that +`s2n_recv()` should be called again. An application can solve this problem by +calling `s2n_peek()` to determine if `s2n_recv()` needs to be called again. + +## Closing the Connection + +`s2n_shutdown()` attempts a graceful closure at the TLS layer. It does not close the +underlying transport. The call may block on either reading or writing. + +`s2n_shutdown()` should be called after an error in order to ensure that s2n-tls +sends an alert to notify the peer of the failure. + +`s2n_shutdown()` will discard any application data received from the peer. This +can lead to data truncation, so `s2n_shutdown_send()` may be preferred for TLS1.3 +connections where the peer continues sending after the application initiates +shutdown. See [Closing the connection for writes](#closing-the-connection-for-writes) +below. + +Because `s2n_shutdown()` attempts a graceful shutdown, it will not return success +unless a close_notify alert is successfully both sent and received. As a result, +`s2n_shutdown()` may fail when interacting with a non-conformant TLS implementation +or if called on a connection in a bad state. + +Once `s2n_shutdown()` is complete: +* The s2n_connection handle cannot be used for reading or writing. +* The underlying transport can be closed, most likely via `shutdown()` or `close()`. +* The s2n_connection handle can be freed via `s2n_connection_free()` or reused +via `s2n_connection_wipe()` + +### Closing the connection for writes + +TLS1.3 supports closing the write side of a TLS connection while leaving the read +side unaffected. This indicates "end-of-data" to the peer without preventing +future reads. This feature is usually referred to as "half-close". + +s2n-tls offers the `s2n_shutdown_send()` method to close the write side of +a connection. Unlike `s2n_shutdown()`, it does not wait for the peer to respond +with a close_notify alert and does not discard any incoming application data. An +application can continue to call `s2n_recv()` after a call to `s2n_shutdown_send()`. + +`s2n_shutdown_send()` may still be called for earlier TLS versions, but most +TLS implementations will react by immediately discarding any pending writes and +closing the connection. + +If `s2n_shutdown_send()` is used, the application should still call `s2n_shutdown()` +or wait for `s2n_recv()` to return 0 to indicate end-of-data before cleaning up +the connection or closing the read side of the underlying transport. + +## Custom IO Callbacks + +By default, s2n-tls sends and receives data using a provided file descriptor +(usually a socket) and the read/write system calls. To change this default behavior, +an application can implement custom send and receive methods using `s2n_connection_set_recv_cb()` +and `s2n_connection_set_send_cb()`. +The application can pass inputs (such as a file descriptor or destination buffer) +to the custom IO methods by using `s2n_connection_set_recv_ctx()` and `s2n_connection_set_send_ctx()`. +s2n-tls will call the custom IO methods with the custom context instead of calling +the default implementation. + +The custom IO methods may send or receive less than the requested length. They +should return the number of bytes sent/received, or set errno and return an error code < 0. +s2n-tls will interpret errno set to EWOULDBLOCK or EAGAIN as indicating a retriable +blocking error, and set **s2n_errno** and the s2n_blocked_status appropriately. +s2n-tls will interpret a return value of 0 as a closed connection. diff --git a/docs/usage-guide/src/preshared_keys.md b/docs/usage-guide/src/preshared_keys.md new file mode 100644 index 00000000000..1214906407a --- /dev/null +++ b/docs/usage-guide/src/preshared_keys.md @@ -0,0 +1,59 @@ +# Pre-shared Keys + +s2n-tls supports pre-shared keys (PSKs) as of TLS1.3. PSKs allow users to establish secrets outside of the handshake, skipping certificate exchange and authentication. + +## Benefits of Using Pre-Shared Keys + +Using pre-shared keys can avoid the need for public key operations. This is useful in performance-constrained environments with limited CPU power. PSKs may also be more convenient from a key management point of view: If the system already has a mechanism for sharing secrets, that mechanism can be reused for TLS PSKs. + +## Security Considerations + +A PSK must not be shared between more than one server and one client. An entity that acts as both a server and a client should not use the same PSK for both roles. For more information see: [Selfie: reflections on TLS 1.3 with PSK.](https://eprint.iacr.org/2019/347.pdf) + + +## Configuring External Pre-Shared Keys + +Both clients and servers will need to create and append a PSK to a connection in order to negotiate that PSK. Call `s2n_external_psk_new()` to allocate memory for a PSK object. Call `s2n_psk_set_identity()` to set a unique identifier for the PSK. Note that this identity will be transmitted over the network unencrypted, so do not include any confidential information in it. Call `s2n_psk_set_secret()` to set the secret value for a given PSK. Deriving a shared secret from a password or other low-entropy source is _not_ secure and is subject to dictionary attacks. See [this RFC](https://www.rfc-editor.org/rfc/rfc9257.html#name-recommendations-for-externa) for more guidelines on creating a secure PSK secret. Call `s2n_psk_set_hmac()` to change the hmac algorithm (defaults to **S2N_PSK_HMAC_SHA256**) for a given PSK. Note that the hmac algorithm may influence server cipher-suite selection. + +Call `s2n_connection_append_psk()` to append the newly created PSK to the connection. Both the server and client should call this API to add PSKs to their connection. PSKs that are appended first will be preferred over PSKs appended last unless custom PSK selection logic is implemented. Use `s2n_psk_free()` to free the memory allocated for a PSK once you have associated it with a connection. + +External PSKs and Session Resumption cannot both be used in TLS13. Therefore, users must pick which mode they are using by calling `s2n_config_set_psk_mode()` prior to the handshake. Additionally, `s2n_connection_set_psk_mode()` overrides the PSK mode set on the config for a particular connection. + +## Selecting a Pre-Shared Key + +By default, a server chooses the first identity in its PSK list that also appears in the client's PSK list. The `s2n_psk_selection_callback` is available if you would like to implement your own PSK selection logic. Currently, this callback is not asynchronous. Call `s2n_config_set_psk_selection_callback()` to associate your `s2n_psk_selection_callback` with a config. + +The `s2n_psk_selection_callback` will provide the list of PSK identities sent by the client in the **psk_list** input parameter. You will need to create an offered PSK object by calling `s2n_offered_psk_new()` and pass this object as a parameter in `s2n_offered_psk_list_next()` in order to populate the offered PSK object. Call `s2n_offered_psk_list_has_next()` prior to calling `s2n_offered_psk_list_next()` to determine if there exists another PSK in the **psk_list**. Call `s2n_offered_psk_get_identity()` to get the identity of a particular **s2n_offered_psk**. + +Call `s2n_offered_psk_list_choose_psk()` to choose a particular **s2n_offered_psk** to be used for the connection. Note that the server must have already configured the corresponding PSK on the connection using `s2n_connection_append_psk()`. To disable PSKs for the connection and perform a full handshake instead, set the PSK identity to NULL. Call `s2n_offered_psk_free()` once you have chosen a particular PSK to free the memory allocated. + +If desired, `s2n_offered_psk_list_reread()` returns the offered PSK list to its original read state. After `s2n_offered_psk_list_reread()` is called, the next call to `s2n_offered_psk_list_next()` will return the first PSK in the offered PSK list. + +Use `s2n_connection_get_negotiated_psk_identity()` to retrieve the PSK identity selected by the server for the connection. + +In the following example, `s2n_psk_selection_callback` chooses the first client offered PSK identity present in an external store. + +```c +int s2n_psk_selection_callback(struct s2n_connection *conn, void *context, + struct s2n_offered_psk_list *psk_list) +{ + struct s2n_offered_psk *offered_psk = s2n_offered_psk_new(); + + while (s2n_offered_psk_list_has_next(psk_list)) { + uint8_t *client_psk_id = NULL; + uint16_t client_psk_id_len = 0; + + s2n_offered_psk_list_next(psk_list, offered_psk); + s2n_offered_psk_get_identity(offered_psk, &client_psk_id, &client_psk_id_len); + struct s2n_psk *psk = user_lookup_identity_db(client_psk_id, client_psk_id_len); + + if (psk) { + s2n_connection_append_psk(conn, psk); + s2n_offered_psk_list_choose_psk(psk_list, offered_psk); + break; + } + } + s2n_offered_psk_free(&offered_psk); + return S2N_SUCCESS; +} +``` diff --git a/docs/usage-guide/src/private_key_ops.md b/docs/usage-guide/src/private_key_ops.md new file mode 100644 index 00000000000..46f07c0b7ba --- /dev/null +++ b/docs/usage-guide/src/private_key_ops.md @@ -0,0 +1,77 @@ +# Offloading Private Key Operations +By default, s2n-tls automatically uses the configured private key to synchronously perform the signature +and decryption operations required for a tls handshake. However, this default behavior may not +work for some situations. + +For example: +* An application may want to perform the CPU-expensive signature and decryption operations +asynchronously to avoid blocking the main event loop. +See [Asynchronous private key operations](#asynchronous-private-key-operations) +* An application may not have direct access to the private key, such as when using PKCS#11. +See [Offloading private key operations](#offloading-private-key-operations-1) + +To handle these use cases, s2n-tls provides a callback to allow users to control how these operations +are performed. The callback is set via `s2n_config_set_async_pkey_callback()` and is triggered +every time `s2n_negotiate()` performs an action involving the private key. The callback is passed +**op**, an opaque object representing the private key operation. To avoid memory leaks, **op** must +always eventually be freed by calling `s2n_async_pkey_op_free()`. + +The private key operation can be performed by calling `s2n_async_pkey_op_perform()` +(or `s2n_async_pkey_op_set_output()`: see [Offloading private key operations](#offloading-private-key-operations-1)). +The required private key can be retrieved using the `s2n_connection_get_selected_cert()` and `s2n_cert_chain_and_key_get_private_key()` calls. The operation can then be finalized with `s2n_async_pkey_op_apply()` to continue the handshake. + +## Asynchronous Private Key Operations + +When s2n-tls is used in non-blocking mode, private key operations can be completed +asynchronously. This model can be useful to move execution of +CPU-heavy private key operations out of the main +event loop, preventing `s2n_negotiate()` from blocking the loop for a few +milliseconds each time the private key operation needs to be performed. + +To handle private key operations asynchronously, return from the callback without calling +`s2n_async_pkey_op_perform()` or `s2n_async_pkey_op_apply()`. Usually the user would do this +by spawning a separate thread to perform **op** and immediately returning **S2N_SUCCESS** +from the callback without waiting for that separate thread to complete. In response, +`s2n_negotiate()` will return **S2N_FAILURE** with an error of type **S2N_ERR_T_BLOCKED** +and **s2n_blocked_status** set to **S2N_BLOCKED_ON_APPLICATION_INPUT**. +All subsequent calls to `s2n_negotiate()` will produce the same result until `s2n_async_pkey_op_apply()` +is called to finalize the **op**. + +Note: It is not safe to call multiple functions on the same **conn** or +**op** objects from 2 different threads at the same time. Doing so will +produce undefined behavior. However it is safe to have a call to a +function involving only **conn** at the same time as a call to a +function involving only **op**, as those objects are not coupled with +each other. It is also safe to free **conn** or **op** at any moment with +respective function calls, with the exception that **conn** cannot +be freed inside the `s2n_async_pkey_fn()` callback. + +## Synchronous Private Key Operations + +Despite the "async" in the function names, private key operations can also be completed synchronously using the callback. +To complete an operation synchronously, simply call `s2n_async_pkey_op_perform()` and `s2n_async_pkey_op_apply()` inside the callback. +If the callback succeeds, the handshake will continue uninterrupted. +If the callback fails, `s2n_negotiate()` will fail with an error of type **S2N_ERR_T_INTERNAL**. + +## Offloading Private Key Operations + +The `s2n_async_pkey_op_perform()` call used to perform a private key operation requires +direct access to the private key. In some cases, like when using PKCS#11, users may not +have access to the private key. In these cases, we can substitute `s2n_async_pkey_op_set_output()` +for `s2n_async_pkey_op_perform()` to tell s2n-tls the result of the operation rather than +having s2n-tls perform the operation itself. + +s2n-tls provides a number of calls to gather the information necessary for +an outside module or library to perform the operation. The application can query the type of private +key operation by calling `s2n_async_pkey_op_get_op_type()`. In order to perform +an operation, the application must ask s2n-tls to copy the operation's input into an +application supplied buffer. The appropriate buffer size can be determined by calling +`s2n_async_pkey_op_get_input_size()`. Once a buffer of the proper size is +allocated, the application can request the input data by calling `s2n_async_pkey_op_get_input()`. +After the operation is completed, the finished output can be copied back to S2N by calling `s2n_async_pkey_op_set_output()`. +Once the output is set, the private key operation can be completed by calling `s2n_async_pkey_op_apply()` as usual. + +Offloading can be performed either synchronously or asynchronously. If the offloaded operation +fails synchronously, simply return **S2N_FAILURE** from the callback. If the offloaded operation +fails asynchronously, s2n-tls does not provide a way to communicate that result. Instead, +simply shutdown and cleanup the connection as you would for any other error. diff --git a/docs/usage-guide/src/record_sizes.md b/docs/usage-guide/src/record_sizes.md new file mode 100644 index 00000000000..ab529171dff --- /dev/null +++ b/docs/usage-guide/src/record_sizes.md @@ -0,0 +1,50 @@ +# TLS Record Sizes + +## Throughput vs Latency + +When sending data, s2n-tls uses a default maximum record size which experimentation +has suggested provides a reasonable balance of performance and throughput. + +`s2n_connection_prefer_throughput()` can be called to increase the record size, which +minimizes overhead. It also increases s2n-tls's memory usage. + +`s2n_connection_prefer_low_latency()` can be called to decrease the record size, which +allows the receiver to decrypt the data faster. It also decreases s2n-tls's memory usage. + +These options only affect the size of the records that s2n-tls sends, not the behavior +of the peer. + +## Maximum Fragment Length + +The maximum number of bytes that can be sent in a TLS record is called the "maximum fragment length", +and is set to 2^14 bytes by default. Regardless of the maximum record size that s2n-tls +uses when sending, it may receive records containing up to 2^14 bytes of plaintext. + +A client can request a lower maximum fragment length by calling `s2n_config_send_max_fragment_length()`, +reducing the size of TLS records sent and providing benefits similar to `s2n_connection_prefer_low_latency()`. +However, many TLS servers either ignore these requests or handle them incorrectly, so a client should +never assume that a lower maximum fragment length will be honored. If a server accepts the requested +maximum fragment length, the client will respect that maximum when sending. + +By default, an s2n-tls server will ignore a client's requested maximum fragment length. +If `s2n_config_accept_max_fragment_length()` is called, the server will respect the client's requested +maximum fragment length when sending, but will not reject client records with a larger fragment size. + +If a maximum fragment length is negotiated during the connection, it will override the behavior +configured by `s2n_connection_prefer_throughput()` and `s2n_connection_prefer_low_latency()`. + +## Dynamic Record Sizing + +Sending smaller records at the beginning of a connection can decrease first byte latency, +particularly if TCP slow start is used. + +`s2n_connection_set_dynamic_record_threshold()` can be called to initially send smaller records. +The connection will send the first **resize_threshold** bytes in records small enough to +fit in a single standard 1500 byte ethernet frame. Whenever **timeout_threshold** seconds +pass without sending data, the connection will revert to this behavior and send small records again. + +Dynamic record sizing doesn't completely override `s2n_connection_prefer_throughput()`, +`s2n_connection_prefer_low_latency()`, or the negotiated maximum fragment length. +Once **resize_threshold** is hit, records return to the maximum size configured for the connection. +And if the maximum fragment length negotiated with the peer is lower than what dynamic record sizing +would normally produce, the lower value will be used. diff --git a/docs/usage-guide/src/resumption.md b/docs/usage-guide/src/resumption.md new file mode 100644 index 00000000000..55bc249adbd --- /dev/null +++ b/docs/usage-guide/src/resumption.md @@ -0,0 +1,46 @@ +# Session Resumption +TLS handshake sessions are CPU-heavy due to the calculations involved in authenticating a certificate. These calculations can be skipped after the first connection by turning on session resumption. This mechanism stores state from the previous session and uses it to establish the next session, allowing the handshake to skip the costly authentication step while keeping the same cryptographic guarantees. The authentication step can be skipped because both the server and client will use their possession of the key from the previous session to prove who they are. We usually refer to the stored session state as a "session ticket". Note that this session ticket is encrypted by the server, so a server will have to set up an external key in order to do session resumption. + +## Session Ticket Key + +The key that encrypts and decrypts the session state is not related to the keys negotiated as part of the TLS handshake and has to be set by the server by calling `s2n_config_add_ticket_crypto_key()`. See [RFC5077](https://www.rfc-editor.org/rfc/rfc5077#section-5.5) for guidelines on securely generating keys. + +Each key has two different expiration dates. The first expiration date signifies the time that the key can be used for both encryption and decryption. The second expiration date signifies the time that the key can be used only for decryption. This mechanism is to ensure that a session ticket can be successfully decrypted if it was encrypted by a key that was about to expire. The full lifetime of the key is therefore the encrypt-decrypt lifetime plus the decrypt-only lifetime. To alter the default key lifetime call `s2n_config_set_ticket_encrypt_decrypt_key_lifetime()` and `s2n_config_set_ticket_decrypt_key_lifetime()`. + +The server will stop issuing session resumption tickets if a user doesn't set up a new key before the previous key passes through its encrypt-decrypt lifetime. Therefore it is recommended to add a new key when half of the previous key's encrypt-decrypt lifetime has passed. + +## Stateless Session Resumption + +In stateless session resumption the server sends a session ticket to a client after a successful handshake, and the client can send that ticket back to the server during a new connection to skip the authentication step. This mechanism allows servers to avoid storing individual state for each client, and for that reason is the preferred method for resuming a session. + +Servers should call `s2n_config_set_session_tickets_onoff()` to enable stateless session resumption. Additionally the server needs to set up an encryption key using `s2n_config_add_ticket_crypto_key()`. + +Clients should call `s2n_config_set_session_tickets_onoff()` to enable stateless session resumption and set a session ticket callback function using `s2n_config_set_session_ticket_cb()`, which will allow clients to receive a session ticket when it arrives. Then `s2n_connection_set_session()` should be called with that saved ticket when attempting to resume a new connection. + +## Stateful Session Resumption + +In stateful session resumption, also known as session caching, the server caches the session state per client and resumes a session based on the client's session ID. Note that session caching has not been implemented for > TLS1.2. If stateful session resumption is turned on and a TLS1.3 handshake is negotiated, the caching mechanism will not store that session and resumption will not be available the next time the client connects. + +Servers should set the three caching callback functions: `s2n_config_set_cache_store_callback()`, `s2n_config_set_cache_retrieve_callback()`, and `s2n_config_set_cache_delete_callback()` and then call `s2n_config_set_session_cache_onoff()` to enable stateful session resumption. Session caching will not be turned on unless all three session cache callbacks are set prior to calling `s2n_config_set_session_cache_onoff()`. Additionally, the server needs to set up an encryption key using `s2n_config_add_ticket_crypto_key()`. + +Clients should call `s2n_connection_get_session()` to retrieve some serialized state about the session. Then `s2n_connection_set_session()` should be called with that saved state when attempting to resume a new connection. + +## Session Resumption in TLS1.2 and TLS1.3 + +In TLS1.2, session ticket messages are sent during the handshake and are automatically received as part of calling `s2n_negotiate()`. They will be available as soon as negotiation is complete. + +In TLS1.3, session ticket messages are sent after the handshake as "post-handshake" messages, and may not be received as part of calling `s2n_negotiate()`. A s2n-tls server will send tickets immediately after the handshake, so clients can receive them by calling `s2n_recv()` immediately after the handshake completes. However, other server implementations may send their session tickets later, at any time during the connection. + +Additionally, in TLS1.3, multiple session tickets may be issued for the same connection. Servers can call `s2n_config_set_initial_ticket_count()` to set the number of tickets they want to send and `s2n_connection_add_new_tickets_to_send()` to increase the number of tickets to send during a connection. + +## Session Resumption Forward Secrecy + +In TLS1.2, the secret stored inside the ticket is the original session's master secret. Because of this, TLS1.2 session tickets are not forward secret, meaning that compromising the resumed session's secret exposes the original session's encrypted data. + +In contrast, in TLS1.3 the secret stored inside the ticket is _derived_ from the original session's master secret. The derivation uses a cryptographic operation that can't be reversed by an attacker to retrieve the original master secret. Therefore, TLS1.3 session tickets are forward secret, meaning compromising the resumed session's secret will not expose the original session's encrypted data. + +## Keying Material Lifetimes in TLS1.2 and TLS1.3 + +In TLS1.2, a full handshake can issue a session ticket encrypted with a specific session ticket encryption key. Connections that resume using that session ticket will not issue new session tickets. Therefore, the lifetime of the original "keying material"-- meaning the lifetime of any secret derived from the original full handshake-- is limited by the lifetime of the session ticket encryption key. Applications can set the session ticket encryption key lifetime with `s2n_config_set_ticket_encrypt_decrypt_key_lifetime()`. + +In TLS1.3, connections that resume using a session ticket CAN issue new session tickets. This is because TLS1.3 tickets are intended to be single-use, and each ticket contains a different secret: see [Session Resumption Forward Secrecy](#session-resumption-forward-secrecy). These new session tickets may be encrypted with newer session ticket encryption keys, allowing the original "keying material" to outlive the original session ticket encryption key. However, TLS1.3 enforces a specific separate "keying material" lifetime, which servers can configure with `s2n_connection_set_server_keying_material_lifetime()`. This effectively places a limit on how long sessions can be resumed before a new full handshake is required. diff --git a/docs/usage-guide/src/security_policies.md b/docs/usage-guide/src/security_policies.md new file mode 100644 index 00000000000..7b8b596ca6f --- /dev/null +++ b/docs/usage-guide/src/security_policies.md @@ -0,0 +1,115 @@ +# Security Policies + +s2n-tls uses pre-made security policies to help avoid common misconfiguration mistakes for TLS. + +`s2n_config_set_cipher_preferences()` sets a security policy, which includes the cipher/kem/signature/ecc preferences and protocol version. + +### Chart: Security Policy Version To Protocol Version And Ciphersuites + +The following chart maps the security policy version to protocol version and ciphersuites supported. + +| version | TLS1.0 | TLS1.1 | TLS1.2 | TLS1.3 | AES-CBC | AES-GCM | CHACHAPOLY | 3DES | RC4 | DHE | ECDHE | RSA kx | +|---------------|--------|--------|--------|--------|---------|---------|------------|------|-----|-----|-------|--------| +| 20230317 | | | X | X | X | X | | | | | X | | +| default | X | X | X | | X | X | X | | | | X | X | +| default_tls13 | X | X | X | X | X | X | X | | | | X | X | +| default_fips | | | X | | X | X | | | | X | X | | +| 20190214 | X | X | X | | X | X | | X | | X | X | X | +| 20170718 | X | X | X | | X | X | | | | | X | X | +| 20170405 | X | X | X | | X | X | | X | | | X | X | +| 20170328 | X | X | X | | X | X | | X | | X | X | X | +| 20170210 | X | X | X | | X | X | X | | | | X | X | +| 20160824 | X | X | X | | X | X | | | | | X | X | +| 20160804 | X | X | X | | X | X | | X | | | X | X | +| 20160411 | X | X | X | | X | X | | X | | | X | X | +| 20150306 | X | X | X | | X | X | | X | | | X | X | +| 20150214 | X | X | X | | X | X | | X | | X | | X | +| 20150202 | X | X | X | | X | | | X | | X | | X | +| 20141001 | X | X | X | | X | | | X | X | X | | X | +| 20190120 | X | X | X | | X | X | X | X | | | X | X | +| 20190121 | X | X | X | | X | X | X | X | | | X | X | +| 20190122 | X | X | X | | X | X | X | X | | | X | X | +| 20190801 | X | X | X | X | X | X | X | | | | X | X | +| 20190802 | X | X | X | X | X | X | X | | | | X | X | +| 20200207 | | | | X | | X | X | | | | X | | +| rfc9151 | | | X | X | | X | | | | X | X | X | + +The "default", "default_tls13", and "default_fips" versions are special in that they will be updated with future s2n-tls changes and ciphersuites and protocol versions may be added and removed, or their internal order of preference might change. Numbered versions are fixed and will never change. +In general, customers prefer to use numbered versions for production use cases to prevent impact from library updates. + +"20230317" is a FIPS compliant policy. It offers more limited but more secure options than "default". It only supports TLS1.2 and TLS1.3. Consider this policy if you plan to enable FIPS mode or don't need or want to support less secure legacy options like TLS1.1 or SHA1. + +"20160411" follows the same general preference order as "default". The main difference is it has a CBC cipher suite at the top. This is to accommodate certain Java clients that have poor GCM implementations. Users of s2n-tls who have found GCM to be hurting performance for their clients should consider this version. + +"rfc9151" is derived from [Commercial National Security Algorithm (CNSA) Suite Profile for TLS and DTLS 1.2 and 1.3](https://datatracker.ietf.org/doc/html/rfc9151). This policy restricts the algorithms allowed for signatures on certificates in the certificate chain to RSA or ECDSA with sha384, which may require you to update your certificates. + +s2n-tls does not expose an API to control the order of preference for each ciphersuite or protocol version. s2n-tls follows the following order: + +*NOTE*: All ChaCha20-Poly1305 cipher suites will not be available if s2n-tls is not built with an Openssl 1.1.1 libcrypto. The underlying encrypt/decrypt functions are not available in older versions. + +1. Always prefer the highest protocol version supported +2. Always use forward secrecy where possible. Prefer ECDHE over DHE. +3. Prefer encryption ciphers in the following order: AES128, AES256, ChaCha20, 3DES, RC4. +4. Prefer record authentication modes in the following order: GCM, Poly1305, SHA256, SHA1, MD5. + +#### ChaCha20 Boosting + +s2n-tls usually prefers AES over ChaCha20. However, some clients-- particularly mobile or IOT devices-- do not support AES hardware acceleration, making AES less efficient and performant than ChaCha20. In this case, clients will indicate their preference for ChaCha20 by listing it first during cipher suite negotiation. Usually s2n-tls servers ignore client preferences, but s2n-tls offers "ChaCha20 boosted" security policies that will choose ChaCha20 over AES if the client indicates a preference for ChaCha20. This is available in the "CloudFront-TLS-1-2-2021-ChaCha20-Boosted" policy, which is identical to the "CloudFront-TLS-1-2-2021" policy listed above but with ChaCha20 Boosting enabled. + +### Chart: Security Policy Version To Supported Signature Schemes + +| version | RSA PKCS1 | ECDSA | SHA-1 Legacy | RSA PSS | +|---------------|-----------|-------|--------------|---------| +| 20230317 | X | X | | X | +| default | X | | X | | +| default_tls13 | X | X | X | X | +| default_fips | X | X | | | +| 20190214 | X | X | X | | +| 20170718 | X | | X | | +| 20170405 | X | | X | | +| 20170328 | X | | X | | +| 20170210 | X | | X | | +| 20160824 | X | | X | | +| 20160804 | X | | X | | +| 20160411 | X | | X | | +| 20150306 | X | | X | | +| 20150214 | X | | X | | +| 20150202 | X | | X | | +| 20141001 | X | | X | | +| 20190120 | X | | X | | +| 20190121 | X | | X | | +| 20190122 | X | | X | | +| 20190801 | X | X | X | X | +| 20190802 | X | X | X | X | +| 20200207 | | X | | X | +| rfc9151 | X | X | | X | + +Note that legacy SHA-1 algorithms are not supported in TLS1.3. Legacy SHA-1 algorithms will be supported only if TLS1.2 has been negotiated and the security policy allows them. + +### Chart: Security policy version to supported curves/groups + +| version | secp256r1 | secp384r1 | x25519 | +|---------------|-----------|-----------|--------| +| 20230317 | X | X | | +| default | X | X | | +| default_tls13 | X | X | X | +| default_fips | X | X | | +| 20190214 | X | X | | +| 20170718 | X | X | | +| 20170405 | X | X | | +| 20170328 | X | X | | +| 20170210 | X | X | | +| 20160824 | X | X | | +| 20160804 | X | X | | +| 20160411 | X | X | | +| 20150306 | X | X | | +| 20150214 | | | | +| 20150202 | | | | +| 20141001 | | | | +| 20190120 | X | X | | +| 20190121 | X | X | | +| 20190122 | X | X | | +| 20190801 | X | X | X | +| 20190802 | X | X | | +| 20200207 | X | X | X | +| rfc9151 | | X | | From 5021675f42bf3abf6ce2976050648f5b443dc73e Mon Sep 17 00:00:00 2001 From: Appelmans Date: Thu, 7 Dec 2023 17:24:39 -0800 Subject: [PATCH 2/7] Changed folder name --- docs/usage-guide/book.toml | 2 +- docs/usage-guide/{src => topics}/SUMMARY.md | 0 docs/usage-guide/{src => topics}/api.md | 8 ++------ docs/usage-guide/{src => topics}/certificates.md | 0 docs/usage-guide/{src => topics}/client_hello.md | 0 docs/usage-guide/{src => topics}/config.md | 0 docs/usage-guide/{src => topics}/connection.md | 0 docs/usage-guide/{src => topics}/early_data.md | 0 docs/usage-guide/{src => topics}/error_handling.md | 0 docs/usage-guide/{src => topics}/initialization.md | 0 docs/usage-guide/{src => topics}/introduction.md | 0 docs/usage-guide/{src => topics}/io.md | 0 docs/usage-guide/{src => topics}/preshared_keys.md | 0 docs/usage-guide/{src => topics}/private_key_ops.md | 0 docs/usage-guide/{src => topics}/record_sizes.md | 0 docs/usage-guide/{src => topics}/resumption.md | 0 docs/usage-guide/{src => topics}/security_policies.md | 5 +++++ 17 files changed, 8 insertions(+), 7 deletions(-) rename docs/usage-guide/{src => topics}/SUMMARY.md (100%) rename docs/usage-guide/{src => topics}/api.md (81%) rename docs/usage-guide/{src => topics}/certificates.md (100%) rename docs/usage-guide/{src => topics}/client_hello.md (100%) rename docs/usage-guide/{src => topics}/config.md (100%) rename docs/usage-guide/{src => topics}/connection.md (100%) rename docs/usage-guide/{src => topics}/early_data.md (100%) rename docs/usage-guide/{src => topics}/error_handling.md (100%) rename docs/usage-guide/{src => topics}/initialization.md (100%) rename docs/usage-guide/{src => topics}/introduction.md (100%) rename docs/usage-guide/{src => topics}/io.md (100%) rename docs/usage-guide/{src => topics}/preshared_keys.md (100%) rename docs/usage-guide/{src => topics}/private_key_ops.md (100%) rename docs/usage-guide/{src => topics}/record_sizes.md (100%) rename docs/usage-guide/{src => topics}/resumption.md (100%) rename docs/usage-guide/{src => topics}/security_policies.md (96%) diff --git a/docs/usage-guide/book.toml b/docs/usage-guide/book.toml index d34134a466f..bcc41d984e8 100644 --- a/docs/usage-guide/book.toml +++ b/docs/usage-guide/book.toml @@ -2,4 +2,4 @@ authors = [] language = "en" multilingual = false -src = "src" +src = "topics" diff --git a/docs/usage-guide/src/SUMMARY.md b/docs/usage-guide/topics/SUMMARY.md similarity index 100% rename from docs/usage-guide/src/SUMMARY.md rename to docs/usage-guide/topics/SUMMARY.md diff --git a/docs/usage-guide/src/api.md b/docs/usage-guide/topics/api.md similarity index 81% rename from docs/usage-guide/src/api.md rename to docs/usage-guide/topics/api.md index d1f1943d9d1..220f59bb6d1 100644 --- a/docs/usage-guide/src/api.md +++ b/docs/usage-guide/topics/api.md @@ -6,6 +6,8 @@ are intended to be stable (API and ABI) within major version numbers of s2n-tls and structures used in s2n-tls internally can not be considered stable and their parameters, names, and sizes may change. +Read [Error Handling](./error_handling.md) for information on processing API return values safely. + The [VERSIONING.rst](https://github.com/aws/s2n-tls/blob/main/VERSIONING.rst) document contains more details about s2n's approach to versions and API changes. ## API Reference @@ -18,12 +20,6 @@ Doxygen installation instructions are available at the [Doxygen](https://doxygen The doxygen documentation should be used in conjunction with this guide. -## Supported TLS Versions - -Currently TLS 1.2 is our default version, but we recommend TLS 1.3 where possible. To use TLS 1.3 you need a security policy that supports TLS 1.3. See the [Security Policies](#security-policies) section for more information. - -**Note:** s2n-tls does not support SSL2.0 for sending and receiving encrypted data, but does accept SSL2.0 hello messages. - ## Examples To understand the API it may be easiest to see examples in action. s2n-tls's [bin](https://github.com/aws/s2n-tls/blob/main/bin/) directory diff --git a/docs/usage-guide/src/certificates.md b/docs/usage-guide/topics/certificates.md similarity index 100% rename from docs/usage-guide/src/certificates.md rename to docs/usage-guide/topics/certificates.md diff --git a/docs/usage-guide/src/client_hello.md b/docs/usage-guide/topics/client_hello.md similarity index 100% rename from docs/usage-guide/src/client_hello.md rename to docs/usage-guide/topics/client_hello.md diff --git a/docs/usage-guide/src/config.md b/docs/usage-guide/topics/config.md similarity index 100% rename from docs/usage-guide/src/config.md rename to docs/usage-guide/topics/config.md diff --git a/docs/usage-guide/src/connection.md b/docs/usage-guide/topics/connection.md similarity index 100% rename from docs/usage-guide/src/connection.md rename to docs/usage-guide/topics/connection.md diff --git a/docs/usage-guide/src/early_data.md b/docs/usage-guide/topics/early_data.md similarity index 100% rename from docs/usage-guide/src/early_data.md rename to docs/usage-guide/topics/early_data.md diff --git a/docs/usage-guide/src/error_handling.md b/docs/usage-guide/topics/error_handling.md similarity index 100% rename from docs/usage-guide/src/error_handling.md rename to docs/usage-guide/topics/error_handling.md diff --git a/docs/usage-guide/src/initialization.md b/docs/usage-guide/topics/initialization.md similarity index 100% rename from docs/usage-guide/src/initialization.md rename to docs/usage-guide/topics/initialization.md diff --git a/docs/usage-guide/src/introduction.md b/docs/usage-guide/topics/introduction.md similarity index 100% rename from docs/usage-guide/src/introduction.md rename to docs/usage-guide/topics/introduction.md diff --git a/docs/usage-guide/src/io.md b/docs/usage-guide/topics/io.md similarity index 100% rename from docs/usage-guide/src/io.md rename to docs/usage-guide/topics/io.md diff --git a/docs/usage-guide/src/preshared_keys.md b/docs/usage-guide/topics/preshared_keys.md similarity index 100% rename from docs/usage-guide/src/preshared_keys.md rename to docs/usage-guide/topics/preshared_keys.md diff --git a/docs/usage-guide/src/private_key_ops.md b/docs/usage-guide/topics/private_key_ops.md similarity index 100% rename from docs/usage-guide/src/private_key_ops.md rename to docs/usage-guide/topics/private_key_ops.md diff --git a/docs/usage-guide/src/record_sizes.md b/docs/usage-guide/topics/record_sizes.md similarity index 100% rename from docs/usage-guide/src/record_sizes.md rename to docs/usage-guide/topics/record_sizes.md diff --git a/docs/usage-guide/src/resumption.md b/docs/usage-guide/topics/resumption.md similarity index 100% rename from docs/usage-guide/src/resumption.md rename to docs/usage-guide/topics/resumption.md diff --git a/docs/usage-guide/src/security_policies.md b/docs/usage-guide/topics/security_policies.md similarity index 96% rename from docs/usage-guide/src/security_policies.md rename to docs/usage-guide/topics/security_policies.md index 7b8b596ca6f..2eea2376080 100644 --- a/docs/usage-guide/src/security_policies.md +++ b/docs/usage-guide/topics/security_policies.md @@ -4,6 +4,11 @@ s2n-tls uses pre-made security policies to help avoid common misconfiguration mi `s2n_config_set_cipher_preferences()` sets a security policy, which includes the cipher/kem/signature/ecc preferences and protocol version. +## Supported TLS Versions + +Currently TLS 1.2 is our default version, but we recommend TLS 1.3 where possible. To use TLS 1.3 you need a security policy that supports TLS 1.3. +**Note:** s2n-tls does not support SSL2.0 for sending and receiving encrypted data, but does accept SSL2.0 hello messages. + ### Chart: Security Policy Version To Protocol Version And Ciphersuites The following chart maps the security policy version to protocol version and ciphersuites supported. From 984ce3089d69aaf907b917c0e8a004ecc990c195 Mon Sep 17 00:00:00 2001 From: Appelmans Date: Tue, 12 Dec 2023 10:27:43 -0800 Subject: [PATCH 3/7] Added prefixes to file names --- docs/usage-guide/topics/SUMMARY.md | 30 +++++++++---------- .../{introduction.md => ch00-introduction.md} | 0 .../topics/{api.md => ch01-api.md} | 0 ...itialization.md => ch02-initialization.md} | 0 ...ror_handling.md => ch03-error-handling.md} | 0 .../{connection.md => ch04-connection.md} | 0 .../topics/{config.md => ch05-config.md} | 0 ..._policies.md => ch06-security-policies.md} | 0 docs/usage-guide/topics/{io.md => ch07-io.md} | 0 .../{record_sizes.md => ch08-record-sizes.md} | 0 .../{certificates.md => ch09-certificates.md} | 0 .../{client_hello.md => ch10-client-hello.md} | 0 .../{resumption.md => ch11-resumption.md} | 0 ...ate_key_ops.md => ch12-private-key-ops.md} | 0 ...eshared_keys.md => ch13-preshared-keys.md} | 0 .../usage-guide/topics/ch13-preshared_keys.md | 1 + .../{early_data.md => ch14-early-data.md} | 0 17 files changed, 16 insertions(+), 15 deletions(-) rename docs/usage-guide/topics/{introduction.md => ch00-introduction.md} (100%) rename docs/usage-guide/topics/{api.md => ch01-api.md} (100%) rename docs/usage-guide/topics/{initialization.md => ch02-initialization.md} (100%) rename docs/usage-guide/topics/{error_handling.md => ch03-error-handling.md} (100%) rename docs/usage-guide/topics/{connection.md => ch04-connection.md} (100%) rename docs/usage-guide/topics/{config.md => ch05-config.md} (100%) rename docs/usage-guide/topics/{security_policies.md => ch06-security-policies.md} (100%) rename docs/usage-guide/topics/{io.md => ch07-io.md} (100%) rename docs/usage-guide/topics/{record_sizes.md => ch08-record-sizes.md} (100%) rename docs/usage-guide/topics/{certificates.md => ch09-certificates.md} (100%) rename docs/usage-guide/topics/{client_hello.md => ch10-client-hello.md} (100%) rename docs/usage-guide/topics/{resumption.md => ch11-resumption.md} (100%) rename docs/usage-guide/topics/{private_key_ops.md => ch12-private-key-ops.md} (100%) rename docs/usage-guide/topics/{preshared_keys.md => ch13-preshared-keys.md} (100%) create mode 100644 docs/usage-guide/topics/ch13-preshared_keys.md rename docs/usage-guide/topics/{early_data.md => ch14-early-data.md} (100%) diff --git a/docs/usage-guide/topics/SUMMARY.md b/docs/usage-guide/topics/SUMMARY.md index 74823cd703d..c840ddf7bca 100644 --- a/docs/usage-guide/topics/SUMMARY.md +++ b/docs/usage-guide/topics/SUMMARY.md @@ -1,17 +1,17 @@ # Summary -[Introduction](./introduction.md) -- [s2n-tls API](./api.md) -- [Initialization and Teardown](./initialization.md) -- [Error Handling](./error_handling.md) -- [TLS Connections](./connection.md) -- [Configuring the Connection](./config.md) -- [Security Policies](./security_policies.md) -- [IO](./io.md) -- [TLS Record Sizes](./record_sizes.md) -- [Certificates and Authentication](./certificates.md) -- [Examining the Client Hello](./client_hello.md) -- [Session Resumption](./resumption.md) -- [Offloading Private Key Operations](./private_key_ops.md) -- [Pre-shared Keys](./preshared_keys.md) -- [Early Data](./early_data.md) +[Introduction](./ch00-introduction.md) +- [s2n-tls API](./ch01-api.md) +- [Initialization and Teardown](./ch02-initialization.md) +- [Error Handling](./ch03-error-handling.md) +- [TLS Connections](./ch04-connection.md) +- [Configuring the Connection](./ch05-config.md) +- [Security Policies](./ch06-security-policies.md) +- [IO](./ch07-io.md) +- [TLS Record Sizes](./ch08-record-sizes.md) +- [Certificates and Authentication](./ch09-certificates.md) +- [Examining the Client Hello](./ch10-client-hello.md) +- [Session Resumption](./ch11-resumption.md) +- [Offloading Private Key Operations](./ch12-private-key-ops.md) +- [Pre-shared Keys](./ch13-preshared_keys.md) +- [Early Data](./ch14-early-data.md) diff --git a/docs/usage-guide/topics/introduction.md b/docs/usage-guide/topics/ch00-introduction.md similarity index 100% rename from docs/usage-guide/topics/introduction.md rename to docs/usage-guide/topics/ch00-introduction.md diff --git a/docs/usage-guide/topics/api.md b/docs/usage-guide/topics/ch01-api.md similarity index 100% rename from docs/usage-guide/topics/api.md rename to docs/usage-guide/topics/ch01-api.md diff --git a/docs/usage-guide/topics/initialization.md b/docs/usage-guide/topics/ch02-initialization.md similarity index 100% rename from docs/usage-guide/topics/initialization.md rename to docs/usage-guide/topics/ch02-initialization.md diff --git a/docs/usage-guide/topics/error_handling.md b/docs/usage-guide/topics/ch03-error-handling.md similarity index 100% rename from docs/usage-guide/topics/error_handling.md rename to docs/usage-guide/topics/ch03-error-handling.md diff --git a/docs/usage-guide/topics/connection.md b/docs/usage-guide/topics/ch04-connection.md similarity index 100% rename from docs/usage-guide/topics/connection.md rename to docs/usage-guide/topics/ch04-connection.md diff --git a/docs/usage-guide/topics/config.md b/docs/usage-guide/topics/ch05-config.md similarity index 100% rename from docs/usage-guide/topics/config.md rename to docs/usage-guide/topics/ch05-config.md diff --git a/docs/usage-guide/topics/security_policies.md b/docs/usage-guide/topics/ch06-security-policies.md similarity index 100% rename from docs/usage-guide/topics/security_policies.md rename to docs/usage-guide/topics/ch06-security-policies.md diff --git a/docs/usage-guide/topics/io.md b/docs/usage-guide/topics/ch07-io.md similarity index 100% rename from docs/usage-guide/topics/io.md rename to docs/usage-guide/topics/ch07-io.md diff --git a/docs/usage-guide/topics/record_sizes.md b/docs/usage-guide/topics/ch08-record-sizes.md similarity index 100% rename from docs/usage-guide/topics/record_sizes.md rename to docs/usage-guide/topics/ch08-record-sizes.md diff --git a/docs/usage-guide/topics/certificates.md b/docs/usage-guide/topics/ch09-certificates.md similarity index 100% rename from docs/usage-guide/topics/certificates.md rename to docs/usage-guide/topics/ch09-certificates.md diff --git a/docs/usage-guide/topics/client_hello.md b/docs/usage-guide/topics/ch10-client-hello.md similarity index 100% rename from docs/usage-guide/topics/client_hello.md rename to docs/usage-guide/topics/ch10-client-hello.md diff --git a/docs/usage-guide/topics/resumption.md b/docs/usage-guide/topics/ch11-resumption.md similarity index 100% rename from docs/usage-guide/topics/resumption.md rename to docs/usage-guide/topics/ch11-resumption.md diff --git a/docs/usage-guide/topics/private_key_ops.md b/docs/usage-guide/topics/ch12-private-key-ops.md similarity index 100% rename from docs/usage-guide/topics/private_key_ops.md rename to docs/usage-guide/topics/ch12-private-key-ops.md diff --git a/docs/usage-guide/topics/preshared_keys.md b/docs/usage-guide/topics/ch13-preshared-keys.md similarity index 100% rename from docs/usage-guide/topics/preshared_keys.md rename to docs/usage-guide/topics/ch13-preshared-keys.md diff --git a/docs/usage-guide/topics/ch13-preshared_keys.md b/docs/usage-guide/topics/ch13-preshared_keys.md new file mode 100644 index 00000000000..e31784ac2b6 --- /dev/null +++ b/docs/usage-guide/topics/ch13-preshared_keys.md @@ -0,0 +1 @@ +# Pre-shared Keys diff --git a/docs/usage-guide/topics/early_data.md b/docs/usage-guide/topics/ch14-early-data.md similarity index 100% rename from docs/usage-guide/topics/early_data.md rename to docs/usage-guide/topics/ch14-early-data.md From 326dd84acecee5641457b3cbd10fa79a56dee726 Mon Sep 17 00:00:00 2001 From: Appelmans Date: Tue, 12 Dec 2023 10:29:02 -0800 Subject: [PATCH 4/7] Fixed grammar --- docs/BUILD.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/BUILD.md b/docs/BUILD.md index bb9ee69bace..a47ccc681d8 100644 --- a/docs/BUILD.md +++ b/docs/BUILD.md @@ -68,7 +68,7 @@ cmake --install build Note that we currently do not support building on Windows. See https://github.com/aws/s2n-tls/issues/497 for more information. -## Consuming s2n-tls via. CMake +## Consuming s2n-tls via CMake s2n-tls ships with modern CMake finder scripts if CMake is used for the build. To take advantage of this from your CMake script, all you need to do to compile and link against s2n-tls in your project is: From dd35e798b488b66bb51d555a8e085c22e62b96fd Mon Sep 17 00:00:00 2001 From: Appelmans Date: Tue, 12 Dec 2023 13:17:17 -0800 Subject: [PATCH 5/7] Fixes broken links --- docs/usage-guide/topics/SUMMARY.md | 2 +- docs/usage-guide/topics/ch01-api.md | 2 +- docs/usage-guide/topics/ch05-config.md | 4 ++-- docs/usage-guide/topics/ch07-io.md | 2 +- docs/usage-guide/topics/ch09-certificates.md | 2 +- docs/usage-guide/topics/ch13-preshared_keys.md | 1 - docs/usage-guide/topics/ch14-early-data.md | 4 ++-- 7 files changed, 8 insertions(+), 9 deletions(-) delete mode 100644 docs/usage-guide/topics/ch13-preshared_keys.md diff --git a/docs/usage-guide/topics/SUMMARY.md b/docs/usage-guide/topics/SUMMARY.md index c840ddf7bca..b365246a4ca 100644 --- a/docs/usage-guide/topics/SUMMARY.md +++ b/docs/usage-guide/topics/SUMMARY.md @@ -13,5 +13,5 @@ - [Examining the Client Hello](./ch10-client-hello.md) - [Session Resumption](./ch11-resumption.md) - [Offloading Private Key Operations](./ch12-private-key-ops.md) -- [Pre-shared Keys](./ch13-preshared_keys.md) +- [Pre-shared Keys](./ch13-preshared-keys.md) - [Early Data](./ch14-early-data.md) diff --git a/docs/usage-guide/topics/ch01-api.md b/docs/usage-guide/topics/ch01-api.md index 220f59bb6d1..4d3c019d0b9 100644 --- a/docs/usage-guide/topics/ch01-api.md +++ b/docs/usage-guide/topics/ch01-api.md @@ -6,7 +6,7 @@ are intended to be stable (API and ABI) within major version numbers of s2n-tls and structures used in s2n-tls internally can not be considered stable and their parameters, names, and sizes may change. -Read [Error Handling](./error_handling.md) for information on processing API return values safely. +Read [Error Handling](./ch03-error-handling.md) for information on processing API return values safely. The [VERSIONING.rst](https://github.com/aws/s2n-tls/blob/main/VERSIONING.rst) document contains more details about s2n's approach to versions and API changes. diff --git a/docs/usage-guide/topics/ch05-config.md b/docs/usage-guide/topics/ch05-config.md index 67d908c27f2..6ffaa23c68c 100644 --- a/docs/usage-guide/topics/ch05-config.md +++ b/docs/usage-guide/topics/ch05-config.md @@ -3,11 +3,11 @@ `s2n_config` objects are used to change the default settings of a s2n-tls connection. Use `s2n_config_new()` to create a new config object. To associate a config with a connection call `s2n_connection_set_config()`. A config should not be altered once it is associated with a connection as this will produce undefined behavior. It is not necessary to create a config object per connection; one config object should be used for many connections. Call `s2n_config_free()` to free the object when no longer needed. _Only_ free the config object when all connections using it have been freed. Calling `s2n_config_new()` can have a performance cost during config creation due to loading -default system certificates into the trust store (see [Configuring the Trust Store](./certificates.md#configuring-the-trust-store)). +default system certificates into the trust store (see [Configuring the Trust Store](./ch09-certificates.md#configuring-the-trust-store)). For increased performance, use `s2n_config_new_minimal()` when system certificates are not needed for certificate validation. -Most commonly, a `s2n_config` object is used to set the certificate key pair for authentication and change the default security policy. See the sections for [certificates](./certificates.md) and [security policies](./security_policies.md) for more information on those settings. +Most commonly, a `s2n_config` object is used to set the certificate key pair for authentication and change the default security policy. See the sections for [certificates](./ch09-certificates.md) and [security policies](./ch06-security-policies.md) for more information on those settings. ## Overriding the Config diff --git a/docs/usage-guide/topics/ch07-io.md b/docs/usage-guide/topics/ch07-io.md index 85368e21e35..65e27db8acd 100644 --- a/docs/usage-guide/topics/ch07-io.md +++ b/docs/usage-guide/topics/ch07-io.md @@ -102,7 +102,7 @@ connections aborted while active. A single call to `s2n_send()` may involve multiple system calls to write the provided application data. s2n-tls breaks the application data into fixed-sized records before encryption, and calls write for each record. -[See the record size documentation for how record size may impact performance](https://github.com/aws/s2n-tls/blob/main/docs/USAGE-GUIDE.md#record-sizes). +[See the record size documentation for how record size may impact performance](./ch08-record-sizes.md). In non-blocking mode, `s2n_send()` will send data from the provided buffer and return the number of bytes sent, as long as the socket was able to send at least 1 byte. If no bytes could be sent on the diff --git a/docs/usage-guide/topics/ch09-certificates.md b/docs/usage-guide/topics/ch09-certificates.md index 2266d59fd2b..2c81640d8fc 100644 --- a/docs/usage-guide/topics/ch09-certificates.md +++ b/docs/usage-guide/topics/ch09-certificates.md @@ -2,7 +2,7 @@ TLS uses certificates to authenticate the server (and optionally the client). The handshake will fail if the client cannot verify the server’s certificate. -Authentication is usually the most expensive part of the handshake. To avoid the cost, consider using [session resumption](./resumption.md) or [pre-shared keys](./preshared_keys.md). +Authentication is usually the most expensive part of the handshake. To avoid the cost, consider using [session resumption](./ch11-resumption.md) or [pre-shared keys](./ch13-preshared-keys.md). ## Configuring the Trust Store diff --git a/docs/usage-guide/topics/ch13-preshared_keys.md b/docs/usage-guide/topics/ch13-preshared_keys.md deleted file mode 100644 index e31784ac2b6..00000000000 --- a/docs/usage-guide/topics/ch13-preshared_keys.md +++ /dev/null @@ -1 +0,0 @@ -# Pre-shared Keys diff --git a/docs/usage-guide/topics/ch14-early-data.md b/docs/usage-guide/topics/ch14-early-data.md index 29024d70e7e..54687d50b8c 100644 --- a/docs/usage-guide/topics/ch14-early-data.md +++ b/docs/usage-guide/topics/ch14-early-data.md @@ -24,7 +24,7 @@ To send early data, your application should call `s2n_send_early_data()` before `s2n_connection_get_remaining_early_data_size()` can be called to check how much more early data the client is allowed to send. If `s2n_send_early_data()` exceeds the allowed maximum, s2n-tls returns a usage error. -Like other IO functions, `s2n_send_early_data()` can potentially fail repeatedly with a blocking error before it eventually succeeds: see [I/O Functions](./io.md) for more information. An application can stop calling `s2n_send_early_data()` at any time, even if the function has not returned success yet. If `s2n_send_early_data()` does return success, the connection is ready to complete the handshake and begin sending normal data. However, `s2n_send_early_data()` can continue to be called to send more early data if desired. +Like other IO functions, `s2n_send_early_data()` can potentially fail repeatedly with a blocking error before it eventually succeeds: see [I/O Functions](./ch07-io.md) for more information. An application can stop calling `s2n_send_early_data()` at any time, even if the function has not returned success yet. If `s2n_send_early_data()` does return success, the connection is ready to complete the handshake and begin sending normal data. However, `s2n_send_early_data()` can continue to be called to send more early data if desired. Once a client finishes sending early data, you should call `s2n_negotiate()` to complete the handshake just as you would for a handshake that did not include early data. @@ -54,7 +54,7 @@ while (s2n_negotiate(client_conn, &blocked) != S2N_SUCCESS) { To receive early data, your application should call `s2n_recv_early_data()` before it calls `s2n_negotiate()`. -Like other S2N IO functions, `s2n_recv_early_data()` can potentially fail repeatedly with a blocking error before it eventually succeeds: see [I/O Functions](./io.md) for more information. Once `s2n_recv_early_data()` has been called, it must be called until it returns success. If an application stops calling `s2n_recv_early_data()` early, some early data may be left unread and cause later calls to `s2n_negotiate()` to return fatal errors. Calling `s2n_recv_early_data()` again after it returns success is possible but has no effect on the connection. +Like other S2N IO functions, `s2n_recv_early_data()` can potentially fail repeatedly with a blocking error before it eventually succeeds: see [I/O Functions](./ch07-io.md) for more information. Once `s2n_recv_early_data()` has been called, it must be called until it returns success. If an application stops calling `s2n_recv_early_data()` early, some early data may be left unread and cause later calls to `s2n_negotiate()` to return fatal errors. Calling `s2n_recv_early_data()` again after it returns success is possible but has no effect on the connection. Once a server has read all early data, you should call `s2n_negotiate()` to complete the handshake just as you would for a handshake that did not include early data. From e07f7501219a3f58a824399b6a816b906c976e38 Mon Sep 17 00:00:00 2001 From: Appelmans Date: Mon, 18 Dec 2023 17:06:38 -0800 Subject: [PATCH 6/7] Fixes links that will be broken --- README.md | 4 ++-- api/s2n.h | 12 ++++++------ bin/s2nc.c | 2 +- bin/s2nd.c | 2 +- docs/DEVELOPMENT-GUIDE.md | 2 +- docs/FAQ.md | 10 +++++----- error/s2n_errno.c | 2 +- libcrypto-build/README.md | 2 +- tls/s2n_config.h | 3 +-- tls/s2n_internal.h | 2 +- 10 files changed, 20 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index b983325e10b..19e91e33d70 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ If you have any questions about submitting PRs, s2n-tls API usage, or something ## Documentation -s2n-tls uses [Doxygen](https://doxygen.nl/index.html) to document its public API. The latest s2n-tls documentation can be found on [GitHub pages](https://aws.github.io/s2n-tls/doxygen/). The [Usage Guide](docs/USAGE-GUIDE.md) explains how different TLS features can be configured and used. +s2n-tls uses [Doxygen](https://doxygen.nl/index.html) to document its public API. The latest s2n-tls documentation can be found on [GitHub pages](https://aws.github.io/s2n-tls/doxygen/). The [Usage Guide](docs/usage-guide/) explains how different TLS features can be configured and used. Documentation for older versions or branches of s2n-tls can be generated locally. To generate the documentation, install doxygen and run `doxygen docs/doxygen/Doxyfile`. The doxygen documentation can now be found at `docs/doxygen/output/html/index.html`. @@ -77,7 +77,7 @@ int bytes_written; bytes_written = s2n_send(conn, "Hello World", sizeof("Hello World"), &blocked); ``` -For details on building the s2n-tls library and how to use s2n-tls in an application you are developing, see the [usage guide](https://github.com/aws/s2n-tls/blob/main/docs/USAGE-GUIDE.md). +For details on building the s2n-tls library and how to use s2n-tls in an application you are developing, see the [usage guide][Usage Guide](docs/usage-guide). ## s2n-tls features diff --git a/api/s2n.h b/api/s2n.h index a7c3d3e5f52..b7ea920f02c 100644 --- a/api/s2n.h +++ b/api/s2n.h @@ -28,7 +28,7 @@ */ #define S2N_API __attribute__((visibility("default"))) #else - /** +/** * Marks a function as belonging to the public s2n API. */ #define S2N_API @@ -142,7 +142,7 @@ S2N_API extern int *s2n_errno_location(void); * error. To retrieve the type for a given error use `s2n_error_get_type()`. Applications should * perform any error handling logic using these high level types. * - * See the [Error Handling](https://github.com/aws/s2n-tls/blob/main/docs/USAGE-GUIDE.md#error-handling) section for how the errors should be interpreted. + * See the [Error Handling](https://github.com/aws/s2n-tls/blob/main/docs/usage-guide/topics/ch03-error-handling.md) section for how the errors should be interpreted. */ typedef enum { /** No error */ @@ -673,7 +673,7 @@ S2N_API extern int s2n_cert_chain_and_key_load_pem_bytes(struct s2n_cert_chain_a /** * Associates a public certificate chain with a `s2n_cert_chain_and_key` object. It does * NOT set a private key, so the connection will need to be configured to - * [offload private key operations](https://github.com/aws/s2n-tls/blob/main/docs/USAGE-GUIDE.md#offloading-asynchronous-private-key-operations). + * [offload private key operations](https://github.com/aws/s2n-tls/blob/main/docs/usage-guide/topics/ch12-private-key-ops.md). * * @param chain_and_key The certificate chain and private key handle * @param chain_pem A byte array of a PEM encoded certificate chain. @@ -1043,7 +1043,7 @@ S2N_API extern int s2n_config_add_dhparams(struct s2n_config *config, const char * Sets the security policy that includes the cipher/kem/signature/ecc preferences and * protocol version. * - * See the [USAGE-GUIDE.md](https://github.com/aws/s2n-tls/blob/main/docs/USAGE-GUIDE.md) for how to use security policies. + * See the [USAGE-GUIDE.md](https://github.com/aws/s2n-tls/blob/main/docs/usage-guide) for how to use security policies. */ S2N_API extern int s2n_config_set_cipher_preferences(struct s2n_config *config, const char *version); @@ -3295,7 +3295,7 @@ S2N_API int s2n_connection_get_max_early_data_size(struct s2n_connection *conn, /** * Called by the client to begin negotiation and send early data. * - * See https://github.com/aws/s2n-tls/blob/main/docs/USAGE-GUIDE.md#using-early-data--0rtt + * See https://github.com/aws/s2n-tls/blob/main/docs/usage-guide/topics/ch14-early-data.md * for usage and examples. DO NOT USE unless you have considered the security issues and * implemented mitigation for anti-replay attacks. * @@ -3312,7 +3312,7 @@ S2N_API int s2n_send_early_data(struct s2n_connection *conn, const uint8_t *data /** * Called by the server to begin negotiation and accept any early data the client sends. * - * See https://github.com/aws/s2n-tls/blob/main/docs/USAGE-GUIDE.md#using-early-data--0rtt + * See https://github.com/aws/s2n-tls/blob/main/docs/usage-guide/topics/ch14-early-data.md * for usage and examples. DO NOT USE unless you have considered the security issues and * implemented mitigation for anti-replay attacks. * diff --git a/bin/s2nc.c b/bin/s2nc.c index 8203a1c48a6..a7fcfc1ac01 100644 --- a/bin/s2nc.c +++ b/bin/s2nc.c @@ -61,7 +61,7 @@ void usage() fprintf(stderr, " Sets the application protocols supported by this client, as a comma separated list.\n"); fprintf(stderr, " -c [version_string]\n"); fprintf(stderr, " --ciphers [version_string]\n"); - fprintf(stderr, " Set the cipher preference version string. Defaults to \"default\". See USAGE-GUIDE.md\n"); + fprintf(stderr, " Set the cipher preference version string. Defaults to \"default\" \n"); fprintf(stderr, " --enter-fips-mode\n"); fprintf(stderr, " Enter libcrypto's FIPS mode. The linked version of OpenSSL must be built with the FIPS module.\n"); fprintf(stderr, " -e,--echo\n"); diff --git a/bin/s2nd.c b/bin/s2nd.c index 54d583ca1b7..c34ffbc740c 100644 --- a/bin/s2nd.c +++ b/bin/s2nd.c @@ -145,7 +145,7 @@ void usage() fprintf(stderr, " Sets a single application protocol supported by this server.\n"); fprintf(stderr, " -c [version_string]\n"); fprintf(stderr, " --ciphers [version_string]\n"); - fprintf(stderr, " Set the cipher preference version string. Defaults to \"default\". See USAGE-GUIDE.md\n"); + fprintf(stderr, " Set the cipher preference version string. Defaults to \"default\" \n"); fprintf(stderr, " --enter-fips-mode\n"); fprintf(stderr, " Enter libcrypto's FIPS mode. The linked version of OpenSSL must be built with the FIPS module.\n"); fprintf(stderr, " --cert\n"); diff --git a/docs/DEVELOPMENT-GUIDE.md b/docs/DEVELOPMENT-GUIDE.md index 09ee50f4678..4cd34b8534d 100644 --- a/docs/DEVELOPMENT-GUIDE.md +++ b/docs/DEVELOPMENT-GUIDE.md @@ -2,7 +2,7 @@ If you are curious about the internals of s2n-tls, or interested in contributing to s2n-tls, this document is for you. If instead you are interested in using s2n-tls in an application -that you are developing, please see the accompanying [Usage Guide](https://github.com/aws/s2n-tls/blob/main/docs/USAGE-GUIDE.md). +that you are developing, please see the accompanying [Usage Guide](usage-guide). ## s2n-tls's development principles diff --git a/docs/FAQ.md b/docs/FAQ.md index aa191f0af59..b6edbff674a 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -15,23 +15,23 @@ higher than "TLS1.2" for similar reasons. If the client does support TLS1.3, it will include that information in the ClientHello "supported_versions" extension instead of setting any of the legacy version fields. -s2n-tls offers [methods](USAGE-GUIDE/#protocol-version) to retrieve accurate protocol versions. +s2n-tls offers [methods](usage-guide/topics/ch04-connection.md) to retrieve accurate protocol versions. ### Why isn't my connection using TLS1.3? There are several possible reasons: -* Are you using a security policy that supports TLS1.3? See [security policies](USAGE-GUIDE.md/#security-policies). +* Are you using a security policy that supports TLS1.3? See [security policies](usage-guide/topics/ch06-security-policies.md). * Are you verifying the connection version correctly? See [the previous question](FAQ.md#why-is-my-connection-using-tls10). * Are you using a libcrypto library that supports TLS1.3? Modern libcrypto libraries support the algorithms needed for TLS1.3, but older libraries like Openssl 1.0.2 do not. If s2n-tls is built with Openssl 1.0.2, TLS1.3 is unlikely to be negotiated. * Does your peer support TLS1.3? If your peer does not support TLS1.3, TLS1.3 will not be negotiated. ### Why is the TLS handshake failing on validating my peer's certificate? -Have you already configure a trust store to be able to trust your peer's certificate? If so it may be necessary to implement `s2n_verify_host_fn` as the default behavior may not work for your use case. See the [certificates](USAGE-GUIDE.md/#certificates-and-authentication) section for detailed instructions on verifying a peer's certificate. +Have you already configure a trust store to be able to trust your peer's certificate? If so it may be necessary to implement `s2n_verify_host_fn` as the default behavior may not work for your use case. See the [certificates](usage-guide/topics/ch09-certificates.md) section for detailed instructions on verifying a peer's certificate. ### Why is s2n hanging for so long before erroring? -s2n-tls sleeps for a random period between 10 and 30 seconds after specific errors occur to avoid leaking any secret information via timing data. This technique is called blinding and it is utilized to prevent timing side-channel attacks. See [blinding](USAGE-GUIDE.md/#blinding). +s2n-tls sleeps for a random period between 10 and 30 seconds after specific errors occur to avoid leaking any secret information via timing data. This technique is called blinding and it is utilized to prevent timing side-channel attacks. See [blinding](usage-guide/topics/ch03-error-handling.md#blinding). ### Which security policy should I use if I want to make sure that it will never be altered? -Our numbered security policies are guaranteed to never change. We will not alter or update them based on changing cryptography standards. However, our named security policies (like “default” or “default_tls13”) change based on new cryptography standards that come out. See [security policies](USAGE-GUIDE.md/#security-policies). +Our numbered security policies are guaranteed to never change. We will not alter or update them based on changing cryptography standards. However, our named security policies (like “default” or “default_tls13”) change based on new cryptography standards that come out. See [security policies](usage-guide/topics/ch06-security-policies.md). ### Why does s2n-tls have a dependency on OpenSSL? Isn't s2n-tls a replacement for OpenSSL? OpenSSL includes both a TLS library, called libssl, and a cryptography library, called libcrypto. s2n-tls implements a TLS library, but does not implement a cryptography library. Instead, s2n-tls links to a separate libcrypto in order to perform cryptographic operations. Libcryptos other than OpenSSL can be used, such as [AWS-LC](https://github.com/aws/aws-lc). diff --git a/error/s2n_errno.c b/error/s2n_errno.c index 22d5fe94f54..61869a9a562 100644 --- a/error/s2n_errno.c +++ b/error/s2n_errno.c @@ -461,7 +461,7 @@ int s2n_print_stacktrace(FILE *fptr) if (!s_s2n_stack_traces_enabled) { fprintf(fptr, "%s\n%s\n", "NOTE: Some details are omitted, run with S2N_PRINT_STACKTRACE=1 for a verbose backtrace.", - "See https://github.com/aws/s2n-tls/blob/main/docs/USAGE-GUIDE.md"); + "See https://github.com/aws/s2n-tls/blob/main/docs/usage-guide"); return S2N_SUCCESS; } diff --git a/libcrypto-build/README.md b/libcrypto-build/README.md index 30fe3da2c34..554873b1612 100644 --- a/libcrypto-build/README.md +++ b/libcrypto-build/README.md @@ -1,4 +1,4 @@ This directory is used to store build artifacts (tarballs and source) for a locally built copy of libcrypto, either from OpenSSL, LibreSSL or BoringSSL. -See the s2n [Usage Guide](https://github.com/aws/s2n-tls/blob/main/docs/USAGE-GUIDE.md) for more details. +See the s2n [Build Guide](../docs/BUILD.md#building-with-a-specific-libcrypto) for more details. diff --git a/tls/s2n_config.h b/tls/s2n_config.h index 3b4cbf49ed9..828c9439f1e 100644 --- a/tls/s2n_config.h +++ b/tls/s2n_config.h @@ -69,8 +69,7 @@ struct s2n_config { unsigned disable_x509_time_validation : 1; unsigned disable_x509_validation : 1; unsigned max_verify_cert_chain_depth_set : 1; - /* Whether to add dss cert type during a server certificate request. - * See https://github.com/aws/s2n-tls/blob/main/docs/USAGE-GUIDE.md */ + /* Whether to add dss cert type during a server certificate request */ unsigned cert_req_dss_legacy_compat_enabled : 1; /* Whether any RSA certificates have been configured server-side to send to clients. This is needed so that the * server knows whether or not to self-downgrade to TLS 1.2 if the server is compiled with Openssl 1.0.2 and does diff --git a/tls/s2n_internal.h b/tls/s2n_internal.h index ed4f5d936b1..c1ab6a3e700 100644 --- a/tls/s2n_internal.h +++ b/tls/s2n_internal.h @@ -49,7 +49,7 @@ S2N_PRIVATE_API int s2n_connection_get_config(struct s2n_connection *conn, struc * Sets a certificate chain on the config. * * It does NOT set a private key, so the connection will need to be configured to - * [offload private key operations](https://github.com/aws/s2n-tls/blob/main/docs/USAGE-GUIDE.md#offloading-asynchronous-private-key-operations). + * [offload private key operations](https://github.com/aws/s2n-tls/blob/main/docs/usage-guide/topics/ch12-private-key-ops.md). */ S2N_PRIVATE_API int s2n_config_add_cert_chain(struct s2n_config *config, uint8_t *cert_chain_pem, uint32_t cert_chain_pem_size); From cdb5c49b6096bc0317acfd405b98d876ae14e99f Mon Sep 17 00:00:00 2001 From: Appelmans Date: Tue, 19 Dec 2023 17:49:36 -0800 Subject: [PATCH 7/7] PR feedback --- api/s2n.h | 2 +- tls/s2n_config.h | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/api/s2n.h b/api/s2n.h index b7ea920f02c..c77b97a8c9f 100644 --- a/api/s2n.h +++ b/api/s2n.h @@ -28,7 +28,7 @@ */ #define S2N_API __attribute__((visibility("default"))) #else -/** + /** * Marks a function as belonging to the public s2n API. */ #define S2N_API diff --git a/tls/s2n_config.h b/tls/s2n_config.h index 828c9439f1e..2f2e0dcb03f 100644 --- a/tls/s2n_config.h +++ b/tls/s2n_config.h @@ -69,7 +69,8 @@ struct s2n_config { unsigned disable_x509_time_validation : 1; unsigned disable_x509_validation : 1; unsigned max_verify_cert_chain_depth_set : 1; - /* Whether to add dss cert type during a server certificate request */ + /* Whether to add dss cert type during a server certificate request. + * See s2n_config_enable_cert_req_dss_legacy_compat. */ unsigned cert_req_dss_legacy_compat_enabled : 1; /* Whether any RSA certificates have been configured server-side to send to clients. This is needed so that the * server knows whether or not to self-downgrade to TLS 1.2 if the server is compiled with Openssl 1.0.2 and does @@ -90,7 +91,7 @@ struct s2n_config { /* Indicates s2n_recv should read as much as it can into the output buffer * - * Note: This defaults to false to ensure backwards compatability with + * Note: This defaults to false to ensure backwards compatibility with * applications which relied on s2n_recv returning a single record. */ unsigned recv_multi_record : 1;