/* * Copyright (C) 2017 The Android Open Source Project * Copyright 2017 NXP * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "caam.h" #include "common.h" #include "hwkey_keyslots.h" #include "hwkey_srv_priv.h" #define TLOG_TAG "hwkey_caam" #include static const uint8_t skeymod[16] __attribute__((aligned(16))) = { 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00}; static uint8_t kdfv1_key[32] __attribute__((aligned(32))); /* * Derive key V1 - HKDF based key derive. */ uint32_t derive_key_v1(const uuid_t* uuid, const uint8_t* ikm_data, size_t ikm_len, uint8_t* key_buf, size_t* key_len) { uint32_t res; *key_len = 0; if (!ikm_len) return HWKEY_ERR_BAD_LEN; if (!HKDF(key_buf, ikm_len, EVP_sha256(), (const uint8_t*)kdfv1_key, sizeof(kdfv1_key), (const uint8_t*)uuid, sizeof(uuid_t), ikm_data, ikm_len)) { TLOGE("HDKF failed 0x%x\n", ERR_get_error()); memset(key_buf, 0, ikm_len); res = HWKEY_ERR_GENERIC; goto done; } *key_len = ikm_len; res = HWKEY_NO_ERROR; done: return res; } /* * RPMB Key support */ #define RPMB_SS_AUTH_KEY_SIZE 32 #define RPMB_SS_AUTH_KEY_ID "com.android.trusty.storage_auth.rpmb" /* Secure storage service app uuid */ static const uuid_t ss_uuid = SECURE_STORAGE_SERVER_APP_UUID; static size_t rpmb_keyblob_len; static uint8_t rpmb_keyblob[RPMBKEY_LEN]; /* * Fetch RPMB Secure Storage Authentication key */ static uint32_t get_rpmb_ss_auth_key(const struct hwkey_keyslot* slot, uint8_t* kbuf, size_t kbuf_len, size_t* klen) { uint32_t res; assert(kbuf_len >= RPMB_SS_AUTH_KEY_SIZE); if (rpmb_keyblob_len != sizeof(rpmb_keyblob)) return HWKEY_ERR_NOT_FOUND; /* no RPMB key */ res = caam_decap_blob(skeymod, sizeof(skeymod), kbuf, rpmb_keyblob, RPMB_SS_AUTH_KEY_SIZE); if (res == CAAM_SUCCESS) { *klen = RPMB_SS_AUTH_KEY_SIZE; return HWKEY_NO_ERROR; } else { /* wipe target buffer */ TLOGE("%s: failed to unpack rpmb key\n", __func__); memset(kbuf, 0, RPMB_SS_AUTH_KEY_SIZE); return HWKEY_ERR_GENERIC; } } /* * List of keys slots that hwkey service supports */ static const struct hwkey_keyslot _keys[] = { { .uuid = &ss_uuid, .key_id = RPMB_SS_AUTH_KEY_ID, .handler = get_rpmb_ss_auth_key, }, }; static void unpack_kbox(void) { uint32_t res; struct keyslot_package* kbox = caam_get_keybox(); if (strncmp(kbox->magic, KEYPACK_MAGIC, 4)) { TLOGE("Invalid magic\n"); abort(); } /* Copy RPMB blob */ assert(!rpmb_keyblob_len); /* key should be unset */ if (kbox->rpmb_keyblob_len != sizeof(rpmb_keyblob)) { TLOGE("Unexpected RPMB key len: %u\n", kbox->rpmb_keyblob_len); } else { memcpy(rpmb_keyblob, kbox->rpmb_keyblob, kbox->rpmb_keyblob_len); rpmb_keyblob_len = kbox->rpmb_keyblob_len; } /* generate kdfv1 root it should never fail */ res = caam_gen_kdfv1_root_key(kdfv1_key, sizeof(kdfv1_key)); assert(res == CAAM_SUCCESS); /* copy pubkey blob */ /* wipe kbox in sram */ memset(kbox, 0, sizeof(*kbox)); } /* * Initialize Fake HWKEY service provider */ void hwkey_init_srv_provider(void) { int rc; TLOGD("Init HWKEY service provider\n"); unpack_kbox(); /* install key handlers */ hwkey_install_keys(_keys, countof(_keys)); /* start service */ rc = hwkey_start_service(); if (rc != NO_ERROR) { TLOGE("failed (%d) to start HWKEY service\n", rc); } }