From de3b697610006cdc9c9b0b04f89b345518dc671d Mon Sep 17 00:00:00 2001 From: Sam Clark <3758302+goatgoose@users.noreply.github.com> Date: Fri, 27 Sep 2024 12:14:28 -0400 Subject: [PATCH] docs: Update certificate loading documentation (#4790) --- api/s2n.h | 28 ++++++++++++++++---- docs/usage-guide/topics/ch09-certificates.md | 18 ++++++++++++- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/api/s2n.h b/api/s2n.h index 6a627aa6951..0ba344885aa 100644 --- a/api/s2n.h +++ b/api/s2n.h @@ -801,13 +801,13 @@ S2N_API extern int s2n_config_add_cert_chain_and_key(struct s2n_config *config, /** * The preferred method of associating a certificate chain and private key pair with an `s2n_config` object. - * This method may be called multiple times to support multiple key types(RSA, ECDSA) and multiple domains. - * On the server side, the certificate selected will be based on the incoming SNI value and the - * client's capabilities(supported ciphers). + * This method may be called multiple times to support multiple key types (RSA, RSA-PSS, ECDSA) and multiple + * domains. On the server side, the certificate selected will be based on the incoming SNI value and the + * client's capabilities (supported ciphers). * * In the case of no certificate matching the client's SNI extension or if no SNI extension was sent by - * the client, the certificate from the `first` call to `s2n_config_add_cert_chain_and_key_to_store` - * will be selected. + * the client, the certificate from the `first` call to `s2n_config_add_cert_chain_and_key_to_store()` + * will be selected. Use `s2n_config_set_cert_chain_and_key_defaults()` to set different defaults. * * @warning It is not recommended to free or modify the `cert_key_pair` as any subsequent changes will be * reflected in the config. @@ -849,6 +849,16 @@ S2N_API extern int s2n_config_set_cert_chain_and_key_defaults(struct s2n_config * * @note The trust store will be initialized with the common locations for the host * operating system by default. + * + * @warning This API uses the PEM parsing implementation from the linked libcrypto. This + * implementation will typically make a best-effort attempt to parse all of the certificates in the + * provided file or directory. This permissive approach may silently ignore malformed certificates, + * leading to possible connection failures if a certificate was expected to exist in the trust + * store but was skipped while parsing. As such, this API should only be used on PEMs that are + * known to be well-formed and parsable with the linked libcrypto, such as the system trust store. + * For all other PEMs, `s2n_config_add_pem_to_trust_store()` should be used instead, which parses + * more strictly. + * * @param config The configuration object being updated * @param ca_pem_filename A string for the file path of the CA PEM file. * @param ca_dir A string for the directory of the CA PEM files. @@ -863,6 +873,14 @@ S2N_API extern int s2n_config_set_verification_ca_location(struct s2n_config *co * system certificates. To completely override these certificates, call * `s2n_config_wipe_trust_store()` before calling this function. * + * @note This API uses the s2n-tls PEM parsing implementation, which is more strict than typical + * libcrypto implementations such as OpenSSL. An error is returned if any unexpected data is + * encountered while parsing `pem`. This allows applications to be made aware of any malformed + * certificates rather than attempt to negotiate with a partial trust store. However, some PEMs may + * need to be loaded that are not under control of the application, such as system trust stores. In + * this case, `s2n_config_set_verification_ca_location()` may be used, which performs more widely + * compatible and permissive parsing from the linked libcrypto. + * * @param config The configuration object being updated * @param pem The string value of the PEM certificate. * @returns S2N_SUCCESS on success. S2N_FAILURE on failure diff --git a/docs/usage-guide/topics/ch09-certificates.md b/docs/usage-guide/topics/ch09-certificates.md index 2c81640d8fc..d4281656f6f 100644 --- a/docs/usage-guide/topics/ch09-certificates.md +++ b/docs/usage-guide/topics/ch09-certificates.md @@ -29,12 +29,28 @@ 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. +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 for a given domain name. 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()`. +### SNI + +TLS servers will often serve multiple domains from a single IP address, with each domain potentially requiring its own certificate. When a TLS client receives a server's certificate, it will check to ensure that it was issued for the domain that the client is connecting to. As such, the server needs to know which domain the client is connecting to in order to send the correct certificate. This information is communicated to the server via the Server Name Indication (SNI) extension. + +#### Client configuration + +`s2n_set_server_name()` is used on client connections to specify a domain name in the SNI extension. + +#### Server configuration + +Each certificate loaded with `s2n_config_add_cert_chain_and_key_to_store()` is automatically associated with every domain name listed in its Subject Alternative Name (SAN) field. The domain names listed in the Common Name (CN) field are used instead if the certificate doesn't contain an SAN field. s2n-tls servers automatically send a certificate that matches the value of the client's SNI extension during the TLS handshake. + +s2n-tls servers allow a maximum of 1 certificate to be loaded per domain, per certificate type (RSA, RSA-PSS, ECDSA). By default, a newly loaded certificate with an overlapping domain name will not replace the existing certificate associated with that domain. The `s2n_cert_tiebreak_callback` may be implemented to customize which certificate is selected when an overlapping domain is encountered. + +When selecting a certificate to send to the client, s2n-tls servers prefer an exact SNI match before falling back to a certificate with an associated wildcard domain (a domain starting with "*.", covering all subdomains). A default certificate is selected if no SNI match exists, or if the client doesn't send an SNI extension. A default certificate is set when `s2n_config_add_cert_chain_and_key_to_store()` is called for the first time for a given certificate type (RSA, RSA-PSS, ECDSA). `s2n_config_set_cert_chain_and_key_defaults()` may be used to override the default certificates. + ## 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.