Mate Toth-Pal | 530106f | 2022-05-03 15:29:49 +0200 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 2 | # ----------------------------------------------------------------------------- |
Mate Toth-Pal | 6e1d774 | 2025-04-17 11:00:09 +0200 | [diff] [blame^] | 3 | # Copyright (c) 2019-2025, Arm Limited. All rights reserved. |
Mate Toth-Pal | 51b6198 | 2022-03-17 14:19:30 +0100 | [diff] [blame] | 4 | # |
| 5 | # SPDX-License-Identifier: BSD-3-Clause |
| 6 | # |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 7 | # ----------------------------------------------------------------------------- |
Mate Toth-Pal | 51b6198 | 2022-03-17 14:19:30 +0100 | [diff] [blame] | 8 | |
Mate Toth-Pal | b9057ff | 2022-04-29 16:03:21 +0200 | [diff] [blame] | 9 | """CLI script for verifying an IAT.""" |
| 10 | |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 11 | import argparse |
| 12 | import json |
| 13 | import logging |
| 14 | import sys |
| 15 | |
Thomas Fossati | f4e1ca3 | 2024-08-16 16:01:31 +0000 | [diff] [blame] | 16 | from pycose.algorithms import Es256, Es384, HMAC256 |
| 17 | |
Mate Toth-Pal | b9057ff | 2022-04-29 16:03:21 +0200 | [diff] [blame] | 18 | 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] | 19 | from iatverifier.psa_iot_profile1_token_verifier import PSAIoTProfile1TokenVerifier |
Tamas Ban | 1e7944a | 2022-07-04 13:09:03 +0200 | [diff] [blame] | 20 | from iatverifier.psa_2_0_0_token_verifier import PSA_2_0_0_TokenVerifier |
Mate Toth-Pal | bb187d0 | 2022-04-26 16:01:51 +0200 | [diff] [blame] | 21 | from iatverifier.attest_token_verifier import VerifierConfiguration, AttestationTokenVerifier |
Mate Toth-Pal | 5ebca51 | 2022-03-24 16:45:51 +0100 | [diff] [blame] | 22 | from iatverifier.cca_token_verifier import CCATokenVerifier, CCAPlatformTokenVerifier |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 23 | |
| 24 | logger = logging.getLogger('iat-verify') |
| 25 | |
| 26 | def main(): |
Mate Toth-Pal | b9057ff | 2022-04-29 16:03:21 +0200 | [diff] [blame] | 27 | """Main function for verifying an IAT""" |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 28 | |
| 29 | token_verifiers = { |
| 30 | "PSA-IoT-Profile1-token": PSAIoTProfile1TokenVerifier, |
Mate Toth-Pal | 5ebca51 | 2022-03-24 16:45:51 +0100 | [diff] [blame] | 31 | "CCA-token": CCATokenVerifier, |
| 32 | "CCA-plat-token": CCAPlatformTokenVerifier, |
Tamas Ban | 1e7944a | 2022-07-04 13:09:03 +0200 | [diff] [blame] | 33 | "PSA-2.0.0-token": PSA_2_0_0_TokenVerifier, |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 34 | } |
| 35 | |
| 36 | parser = argparse.ArgumentParser( |
| 37 | description=''' |
| 38 | Validates a signed Initial Attestation Token (IAT), checking |
| 39 | that the signature is valid, the token contian the required |
| 40 | fields, and those fields are in a valid format. |
| 41 | ''') |
Mate Toth-Pal | a8b46b1 | 2022-10-07 13:30:54 +0200 | [diff] [blame] | 42 | parser.add_argument('-k', '--key', |
Mate Toth-Pal | 5ebca51 | 2022-03-24 16:45:51 +0100 | [diff] [blame] | 43 | help='''Path to the key in PEM format that should be used to |
| 44 | verify the token. If this is not specified, the token signature |
| 45 | will not be checked.''') |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 46 | parser.add_argument('tokenfile', |
| 47 | help=''' |
| 48 | path to a file containing a signed IAT. |
| 49 | ''') |
| 50 | parser.add_argument('-K', '--keep-going', action='store_true', |
| 51 | help=''' |
| 52 | Do not stop upon encountering a validation error. |
| 53 | ''') |
| 54 | parser.add_argument('-p', '--print-iat', action='store_true', |
| 55 | help=''' |
| 56 | Print the decoded token in JSON format. |
| 57 | ''') |
| 58 | parser.add_argument('-s', '--strict', action='store_true', |
| 59 | help=''' |
| 60 | Report failure if unknown claim is encountered. |
| 61 | ''') |
Mate Toth-Pal | 1527a3c | 2022-11-30 11:27:54 +0100 | [diff] [blame] | 62 | parser.add_argument('-m', '--method', choices=['sign', 'mac', 'raw'], default='sign', |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 63 | help=''' |
| 64 | Specify how this token is wrapped -- whether Sign1Message or |
Mate Toth-Pal | 1527a3c | 2022-11-30 11:27:54 +0100 | [diff] [blame] | 65 | Mac0Message COSE structure is used. In case of 'raw' no COSE envelope is |
| 66 | expected. |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 67 | ''') |
| 68 | parser.add_argument('-t', '--token-type', |
| 69 | help='''The type of the Token.''', |
| 70 | choices=token_verifiers.keys(), |
| 71 | required=True) |
Mate Toth-Pal | 6e1d774 | 2025-04-17 11:00:09 +0200 | [diff] [blame^] | 72 | parser.add_argument('--expect-token-indicator', |
| 73 | help='''Expect token indicator in the cbor.''', |
| 74 | action='store_true') |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 75 | |
| 76 | args = parser.parse_args() |
| 77 | |
| 78 | logging.basicConfig(level=logging.INFO) |
| 79 | |
| 80 | config = VerifierConfiguration(keep_going=args.keep_going, strict=args.strict) |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 81 | if args.method == 'mac': |
Mate Toth-Pal | b9057ff | 2022-04-29 16:03:21 +0200 | [diff] [blame] | 82 | method = AttestationTokenVerifier.SIGN_METHOD_MAC0 |
Mate Toth-Pal | 1527a3c | 2022-11-30 11:27:54 +0100 | [diff] [blame] | 83 | elif args.method == 'raw': |
| 84 | if args.key: |
| 85 | raise ValueError('A keyfile cannot be specified with --raw.') |
| 86 | method = AttestationTokenVerifier.SIGN_METHOD_RAW |
| 87 | elif args.method == 'sign': |
Mate Toth-Pal | b9057ff | 2022-04-29 16:03:21 +0200 | [diff] [blame] | 88 | method = AttestationTokenVerifier.SIGN_METHOD_SIGN1 |
Mate Toth-Pal | 1527a3c | 2022-11-30 11:27:54 +0100 | [diff] [blame] | 89 | else: |
| 90 | assert False |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 91 | |
Mate Toth-Pal | 5ebca51 | 2022-03-24 16:45:51 +0100 | [diff] [blame] | 92 | key_checked = False |
Mate Toth-Pal | b9057ff | 2022-04-29 16:03:21 +0200 | [diff] [blame] | 93 | |
| 94 | verifier_class = token_verifiers[args.token_type] |
| 95 | if verifier_class == PSAIoTProfile1TokenVerifier: |
Mate Toth-Pal | a8b46b1 | 2022-10-07 13:30:54 +0200 | [diff] [blame] | 96 | key_checked = args.key |
| 97 | key = read_keyfile(keyfile=args.key, method=method) |
Mate Toth-Pal | 5ebca51 | 2022-03-24 16:45:51 +0100 | [diff] [blame] | 98 | if method == AttestationTokenVerifier.SIGN_METHOD_SIGN1: |
Thomas Fossati | f4e1ca3 | 2024-08-16 16:01:31 +0000 | [diff] [blame] | 99 | cose_alg = get_cose_alg_from_key(key, Es256) |
Mate Toth-Pal | 5ebca51 | 2022-03-24 16:45:51 +0100 | [diff] [blame] | 100 | else: |
Thomas Fossati | f4e1ca3 | 2024-08-16 16:01:31 +0000 | [diff] [blame] | 101 | cose_alg = HMAC256 |
Mate Toth-Pal | b9057ff | 2022-04-29 16:03:21 +0200 | [diff] [blame] | 102 | verifier = PSAIoTProfile1TokenVerifier( |
| 103 | method=method, |
| 104 | cose_alg=cose_alg, |
| 105 | signing_key=key, |
| 106 | configuration=config) |
Mate Toth-Pal | 5ebca51 | 2022-03-24 16:45:51 +0100 | [diff] [blame] | 107 | elif verifier_class == CCATokenVerifier: |
| 108 | if method != AttestationTokenVerifier.SIGN_METHOD_SIGN1: |
| 109 | logger.error('Only sign1 method is supported by this token type.\n\t'.format(verifier_class)) |
| 110 | sys.exit(1) |
Mate Toth-Pal | a8b46b1 | 2022-10-07 13:30:54 +0200 | [diff] [blame] | 111 | key_checked = args.key |
| 112 | platform_token_key = read_keyfile(args.key, method) |
Mate Toth-Pal | 5ebca51 | 2022-03-24 16:45:51 +0100 | [diff] [blame] | 113 | realm_token_method = AttestationTokenVerifier.SIGN_METHOD_SIGN1 |
| 114 | platform_token_method = AttestationTokenVerifier.SIGN_METHOD_SIGN1 |
Thomas Fossati | f4e1ca3 | 2024-08-16 16:01:31 +0000 | [diff] [blame] | 115 | realm_token_cose_alg = get_cose_alg_from_key(None, Es384) |
| 116 | platform_token_cose_alg = get_cose_alg_from_key(platform_token_key, Es384) |
Mate Toth-Pal | 5ebca51 | 2022-03-24 16:45:51 +0100 | [diff] [blame] | 117 | verifier = CCATokenVerifier( |
| 118 | realm_token_method=realm_token_method, |
| 119 | realm_token_cose_alg=realm_token_cose_alg, |
Mate Toth-Pal | 5ebca51 | 2022-03-24 16:45:51 +0100 | [diff] [blame] | 120 | platform_token_method=platform_token_method, |
| 121 | platform_token_cose_alg=platform_token_cose_alg, |
| 122 | platform_token_key=platform_token_key, |
| 123 | configuration=config) |
| 124 | elif verifier_class == CCAPlatformTokenVerifier: |
Mate Toth-Pal | a8b46b1 | 2022-10-07 13:30:54 +0200 | [diff] [blame] | 125 | key_checked = args.key |
| 126 | key = read_keyfile(args.key, method) |
Thomas Fossati | f4e1ca3 | 2024-08-16 16:01:31 +0000 | [diff] [blame] | 127 | cose_alg = get_cose_alg_from_key(key, Es384) |
Mate Toth-Pal | 5ebca51 | 2022-03-24 16:45:51 +0100 | [diff] [blame] | 128 | verifier = CCAPlatformTokenVerifier( |
| 129 | method=AttestationTokenVerifier.SIGN_METHOD_SIGN1, |
| 130 | cose_alg=cose_alg, |
| 131 | signing_key=key, |
| 132 | configuration=config, |
Mate Toth-Pal | 6e1d774 | 2025-04-17 11:00:09 +0200 | [diff] [blame^] | 133 | necessity=None, |
| 134 | has_type_indicator=args.expect_token_indicator) |
Tamas Ban | 1e7944a | 2022-07-04 13:09:03 +0200 | [diff] [blame] | 135 | elif verifier_class == PSA_2_0_0_TokenVerifier: |
Mate Toth-Pal | a8b46b1 | 2022-10-07 13:30:54 +0200 | [diff] [blame] | 136 | key_checked = args.key |
| 137 | key = read_keyfile(keyfile=args.key, method=method) |
Tamas Ban | 1e7944a | 2022-07-04 13:09:03 +0200 | [diff] [blame] | 138 | if method == AttestationTokenVerifier.SIGN_METHOD_SIGN1: |
Thomas Fossati | f4e1ca3 | 2024-08-16 16:01:31 +0000 | [diff] [blame] | 139 | cose_alg = get_cose_alg_from_key(key, Es256) |
Tamas Ban | 1e7944a | 2022-07-04 13:09:03 +0200 | [diff] [blame] | 140 | else: |
Thomas Fossati | f4e1ca3 | 2024-08-16 16:01:31 +0000 | [diff] [blame] | 141 | cose_alg = HMAC256 |
Tamas Ban | 1e7944a | 2022-07-04 13:09:03 +0200 | [diff] [blame] | 142 | verifier = PSA_2_0_0_TokenVerifier(method=method, cose_alg=cose_alg, signing_key=key, configuration=config) |
Mate Toth-Pal | b9057ff | 2022-04-29 16:03:21 +0200 | [diff] [blame] | 143 | else: |
| 144 | logger.error(f'Invalid token type:{verifier_class}\n\t') |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 145 | sys.exit(1) |
| 146 | |
| 147 | try: |
Mate Toth-Pal | b9057ff | 2022-04-29 16:03:21 +0200 | [diff] [blame] | 148 | with open(args.tokenfile, 'rb') as token_file: |
| 149 | token = verifier.parse_token( |
| 150 | token=token_file.read(), |
Mate Toth-Pal | b9057ff | 2022-04-29 16:03:21 +0200 | [diff] [blame] | 151 | lower_case_key=False) |
Mate Toth-Pal | c7404e9 | 2022-07-15 11:11:13 +0200 | [diff] [blame] | 152 | token.verify() |
Mate Toth-Pal | 5ebca51 | 2022-03-24 16:45:51 +0100 | [diff] [blame] | 153 | if key_checked: |
Mate Toth-Pal | b9057ff | 2022-04-29 16:03:21 +0200 | [diff] [blame] | 154 | print('Signature OK') |
| 155 | print('Token format OK') |
| 156 | except ValueError as exc: |
Mate Toth-Pal | 5ebca51 | 2022-03-24 16:45:51 +0100 | [diff] [blame] | 157 | logger.error(f'Token verification failed:\n\t{exc}') |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 158 | sys.exit(1) |
| 159 | |
| 160 | if args.print_iat: |
| 161 | print('Token:') |
Mate Toth-Pal | c7404e9 | 2022-07-15 11:11:13 +0200 | [diff] [blame] | 162 | token_map = token.get_token_map() |
| 163 | json.dump(recursive_bytes_to_strings(token_map, in_place=True), |
Mate Toth-Pal | 1cb66cd | 2022-04-26 15:40:07 +0200 | [diff] [blame] | 164 | sys.stdout, indent=4) |
| 165 | print('') |
| 166 | |
| 167 | if __name__ == '__main__': |
Mate Toth-Pal | b9057ff | 2022-04-29 16:03:21 +0200 | [diff] [blame] | 168 | main() |