Repository: aws/s2n-tls (C)

Issue:
PARTIAL_CHAIN libcrypto flag is selectively applied
### Problem:

The `X509_V_FLAG_PARTIAL_CHAIN` ossl flag allows certificates that aren't self signed to be added to the trust store and used as root certificates, without requiring the issuer of the added cert to also be present. This flag is set whenever `s2n_config_set_verification_ca_location()` is called, since we assume that whatever cert the applications loads with this API should be trusted, even if it isn't self-signed.

`s2n_config_add_pem_to_trust_store()` is a similar API, but we don't set the PARTIAL_CHAIN flag with this API.

### Solution:

We should change `s2n_config_add_pem_to_trust_store()` to also set the flag.

Alternatively, we could consider just always setting this flag when validating a cert. After adding this flag in `s2n_config_add_pem_to_trust_store()`, the only time this flag wouldn't be set is when only the system's trust store is loaded. It likely makes sense to set PARTIAL_CHAIN even in this case, since applications could place non self-signed certs into the system's cert directory and expect them to be trusted.

* **Does this change what S2N sends over the wire?** If yes, explain.
  * No
* **Does this change any public APIs?** If yes, explain.
  * Yes: non-root certificates would be trusted when loaded with `s2n_config_add_pem_to_trust_store()`, and potentially also for system certificates loaded by default s2n_configs or `s2n_config_load_system_certs()`.
* **Which versions of TLS will this impact?**
  * All versions

[//]: #  (NOTE: If you believe this might be a security issue, please email aws-security@amazon.com instead of creating a GitHub issue. For more details, see the AWS Vulnerability Reporting Guide: https://aws.amazon.com/security/vulnerability-reporting/ )




Fix (patch):
diff --git a/tls/s2n_x509_validator.c b/tls/s2n_x509_validator.c
index ec37e7c8645..a1d0a1729ff 100644
--- a/tls/s2n_x509_validator.c
+++ b/tls/s2n_x509_validator.c
@@ -125,13 +125,6 @@ int s2n_x509_trust_store_from_ca_file(struct s2n_x509_trust_store *store, const
         POSIX_BAIL(S2N_ERR_X509_TRUST_STORE);
     }
 
-    /* It's a likely scenario if this function is called, a self-signed certificate is used, and that is was generated
-     * without a trust anchor. However if you call this function, the assumption is you trust ca_file or path and if a certificate
-     * is encountered that's in that path, it should be trusted. The following flag tells libcrypto to not care that the cert
-     * is missing a root anchor. */
-    unsigned long flags = X509_V_FLAG_PARTIAL_CHAIN;
-    X509_STORE_set_flags(store->trust_store, flags);
-
     return 0;
 }
 
@@ -603,6 +596,13 @@ static S2N_RESULT s2n_x509_validator_verify_cert_chain(struct s2n_x509_validator
         X509_STORE_CTX_set_time(validator->store_ctx, 0, current_time);
     }
 
+    /* It's assumed that if a valid certificate chain is received with an issuer that's present in
+     * the trust store, the certificate chain should be trusted. This should be the case even if
+     * the issuer in the trust store isn't a root certificate. Setting the PARTIAL_CHAIN flag
+     * allows the libcrypto to trust certificates in the trust store that aren't root certificates.
+     */
+    X509_STORE_CTX_set_flags(validator->store_ctx, X509_V_FLAG_PARTIAL_CHAIN);
+
     int verify_ret = X509_verify_cert(validator->store_ctx);
     if (verify_ret <= 0) {
         int ossl_error = X509_STORE_CTX_get_error(validator->store_ctx);