2019-03-28 20:21:16 +00:00
Go-Attestation
==============
2019-08-06 00:32:18 +00:00
[![GoDoc ](https://godoc.org/github.com/google/go-attestation/attest?status.svg )](https://godoc.org/github.com/google/go-attestation/attest)
2019-03-28 20:21:16 +00:00
Go-Attestation abstracts remote attestation operations across a variety of platforms
2019-11-06 16:46:56 +00:00
and TPMs, enabling remote validation of machine identity and state. This project
attempts to provide high level primitives for both client and server logic.
2019-03-28 20:21:16 +00:00
2019-11-06 16:46:56 +00:00
Talks on this project:
* _"Making Device Identity Trustworthy"_ - Open Source Summit Europe - October 2019 - ([Slides](https://static.sched.com/hosted_files/osseu19/ec/Device%20Identity.pdf))
* _"Using TPMs to Cryptographically Verify Devices at Scale"_ - Open Source Summit North America - September 2019 - ([Video](https://www.youtube.com/watch?v=EmEymlA5Q5Q) 39min)
* _"Making Remote Attestation Useful on Linux"_ - Linux Security Summit - September 2019 - ([Video](https://www.youtube.com/watch?v=TKva_h66Ptc) 26min)
## Status
2021-09-01 00:45:37 +00:00
Go-Attestation is under active development. Expect
2019-11-06 16:46:56 +00:00
API changes at any time.
Please note that this is not an official Google product.
2019-08-29 16:36:35 +00:00
2021-12-09 00:43:38 +00:00
TPM 1.2 support is best effort, meaning we will accept fixes for TPM 1.2, but
testing is not covered by CI.
2019-08-29 16:36:35 +00:00
## Installation
The go-attestation package is installable using go get: `go get github.com/google/go-attestation/attest`
2021-12-09 00:43:38 +00:00
### TPM1.2
By default, go-attestation does not build in TPM1.2 support on Linux.
Linux users must install [`libtspi` ](http://trousers.sourceforge.net/ ) and its headers if they need TPM 1.2 support. This can be installed on debian-based systems using: `sudo apt-get install libtspi-dev` .
Then, build go-attestation with the `tspi` [build tag ](https://pkg.go.dev/go/build#hdr-Build_Constraints ) `go build --tags=tspi` .
Windows users can use go-attestation with TPM1.2 by default.
2019-08-29 16:36:35 +00:00
2019-11-06 16:46:56 +00:00
## Example: device identity
2019-03-28 20:21:16 +00:00
2019-11-06 16:46:56 +00:00
TPMs can be used to identify a device remotely and provision unique per-device
hardware-bound keys.
2019-03-28 20:21:16 +00:00
2019-11-06 16:46:56 +00:00
TPMs are provisioned with a set of Endorsement Keys (EKs) by the manufacturer.
These optionally include a certificate signed by the manufacturer and act as a
TPM's identity. For privacy reasons the EK can't be used to sign or encrypt data
directly, and is instead used to attest to the presence of a signing key, an
Attestation Key (AK), on the same TPM. (Newer versions of the spec may allow the
EK to sign directly.)
During attestation, a TPM generates an AK and proves to a certificate authority
that the AK is on the same TPM as a EK. If the certificate authority trusts the
EK, it can transitively trust the AK, for example by issuing a certificate for
the AK.
To perform attestation, the client generates an AK and sends the EK and AK
parameters to the server:
```go
2019-12-11 21:02:49 +00:00
// Client generates an AK and sends it to the server
2019-11-06 16:46:56 +00:00
config := & attest.OpenConfig{}
tpm, err := attest.OpenTPM(config)
if err != nil {
// handle error
}
eks, err := tpm.EKs()
if err != nil {
// handle error
}
ek := eks[0]
akConfig := & attest.AKConfig{}
2020-06-10 14:57:09 +00:00
ak, err := tpm.NewAK(akConfig)
2019-11-06 16:46:56 +00:00
if err != nil {
// handle error
}
attestParams := ak.AttestationParameters()
akBytes, err := ak.Marshal()
if err != nil {
// handle error
}
2022-11-01 19:57:06 +00:00
if err := os.WriteFile("encrypted_aik.json", akBytes, 0600); err != nil {
2019-11-06 16:46:56 +00:00
// handle error
}
// send TPM version, EK, and attestParams to the server
```
The server uses the EK and AK parameters to generate a challenge encrypted to
the EK, returning the challenge to the client. During this phase, the server
determines if it trusts the EK, either by chaining its certificate to a known
manufacturer and/or querying an inventory system.
```go
// Server validates EK and/or EK certificate
params := attest.ActivationParameters{
TPMVersion: tpmVersion,
EK: ek.Public,
AK: attestParams,
}
secret, encryptedCredentials, err := params.Generate()
if err != nil {
// handle error
}
// return encrypted credentials to client
```
The client proves possession of the AK by decrypting the challenge and
returning the same secret to the server.
```go
// Client decrypts the credential
2022-11-01 19:57:06 +00:00
akBytes, err := os.ReadFile("encrypted_aik.json")
2019-11-06 16:46:56 +00:00
if err != nil {
// handle error
}
ak, err := tpm.LoadAK(akBytes)
if err != nil {
// handle error
}
secret, err := ak.ActivateCredential(tpm, encryptedCredentials)
if err != nil {
// handle error
}
// return secret to server
```
At this point, the server records the AK and EK association and allows the client
to use its AK as a credential (e.g. by issuing it a client certificate).