Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ACME device attestation and TPM residency of AKs #2

Closed
NickDarvey opened this issue Nov 11, 2024 · 10 comments
Closed

ACME device attestation and TPM residency of AKs #2

NickDarvey opened this issue Nov 11, 2024 · 10 comments

Comments

@NickDarvey
Copy link

I see you're working on implementing acme-device-attest. I'm curious, how does that flow can guarantee TPM residency of AKs as described in TPM 2.0 Keys for Device Identity and Attestation?

@jeremyhahn
Copy link
Owner

jeremyhahn commented Nov 11, 2024

The device-attest-01 challenge does not implement a workflow mentioned in the TPM 2.0 Keys for Device Identity and Attestation. It implements a workflow that more closely aligns with the WebAuthn standard which supports more than just TPMs.

I've created a new challenge type for this project, device-01, which does follow the TCG specs you mentioned. It currently supports both of the Identity Provisioning use cases mentioned for OEM's, and I will add more in the future.

I actually just got the first end to end test working today. You can be the first to give it a try and let me know what you think:

ACME Server:

cd /tmp
mkdir server
cd server
cp ~/sources/go-trusted-platform/configs/platform/config.debug.server.yaml config.yaml
~/sources/go-trusted-platform/tpadm webservice \
    --debug \
    --init \
    --platform-dir trusted-data \
    --config-dir trusted-data/etc \
    --log-dir trusted-data/log \
    --ca-dir trusted-data/ca \
    --raw-so-pin test \
    --raw-pin test

ACME Client:

cd /tmp
mkdir client
cd client
cp ~/sources/go-trusted-platform/configs/platform/config.debug.client.yaml config.yaml
~/sources/go-trusted-platform/tpadm webservice \
    --debug \
    --init \
    --platform-dir trusted-data \
    --config-dir trusted-data/etc \
    --log-dir trusted-data/log \
    --ca-dir trusted-data/ca \
    --raw-so-pin test \
    --raw-pin test
  • /etc/hosts
127.0.0.1	localhost server1.trusted-platform.local node1.trusted-platform.local node1-api.trusted-platform.local

Both the ACME server and client will start up using the embedded TPM simulator. The platform software fully provisions the TPM, including an EK, SRK, IAK, and IDevID keys. Then, the client will see the ACME client config and use the configured ACME server endpoint to request an EK, IAK, IDevID certificates (with all of the proper TCG OIDs) and finally, a web server TLS certificate using a standalone pkcs8 key.

The EK is retrieved using a custom endorse-01 challenge to support automated OEM factory device provisioning use cases.

The IAK and IDevID is retrieved using a custom device-01 challenge that uses the TCG workflow you mentioned above, using a modified version of the http-01 challenge, where instead of returning the key authorization as in http-01, the TCG-CSR-IDEVID is returned with the key authorization used in the qualifying attestation data.

Finally, a TLS certificate is requested & issued, using a separate pkcs8 key, for its web services which will be running on localhost:8444. You can inspect the certificate in the browser to confirm it's issued by the Enterprise CA.

I've run into an issue fully implementing the device-attest-01 challenge and sent @brandonweeks an email to address the issue. The device-attest-01 requires sending the attestation statement to the ACME server during the "Accept" call, which is not compliant with RFC-8555. As such, the Golang ACME client library I'm using does not support sending the device-attest-01 payload, and is in fact hard coded to send an empty object per RFC 8555. It looks like in the past this library did support sending a custom payload, but that support was removed in the latest versions.

It seems like there are 3 paths to pursue with device-attest-01:

  1. Piggyback http-01 or dns-01 similar to how I implemented device-01 , or use some other async procedure.

  2. Change RFC 8555 to support an ACME client sending the challenge response along with the "Accept" response. I think this is the most desirable because there is no reason to require an async verification process for device attestations. This eliminates the need for clients to open firewall ports or make configuration changes to verify anything, since everything needed is contained within the attestation. This also shaves off a round trip in the process which reduces latency.

  3. Leave the spec as is and force ACME clients to deviate from RFC 8555. I actually started to go down this path, but ran into a wall when the JOSE library being used to sign JWS requests is base64 encoding the ACME replay-nonce, causing the validation to fail, and there is no way to change the behavior in the library. That means going further down the rabbit hole, creating a custom serializer, signer, etc, finding a new ACME client library, or creating an entire low level client to replace the crypto/acme client altogether. Ugh.

I just pushed the latest code to the feature/acme branch if you want to check it out.

@NickDarvey
Copy link
Author

Ahh! Okay, that makes sense. Great timing! I'll give this a go and read about your endorse-01 and device-01 challenges.

@brandonweeks
Copy link

brandonweeks commented Nov 11, 2024

I'll take a closer look when I get a chance but drive by comment in the mean time:

It implements a workflow that more closely aligns with the WebAuthn standard which supports more than just TPMs.

The intent is not to align with WebAuthn per se. It is just that every other attestation schemed covered by the acme-device-attest document is able to attest without prerequisite steps.

In order to make the TPM specifications generalizable to both enterprise and privacy preserving use cases the concept of a third party attestation/privacy CA is included. Until a subject device has been issued an AK certificate, it is unable to participate in any attestation flow, including the ACME flow described by acme-device-attest.

There are a lot of considerations in implementing an attestation CA, including important privacy considerations. It seems inappropriate for a acme-device-attest to prescribe a specific design, especially in such a short document.

@NickDarvey
Copy link
Author

I notice that the ACME client starts as a web server

tpadm webservice

Is this necessary? Does the client have to be addressable for endorse-01 and device-01 to work?

@jeremyhahn
Copy link
Owner

jeremyhahn commented Nov 11, 2024

The ACME client is starting with the web service because the web server needs a TLS certificate before it can start. Therefore, it fires up the ACME client first to request it, but before that can happen, the attestation procedure outlined above takes place so that when a TLS certificate is requested, the ACME server can perform the device-attest-01 challenge. As Brandon mentioned, that challenge expects the ACME server to already know about the permanent-identifier and how to verifiy the attestation statement, which implies some kind of enrollment has already happened. For this reason, endorse-01 and device-01 were created, to allow the device to be enrolled first, so the CA has the root certificates, permanent-identifiers or whatever else it needs to verify the device-attest-01 challenge, and also verify that it is talking to a known device (via the IDevID cert).

Yes, both endorse-01 and device-01 require HTTP as they are slightly modified versions of http-01, however, they start their own web servers and tear them down once the challenge has been completed. Once the TLS certificate is obtained, the main web services are started.

I currently have http-8080 and http-8081 as challenge options to work around privileged port requirements, and will probably just consolidate them into something like http-x that reads the port from the config file, and make endorse-01 and device-01 ports configurable in the same manner, that way anyone in control of the Enterprise CA deployment can define the challenge to happen on any port they want.

@NickDarvey
Copy link
Author

Yes, both endorse-01 and device-01 require HTTP as they are slightly modified versions of http-01

Ahh okay. That makes sense, though it might make things tricky in my scenario where my devices are NATed.

@jeremyhahn
Copy link
Owner

The same efforts to make the NATed devices work would be required for http-01 as well. dns-01 doesn't seem like a good candidate due to the attestation statement payload size. The most convenient solution for device attestation is to send the attestation payload when the client accepts the challenge, as defined in device-attest-01. I also prefer this approach and don't see any reason why it can't / shouldn't be supported.

If you have other suggestions for a challenge type that would make the an async validation process more automation and administration friendly for NATed devices, I'm open to suggestions.

I pinged the Boulder team. I'm interested in their thoughts on this as well.
letsencrypt/boulder#7798

@NickDarvey
Copy link
Author

Cheers @jeremyhahn — that sounds sensible. I've subscribed to that issue, will see what comes of it. I look fowrard to seeing what you do in this space

@jeremyhahn
Copy link
Owner

I confirmed via the ACME mailing list that the empty payload object is not a strict RFC requirement and opened a PR to allow the golang acme client to support our use case.

golang/crypto#305
https://go-review.googlesource.com/c/crypto/+/628635

Upon merge, I'll finish wiring up the last remaining piece for acme-device-attest and refactor the custom enrollment challenges to reduce a round trip.

I'm going to leave this issue open until complete.

@hslatman
Copy link

hslatman commented Nov 21, 2024

You may be able to use acmez as the ACME client in the meantime. An example using it with device-attest-01 is available here: https://github.com/mholt/acmez/blob/527e47cae3f84fa3a92d1d9b9c21c5eb0b44359a/examples/attestation/main.go.

jeremyhahn added a commit that referenced this issue Nov 29, 2024
# This is the 1st commit message:

ACME client & server iteration

# This is the commit message #2:

fix http challenge urls. clean up comments

# This is the commit message #3:

Add webapp to public_html. more misc cleanup

# This is the commit message #4:

support configurable / dynamic port assignments for http based challenges

# This is the commit message #5:

misc bug fixes and cleanup

# This is the commit message #6:

- Add key rotation support to key stores
- Add overwrite flag to key store backend and save operations
- Add docker and packer support for the core platform and RPI
- Create Trusted Platform ISO build scripts
- Re-organize webservice package, decouple configs
- Add ACME client cross-signing support
- Create examples directory

# This is the commit message #7:

Remove TSS attestation workflow from core project, move to examples

# This is the commit message #8:

Remove protobuf from core project, relocate to TSS examples

# This is the commit message #9:

- Add support for external ACME servers (tested w/ LetsEncrypt)
- Add DNS server w/ support for internal and public DNS zones
- Add full support for dns-01 ACME challenge w/ DNS server integration
- Create docker based ISO builders

# This is the commit message #10:

- Add support for automated ACME certificates deployed to web server
  via external CA's (e.g. LetsEncrypt)
- Add virtual hosts, url rewrite and reverse proxy support to web server
- Add support for HTTP/3 QUIC
- Create build-public-html target to automate dashboard build
- Re-organize configs, cleanup
- Create custom security logging facility
- Add ACME docs, lots of cleanup
- Fix bugs and broken tests
- Clean up VS code tasks and targets
- Iterate on minimal docker and ISO build targets for platform and ansible
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

No branches or pull requests

4 participants