blob: 9f55de76f68263dd320c115989ef815f5087f7be [file] [log] [blame]
/*
* 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 <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <uapi/err.h>
#include <interface/hwkey/hwkey.h>
#include <openssl/cipher.h>
#include <openssl/aes.h>
#include <openssl/digest.h>
#include <openssl/err.h>
#include <openssl/hkdf.h>
#include "caam.h"
#include "common.h"
#include "uuids.h"
#include "hwkey_srv_priv.h"
#include "hwkey_keyslots.h"
#define TLOG_LVL TLOG_LVL_DEFAULT
#define TLOG_TAG "hwkey_caam"
#include "tlog.h"
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;
TLOGI("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);
}
}