blob: ccea2a4a31284a5a9920d0feb6b990775106694c [file] [log] [blame]
#!/usr/bin/env python3
# -----------------------------------------------------------------------------
# Copyright (c) 2019-2022, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# -----------------------------------------------------------------------------
"""CLI script for verifying an IAT."""
import argparse
import json
import logging
import sys
from iatverifier.util import recursive_bytes_to_strings, read_keyfile, get_cose_alg_from_key
from iatverifier.psa_iot_profile1_token_verifier import PSAIoTProfile1TokenVerifier
from iatverifier.psa_2_0_0_token_verifier import PSA_2_0_0_TokenVerifier
from iatverifier.attest_token_verifier import VerifierConfiguration, AttestationTokenVerifier
from iatverifier.cca_token_verifier import CCATokenVerifier, CCAPlatformTokenVerifier
logger = logging.getLogger('iat-verify')
def main():
"""Main function for verifying an IAT"""
token_verifiers = {
"PSA-IoT-Profile1-token": PSAIoTProfile1TokenVerifier,
"CCA-token": CCATokenVerifier,
"CCA-plat-token": CCAPlatformTokenVerifier,
"PSA-2.0.0-token": PSA_2_0_0_TokenVerifier,
}
parser = argparse.ArgumentParser(
description='''
Validates a signed Initial Attestation Token (IAT), checking
that the signature is valid, the token contian the required
fields, and those fields are in a valid format.
''')
parser.add_argument('-k', '--key',
help='''Path to the key in PEM format that should be used to
verify the token. If this is not specified, the token signature
will not be checked.''')
parser.add_argument('tokenfile',
help='''
path to a file containing a signed IAT.
''')
parser.add_argument('-K', '--keep-going', action='store_true',
help='''
Do not stop upon encountering a validation error.
''')
parser.add_argument('-p', '--print-iat', action='store_true',
help='''
Print the decoded token in JSON format.
''')
parser.add_argument('-s', '--strict', action='store_true',
help='''
Report failure if unknown claim is encountered.
''')
parser.add_argument('-c', '--check-protected-header', action='store_true',
help='''
Check the presence and content of COSE protected header.
''')
parser.add_argument('-m', '--method', choices=['sign', 'mac'], default='sign',
help='''
Specify how this token is wrapped -- whether Sign1Message or
Mac0Message COSE structure is used.
''')
parser.add_argument('-t', '--token-type',
help='''The type of the Token.''',
choices=token_verifiers.keys(),
required=True)
args = parser.parse_args()
logging.basicConfig(level=logging.INFO)
config = VerifierConfiguration(keep_going=args.keep_going, strict=args.strict)
if args.method == 'mac':
method = AttestationTokenVerifier.SIGN_METHOD_MAC0
else:
method = AttestationTokenVerifier.SIGN_METHOD_SIGN1
key_checked = False
verifier_class = token_verifiers[args.token_type]
if verifier_class == PSAIoTProfile1TokenVerifier:
key_checked = args.key
key = read_keyfile(keyfile=args.key, method=method)
if method == AttestationTokenVerifier.SIGN_METHOD_SIGN1:
cose_alg = get_cose_alg_from_key(key, AttestationTokenVerifier.COSE_ALG_ES256)
else:
cose_alg = AttestationTokenVerifier.COSE_ALG_HS256
verifier = PSAIoTProfile1TokenVerifier(
method=method,
cose_alg=cose_alg,
signing_key=key,
configuration=config)
elif verifier_class == CCATokenVerifier:
if method != AttestationTokenVerifier.SIGN_METHOD_SIGN1:
logger.error('Only sign1 method is supported by this token type.\n\t'.format(verifier_class))
sys.exit(1)
key_checked = args.key
platform_token_key = read_keyfile(args.key, method)
realm_token_method = AttestationTokenVerifier.SIGN_METHOD_SIGN1
platform_token_method = AttestationTokenVerifier.SIGN_METHOD_SIGN1
realm_token_cose_alg = get_cose_alg_from_key(
None,
AttestationTokenVerifier.COSE_ALG_ES384)
platform_token_cose_alg = get_cose_alg_from_key(
platform_token_key,
AttestationTokenVerifier.COSE_ALG_ES384)
verifier = CCATokenVerifier(
realm_token_method=realm_token_method,
realm_token_cose_alg=realm_token_cose_alg,
platform_token_method=platform_token_method,
platform_token_cose_alg=platform_token_cose_alg,
platform_token_key=platform_token_key,
configuration=config)
elif verifier_class == CCAPlatformTokenVerifier:
key_checked = args.key
key = read_keyfile(args.key, method)
cose_alg = get_cose_alg_from_key(key, AttestationTokenVerifier.COSE_ALG_ES384)
verifier = CCAPlatformTokenVerifier(
method=AttestationTokenVerifier.SIGN_METHOD_SIGN1,
cose_alg=cose_alg,
signing_key=key,
configuration=config,
necessity=None)
elif verifier_class == PSA_2_0_0_TokenVerifier:
key_checked = args.key
key = read_keyfile(keyfile=args.key, method=method)
if method == AttestationTokenVerifier.SIGN_METHOD_SIGN1:
cose_alg = get_cose_alg_from_key(key, AttestationTokenVerifier.COSE_ALG_ES256)
else:
cose_alg = AttestationTokenVerifier.COSE_ALG_HS256
verifier = PSA_2_0_0_TokenVerifier(method=method, cose_alg=cose_alg, signing_key=key, configuration=config)
else:
logger.error(f'Invalid token type:{verifier_class}\n\t')
sys.exit(1)
try:
with open(args.tokenfile, 'rb') as token_file:
token = verifier.parse_token(
token=token_file.read(),
check_p_header=args.check_protected_header,
lower_case_key=False)
token.verify()
if key_checked:
print('Signature OK')
print('Token format OK')
except ValueError as exc:
logger.error(f'Token verification failed:\n\t{exc}')
sys.exit(1)
if args.print_iat:
print('Token:')
token_map = token.get_token_map()
json.dump(recursive_bytes_to_strings(token_map, in_place=True),
sys.stdout, indent=4)
print('')
if __name__ == '__main__':
main()