Skip to content

Commit

Permalink
[release/4.x] Cherry pick: Include intermediate certs in TLS handshake (
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyashton authored Jul 14, 2023
1 parent 176cf6a commit f22bda1
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
[4.0.5]: https://github.com/microsoft/CCF/releases/tag/ccf-4.0.5

- Debug logging is now available in non-SGX builds by default, and controlled by a run-time CLI argument (`--enclave-log-level`). On SGX this remains a build-time decision (#5375).
- Supporting intermediate cert chain included in TLS handshake, where previously only server leaf certificate was present (#5453).
- Added `getVersionOfPreviousWrite` to TypeScript `TypedKvMap` interface (#5451).

## [4.0.4]
Expand Down
28 changes: 23 additions & 5 deletions src/tls/cert.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace tls
bool auth_required;

Unique_X509 own_cert;
Unique_STACK_OF_X509 chain;
std::shared_ptr<crypto::KeyPair_OpenSSL> own_pkey;
bool has_own_cert = false;

Expand All @@ -44,10 +45,26 @@ namespace tls
{
if (own_cert_.has_value() && own_pkey_.has_value())
{
Unique_BIO certbio(*own_cert_);
own_cert = Unique_X509(certbio, true);
own_pkey = std::make_shared<crypto::KeyPair_OpenSSL>(*own_pkey_);
const auto certs = crypto::split_x509_cert_bundle(own_cert_->str());
has_own_cert = true;

{
Unique_BIO certbio(certs[0]);
own_cert = Unique_X509(certbio, true);
own_pkey = std::make_shared<crypto::KeyPair_OpenSSL>(*own_pkey_);
}

if (certs.size() > 1)
{
for (auto it = certs.begin() + 1; it != certs.end(); ++it)
{
Unique_BIO certbio(*it);
Unique_X509 cert(certbio, true);

CHECK1(sk_X509_push(chain, cert));
CHECK1(X509_up_ref(cert));
}
}
}
}

Expand Down Expand Up @@ -91,8 +108,9 @@ namespace tls

if (has_own_cert)
{
CHECK1(SSL_CTX_use_cert_and_key(ssl_ctx, own_cert, *own_pkey, NULL, 1));
CHECK1(SSL_use_cert_and_key(ssl, own_cert, *own_pkey, NULL, 1));
CHECK1(
SSL_CTX_use_cert_and_key(ssl_ctx, own_cert, *own_pkey, chain, 1));
CHECK1(SSL_use_cert_and_key(ssl, own_cert, *own_pkey, chain, 1));
}
}
};
Expand Down
21 changes: 10 additions & 11 deletions tests/acme_endorsement.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def wait_for_port_to_listen(host, port, timeout=10):

@reqs.description("Start network and wait for ACME certificates")
def wait_for_certificates(
args, network_name, ca_certs, interface_name, challenge_interface, timeout=5 * 60
args, network_name, root_cert, interface_name, challenge_interface, timeout=5
):
with infra.network.network(
args.nodes, args.binary_dir, args.debug_nodes, args.perf_nodes, pdb=args.pdb
Expand Down Expand Up @@ -76,8 +76,7 @@ def wait_for_certificates(
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
context.verify_mode = ssl.CERT_REQUIRED
context.check_hostname = True
for crt in ca_certs:
context.load_verify_locations(cadata=crt)
context.load_verify_locations(cadata=root_cert)

s = socket.socket()
s.settimeout(1)
Expand All @@ -92,9 +91,12 @@ def wait_for_certificates(
assert network_public_key == cert_public_key
num_ok += 1
except Exception as ex:
LOG.trace(f"Likely expected exception: {ex}")
LOG.warning(f"Likely temporary exception: {ex}")

if num_ok != len(args.nodes):
LOG.warning(
f"{num_ok}/{len(args.nodes)} nodes presenting endorsed cert"
)
time.sleep(1)

# We can't run test_unsecured_interfaces against the ACME-endorsed interface
Expand Down Expand Up @@ -195,12 +197,9 @@ def get_without_cert_check(url):
return urllib.request.urlopen(url, context=ctx).read().decode("utf-8")


def get_pebble_ca_certs(mgmt_address):
def get_pebble_root_cert(mgmt_address):
ca = get_without_cert_check("https://" + mgmt_address + "/roots/0")
intermediate = get_without_cert_check(
"https://" + mgmt_address + "/intermediates/0"
)
return ca, intermediate
return ca


@reqs.description("Test that secure content is not available on an unsecured interface")
Expand Down Expand Up @@ -321,11 +320,11 @@ def run_pebble(args):
)

try:
ca_certs = get_pebble_ca_certs(mgmt_address)
root_cert = get_pebble_root_cert(mgmt_address)
wait_for_certificates(
args,
network_name,
ca_certs,
root_cert,
"acme_endorsed_interface",
"acme_challenge_server_if",
)
Expand Down

0 comments on commit f22bda1

Please sign in to comment.