Skip to content

Commit

Permalink
scheme/tpm-enacttrust: BadEvidenceError when token decode fails
Browse files Browse the repository at this point in the history
Return BadEvidenceError when token decoding fails. This is used
distinguish between errors in the user-provided input and internal
server errors. Without this, sending a bad token resulted in a 500
response from the REST frontend.

Signed-off-by: Sergei Trofimov <[email protected]>
  • Loading branch information
setrofim committed Aug 30, 2023
1 parent 2fa992a commit da68896
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 17 deletions.
7 changes: 7 additions & 0 deletions integration-tests/data/claims/enacttrust.badnode.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"node-id": "7df7714e-aa04-4638-bcbf-434b1dd720f1",
"firmware": 7,
"pcrs": [1, 2, 3, 4],
"algorithm": 11,
"digest": "h0KPxSKAPTEGXnvOPPA/5HUJZjHl4Hu9eg/eYMTPJcc="
}
17 changes: 17 additions & 0 deletions integration-tests/data/results/enacttrust.badnode.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"ear.status": "contraindicated",
"ear.trustworthiness-vector": {
"configuration": 99,
"executables": 99,
"file-system": 99,
"hardware": 99,
"instance-identity": 99,
"runtime-opaque": 99,
"sourced-data": 99,
"storage-opaque": 99
},
"ear.appraisal-policy-id": "policy:TPM_ENACTTRUST",
"ear.veraison.policy-claims": {
"problem": "could not establish identity from evidence"
}
}
74 changes: 74 additions & 0 deletions integration-tests/tests/test_enacttrust_badnode.tavern.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
test_name: enacttrust-badnode

marks:
- parametrize:
key:
# Attestation scheme -- this is used to indicate how test cases should
# be constructed (e.g. how the evidence token will be compiled.
- scheme
# Some attestation schemes (currently, only PSA) may support multiple
# profiles. If a scheme does not support multiple profiles, specify it
# as '_'.
- profile
# Which evidence description will be used to construct the evidence token.
- evidence
# The name of the endorsements spec within common.yaml
- endorsements
# Signing keys that will be used to construct the evidence. How this is
# used is dependent on the scheme.
- signing
# Expected structure of the returned EAR (EAT (Entity Attestation
# Token) Attestation Result).
- expected
vals:
- [enacttrust, _, badnode, mini, ec.p256.enacttrust, badnode]

includes:
- !include common.yaml

stages:
- name: submit post request to the provisioning service successfully
request:
method: POST
url: http://{provisioning-service}/endorsement-provisioning/v1/submit
headers:
content-type: '{endorsements-content-type}' # set via hook
file_body: __generated__/endorsements/corim-{scheme}-{endorsements}.cbor
response:
status_code: 200

- name: verify as relying party - creation of session resource
request:
method: POST
url: http://{verification-service}/challenge-response/v1/newSession?nonce={good-nonce}
response:
status_code: 201
save:
headers:
relying-party-session: Location

- name: verify as relying party - submitting the evidence
request:
method: POST
url: http://{verification-service}/challenge-response/v1/{relying-party-session}
headers:
content-type: '{evidence-content-type}' # set via hook
file_body: __generated__/evidence/{scheme}.{evidence}.cbor
response:
status_code: 200
verify_response_with:
- function: checkers:save_result
extra_kwargs:
scheme: '{scheme}'
evidence: '{evidence}'
- function: checkers:compare_to_expected_result
extra_kwargs:
expected: data/results/{scheme}.{expected}.json
verifier_key: data/keys/verifier.jwk

- name: verify as relying party - deleting the session object
request:
method: DELETE
url: http://{verification-service}/challenge-response/v1/{relying-party-session}
response:
status_code: 204
11 changes: 7 additions & 4 deletions integration-tests/utils/generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,12 @@ def generate_evidence(scheme, evidence, nonce, signing, outname):
)
elif scheme == 'enacttrust':
key = signing
generate_eancttrust_evidence_token(
badnode = True if 'badnode' in evidence else False
generate_enacttrust_evidence_token(
claims_file,
f'data/keys/{key}.pem',
f'{GENDIR}/evidence/{outname}.cbor',
badnode,
)
else:
raise ValueError(f'Unexpected scheme: {scheme}')
Expand Down Expand Up @@ -137,7 +139,7 @@ def generate_evidence_no_nonce(scheme, evidence, signing, outname):
)
elif scheme == 'enacttrust':
key = signing
generate_eancttrust_evidence_token(
generate_enacttrust_evidence_token(
claims_file,
f'data/keys/{key}.pem',
f'{GENDIR}/evidence/{outname}.cbor',
Expand Down Expand Up @@ -175,6 +177,7 @@ def generate_cca_evidence_token(claims_file, iak_file, rak_file, token_file):
f"--iak={iak_file} --rak={rak_file} --token={token_file}"
run_command(evcli_command, 'generate CCA token')

def generate_eancttrust_evidence_token(claims_file, key_file, token_file):
gentoken_command = f"gen-enacttrust-token -key {key_file} -out {token_file} {claims_file}"
def generate_enacttrust_evidence_token(claims_file, key_file, token_file, badnode):
bn_flag = '-bad-node' if badnode else ''
gentoken_command = f"gen-enacttrust-token {bn_flag} -key {key_file} -out {token_file} {claims_file}"
run_command(gentoken_command, 'generate EnactTrust token')
6 changes: 6 additions & 0 deletions integration-tests/utils/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ def setup_multi_nonce(test, variables):
generate_evidence_from_test_no_nonce(test)


def setup_enacttrust_badnode(test, variables):
_set_content_types(test, variables)
generate_endorsements(test)
generate_evidence_from_test(test)


def _set_content_types(test, variables):
scheme = test.test_vars['scheme']
profile = test.test_vars['profile']
Expand Down
6 changes: 3 additions & 3 deletions scheme/tpm-enacttrust/evidence_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func (s EvidenceHandler) GetTrustAnchorID(token *proto.AttestationToken) (string
var decoded Token

if err := decoded.Decode(token.Data); err != nil {
return "", err
return "", handler.BadEvidence(err)
}

return tpmEnactTrustLookupKey(token.TenantId, decoded.NodeId.String()), nil
Expand Down Expand Up @@ -93,11 +93,11 @@ func (s EvidenceHandler) ExtractClaims(
var decoded Token

if err := decoded.Decode(token.Data); err != nil {
return nil, fmt.Errorf("could not decode token: %w", err)
return nil, handler.BadEvidence("could not decode token: %w", err)
}

if decoded.AttestationData.Type != tpm2.TagAttestQuote {
return nil, fmt.Errorf("wrong TPMS_ATTEST type: want %d, got %d",
return nil, handler.BadEvidence("wrong TPMS_ATTEST type: want %d, got %d",
tpm2.TagAttestQuote, decoded.AttestationData.Type)
}

Expand Down
27 changes: 17 additions & 10 deletions scheme/tpm-enacttrust/test/cmd/gen-token/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,12 @@ func readPrivateKey(path string) (*ecdsa.PrivateKey, error) {

func main() {
var keyPath, outPath string
var badNode bool
var marshaledNodeID []byte
flag.StringVar(&keyPath, "key", "key.pem", "Path of the ECDSA key used to sign the token data encoded in PEM.")
flag.StringVar(&outPath, "out", "quote.bin", "Output path of the generated token.")
flag.BoolVar(&badNode, "bad-node", false,
"Allow node-id to not be a valid UUID. If this is set, the bytes of the string will be written as-is, rather than attempting to parse UUID out of it. No length check or any other validation will be performed.")
flag.Parse()
descPath := flag.Arg(0)

Expand All @@ -94,16 +98,19 @@ func main() {
os.Exit(1)
}

nodeID, err := uuid.Parse(desc.NodeID)
if err != nil {
fmt.Printf("ERROR: could not parse nodeID: %v\n", err)
os.Exit(1)
}

marshaledNodeID, err := nodeID.MarshalBinary()
if err != nil {
fmt.Printf("ERROR: could not mashal nodeID: %v\n", err)
os.Exit(1)
if badNode {
marshaledNodeID = []byte(desc.NodeID)
} else { // node-id must be a string encoding of a UUID
nodeID, err := uuid.Parse(desc.NodeID)
if err != nil {
fmt.Printf("ERROR: could not parse nodeID: %v\n", err)
os.Exit(1)
}
marshaledNodeID, err = nodeID.MarshalBinary()
if err != nil {
fmt.Printf("ERROR: could not mashal nodeID: %v\n", err)
os.Exit(1)
}
}

d, err := makeAttestationData(desc)
Expand Down

0 comments on commit da68896

Please sign in to comment.