Skip to content

Commit

Permalink
Support RSA application keys (#218)
Browse files Browse the repository at this point in the history
  • Loading branch information
pszal authored May 20, 2021
1 parent 7f6fec6 commit 0b7298f
Show file tree
Hide file tree
Showing 5 changed files with 332 additions and 32 deletions.
4 changes: 2 additions & 2 deletions attest/application_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type key interface {
close(tpmBase) error
marshal() ([]byte, error)
certificationParameters() CertificationParameters
sign(tpmBase, []byte) ([]byte, error)
sign(tpmBase, []byte, crypto.PublicKey, crypto.SignerOpts) ([]byte, error)
decrypt(tpmBase, []byte) ([]byte, error)
blobs() ([]byte, []byte, error)
}
Expand All @@ -48,7 +48,7 @@ type signer struct {

// Sign signs digest with the TPM-stored private signing key.
func (s *signer) Sign(r io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
return s.key.sign(s.tpm, digest)
return s.key.sign(s.tpm, digest, s.pub, opts)
}

// Public returns the public key corresponding to the private signing key.
Expand Down
164 changes: 149 additions & 15 deletions attest/application_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,23 @@ func testKeyCreateAndLoad(t *testing.T, tpm *TPM) {
Size: 521,
},
},
{
name: "RSA-1024",
opts: &KeyConfig{
Algorithm: RSA,
Size: 1024,
},
},
{
name: "RSA-2048",
opts: &KeyConfig{
Algorithm: RSA,
Size: 2048,
},
},
} {
t.Run(test.name, func(t *testing.T) {
sk, err := tpm.NewKey(ak, nil)
sk, err := tpm.NewKey(ak, test.opts)
if err != nil {
t.Fatalf("NewKey() failed: %v", err)
}
Expand Down Expand Up @@ -164,48 +178,131 @@ func TestTPM20KeySign(t *testing.T) {
testKeySign(t, tpm)
}

type simpleOpts struct {
Hash crypto.Hash
}

func (o *simpleOpts) HashFunc() crypto.Hash {
return o.Hash
}

func testKeySign(t *testing.T, tpm *TPM) {
ak, err := tpm.NewAK(nil)
if err != nil {
t.Fatalf("NewAK() failed: %v", err)
}

for _, test := range []struct {
name string
opts *KeyConfig
digest []byte
name string
keyOpts *KeyConfig
signOpts crypto.SignerOpts
digest []byte
}{
{
name: "default",
opts: nil,
digest: []byte("12345678901234567890123456789012"),
name: "default",
keyOpts: nil,
signOpts: nil,
digest: []byte("12345678901234567890123456789012"),
},
{
name: "ECDSAP256-SHA256",
opts: &KeyConfig{
keyOpts: &KeyConfig{
Algorithm: ECDSA,
Size: 256,
},
digest: []byte("12345678901234567890123456789012"),
signOpts: nil,
digest: []byte("12345678901234567890123456789012"),
},
{
name: "ECDSAP384-SHA384",
opts: &KeyConfig{
keyOpts: &KeyConfig{
Algorithm: ECDSA,
Size: 384,
},
digest: []byte("123456789012345678901234567890121234567890123456"),
signOpts: nil,
digest: []byte("123456789012345678901234567890121234567890123456"),
},
{
name: "ECDSAP521-SHA512",
opts: &KeyConfig{
keyOpts: &KeyConfig{
Algorithm: ECDSA,
Size: 521,
},
signOpts: nil,
digest: []byte("1234567890123456789012345678901212345678901234567890123456789012"),
},
{
name: "RSA2048-PKCS1v15-SHA256",
keyOpts: &KeyConfig{
Algorithm: RSA,
Size: 2048,
},
signOpts: &simpleOpts{
Hash: crypto.SHA256,
},
digest: []byte("12345678901234567890123456789012"),
},
{
name: "RSA2048-PKCS1v15-SHA384",
keyOpts: &KeyConfig{
Algorithm: RSA,
Size: 2048,
},
signOpts: &simpleOpts{
Hash: crypto.SHA384,
},
digest: []byte("123456789012345678901234567890121234567890123456"),
},
{
name: "RSA2048-PKCS1v15-SHA512",
keyOpts: &KeyConfig{
Algorithm: RSA,
Size: 2048,
},
signOpts: &simpleOpts{
Hash: crypto.SHA512,
},
digest: []byte("1234567890123456789012345678901212345678901234567890123456789012"),
},
{
name: "RSA2048-PSS-SHA256",
keyOpts: &KeyConfig{
Algorithm: RSA,
Size: 2048,
},
signOpts: &rsa.PSSOptions{
SaltLength: rsa.PSSSaltLengthAuto,
Hash: crypto.SHA256,
},
digest: []byte("12345678901234567890123456789012"),
},
{
name: "RSA2048-PSS-SHA384",
keyOpts: &KeyConfig{
Algorithm: RSA,
Size: 2048,
},
signOpts: &rsa.PSSOptions{
SaltLength: rsa.PSSSaltLengthAuto,
Hash: crypto.SHA384,
},
digest: []byte("123456789012345678901234567890121234567890123456"),
},
{
name: "RSA2048-PSS-SHA512",
keyOpts: &KeyConfig{
Algorithm: RSA,
Size: 2048,
},
signOpts: &rsa.PSSOptions{
SaltLength: rsa.PSSSaltLengthAuto,
Hash: crypto.SHA512,
},
digest: []byte("1234567890123456789012345678901212345678901234567890123456789012"),
},
} {
t.Run(test.name, func(t *testing.T) {
sk, err := tpm.NewKey(ak, test.opts)
sk, err := tpm.NewKey(ak, test.keyOpts)
if err != nil {
t.Fatalf("NewKey() failed: %v", err)
}
Expand All @@ -220,12 +317,16 @@ func testKeySign(t *testing.T, tpm *TPM) {
if !ok {
t.Fatalf("want crypto.Signer, got %T", priv)
}
sig, err := signer.Sign(rand.Reader, test.digest, nil)
sig, err := signer.Sign(rand.Reader, test.digest, test.signOpts)
if err != nil {
t.Fatalf("signer.Sign() failed: %v", err)
}

verifyECDSA(t, pub, test.digest, sig)
if test.keyOpts == nil || test.keyOpts.Algorithm == ECDSA {
verifyECDSA(t, pub, test.digest, sig)
} else {
verifyRSA(t, pub, test.digest, sig, test.signOpts)
}
})
}
}
Expand All @@ -246,6 +347,23 @@ func verifyECDSA(t *testing.T, pub crypto.PublicKey, digest, sig []byte) {
}
}

func verifyRSA(t *testing.T, pub crypto.PublicKey, digest, sig []byte, opts crypto.SignerOpts) {
t.Helper()
pubRSA, ok := pub.(*rsa.PublicKey)
if !ok {
t.Fatalf("want *rsa.PublicKey, got %T", pub)
}
if pss, ok := opts.(*rsa.PSSOptions); ok {
if err := rsa.VerifyPSS(pubRSA, opts.HashFunc(), digest, sig, pss); err != nil {
t.Fatalf("rsa.VerifyPSS(): %v", err)
}
} else {
if err := rsa.VerifyPKCS1v15(pubRSA, opts.HashFunc(), digest, sig); err != nil {
t.Fatalf("signature verification failed: %v", err)
}
}
}

func TestSimTPM20KeyOpts(t *testing.T) {
sim, tpm := setupSimulatedTPM(t)
defer sim.Close()
Expand Down Expand Up @@ -318,6 +436,22 @@ func testKeyOpts(t *testing.T, tpm *TPM) {
},
err: false,
},
{
name: "RSA-1024",
opts: &KeyConfig{
Algorithm: RSA,
Size: 1024,
},
err: false,
},
{
name: "RSA-2048",
opts: &KeyConfig{
Algorithm: RSA,
Size: 2048,
},
err: false,
},
} {
t.Run(test.name, func(t *testing.T) {
sk, err := tpm.NewKey(ak, test.opts)
Expand Down
127 changes: 124 additions & 3 deletions attest/certification_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,25 @@ import (
"github.com/google/go-tpm/tpm2"
)

func TestCertificationParametersTPM20(t *testing.T) {
s, tpm := setupSimulatedTPM(t)
defer s.Close()
func TestSimTPM20CertificationParameters(t *testing.T) {
sim, tpm := setupSimulatedTPM(t)
defer sim.Close()
testCertificationParameters(t, tpm)
}

func TestTPM20CertificationParameters(t *testing.T) {
if !*testLocal {
t.SkipNow()
}
tpm, err := OpenTPM(nil)
if err != nil {
t.Fatalf("OpenTPM() failed: %v", err)
}
defer tpm.Close()
testCertificationParameters(t, tpm)
}

func testCertificationParameters(t *testing.T, tpm *TPM) {
ak, err := tpm.NewAK(nil)
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -148,3 +163,109 @@ func TestCertificationParametersTPM20(t *testing.T) {
})
}
}

func TestSimTPM20KeyCertification(t *testing.T) {
sim, tpm := setupSimulatedTPM(t)
defer sim.Close()
testKeyCertification(t, tpm)
}

func TestTPM20KeyCertification(t *testing.T) {
if !*testLocal {
t.SkipNow()
}
tpm, err := OpenTPM(nil)
if err != nil {
t.Fatalf("OpenTPM() failed: %v", err)
}
defer tpm.Close()
testKeyCertification(t, tpm)
}

func testKeyCertification(t *testing.T, tpm *TPM) {
ak, err := tpm.NewAK(nil)
if err != nil {
t.Fatalf("NewAK() failed: %v", err)
}
akAttestParams := ak.AttestationParameters()
pub, err := tpm2.DecodePublic(akAttestParams.Public)
if err != nil {
t.Fatalf("DecodePublic() failed: %v", err)
}
pk := &rsa.PublicKey{E: int(pub.RSAParameters.Exponent()), N: pub.RSAParameters.Modulus()}
hash, err := pub.RSAParameters.Sign.Hash.Hash()
if err != nil {
t.Fatalf("cannot access AK's hash function: %v", err)
}
verifyOpts := VerifyOpts{
Public: pk,
Hash: hash,
}
for _, test := range []struct {
name string
opts *KeyConfig
err error
}{
{
name: "default",
opts: nil,
err: nil,
},
{
name: "ECDSAP256-SHA256",
opts: &KeyConfig{
Algorithm: ECDSA,
Size: 256,
},
err: nil,
},
{
name: "ECDSAP384-SHA384",
opts: &KeyConfig{
Algorithm: ECDSA,
Size: 384,
},
err: nil,
},
{
name: "ECDSAP521-SHA512",
opts: &KeyConfig{
Algorithm: ECDSA,
Size: 521,
},
err: nil,
},
{
name: "RSA-1024, key too short",
opts: &KeyConfig{
Algorithm: RSA,
Size: 1024,
},
err: cmpopts.AnyError,
},
{
name: "RSA-2048",
opts: &KeyConfig{
Algorithm: RSA,
Size: 2048,
},
err: nil,
},
} {
t.Run(test.name, func(t *testing.T) {
sk, err := tpm.NewKey(ak, test.opts)
if err != nil {
t.Fatalf("NewKey() failed: %v", err)
}
defer sk.Close()
p := sk.CertificationParameters()
err = p.Verify(verifyOpts)
if test.err == nil && err == nil {
return
}
if got, want := err, test.err; !cmp.Equal(got, want, cmpopts.EquateErrors()) {
t.Errorf("p.Verify() err = %v, want = %v", got, want)
}
})
}
}
Loading

0 comments on commit 0b7298f

Please sign in to comment.