Skip to content

Add attested-tls crate#6

Merged
ameba23 merged 39 commits intomainfrom
peg/attested-tls-crate
Apr 16, 2026
Merged

Add attested-tls crate#6
ameba23 merged 39 commits intomainfrom
peg/attested-tls-crate

Conversation

@ameba23
Copy link
Copy Markdown
Collaborator

@ameba23 ameba23 commented Mar 13, 2026

This adds a the attested TLS crate which provides an attested certificate resolver, providing and handling renewal of TLS certificates with embedded attestations, and an attested certificate verifier, which can verify these attestations during the TLS handshake.

Note: This PR targets peg/add-attestation-crate as i needed stuff from that branch.

Attestation input data is computed as

SHA512(
  Der-encoded public key 
  || not before date as seconds big endian u64
  || not after date as seconds big endian u64
  || hostname
)

Features

  • Both self-signed certificates and private certificate authorities are supported
  • Verifier caches trusted certificates and skips subsequent attestation verification for them
  • Attested client authentication supported

Things to be aware of

@ameba23 ameba23 marked this pull request as draft March 13, 2026 07:41
@ameba23 ameba23 changed the base branch from main to peg/add-attestation-crate March 16, 2026 07:04
@ameba23 ameba23 marked this pull request as ready for review March 16, 2026 10:29
@ameba23 ameba23 requested a review from 0x416e746f6e March 16, 2026 10:29
Base automatically changed from peg/add-attestation-crate to main March 30, 2026 11:24
Comment thread crates/attested-tls/src/lib.rs Outdated
Comment thread crates/attested-tls/src/lib.rs Outdated
Comment thread crates/attested-tls/src/lib.rs Outdated
Comment thread crates/attested-tls/src/lib.rs Outdated
Comment thread crates/attested-tls/src/lib.rs Outdated
Comment thread crates/attested-tls/src/lib.rs
}
}

fn default_crypto_provider() -> Result<Arc<CryptoProvider>, AttestedTlsError> {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question:

why do we prefer this method over underlying CryptoProvider::get_default()?

Copy link
Copy Markdown
Collaborator Author

@ameba23 ameba23 Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for convenience it handles the error and clones.

/// self-signed
client_inner: Option<Arc<dyn ClientCertVerifier>>,
/// Underlying cryptography provider
provider: Arc<CryptoProvider>,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question:

similarly to above, why not just use the default? are there cases when user will want to have 2 different providers at the same time?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because otherwise we have to handle the case that there is no provider available during signature verification. We could actually replace this with just the signature algorithms for that provider, which is what we need it for.

Comment thread crates/attested-tls/src/lib.rs
}

/// Also provide a crypto provider
pub async fn new_with_provider(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question:

should this be async too?

basically the whole chain of calls:

  • AttestedCertificateResolver::new()
  • AttestedCertificateResolver::new_with_provider()
  • AttestedCertificateResolver::issue_ra_cert_chain()
  • AttestedCertificateResolver::create_attestation_payload()
  • AttestationGenerator::generate_attestation()
  • AttestationGenerator::use_attestation_provider()

^-- is made async because we are calling external provider's URL via reqwest.

but since in normal scenarios this URL is supposed to be on a localhost, can we just use a blocking call instead?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, just in case some of these commits are useful: #20

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually was thinking of going in the opposite direction - to make attestation generation always be async by using tokio's filesystem API when getting the quotes. See entropyxyz/configfs-tsm#10

We know that quote generation is generally slow. I don't fully understand the tradeoffs of using blocking APIs from the tokio runtime, but in my understanding it is something you are supposed to avoid. So this choice depends a bit whether the caller is using tokio right?

Copy link
Copy Markdown
Member

@0x416e746f6e 0x416e746f6e Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

even though quote generation is slow, we are not winning anything by marking AttestationGenerator::generate_attestation() async on the path where it uses dcap::create_dcap_attestation() b/c the latter is blocking.

it's the same as marking function async while still using std::thread::sleep() in it (instead of tokio::time::sleep()).

unless underlying configfs-tsm crate offers async counterparts to its quote-generating methods I don't see a point of tagging functions async just because they are slow.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am the maintainer of that crate, which really just reads and writes files using std::fs, and i have an open PR to use tokio::fs (linked above).

But we could also switch to dstack's quote generation crate, which is likely much better. I can't remember whether it is async or not, need to find it...

Copy link
Copy Markdown
Member

@0x416e746f6e 0x416e746f6e Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if dstack uses tokio::fs (or configfs-tsm starts to), yes, then switching to async would make sense. this way we would at least avoid blocking tokio workers

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dstack's tdx-attest crate also provides a synchronous api, using std::fs to read and write to configfs-tsm:

https://github.com/Dstack-TEE/dstack/blob/3a456dd6e332509f97e7ef3d83758ca3ea35770c/tdx-attest/src/linux.rs#L286-L329

I would strongly consider switching to their crate as generally their stuff is used in production and well maintained. It also has some extra features like falling back to vsock if configfs is not available. But i would wanna give it a proper review before switching.

So:

  • I think we should move to synchronous api for AttestationGenerator as you propose.
  • but if attestation generation is called from a tokio runtime, it should really be wrapped in spawn_blocking to prevent it from causing the tokio executor to wait.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree. let's do it

ameba23 and others added 8 commits April 14, 2026 12:22
Co-authored-by: Anton <anton@northernforest.nl>
Co-authored-by: Anton <anton@northernforest.nl>
Co-authored-by: Anton <anton@northernforest.nl>
Co-authored-by: Anton <anton@northernforest.nl>
Co-authored-by: Anton <anton@northernforest.nl>
Co-authored-by: Anton <anton@northernforest.nl>
Co-authored-by: Anton <anton@northernforest.nl>
Co-authored-by: Anton <anton@northernforest.nl>
@ameba23 ameba23 requested a review from 0x416e746f6e April 15, 2026 06:55
Copy link
Copy Markdown
Member

@0x416e746f6e 0x416e746f6e left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚢 🛳️ 🐑

Comment on lines +745 to +747
Err(rustls::Error::InvalidCertificate(rustls::CertificateError::UnknownIssuer)) => {
Self::verify_cert_time_validity(end_entity, now)?;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue:

#25

Comment on lines +673 to +676
Err(rustls::Error::InvalidCertificate(rustls::CertificateError::UnknownIssuer)) => {
// handle self-signed certs differently
Self::verify_server_cert_constraints(end_entity, server_name, now)?;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue:

#25

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch

@ameba23 ameba23 merged commit 63685e8 into main Apr 16, 2026
2 checks passed
@ameba23 ameba23 deleted the peg/attested-tls-crate branch April 16, 2026 09:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants