blob: 6ae45ccdd9e6ecb0287c11598a7d99203171b661 [file] [log] [blame]
Mate Toth-Pal530106f2022-05-03 15:29:49 +02001#!/usr/bin/env python3
Mate Toth-Pal1cb66cd2022-04-26 15:40:07 +02002# -----------------------------------------------------------------------------
Mate Toth-Pal6e1d7742025-04-17 11:00:09 +02003# Copyright (c) 2019-2025, Arm Limited. All rights reserved.
Mate Toth-Pal51b61982022-03-17 14:19:30 +01004#
5# SPDX-License-Identifier: BSD-3-Clause
6#
Mate Toth-Pal1cb66cd2022-04-26 15:40:07 +02007# -----------------------------------------------------------------------------
Mate Toth-Pal51b61982022-03-17 14:19:30 +01008
Mate Toth-Palb9057ff2022-04-29 16:03:21 +02009"""CLI script for verifying an IAT."""
10
Mate Toth-Pal1cb66cd2022-04-26 15:40:07 +020011import argparse
12import json
13import logging
14import sys
15
Thomas Fossatif4e1ca32024-08-16 16:01:31 +000016from pycose.algorithms import Es256, Es384, HMAC256
17
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020018from iatverifier.util import recursive_bytes_to_strings, read_keyfile, get_cose_alg_from_key
Mate Toth-Pal1cb66cd2022-04-26 15:40:07 +020019from iatverifier.psa_iot_profile1_token_verifier import PSAIoTProfile1TokenVerifier
Tamas Ban1e7944a2022-07-04 13:09:03 +020020from iatverifier.psa_2_0_0_token_verifier import PSA_2_0_0_TokenVerifier
Mate Toth-Palbb187d02022-04-26 16:01:51 +020021from iatverifier.attest_token_verifier import VerifierConfiguration, AttestationTokenVerifier
Mate Toth-Pal5ebca512022-03-24 16:45:51 +010022from iatverifier.cca_token_verifier import CCATokenVerifier, CCAPlatformTokenVerifier
Mate Toth-Pal1cb66cd2022-04-26 15:40:07 +020023
24logger = logging.getLogger('iat-verify')
25
26def main():
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020027 """Main function for verifying an IAT"""
Mate Toth-Pal1cb66cd2022-04-26 15:40:07 +020028
29 token_verifiers = {
30 "PSA-IoT-Profile1-token": PSAIoTProfile1TokenVerifier,
Mate Toth-Pal5ebca512022-03-24 16:45:51 +010031 "CCA-token": CCATokenVerifier,
32 "CCA-plat-token": CCAPlatformTokenVerifier,
Tamas Ban1e7944a2022-07-04 13:09:03 +020033 "PSA-2.0.0-token": PSA_2_0_0_TokenVerifier,
Mate Toth-Pal1cb66cd2022-04-26 15:40:07 +020034 }
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-Pala8b46b12022-10-07 13:30:54 +020042 parser.add_argument('-k', '--key',
Mate Toth-Pal5ebca512022-03-24 16:45:51 +010043 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-Pal1cb66cd2022-04-26 15:40:07 +020046 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-Pal1527a3c2022-11-30 11:27:54 +010062 parser.add_argument('-m', '--method', choices=['sign', 'mac', 'raw'], default='sign',
Mate Toth-Pal1cb66cd2022-04-26 15:40:07 +020063 help='''
64 Specify how this token is wrapped -- whether Sign1Message or
Mate Toth-Pal1527a3c2022-11-30 11:27:54 +010065 Mac0Message COSE structure is used. In case of 'raw' no COSE envelope is
66 expected.
Mate Toth-Pal1cb66cd2022-04-26 15:40:07 +020067 ''')
68 parser.add_argument('-t', '--token-type',
69 help='''The type of the Token.''',
70 choices=token_verifiers.keys(),
71 required=True)
Mate Toth-Pal6e1d7742025-04-17 11:00:09 +020072 parser.add_argument('--expect-token-indicator',
73 help='''Expect token indicator in the cbor.''',
74 action='store_true')
Mate Toth-Pal1cb66cd2022-04-26 15:40:07 +020075
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-Pal1cb66cd2022-04-26 15:40:07 +020081 if args.method == 'mac':
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020082 method = AttestationTokenVerifier.SIGN_METHOD_MAC0
Mate Toth-Pal1527a3c2022-11-30 11:27:54 +010083 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-Palb9057ff2022-04-29 16:03:21 +020088 method = AttestationTokenVerifier.SIGN_METHOD_SIGN1
Mate Toth-Pal1527a3c2022-11-30 11:27:54 +010089 else:
90 assert False
Mate Toth-Pal1cb66cd2022-04-26 15:40:07 +020091
Mate Toth-Pal5ebca512022-03-24 16:45:51 +010092 key_checked = False
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020093
94 verifier_class = token_verifiers[args.token_type]
95 if verifier_class == PSAIoTProfile1TokenVerifier:
Mate Toth-Pala8b46b12022-10-07 13:30:54 +020096 key_checked = args.key
97 key = read_keyfile(keyfile=args.key, method=method)
Mate Toth-Pal5ebca512022-03-24 16:45:51 +010098 if method == AttestationTokenVerifier.SIGN_METHOD_SIGN1:
Thomas Fossatif4e1ca32024-08-16 16:01:31 +000099 cose_alg = get_cose_alg_from_key(key, Es256)
Mate Toth-Pal5ebca512022-03-24 16:45:51 +0100100 else:
Thomas Fossatif4e1ca32024-08-16 16:01:31 +0000101 cose_alg = HMAC256
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200102 verifier = PSAIoTProfile1TokenVerifier(
103 method=method,
104 cose_alg=cose_alg,
105 signing_key=key,
106 configuration=config)
Mate Toth-Pal5ebca512022-03-24 16:45:51 +0100107 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-Pala8b46b12022-10-07 13:30:54 +0200111 key_checked = args.key
112 platform_token_key = read_keyfile(args.key, method)
Mate Toth-Pal5ebca512022-03-24 16:45:51 +0100113 realm_token_method = AttestationTokenVerifier.SIGN_METHOD_SIGN1
114 platform_token_method = AttestationTokenVerifier.SIGN_METHOD_SIGN1
Thomas Fossatif4e1ca32024-08-16 16:01:31 +0000115 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-Pal5ebca512022-03-24 16:45:51 +0100117 verifier = CCATokenVerifier(
118 realm_token_method=realm_token_method,
119 realm_token_cose_alg=realm_token_cose_alg,
Mate Toth-Pal5ebca512022-03-24 16:45:51 +0100120 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-Pala8b46b12022-10-07 13:30:54 +0200125 key_checked = args.key
126 key = read_keyfile(args.key, method)
Thomas Fossatif4e1ca32024-08-16 16:01:31 +0000127 cose_alg = get_cose_alg_from_key(key, Es384)
Mate Toth-Pal5ebca512022-03-24 16:45:51 +0100128 verifier = CCAPlatformTokenVerifier(
129 method=AttestationTokenVerifier.SIGN_METHOD_SIGN1,
130 cose_alg=cose_alg,
131 signing_key=key,
132 configuration=config,
Mate Toth-Pal6e1d7742025-04-17 11:00:09 +0200133 necessity=None,
134 has_type_indicator=args.expect_token_indicator)
Tamas Ban1e7944a2022-07-04 13:09:03 +0200135 elif verifier_class == PSA_2_0_0_TokenVerifier:
Mate Toth-Pala8b46b12022-10-07 13:30:54 +0200136 key_checked = args.key
137 key = read_keyfile(keyfile=args.key, method=method)
Tamas Ban1e7944a2022-07-04 13:09:03 +0200138 if method == AttestationTokenVerifier.SIGN_METHOD_SIGN1:
Thomas Fossatif4e1ca32024-08-16 16:01:31 +0000139 cose_alg = get_cose_alg_from_key(key, Es256)
Tamas Ban1e7944a2022-07-04 13:09:03 +0200140 else:
Thomas Fossatif4e1ca32024-08-16 16:01:31 +0000141 cose_alg = HMAC256
Tamas Ban1e7944a2022-07-04 13:09:03 +0200142 verifier = PSA_2_0_0_TokenVerifier(method=method, cose_alg=cose_alg, signing_key=key, configuration=config)
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200143 else:
144 logger.error(f'Invalid token type:{verifier_class}\n\t')
Mate Toth-Pal1cb66cd2022-04-26 15:40:07 +0200145 sys.exit(1)
146
147 try:
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200148 with open(args.tokenfile, 'rb') as token_file:
149 token = verifier.parse_token(
150 token=token_file.read(),
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200151 lower_case_key=False)
Mate Toth-Palc7404e92022-07-15 11:11:13 +0200152 token.verify()
Mate Toth-Pal5ebca512022-03-24 16:45:51 +0100153 if key_checked:
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200154 print('Signature OK')
155 print('Token format OK')
156 except ValueError as exc:
Mate Toth-Pal5ebca512022-03-24 16:45:51 +0100157 logger.error(f'Token verification failed:\n\t{exc}')
Mate Toth-Pal1cb66cd2022-04-26 15:40:07 +0200158 sys.exit(1)
159
160 if args.print_iat:
161 print('Token:')
Mate Toth-Palc7404e92022-07-15 11:11:13 +0200162 token_map = token.get_token_map()
163 json.dump(recursive_bytes_to_strings(token_map, in_place=True),
Mate Toth-Pal1cb66cd2022-04-26 15:40:07 +0200164 sys.stdout, indent=4)
165 print('')
166
167if __name__ == '__main__':
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200168 main()