xref: /optee_os/scripts/derive_rpmb_key.py (revision 4edd96e6d7a7228e907cf498b23e5b5fbdaf39a0)
1*4edd96e6SJens Wiklander#!/usr/bin/env python3
2*4edd96e6SJens Wiklander# SPDX-License-Identifier: BSD-2-Clause
3*4edd96e6SJens Wiklander#
4*4edd96e6SJens Wiklander# Copyright (c) 2023, Linaro Limited
5*4edd96e6SJens Wiklander#
6*4edd96e6SJens Wiklander
7*4edd96e6SJens Wiklanderimport sys
8*4edd96e6SJens Wiklander
9*4edd96e6SJens Wiklander
10*4edd96e6SJens Wiklanderdef hex_parse(str):
11*4edd96e6SJens Wiklander    try:
12*4edd96e6SJens Wiklander        h = bytes.fromhex(str)
13*4edd96e6SJens Wiklander    except ValueError as e:
14*4edd96e6SJens Wiklander        try:
15*4edd96e6SJens Wiklander            # Try to pad with a '0' nibble in front
16*4edd96e6SJens Wiklander            h = bytes.fromhex('0' + str)
17*4edd96e6SJens Wiklander            print('Odd number of nibbles in hexadecimal string',
18*4edd96e6SJens Wiklander                  file=sys.stderr)
19*4edd96e6SJens Wiklander            raise e
20*4edd96e6SJens Wiklander        except ValueError:
21*4edd96e6SJens Wiklander            raise e
22*4edd96e6SJens Wiklander    return h
23*4edd96e6SJens Wiklander
24*4edd96e6SJens Wiklander
25*4edd96e6SJens Wiklanderdef get_args():
26*4edd96e6SJens Wiklander    import argparse
27*4edd96e6SJens Wiklander    import textwrap
28*4edd96e6SJens Wiklander
29*4edd96e6SJens Wiklander    parser = argparse.ArgumentParser(
30*4edd96e6SJens Wiklander        allow_abbrev=False,
31*4edd96e6SJens Wiklander        description='''Derive an RPMB key from the Hardware Unique Key used
32*4edd96e6SJens Wiklander                       by OP-TEE and the CID of the RPMB.''',
33*4edd96e6SJens Wiklander        epilog='''Note that the derived key matches what the
34*4edd96e6SJens Wiklander                  __huk_subkey_derive() would produce. If huk_subkey_derive()
35*4edd96e6SJens Wiklander                  is overridden to call another function, please don't use
36*4edd96e6SJens Wiklander                  this script''')
37*4edd96e6SJens Wiklander
38*4edd96e6SJens Wiklander    parser.add_argument('--quiet', action='store_true', default=False,
39*4edd96e6SJens Wiklander                        help='''Gives only the hexstring of the RPMB key as
40*4edd96e6SJens Wiklander                                output, intended for scripting''')
41*4edd96e6SJens Wiklander    parser.add_argument('--testkey', action='store_true', default=False,
42*4edd96e6SJens Wiklander                        help='''Outputs the hardcoded test key''')
43*4edd96e6SJens Wiklander    parser.add_argument('--huk', type=hex_parse,
44*4edd96e6SJens Wiklander                        help='''Hardware Unique Key (16 bytes), as returned
45*4edd96e6SJens Wiklander                                by the platform specific function
46*4edd96e6SJens Wiklander                                tee_otp_get_hw_unique_key() in OP-TEE''')
47*4edd96e6SJens Wiklander    parser.add_argument('--cid', type=hex_parse, help='CID (16 bytes)')
48*4edd96e6SJens Wiklander    parser.add_argument('--compat', action='store_true', default=False,
49*4edd96e6SJens Wiklander                        help='''Generates a backwards compatible key,
50*4edd96e6SJens Wiklander                                only to be used if OP-TEE is build with
51*4edd96e6SJens Wiklander                                CFG_CORE_HUK_SUBKEY_COMPAT=y''')
52*4edd96e6SJens Wiklander
53*4edd96e6SJens Wiklander    return parser.parse_args()
54*4edd96e6SJens Wiklander
55*4edd96e6SJens Wiklander
56*4edd96e6SJens Wiklanderdef derive_key(huk, cid, compat):
57*4edd96e6SJens Wiklander    import struct
58*4edd96e6SJens Wiklander    from cryptography.hazmat.primitives import hashes, hmac
59*4edd96e6SJens Wiklander
60*4edd96e6SJens Wiklander    # Prepare the CID and Clear the PRV (Product revision) and CRC (CRC7
61*4edd96e6SJens Wiklander    # checksum) fields as OP-TEE does.
62*4edd96e6SJens Wiklander    data = bytearray(cid)
63*4edd96e6SJens Wiklander    data[9] = 0
64*4edd96e6SJens Wiklander    data[15] = 0
65*4edd96e6SJens Wiklander
66*4edd96e6SJens Wiklander    # This is how __huk_subkey_derive() is implemented, if huk_subkey_derive()
67*4edd96e6SJens Wiklander    # is overridden the key derived here may not match what OP-TEE is using
68*4edd96e6SJens Wiklander    #
69*4edd96e6SJens Wiklander    # HUK is as tee_otp_get_hw_unique_key() in OP-TEE returns it
70*4edd96e6SJens Wiklander    h = hmac.HMAC(huk, hashes.SHA256())
71*4edd96e6SJens Wiklander    if not compat:
72*4edd96e6SJens Wiklander        usage_word = struct.pack('<I', 0)
73*4edd96e6SJens Wiklander        h.update(usage_word)
74*4edd96e6SJens Wiklander    h.update(data)
75*4edd96e6SJens Wiklander    return h.finalize()
76*4edd96e6SJens Wiklander
77*4edd96e6SJens Wiklander
78*4edd96e6SJens Wiklanderdef main():
79*4edd96e6SJens Wiklander    args = get_args()
80*4edd96e6SJens Wiklander
81*4edd96e6SJens Wiklander    if args.testkey:
82*4edd96e6SJens Wiklander        if args.cid or args.huk or args.compat:
83*4edd96e6SJens Wiklander            print('--cid, --huk, or --compat '
84*4edd96e6SJens Wiklander                  'cannot be given together with --testkey')
85*4edd96e6SJens Wiklander            sys.exit(1)
86*4edd96e6SJens Wiklander        # The test key hardcoded in OP-TEE
87*4edd96e6SJens Wiklander        key = bytes.fromhex('''D3 EB 3E C3 6E 33 4C 9F
88*4edd96e6SJens Wiklander                               98 8C E2 C0 B8 59 54 61
89*4edd96e6SJens Wiklander                               0D 2B CF 86 64 84 4D F2
90*4edd96e6SJens Wiklander                               AB 56 E6 C6 1B B7 01 E4''')
91*4edd96e6SJens Wiklander    else:
92*4edd96e6SJens Wiklander        if not args.cid:
93*4edd96e6SJens Wiklander            print('--cid is required without --testkey')
94*4edd96e6SJens Wiklander            sys.exit(1)
95*4edd96e6SJens Wiklander
96*4edd96e6SJens Wiklander        if not args.huk:
97*4edd96e6SJens Wiklander            print('--huk is required without --testkey')
98*4edd96e6SJens Wiklander            sys.exit(1)
99*4edd96e6SJens Wiklander
100*4edd96e6SJens Wiklander        if len(args.cid) != 16:
101*4edd96e6SJens Wiklander            print(f'Invalid CID length, expected 16 bytes got {len(args.cid)}',
102*4edd96e6SJens Wiklander                  file=sys.stderr)
103*4edd96e6SJens Wiklander            sys.exit(1)
104*4edd96e6SJens Wiklander
105*4edd96e6SJens Wiklander        if len(args.huk) != 16:
106*4edd96e6SJens Wiklander            print(f'Invalid HUK length, expected 16 bytes got {len(args.huk)}',
107*4edd96e6SJens Wiklander                  file=sys.stderr)
108*4edd96e6SJens Wiklander            sys.exit(1)
109*4edd96e6SJens Wiklander
110*4edd96e6SJens Wiklander        if not args.quiet:
111*4edd96e6SJens Wiklander            print(f'HUK:      {args.huk.hex()} length {len(args.huk)}')
112*4edd96e6SJens Wiklander            print(f'RPMB CID: {args.cid.hex()} length {len(args.cid)}')
113*4edd96e6SJens Wiklander
114*4edd96e6SJens Wiklander        key = derive_key(args.huk, args.cid, args.compat)
115*4edd96e6SJens Wiklander
116*4edd96e6SJens Wiklander    if args.quiet:
117*4edd96e6SJens Wiklander        print(key.hex())
118*4edd96e6SJens Wiklander    else:
119*4edd96e6SJens Wiklander        print(f'RPMB key: {key.hex()}')
120*4edd96e6SJens Wiklander        print(f'          length {len(key)}')
121*4edd96e6SJens Wiklander        if args.testkey:
122*4edd96e6SJens Wiklander            print('''
123*4edd96e6SJens Wiklander*********************************************************************
124*4edd96e6SJens Wiklander*** Please note that the test key should only be used for testing ***
125*4edd96e6SJens Wiklander*** purposes since it's well known and the same for all devices.  ***
126*4edd96e6SJens Wiklander*********************************************************************''')
127*4edd96e6SJens Wiklander        else:
128*4edd96e6SJens Wiklander            print('''
129*4edd96e6SJens WiklanderPlease take care to double-check the provided input since writing the RPMB
130*4edd96e6SJens Wiklanderkey is an irreversible step.''')
131*4edd96e6SJens Wiklander
132*4edd96e6SJens Wiklander
133*4edd96e6SJens Wiklanderif __name__ == "__main__":
134*4edd96e6SJens Wiklander    main()
135