Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 1 | # ----------------------------------------------------------------------------- |
| 2 | # Copyright (c) 2019-2022, Arm Limited. All rights reserved. |
Mate Toth-Pal | 51b6198 | 2022-03-17 14:19:30 +0100 | [diff] [blame] | 3 | # |
| 4 | # SPDX-License-Identifier: BSD-3-Clause |
| 5 | # |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 6 | # ----------------------------------------------------------------------------- |
Mate Toth-Pal | 51b6198 | 2022-03-17 14:19:30 +0100 | [diff] [blame] | 7 | |
Mate Toth-Pal | b9057ff | 2022-04-29 16:03:21 +0200 | [diff] [blame] | 8 | """CLI script for verifying an IAT.""" |
| 9 | |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 10 | import argparse |
| 11 | import json |
| 12 | import logging |
| 13 | import sys |
| 14 | |
Mate Toth-Pal | b9057ff | 2022-04-29 16:03:21 +0200 | [diff] [blame] | 15 | from iatverifier.util import recursive_bytes_to_strings, read_keyfile, get_cose_alg_from_key |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 16 | from iatverifier.psa_iot_profile1_token_verifier import PSAIoTProfile1TokenVerifier |
Mate Toth-Pal | bb187d0 | 2022-04-26 16:01:51 +0200 | [diff] [blame] | 17 | from iatverifier.attest_token_verifier import VerifierConfiguration, AttestationTokenVerifier |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 18 | |
| 19 | logger = logging.getLogger('iat-verify') |
| 20 | |
| 21 | def main(): |
Mate Toth-Pal | b9057ff | 2022-04-29 16:03:21 +0200 | [diff] [blame] | 22 | """Main function for verifying an IAT""" |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 23 | |
| 24 | token_verifiers = { |
| 25 | "PSA-IoT-Profile1-token": PSAIoTProfile1TokenVerifier, |
| 26 | } |
| 27 | |
| 28 | parser = argparse.ArgumentParser( |
| 29 | description=''' |
| 30 | Validates a signed Initial Attestation Token (IAT), checking |
| 31 | that the signature is valid, the token contian the required |
| 32 | fields, and those fields are in a valid format. |
| 33 | ''') |
| 34 | parser.add_argument('-k', '--keyfile', |
| 35 | help=''' |
| 36 | Path to a file containing signing key in PEM format. |
| 37 | ''') |
| 38 | parser.add_argument('tokenfile', |
| 39 | help=''' |
| 40 | path to a file containing a signed IAT. |
| 41 | ''') |
| 42 | parser.add_argument('-K', '--keep-going', action='store_true', |
| 43 | help=''' |
| 44 | Do not stop upon encountering a validation error. |
| 45 | ''') |
| 46 | parser.add_argument('-p', '--print-iat', action='store_true', |
| 47 | help=''' |
| 48 | Print the decoded token in JSON format. |
| 49 | ''') |
| 50 | parser.add_argument('-s', '--strict', action='store_true', |
| 51 | help=''' |
| 52 | Report failure if unknown claim is encountered. |
| 53 | ''') |
| 54 | parser.add_argument('-c', '--check-protected-header', action='store_true', |
| 55 | help=''' |
| 56 | Check the presence and content of COSE protected header. |
| 57 | ''') |
| 58 | parser.add_argument('-m', '--method', choices=['sign', 'mac'], default='sign', |
| 59 | help=''' |
| 60 | Specify how this token is wrapped -- whether Sign1Message or |
| 61 | Mac0Message COSE structure is used. |
| 62 | ''') |
| 63 | parser.add_argument('-t', '--token-type', |
| 64 | help='''The type of the Token.''', |
| 65 | choices=token_verifiers.keys(), |
| 66 | required=True) |
| 67 | |
| 68 | args = parser.parse_args() |
| 69 | |
| 70 | logging.basicConfig(level=logging.INFO) |
| 71 | |
| 72 | config = VerifierConfiguration(keep_going=args.keep_going, strict=args.strict) |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 73 | if args.method == 'mac': |
Mate Toth-Pal | b9057ff | 2022-04-29 16:03:21 +0200 | [diff] [blame] | 74 | method = AttestationTokenVerifier.SIGN_METHOD_MAC0 |
| 75 | else: |
| 76 | method = AttestationTokenVerifier.SIGN_METHOD_SIGN1 |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 77 | |
Mate Toth-Pal | b9057ff | 2022-04-29 16:03:21 +0200 | [diff] [blame] | 78 | key = read_keyfile(keyfile=args.keyfile, method=method) |
| 79 | |
| 80 | if args.method == 'mac': |
| 81 | cose_alg = AttestationTokenVerifier.COSE_ALG_HS256 |
| 82 | else: |
| 83 | if key is not None: |
| 84 | cose_alg = get_cose_alg_from_key(key) |
| 85 | else: |
| 86 | cose_alg = AttestationTokenVerifier.COSE_ALG_ES256 |
| 87 | |
| 88 | verifier_class = token_verifiers[args.token_type] |
| 89 | if verifier_class == PSAIoTProfile1TokenVerifier: |
| 90 | verifier = PSAIoTProfile1TokenVerifier( |
| 91 | method=method, |
| 92 | cose_alg=cose_alg, |
| 93 | signing_key=key, |
| 94 | configuration=config) |
| 95 | else: |
| 96 | logger.error(f'Invalid token type:{verifier_class}\n\t') |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 97 | sys.exit(1) |
| 98 | |
| 99 | try: |
Mate Toth-Pal | b9057ff | 2022-04-29 16:03:21 +0200 | [diff] [blame] | 100 | with open(args.tokenfile, 'rb') as token_file: |
| 101 | token = verifier.parse_token( |
| 102 | token=token_file.read(), |
| 103 | verify=True, |
| 104 | check_p_header=args.check_protected_header, |
| 105 | lower_case_key=False) |
| 106 | if args.keyfile: |
| 107 | print('Signature OK') |
| 108 | print('Token format OK') |
| 109 | except ValueError as exc: |
| 110 | logger.error(f'Could not extract IAT from COSE:\n\t{exc}') |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 111 | sys.exit(1) |
| 112 | |
| 113 | if args.print_iat: |
| 114 | print('Token:') |
| 115 | json.dump(recursive_bytes_to_strings(token, in_place=True), |
| 116 | sys.stdout, indent=4) |
| 117 | print('') |
| 118 | |
| 119 | if __name__ == '__main__': |
Mate Toth-Pal | b9057ff | 2022-04-29 16:03:21 +0200 | [diff] [blame] | 120 | main() |