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

Add fake client that cleanly implements the Client interface instead of using GRPC libraries. #234

Merged
merged 1 commit into from
Aug 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion launcher/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func (a *agent) MeasureEvent(event cel.Content) error {

// Attest fetches the nonce and connection ID from the Attestation Service,
// creates an attestation message, and returns the resultant
// principalIDTokens are Metadata Server-generated ID tokens for the instance.
// principalIDTokens and Metadata Server-generated ID tokens for the instance.
func (a *agent) Attest(ctx context.Context) ([]byte, error) {
challenge, err := a.client.CreateChallenge(ctx)
if err != nil {
Expand Down
64 changes: 32 additions & 32 deletions launcher/agent/agent_test.go
Original file line number Diff line number Diff line change
@@ -1,58 +1,58 @@
package agent

import (
"bytes"
"context"
"log"
"net"
"crypto/rand"
"crypto/rsa"
"fmt"
"testing"

"github.com/golang-jwt/jwt/v4"
"github.com/google/go-tpm-tools/client"
"github.com/google/go-tpm-tools/internal/test"
"github.com/google/go-tpm-tools/launcher/verifier/grpcclient"
"github.com/google/go-tpm-tools/launcher/verifier/grpcclient/service"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/test/bufconn"

servgrpc "github.com/google/go-tpm-tools/launcher/verifier/grpcclient/proto/attestation_verifier/v0"
"github.com/google/go-tpm-tools/launcher/verifier/fake"
)

func TestAttest(t *testing.T) {
tpm := test.GetTPM(t)
defer client.CheckedClose(t, tpm)

server := grpc.NewServer()

fakeServer := service.New()
servgrpc.RegisterAttestationVerifierServer(server, &fakeServer)

lis := bufconn.Listen(1024 * 1024)
go func() {
if err := server.Serve(lis); err != nil {
log.Fatalf("Server exited with error: %v", err)
}
}()
bufDialer := func(context.Context, string) (net.Conn, error) {
return lis.Dial()
}

conn, err := grpc.DialContext(context.Background(), "bufconn", grpc.WithContextDialer(bufDialer), grpc.WithTransportCredentials(insecure.NewCredentials()))
fakeSigner, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
t.Fatalf("failed to connect to attestation service: %v", err)
t.Errorf("Failed to generate signing key %v", err)
}
verifierClient := grpcclient.NewClient(conn, log.Default())
// Cannot test a GCE key on the simulator.
verifierClient := fake.NewClient(fakeSigner)
agent := CreateAttestationAgent(tpm, client.AttestationKeyECC, verifierClient, placeholderFetcher)

token, err := agent.Attest(context.Background())
tokenBytes, err := agent.Attest(context.Background())
if err != nil {
t.Errorf("failed to attest to Attestation Service: %v", err)
}

if !bytes.Equal(token, service.FakeToken) {
t.Errorf("received unexpected token: %v, expected: %v", token, service.FakeToken)
registeredClaims := &jwt.RegisteredClaims{}
keyFunc := func(token *jwt.Token) (interface{}, error) { return fakeSigner.Public(), nil }
token, err := jwt.ParseWithClaims(string(tokenBytes), registeredClaims, keyFunc)
if err != nil {
t.Errorf("Failed to parse token %s", err)
}

if err = registeredClaims.Valid(); err != nil {
t.Errorf("Invalid exp, iat, or nbf: %s", err)
}

if !registeredClaims.VerifyAudience("https://sts.googleapis.com/", true) {
t.Errorf("Invalid aud")
}

if !registeredClaims.VerifyIssuer("https://confidentialcomputing.googleapis.com/", true) {
t.Errorf("Invalid iss")
}

if registeredClaims.Subject != "https://www.googleapis.com/compute/v1/projects/fakeProject/zones/fakeZone/instances/fakeInstance" {
t.Errorf("Invalid sub")
}

fmt.Printf("token.Claims: %v\n", token.Claims)
}

func placeholderFetcher(audience string) ([][]byte, error) {
Expand Down
66 changes: 66 additions & 0 deletions launcher/verifier/fake/fakeverifier.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Package fake is a fake implementation of the Client interface for testing.
package fake

import (
"context"
"crypto"
"encoding/binary"
"time"

"github.com/golang-jwt/jwt/v4"
"github.com/google/go-tpm-tools/launcher/verifier"
)

type fakeClient struct {
signer crypto.Signer
}

// NewClient contructs a new fake client given a crypto.Signer.
func NewClient(signer crypto.Signer) verifier.Client {
return &fakeClient{signer}
}

// CreateChallenge returns a hard coded, basic challenge.
//
// If you have found this method is insufficient for your tests, this class must be updated to
// allow for better testing.
func (fc *fakeClient) CreateChallenge(ctx context.Context) (*verifier.Challenge, error) {
bs := make([]byte, 2)
binary.LittleEndian.PutUint16(bs, 15)
return &verifier.Challenge{
Name: "projects/fakeProject/locations/fakeRegion/challenges/d882c62f-452f-4709-9335-0cccaf64eee1",
Nonce: bs,
}, nil
}

// VerifyAttestation does basic checks and returns a hard coded attestation response.
//
// If you have found this method is insufficient for your tests, this class must be updated to
// allow for better testing.
func (fc *fakeClient) VerifyAttestation(ctx context.Context, request verifier.VerifyAttestationRequest) (*verifier.VerifyAttestationResponse, error) {
// Determine signing algorithm.
signingMethod := jwt.SigningMethodRS256
now := jwt.TimeFunc()
claims := jwt.RegisteredClaims{
IssuedAt: &jwt.NumericDate{Time: now},
NotBefore: &jwt.NumericDate{Time: now},
ExpiresAt: &jwt.NumericDate{Time: now.Add(time.Hour)},
Audience: []string{"https://sts.googleapis.com/"},
Issuer: "https://confidentialcomputing.googleapis.com/",
Subject: "https://www.googleapis.com/compute/v1/projects/fakeProject/zones/fakeZone/instances/fakeInstance",
}

token := jwt.NewWithClaims(signingMethod, claims)

// Instead of a private key, provide the signer.
signed, err := token.SignedString(fc.signer)
if err != nil {
return nil, err
}

response := verifier.VerifyAttestationResponse{
ClaimsToken: []byte(signed),
}

return &response, nil
}
81 changes: 0 additions & 81 deletions launcher/verifier/grpcclient/service/fake_attestationverifier.go

This file was deleted.

111 changes: 0 additions & 111 deletions launcher/verifier/grpcclient/service/fake_attestationverifier_test.go

This file was deleted.

This file was deleted.