Skip to content

Commit

Permalink
scheme: freshness check for PSA_IOT and CCA_SSD_PLATFORM
Browse files Browse the repository at this point in the history
Update PSA_IOT and CCA_SSD_PLATFORM schemes to perform a freshness
check as part of token integrity validation.

Freshness check is integral to attestation validation to prevent replay
attacks. Thus far, we have not performed it as part of our verification
pipeline, and instead left it the RP. However, PSA and CCA both mandate
freshness claims, and so there is no reason why this check cannot be
performed as part of the scheme evidence handling, therefore reducing
the risk of the RP neglecting to consider freshness and taking an
affirming attestation result from Veraison at face value.

Signed-off-by: Sergei Trofimov <[email protected]>
  • Loading branch information
setrofim committed Sep 26, 2023
1 parent 2ba8481 commit 5e82512
Show file tree
Hide file tree
Showing 17 changed files with 245 additions and 28 deletions.
18 changes: 18 additions & 0 deletions integration-tests/data/results/cca.freshness-fail.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"ear.appraisal-policy-id": "policy:CCA_SSD_PLATFORM",
"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.veraison.policy-claims": {
"problem": "integrity validation failed"
}
}

2 changes: 1 addition & 1 deletion integration-tests/data/results/psa.badcrypto.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
},
"ear.appraisal-policy-id": "policy:PSA_IOT",
"ear.veraison.policy-claims": {
"problem": "signature validation failed"
"problem": "integrity validation failed"
}
}
17 changes: 17 additions & 0 deletions integration-tests/data/results/psa.freshness-fail.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"ear.appraisal-policy-id": "policy:PSA_IOT",
"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.veraison.policy-claims": {
"problem": "integrity validation failed"
}
}
11 changes: 9 additions & 2 deletions integration-tests/tests/common.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,15 @@ variables:
verification-service: '{tavern.env_vars.VERIFICATION_HOST}.{tavern.env_vars.VERAISON_NETWORK}:{tavern.env_vars.VERIFICATION_PORT}'
management-service: '{tavern.env_vars.MANAGEMENT_HOST}.{tavern.env_vars.VERAISON_NETWORK}:{tavern.env_vars.MANAGEMENT_PORT}'
keycloak-service: '{tavern.env_vars.KEYCLOAK_HOST}.{tavern.env_vars.VERAISON_NETWORK}:{tavern.env_vars.KEYCLOAK_PORT}'
good-nonce: QUp8F0FBs9DpodKK8xUg8NQimf6sQAfe2J1ormzZLxk=
good-nonce-64: byTWuWNaLIu_WOkIuU4Ewb-zroDN6-gyQkV4SZ_jF2Hn9eHYvOASGET1Sr36UobaiPU6ZXsVM1yTlrQyklS8XA==
nonce32:
value: QUp8F0FBs9DpodKK8xUg8NQimf6sQAfe2J1ormzZLxk=
size: 32
bad-value: deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdea=
nonce64:
value: byTWuWNaLIu_WOkIuU4Ewb-zroDN6-gyQkV4SZ_jF2Hn9eHYvOASGET1Sr36UobaiPU6ZXsVM1yTlrQyklS8XA==
size: 64
bad-value: deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbe==

bad-nonce: Ppfdfe2JzZLOk=
endorsements-content-types:
psa.p1: application/corim-unsigned+cbor; profile=http://arm.com/psa/iot/1
Expand Down
6 changes: 4 additions & 2 deletions integration-tests/tests/test_cca_verify_challenge.tavern.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ marks:
# Expected structure of the returned EAR (EAT (Entity Attestation
# Token) Attestation Result).
- expected
# Indicates which nonce configurations ought to be used.
- nonce
vals:
- [cca, _, good, full, ccakeys, verify-challenge]
- [cca, _, good, full, ccakeys, verify-challenge, nonce64]

includes:
- !include common.yaml
Expand Down Expand Up @@ -65,7 +67,7 @@ stages:
- name: verify as relying party - creation of session resource
request:
method: POST
url: http://{verification-service}/challenge-response/v1/newSession?nonce={good-nonce-64}
url: http://{verification-service}/challenge-response/v1/newSession?nonce={nonce-value}
response:
status_code: 201
save:
Expand Down
6 changes: 4 additions & 2 deletions integration-tests/tests/test_enacttrust_badnode.tavern.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ marks:
# Expected structure of the returned EAR (EAT (Entity Attestation
# Token) Attestation Result).
- expected
# Indicates which nonce configurations ought to be used.
- nonce
vals:
- [enacttrust, _, badnode, mini, ec.p256.enacttrust, badnode]
- [enacttrust, _, badnode, mini, ec.p256.enacttrust, badnode, nonce32]

includes:
- !include common.yaml
Expand All @@ -41,7 +43,7 @@ stages:
- name: verify as relying party - creation of session resource
request:
method: POST
url: http://{verification-service}/challenge-response/v1/newSession?nonce={good-nonce}
url: http://{verification-service}/challenge-response/v1/newSession?nonce={nonce-value}
response:
status_code: 201
save:
Expand Down
22 changes: 12 additions & 10 deletions integration-tests/tests/test_end_to_end.tavern.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,17 @@ marks:
# Expected structure of the returned EAR (EAT (Entity Attestation
# Token) Attestation Result).
- expected
# Indicates which nonce configurations ought to be used.
- nonce
vals:
- [psa, p1, good, full, ec.p256, good]
- [psa, p1, good, mini, ec.p256, good]
- [psa, p1, missingclaims, mini, ec.p256, noident]
- [psa, p1, good, mini, bad, badcrypto]
- [psa, p1, badinstance, full, ec.p256, badinstance]
- [psa, p1, badswcomp, full, ec.p256, badswcomp]
- [cca, _, good, full, ccakeys, good]
- [enacttrust, _, good, mini, ec.p256.enacttrust, good]
- [psa, p1, good, full, ec.p256, good, nonce32]
- [psa, p1, good, mini, ec.p256, good, nonce32]
- [psa, p1, missingclaims, mini, ec.p256, noident, nonce32]
- [psa, p1, good, mini, bad, badcrypto, nonce32]
- [psa, p1, badinstance, full, ec.p256, badinstance, nonce32]
- [psa, p1, badswcomp, full, ec.p256, badswcomp, nonce32]
- [cca, _, good, full, ccakeys, good, nonce64]
- [enacttrust, _, good, mini, ec.p256.enacttrust, good, nonce32]

includes:
- !include common.yaml
Expand All @@ -48,7 +50,7 @@ stages:
- name: verify as relying party - creation of session resource
request:
method: POST
url: http://{verification-service}/challenge-response/v1/newSession?nonce={good-nonce}
url: http://{verification-service}/challenge-response/v1/newSession?nonce={nonce-value}
response:
status_code: 201
save:
Expand Down Expand Up @@ -84,7 +86,7 @@ stages:
- name: verify as attester - creation of session resource
request:
method: POST
url: http://{verification-service}/challenge-response/v1/newSession?nonceSize=32
url: http://{verification-service}/challenge-response/v1/newSession?nonceSize={nonce-size}
response:
status_code: 201
verify_response_with:
Expand Down
78 changes: 78 additions & 0 deletions integration-tests/tests/test_freshness_check_fail.tavern.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
test_name: freshness-check-fail

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
# Indicates which nonce configurations ought to be used.
- nonce
vals:
- [psa, p1, good, full, ec.p256, freshness-fail, nonce32]
- [cca, _, good, full, ccakeys, freshness-fail, nonce64]

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
authorization: '{authorization}' # 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={nonce-bad-value}
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
6 changes: 4 additions & 2 deletions integration-tests/tests/test_multinonce.tavern.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ marks:
# Expected structure of the returned EAR (EAT (Entity Attestation
# Token) Attestation Result).
- expected
# Indicates which nonce configurations ought to be used.
- nonce
vals:
- [psa, p1, multinonce, full, ec.p256, noident]
- [psa, p1, multinonce, full, ec.p256, noident, nonce32]

includes:
- !include common.yaml
Expand All @@ -41,7 +43,7 @@ stages:
- name: verify - creation of session resource
request:
method: POST
url: http://{verification-service}/challenge-response/v1/newSession?nonce={good-nonce}
url: http://{verification-service}/challenge-response/v1/newSession?nonce={nonce-value}
response:
status_code: 201
save:
Expand Down
23 changes: 19 additions & 4 deletions integration-tests/utils/generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,16 @@ def generate_expecte_result_from_response(response, scheme, expected):
outfile = f'{GENDIR}/expected/{scheme}.{expected}.server-nonce.json'
nonce = response.json()["nonce"]

if scheme in ['psa'] and nonce:
if scheme == 'psa' and nonce:
update_json(
infile,
{'ear.veraison.annotated-evidence': {f'{scheme}-nonce': nonce}},
{'ear.veraison.annotated-evidence': {f'psa-nonce': nonce}},
outfile,
)
elif scheme == 'cca' and nonce:
update_json(
infile,
{'ear.veraison.annotated-evidence': {'realm': {f'cca-realm-challenge': nonce}}},
outfile,
)
else:
Expand All @@ -56,7 +62,7 @@ def generate_expecte_result_from_response(response, scheme, expected):
def generate_evidence_from_test(test):
scheme = test.test_vars['scheme']
evidence = test.test_vars['evidence']
nonce = test.common_vars['good-nonce']
nonce = test.common_vars[test.test_vars['nonce']]['value']
signing = test.common_vars['keys'][test.test_vars['signing']]
outname = f'{scheme}.{evidence}'

Expand All @@ -75,13 +81,22 @@ def generate_evidence(scheme, evidence, nonce, signing, outname):
os.makedirs(f'{GENDIR}/evidence', exist_ok=True)
os.makedirs(f'{GENDIR}/claims', exist_ok=True)

if scheme in ['psa', 'cca'] and nonce:
if scheme == 'psa' and nonce:
claims_file = f'{GENDIR}/claims/{scheme}.{evidence}.json'
update_json(
f'data/claims/{scheme}.{evidence}.json',
{f'{scheme}-nonce': nonce},
claims_file,
)
elif scheme == 'cca' and nonce:
claims_file = f'{GENDIR}/claims/{scheme}.{evidence}.json'
# convert nonce from base64url to base64
translated_nonce = nonce.replace('-', '+').replace('_', '/')
update_json(
f'data/claims/{scheme}.{evidence}.json',
{'cca-realm-delegated-token': {f'cca-realm-challenge': translated_nonce}},
claims_file,
)
else:
claims_file = f'data/claims/{scheme}.{evidence}.json'

Expand Down
19 changes: 19 additions & 0 deletions integration-tests/utils/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
def setup_end_to_end(test, variables):
_set_content_types(test, variables)
_set_authorization(test, variables, 'provisioner')
_set_nonce(test, variables)
generate_endorsements(test)
generate_evidence_from_test(test)

Expand All @@ -26,13 +27,15 @@ def setup_no_nonce(test, variables):
def setup_multi_nonce(test, variables):
_set_content_types(test, variables)
_set_authorization(test, variables, 'provisioner')
_set_nonce(test, variables)
generate_endorsements(test)
generate_evidence_from_test_no_nonce(test)


def setup_enacttrust_badnode(test, variables):
_set_authorization(test, variables, 'provisioner')
_set_content_types(test, variables)
_set_nonce(test, variables)
generate_endorsements(test)
generate_evidence_from_test(test)

Expand All @@ -54,6 +57,15 @@ def setup_cca_verify_challenge(test, variables):
_set_content_types(test, variables)
_set_authorization(test, variables, 'provisioner')
_set_alt_authorization(test, variables, 'manager')
_set_nonce(test, variables)
generate_endorsements(test)
generate_evidence_from_test(test)


def setup_freshness_check_fail(test, variables):
_set_content_types(test, variables)
_set_authorization(test, variables, 'provisioner')
_set_nonce(test, variables)
generate_endorsements(test)
generate_evidence_from_test(test)

Expand All @@ -75,3 +87,10 @@ def _set_authorization(test, variables, role):
def _set_alt_authorization(test, variables, role):
token = get_access_token(test, role)
variables['alt-authorization'] = f'Bearer {token}'


def _set_nonce(test, variables):
nonce_config = test.test_vars['nonce']
variables['nonce-value'] = test.common_vars[nonce_config]['value']
variables['nonce-bad-value'] = test.common_vars[nonce_config]['bad-value']
variables['nonce-size'] = test.common_vars[nonce_config]['size']
8 changes: 4 additions & 4 deletions policy/mocks/mock_ibackend.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 5e82512

Please sign in to comment.