blob: b44a8555448dddf44f485823ce064639570a9891 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "trusty_atap_ops.h"
#include "secure_storage_manager.h"
#include "trusty_logger.h"
#include <keymaster/UniquePtr.h>
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
namespace {
using keymaster::AttestationKeySlot;
AttestationKeySlot MapKeyTypeToSlot(const AtapKeyType atap_key_type) {
switch (atap_key_type) {
case ATAP_KEY_TYPE_RSA:
return AttestationKeySlot::kRsa;
case ATAP_KEY_TYPE_ECDSA:
return AttestationKeySlot::kEcdsa;
case ATAP_KEY_TYPE_edDSA:
return AttestationKeySlot::kEddsa;
case ATAP_KEY_TYPE_EPID:
return AttestationKeySlot::kEpid;
case ATAP_KEY_TYPE_SPECIAL:
return AttestationKeySlot::kClaimable0;
case ATAP_KEY_TYPE_RSA_SOM:
return AttestationKeySlot::kSomRsa;
case ATAP_KEY_TYPE_ECDSA_SOM:
return AttestationKeySlot::kSomEcdsa;
case ATAP_KEY_TYPE_edDSA_SOM:
return AttestationKeySlot::kSomEddsa;
case ATAP_KEY_TYPE_EPID_SOM:
return AttestationKeySlot::kSomEpid;
default:
return AttestationKeySlot::kInvalid;
}
return AttestationKeySlot::kInvalid;
}
} // namespace
namespace keymaster {
struct EVP_PKEY_Delete {
void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); }
};
typedef UniquePtr<EVP_PKEY, EVP_PKEY_Delete> Unique_EVP_PKEY;
TrustyAtapOps::TrustyAtapOps() {}
TrustyAtapOps::~TrustyAtapOps() {}
struct PKCS8_PRIV_KEY_INFO_Delete {
void operator()(PKCS8_PRIV_KEY_INFO* p) const {
PKCS8_PRIV_KEY_INFO_free(p);
}
};
typedef UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete>
Unique_PKCS8_PRIV_KEY_INFO;
struct EVP_MD_CTX_Delete {
void operator()(EVP_MD_CTX* p) const {
EVP_MD_CTX_cleanup(p);
EVP_MD_CTX_destroy(p);
}
};
typedef UniquePtr<EVP_MD_CTX, EVP_MD_CTX_Delete> Unique_EVP_MD_CTX;
AtapResult TrustyAtapOps::read_product_id(
uint8_t product_id[ATAP_PRODUCT_ID_LEN]) {
SecureStorageManager* ss_manager = SecureStorageManager::get_instance();
if (ss_manager == nullptr)
return ATAP_RESULT_ERROR_STORAGE;
if (ss_manager->ReadProductId(product_id) != KM_ERROR_OK) {
/* If we can't get permanent attributes, set product id to the test
product id (all zero). */
LOG_E("Fail to read product id from storage, set as 0.", 0);
memset(product_id, 0, ATAP_PRODUCT_ID_LEN);
}
return ATAP_RESULT_OK;
}
AtapResult TrustyAtapOps::get_auth_key_type(AtapKeyType* key_type) {
if (_auth_key_type_init) {
*key_type = _auth_key_type;
return ATAP_RESULT_OK;
}
*key_type = ATAP_KEY_TYPE_NONE;
SecureStorageManager* ss_manager = SecureStorageManager::get_instance();
if (ss_manager == nullptr)
return ATAP_RESULT_ERROR_STORAGE;
const AtapKeyType kAuthKeyTypes[3] = {ATAP_KEY_TYPE_EPID_SOM,
ATAP_KEY_TYPE_RSA_SOM,
ATAP_KEY_TYPE_ECDSA_SOM};
for (size_t i = 0; i < (sizeof(kAuthKeyTypes) / sizeof(AtapKeyType)); i++) {
AttestationKeySlot key_slot = MapKeyTypeToSlot(kAuthKeyTypes[i]);
bool key_exists;
if (ss_manager->AttestationKeyExists(key_slot, &key_exists) !=
KM_ERROR_OK) {
return ATAP_RESULT_ERROR_STORAGE;
}
if (key_exists) {
*key_type = kAuthKeyTypes[i];
break;
}
}
_auth_key_type_init = true;
_auth_key_type = *key_type;
return ATAP_RESULT_OK;
}
AtapResult TrustyAtapOps::read_auth_key_cert_chain(AtapCertChain* cert_chain) {
AtapKeyType key_type;
AtapResult atap_result = get_auth_key_type(&key_type);
if (atap_result != ATAP_RESULT_OK) {
LOG_E("Failed to get key type.", 0);
return atap_result;
}
if (key_type == ATAP_KEY_TYPE_NONE) {
return ATAP_RESULT_ERROR_UNSUPPORTED_OPERATION;
}
SecureStorageManager* ss_manager = SecureStorageManager::get_instance();
if (ss_manager == nullptr) {
return ATAP_RESULT_ERROR_STORAGE;
}
AttestationKeySlot key_slot = MapKeyTypeToSlot(key_type);
keymaster_error_t result =
ss_manager->ReadAtapCertChainFromStorage(key_slot, cert_chain);
if (result != KM_ERROR_OK) {
LOG_E("Failed to read som cert chain from slot %d (err = %d)", key_slot,
result);
return ATAP_RESULT_ERROR_STORAGE;
}
if (cert_chain->entry_count > ATAP_CERT_CHAIN_ENTRIES_MAX) {
LOG_E("Stored cert chain length is larger than the maximum cert chain length",
0);
return ATAP_RESULT_ERROR_CRYPTO;
}
return ATAP_RESULT_OK;
}
AtapResult TrustyAtapOps::write_attestation_key(
AtapKeyType key_type,
const AtapBlob* key,
const AtapCertChain* cert_chain) {
SecureStorageManager* ss_manager = SecureStorageManager::get_instance();
if (ss_manager == nullptr)
return ATAP_RESULT_ERROR_STORAGE;
AttestationKeySlot slot = MapKeyTypeToSlot(key_type);
if (key_type == ATAP_KEY_TYPE_RSA_SOM ||
key_type == ATAP_KEY_TYPE_ECDSA_SOM ||
key_type == ATAP_KEY_TYPE_EPID_SOM ||
key_type == ATAP_KEY_TYPE_edDSA_SOM) {
/* If writing a som key, invalidate the cached auth_key_type. */
_auth_key_type_init = false;
}
if (slot == AttestationKeySlot::kInvalid) {
return ATAP_RESULT_ERROR_INVALID_INPUT;
}
keymaster_error_t result = ss_manager->WriteAtapKeyAndCertsToStorage(
slot, key->data, key->data_length, cert_chain);
if (result != KM_ERROR_OK) {
LOG_E("Failed to write key and certs to slot %d (err = %d)", slot,
result);
return ATAP_RESULT_ERROR_STORAGE;
}
return ATAP_RESULT_OK;
}
AtapResult TrustyAtapOps::read_attestation_public_key(
AtapKeyType key_type,
uint8_t pubkey[ATAP_KEY_LEN_MAX],
uint32_t* pubkey_len) {
return ATAP_RESULT_ERROR_UNSUPPORTED_OPERATION;
}
AtapResult TrustyAtapOps::read_soc_global_key(
uint8_t global_key[ATAP_AES_128_KEY_LEN]) {
return ATAP_RESULT_ERROR_UNSUPPORTED_OPERATION;
}
AtapResult TrustyAtapOps::write_hex_uuid(
const uint8_t uuid[ATAP_HEX_UUID_LEN]) {
SecureStorageManager* ss_manager = SecureStorageManager::get_instance();
if (ss_manager == nullptr)
return ATAP_RESULT_ERROR_STORAGE;
if (ss_manager->WriteAttestationUuid(uuid) != KM_ERROR_OK) {
return ATAP_RESULT_ERROR_STORAGE;
}
return ATAP_RESULT_OK;
}
AtapResult TrustyAtapOps::auth_key_sign(const uint8_t* nonce,
uint32_t nonce_len,
uint8_t sig[ATAP_SIGNATURE_LEN_MAX],
uint32_t* sig_len) {
AtapKeyType key_type;
keymaster_error_t result = KM_ERROR_OK;
AtapResult atap_result = get_auth_key_type(&key_type);
if (atap_result != ATAP_RESULT_OK) {
LOG_E("Failed to get key type", 0);
return atap_result;
}
if (key_type == ATAP_KEY_TYPE_NONE) {
return ATAP_RESULT_ERROR_UNSUPPORTED_OPERATION;
}
SecureStorageManager* ss_manager = SecureStorageManager::get_instance();
if (ss_manager == nullptr) {
return ATAP_RESULT_ERROR_STORAGE;
}
AttestationKeySlot key_slot = MapKeyTypeToSlot(key_type);
KeymasterKeyBlob key_blob =
ss_manager->ReadKeyFromStorage(key_slot, &result);
if (result != KM_ERROR_OK) {
LOG_E("Failed to read som cert chain from slot %d (err = %d)", key_slot,
result);
return ATAP_RESULT_ERROR_STORAGE;
}
const uint8_t* pkcs_priv_key_p = key_blob.key_material;
Unique_PKCS8_PRIV_KEY_INFO pkcs8(d2i_PKCS8_PRIV_KEY_INFO(
NULL, &pkcs_priv_key_p, key_blob.key_material_size));
if (!pkcs8.get()) {
LOG_E("Error parsing pkcs8 format private key.", 0);
return ATAP_RESULT_ERROR_INVALID_INPUT;
}
Unique_EVP_PKEY pkey(EVP_PKCS82PKEY(pkcs8.get()));
if (!pkey.get()) {
LOG_E("Error parsing pkcs8 private key to EVP_PKEY.", 0);
return ATAP_RESULT_ERROR_INVALID_INPUT;
}
Unique_EVP_MD_CTX mdctx(EVP_MD_CTX_create());
if (!mdctx.get()) {
LOG_E("Error creating md ctx.", 0);
return ATAP_RESULT_ERROR_OOM;
}
EVP_PKEY_CTX* evp_pkey_ctx;
if (1 != EVP_DigestSignInit(mdctx.get(), &evp_pkey_ctx, EVP_sha512(), NULL,
pkey.get())) {
return ATAP_RESULT_ERROR_OOM;
}
if (key_type == ATAP_KEY_TYPE_RSA_SOM &&
1 != EVP_PKEY_CTX_set_rsa_padding(evp_pkey_ctx, RSA_PKCS1_PADDING)) {
return ATAP_RESULT_ERROR_CRYPTO;
}
if (1 != EVP_DigestSignUpdate(mdctx.get(), nonce, nonce_len)) {
return ATAP_RESULT_ERROR_CRYPTO;
}
/* Get sig length. */
size_t local_sig_len;
if (1 != EVP_DigestSignFinal(mdctx.get(), NULL, &local_sig_len)) {
return ATAP_RESULT_ERROR_CRYPTO;
}
if (local_sig_len > ATAP_SIGNATURE_LEN_MAX) {
LOG_E("Signature length larger than the supported maximum signature length.",
0);
return ATAP_RESULT_ERROR_INVALID_INPUT;
}
/* Obtain the signature */
if (1 != EVP_DigestSignFinal(mdctx.get(), sig, &local_sig_len)) {
return ATAP_RESULT_ERROR_CRYPTO;
}
*sig_len = (uint32_t)local_sig_len;
return ATAP_RESULT_OK;
}
} // namespace keymaster