blob: bc78aad0a4fc463a0d2397c8db7d1984ee250b58 [file] [log] [blame]
Mate Toth-Pal51b61982022-03-17 14:19:30 +01001# -----------------------------------------------------------------------------
2# Copyright (c) 2019-2022, Arm Limited. All rights reserved.
3#
4# SPDX-License-Identifier: BSD-3-Clause
5#
6# -----------------------------------------------------------------------------
7
Mate Toth-Palb9057ff2022-04-29 16:03:21 +02008"""Helper utilities for CLI tools and tests"""
9
Mate Toth-Pal51b61982022-03-17 14:19:30 +010010from collections.abc import Iterable
11from copy import deepcopy
12import logging
13
14import base64
Mate Toth-Pal51b61982022-03-17 14:19:30 +010015import yaml
16from ecdsa import SigningKey, VerifyingKey
Mate Toth-Palbb187d02022-04-26 16:01:51 +020017from iatverifier.attest_token_verifier import AttestationTokenVerifier
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020018from cbor2 import CBOREncoder
Mate Toth-Pal51b61982022-03-17 14:19:30 +010019
20_logger = logging.getLogger("util")
21
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020022_known_curves = {
23 "NIST256p": AttestationTokenVerifier.COSE_ALG_ES256,
24 "NIST384p": AttestationTokenVerifier.COSE_ALG_ES384,
25 "NIST521p": AttestationTokenVerifier.COSE_ALG_ES512,
26}
27
28def convert_map_to_token(token_map, verifier, wfh, *, add_p_header, name_as_key, parse_raw_value):
29 """
30 Convert a map to token and write the result to a file.
31 """
32 encoder = CBOREncoder(wfh)
33 verifier.convert_map_to_token(
34 encoder,
35 token_map,
36 add_p_header=add_p_header,
37 name_as_key=name_as_key,
38 parse_raw_value=parse_raw_value,
39 root=True)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010040
41
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020042def read_token_map(file):
43 """
44 Read a yaml file and return a map
45 """
46 if hasattr(file, 'read'):
47 raw = yaml.safe_load(file)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010048 else:
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020049 with open(file, encoding="utf8") as file_obj:
50 raw = yaml.safe_load(file_obj)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010051
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020052 return raw
Mate Toth-Pal51b61982022-03-17 14:19:30 +010053
54
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020055def recursive_bytes_to_strings(token, in_place=False):
56 """
57 Transform the map in 'token' by changing changing bytes to base64 encoded form.
Mate Toth-Pal51b61982022-03-17 14:19:30 +010058
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020059 if 'in_place' is True, 'token' is modified, a new map is returned otherwise.
60 """
Mate Toth-Pal51b61982022-03-17 14:19:30 +010061 if in_place:
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020062 result = token
Mate Toth-Pal51b61982022-03-17 14:19:30 +010063 else:
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020064 result = deepcopy(token)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010065
66 if hasattr(result, 'items'):
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020067 for key, value in result.items():
68 result[key] = recursive_bytes_to_strings(value, in_place=True)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010069 elif (isinstance(result, Iterable) and
70 not isinstance(result, (str, bytes))):
71 result = [recursive_bytes_to_strings(r, in_place=True)
72 for r in result]
73 elif isinstance(result, bytes):
74 result = str(base64.b16encode(result))
75
76 return result
77
78
79def read_keyfile(keyfile, method=AttestationTokenVerifier.SIGN_METHOD_SIGN1):
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020080 """
81 Read a keyfile and return the key
82 """
Mate Toth-Pal51b61982022-03-17 14:19:30 +010083 if keyfile:
84 if method == AttestationTokenVerifier.SIGN_METHOD_SIGN1:
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020085 return _read_sign1_key(keyfile)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010086 if method == AttestationTokenVerifier.SIGN_METHOD_MAC0:
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020087 return _read_hmac_key(keyfile)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010088 err_msg = 'Unexpected method "{}"; must be one of: sign, mac'
89 raise ValueError(err_msg.format(method))
90
91 return None
92
Mate Toth-Pal5ebca512022-03-24 16:45:51 +010093def get_cose_alg_from_key(key, default):
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020094 """Extract the algorithm from the key if possible
Mate Toth-Pal51b61982022-03-17 14:19:30 +010095
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020096 Returns the signature algorithm ID defined by COSE
Mate Toth-Pal5ebca512022-03-24 16:45:51 +010097 If key is None, default is returned.
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020098 """
Mate Toth-Pal5ebca512022-03-24 16:45:51 +010099 if key is None:
100 return default
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200101 if not hasattr(key, "curve"):
102 raise ValueError("Key has no curve specified in it.")
103 return _known_curves[key.curve.name]
104
105def _read_sign1_key(keyfile):
106 with open(keyfile, 'rb') as file_obj:
107 raw_key = file_obj.read()
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100108 try:
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200109 key = SigningKey.from_pem(raw_key)
110 except Exception as exc:
111 signing_key_error = str(exc)
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100112
113 try:
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200114 key = VerifyingKey.from_pem(raw_key)
115 except Exception as vexc:
116 verifying_key_error = str(vexc)
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100117
118 msg = 'Bad key file "{}":\n\tpubkey error: {}\n\tprikey error: {}'
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200119 raise ValueError(msg.format(keyfile, verifying_key_error, signing_key_error)) from vexc
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100120 return key
121
122
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200123def _read_hmac_key(keyfile):
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100124 return open(keyfile, 'rb').read()