/* Copyright 2017 The ChromiumOS Authors * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "dcrypto.h" #include "internal.h" #include "endian.h" #include "registers.h" static void ladder_init(void) { /* Do not reset keyladder engine here, as before. * * Should not be needed and if it is, it is indicative * of sync error between this and sha engine usage. * Reset will make this flow work, but will have broken * the other pending sha flow. * Hence leave as is and observe the error. */ /* Enable random stalls for key-ladder usage. Note that * the stall rate used for key-ladder operations is * 25% (vs. 12% for generic SHA operations). This distinction * is made so as to increase the difficulty in characterizng * the key-ladder engine via random inputs provided over the * generic SHA interface. */ /* Turn off random nops (which are enabled by default). */ GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, STALL_EN, 0); /* Configure random nop percentage at 25%. */ GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, FREQ, 1); /* Now turn on random nops. */ GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, STALL_EN, 1); } static int ladder_step(uint32_t cert, const uint32_t input[8]) { GREG32(KEYMGR, SHA_ITOP) = 0; /* clear status */ GREG32(KEYMGR, SHA_USE_CERT_INDEX) = (cert << GC_KEYMGR_SHA_USE_CERT_INDEX_LSB) | GC_KEYMGR_SHA_USE_CERT_ENABLE_MASK; GREG32(KEYMGR, SHA_CFG_EN) = GC_KEYMGR_SHA_CFG_EN_INT_EN_DONE_MASK; GREG32(KEYMGR, SHA_TRIG) = GC_KEYMGR_SHA_TRIG_TRIG_GO_MASK; if (input) { GREG32(KEYMGR, SHA_INPUT_FIFO) = input[0]; GREG32(KEYMGR, SHA_INPUT_FIFO) = input[1]; GREG32(KEYMGR, SHA_INPUT_FIFO) = input[2]; GREG32(KEYMGR, SHA_INPUT_FIFO) = input[3]; GREG32(KEYMGR, SHA_INPUT_FIFO) = input[4]; GREG32(KEYMGR, SHA_INPUT_FIFO) = input[5]; GREG32(KEYMGR, SHA_INPUT_FIFO) = input[6]; GREG32(KEYMGR, SHA_INPUT_FIFO) = input[7]; GREG32(KEYMGR, SHA_TRIG) = GC_KEYMGR_SHA_TRIG_TRIG_STOP_MASK; } while (!GREG32(KEYMGR, SHA_ITOP)) ; GREG32(KEYMGR, SHA_ITOP) = 0; /* clear status */ return !!GREG32(KEYMGR, HKEY_ERR_FLAGS); } static int compute_certs(const uint32_t *certs, size_t num_certs) { size_t i; for (i = 0; i < num_certs; i++) { if (ladder_step(certs[i], NULL)) return 0; } return 1; } #define KEYMGR_CERT_0 0 #define KEYMGR_CERT_3 3 #define KEYMGR_CERT_4 4 #define KEYMGR_CERT_5 5 #define KEYMGR_CERT_7 7 #define KEYMGR_CERT_15 15 #define KEYMGR_CERT_20 20 #define KEYMGR_CERT_25 25 #define KEYMGR_CERT_26 26 #define KEYMGR_CERT_27 27 #define KEYMGR_CERT_28 28 #define KEYMGR_CERT_34 34 #define KEYMGR_CERT_35 35 #define KEYMGR_CERT_38 38 static const uint32_t FRK2_CERTS_PREFIX[] = { KEYMGR_CERT_0, KEYMGR_CERT_3, KEYMGR_CERT_4, KEYMGR_CERT_5, KEYMGR_CERT_7, KEYMGR_CERT_15, KEYMGR_CERT_20, }; static const uint32_t FRK2_CERTS_POSTFIX[] = { KEYMGR_CERT_26, }; #define MAX_MAJOR_FW_VERSION 254 int DCRYPTO_ladder_compute_frk2(size_t fw_version, uint8_t *frk2) { int result = 0; if (fw_version > MAX_MAJOR_FW_VERSION) return 0; if (!dcrypto_grab_sha_hw()) return 0; do { size_t i; ladder_init(); if (!compute_certs(FRK2_CERTS_PREFIX, ARRAY_SIZE(FRK2_CERTS_PREFIX))) break; for (i = 0; i < MAX_MAJOR_FW_VERSION - fw_version; i++) { if (ladder_step(KEYMGR_CERT_25, NULL)) break; } if (!compute_certs(FRK2_CERTS_POSTFIX, ARRAY_SIZE(FRK2_CERTS_POSTFIX))) break; memcpy(frk2, (void *) GREG32_ADDR(KEYMGR, HKEY_FRR0), AES256_BLOCK_CIPHER_KEY_SIZE); result = 1; } while (0); dcrypto_release_sha_hw(); return result; } /* ISR salt (SHA256("ISR_SALT")) to use for USR generation. */ static const uint32_t ISR_SALT[8] = { 0x6ba1b495, 0x4b7ca214, 0xfe07e922, 0x09735185, 0xfcca43ca, 0xc6d4dfd9, 0x5fc2fcca, 0xaa45400b }; /* Map of populated USR registers. */ static int usr_ready[8] = {}; int dcrypto_ladder_compute_usr(enum dcrypto_appid id, const uint32_t usr_salt[8]) { int result = 0; /* Check for USR readiness. */ if (usr_ready[id]) return 1; if (!dcrypto_grab_sha_hw()) return 0; do { int i; /* The previous check performed without lock acquisition. */ if (usr_ready[id]) { result = 1; break; } ladder_init(); if (!compute_certs(FRK2_CERTS_PREFIX, ARRAY_SIZE(FRK2_CERTS_PREFIX))) break; /* USR generation requires running the key-ladder till * the end (version 0), plus one additional iteration. */ for (i = 0; i < MAX_MAJOR_FW_VERSION - 0 + 1; i++) { if (ladder_step(KEYMGR_CERT_25, NULL)) break; } if (i != MAX_MAJOR_FW_VERSION - 0 + 1) break; if (ladder_step(KEYMGR_CERT_34, ISR_SALT)) break; /* Output goes to USR[appid] (the multiply by 2 is an * artifact of slot addressing). */ GWRITE_FIELD(KEYMGR, SHA_CERT_OVERRIDE, DIGEST_PTR, 2 * id); if (ladder_step(KEYMGR_CERT_35, usr_salt)) break; /* Check for key-ladder errors. */ if (GREG32(KEYMGR, HKEY_ERR_FLAGS)) break; /* Key deposited in USR[id], and ready to use. */ usr_ready[id] = 1; result = 1; } while (0); dcrypto_release_sha_hw(); return result; } static void ladder_out(uint32_t output[8]) { output[0] = GREG32(KEYMGR, SHA_STS_H0); output[1] = GREG32(KEYMGR, SHA_STS_H1); output[2] = GREG32(KEYMGR, SHA_STS_H2); output[3] = GREG32(KEYMGR, SHA_STS_H3); output[4] = GREG32(KEYMGR, SHA_STS_H4); output[5] = GREG32(KEYMGR, SHA_STS_H5); output[6] = GREG32(KEYMGR, SHA_STS_H6); output[7] = GREG32(KEYMGR, SHA_STS_H7); } int dcrypto_ladder_derive(enum dcrypto_appid appid, const uint32_t salt[8], const uint32_t input[8], uint32_t output[8]) { int error; if (!dcrypto_grab_sha_hw()) return 0; GWRITE_FIELD(KEYMGR, SHA_CERT_OVERRIDE, KEY_PTR, 2 * appid); error = ladder_step(KEYMGR_CERT_38, input); /* HMAC */ if (!error) ladder_out(output); dcrypto_release_sha_hw(); return !error; } void DCRYPTO_ladder_revoke(void) { /* Revoke certificates */ GWRITE(KEYMGR, CERT_REVOKE_CTRL0, 0xffffffff); GWRITE(KEYMGR, CERT_REVOKE_CTRL1, 0xffffffff); /* Wipe out the hidden keys cached in AES and SHA engines. */ GWRITE_FIELD(KEYMGR, AES_USE_HIDDEN_KEY, ENABLE, 0); GWRITE_FIELD(KEYMGR, SHA_USE_HIDDEN_KEY, ENABLE, 0); /* Clear usr_ready[] */ memset(usr_ready, 0, sizeof(usr_ready)); } #define KEYMGR_CERT_REVOKE_CTRL0_DEFAULT_VAL 0xa8028a82 #define KEYMGR_CERT_REVOKE_CTRL1_DEFAULT_VAL 0xaaaaaaaa int DCRYPTO_ladder_is_enabled(void) { uint32_t ctrl0; uint32_t ctrl1; ctrl0 = GREAD(KEYMGR, CERT_REVOKE_CTRL0); ctrl1 = GREAD(KEYMGR, CERT_REVOKE_CTRL1); return ctrl0 == KEYMGR_CERT_REVOKE_CTRL0_DEFAULT_VAL && ctrl1 == KEYMGR_CERT_REVOKE_CTRL1_DEFAULT_VAL; }