forked from TrueCloudLab/certificates
Add tests for doTPMAttestationFormat
This commit is contained in:
parent
ae30f6e96b
commit
52023d6083
2 changed files with 453 additions and 31 deletions
|
@ -446,7 +446,7 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose
|
||||||
az.Fingerprint = data.Fingerprint
|
az.Fingerprint = data.Fingerprint
|
||||||
|
|
||||||
case "tpm":
|
case "tpm":
|
||||||
data, err := doTPMAttestationFormat(ctx, ch, db, jwk, &att)
|
data, err := doTPMAttestationFormat(ctx, prov, ch, jwk, &att)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO(hs): we should provide more details in the error reported to the client;
|
// TODO(hs): we should provide more details in the error reported to the client;
|
||||||
// "Attestation statement cannot be verified" is VERY generic. Also holds true for the other formats.
|
// "Attestation statement cannot be verified" is VERY generic. Also holds true for the other formats.
|
||||||
|
@ -511,13 +511,7 @@ type tpmAttestationData struct {
|
||||||
Fingerprint string
|
Fingerprint string
|
||||||
}
|
}
|
||||||
|
|
||||||
func doTPMAttestationFormat(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWebKey, att *attestationObject) (*tpmAttestationData, error) {
|
func doTPMAttestationFormat(ctx context.Context, prov Provisioner, ch *Challenge, jwk *jose.JSONWebKey, att *attestationObject) (*tpmAttestationData, error) {
|
||||||
p := MustProvisionerFromContext(ctx)
|
|
||||||
prov, ok := p.(*provisioner.ACME)
|
|
||||||
if !ok {
|
|
||||||
return nil, NewErrorISE("provisioner in context is not an ACME provisioner")
|
|
||||||
}
|
|
||||||
|
|
||||||
ver, ok := att.AttStatement["ver"].(string)
|
ver, ok := att.AttStatement["ver"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, NewError(ErrorBadAttestationStatementType, "ver not present")
|
return nil, NewError(ErrorBadAttestationStatementType, "ver not present")
|
||||||
|
@ -577,7 +571,7 @@ func doTPMAttestationFormat(ctx context.Context, ch *Challenge, db DB, jwk *jose
|
||||||
|
|
||||||
roots, ok := prov.GetAttestationRoots()
|
roots, ok := prov.GetAttestationRoots()
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, NewErrorISE("failed getting tpm attestation root CAs")
|
return nil, NewErrorISE("failed getting TPM attestation root CAs")
|
||||||
}
|
}
|
||||||
|
|
||||||
verifiedChains, err := akCert.Verify(x509.VerifyOptions{
|
verifiedChains, err := akCert.Verify(x509.VerifyOptions{
|
||||||
|
@ -605,24 +599,6 @@ func doTPMAttestationFormat(ctx context.Context, ch *Challenge, db DB, jwk *jose
|
||||||
return nil, NewError(ErrorBadAttestationStatementType, "AK certificate is missing Subject Alternative Name extension")
|
return nil, NewError(ErrorBadAttestationStatementType, "AK certificate is missing Subject Alternative Name extension")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(hs): below code fails if there's a URI SAN, for example. Needs more complete parsing of SANS,
|
|
||||||
// or skip ASN1 tags that can't be parsed.
|
|
||||||
// san, err := x509ext.ParseSubjectAltName(sanExtension) // TODO(hs): move to a package under our control?
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, WrapError(ErrorBadAttestationStatementType, err, "failed parsing Subject Alternative Name extension")
|
|
||||||
// }
|
|
||||||
|
|
||||||
// var permanentIdentifiers = make([]string, len(san.PermanentIdentifiers))
|
|
||||||
// for i, p := range san.PermanentIdentifiers {
|
|
||||||
// permanentIdentifiers[i] = p.IdentifierValue
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO(hs): reenable this check when we want to enforce a PermanentIdentifier to be present in
|
|
||||||
// the AK certificate.
|
|
||||||
// if len(permanentIdentifiers) == 0 {
|
|
||||||
// return nil, NewError(ErrorBadAttestationStatementType, "AK certificate doesn't contain a PermanentIdentifier")
|
|
||||||
// }
|
|
||||||
|
|
||||||
// extract and validate pubArea, sig, certInfo and alg properties from the request body
|
// extract and validate pubArea, sig, certInfo and alg properties from the request body
|
||||||
pubArea, ok := att.AttStatement["pubArea"].([]byte)
|
pubArea, ok := att.AttStatement["pubArea"].([]byte)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -680,7 +656,7 @@ func doTPMAttestationFormat(ctx context.Context, ch *Challenge, db DB, jwk *jose
|
||||||
return nil, WrapError(ErrorBadAttestationStatementType, err, "invalid certification parameters")
|
return nil, WrapError(ErrorBadAttestationStatementType, err, "invalid certification parameters")
|
||||||
}
|
}
|
||||||
|
|
||||||
// decode the "certInfo" data
|
// decode the "certInfo" data. This won't fail, as it's also done as part of Verify().
|
||||||
tpmCertInfo, err := tpm2.DecodeAttestationData(certInfo)
|
tpmCertInfo, err := tpm2.DecodeAttestationData(certInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, WrapError(ErrorBadAttestationStatementType, err, "failed decoding attestation data")
|
return nil, WrapError(ErrorBadAttestationStatementType, err, "failed decoding attestation data")
|
||||||
|
@ -698,7 +674,7 @@ func doTPMAttestationFormat(ctx context.Context, ch *Challenge, db DB, jwk *jose
|
||||||
return nil, NewError(ErrorBadAttestationStatementType, "key authorization does not match")
|
return nil, NewError(ErrorBadAttestationStatementType, "key authorization does not match")
|
||||||
}
|
}
|
||||||
|
|
||||||
// decode the (attested) public key and determine its fingerprint
|
// decode the (attested) public key and determine its fingerprint. This won't fail, as it's also done as part of Verify().
|
||||||
pub, err := tpm2.DecodePublic(pubArea)
|
pub, err := tpm2.DecodePublic(pubArea)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, WrapError(ErrorBadAttestationStatementType, err, "failed decoding pubArea")
|
return nil, WrapError(ErrorBadAttestationStatementType, err, "failed decoding pubArea")
|
||||||
|
@ -712,7 +688,6 @@ func doTPMAttestationFormat(ctx context.Context, ch *Challenge, db DB, jwk *jose
|
||||||
data := &tpmAttestationData{
|
data := &tpmAttestationData{
|
||||||
Certificate: akCert,
|
Certificate: akCert,
|
||||||
VerifiedChains: verifiedChains,
|
VerifiedChains: verifiedChains,
|
||||||
//PermanentIdentifiers: permanentIdentifiers,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.Fingerprint, err = keyutil.Fingerprint(publicKey); err != nil {
|
if data.Fingerprint, err = keyutil.Fingerprint(publicKey); err != nil {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
"errors"
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -63,6 +64,7 @@ func generateKeyID(t *testing.T, pub crypto.PublicKey) []byte {
|
||||||
func mustAttestTPM(t *testing.T, keyAuthorization string) ([]byte, crypto.Signer, *x509.Certificate) {
|
func mustAttestTPM(t *testing.T, keyAuthorization string) ([]byte, crypto.Signer, *x509.Certificate) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
aca, err := minica.New(
|
aca, err := minica.New(
|
||||||
|
minica.WithName("TPM Testing"),
|
||||||
minica.WithGetSignerFunc(
|
minica.WithGetSignerFunc(
|
||||||
func() (crypto.Signer, error) {
|
func() (crypto.Signer, error) {
|
||||||
return keyutil.GenerateSigner("RSA", "", 2048)
|
return keyutil.GenerateSigner("RSA", "", 2048)
|
||||||
|
@ -133,7 +135,7 @@ func mustAttestTPM(t *testing.T, keyAuthorization string) ([]byte, crypto.Signer
|
||||||
AttStatement: map[string]interface{}{
|
AttStatement: map[string]interface{}{
|
||||||
"ver": "2.0",
|
"ver": "2.0",
|
||||||
"x5c": []interface{}{akCert.Raw, aca.Intermediate.Raw},
|
"x5c": []interface{}{akCert.Raw, aca.Intermediate.Raw},
|
||||||
"alg": int64(-257), // RSA
|
"alg": int64(-257), // RS256
|
||||||
"sig": params.CreateSignature,
|
"sig": params.CreateSignature,
|
||||||
"certInfo": params.CreateAttestation,
|
"certInfo": params.CreateAttestation,
|
||||||
"pubArea": params.Public,
|
"pubArea": params.Public,
|
||||||
|
@ -292,3 +294,448 @@ func Test_deviceAttest01ValidateWithTPMSimulator(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newBadAttestationStatementError(msg string) *Error {
|
||||||
|
return &Error{
|
||||||
|
Type: "urn:ietf:params:acme:error:badAttestationStatement",
|
||||||
|
Status: 400,
|
||||||
|
Err: errors.New(msg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newInternalServerError(msg string) *Error {
|
||||||
|
return &Error{
|
||||||
|
Type: "urn:ietf:params:acme:error:serverInternal",
|
||||||
|
Status: 500,
|
||||||
|
Err: errors.New(msg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_doTPMAttestationFormat(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
aca, err := minica.New(
|
||||||
|
minica.WithName("TPM Testing"),
|
||||||
|
minica.WithGetSignerFunc(
|
||||||
|
func() (crypto.Signer, error) {
|
||||||
|
return keyutil.GenerateSigner("RSA", "", 2048)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
acaRoot := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: aca.Root.Raw})
|
||||||
|
|
||||||
|
// prepare simulated TPM and create an AK
|
||||||
|
stpm := newSimulatedTPM(t)
|
||||||
|
eks, err := stpm.GetEKs(context.Background())
|
||||||
|
require.NoError(t, err)
|
||||||
|
ak, err := stpm.CreateAK(context.Background(), "first-ak")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, ak)
|
||||||
|
|
||||||
|
// extract the AK public key // TODO(hs): replace this when there's a simpler method to get the AK public key (e.g. ak.Public())
|
||||||
|
ap, err := ak.AttestationParameters(context.Background())
|
||||||
|
require.NoError(t, err)
|
||||||
|
akp, err := attest.ParseAKPublic(attest.TPMVersion20, ap.Public)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// create template and sign certificate for the AK public key
|
||||||
|
keyID := generateKeyID(t, eks[0].Public())
|
||||||
|
template := &x509.Certificate{
|
||||||
|
Subject: pkix.Name{
|
||||||
|
CommonName: "testakcert",
|
||||||
|
},
|
||||||
|
PublicKey: akp.Public,
|
||||||
|
URIs: []*url.URL{
|
||||||
|
{Scheme: "urn", Opaque: "ek:sha256:" + base64.StdEncoding.EncodeToString(keyID)},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
akCert, err := aca.Sign(template)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, akCert)
|
||||||
|
|
||||||
|
templateMissingSAN := &x509.Certificate{
|
||||||
|
Subject: pkix.Name{
|
||||||
|
CommonName: "testakcertmissingsan",
|
||||||
|
},
|
||||||
|
PublicKey: akp.Public,
|
||||||
|
}
|
||||||
|
akCertMissingSAN, err := aca.Sign(templateMissingSAN)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, akCert)
|
||||||
|
|
||||||
|
// generate a JWK and the key authorization value
|
||||||
|
jwk, err := jose.GenerateJWK("EC", "P-256", "ES256", "sig", "", 0)
|
||||||
|
require.NoError(t, err)
|
||||||
|
keyAuthorization, err := KeyAuthorization("token", jwk)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// create a new key attested by the AK, while including
|
||||||
|
// the key authorization bytes as qualifying data.
|
||||||
|
keyAuthSum := sha256.Sum256([]byte(keyAuthorization))
|
||||||
|
config := tpm.AttestKeyConfig{
|
||||||
|
Algorithm: "RSA",
|
||||||
|
Size: 2048,
|
||||||
|
QualifyingData: keyAuthSum[:],
|
||||||
|
}
|
||||||
|
key, err := stpm.AttestKey(context.Background(), "first-ak", "first-key", config)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, key)
|
||||||
|
params, err := key.CertificationParameters(context.Background())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
signer, err := key.Signer(context.Background())
|
||||||
|
require.NoError(t, err)
|
||||||
|
fingerprint, err := keyutil.Fingerprint(signer.Public())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// attest another key and get its certification parameters
|
||||||
|
anotherKey, err := stpm.AttestKey(context.Background(), "first-ak", "another-key", config)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, key)
|
||||||
|
anotherKeyParams, err := anotherKey.CertificationParameters(context.Background())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
type args struct {
|
||||||
|
ctx context.Context
|
||||||
|
prov Provisioner
|
||||||
|
ch *Challenge
|
||||||
|
jwk *jose.JSONWebKey
|
||||||
|
att *attestationObject
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want *tpmAttestationData
|
||||||
|
expErr *Error
|
||||||
|
}{
|
||||||
|
{"ok", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{akCert.Raw, aca.Intermediate.Raw},
|
||||||
|
"alg": int64(-257), //
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, nil},
|
||||||
|
{"fail ver not present", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"x5c": []interface{}{akCert.Raw, aca.Intermediate.Raw},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("ver not present")},
|
||||||
|
{"fail ver type", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": []interface{}{},
|
||||||
|
"x5c": []interface{}{akCert.Raw, aca.Intermediate.Raw},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("ver not present")},
|
||||||
|
{"fail bogus ver", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "bogus",
|
||||||
|
"x5c": []interface{}{akCert.Raw, aca.Intermediate.Raw},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError(`version "bogus" is not supported`)},
|
||||||
|
{"fail x5c not present", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("x5c not present")},
|
||||||
|
{"fail x5c type", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": [][]byte{akCert.Raw, aca.Intermediate.Raw},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("x5c not present")},
|
||||||
|
{"fail x5c empty", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("x5c is empty")},
|
||||||
|
{"fail leaf type", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "step",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{"leaf", aca.Intermediate.Raw},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("x5c is malformed")},
|
||||||
|
{"fail leaf parse", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "step",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{akCert.Raw[:100], aca.Intermediate.Raw},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("x5c is malformed: x509: malformed certificate")},
|
||||||
|
{"fail intermediate type", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "step",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{akCert.Raw, "intermediate"},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("x5c is malformed")},
|
||||||
|
{"fail intermediate parse", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "step",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{akCert.Raw, aca.Intermediate.Raw[:100]},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("x5c is malformed: x509: malformed certificate")},
|
||||||
|
{"fail roots", args{ctx, mustAttestationProvisioner(t, nil), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{akCert.Raw, aca.Intermediate.Raw},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newInternalServerError("failed getting TPM attestation root CAs")},
|
||||||
|
{"fail verify", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "step",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{akCert.Raw},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("x5c is not valid: x509: certificate signed by unknown authority")},
|
||||||
|
{"fail missing SAN extension", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{akCertMissingSAN.Raw, aca.Intermediate.Raw},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("AK certificate is missing Subject Alternative Name extension")},
|
||||||
|
{"fail pubArea not present", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{akCert.Raw, aca.Intermediate.Raw},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("invalid pubArea in attestation statement")},
|
||||||
|
{"fail pubArea type", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{akCert.Raw, aca.Intermediate.Raw},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": []interface{}{},
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("invalid pubArea in attestation statement")},
|
||||||
|
{"fail pubArea empty", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{akCert.Raw, aca.Intermediate.Raw},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": []byte{},
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("pubArea is empty")},
|
||||||
|
{"fail sig not present", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{akCert.Raw, aca.Intermediate.Raw},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("invalid sig in attestation statement")},
|
||||||
|
{"fail sig type", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{akCert.Raw, aca.Intermediate.Raw},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": []interface{}{},
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("invalid sig in attestation statement")},
|
||||||
|
{"fail sig empty", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{akCert.Raw, aca.Intermediate.Raw},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": []byte{},
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("sig is empty")},
|
||||||
|
{"fail certInfo not present", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{akCert.Raw, aca.Intermediate.Raw},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("invalid certInfo in attestation statement")},
|
||||||
|
{"fail certInfo type", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{akCert.Raw, aca.Intermediate.Raw},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": []interface{}{},
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("invalid certInfo in attestation statement")},
|
||||||
|
{"fail certInfo empty", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{akCert.Raw, aca.Intermediate.Raw},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": []byte{},
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("certInfo is empty")},
|
||||||
|
{"fail alg not present", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{akCert.Raw, aca.Intermediate.Raw},
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("invalid alg in attestation statement")},
|
||||||
|
{"fail alg type", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{akCert.Raw, aca.Intermediate.Raw},
|
||||||
|
"alg": int64(0), // invalid alg
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("invalid alg 0 in attestation statement")},
|
||||||
|
{"fail attestation verification", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, jwk, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{akCert.Raw, aca.Intermediate.Raw},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": anotherKeyParams.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("invalid certification parameters: certification refers to a different key")},
|
||||||
|
{"fail keyAuthorization", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "token"}, &jose.JSONWebKey{Key: []byte("not an asymmetric key")}, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{akCert.Raw, aca.Intermediate.Raw},
|
||||||
|
"alg": int64(-257), // RS256
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newInternalServerError("failed creating key auth digest: error generating JWK thumbprint: square/go-jose: unknown key type '[]uint8'")},
|
||||||
|
{"fail different keyAuthorization", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "aDifferentToken"}, jwk, &attestationObject{
|
||||||
|
Format: "tpm",
|
||||||
|
AttStatement: map[string]interface{}{
|
||||||
|
"ver": "2.0",
|
||||||
|
"x5c": []interface{}{akCert.Raw, aca.Intermediate.Raw},
|
||||||
|
"alg": int64(-257), //
|
||||||
|
"sig": params.CreateSignature,
|
||||||
|
"certInfo": params.CreateAttestation,
|
||||||
|
"pubArea": params.Public,
|
||||||
|
},
|
||||||
|
}}, nil, newBadAttestationStatementError("key authorization does not match")},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := doTPMAttestationFormat(tt.args.ctx, tt.args.prov, tt.args.ch, tt.args.jwk, tt.args.att)
|
||||||
|
if tt.expErr != nil {
|
||||||
|
var ae *Error
|
||||||
|
if assert.True(t, errors.As(err, &ae)) {
|
||||||
|
assert.EqualError(t, err, tt.expErr.Error())
|
||||||
|
assert.Equal(t, ae.StatusCode(), tt.expErr.StatusCode())
|
||||||
|
assert.Equal(t, ae.Type, tt.expErr.Type)
|
||||||
|
}
|
||||||
|
assert.Nil(t, got)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if assert.NotNil(t, got) {
|
||||||
|
assert.Equal(t, akCert, got.Certificate)
|
||||||
|
assert.Equal(t, [][]*x509.Certificate{
|
||||||
|
{
|
||||||
|
akCert, aca.Intermediate, aca.Root,
|
||||||
|
},
|
||||||
|
}, got.VerifiedChains)
|
||||||
|
assert.Equal(t, fingerprint, got.Fingerprint)
|
||||||
|
assert.Empty(t, got.PermanentIdentifiers) // currently expected to be always empty
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue