blob: 9350979d4c8b26a3bf0d1eda81a703fbb31b73cc [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
Mate Toth-Pale305e552022-10-07 14:04:53 +020028def convert_map_to_token(token_map, verifier, wfh, *, name_as_key, parse_raw_value):
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020029 """
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,
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020036 name_as_key=name_as_key,
37 parse_raw_value=parse_raw_value,
38 root=True)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010039
40
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020041def read_token_map(file):
42 """
43 Read a yaml file and return a map
44 """
45 if hasattr(file, 'read'):
46 raw = yaml.safe_load(file)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010047 else:
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020048 with open(file, encoding="utf8") as file_obj:
49 raw = yaml.safe_load(file_obj)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010050
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020051 return raw
Mate Toth-Pal51b61982022-03-17 14:19:30 +010052
53
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020054def recursive_bytes_to_strings(token, in_place=False):
55 """
56 Transform the map in 'token' by changing changing bytes to base64 encoded form.
Mate Toth-Pal51b61982022-03-17 14:19:30 +010057
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020058 if 'in_place' is True, 'token' is modified, a new map is returned otherwise.
59 """
Mate Toth-Pal51b61982022-03-17 14:19:30 +010060 if in_place:
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020061 result = token
Mate Toth-Pal51b61982022-03-17 14:19:30 +010062 else:
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020063 result = deepcopy(token)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010064
65 if hasattr(result, 'items'):
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020066 for key, value in result.items():
67 result[key] = recursive_bytes_to_strings(value, in_place=True)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010068 elif (isinstance(result, Iterable) and
69 not isinstance(result, (str, bytes))):
70 result = [recursive_bytes_to_strings(r, in_place=True)
71 for r in result]
72 elif isinstance(result, bytes):
73 result = str(base64.b16encode(result))
74
75 return result
76
77
78def read_keyfile(keyfile, method=AttestationTokenVerifier.SIGN_METHOD_SIGN1):
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020079 """
80 Read a keyfile and return the key
81 """
Mate Toth-Pal51b61982022-03-17 14:19:30 +010082 if keyfile:
83 if method == AttestationTokenVerifier.SIGN_METHOD_SIGN1:
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020084 return _read_sign1_key(keyfile)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010085 if method == AttestationTokenVerifier.SIGN_METHOD_MAC0:
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020086 return _read_hmac_key(keyfile)
Mate Toth-Pal51b61982022-03-17 14:19:30 +010087 err_msg = 'Unexpected method "{}"; must be one of: sign, mac'
88 raise ValueError(err_msg.format(method))
89
90 return None
91
Mate Toth-Pal5ebca512022-03-24 16:45:51 +010092def get_cose_alg_from_key(key, default):
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020093 """Extract the algorithm from the key if possible
Mate Toth-Pal51b61982022-03-17 14:19:30 +010094
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020095 Returns the signature algorithm ID defined by COSE
Mate Toth-Pal5ebca512022-03-24 16:45:51 +010096 If key is None, default is returned.
Mate Toth-Palb9057ff2022-04-29 16:03:21 +020097 """
Mate Toth-Pal5ebca512022-03-24 16:45:51 +010098 if key is None:
99 return default
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200100 if not hasattr(key, "curve"):
101 raise ValueError("Key has no curve specified in it.")
102 return _known_curves[key.curve.name]
103
104def _read_sign1_key(keyfile):
105 with open(keyfile, 'rb') as file_obj:
106 raw_key = file_obj.read()
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100107 try:
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200108 key = SigningKey.from_pem(raw_key)
109 except Exception as exc:
110 signing_key_error = str(exc)
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100111
112 try:
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200113 key = VerifyingKey.from_pem(raw_key)
114 except Exception as vexc:
115 verifying_key_error = str(vexc)
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100116
117 msg = 'Bad key file "{}":\n\tpubkey error: {}\n\tprikey error: {}'
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200118 raise ValueError(msg.format(keyfile, verifying_key_error, signing_key_error)) from vexc
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100119 return key
120
121
Mate Toth-Palb9057ff2022-04-29 16:03:21 +0200122def _read_hmac_key(keyfile):
Mate Toth-Pal51b61982022-03-17 14:19:30 +0100123 return open(keyfile, 'rb').read()