Skip to content

Commit

Permalink
Add v2 tpm nonce support
Browse files Browse the repository at this point in the history
  • Loading branch information
Joshua Krstic committed Sep 13, 2023
1 parent 51e5a28 commit 7c50047
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 0 deletions.
59 changes: 59 additions & 0 deletions launcher/tpm_nonce/tpm_nonce.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package internal

Check warning on line 1 in launcher/tpm_nonce/tpm_nonce.go

View workflow job for this annotation

GitHub Actions / Lint ./launcher (ubuntu-latest, Go 1.20.x)

package-comments: should have a package comment (revive)

import (
"bytes"
"crypto/sha256"
"fmt"
"sort"
"strings"
)

const (
// ChallengePrefix is the prefix on all challenges generated by the Attestation Service.
ChallengePrefix = "GoogAttestV1"
// NoncePrefix is the prefix on the nonce given to the TPM before the quote is generated.
NoncePrefix = "GoogAttestV2"
)

// GenerateTpmNonce generates the nonce to give to the TPM before getting a quote.
// TpmNonce = noncePrefix | SHA256(C | SHA256(sort[applyPrefix(arr)])
// C == GoogAttestV1 | 128bits entropy
func GenerateTpmNonce(challenge []byte, nonces [][]byte) ([]byte, error) {
if challenge == nil || !strings.HasPrefix(string(challenge), ChallengePrefix) {
return nil, fmt.Errorf("expected GoogAttestV1 challenge, got %v", challenge)
}

// No custom nonces specified is OK.
if nonces == nil {
nonces = [][]byte{}
}

// Prefix the length of each nonce to itself.
for i, s := range nonces {
l := byte(len(s))
nonces[i] = append([]byte{l}, s...)
}

// Sort nonces.
sort.Slice(nonces, func(i, j int) bool {
return bytes.Compare(nonces[i], nonces[j]) == -1
})

// Concatenate nonces.
cat := []byte{}
for _, v := range nonces {
cat = append(cat, v...)
}

// Take the SHA256 sum of the concatenated nonces.
nonceHash := sha256.Sum256(cat)

// Concatenate the challenge with the hashed nonces.
challengeCat := append(challenge, nonceHash[:]...)

// Hash the newly concatenated challenge.
challengeHash := sha256.Sum256(challengeCat)

// Return the noncePrefix concatenated with the hashed challenge.
return append([]byte(NoncePrefix), challengeHash[:]...), nil
}
87 changes: 87 additions & 0 deletions launcher/tpm_nonce/tpm_nonce_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package internal

import (
b64 "encoding/base64"
"strings"
"testing"
)

func TestGenerateTpmNonce(t *testing.T) {
challenge := "GoogAttestV1lcdYd8KX3W3uESVrPbmTjA"
nonces := [][]byte{
[]byte("GoogAttestV1lddYd8KX3W3uESVrPbmTjA"),
[]byte("ThisIsACustomNonce"),
}

tpmNonce, err := GenerateTpmNonce([]byte(challenge), nonces)

if err != nil {
t.Errorf("expected no error, got %v", err)
t.Fail()
}
if len(tpmNonce) != 44 {
t.Errorf("expected a nonce 44 bytes long, got %d bytes", len(tpmNonce))
}
tpmNonceString := string(tpmNonce)
if !strings.HasPrefix(tpmNonceString, "GoogAttestV2") {
t.Errorf("expected a with prefix 'GoogAttestV2', actual nonce %v", tpmNonceString)
t.Fail()
}
}

func TestGenerateTpmNonceNilCustomNonces(t *testing.T) {
challenge := "GoogAttestV1lcdYd8KX3W3uESVrPbmTjA"

tpmNonce, err := GenerateTpmNonce([]byte(challenge), nil)

if err != nil {
t.Errorf("expected no error, got %v", err)
t.Fail()
}
if len(tpmNonce) != 44 {
t.Errorf("expected a nonce 44 bytes long, got %d bytes", len(tpmNonce))
}
tpmNonceString := string(tpmNonce)
if !strings.HasPrefix(tpmNonceString, "GoogAttestV2") {
t.Errorf("expected a with prefix 'GoogAttestV2', actual nonce %v", tpmNonceString)
t.Fail()
}
}

func TestGenerateTpmNonceEmptyCustomNonces(t *testing.T) {
challenge := "GoogAttestV1lcdYd8KX3W3uESVrPbmTjA"

tpmNonce, err := GenerateTpmNonce([]byte(challenge), [][]byte{})

if err != nil {
t.Errorf("expected no error, got %v", err)
}
if len(tpmNonce) != 44 {
t.Errorf("expected a nonce 44 bytes long, got %d bytes", len(tpmNonce))
}
tpmNonceString := string(tpmNonce)
if !strings.HasPrefix(tpmNonceString, "GoogAttestV2") {
t.Errorf("expected a with prefix 'GoogAttestV2', actual nonce %v", tpmNonceString)
}
}

func TestGenerateTpmNonceBase64ChallengeError(t *testing.T) {
challenge := "GoogAttestV1lcdYd8KX3W3uESVrPbmTjA"
base64Challenge := []byte(b64.StdEncoding.EncodeToString([]byte(challenge)))

_, err := GenerateTpmNonce(base64Challenge, nil)

if err == nil {
t.Errorf("expected error")
}
}

func TestGenerateTpmNonceNoChallengeError(t *testing.T) {
challenge := ""

_, err := GenerateTpmNonce([]byte(challenge), nil)

if err == nil {
t.Errorf("expected error")
}
}

0 comments on commit 7c50047

Please sign in to comment.