1*60083261SDirk Eibach /* 2*60083261SDirk Eibach * (C) Copyright 2016 3*60083261SDirk Eibach * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc 4*60083261SDirk Eibach * 5*60083261SDirk Eibach * SPDX-License-Identifier: GPL-2.0+ 6*60083261SDirk Eibach */ 7*60083261SDirk Eibach 8*60083261SDirk Eibach #include <common.h> 9*60083261SDirk Eibach #include <tpm.h> 10*60083261SDirk Eibach #include <malloc.h> 11*60083261SDirk Eibach #include <linux/ctype.h> 12*60083261SDirk Eibach #include <asm/unaligned.h> 13*60083261SDirk Eibach 14*60083261SDirk Eibach #include "hre.h" 15*60083261SDirk Eibach 16*60083261SDirk Eibach int flush_keys(void) 17*60083261SDirk Eibach { 18*60083261SDirk Eibach u16 key_count; 19*60083261SDirk Eibach u8 buf[288]; 20*60083261SDirk Eibach u8 *ptr; 21*60083261SDirk Eibach u32 err; 22*60083261SDirk Eibach uint i; 23*60083261SDirk Eibach 24*60083261SDirk Eibach /* fetch list of already loaded keys in the TPM */ 25*60083261SDirk Eibach err = tpm_get_capability(TPM_CAP_HANDLE, TPM_RT_KEY, buf, sizeof(buf)); 26*60083261SDirk Eibach if (err) 27*60083261SDirk Eibach return -1; 28*60083261SDirk Eibach key_count = get_unaligned_be16(buf); 29*60083261SDirk Eibach ptr = buf + 2; 30*60083261SDirk Eibach for (i = 0; i < key_count; ++i, ptr += 4) { 31*60083261SDirk Eibach err = tpm_flush_specific(get_unaligned_be32(ptr), TPM_RT_KEY); 32*60083261SDirk Eibach if (err && err != TPM_KEY_OWNER_CONTROL) 33*60083261SDirk Eibach return err; 34*60083261SDirk Eibach } 35*60083261SDirk Eibach 36*60083261SDirk Eibach return 0; 37*60083261SDirk Eibach } 38*60083261SDirk Eibach 39*60083261SDirk Eibach int decode_hexstr(char *hexstr, u8 **result) 40*60083261SDirk Eibach { 41*60083261SDirk Eibach int len = strlen(hexstr); 42*60083261SDirk Eibach int bytes = len / 2; 43*60083261SDirk Eibach int i; 44*60083261SDirk Eibach u8 acc = 0; 45*60083261SDirk Eibach 46*60083261SDirk Eibach if (len % 2 == 1) 47*60083261SDirk Eibach return 1; 48*60083261SDirk Eibach 49*60083261SDirk Eibach *result = (u8 *)malloc(bytes); 50*60083261SDirk Eibach 51*60083261SDirk Eibach for (i = 0; i < len; i++) { 52*60083261SDirk Eibach char cur = tolower(hexstr[i]); 53*60083261SDirk Eibach u8 val; 54*60083261SDirk Eibach 55*60083261SDirk Eibach if ((cur >= 'a' && cur <= 'f') || (cur >= '0' && cur <= '9')) { 56*60083261SDirk Eibach val = cur - (cur > '9' ? 87 : 48); 57*60083261SDirk Eibach 58*60083261SDirk Eibach if (i % 2 == 0) 59*60083261SDirk Eibach acc = 16 * val; 60*60083261SDirk Eibach else 61*60083261SDirk Eibach (*result)[i / 2] = acc + val; 62*60083261SDirk Eibach } else { 63*60083261SDirk Eibach free(*result); 64*60083261SDirk Eibach return 1; 65*60083261SDirk Eibach } 66*60083261SDirk Eibach } 67*60083261SDirk Eibach 68*60083261SDirk Eibach return 0; 69*60083261SDirk Eibach } 70*60083261SDirk Eibach 71*60083261SDirk Eibach int extract_subprogram(u8 **progdata, u32 expected_magic, 72*60083261SDirk Eibach struct key_program **result) 73*60083261SDirk Eibach { 74*60083261SDirk Eibach struct key_program *prog = *result; 75*60083261SDirk Eibach u32 magic, code_crc, code_size; 76*60083261SDirk Eibach 77*60083261SDirk Eibach magic = get_unaligned_be32(*progdata); 78*60083261SDirk Eibach code_crc = get_unaligned_be32(*progdata + 4); 79*60083261SDirk Eibach code_size = get_unaligned_be32(*progdata + 8); 80*60083261SDirk Eibach 81*60083261SDirk Eibach *progdata += 12; 82*60083261SDirk Eibach 83*60083261SDirk Eibach if (magic != expected_magic) 84*60083261SDirk Eibach return -1; 85*60083261SDirk Eibach 86*60083261SDirk Eibach *result = malloc(sizeof(struct key_program) + code_size); 87*60083261SDirk Eibach 88*60083261SDirk Eibach if (!*result) 89*60083261SDirk Eibach return -1; 90*60083261SDirk Eibach 91*60083261SDirk Eibach prog->magic = magic; 92*60083261SDirk Eibach prog->code_crc = code_crc; 93*60083261SDirk Eibach prog->code_size = code_size; 94*60083261SDirk Eibach memcpy(prog->code, *progdata, code_size); 95*60083261SDirk Eibach 96*60083261SDirk Eibach *progdata += code_size; 97*60083261SDirk Eibach 98*60083261SDirk Eibach if (hre_verify_program(prog)) { 99*60083261SDirk Eibach free(prog); 100*60083261SDirk Eibach return -1; 101*60083261SDirk Eibach } 102*60083261SDirk Eibach 103*60083261SDirk Eibach return 0; 104*60083261SDirk Eibach } 105*60083261SDirk Eibach 106*60083261SDirk Eibach struct key_program *parse_and_check_keyprog(u8 *progdata) 107*60083261SDirk Eibach { 108*60083261SDirk Eibach struct key_program *result = NULL, *hmac = NULL; 109*60083261SDirk Eibach 110*60083261SDirk Eibach /* Part 1: Load key program */ 111*60083261SDirk Eibach 112*60083261SDirk Eibach if (extract_subprogram(&progdata, MAGIC_KEY_PROGRAM, &result)) 113*60083261SDirk Eibach return NULL; 114*60083261SDirk Eibach 115*60083261SDirk Eibach /* Part 2: Load hmac program */ 116*60083261SDirk Eibach 117*60083261SDirk Eibach if (extract_subprogram(&progdata, MAGIC_HMAC, &hmac)) 118*60083261SDirk Eibach return NULL; 119*60083261SDirk Eibach 120*60083261SDirk Eibach free(hmac); 121*60083261SDirk Eibach 122*60083261SDirk Eibach return result; 123*60083261SDirk Eibach } 124*60083261SDirk Eibach 125*60083261SDirk Eibach int load_and_run_keyprog(void) 126*60083261SDirk Eibach { 127*60083261SDirk Eibach char *cmd = NULL; 128*60083261SDirk Eibach u8 *binprog = NULL; 129*60083261SDirk Eibach char *hexprog; 130*60083261SDirk Eibach struct key_program *prog; 131*60083261SDirk Eibach 132*60083261SDirk Eibach cmd = getenv("loadkeyprogram"); 133*60083261SDirk Eibach 134*60083261SDirk Eibach if (!cmd || run_command(cmd, 0)) 135*60083261SDirk Eibach return 1; 136*60083261SDirk Eibach 137*60083261SDirk Eibach hexprog = getenv("keyprogram"); 138*60083261SDirk Eibach 139*60083261SDirk Eibach if (decode_hexstr(hexprog, &binprog)) 140*60083261SDirk Eibach return 1; 141*60083261SDirk Eibach 142*60083261SDirk Eibach prog = parse_and_check_keyprog(binprog); 143*60083261SDirk Eibach free(binprog); 144*60083261SDirk Eibach 145*60083261SDirk Eibach if (!prog) 146*60083261SDirk Eibach return 1; 147*60083261SDirk Eibach 148*60083261SDirk Eibach if (hre_run_program(prog->code, prog->code_size)) { 149*60083261SDirk Eibach free(prog); 150*60083261SDirk Eibach return 1; 151*60083261SDirk Eibach } 152*60083261SDirk Eibach 153*60083261SDirk Eibach printf("\nSD code ran successfully\n"); 154*60083261SDirk Eibach 155*60083261SDirk Eibach free(prog); 156*60083261SDirk Eibach 157*60083261SDirk Eibach return 0; 158*60083261SDirk Eibach } 159