367 lines
14 KiB
C++
367 lines
14 KiB
C++
|
|
#include "ffi_test_utils.hpp"
|
||
|
|
|
||
|
|
#include <iostream>
|
||
|
|
|
||
|
|
#include <KeyMintAidlTestBase.h>
|
||
|
|
#include <aidl/android/hardware/security/keymint/ErrorCode.h>
|
||
|
|
#include <keymaster/UniquePtr.h>
|
||
|
|
|
||
|
|
#include <memory>
|
||
|
|
#include <vector>
|
||
|
|
|
||
|
|
#include <hardware/keymaster_defs.h>
|
||
|
|
#include <keymaster/android_keymaster_utils.h>
|
||
|
|
#include <keymaster/keymaster_tags.h>
|
||
|
|
|
||
|
|
#include <keymaster/km_openssl/attestation_record.h>
|
||
|
|
#include <keymaster/km_openssl/openssl_err.h>
|
||
|
|
#include <keymaster/km_openssl/openssl_utils.h>
|
||
|
|
#include <openssl/asn1t.h>
|
||
|
|
|
||
|
|
using aidl::android::hardware::security::keymint::ErrorCode;
|
||
|
|
|
||
|
|
#define TAG_SEQUENCE 0x30
|
||
|
|
#define LENGTH_MASK 0x80
|
||
|
|
#define LENGTH_VALUE_MASK 0x7F
|
||
|
|
|
||
|
|
/**
|
||
|
|
* ASN.1 structure for `KeyDescription` Schema.
|
||
|
|
* See `IKeyMintDevice.aidl` for documentation of the `KeyDescription` schema.
|
||
|
|
* KeyDescription ::= SEQUENCE(
|
||
|
|
* keyFormat INTEGER, # Values from KeyFormat enum.
|
||
|
|
* keyParams AuthorizationList,
|
||
|
|
* )
|
||
|
|
*/
|
||
|
|
typedef struct key_description {
|
||
|
|
ASN1_INTEGER* key_format;
|
||
|
|
keymaster::KM_AUTH_LIST* key_params;
|
||
|
|
} TEST_KEY_DESCRIPTION;
|
||
|
|
|
||
|
|
ASN1_SEQUENCE(TEST_KEY_DESCRIPTION) = {
|
||
|
|
ASN1_SIMPLE(TEST_KEY_DESCRIPTION, key_format, ASN1_INTEGER),
|
||
|
|
ASN1_SIMPLE(TEST_KEY_DESCRIPTION, key_params, keymaster::KM_AUTH_LIST),
|
||
|
|
} ASN1_SEQUENCE_END(TEST_KEY_DESCRIPTION);
|
||
|
|
DECLARE_ASN1_FUNCTIONS(TEST_KEY_DESCRIPTION);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* ASN.1 structure for `SecureKeyWrapper` Schema.
|
||
|
|
* See `IKeyMintDevice.aidl` for documentation of the `SecureKeyWrapper` schema.
|
||
|
|
* SecureKeyWrapper ::= SEQUENCE(
|
||
|
|
* version INTEGER, # Contains value 0
|
||
|
|
* encryptedTransportKey OCTET_STRING,
|
||
|
|
* initializationVector OCTET_STRING,
|
||
|
|
* keyDescription KeyDescription,
|
||
|
|
* encryptedKey OCTET_STRING,
|
||
|
|
* tag OCTET_STRING
|
||
|
|
* )
|
||
|
|
*/
|
||
|
|
typedef struct secure_key_wrapper {
|
||
|
|
ASN1_INTEGER* version;
|
||
|
|
ASN1_OCTET_STRING* encrypted_transport_key;
|
||
|
|
ASN1_OCTET_STRING* initialization_vector;
|
||
|
|
TEST_KEY_DESCRIPTION* key_desc;
|
||
|
|
ASN1_OCTET_STRING* encrypted_key;
|
||
|
|
ASN1_OCTET_STRING* tag;
|
||
|
|
} TEST_SECURE_KEY_WRAPPER;
|
||
|
|
|
||
|
|
ASN1_SEQUENCE(TEST_SECURE_KEY_WRAPPER) = {
|
||
|
|
ASN1_SIMPLE(TEST_SECURE_KEY_WRAPPER, version, ASN1_INTEGER),
|
||
|
|
ASN1_SIMPLE(TEST_SECURE_KEY_WRAPPER, encrypted_transport_key, ASN1_OCTET_STRING),
|
||
|
|
ASN1_SIMPLE(TEST_SECURE_KEY_WRAPPER, initialization_vector, ASN1_OCTET_STRING),
|
||
|
|
ASN1_SIMPLE(TEST_SECURE_KEY_WRAPPER, key_desc, TEST_KEY_DESCRIPTION),
|
||
|
|
ASN1_SIMPLE(TEST_SECURE_KEY_WRAPPER, encrypted_key, ASN1_OCTET_STRING),
|
||
|
|
ASN1_SIMPLE(TEST_SECURE_KEY_WRAPPER, tag, ASN1_OCTET_STRING),
|
||
|
|
} ASN1_SEQUENCE_END(TEST_SECURE_KEY_WRAPPER);
|
||
|
|
DECLARE_ASN1_FUNCTIONS(TEST_SECURE_KEY_WRAPPER);
|
||
|
|
|
||
|
|
IMPLEMENT_ASN1_FUNCTIONS(TEST_SECURE_KEY_WRAPPER);
|
||
|
|
IMPLEMENT_ASN1_FUNCTIONS(TEST_KEY_DESCRIPTION);
|
||
|
|
|
||
|
|
struct TEST_KEY_DESCRIPTION_Delete {
|
||
|
|
void operator()(TEST_KEY_DESCRIPTION* p) { TEST_KEY_DESCRIPTION_free(p); }
|
||
|
|
};
|
||
|
|
struct TEST_SECURE_KEY_WRAPPER_Delete {
|
||
|
|
void operator()(TEST_SECURE_KEY_WRAPPER* p) { TEST_SECURE_KEY_WRAPPER_free(p); }
|
||
|
|
};
|
||
|
|
|
||
|
|
/* This function extracts a certificate from the certs_chain_buffer at the given
|
||
|
|
* offset. Each DER encoded certificate starts with TAG_SEQUENCE followed by the
|
||
|
|
* total length of the certificate. The length of the certificate is determined
|
||
|
|
* as per ASN.1 encoding rules for the length octets.
|
||
|
|
*
|
||
|
|
* @param certs_chain_buffer: buffer containing DER encoded X.509 certificates
|
||
|
|
* arranged sequentially.
|
||
|
|
* @data_size: Length of the DER encoded X.509 certificates buffer.
|
||
|
|
* @index: DER encoded X.509 certificates buffer offset.
|
||
|
|
* @cert: Encoded certificate to be extracted from buffer as outcome.
|
||
|
|
* @return: ErrorCode::OK on success, otherwise ErrorCode::UNKNOWN_ERROR.
|
||
|
|
*/
|
||
|
|
ErrorCode
|
||
|
|
extractCertFromCertChainBuffer(uint8_t* certs_chain_buffer, int certs_chain_buffer_size, int& index,
|
||
|
|
aidl::android::hardware::security::keymint::Certificate& cert) {
|
||
|
|
if (index >= certs_chain_buffer_size) {
|
||
|
|
return ErrorCode::UNKNOWN_ERROR;
|
||
|
|
}
|
||
|
|
|
||
|
|
uint32_t length = 0;
|
||
|
|
std::vector<uint8_t> cert_bytes;
|
||
|
|
if (certs_chain_buffer[index] == TAG_SEQUENCE) {
|
||
|
|
// Short form. One octet. Bit 8 has value "0" and bits 7-1 give the length.
|
||
|
|
if (0 == (certs_chain_buffer[index + 1] & LENGTH_MASK)) {
|
||
|
|
length = (uint32_t)certs_chain_buffer[index];
|
||
|
|
// Add SEQ and Length fields
|
||
|
|
length += 2;
|
||
|
|
} else {
|
||
|
|
// Long form. Two to 127 octets. Bit 8 of first octet has value "1" and
|
||
|
|
// bits 7-1 give the number of additional length octets. Second and following
|
||
|
|
// octets give the actual length.
|
||
|
|
int additionalBytes = certs_chain_buffer[index + 1] & LENGTH_VALUE_MASK;
|
||
|
|
if (additionalBytes == 0x01) {
|
||
|
|
length = certs_chain_buffer[index + 2];
|
||
|
|
// Add SEQ and Length fields
|
||
|
|
length += 3;
|
||
|
|
} else if (additionalBytes == 0x02) {
|
||
|
|
length = (certs_chain_buffer[index + 2] << 8 | certs_chain_buffer[index + 3]);
|
||
|
|
// Add SEQ and Length fields
|
||
|
|
length += 4;
|
||
|
|
} else if (additionalBytes == 0x04) {
|
||
|
|
length = certs_chain_buffer[index + 2] << 24;
|
||
|
|
length |= certs_chain_buffer[index + 3] << 16;
|
||
|
|
length |= certs_chain_buffer[index + 4] << 8;
|
||
|
|
length |= certs_chain_buffer[index + 5];
|
||
|
|
// Add SEQ and Length fields
|
||
|
|
length += 6;
|
||
|
|
} else {
|
||
|
|
// Length is larger than uint32_t max limit.
|
||
|
|
return ErrorCode::UNKNOWN_ERROR;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
cert_bytes.insert(cert_bytes.end(), (certs_chain_buffer + index),
|
||
|
|
(certs_chain_buffer + index + length));
|
||
|
|
index += length;
|
||
|
|
|
||
|
|
for (int i = 0; i < cert_bytes.size(); i++) {
|
||
|
|
cert.encodedCertificate = std::move(cert_bytes);
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
// SEQUENCE TAG MISSING.
|
||
|
|
return ErrorCode::UNKNOWN_ERROR;
|
||
|
|
}
|
||
|
|
|
||
|
|
return ErrorCode::OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
ErrorCode getCertificateChain(
|
||
|
|
rust::Vec<rust::u8>& chainBuffer,
|
||
|
|
std::vector<aidl::android::hardware::security::keymint::Certificate>& certChain) {
|
||
|
|
uint8_t* data = chainBuffer.data();
|
||
|
|
int index = 0;
|
||
|
|
int data_size = chainBuffer.size();
|
||
|
|
|
||
|
|
while (index < data_size) {
|
||
|
|
aidl::android::hardware::security::keymint::Certificate cert =
|
||
|
|
aidl::android::hardware::security::keymint::Certificate();
|
||
|
|
if (extractCertFromCertChainBuffer(data, data_size, index, cert) != ErrorCode::OK) {
|
||
|
|
return ErrorCode::UNKNOWN_ERROR;
|
||
|
|
}
|
||
|
|
certChain.push_back(std::move(cert));
|
||
|
|
}
|
||
|
|
return ErrorCode::OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool validateCertChain(rust::Vec<rust::u8> cert_buf, uint32_t cert_len, bool strict_issuer_check) {
|
||
|
|
std::vector<aidl::android::hardware::security::keymint::Certificate> cert_chain =
|
||
|
|
std::vector<aidl::android::hardware::security::keymint::Certificate>();
|
||
|
|
if (cert_len <= 0) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (getCertificateChain(cert_buf, cert_chain) != ErrorCode::OK) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = 0; i < cert_chain.size(); i++) {
|
||
|
|
std::cout << cert_chain[i].toString() << "\n";
|
||
|
|
}
|
||
|
|
auto result = aidl::android::hardware::security::keymint::test::ChainSignaturesAreValid(
|
||
|
|
cert_chain, strict_issuer_check);
|
||
|
|
|
||
|
|
if (result == testing::AssertionSuccess()) return true;
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Below mentioned key parameters are used to create authorization list of
|
||
|
|
* secure key.
|
||
|
|
* Algorithm: AES-256
|
||
|
|
* Padding: PKCS7
|
||
|
|
* Blockmode: ECB
|
||
|
|
* Purpose: Encrypt, Decrypt
|
||
|
|
*/
|
||
|
|
keymaster::AuthorizationSet build_wrapped_key_auth_list() {
|
||
|
|
return keymaster::AuthorizationSet(keymaster::AuthorizationSetBuilder()
|
||
|
|
.AesEncryptionKey(256)
|
||
|
|
.Authorization(keymaster::TAG_BLOCK_MODE, KM_MODE_ECB)
|
||
|
|
.Authorization(keymaster::TAG_PADDING, KM_PAD_PKCS7)
|
||
|
|
.Authorization(keymaster::TAG_NO_AUTH_REQUIRED));
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Creates ASN.1 DER-encoded data corresponding to `KeyDescription` schema as
|
||
|
|
* AAD. See `IKeyMintDevice.aidl` for documentation of the `KeyDescription` schema.
|
||
|
|
*/
|
||
|
|
CxxResult buildAsn1DerEncodedWrappedKeyDescription() {
|
||
|
|
CxxResult cxx_result{};
|
||
|
|
keymaster_error_t error;
|
||
|
|
cxx_result.error = KM_ERROR_OK;
|
||
|
|
|
||
|
|
keymaster::UniquePtr<TEST_KEY_DESCRIPTION, TEST_KEY_DESCRIPTION_Delete> key_description(
|
||
|
|
TEST_KEY_DESCRIPTION_new());
|
||
|
|
if (!key_description.get()) {
|
||
|
|
cxx_result.error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
|
||
|
|
return cxx_result;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Fill secure key authorizations.
|
||
|
|
keymaster::AuthorizationSet auth_list = build_wrapped_key_auth_list();
|
||
|
|
error = build_auth_list(auth_list, key_description->key_params);
|
||
|
|
if (error != KM_ERROR_OK) {
|
||
|
|
cxx_result.error = error;
|
||
|
|
return cxx_result;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Fill secure key format.
|
||
|
|
if (!ASN1_INTEGER_set(key_description->key_format, KM_KEY_FORMAT_RAW)) {
|
||
|
|
cxx_result.error = keymaster::TranslateLastOpenSslError();
|
||
|
|
return cxx_result;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Perform ASN.1 DER encoding of KeyDescription.
|
||
|
|
int asn1_data_len = i2d_TEST_KEY_DESCRIPTION(key_description.get(), nullptr);
|
||
|
|
if (asn1_data_len < 0) {
|
||
|
|
cxx_result.error = keymaster::TranslateLastOpenSslError();
|
||
|
|
return cxx_result;
|
||
|
|
}
|
||
|
|
std::vector<uint8_t> asn1_data(asn1_data_len, 0);
|
||
|
|
|
||
|
|
if (!asn1_data.data()) {
|
||
|
|
cxx_result.error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
|
||
|
|
return cxx_result;
|
||
|
|
}
|
||
|
|
|
||
|
|
uint8_t* p = asn1_data.data();
|
||
|
|
asn1_data_len = i2d_TEST_KEY_DESCRIPTION(key_description.get(), &p);
|
||
|
|
if (asn1_data_len < 0) {
|
||
|
|
cxx_result.error = keymaster::TranslateLastOpenSslError();
|
||
|
|
return cxx_result;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::move(asn1_data.begin(), asn1_data.end(), std::back_inserter(cxx_result.data));
|
||
|
|
|
||
|
|
return cxx_result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Creates wrapped key material to import in ASN.1 DER-encoded data corresponding to
|
||
|
|
* `SecureKeyWrapper` schema. See `IKeyMintDevice.aidl` for documentation of the `SecureKeyWrapper`
|
||
|
|
* schema.
|
||
|
|
*/
|
||
|
|
CxxResult createWrappedKey(rust::Vec<rust::u8> encrypted_secure_key,
|
||
|
|
rust::Vec<rust::u8> encrypted_transport_key, rust::Vec<rust::u8> iv,
|
||
|
|
rust::Vec<rust::u8> tag) {
|
||
|
|
CxxResult cxx_result{};
|
||
|
|
keymaster_error_t error;
|
||
|
|
cxx_result.error = KM_ERROR_OK;
|
||
|
|
|
||
|
|
uint8_t* enc_secure_key_data = encrypted_secure_key.data();
|
||
|
|
int enc_secure_key_size = encrypted_secure_key.size();
|
||
|
|
|
||
|
|
uint8_t* iv_data = iv.data();
|
||
|
|
int iv_size = iv.size();
|
||
|
|
|
||
|
|
uint8_t* tag_data = tag.data();
|
||
|
|
int tag_size = tag.size();
|
||
|
|
|
||
|
|
uint8_t* enc_transport_key_data = encrypted_transport_key.data();
|
||
|
|
int enc_transport_key_size = encrypted_transport_key.size();
|
||
|
|
|
||
|
|
keymaster::UniquePtr<TEST_SECURE_KEY_WRAPPER, TEST_SECURE_KEY_WRAPPER_Delete> sec_key_wrapper(
|
||
|
|
TEST_SECURE_KEY_WRAPPER_new());
|
||
|
|
if (!sec_key_wrapper.get()) {
|
||
|
|
cxx_result.error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
|
||
|
|
return cxx_result;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Fill version = 0
|
||
|
|
if (!ASN1_INTEGER_set(sec_key_wrapper->version, 0)) {
|
||
|
|
cxx_result.error = keymaster::TranslateLastOpenSslError();
|
||
|
|
return cxx_result;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Fill encrypted transport key.
|
||
|
|
if (enc_transport_key_size &&
|
||
|
|
!ASN1_OCTET_STRING_set(sec_key_wrapper->encrypted_transport_key, enc_transport_key_data,
|
||
|
|
enc_transport_key_size)) {
|
||
|
|
cxx_result.error = keymaster::TranslateLastOpenSslError();
|
||
|
|
return cxx_result;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Fill encrypted secure key.
|
||
|
|
if (enc_secure_key_size && !ASN1_OCTET_STRING_set(sec_key_wrapper->encrypted_key,
|
||
|
|
enc_secure_key_data, enc_secure_key_size)) {
|
||
|
|
cxx_result.error = keymaster::TranslateLastOpenSslError();
|
||
|
|
return cxx_result;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Fill secure key authorization list.
|
||
|
|
keymaster::AuthorizationSet auth_list = build_wrapped_key_auth_list();
|
||
|
|
error = build_auth_list(auth_list, sec_key_wrapper->key_desc->key_params);
|
||
|
|
if (error != KM_ERROR_OK) {
|
||
|
|
cxx_result.error = error;
|
||
|
|
return cxx_result;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Fill secure key format.
|
||
|
|
if (!ASN1_INTEGER_set(sec_key_wrapper->key_desc->key_format, KM_KEY_FORMAT_RAW)) {
|
||
|
|
cxx_result.error = keymaster::TranslateLastOpenSslError();
|
||
|
|
return cxx_result;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Fill initialization vector used for encrypting secure key.
|
||
|
|
if (iv_size &&
|
||
|
|
!ASN1_OCTET_STRING_set(sec_key_wrapper->initialization_vector, iv_data, iv_size)) {
|
||
|
|
cxx_result.error = keymaster::TranslateLastOpenSslError();
|
||
|
|
return cxx_result;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Fill GCM-tag, extracted during secure key encryption.
|
||
|
|
if (tag_size && !ASN1_OCTET_STRING_set(sec_key_wrapper->tag, tag_data, tag_size)) {
|
||
|
|
cxx_result.error = keymaster::TranslateLastOpenSslError();
|
||
|
|
return cxx_result;
|
||
|
|
}
|
||
|
|
|
||
|
|
// ASN.1 DER-encoding of secure key wrapper.
|
||
|
|
int asn1_data_len = i2d_TEST_SECURE_KEY_WRAPPER(sec_key_wrapper.get(), nullptr);
|
||
|
|
if (asn1_data_len < 0) {
|
||
|
|
cxx_result.error = keymaster::TranslateLastOpenSslError();
|
||
|
|
return cxx_result;
|
||
|
|
}
|
||
|
|
std::vector<uint8_t> asn1_data(asn1_data_len, 0);
|
||
|
|
|
||
|
|
if (!asn1_data.data()) {
|
||
|
|
cxx_result.error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
|
||
|
|
return cxx_result;
|
||
|
|
}
|
||
|
|
|
||
|
|
uint8_t* p = asn1_data.data();
|
||
|
|
asn1_data_len = i2d_TEST_SECURE_KEY_WRAPPER(sec_key_wrapper.get(), &p);
|
||
|
|
if (asn1_data_len < 0) {
|
||
|
|
cxx_result.error = keymaster::TranslateLastOpenSslError();
|
||
|
|
return cxx_result;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::move(asn1_data.begin(), asn1_data.end(), std::back_inserter(cxx_result.data));
|
||
|
|
|
||
|
|
return cxx_result;
|
||
|
|
}
|