183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+ 260083261SDirk Eibach /* 360083261SDirk Eibach * (C) Copyright 2016 460083261SDirk Eibach * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc 560083261SDirk Eibach */ 660083261SDirk Eibach 760083261SDirk Eibach #include <common.h> 8d677bfe2SMiquel Raynal #include <tpm-v1.h> 960083261SDirk Eibach #include <malloc.h> 1060083261SDirk Eibach #include <linux/ctype.h> 1160083261SDirk Eibach #include <asm/unaligned.h> 1260083261SDirk Eibach 1360083261SDirk Eibach #include "hre.h" 1460083261SDirk Eibach 15*abdc7b8aSSimon Glass int flush_keys(struct udevice *tpm) 1660083261SDirk Eibach { 1760083261SDirk Eibach u16 key_count; 1860083261SDirk Eibach u8 buf[288]; 1960083261SDirk Eibach u8 *ptr; 2060083261SDirk Eibach u32 err; 2160083261SDirk Eibach uint i; 2260083261SDirk Eibach 2360083261SDirk Eibach /* fetch list of already loaded keys in the TPM */ 24*abdc7b8aSSimon Glass err = tpm_get_capability(tpm, TPM_CAP_HANDLE, TPM_RT_KEY, buf, 25*abdc7b8aSSimon Glass sizeof(buf)); 2660083261SDirk Eibach if (err) 2760083261SDirk Eibach return -1; 2860083261SDirk Eibach key_count = get_unaligned_be16(buf); 2960083261SDirk Eibach ptr = buf + 2; 3060083261SDirk Eibach for (i = 0; i < key_count; ++i, ptr += 4) { 31*abdc7b8aSSimon Glass err = tpm_flush_specific(tpm, get_unaligned_be32(ptr), 32*abdc7b8aSSimon Glass TPM_RT_KEY); 3360083261SDirk Eibach if (err && err != TPM_KEY_OWNER_CONTROL) 3460083261SDirk Eibach return err; 3560083261SDirk Eibach } 3660083261SDirk Eibach 3760083261SDirk Eibach return 0; 3860083261SDirk Eibach } 3960083261SDirk Eibach 4060083261SDirk Eibach int decode_hexstr(char *hexstr, u8 **result) 4160083261SDirk Eibach { 4260083261SDirk Eibach int len = strlen(hexstr); 4360083261SDirk Eibach int bytes = len / 2; 4460083261SDirk Eibach int i; 4560083261SDirk Eibach u8 acc = 0; 4660083261SDirk Eibach 4760083261SDirk Eibach if (len % 2 == 1) 4860083261SDirk Eibach return 1; 4960083261SDirk Eibach 5060083261SDirk Eibach *result = (u8 *)malloc(bytes); 5160083261SDirk Eibach 5260083261SDirk Eibach for (i = 0; i < len; i++) { 5360083261SDirk Eibach char cur = tolower(hexstr[i]); 5460083261SDirk Eibach u8 val; 5560083261SDirk Eibach 5660083261SDirk Eibach if ((cur >= 'a' && cur <= 'f') || (cur >= '0' && cur <= '9')) { 5760083261SDirk Eibach val = cur - (cur > '9' ? 87 : 48); 5860083261SDirk Eibach 5960083261SDirk Eibach if (i % 2 == 0) 6060083261SDirk Eibach acc = 16 * val; 6160083261SDirk Eibach else 6260083261SDirk Eibach (*result)[i / 2] = acc + val; 6360083261SDirk Eibach } else { 6460083261SDirk Eibach free(*result); 6560083261SDirk Eibach return 1; 6660083261SDirk Eibach } 6760083261SDirk Eibach } 6860083261SDirk Eibach 6960083261SDirk Eibach return 0; 7060083261SDirk Eibach } 7160083261SDirk Eibach 7260083261SDirk Eibach int extract_subprogram(u8 **progdata, u32 expected_magic, 7360083261SDirk Eibach struct key_program **result) 7460083261SDirk Eibach { 7560083261SDirk Eibach struct key_program *prog = *result; 7660083261SDirk Eibach u32 magic, code_crc, code_size; 7760083261SDirk Eibach 7860083261SDirk Eibach magic = get_unaligned_be32(*progdata); 7960083261SDirk Eibach code_crc = get_unaligned_be32(*progdata + 4); 8060083261SDirk Eibach code_size = get_unaligned_be32(*progdata + 8); 8160083261SDirk Eibach 8260083261SDirk Eibach *progdata += 12; 8360083261SDirk Eibach 8460083261SDirk Eibach if (magic != expected_magic) 8560083261SDirk Eibach return -1; 8660083261SDirk Eibach 8760083261SDirk Eibach *result = malloc(sizeof(struct key_program) + code_size); 8860083261SDirk Eibach 8960083261SDirk Eibach if (!*result) 9060083261SDirk Eibach return -1; 9160083261SDirk Eibach 9260083261SDirk Eibach prog->magic = magic; 9360083261SDirk Eibach prog->code_crc = code_crc; 9460083261SDirk Eibach prog->code_size = code_size; 9560083261SDirk Eibach memcpy(prog->code, *progdata, code_size); 9660083261SDirk Eibach 9760083261SDirk Eibach *progdata += code_size; 9860083261SDirk Eibach 9960083261SDirk Eibach if (hre_verify_program(prog)) { 10060083261SDirk Eibach free(prog); 10160083261SDirk Eibach return -1; 10260083261SDirk Eibach } 10360083261SDirk Eibach 10460083261SDirk Eibach return 0; 10560083261SDirk Eibach } 10660083261SDirk Eibach 10760083261SDirk Eibach struct key_program *parse_and_check_keyprog(u8 *progdata) 10860083261SDirk Eibach { 10960083261SDirk Eibach struct key_program *result = NULL, *hmac = NULL; 11060083261SDirk Eibach 11160083261SDirk Eibach /* Part 1: Load key program */ 11260083261SDirk Eibach 11360083261SDirk Eibach if (extract_subprogram(&progdata, MAGIC_KEY_PROGRAM, &result)) 11460083261SDirk Eibach return NULL; 11560083261SDirk Eibach 11660083261SDirk Eibach /* Part 2: Load hmac program */ 11760083261SDirk Eibach 11860083261SDirk Eibach if (extract_subprogram(&progdata, MAGIC_HMAC, &hmac)) 11960083261SDirk Eibach return NULL; 12060083261SDirk Eibach 12160083261SDirk Eibach free(hmac); 12260083261SDirk Eibach 12360083261SDirk Eibach return result; 12460083261SDirk Eibach } 12560083261SDirk Eibach 126*abdc7b8aSSimon Glass int load_and_run_keyprog(struct udevice *tpm) 12760083261SDirk Eibach { 12860083261SDirk Eibach char *cmd = NULL; 12960083261SDirk Eibach u8 *binprog = NULL; 13060083261SDirk Eibach char *hexprog; 13160083261SDirk Eibach struct key_program *prog; 13260083261SDirk Eibach 13300caae6dSSimon Glass cmd = env_get("loadkeyprogram"); 13460083261SDirk Eibach 13560083261SDirk Eibach if (!cmd || run_command(cmd, 0)) 13660083261SDirk Eibach return 1; 13760083261SDirk Eibach 13800caae6dSSimon Glass hexprog = env_get("keyprogram"); 13960083261SDirk Eibach 14060083261SDirk Eibach if (decode_hexstr(hexprog, &binprog)) 14160083261SDirk Eibach return 1; 14260083261SDirk Eibach 14360083261SDirk Eibach prog = parse_and_check_keyprog(binprog); 14460083261SDirk Eibach free(binprog); 14560083261SDirk Eibach 14660083261SDirk Eibach if (!prog) 14760083261SDirk Eibach return 1; 14860083261SDirk Eibach 149*abdc7b8aSSimon Glass if (hre_run_program(tpm, prog->code, prog->code_size)) { 15060083261SDirk Eibach free(prog); 15160083261SDirk Eibach return 1; 15260083261SDirk Eibach } 15360083261SDirk Eibach 15460083261SDirk Eibach printf("\nSD code ran successfully\n"); 15560083261SDirk Eibach 15660083261SDirk Eibach free(prog); 15760083261SDirk Eibach 15860083261SDirk Eibach return 0; 15960083261SDirk Eibach } 160