am ee47386a: am 0e26977c: Merge changes from topic \'trusty-gk-km\'\'
* commit 'ee47386aa3074dbcff9c2fc757687d34721b66d9': [core][trusty] add gatekeeper module [core][trusty] add keymaster module
This commit is contained in:
commit
862718b592
|
@ -0,0 +1,50 @@
|
|||
#
|
||||
# Copyright (C) 2015 The Android Open-Source Project
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# WARNING: Everything listed here will be built on ALL platforms,
|
||||
# including x86, the emulator, and the SDK. Modules must be uniquely
|
||||
# named (liblights.panda), and must build everywhere, or limit themselves
|
||||
# to only building on ARM if they include assembly. Individual makefiles
|
||||
# are responsible for having their own logic, for fine-grained control.
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := gatekeeper.trusty
|
||||
|
||||
LOCAL_MODULE_RELATIVE_PATH := hw
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
module.cpp \
|
||||
trusty_gatekeeper_ipc.c \
|
||||
trusty_gatekeeper.cpp
|
||||
|
||||
LOCAL_CLFAGS = -fvisibility=hidden -Wall -Werror
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libgatekeeper \
|
||||
liblog \
|
||||
libcutils \
|
||||
libtrusty
|
||||
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
# Symlink gatekeeper.trusty.so -> gatekeeper.<device>.so so libhardware can find it.
|
||||
LOCAL_POST_INSTALL_CMD = \
|
||||
$(hide) ln -sf $(notdir $(LOCAL_INSTALLED_MODULE)) $(dir $(LOCAL_INSTALLED_MODULE))gatekeeper.$(TARGET_DEVICE).so
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define GATEKEEPER_PORT "com.android.trusty.gatekeeper"
|
||||
#define GATEKEEPER_MAX_BUFFER_LENGTH 1024
|
||||
|
||||
enum gatekeeper_command {
|
||||
GK_REQ_SHIFT = 1,
|
||||
GK_RESP_BIT = 1,
|
||||
|
||||
GK_ENROLL = (0 << GK_REQ_SHIFT),
|
||||
GK_VERIFY = (1 << GK_REQ_SHIFT),
|
||||
};
|
||||
|
||||
/**
|
||||
* gatekeeper_message - Serial header for communicating with GK server
|
||||
* @cmd: the command, one of ENROLL, VERIFY. Payload must be a serialized
|
||||
* buffer of the corresponding request object.
|
||||
* @payload: start of the serialized command specific payload
|
||||
*/
|
||||
struct gatekeeper_message {
|
||||
uint32_t cmd;
|
||||
uint8_t payload[0];
|
||||
};
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* 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 <hardware/hardware.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "trusty_gatekeeper.h"
|
||||
|
||||
using gatekeeper::TrustyGateKeeperDevice;
|
||||
|
||||
static int trusty_gatekeeper_open(const hw_module_t *module, const char *name,
|
||||
hw_device_t **device) {
|
||||
|
||||
if (strcmp(name, HARDWARE_GATEKEEPER) != 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
TrustyGateKeeperDevice *gatekeeper = new TrustyGateKeeperDevice(module);
|
||||
if (gatekeeper == NULL) return -ENOMEM;
|
||||
*device = gatekeeper->hw_device();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hw_module_methods_t gatekeeper_module_methods = {
|
||||
.open = trusty_gatekeeper_open,
|
||||
};
|
||||
|
||||
struct gatekeeper_module HAL_MODULE_INFO_SYM __attribute__((visibility("default"))) = {
|
||||
.common = {
|
||||
.tag = HARDWARE_MODULE_TAG,
|
||||
.module_api_version = GATEKEEPER_MODULE_API_VERSION_0_1,
|
||||
.hal_api_version = HARDWARE_HAL_API_VERSION,
|
||||
.id = GATEKEEPER_HARDWARE_MODULE_ID,
|
||||
.name = "Trusty GateKeeper HAL",
|
||||
.author = "The Android Open Source Project",
|
||||
.methods = &gatekeeper_module_methods,
|
||||
.dso = 0,
|
||||
.reserved = {}
|
||||
},
|
||||
};
|
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* 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 <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <type_traits>
|
||||
|
||||
#include "trusty_gatekeeper.h"
|
||||
#include "trusty_gatekeeper_ipc.h"
|
||||
#include "gatekeeper_ipc.h"
|
||||
|
||||
#define LOG_TAG "TrustyGateKeeper"
|
||||
#include <cutils/log.h>
|
||||
|
||||
namespace gatekeeper {
|
||||
|
||||
const uint32_t SEND_BUF_SIZE = 8192;
|
||||
const uint32_t RECV_BUF_SIZE = 8192;
|
||||
|
||||
TrustyGateKeeperDevice::TrustyGateKeeperDevice(const hw_module_t *module) {
|
||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
static_assert(std::is_standard_layout<TrustyGateKeeperDevice>::value,
|
||||
"TrustyGateKeeperDevice must be standard layout");
|
||||
static_assert(offsetof(TrustyGateKeeperDevice, device_) == 0,
|
||||
"device_ must be the first member of TrustyGateKeeperDevice");
|
||||
static_assert(offsetof(TrustyGateKeeperDevice, device_.common) == 0,
|
||||
"common must be the first member of gatekeeper_device");
|
||||
#else
|
||||
assert(reinterpret_cast<gatekeeper_device_t *>(this) == &device_);
|
||||
assert(reinterpret_cast<hw_device_t *>(this) == &(device_.common));
|
||||
#endif
|
||||
|
||||
memset(&device_, 0, sizeof(device_));
|
||||
device_.common.tag = HARDWARE_DEVICE_TAG;
|
||||
device_.common.version = 1;
|
||||
device_.common.module = const_cast<hw_module_t *>(module);
|
||||
device_.common.close = close_device;
|
||||
|
||||
device_.enroll = enroll;
|
||||
device_.verify = verify;
|
||||
device_.delete_user = nullptr;
|
||||
device_.delete_all_users = nullptr;
|
||||
|
||||
int rc = trusty_gatekeeper_connect();
|
||||
if (rc < 0) {
|
||||
ALOGE("Error initializing trusty session: %d", rc);
|
||||
}
|
||||
|
||||
error_ = rc;
|
||||
|
||||
}
|
||||
|
||||
hw_device_t* TrustyGateKeeperDevice::hw_device() {
|
||||
return &device_.common;
|
||||
}
|
||||
|
||||
int TrustyGateKeeperDevice::close_device(hw_device_t* dev) {
|
||||
delete reinterpret_cast<TrustyGateKeeperDevice *>(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
TrustyGateKeeperDevice::~TrustyGateKeeperDevice() {
|
||||
trusty_gatekeeper_disconnect();
|
||||
}
|
||||
|
||||
int TrustyGateKeeperDevice::Enroll(uint32_t uid, const uint8_t *current_password_handle,
|
||||
uint32_t current_password_handle_length, const uint8_t *current_password,
|
||||
uint32_t current_password_length, const uint8_t *desired_password,
|
||||
uint32_t desired_password_length, uint8_t **enrolled_password_handle,
|
||||
uint32_t *enrolled_password_handle_length) {
|
||||
|
||||
if (error_ != 0) {
|
||||
return error_;
|
||||
}
|
||||
|
||||
SizedBuffer desired_password_buffer(desired_password_length);
|
||||
memcpy(desired_password_buffer.buffer.get(), desired_password, desired_password_length);
|
||||
|
||||
SizedBuffer current_password_handle_buffer(current_password_handle_length);
|
||||
if (current_password_handle) {
|
||||
memcpy(current_password_handle_buffer.buffer.get(), current_password_handle,
|
||||
current_password_handle_length);
|
||||
}
|
||||
|
||||
SizedBuffer current_password_buffer(current_password_length);
|
||||
if (current_password) {
|
||||
memcpy(current_password_buffer.buffer.get(), current_password, current_password_length);
|
||||
}
|
||||
|
||||
EnrollRequest request(uid, ¤t_password_handle_buffer, &desired_password_buffer,
|
||||
¤t_password_buffer);
|
||||
EnrollResponse response;
|
||||
|
||||
gatekeeper_error_t error = Send(request, &response);
|
||||
|
||||
if (error == ERROR_RETRY) {
|
||||
return response.retry_timeout;
|
||||
} else if (error != ERROR_NONE) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*enrolled_password_handle = response.enrolled_password_handle.buffer.release();
|
||||
*enrolled_password_handle_length = response.enrolled_password_handle.length;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TrustyGateKeeperDevice::Verify(uint32_t uid, uint64_t challenge,
|
||||
const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,
|
||||
const uint8_t *provided_password, uint32_t provided_password_length,
|
||||
uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll) {
|
||||
if (error_ != 0) {
|
||||
return error_;
|
||||
}
|
||||
|
||||
SizedBuffer password_handle_buffer(enrolled_password_handle_length);
|
||||
memcpy(password_handle_buffer.buffer.get(), enrolled_password_handle,
|
||||
enrolled_password_handle_length);
|
||||
SizedBuffer provided_password_buffer(provided_password_length);
|
||||
memcpy(provided_password_buffer.buffer.get(), provided_password, provided_password_length);
|
||||
|
||||
VerifyRequest request(uid, challenge, &password_handle_buffer, &provided_password_buffer);
|
||||
VerifyResponse response;
|
||||
|
||||
gatekeeper_error_t error = Send(request, &response);
|
||||
|
||||
if (error == ERROR_RETRY) {
|
||||
return response.retry_timeout;
|
||||
} else if (error != ERROR_NONE) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (auth_token != NULL && auth_token_length != NULL) {
|
||||
*auth_token = response.auth_token.buffer.release();
|
||||
*auth_token_length = response.auth_token.length;
|
||||
}
|
||||
|
||||
if (request_reenroll != NULL) {
|
||||
*request_reenroll = response.request_reenroll;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gatekeeper_error_t TrustyGateKeeperDevice::Send(uint32_t command, const GateKeeperMessage& request,
|
||||
GateKeeperMessage *response) {
|
||||
uint32_t request_size = request.GetSerializedSize();
|
||||
if (request_size > SEND_BUF_SIZE)
|
||||
return ERROR_INVALID;
|
||||
uint8_t send_buf[SEND_BUF_SIZE];
|
||||
request.Serialize(send_buf, send_buf + request_size);
|
||||
|
||||
// Send it
|
||||
uint8_t recv_buf[RECV_BUF_SIZE];
|
||||
uint32_t response_size = RECV_BUF_SIZE;
|
||||
int rc = trusty_gatekeeper_call(command, send_buf, request_size, recv_buf, &response_size);
|
||||
if (rc < 0) {
|
||||
ALOGE("error (%d) calling gatekeeper TA", rc);
|
||||
return ERROR_INVALID;
|
||||
}
|
||||
|
||||
const gatekeeper_message *msg = reinterpret_cast<gatekeeper_message *>(recv_buf);
|
||||
const uint8_t *payload = msg->payload;
|
||||
|
||||
return response->Deserialize(payload, payload + response_size);
|
||||
}
|
||||
|
||||
static inline TrustyGateKeeperDevice *convert_device(const gatekeeper_device *dev) {
|
||||
return reinterpret_cast<TrustyGateKeeperDevice *>(const_cast<gatekeeper_device *>(dev));
|
||||
}
|
||||
|
||||
/* static */
|
||||
int TrustyGateKeeperDevice::enroll(const struct gatekeeper_device *dev, uint32_t uid,
|
||||
const uint8_t *current_password_handle, uint32_t current_password_handle_length,
|
||||
const uint8_t *current_password, uint32_t current_password_length,
|
||||
const uint8_t *desired_password, uint32_t desired_password_length,
|
||||
uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length) {
|
||||
|
||||
if (dev == NULL ||
|
||||
enrolled_password_handle == NULL || enrolled_password_handle_length == NULL ||
|
||||
desired_password == NULL || desired_password_length == 0)
|
||||
return -EINVAL;
|
||||
|
||||
// Current password and current password handle go together
|
||||
if (current_password_handle == NULL || current_password_handle_length == 0 ||
|
||||
current_password == NULL || current_password_length == 0) {
|
||||
current_password_handle = NULL;
|
||||
current_password_handle_length = 0;
|
||||
current_password = NULL;
|
||||
current_password_length = 0;
|
||||
}
|
||||
|
||||
return convert_device(dev)->Enroll(uid, current_password_handle, current_password_handle_length,
|
||||
current_password, current_password_length, desired_password, desired_password_length,
|
||||
enrolled_password_handle, enrolled_password_handle_length);
|
||||
|
||||
}
|
||||
|
||||
/* static */
|
||||
int TrustyGateKeeperDevice::verify(const struct gatekeeper_device *dev, uint32_t uid,
|
||||
uint64_t challenge, const uint8_t *enrolled_password_handle,
|
||||
uint32_t enrolled_password_handle_length, const uint8_t *provided_password,
|
||||
uint32_t provided_password_length, uint8_t **auth_token, uint32_t *auth_token_length,
|
||||
bool *request_reenroll) {
|
||||
|
||||
if (dev == NULL || enrolled_password_handle == NULL ||
|
||||
provided_password == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return convert_device(dev)->Verify(uid, challenge, enrolled_password_handle,
|
||||
enrolled_password_handle_length, provided_password, provided_password_length,
|
||||
auth_token, auth_token_length, request_reenroll);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef TRUSTY_GATEKEEPER_H
|
||||
#define TRUSTY_GATEKEEPER_H
|
||||
|
||||
#include <hardware/gatekeeper.h>
|
||||
#include <gatekeeper/gatekeeper_messages.h>
|
||||
|
||||
#include "gatekeeper_ipc.h"
|
||||
|
||||
namespace gatekeeper {
|
||||
|
||||
class TrustyGateKeeperDevice {
|
||||
public:
|
||||
|
||||
TrustyGateKeeperDevice(const hw_module_t* module);
|
||||
~TrustyGateKeeperDevice();
|
||||
|
||||
hw_device_t* hw_device();
|
||||
|
||||
/**
|
||||
* Enrolls password_payload, which should be derived from a user selected pin or password,
|
||||
* with the authentication factor private key used only for enrolling authentication
|
||||
* factor data.
|
||||
*
|
||||
* Returns: 0 on success or an error code less than 0 on error.
|
||||
* On error, enrolled_password will not be allocated.
|
||||
*/
|
||||
int Enroll(uint32_t uid, const uint8_t *current_password_handle,
|
||||
uint32_t current_password_handle_length, const uint8_t *current_password,
|
||||
uint32_t current_password_length, const uint8_t *desired_password,
|
||||
uint32_t desired_password_length, uint8_t **enrolled_password_handle,
|
||||
uint32_t *enrolled_password_handle_length);
|
||||
|
||||
/**
|
||||
* Verifies provided_password matches expected_password after enrolling
|
||||
* with the authentication factor private key.
|
||||
*
|
||||
* Implementations of this module may retain the result of this call
|
||||
* to attest to the recency of authentication.
|
||||
*
|
||||
* On success, writes the address of a verification token to verification_token,
|
||||
*
|
||||
* Returns: 0 on success or an error code less than 0 on error
|
||||
* On error, verification token will not be allocated
|
||||
*/
|
||||
int Verify(uint32_t uid, uint64_t challenge, const uint8_t *enrolled_password_handle,
|
||||
uint32_t enrolled_password_handle_length, const uint8_t *provided_password,
|
||||
uint32_t provided_password_length, uint8_t **auth_token, uint32_t *auth_token_length,
|
||||
bool *request_reenroll);
|
||||
|
||||
private:
|
||||
|
||||
gatekeeper_error_t Send(uint32_t command, const GateKeeperMessage& request,
|
||||
GateKeeperMessage* response);
|
||||
|
||||
gatekeeper_error_t Send(const EnrollRequest& request, EnrollResponse *response) {
|
||||
return Send(GK_ENROLL, request, response);
|
||||
}
|
||||
|
||||
gatekeeper_error_t Send(const VerifyRequest& request, VerifyResponse *response) {
|
||||
return Send(GK_VERIFY, request, response);
|
||||
}
|
||||
|
||||
// Static methods interfacing the HAL API with the TrustyGateKeeper device
|
||||
|
||||
/**
|
||||
* Enrolls desired_password, which should be derived from a user selected pin or password,
|
||||
* with the authentication factor private key used only for enrolling authentication
|
||||
* factor data.
|
||||
*
|
||||
* If there was already a password enrolled, it should be provided in
|
||||
* current_password_handle, along with the current password in current_password
|
||||
* that should validate against current_password_handle.
|
||||
*
|
||||
* Returns: 0 on success or an error code less than 0 on error.
|
||||
* On error, enrolled_password_handle will not be allocated.
|
||||
*/
|
||||
static int enroll(const struct gatekeeper_device *dev, uint32_t uid,
|
||||
const uint8_t *current_password_handle, uint32_t current_password_handle_length,
|
||||
const uint8_t *current_password, uint32_t current_password_length,
|
||||
const uint8_t *desired_password, uint32_t desired_password_length,
|
||||
uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length);
|
||||
|
||||
/**
|
||||
* Verifies provided_password matches enrolled_password_handle.
|
||||
*
|
||||
* Implementations of this module may retain the result of this call
|
||||
* to attest to the recency of authentication.
|
||||
*
|
||||
* On success, writes the address of a verification token to auth_token,
|
||||
* usable to attest password verification to other trusted services. Clients
|
||||
* may pass NULL for this value.
|
||||
*
|
||||
* Returns: 0 on success or an error code less than 0 on error
|
||||
* On error, verification token will not be allocated
|
||||
*/
|
||||
static int verify(const struct gatekeeper_device *dev, uint32_t uid, uint64_t challenge,
|
||||
const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,
|
||||
const uint8_t *provided_password, uint32_t provided_password_length,
|
||||
uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll);
|
||||
|
||||
static int close_device(hw_device_t* dev);
|
||||
|
||||
gatekeeper_device device_;
|
||||
int error_;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* 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 <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define LOG_TAG "TrustyGateKeeper"
|
||||
#include <cutils/log.h>
|
||||
#include <trusty/tipc.h>
|
||||
|
||||
#include "trusty_gatekeeper_ipc.h"
|
||||
#include "gatekeeper_ipc.h"
|
||||
|
||||
#define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0"
|
||||
|
||||
static int handle_ = 0;
|
||||
|
||||
int trusty_gatekeeper_connect() {
|
||||
int rc = tipc_connect(TRUSTY_DEVICE_NAME, GATEKEEPER_PORT);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
handle_ = rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int trusty_gatekeeper_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out,
|
||||
uint32_t *out_size) {
|
||||
if (handle_ == 0) {
|
||||
ALOGE("not connected\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
size_t msg_size = in_size + sizeof(struct gatekeeper_message);
|
||||
struct gatekeeper_message *msg = malloc(msg_size);
|
||||
msg->cmd = cmd;
|
||||
memcpy(msg->payload, in, in_size);
|
||||
|
||||
ssize_t rc = write(handle_, msg, msg_size);
|
||||
free(msg);
|
||||
|
||||
if (rc < 0) {
|
||||
ALOGE("failed to send cmd (%d) to %s: %s\n", cmd,
|
||||
GATEKEEPER_PORT, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
rc = read(handle_, out, *out_size);
|
||||
if (rc < 0) {
|
||||
ALOGE("failed to retrieve response for cmd (%d) to %s: %s\n",
|
||||
cmd, GATEKEEPER_PORT, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if ((size_t) rc < sizeof(struct gatekeeper_message)) {
|
||||
ALOGE("invalid response size (%d)\n", (int) rc);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
msg = (struct gatekeeper_message *) out;
|
||||
|
||||
if ((cmd | GK_RESP_BIT) != msg->cmd) {
|
||||
ALOGE("invalid command (%d)\n", msg->cmd);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*out_size = ((size_t) rc) - sizeof(struct gatekeeper_message);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void trusty_gatekeeper_disconnect() {
|
||||
if (handle_ != 0) {
|
||||
tipc_close(handle_);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
int trusty_gatekeeper_connect();
|
||||
int trusty_gatekeeper_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out,
|
||||
uint32_t *out_size);
|
||||
void trusty_gatekeeper_disconnect();
|
||||
|
||||
__END_DECLS
|
|
@ -0,0 +1,76 @@
|
|||
#
|
||||
# Copyright (C) 2015 The Android Open-Source Project
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# WARNING: Everything listed here will be built on ALL platforms,
|
||||
# including x86, the emulator, and the SDK. Modules must be uniquely
|
||||
# named (liblights.panda), and must build everywhere, or limit themselves
|
||||
# to only building on ARM if they include assembly. Individual makefiles
|
||||
# are responsible for having their own logic, for fine-grained control.
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
###
|
||||
# trusty_keymaster is a binary used only for on-device testing. It
|
||||
# runs Trusty Keymaster through a basic set of operations with RSA
|
||||
# and ECDSA keys.
|
||||
###
|
||||
LOCAL_MODULE := trusty_keymaster
|
||||
LOCAL_C_INCLUDES:= \
|
||||
system/keymaster \
|
||||
external/openssl/include
|
||||
LOCAL_SRC_FILES := \
|
||||
trusty_keymaster_device.cpp \
|
||||
trusty_keymaster_ipc.c \
|
||||
trusty_keymaster_main.cpp
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libcrypto \
|
||||
libcutils \
|
||||
libkeymaster1 \
|
||||
libtrusty \
|
||||
libkeymaster_messages \
|
||||
liblog
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
###
|
||||
# keystore.trusty is the HAL used by keystore on Trusty devices.
|
||||
##
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := keystore.trusty
|
||||
LOCAL_MODULE_RELATIVE_PATH := hw
|
||||
LOCAL_SRC_FILES := module.cpp \
|
||||
trusty_keymaster_ipc.c \
|
||||
trusty_keymaster_device.cpp
|
||||
LOCAL_C_INCLUDES := system/keymaster
|
||||
LOCAL_CLFAGS = -fvisibility=hidden -Wall -Werror
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libcrypto \
|
||||
libkeymaster_messages \
|
||||
libtrusty \
|
||||
liblog \
|
||||
libcutils
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
|
||||
|
||||
# Symlink keymaster.trusty.so -> keymaster.<device>.so so libhardware can find it.
|
||||
LOCAL_POST_INSTALL_CMD = \
|
||||
$(hide) ln -sf $(notdir $(LOCAL_INSTALLED_MODULE)) $(dir $(LOCAL_INSTALLED_MODULE))keystore.$(TARGET_DEVICE).so
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
|
@ -0,0 +1,199 @@
|
|||
#####
|
||||
# Local unit test Makefile
|
||||
#
|
||||
# This makefile builds and runs the trusty_keymaster unit tests locally on the development
|
||||
# machine, not on an Android device.
|
||||
#
|
||||
# To build and run these tests, one pre-requisite must be manually installed: BoringSSL.
|
||||
# This Makefile expects to find BoringSSL in a directory adjacent to $ANDROID_BUILD_TOP.
|
||||
# To get and build it, first install the Ninja build tool (e.g. apt-get install
|
||||
# ninja-build), then do:
|
||||
#
|
||||
# cd $ANDROID_BUILD_TOP/..
|
||||
# git clone https://boringssl.googlesource.com/boringssl
|
||||
# cd boringssl
|
||||
# mdkir build
|
||||
# cd build
|
||||
# cmake -GNinja ..
|
||||
# ninja
|
||||
#
|
||||
# Then return to $ANDROID_BUILD_TOP/system/keymaster and run "make".
|
||||
#####
|
||||
|
||||
BASE=../../../..
|
||||
SUBS=system/core \
|
||||
system/keymaster \
|
||||
hardware/libhardware \
|
||||
external/gtest
|
||||
GTEST=$(BASE)/external/gtest
|
||||
KM=$(BASE)/system/keymaster
|
||||
|
||||
INCLUDES=$(foreach dir,$(SUBS),-I $(BASE)/$(dir)/include) \
|
||||
-I $(BASE)/libnativehelper/include/nativehelper \
|
||||
-I ../tipc/include \
|
||||
-I $(BASE)/system/keymaster \
|
||||
-I $(GTEST) \
|
||||
-I$(BASE)/../boringssl/include
|
||||
|
||||
ifdef USE_CLANG
|
||||
CC=/usr/bin/clang
|
||||
CXX=/usr/bin/clang
|
||||
CLANG_TEST_DEFINE=-DKEYMASTER_CLANG_TEST_BUILD
|
||||
COMPILER_SPECIFIC_ARGS=-std=c++11 $(CLANG_TEST_DEFINE)
|
||||
else
|
||||
COMPILER_SPECIFIC_ARGS=-std=c++0x -fprofile-arcs
|
||||
endif
|
||||
|
||||
CPPFLAGS=$(INCLUDES) -g -O0 -MD
|
||||
CXXFLAGS=-Wall -Werror -Wno-unused -Winit-self -Wpointer-arith -Wunused-parameter \
|
||||
-Wmissing-declarations -ftest-coverage \
|
||||
-Wno-deprecated-declarations -fno-exceptions -DKEYMASTER_NAME_TAGS \
|
||||
$(COMPILER_SPECIFIC_ARGS)
|
||||
LDLIBS=-L$(BASE)/../boringssl/build/crypto -lcrypto -lpthread -lstdc++
|
||||
|
||||
CPPSRCS=\
|
||||
$(KM)/aead_mode_operation.cpp \
|
||||
$(KM)/aes_key.cpp \
|
||||
$(KM)/aes_operation.cpp \
|
||||
$(KM)/android_keymaster.cpp \
|
||||
$(KM)/android_keymaster_messages.cpp \
|
||||
$(KM)/android_keymaster_messages_test.cpp \
|
||||
$(KM)/android_keymaster_test.cpp \
|
||||
$(KM)/android_keymaster_test_utils.cpp \
|
||||
$(KM)/android_keymaster_utils.cpp \
|
||||
$(KM)/asymmetric_key.cpp \
|
||||
$(KM)/auth_encrypted_key_blob.cpp \
|
||||
$(KM)/auth_encrypted_key_blob.cpp \
|
||||
$(KM)/authorization_set.cpp \
|
||||
$(KM)/authorization_set_test.cpp \
|
||||
$(KM)/ec_key.cpp \
|
||||
$(KM)/ec_keymaster0_key.cpp \
|
||||
$(KM)/ecdsa_operation.cpp \
|
||||
$(KM)/hmac_key.cpp \
|
||||
$(KM)/hmac_operation.cpp \
|
||||
$(KM)/integrity_assured_key_blob.cpp \
|
||||
$(KM)/key.cpp \
|
||||
$(KM)/key_blob_test.cpp \
|
||||
$(KM)/keymaster0_engine.cpp \
|
||||
$(KM)/logger.cpp \
|
||||
$(KM)/ocb_utils.cpp \
|
||||
$(KM)/openssl_err.cpp \
|
||||
$(KM)/openssl_utils.cpp \
|
||||
$(KM)/operation.cpp \
|
||||
$(KM)/operation_table.cpp \
|
||||
$(KM)/rsa_key.cpp \
|
||||
$(KM)/rsa_keymaster0_key.cpp \
|
||||
$(KM)/rsa_operation.cpp \
|
||||
$(KM)/serializable.cpp \
|
||||
$(KM)/soft_keymaster_context.cpp \
|
||||
$(KM)/symmetric_key.cpp \
|
||||
$(KM)/unencrypted_key_blob.cpp \
|
||||
trusty_keymaster_device.cpp \
|
||||
trusty_keymaster_device_test.cpp
|
||||
CCSRCS=$(GTEST)/src/gtest-all.cc
|
||||
CSRCS=ocb.c
|
||||
|
||||
OBJS=$(CPPSRCS:.cpp=.o) $(CCSRCS:.cc=.o) $(CSRCS:.c=.o)
|
||||
DEPS=$(CPPSRCS:.cpp=.d) $(CCSRCS:.cc=.d) $(CSRCS:.c=.d)
|
||||
GCDA=$(CPPSRCS:.cpp=.gcda) $(CCSRCS:.cc=.gcda) $(CSRCS:.c=.gcda)
|
||||
GCNO=$(CPPSRCS:.cpp=.gcno) $(CCSRCS:.cc=.gcno) $(CSRCS:.c=.gcno)
|
||||
|
||||
LINK.o=$(LINK.cc)
|
||||
|
||||
BINARIES=trusty_keymaster_device_test
|
||||
|
||||
ifdef TRUSTY
|
||||
BINARIES += trusty_keymaster_device_test
|
||||
endif # TRUSTY
|
||||
|
||||
.PHONY: coverage memcheck massif clean run
|
||||
|
||||
%.run: %
|
||||
./$<
|
||||
touch $@
|
||||
|
||||
run: $(BINARIES:=.run)
|
||||
|
||||
coverage: coverage.info
|
||||
genhtml coverage.info --output-directory coverage
|
||||
|
||||
coverage.info: run
|
||||
lcov --capture --directory=. --output-file coverage.info
|
||||
|
||||
%.coverage : %
|
||||
$(MAKE) clean && $(MAKE) $<
|
||||
./$<
|
||||
lcov --capture --directory=. --output-file coverage.info
|
||||
genhtml coverage.info --output-directory coverage
|
||||
|
||||
#UNINIT_OPTS=--track-origins=yes
|
||||
UNINIT_OPTS=--undef-value-errors=no
|
||||
|
||||
MEMCHECK_OPTS=--leak-check=full \
|
||||
--show-reachable=yes \
|
||||
--vgdb=full \
|
||||
$(UNINIT_OPTS) \
|
||||
--error-exitcode=1
|
||||
|
||||
MASSIF_OPTS=--tool=massif \
|
||||
--stacks=yes
|
||||
|
||||
%.memcheck : %
|
||||
valgrind $(MEMCHECK_OPTS) ./$< && \
|
||||
touch $@
|
||||
|
||||
%.massif : %
|
||||
valgrind $(MASSIF_OPTS) --massif-out-file=$@ ./$<
|
||||
|
||||
memcheck: $(BINARIES:=.memcheck)
|
||||
|
||||
massif: $(BINARIES:=.massif)
|
||||
|
||||
trusty_keymaster_device_test: trusty_keymaster_device_test.o \
|
||||
trusty_keymaster_device.o \
|
||||
$(KM)/aead_mode_operation.o \
|
||||
$(KM)/aes_key.o \
|
||||
$(KM)/aes_operation.o \
|
||||
$(KM)/android_keymaster.o \
|
||||
$(KM)/android_keymaster_messages.o \
|
||||
$(KM)/android_keymaster_test_utils.o \
|
||||
$(KM)/android_keymaster_utils.o \
|
||||
$(KM)/asymmetric_key.o \
|
||||
$(KM)/auth_encrypted_key_blob.o \
|
||||
$(KM)/auth_encrypted_key_blob.o \
|
||||
$(KM)/authorization_set.o \
|
||||
$(KM)/ec_key.o \
|
||||
$(KM)/ec_keymaster0_key.cpp \
|
||||
$(KM)/ecdsa_operation.o \
|
||||
$(KM)/hmac_key.o \
|
||||
$(KM)/hmac_operation.o \
|
||||
$(KM)/integrity_assured_key_blob.o \
|
||||
$(KM)/key.o \
|
||||
$(KM)/keymaster0_engine.o \
|
||||
$(KM)/logger.o \
|
||||
$(KM)/ocb.o \
|
||||
$(KM)/ocb_utils.o \
|
||||
$(KM)/openssl_err.o \
|
||||
$(KM)/openssl_utils.o \
|
||||
$(KM)/operation.o \
|
||||
$(KM)/operation_table.o \
|
||||
$(KM)/rsa_key.o \
|
||||
$(KM)/rsa_keymaster0_key.o \
|
||||
$(KM)/rsa_operation.o \
|
||||
$(KM)/serializable.o \
|
||||
$(KM)/soft_keymaster_context.o \
|
||||
$(KM)/symmetric_key.o \
|
||||
$(GTEST)/src/gtest-all.o
|
||||
|
||||
$(GTEST)/src/gtest-all.o: CXXFLAGS:=$(subst -Wmissing-declarations,,$(CXXFLAGS))
|
||||
ocb.o: CFLAGS=$(CLANG_TEST_DEFINE)
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) $(DEPS) $(GCDA) $(GCNO) $(BINARIES) \
|
||||
$(BINARIES:=.run) $(BINARIES:=.memcheck) $(BINARIES:=.massif) \
|
||||
coverage.info
|
||||
rm -rf coverage
|
||||
|
||||
-include $(CPPSRCS:.cpp=.d)
|
||||
-include $(CCSRCS:.cc=.d)
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define KEYMASTER_PORT "com.android.trusty.keymaster"
|
||||
#define KEYMASTER_MAX_BUFFER_LENGTH 4096
|
||||
|
||||
// Commands
|
||||
enum keymaster_command {
|
||||
KEYMASTER_RESP_BIT = 1,
|
||||
KEYMASTER_REQ_SHIFT = 1,
|
||||
|
||||
KM_GENERATE_KEY = (0 << KEYMASTER_REQ_SHIFT),
|
||||
KM_BEGIN_OPERATION = (1 << KEYMASTER_REQ_SHIFT),
|
||||
KM_UPDATE_OPERATION = (2 << KEYMASTER_REQ_SHIFT),
|
||||
KM_FINISH_OPERATION = (3 << KEYMASTER_REQ_SHIFT),
|
||||
KM_ABORT_OPERATION = (4 << KEYMASTER_REQ_SHIFT),
|
||||
KM_IMPORT_KEY = (5 << KEYMASTER_REQ_SHIFT),
|
||||
KM_EXPORT_KEY = (6 << KEYMASTER_REQ_SHIFT),
|
||||
KM_GET_VERSION = (7 << KEYMASTER_REQ_SHIFT),
|
||||
KM_ADD_RNG_ENTROPY = (8 << KEYMASTER_REQ_SHIFT),
|
||||
KM_GET_SUPPORTED_ALGORITHMS = (9 << KEYMASTER_REQ_SHIFT),
|
||||
KM_GET_SUPPORTED_BLOCK_MODES = (10 << KEYMASTER_REQ_SHIFT),
|
||||
KM_GET_SUPPORTED_PADDING_MODES = (11 << KEYMASTER_REQ_SHIFT),
|
||||
KM_GET_SUPPORTED_DIGESTS = (12 << KEYMASTER_REQ_SHIFT),
|
||||
KM_GET_SUPPORTED_IMPORT_FORMATS = (13 << KEYMASTER_REQ_SHIFT),
|
||||
KM_GET_SUPPORTED_EXPORT_FORMATS = (14 << KEYMASTER_REQ_SHIFT),
|
||||
KM_GET_KEY_CHARACTERISTICS = (15 << KEYMASTER_REQ_SHIFT),
|
||||
};
|
||||
|
||||
#ifdef __ANDROID__
|
||||
|
||||
/**
|
||||
* keymaster_message - Serial header for communicating with KM server
|
||||
* @cmd: the command, one of keymaster_command.
|
||||
* @payload: start of the serialized command specific payload
|
||||
*/
|
||||
struct keymaster_message {
|
||||
uint32_t cmd;
|
||||
uint8_t payload[0];
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* 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 <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <hardware/hardware.h>
|
||||
#include <hardware/keymaster0.h>
|
||||
|
||||
#include "trusty_keymaster_device.h"
|
||||
|
||||
using keymaster::TrustyKeymasterDevice;
|
||||
|
||||
/*
|
||||
* Generic device handling
|
||||
*/
|
||||
static int trusty_keymaster_open(const hw_module_t* module, const char* name,
|
||||
hw_device_t** device) {
|
||||
if (strcmp(name, KEYSTORE_KEYMASTER) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
TrustyKeymasterDevice* dev = new TrustyKeymasterDevice(module);
|
||||
if (dev == NULL)
|
||||
return -ENOMEM;
|
||||
*device = dev->hw_device();
|
||||
// Do not delete dev; it will get cleaned up when the caller calls device->close(), and must
|
||||
// exist until then.
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hw_module_methods_t keystore_module_methods = {
|
||||
.open = trusty_keymaster_open,
|
||||
};
|
||||
|
||||
struct keystore_module HAL_MODULE_INFO_SYM __attribute__((visibility("default"))) = {
|
||||
.common =
|
||||
{
|
||||
.tag = HARDWARE_MODULE_TAG,
|
||||
.module_api_version = KEYMASTER_MODULE_API_VERSION_0_3,
|
||||
.hal_api_version = HARDWARE_HAL_API_VERSION,
|
||||
.id = KEYSTORE_HARDWARE_MODULE_ID,
|
||||
.name = "Trusty Keymaster HAL",
|
||||
.author = "The Android Open Source Project",
|
||||
.methods = &keystore_module_methods,
|
||||
.dso = 0,
|
||||
.reserved = {},
|
||||
},
|
||||
};
|
|
@ -0,0 +1,536 @@
|
|||
/*
|
||||
* Copyright 2014 The Android Open Source Project
|
||||
*
|
||||
* 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 "trusty_keymaster_device.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#define LOG_TAG "TrustyKeymaster"
|
||||
#include <cutils/log.h>
|
||||
#include <hardware/keymaster0.h>
|
||||
|
||||
#include <keymaster/authorization_set.h>
|
||||
|
||||
#include "trusty_keymaster_ipc.h"
|
||||
#include "keymaster_ipc.h"
|
||||
|
||||
const uint32_t SEND_BUF_SIZE = 8192;
|
||||
const uint32_t RECV_BUF_SIZE = 8192;
|
||||
|
||||
namespace keymaster {
|
||||
|
||||
static keymaster_error_t translate_error(int err) {
|
||||
switch (err) {
|
||||
case 0:
|
||||
return KM_ERROR_OK;
|
||||
case -EPERM:
|
||||
case -EACCES:
|
||||
return KM_ERROR_SECURE_HW_ACCESS_DENIED;
|
||||
|
||||
case -ECANCELED:
|
||||
return KM_ERROR_OPERATION_CANCELLED;
|
||||
|
||||
case -ENODEV:
|
||||
return KM_ERROR_UNIMPLEMENTED;
|
||||
|
||||
case -ENOMEM:
|
||||
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
|
||||
|
||||
case -EBUSY:
|
||||
return KM_ERROR_SECURE_HW_BUSY;
|
||||
|
||||
case -EIO:
|
||||
return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
|
||||
|
||||
case -EOVERFLOW:
|
||||
return KM_ERROR_INVALID_INPUT_LENGTH;
|
||||
|
||||
default:
|
||||
return KM_ERROR_UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
TrustyKeymasterDevice::TrustyKeymasterDevice(const hw_module_t* module) {
|
||||
static_assert(std::is_standard_layout<TrustyKeymasterDevice>::value,
|
||||
"TrustyKeymasterDevice must be standard layout");
|
||||
static_assert(offsetof(TrustyKeymasterDevice, device_) == 0,
|
||||
"device_ must be the first member of KeymasterOpenSsl");
|
||||
static_assert(offsetof(TrustyKeymasterDevice, device_.common) == 0,
|
||||
"common must be the first member of keymaster_device");
|
||||
|
||||
ALOGI("Creating device");
|
||||
ALOGD("Device address: %p", this);
|
||||
|
||||
memset(&device_, 0, sizeof(device_));
|
||||
|
||||
device_.common.tag = HARDWARE_DEVICE_TAG;
|
||||
device_.common.version = 1;
|
||||
device_.common.module = const_cast<hw_module_t*>(module);
|
||||
device_.common.close = close_device;
|
||||
|
||||
device_.flags = KEYMASTER_BLOBS_ARE_STANDALONE | KEYMASTER_SUPPORTS_EC;
|
||||
|
||||
device_.generate_keypair = generate_keypair;
|
||||
device_.import_keypair = import_keypair;
|
||||
device_.get_keypair_public = get_keypair_public;
|
||||
device_.delete_keypair = NULL;
|
||||
device_.delete_all = NULL;
|
||||
device_.sign_data = sign_data;
|
||||
device_.verify_data = verify_data;
|
||||
|
||||
device_.context = NULL;
|
||||
|
||||
int rc = trusty_keymaster_connect();
|
||||
error_ = translate_error(rc);
|
||||
if (rc < 0) {
|
||||
ALOGE("failed to connect to keymaster (%d)", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
GetVersionRequest version_request;
|
||||
GetVersionResponse version_response;
|
||||
error_ = Send(version_request, &version_response);
|
||||
if (error_ == KM_ERROR_INVALID_ARGUMENT || error_ == KM_ERROR_UNIMPLEMENTED) {
|
||||
ALOGI("\"Bad parameters\" error on GetVersion call. Assuming version 0.");
|
||||
message_version_ = 0;
|
||||
error_ = KM_ERROR_OK;
|
||||
}
|
||||
message_version_ = MessageVersion(version_response.major_ver, version_response.minor_ver,
|
||||
version_response.subminor_ver);
|
||||
if (message_version_ < 0) {
|
||||
// Can't translate version? Keymaster implementation must be newer.
|
||||
ALOGE("Keymaster version %d.%d.%d not supported.", version_response.major_ver,
|
||||
version_response.minor_ver, version_response.subminor_ver);
|
||||
error_ = KM_ERROR_VERSION_MISMATCH;
|
||||
}
|
||||
}
|
||||
|
||||
TrustyKeymasterDevice::~TrustyKeymasterDevice() {
|
||||
trusty_keymaster_disconnect();
|
||||
}
|
||||
|
||||
const uint64_t HUNDRED_YEARS = 1000LL * 60 * 60 * 24 * 365 * 100;
|
||||
|
||||
int TrustyKeymasterDevice::generate_keypair(const keymaster_keypair_t key_type,
|
||||
const void* key_params, uint8_t** key_blob,
|
||||
size_t* key_blob_length) {
|
||||
ALOGD("Device received generate_keypair");
|
||||
|
||||
if (error_ != KM_ERROR_OK)
|
||||
return error_;
|
||||
|
||||
GenerateKeyRequest req(message_version_);
|
||||
StoreNewKeyParams(&req.key_description);
|
||||
|
||||
switch (key_type) {
|
||||
case TYPE_RSA: {
|
||||
req.key_description.push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
|
||||
const keymaster_rsa_keygen_params_t* rsa_params =
|
||||
static_cast<const keymaster_rsa_keygen_params_t*>(key_params);
|
||||
ALOGD("Generating RSA pair, modulus size: %u, public exponent: %lu",
|
||||
rsa_params->modulus_size, rsa_params->public_exponent);
|
||||
req.key_description.push_back(TAG_KEY_SIZE, rsa_params->modulus_size);
|
||||
req.key_description.push_back(TAG_RSA_PUBLIC_EXPONENT, rsa_params->public_exponent);
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_EC: {
|
||||
req.key_description.push_back(TAG_ALGORITHM, KM_ALGORITHM_EC);
|
||||
const keymaster_ec_keygen_params_t* ec_params =
|
||||
static_cast<const keymaster_ec_keygen_params_t*>(key_params);
|
||||
ALOGD("Generating ECDSA pair, key size: %u", ec_params->field_size);
|
||||
req.key_description.push_back(TAG_KEY_SIZE, ec_params->field_size);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ALOGD("Received request for unsuported key type %d", key_type);
|
||||
return KM_ERROR_UNSUPPORTED_ALGORITHM;
|
||||
}
|
||||
|
||||
GenerateKeyResponse rsp(message_version_);
|
||||
ALOGD("Sending generate request");
|
||||
keymaster_error_t err = Send(req, &rsp);
|
||||
if (err != KM_ERROR_OK) {
|
||||
ALOGE("Got error %d from send", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
*key_blob_length = rsp.key_blob.key_material_size;
|
||||
*key_blob = static_cast<uint8_t*>(malloc(*key_blob_length));
|
||||
memcpy(*key_blob, rsp.key_blob.key_material, *key_blob_length);
|
||||
ALOGD("Returning %d bytes in key blob\n", (int)*key_blob_length);
|
||||
|
||||
return KM_ERROR_OK;
|
||||
}
|
||||
|
||||
struct EVP_PKEY_Delete {
|
||||
void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); }
|
||||
};
|
||||
|
||||
struct PKCS8_PRIV_KEY_INFO_Delete {
|
||||
void operator()(PKCS8_PRIV_KEY_INFO* p) const { PKCS8_PRIV_KEY_INFO_free(p); }
|
||||
};
|
||||
|
||||
int TrustyKeymasterDevice::import_keypair(const uint8_t* key, const size_t key_length,
|
||||
uint8_t** key_blob, size_t* key_blob_length) {
|
||||
ALOGD("Device received import_keypair");
|
||||
if (error_ != KM_ERROR_OK)
|
||||
return error_;
|
||||
|
||||
if (!key)
|
||||
return KM_ERROR_UNEXPECTED_NULL_POINTER;
|
||||
|
||||
if (!key_blob || !key_blob_length)
|
||||
return KM_ERROR_OUTPUT_PARAMETER_NULL;
|
||||
|
||||
ImportKeyRequest request(message_version_);
|
||||
StoreNewKeyParams(&request.key_description);
|
||||
keymaster_algorithm_t algorithm;
|
||||
keymaster_error_t err = GetPkcs8KeyAlgorithm(key, key_length, &algorithm);
|
||||
if (err != KM_ERROR_OK)
|
||||
return err;
|
||||
request.key_description.push_back(TAG_ALGORITHM, algorithm);
|
||||
|
||||
request.SetKeyMaterial(key, key_length);
|
||||
request.key_format = KM_KEY_FORMAT_PKCS8;
|
||||
ImportKeyResponse response(message_version_);
|
||||
err = Send(request, &response);
|
||||
if (err != KM_ERROR_OK)
|
||||
return err;
|
||||
|
||||
*key_blob_length = response.key_blob.key_material_size;
|
||||
*key_blob = static_cast<uint8_t*>(malloc(*key_blob_length));
|
||||
memcpy(*key_blob, response.key_blob.key_material, *key_blob_length);
|
||||
printf("Returning %d bytes in key blob\n", (int)*key_blob_length);
|
||||
|
||||
return KM_ERROR_OK;
|
||||
}
|
||||
|
||||
keymaster_error_t TrustyKeymasterDevice::GetPkcs8KeyAlgorithm(const uint8_t* key, size_t key_length,
|
||||
keymaster_algorithm_t* algorithm) {
|
||||
if (key == NULL) {
|
||||
ALOGE("No key specified for import");
|
||||
return KM_ERROR_UNEXPECTED_NULL_POINTER;
|
||||
}
|
||||
|
||||
UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> pkcs8(
|
||||
d2i_PKCS8_PRIV_KEY_INFO(NULL, &key, key_length));
|
||||
if (pkcs8.get() == NULL) {
|
||||
ALOGE("Could not parse PKCS8 key blob");
|
||||
return KM_ERROR_INVALID_KEY_BLOB;
|
||||
}
|
||||
|
||||
UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKCS82PKEY(pkcs8.get()));
|
||||
if (pkey.get() == NULL) {
|
||||
ALOGE("Could not extract key from PKCS8 key blob");
|
||||
return KM_ERROR_INVALID_KEY_BLOB;
|
||||
}
|
||||
|
||||
switch (EVP_PKEY_type(pkey->type)) {
|
||||
case EVP_PKEY_RSA:
|
||||
*algorithm = KM_ALGORITHM_RSA;
|
||||
break;
|
||||
case EVP_PKEY_EC:
|
||||
*algorithm = KM_ALGORITHM_EC;
|
||||
break;
|
||||
default:
|
||||
ALOGE("Unsupported algorithm %d", EVP_PKEY_type(pkey->type));
|
||||
return KM_ERROR_UNSUPPORTED_ALGORITHM;
|
||||
}
|
||||
|
||||
return KM_ERROR_OK;
|
||||
}
|
||||
|
||||
int TrustyKeymasterDevice::get_keypair_public(const uint8_t* key_blob, const size_t key_blob_length,
|
||||
uint8_t** x509_data, size_t* x509_data_length) {
|
||||
ALOGD("Device received get_keypair_public");
|
||||
if (error_ != KM_ERROR_OK)
|
||||
return error_;
|
||||
|
||||
ExportKeyRequest request(message_version_);
|
||||
request.SetKeyMaterial(key_blob, key_blob_length);
|
||||
request.key_format = KM_KEY_FORMAT_X509;
|
||||
ExportKeyResponse response(message_version_);
|
||||
keymaster_error_t err = Send(request, &response);
|
||||
if (err != KM_ERROR_OK)
|
||||
return err;
|
||||
|
||||
*x509_data_length = response.key_data_length;
|
||||
*x509_data = static_cast<uint8_t*>(malloc(*x509_data_length));
|
||||
memcpy(*x509_data, response.key_data, *x509_data_length);
|
||||
printf("Returning %d bytes in x509 key\n", (int)*x509_data_length);
|
||||
|
||||
return KM_ERROR_OK;
|
||||
}
|
||||
|
||||
int TrustyKeymasterDevice::sign_data(const void* signing_params, const uint8_t* key_blob,
|
||||
const size_t key_blob_length, const uint8_t* data,
|
||||
const size_t data_length, uint8_t** signed_data,
|
||||
size_t* signed_data_length) {
|
||||
ALOGD("Device received sign_data, %d", error_);
|
||||
if (error_ != KM_ERROR_OK)
|
||||
return error_;
|
||||
|
||||
BeginOperationRequest begin_request(message_version_);
|
||||
begin_request.purpose = KM_PURPOSE_SIGN;
|
||||
begin_request.SetKeyMaterial(key_blob, key_blob_length);
|
||||
keymaster_error_t err = StoreSigningParams(signing_params, key_blob, key_blob_length,
|
||||
&begin_request.additional_params);
|
||||
if (err != KM_ERROR_OK) {
|
||||
ALOGE("Error extracting signing params: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
BeginOperationResponse begin_response(message_version_);
|
||||
ALOGD("Sending signing request begin");
|
||||
err = Send(begin_request, &begin_response);
|
||||
if (err != KM_ERROR_OK) {
|
||||
ALOGE("Error sending sign begin: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
UpdateOperationRequest update_request(message_version_);
|
||||
update_request.op_handle = begin_response.op_handle;
|
||||
update_request.input.Reinitialize(data, data_length);
|
||||
UpdateOperationResponse update_response(message_version_);
|
||||
ALOGD("Sending signing request update");
|
||||
err = Send(update_request, &update_response);
|
||||
if (err != KM_ERROR_OK) {
|
||||
ALOGE("Error sending sign update: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
FinishOperationRequest finish_request(message_version_);
|
||||
finish_request.op_handle = begin_response.op_handle;
|
||||
FinishOperationResponse finish_response(message_version_);
|
||||
ALOGD("Sending signing request finish");
|
||||
err = Send(finish_request, &finish_response);
|
||||
if (err != KM_ERROR_OK) {
|
||||
ALOGE("Error sending sign finish: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
*signed_data_length = finish_response.output.available_read();
|
||||
*signed_data = static_cast<uint8_t*>(malloc(*signed_data_length));
|
||||
if (!finish_response.output.read(*signed_data, *signed_data_length)) {
|
||||
ALOGE("Error reading response data: %d", err);
|
||||
return KM_ERROR_UNKNOWN_ERROR;
|
||||
}
|
||||
return KM_ERROR_OK;
|
||||
}
|
||||
|
||||
int TrustyKeymasterDevice::verify_data(const void* signing_params, const uint8_t* key_blob,
|
||||
const size_t key_blob_length, const uint8_t* signed_data,
|
||||
const size_t signed_data_length, const uint8_t* signature,
|
||||
const size_t signature_length) {
|
||||
ALOGD("Device received verify_data");
|
||||
if (error_ != KM_ERROR_OK)
|
||||
return error_;
|
||||
|
||||
BeginOperationRequest begin_request(message_version_);
|
||||
begin_request.purpose = KM_PURPOSE_VERIFY;
|
||||
begin_request.SetKeyMaterial(key_blob, key_blob_length);
|
||||
keymaster_error_t err = StoreSigningParams(signing_params, key_blob, key_blob_length,
|
||||
&begin_request.additional_params);
|
||||
if (err != KM_ERROR_OK)
|
||||
return err;
|
||||
|
||||
BeginOperationResponse begin_response(message_version_);
|
||||
err = Send(begin_request, &begin_response);
|
||||
if (err != KM_ERROR_OK)
|
||||
return err;
|
||||
|
||||
UpdateOperationRequest update_request(message_version_);
|
||||
update_request.op_handle = begin_response.op_handle;
|
||||
update_request.input.Reinitialize(signed_data, signed_data_length);
|
||||
UpdateOperationResponse update_response(message_version_);
|
||||
err = Send(update_request, &update_response);
|
||||
if (err != KM_ERROR_OK)
|
||||
return err;
|
||||
|
||||
FinishOperationRequest finish_request(message_version_);
|
||||
finish_request.op_handle = begin_response.op_handle;
|
||||
finish_request.signature.Reinitialize(signature, signature_length);
|
||||
FinishOperationResponse finish_response(message_version_);
|
||||
err = Send(finish_request, &finish_response);
|
||||
if (err != KM_ERROR_OK)
|
||||
return err;
|
||||
return KM_ERROR_OK;
|
||||
}
|
||||
|
||||
hw_device_t* TrustyKeymasterDevice::hw_device() {
|
||||
return &device_.common;
|
||||
}
|
||||
|
||||
static inline TrustyKeymasterDevice* convert_device(const keymaster0_device_t* dev) {
|
||||
return reinterpret_cast<TrustyKeymasterDevice*>(const_cast<keymaster0_device_t*>(dev));
|
||||
}
|
||||
|
||||
/* static */
|
||||
int TrustyKeymasterDevice::close_device(hw_device_t* dev) {
|
||||
delete reinterpret_cast<TrustyKeymasterDevice*>(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* static */
|
||||
int TrustyKeymasterDevice::generate_keypair(const keymaster0_device_t* dev,
|
||||
const keymaster_keypair_t key_type,
|
||||
const void* key_params, uint8_t** keyBlob,
|
||||
size_t* keyBlobLength) {
|
||||
ALOGD("Generate keypair, sending to device: %p", convert_device(dev));
|
||||
return convert_device(dev)->generate_keypair(key_type, key_params, keyBlob, keyBlobLength);
|
||||
}
|
||||
|
||||
/* static */
|
||||
int TrustyKeymasterDevice::import_keypair(const keymaster0_device_t* dev, const uint8_t* key,
|
||||
const size_t key_length, uint8_t** key_blob,
|
||||
size_t* key_blob_length) {
|
||||
return convert_device(dev)->import_keypair(key, key_length, key_blob, key_blob_length);
|
||||
}
|
||||
|
||||
/* static */
|
||||
int TrustyKeymasterDevice::get_keypair_public(const keymaster0_device_t* dev,
|
||||
const uint8_t* key_blob, const size_t key_blob_length,
|
||||
uint8_t** x509_data, size_t* x509_data_length) {
|
||||
return convert_device(dev)
|
||||
->get_keypair_public(key_blob, key_blob_length, x509_data, x509_data_length);
|
||||
}
|
||||
|
||||
/* static */
|
||||
int TrustyKeymasterDevice::sign_data(const keymaster0_device_t* dev, const void* params,
|
||||
const uint8_t* keyBlob, const size_t keyBlobLength,
|
||||
const uint8_t* data, const size_t dataLength,
|
||||
uint8_t** signedData, size_t* signedDataLength) {
|
||||
return convert_device(dev)
|
||||
->sign_data(params, keyBlob, keyBlobLength, data, dataLength, signedData, signedDataLength);
|
||||
}
|
||||
|
||||
/* static */
|
||||
int TrustyKeymasterDevice::verify_data(const keymaster0_device_t* dev, const void* params,
|
||||
const uint8_t* keyBlob, const size_t keyBlobLength,
|
||||
const uint8_t* signedData, const size_t signedDataLength,
|
||||
const uint8_t* signature, const size_t signatureLength) {
|
||||
return convert_device(dev)->verify_data(params, keyBlob, keyBlobLength, signedData,
|
||||
signedDataLength, signature, signatureLength);
|
||||
}
|
||||
|
||||
keymaster_error_t TrustyKeymasterDevice::Send(uint32_t command, const Serializable& req,
|
||||
KeymasterResponse* rsp) {
|
||||
uint32_t req_size = req.SerializedSize();
|
||||
if (req_size > SEND_BUF_SIZE)
|
||||
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
|
||||
uint8_t send_buf[SEND_BUF_SIZE];
|
||||
Eraser send_buf_eraser(send_buf, SEND_BUF_SIZE);
|
||||
req.Serialize(send_buf, send_buf + req_size);
|
||||
|
||||
// Send it
|
||||
uint8_t recv_buf[RECV_BUF_SIZE];
|
||||
Eraser recv_buf_eraser(recv_buf, RECV_BUF_SIZE);
|
||||
uint32_t rsp_size = RECV_BUF_SIZE;
|
||||
printf("Sending %d byte request\n", (int)req.SerializedSize());
|
||||
int rc = trusty_keymaster_call(command, send_buf, req_size, recv_buf, &rsp_size);
|
||||
if (rc < 0) {
|
||||
ALOGE("tipc error: %d\n", rc);
|
||||
// TODO(swillden): Distinguish permanent from transient errors and set error_ appropriately.
|
||||
return translate_error(rc);
|
||||
} else {
|
||||
ALOGV("Received %d byte response\n", rsp_size);
|
||||
}
|
||||
|
||||
const keymaster_message* msg = (keymaster_message *) recv_buf;
|
||||
const uint8_t *p = msg->payload;
|
||||
if (!rsp->Deserialize(&p, p + rsp_size)) {
|
||||
ALOGE("Error deserializing response of size %d\n", (int)rsp_size);
|
||||
return KM_ERROR_UNKNOWN_ERROR;
|
||||
} else if (rsp->error != KM_ERROR_OK) {
|
||||
ALOGE("Response of size %d contained error code %d\n", (int)rsp_size, (int)rsp->error);
|
||||
return rsp->error;
|
||||
}
|
||||
return rsp->error;
|
||||
}
|
||||
|
||||
keymaster_error_t TrustyKeymasterDevice::StoreSigningParams(const void* signing_params,
|
||||
const uint8_t* key_blob,
|
||||
size_t key_blob_length,
|
||||
AuthorizationSet* auth_set) {
|
||||
uint8_t* pub_key_data;
|
||||
size_t pub_key_data_length;
|
||||
int err = get_keypair_public(&device_, key_blob, key_blob_length, &pub_key_data,
|
||||
&pub_key_data_length);
|
||||
if (err < 0) {
|
||||
ALOGE("Error %d extracting public key to determine algorithm", err);
|
||||
return KM_ERROR_INVALID_KEY_BLOB;
|
||||
}
|
||||
UniquePtr<uint8_t, Malloc_Delete> pub_key(pub_key_data);
|
||||
|
||||
const uint8_t* p = pub_key_data;
|
||||
UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(
|
||||
d2i_PUBKEY(nullptr /* allocate new struct */, &p, pub_key_data_length));
|
||||
|
||||
switch (EVP_PKEY_type(pkey->type)) {
|
||||
case EVP_PKEY_RSA: {
|
||||
const keymaster_rsa_sign_params_t* rsa_params =
|
||||
reinterpret_cast<const keymaster_rsa_sign_params_t*>(signing_params);
|
||||
if (rsa_params->digest_type != DIGEST_NONE)
|
||||
return KM_ERROR_UNSUPPORTED_DIGEST;
|
||||
if (rsa_params->padding_type != PADDING_NONE)
|
||||
return KM_ERROR_UNSUPPORTED_PADDING_MODE;
|
||||
if (!auth_set->push_back(TAG_DIGEST, KM_DIGEST_NONE) ||
|
||||
!auth_set->push_back(TAG_PADDING, KM_PAD_NONE))
|
||||
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
|
||||
} break;
|
||||
case EVP_PKEY_EC: {
|
||||
const keymaster_ec_sign_params_t* ecdsa_params =
|
||||
reinterpret_cast<const keymaster_ec_sign_params_t*>(signing_params);
|
||||
if (ecdsa_params->digest_type != DIGEST_NONE)
|
||||
return KM_ERROR_UNSUPPORTED_DIGEST;
|
||||
if (!auth_set->push_back(TAG_DIGEST, KM_DIGEST_NONE))
|
||||
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
|
||||
} break;
|
||||
default:
|
||||
return KM_ERROR_UNSUPPORTED_ALGORITHM;
|
||||
}
|
||||
return KM_ERROR_OK;
|
||||
}
|
||||
|
||||
void TrustyKeymasterDevice::StoreNewKeyParams(AuthorizationSet* auth_set) {
|
||||
auth_set->push_back(TAG_PURPOSE, KM_PURPOSE_SIGN);
|
||||
auth_set->push_back(TAG_PURPOSE, KM_PURPOSE_VERIFY);
|
||||
auth_set->push_back(TAG_ALL_USERS);
|
||||
auth_set->push_back(TAG_NO_AUTH_REQUIRED);
|
||||
uint64_t now = java_time(time(NULL));
|
||||
auth_set->push_back(TAG_CREATION_DATETIME, now);
|
||||
auth_set->push_back(TAG_ORIGINATION_EXPIRE_DATETIME, now + HUNDRED_YEARS);
|
||||
if (message_version_ == 0) {
|
||||
auth_set->push_back(TAG_DIGEST_OLD, KM_DIGEST_NONE);
|
||||
auth_set->push_back(TAG_PADDING_OLD, KM_PAD_NONE);
|
||||
} else {
|
||||
auth_set->push_back(TAG_DIGEST, KM_DIGEST_NONE);
|
||||
auth_set->push_back(TAG_PADDING, KM_PAD_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace keymaster
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright 2014 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef EXTERNAL_KEYMASTER_TRUSTY_KEYMASTER_DEVICE_H_
|
||||
#define EXTERNAL_KEYMASTER_TRUSTY_KEYMASTER_DEVICE_H_
|
||||
|
||||
#include <hardware/keymaster0.h>
|
||||
|
||||
#include <keymaster/android_keymaster_messages.h>
|
||||
|
||||
#include "keymaster_ipc.h"
|
||||
|
||||
namespace keymaster {
|
||||
|
||||
/**
|
||||
* Software OpenSSL-based Keymaster device.
|
||||
*
|
||||
* IMPORTANT MAINTAINER NOTE: Pointers to instances of this class must be castable to hw_device_t
|
||||
* and keymaster_device. This means it must remain a standard layout class (no virtual functions and
|
||||
* no data members which aren't standard layout), and device_ must be the first data member.
|
||||
* Assertions in the constructor validate compliance with those constraints.
|
||||
*/
|
||||
class TrustyKeymasterDevice {
|
||||
public:
|
||||
/*
|
||||
* These are the only symbols that will be exported by libtrustykeymaster. All functionality
|
||||
* can be reached via the function pointers in device_.
|
||||
*/
|
||||
__attribute__((visibility("default"))) TrustyKeymasterDevice(const hw_module_t* module);
|
||||
__attribute__((visibility("default"))) hw_device_t* hw_device();
|
||||
|
||||
~TrustyKeymasterDevice();
|
||||
|
||||
keymaster_error_t session_error() { return error_; }
|
||||
|
||||
int generate_keypair(const keymaster_keypair_t key_type, const void* key_params,
|
||||
uint8_t** key_blob, size_t* key_blob_length);
|
||||
int import_keypair(const uint8_t* key, const size_t key_length, uint8_t** key_blob,
|
||||
size_t* key_blob_length);
|
||||
int get_keypair_public(const uint8_t* key_blob, const size_t key_blob_length,
|
||||
uint8_t** x509_data, size_t* x509_data_length);
|
||||
int sign_data(const void* signing_params, const uint8_t* key_blob, const size_t key_blob_length,
|
||||
const uint8_t* data, const size_t data_length, uint8_t** signed_data,
|
||||
size_t* signed_data_length);
|
||||
int verify_data(const void* signing_params, const uint8_t* key_blob,
|
||||
const size_t key_blob_length, const uint8_t* signed_data,
|
||||
const size_t signed_data_length, const uint8_t* signature,
|
||||
const size_t signature_length);
|
||||
|
||||
private:
|
||||
keymaster_error_t Send(uint32_t command, const Serializable& request,
|
||||
KeymasterResponse* response);
|
||||
keymaster_error_t Send(const GenerateKeyRequest& request, GenerateKeyResponse* response) {
|
||||
return Send(KM_GENERATE_KEY, request, response);
|
||||
}
|
||||
keymaster_error_t Send(const BeginOperationRequest& request, BeginOperationResponse* response) {
|
||||
return Send(KM_BEGIN_OPERATION, request, response);
|
||||
}
|
||||
keymaster_error_t Send(const UpdateOperationRequest& request,
|
||||
UpdateOperationResponse* response) {
|
||||
return Send(KM_UPDATE_OPERATION, request, response);
|
||||
}
|
||||
keymaster_error_t Send(const FinishOperationRequest& request,
|
||||
FinishOperationResponse* response) {
|
||||
return Send(KM_FINISH_OPERATION, request, response);
|
||||
}
|
||||
keymaster_error_t Send(const ImportKeyRequest& request, ImportKeyResponse* response) {
|
||||
return Send(KM_IMPORT_KEY, request, response);
|
||||
}
|
||||
keymaster_error_t Send(const ExportKeyRequest& request, ExportKeyResponse* response) {
|
||||
return Send(KM_EXPORT_KEY, request, response);
|
||||
}
|
||||
keymaster_error_t Send(const GetVersionRequest& request, GetVersionResponse* response) {
|
||||
return Send(KM_GET_VERSION, request, response);
|
||||
}
|
||||
|
||||
keymaster_error_t StoreSigningParams(const void* signing_params, const uint8_t* key_blob,
|
||||
size_t key_blob_length, AuthorizationSet* auth_set);
|
||||
void StoreNewKeyParams(AuthorizationSet* auth_set);
|
||||
keymaster_error_t GetPkcs8KeyAlgorithm(const uint8_t* key, size_t key_length,
|
||||
keymaster_algorithm_t* algorithm);
|
||||
|
||||
/*
|
||||
* These static methods are the functions referenced through the function pointers in
|
||||
* keymaster_device. They're all trivial wrappers.
|
||||
*/
|
||||
static int close_device(hw_device_t* dev);
|
||||
static int generate_keypair(const keymaster0_device_t* dev, const keymaster_keypair_t key_type,
|
||||
const void* key_params, uint8_t** keyBlob, size_t* keyBlobLength);
|
||||
static int import_keypair(const keymaster0_device_t* dev, const uint8_t* key,
|
||||
const size_t key_length, uint8_t** key_blob, size_t* key_blob_length);
|
||||
static int get_keypair_public(const keymaster0_device_t* dev, const uint8_t* key_blob,
|
||||
const size_t key_blob_length, uint8_t** x509_data,
|
||||
size_t* x509_data_length);
|
||||
static int sign_data(const keymaster0_device_t* dev, const void* signing_params,
|
||||
const uint8_t* key_blob, const size_t key_blob_length, const uint8_t* data,
|
||||
const size_t data_length, uint8_t** signed_data,
|
||||
size_t* signed_data_length);
|
||||
static int verify_data(const keymaster0_device_t* dev, const void* signing_params,
|
||||
const uint8_t* key_blob, const size_t key_blob_length,
|
||||
const uint8_t* signed_data, const size_t signed_data_length,
|
||||
const uint8_t* signature, const size_t signature_length);
|
||||
|
||||
keymaster0_device_t device_;
|
||||
keymaster_error_t error_;
|
||||
int32_t message_version_;
|
||||
};
|
||||
|
||||
} // namespace keymaster
|
||||
|
||||
#endif // EXTERNAL_KEYMASTER_TRUSTY_KEYMASTER_DEVICE_H_
|
|
@ -0,0 +1,562 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* 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 <algorithm>
|
||||
#include <fstream>
|
||||
|
||||
#include <UniquePtr.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <openssl/engine.h>
|
||||
|
||||
#include <hardware/keymaster0.h>
|
||||
|
||||
#include <keymaster/android_keymaster.h>
|
||||
#include <keymaster/android_keymaster_messages.h>
|
||||
#include <keymaster/android_keymaster_utils.h>
|
||||
#include <keymaster/keymaster_tags.h>
|
||||
#include <keymaster/soft_keymaster_context.h>
|
||||
|
||||
#include "android_keymaster_test_utils.h"
|
||||
#include "trusty_keymaster_device.h"
|
||||
#include "openssl_utils.h"
|
||||
|
||||
using std::string;
|
||||
using std::ifstream;
|
||||
using std::istreambuf_iterator;
|
||||
|
||||
static keymaster::AndroidKeymaster *impl_ = nullptr;
|
||||
|
||||
extern "C" {
|
||||
int __android_log_print();
|
||||
}
|
||||
|
||||
int __android_log_print() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
int result = RUN_ALL_TESTS();
|
||||
// Clean up stuff OpenSSL leaves around, so Valgrind doesn't complain.
|
||||
CRYPTO_cleanup_all_ex_data();
|
||||
ERR_free_strings();
|
||||
return result;
|
||||
}
|
||||
|
||||
int trusty_keymaster_connect() {
|
||||
impl_ = new keymaster::AndroidKeymaster(new keymaster::SoftKeymasterContext(nullptr), 16);
|
||||
}
|
||||
|
||||
void trusty_keymaster_disconnect() {
|
||||
delete static_cast<keymaster::AndroidKeymaster*>(priv_);
|
||||
}
|
||||
|
||||
template <typename Req, typename Rsp>
|
||||
static int fake_call(keymaster::AndroidKeymaster* device,
|
||||
void (keymaster::AndroidKeymaster::*method)(const Req&, Rsp*), void* in_buf,
|
||||
uint32_t in_size, void* out_buf, uint32_t* out_size) {
|
||||
Req req;
|
||||
const uint8_t* in = static_cast<uint8_t*>(in_buf);
|
||||
req.Deserialize(&in, in + in_size);
|
||||
Rsp rsp;
|
||||
(device->*method)(req, &rsp);
|
||||
|
||||
*out_size = rsp.SerializedSize();
|
||||
uint8_t* out = static_cast<uint8_t*>(out_buf);
|
||||
rsp.Serialize(out, out + *out_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int trusty_keymaster_call(uint32_t cmd, void* in_buf, uint32_t in_size, void* out_buf,
|
||||
uint32_t* out_size) {
|
||||
switch (cmd) {
|
||||
case KM_GENERATE_KEY:
|
||||
return fake_call(impl_, &keymaster::AndroidKeymaster::GenerateKey, in_buf, in_size,
|
||||
out_buf, out_size);
|
||||
case KM_BEGIN_OPERATION:
|
||||
return fake_call(impl_, &keymaster::AndroidKeymaster::BeginOperation, in_buf, in_size,
|
||||
out_buf, out_size);
|
||||
case KM_UPDATE_OPERATION:
|
||||
return fake_call(impl_, &keymaster::AndroidKeymaster::UpdateOperation, in_buf, in_size,
|
||||
out_buf, out_size);
|
||||
case KM_FINISH_OPERATION:
|
||||
return fake_call(impl_, &keymaster::AndroidKeymaster::FinishOperation, in_buf, in_size,
|
||||
out_buf, out_size);
|
||||
case KM_IMPORT_KEY:
|
||||
return fake_call(impl_, &keymaster::AndroidKeymaster::ImportKey, in_buf, in_size, out_buf,
|
||||
out_size);
|
||||
case KM_EXPORT_KEY:
|
||||
return fake_call(impl_, &keymaster::AndroidKeymaster::ExportKey, in_buf, in_size, out_buf,
|
||||
out_size);
|
||||
}
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
|
||||
namespace keymaster {
|
||||
namespace test {
|
||||
|
||||
class TrustyKeymasterTest : public testing::Test {
|
||||
protected:
|
||||
TrustyKeymasterTest() : device(NULL) {}
|
||||
|
||||
keymaster_rsa_keygen_params_t build_rsa_params() {
|
||||
keymaster_rsa_keygen_params_t rsa_params;
|
||||
rsa_params.public_exponent = 65537;
|
||||
rsa_params.modulus_size = 2048;
|
||||
return rsa_params;
|
||||
}
|
||||
|
||||
uint8_t* build_message(size_t length) {
|
||||
uint8_t* msg = new uint8_t[length];
|
||||
memset(msg, 'a', length);
|
||||
return msg;
|
||||
}
|
||||
|
||||
size_t dsa_message_len(const keymaster_dsa_keygen_params_t& params) {
|
||||
switch (params.key_size) {
|
||||
case 256:
|
||||
case 1024:
|
||||
return 48;
|
||||
case 2048:
|
||||
case 4096:
|
||||
return 72;
|
||||
default:
|
||||
// Oops.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
TrustyKeymasterDevice device;
|
||||
};
|
||||
|
||||
class Malloc_Delete {
|
||||
public:
|
||||
Malloc_Delete(void* p) : p_(p) {}
|
||||
~Malloc_Delete() { free(p_); }
|
||||
|
||||
private:
|
||||
void* p_;
|
||||
};
|
||||
|
||||
typedef TrustyKeymasterTest KeyGenTest;
|
||||
TEST_F(KeyGenTest, RsaSuccess) {
|
||||
keymaster_rsa_keygen_params_t params = build_rsa_params();
|
||||
uint8_t* ptr = NULL;
|
||||
size_t size;
|
||||
ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, ¶ms, &ptr, &size));
|
||||
EXPECT_GT(size, 0U);
|
||||
Malloc_Delete key_deleter(ptr);
|
||||
}
|
||||
|
||||
TEST_F(KeyGenTest, EcdsaSuccess) {
|
||||
keymaster_ec_keygen_params_t ec_params = {256};
|
||||
uint8_t* ptr = NULL;
|
||||
size_t size;
|
||||
ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &ec_params, &ptr, &size));
|
||||
EXPECT_GT(size, 0U);
|
||||
Malloc_Delete key_deleter(ptr);
|
||||
}
|
||||
|
||||
typedef TrustyKeymasterTest SigningTest;
|
||||
TEST_F(SigningTest, RsaSuccess) {
|
||||
keymaster_rsa_keygen_params_t params = build_rsa_params();
|
||||
uint8_t* ptr = NULL;
|
||||
size_t size;
|
||||
ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, ¶ms, &ptr, &size));
|
||||
EXPECT_GT(size, 0U);
|
||||
Malloc_Delete key_deleter(ptr);
|
||||
|
||||
keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
|
||||
size_t message_len = params.modulus_size / 8;
|
||||
UniquePtr<uint8_t[]> message(build_message(message_len));
|
||||
uint8_t* signature;
|
||||
size_t siglen;
|
||||
EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
|
||||
&signature, &siglen));
|
||||
Malloc_Delete sig_deleter(signature);
|
||||
EXPECT_EQ(message_len, siglen);
|
||||
}
|
||||
|
||||
TEST_F(SigningTest, RsaShortMessage) {
|
||||
keymaster_rsa_keygen_params_t params = build_rsa_params();
|
||||
uint8_t* ptr = NULL;
|
||||
size_t size;
|
||||
ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, ¶ms, &ptr, &size));
|
||||
EXPECT_GT(size, 0U);
|
||||
Malloc_Delete key_deleter(ptr);
|
||||
|
||||
keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
|
||||
size_t message_len = params.modulus_size / 8 - 1;
|
||||
UniquePtr<uint8_t[]> message(build_message(message_len));
|
||||
uint8_t* signature;
|
||||
size_t siglen;
|
||||
EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, device.sign_data(&sig_params, ptr, size, message.get(),
|
||||
message_len, &signature, &siglen));
|
||||
}
|
||||
|
||||
TEST_F(SigningTest, RsaLongMessage) {
|
||||
keymaster_rsa_keygen_params_t params = build_rsa_params();
|
||||
uint8_t* ptr = NULL;
|
||||
size_t size;
|
||||
ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, ¶ms, &ptr, &size));
|
||||
EXPECT_GT(size, 0U);
|
||||
Malloc_Delete key_deleter(ptr);
|
||||
|
||||
keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
|
||||
size_t message_len = params.modulus_size / 8 + 1;
|
||||
UniquePtr<uint8_t[]> message(build_message(message_len));
|
||||
uint8_t* signature;
|
||||
size_t siglen;
|
||||
EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, device.sign_data(&sig_params, ptr, size, message.get(),
|
||||
message_len, &signature, &siglen));
|
||||
}
|
||||
|
||||
TEST_F(SigningTest, EcdsaSuccess) {
|
||||
keymaster_ec_keygen_params_t params = {256};
|
||||
uint8_t* ptr = NULL;
|
||||
size_t size;
|
||||
ASSERT_EQ(0, device.generate_keypair(TYPE_EC, ¶ms, &ptr, &size));
|
||||
EXPECT_GT(size, 0U);
|
||||
Malloc_Delete key_deleter(ptr);
|
||||
|
||||
keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
|
||||
uint8_t message[] = "12345678901234567890123456789012";
|
||||
uint8_t* signature;
|
||||
size_t siglen;
|
||||
ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message,
|
||||
array_size(message) - 1, &signature, &siglen));
|
||||
Malloc_Delete sig_deleter(signature);
|
||||
EXPECT_GT(siglen, 69U);
|
||||
EXPECT_LT(siglen, 73U);
|
||||
}
|
||||
|
||||
TEST_F(SigningTest, EcdsaEmptyMessageSuccess) {
|
||||
keymaster_ec_keygen_params_t params = {256};
|
||||
uint8_t* ptr = NULL;
|
||||
size_t size;
|
||||
ASSERT_EQ(0, device.generate_keypair(TYPE_EC, ¶ms, &ptr, &size));
|
||||
EXPECT_GT(size, 0U);
|
||||
Malloc_Delete key_deleter(ptr);
|
||||
|
||||
keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
|
||||
uint8_t message[] = "";
|
||||
uint8_t* signature;
|
||||
size_t siglen;
|
||||
ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message,
|
||||
array_size(message) - 1, &signature, &siglen));
|
||||
Malloc_Delete sig_deleter(signature);
|
||||
EXPECT_GT(siglen, 69U);
|
||||
EXPECT_LT(siglen, 73U);
|
||||
}
|
||||
|
||||
TEST_F(SigningTest, EcdsaLargeMessageSuccess) {
|
||||
keymaster_ec_keygen_params_t params = {256};
|
||||
uint8_t* ptr = NULL;
|
||||
size_t size;
|
||||
ASSERT_EQ(0, device.generate_keypair(TYPE_EC, ¶ms, &ptr, &size));
|
||||
EXPECT_GT(size, 0U);
|
||||
Malloc_Delete key_deleter(ptr);
|
||||
|
||||
keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
|
||||
size_t message_len = 1024 * 7;
|
||||
UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
|
||||
// contents of message don't matter.
|
||||
uint8_t* signature;
|
||||
size_t siglen;
|
||||
ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
|
||||
&signature, &siglen));
|
||||
Malloc_Delete sig_deleter(signature);
|
||||
EXPECT_GT(siglen, 69U);
|
||||
EXPECT_LT(siglen, 73U);
|
||||
}
|
||||
|
||||
typedef TrustyKeymasterTest VerificationTest;
|
||||
TEST_F(VerificationTest, RsaSuccess) {
|
||||
keymaster_rsa_keygen_params_t params = build_rsa_params();
|
||||
uint8_t* ptr = NULL;
|
||||
size_t size;
|
||||
ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, ¶ms, &ptr, &size));
|
||||
EXPECT_GT(size, 0U);
|
||||
Malloc_Delete key_deleter(ptr);
|
||||
|
||||
keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
|
||||
size_t message_len = params.modulus_size / 8;
|
||||
UniquePtr<uint8_t[]> message(build_message(message_len));
|
||||
uint8_t* signature;
|
||||
size_t siglen;
|
||||
EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
|
||||
&signature, &siglen));
|
||||
Malloc_Delete sig_deleter(signature);
|
||||
|
||||
EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, ptr, size, message.get(), message_len,
|
||||
signature, siglen));
|
||||
}
|
||||
|
||||
TEST_F(VerificationTest, RsaBadSignature) {
|
||||
keymaster_rsa_keygen_params_t params = build_rsa_params();
|
||||
uint8_t* ptr = NULL;
|
||||
size_t size;
|
||||
ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, ¶ms, &ptr, &size));
|
||||
EXPECT_GT(size, 0U);
|
||||
Malloc_Delete key_deleter(ptr);
|
||||
|
||||
keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
|
||||
size_t message_len = params.modulus_size / 8;
|
||||
UniquePtr<uint8_t[]> message(build_message(message_len));
|
||||
uint8_t* signature;
|
||||
size_t siglen;
|
||||
EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
|
||||
&signature, &siglen));
|
||||
|
||||
Malloc_Delete sig_deleter(signature);
|
||||
signature[siglen / 2]++;
|
||||
EXPECT_EQ(
|
||||
KM_ERROR_VERIFICATION_FAILED,
|
||||
device.verify_data(&sig_params, ptr, size, message.get(), message_len, signature, siglen));
|
||||
}
|
||||
|
||||
TEST_F(VerificationTest, RsaBadMessage) {
|
||||
keymaster_rsa_keygen_params_t params = build_rsa_params();
|
||||
uint8_t* ptr = NULL;
|
||||
size_t size;
|
||||
ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, ¶ms, &ptr, &size));
|
||||
EXPECT_GT(size, 0U);
|
||||
Malloc_Delete key_deleter(ptr);
|
||||
|
||||
keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
|
||||
size_t message_len = params.modulus_size / 8;
|
||||
UniquePtr<uint8_t[]> message(build_message(message_len));
|
||||
uint8_t* signature;
|
||||
size_t siglen;
|
||||
EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
|
||||
&signature, &siglen));
|
||||
Malloc_Delete sig_deleter(signature);
|
||||
message[0]++;
|
||||
EXPECT_EQ(
|
||||
KM_ERROR_VERIFICATION_FAILED,
|
||||
device.verify_data(&sig_params, ptr, size, message.get(), message_len, signature, siglen));
|
||||
}
|
||||
|
||||
TEST_F(VerificationTest, RsaShortMessage) {
|
||||
keymaster_rsa_keygen_params_t params = build_rsa_params();
|
||||
uint8_t* ptr = NULL;
|
||||
size_t size;
|
||||
ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, ¶ms, &ptr, &size));
|
||||
EXPECT_GT(size, 0U);
|
||||
Malloc_Delete key_deleter(ptr);
|
||||
|
||||
keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
|
||||
size_t message_len = params.modulus_size / 8;
|
||||
UniquePtr<uint8_t[]> message(build_message(message_len));
|
||||
uint8_t* signature;
|
||||
size_t siglen;
|
||||
EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
|
||||
&signature, &siglen));
|
||||
|
||||
Malloc_Delete sig_deleter(signature);
|
||||
EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH,
|
||||
device.verify_data(&sig_params, ptr, size, message.get(), message_len - 1, signature,
|
||||
siglen));
|
||||
}
|
||||
|
||||
TEST_F(VerificationTest, RsaLongMessage) {
|
||||
keymaster_rsa_keygen_params_t params = build_rsa_params();
|
||||
uint8_t* ptr = NULL;
|
||||
size_t size;
|
||||
ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, ¶ms, &ptr, &size));
|
||||
EXPECT_GT(size, 0U);
|
||||
Malloc_Delete key_deleter(ptr);
|
||||
|
||||
keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
|
||||
size_t message_len = params.modulus_size / 8;
|
||||
UniquePtr<uint8_t[]> message(build_message(message_len + 1));
|
||||
uint8_t* signature;
|
||||
size_t siglen;
|
||||
EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
|
||||
&signature, &siglen));
|
||||
Malloc_Delete sig_deleter(signature);
|
||||
EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH,
|
||||
device.verify_data(&sig_params, ptr, size, message.get(), message_len + 1, signature,
|
||||
siglen));
|
||||
}
|
||||
|
||||
TEST_F(VerificationTest, EcdsaSuccess) {
|
||||
keymaster_ec_keygen_params_t params = {256};
|
||||
uint8_t* ptr = NULL;
|
||||
size_t size;
|
||||
ASSERT_EQ(0, device.generate_keypair(TYPE_EC, ¶ms, &ptr, &size));
|
||||
EXPECT_GT(size, 0U);
|
||||
Malloc_Delete key_deleter(ptr);
|
||||
|
||||
keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
|
||||
uint8_t message[] = "12345678901234567890123456789012";
|
||||
uint8_t* signature;
|
||||
size_t siglen;
|
||||
ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message,
|
||||
array_size(message) - 1, &signature, &siglen));
|
||||
Malloc_Delete sig_deleter(signature);
|
||||
EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, ptr, size, message,
|
||||
array_size(message) - 1, signature, siglen));
|
||||
}
|
||||
|
||||
TEST_F(VerificationTest, EcdsaLargeMessageSuccess) {
|
||||
keymaster_ec_keygen_params_t params = {256};
|
||||
uint8_t* ptr = NULL;
|
||||
size_t size;
|
||||
ASSERT_EQ(0, device.generate_keypair(TYPE_EC, ¶ms, &ptr, &size));
|
||||
EXPECT_GT(size, 0U);
|
||||
Malloc_Delete key_deleter(ptr);
|
||||
|
||||
keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
|
||||
size_t message_len = 1024 * 7;
|
||||
UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
|
||||
// contents of message don't matter.
|
||||
uint8_t* signature;
|
||||
size_t siglen;
|
||||
ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
|
||||
&signature, &siglen));
|
||||
Malloc_Delete sig_deleter(signature);
|
||||
EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, ptr, size, message.get(), message_len,
|
||||
signature, siglen));
|
||||
}
|
||||
|
||||
static string read_file(const string& file_name) {
|
||||
ifstream file_stream(file_name, std::ios::binary);
|
||||
istreambuf_iterator<char> file_begin(file_stream);
|
||||
istreambuf_iterator<char> file_end;
|
||||
return string(file_begin, file_end);
|
||||
}
|
||||
|
||||
typedef TrustyKeymasterTest ImportKeyTest;
|
||||
TEST_F(ImportKeyTest, RsaSuccess) {
|
||||
string pk8_key = read_file("../../../../system/keymaster/rsa_privkey_pk8.der");
|
||||
ASSERT_EQ(633U, pk8_key.size());
|
||||
|
||||
uint8_t* key = NULL;
|
||||
size_t size;
|
||||
ASSERT_EQ(KM_ERROR_OK, device.import_keypair(reinterpret_cast<const uint8_t*>(pk8_key.data()),
|
||||
pk8_key.size(), &key, &size));
|
||||
Malloc_Delete key_deleter(key);
|
||||
|
||||
keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
|
||||
size_t message_size = 1024 /* key size */ / 8;
|
||||
UniquePtr<uint8_t[]> message(new uint8_t[message_size]);
|
||||
memset(message.get(), 'a', message_size);
|
||||
uint8_t* signature;
|
||||
size_t siglen;
|
||||
ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, key, size, message.get(), message_size,
|
||||
&signature, &siglen));
|
||||
Malloc_Delete sig_deleter(signature);
|
||||
EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, key, size, message.get(), message_size,
|
||||
signature, siglen));
|
||||
}
|
||||
|
||||
TEST_F(ImportKeyTest, EcdsaSuccess) {
|
||||
string pk8_key = read_file("../../../../system/keymaster/ec_privkey_pk8.der");
|
||||
ASSERT_EQ(138U, pk8_key.size());
|
||||
|
||||
uint8_t* key = NULL;
|
||||
size_t size;
|
||||
ASSERT_EQ(KM_ERROR_OK, device.import_keypair(reinterpret_cast<const uint8_t*>(pk8_key.data()),
|
||||
pk8_key.size(), &key, &size));
|
||||
Malloc_Delete key_deleter(key);
|
||||
|
||||
keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
|
||||
uint8_t message[] = "12345678901234567890123456789012";
|
||||
uint8_t* signature;
|
||||
size_t siglen;
|
||||
ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, key, size, message,
|
||||
array_size(message) - 1, &signature, &siglen));
|
||||
Malloc_Delete sig_deleter(signature);
|
||||
EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, key, size, message,
|
||||
array_size(message) - 1, signature, siglen));
|
||||
}
|
||||
|
||||
struct EVP_PKEY_CTX_Delete {
|
||||
void operator()(EVP_PKEY_CTX* p) { EVP_PKEY_CTX_free(p); }
|
||||
};
|
||||
|
||||
static void VerifySignature(const uint8_t* key, size_t key_len, const uint8_t* signature,
|
||||
size_t signature_len, const uint8_t* message, size_t message_len) {
|
||||
UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(d2i_PUBKEY(NULL, &key, key_len));
|
||||
ASSERT_TRUE(pkey.get() != NULL);
|
||||
UniquePtr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
|
||||
ASSERT_TRUE(ctx.get() != NULL);
|
||||
ASSERT_EQ(1, EVP_PKEY_verify_init(ctx.get()));
|
||||
if (EVP_PKEY_type(pkey->type) == EVP_PKEY_RSA)
|
||||
ASSERT_EQ(1, EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_NO_PADDING));
|
||||
EXPECT_EQ(1, EVP_PKEY_verify(ctx.get(), signature, signature_len, message, message_len));
|
||||
}
|
||||
|
||||
typedef TrustyKeymasterTest ExportKeyTest;
|
||||
TEST_F(ExportKeyTest, RsaSuccess) {
|
||||
keymaster_rsa_keygen_params_t params = build_rsa_params();
|
||||
uint8_t* ptr = NULL;
|
||||
size_t size;
|
||||
ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, ¶ms, &ptr, &size));
|
||||
EXPECT_GT(size, 0U);
|
||||
Malloc_Delete key_deleter(ptr);
|
||||
|
||||
uint8_t* exported;
|
||||
size_t exported_size;
|
||||
EXPECT_EQ(KM_ERROR_OK, device.get_keypair_public(ptr, size, &exported, &exported_size));
|
||||
Malloc_Delete exported_deleter(exported);
|
||||
|
||||
// Sign a message so we can verify it with the exported pubkey.
|
||||
keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
|
||||
size_t message_len = params.modulus_size / 8;
|
||||
UniquePtr<uint8_t[]> message(build_message(message_len));
|
||||
uint8_t* signature;
|
||||
size_t siglen;
|
||||
EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
|
||||
&signature, &siglen));
|
||||
Malloc_Delete sig_deleter(signature);
|
||||
EXPECT_EQ(message_len, siglen);
|
||||
const uint8_t* tmp = exported;
|
||||
|
||||
VerifySignature(exported, exported_size, signature, siglen, message.get(), message_len);
|
||||
}
|
||||
|
||||
typedef TrustyKeymasterTest ExportKeyTest;
|
||||
TEST_F(ExportKeyTest, EcdsaSuccess) {
|
||||
keymaster_ec_keygen_params_t params = {256};
|
||||
uint8_t* key = NULL;
|
||||
size_t size;
|
||||
ASSERT_EQ(0, device.generate_keypair(TYPE_EC, ¶ms, &key, &size));
|
||||
EXPECT_GT(size, 0U);
|
||||
Malloc_Delete key_deleter(key);
|
||||
|
||||
uint8_t* exported;
|
||||
size_t exported_size;
|
||||
EXPECT_EQ(KM_ERROR_OK, device.get_keypair_public(key, size, &exported, &exported_size));
|
||||
Malloc_Delete exported_deleter(exported);
|
||||
|
||||
// Sign a message so we can verify it with the exported pubkey.
|
||||
keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
|
||||
uint8_t message[] = "12345678901234567890123456789012";
|
||||
uint8_t* signature;
|
||||
size_t siglen;
|
||||
ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, key, size, message,
|
||||
array_size(message) - 1, &signature, &siglen));
|
||||
Malloc_Delete sig_deleter(signature);
|
||||
EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, key, size, message,
|
||||
array_size(message) - 1, signature, siglen));
|
||||
|
||||
VerifySignature(exported, exported_size, signature, siglen, message, array_size(message) - 1);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace keymaster
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// TODO: make this generic in libtrusty
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define LOG_TAG "TrustyKeymaster"
|
||||
#include <cutils/log.h>
|
||||
|
||||
#include <trusty/tipc.h>
|
||||
|
||||
#include "trusty_keymaster_ipc.h"
|
||||
#include "keymaster_ipc.h"
|
||||
|
||||
#define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0"
|
||||
|
||||
static int handle_ = 0;
|
||||
|
||||
int trusty_keymaster_connect() {
|
||||
int rc = tipc_connect(TRUSTY_DEVICE_NAME, KEYMASTER_PORT);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
handle_ = rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int trusty_keymaster_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out,
|
||||
uint32_t *out_size) {
|
||||
if (handle_ == 0) {
|
||||
ALOGE("not connected\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
size_t msg_size = in_size + sizeof(struct keymaster_message);
|
||||
struct keymaster_message *msg = malloc(msg_size);
|
||||
msg->cmd = cmd;
|
||||
memcpy(msg->payload, in, in_size);
|
||||
|
||||
ssize_t rc = write(handle_, msg, msg_size);
|
||||
free(msg);
|
||||
|
||||
if (rc < 0) {
|
||||
ALOGE("failed to send cmd (%d) to %s: %s\n", cmd,
|
||||
KEYMASTER_PORT, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
rc = read(handle_, out, *out_size);
|
||||
if (rc < 0) {
|
||||
ALOGE("failed to retrieve response for cmd (%d) to %s: %s\n",
|
||||
cmd, KEYMASTER_PORT, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if ((size_t) rc < sizeof(struct keymaster_message)) {
|
||||
ALOGE("invalid response size (%d)\n", (int) rc);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
msg = (struct keymaster_message *) out;
|
||||
|
||||
if ((cmd | KEYMASTER_RESP_BIT) != msg->cmd) {
|
||||
ALOGE("invalid command (%d)", msg->cmd);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*out_size = ((size_t) rc) - sizeof(struct keymaster_message);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void trusty_keymaster_disconnect() {
|
||||
if (handle_ != 0) {
|
||||
tipc_close(handle_);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
int trusty_keymaster_connect(void);
|
||||
int trusty_keymaster_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out,
|
||||
uint32_t *out_size);
|
||||
void trusty_keymaster_disconnect(void);
|
||||
|
||||
__END_DECLS
|
|
@ -0,0 +1,368 @@
|
|||
/*
|
||||
* Copyright 2014 The Android Open Source Project
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include "trusty_keymaster_device.h"
|
||||
|
||||
using keymaster::TrustyKeymasterDevice;
|
||||
|
||||
unsigned char rsa_privkey_pk8_der[] = {
|
||||
0x30, 0x82, 0x02, 0x75, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
|
||||
0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x5f, 0x30, 0x82, 0x02, 0x5b, 0x02, 0x01,
|
||||
0x00, 0x02, 0x81, 0x81, 0x00, 0xc6, 0x09, 0x54, 0x09, 0x04, 0x7d, 0x86, 0x34, 0x81, 0x2d, 0x5a,
|
||||
0x21, 0x81, 0x76, 0xe4, 0x5c, 0x41, 0xd6, 0x0a, 0x75, 0xb1, 0x39, 0x01, 0xf2, 0x34, 0x22, 0x6c,
|
||||
0xff, 0xe7, 0x76, 0x52, 0x1c, 0x5a, 0x77, 0xb9, 0xe3, 0x89, 0x41, 0x7b, 0x71, 0xc0, 0xb6, 0xa4,
|
||||
0x4d, 0x13, 0xaf, 0xe4, 0xe4, 0xa2, 0x80, 0x5d, 0x46, 0xc9, 0xda, 0x29, 0x35, 0xad, 0xb1, 0xff,
|
||||
0x0c, 0x1f, 0x24, 0xea, 0x06, 0xe6, 0x2b, 0x20, 0xd7, 0x76, 0x43, 0x0a, 0x4d, 0x43, 0x51, 0x57,
|
||||
0x23, 0x3c, 0x6f, 0x91, 0x67, 0x83, 0xc3, 0x0e, 0x31, 0x0f, 0xcb, 0xd8, 0x9b, 0x85, 0xc2, 0xd5,
|
||||
0x67, 0x71, 0x16, 0x97, 0x85, 0xac, 0x12, 0xbc, 0xa2, 0x44, 0xab, 0xda, 0x72, 0xbf, 0xb1, 0x9f,
|
||||
0xc4, 0x4d, 0x27, 0xc8, 0x1e, 0x1d, 0x92, 0xde, 0x28, 0x4f, 0x40, 0x61, 0xed, 0xfd, 0x99, 0x28,
|
||||
0x07, 0x45, 0xea, 0x6d, 0x25, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x81, 0x80, 0x1b, 0xe0, 0xf0,
|
||||
0x4d, 0x9c, 0xae, 0x37, 0x18, 0x69, 0x1f, 0x03, 0x53, 0x38, 0x30, 0x8e, 0x91, 0x56, 0x4b, 0x55,
|
||||
0x89, 0x9f, 0xfb, 0x50, 0x84, 0xd2, 0x46, 0x0e, 0x66, 0x30, 0x25, 0x7e, 0x05, 0xb3, 0xce, 0xab,
|
||||
0x02, 0x97, 0x2d, 0xfa, 0xbc, 0xd6, 0xce, 0x5f, 0x6e, 0xe2, 0x58, 0x9e, 0xb6, 0x79, 0x11, 0xed,
|
||||
0x0f, 0xac, 0x16, 0xe4, 0x3a, 0x44, 0x4b, 0x8c, 0x86, 0x1e, 0x54, 0x4a, 0x05, 0x93, 0x36, 0x57,
|
||||
0x72, 0xf8, 0xba, 0xf6, 0xb2, 0x2f, 0xc9, 0xe3, 0xc5, 0xf1, 0x02, 0x4b, 0x06, 0x3a, 0xc0, 0x80,
|
||||
0xa7, 0xb2, 0x23, 0x4c, 0xf8, 0xae, 0xe8, 0xf6, 0xc4, 0x7b, 0xbf, 0x4f, 0xd3, 0xac, 0xe7, 0x24,
|
||||
0x02, 0x90, 0xbe, 0xf1, 0x6c, 0x0b, 0x3f, 0x7f, 0x3c, 0xdd, 0x64, 0xce, 0x3a, 0xb5, 0x91, 0x2c,
|
||||
0xf6, 0xe3, 0x2f, 0x39, 0xab, 0x18, 0x83, 0x58, 0xaf, 0xcc, 0xcd, 0x80, 0x81, 0x02, 0x41, 0x00,
|
||||
0xe4, 0xb4, 0x9e, 0xf5, 0x0f, 0x76, 0x5d, 0x3b, 0x24, 0xdd, 0xe0, 0x1a, 0xce, 0xaa, 0xf1, 0x30,
|
||||
0xf2, 0xc7, 0x66, 0x70, 0xa9, 0x1a, 0x61, 0xae, 0x08, 0xaf, 0x49, 0x7b, 0x4a, 0x82, 0xbe, 0x6d,
|
||||
0xee, 0x8f, 0xcd, 0xd5, 0xe3, 0xf7, 0xba, 0x1c, 0xfb, 0x1f, 0x0c, 0x92, 0x6b, 0x88, 0xf8, 0x8c,
|
||||
0x92, 0xbf, 0xab, 0x13, 0x7f, 0xba, 0x22, 0x85, 0x22, 0x7b, 0x83, 0xc3, 0x42, 0xff, 0x7c, 0x55,
|
||||
0x02, 0x41, 0x00, 0xdd, 0xab, 0xb5, 0x83, 0x9c, 0x4c, 0x7f, 0x6b, 0xf3, 0xd4, 0x18, 0x32, 0x31,
|
||||
0xf0, 0x05, 0xb3, 0x1a, 0xa5, 0x8a, 0xff, 0xdd, 0xa5, 0xc7, 0x9e, 0x4c, 0xce, 0x21, 0x7f, 0x6b,
|
||||
0xc9, 0x30, 0xdb, 0xe5, 0x63, 0xd4, 0x80, 0x70, 0x6c, 0x24, 0xe9, 0xeb, 0xfc, 0xab, 0x28, 0xa6,
|
||||
0xcd, 0xef, 0xd3, 0x24, 0xb7, 0x7e, 0x1b, 0xf7, 0x25, 0x1b, 0x70, 0x90, 0x92, 0xc2, 0x4f, 0xf5,
|
||||
0x01, 0xfd, 0x91, 0x02, 0x40, 0x23, 0xd4, 0x34, 0x0e, 0xda, 0x34, 0x45, 0xd8, 0xcd, 0x26, 0xc1,
|
||||
0x44, 0x11, 0xda, 0x6f, 0xdc, 0xa6, 0x3c, 0x1c, 0xcd, 0x4b, 0x80, 0xa9, 0x8a, 0xd5, 0x2b, 0x78,
|
||||
0xcc, 0x8a, 0xd8, 0xbe, 0xb2, 0x84, 0x2c, 0x1d, 0x28, 0x04, 0x05, 0xbc, 0x2f, 0x6c, 0x1b, 0xea,
|
||||
0x21, 0x4a, 0x1d, 0x74, 0x2a, 0xb9, 0x96, 0xb3, 0x5b, 0x63, 0xa8, 0x2a, 0x5e, 0x47, 0x0f, 0xa8,
|
||||
0x8d, 0xbf, 0x82, 0x3c, 0xdd, 0x02, 0x40, 0x1b, 0x7b, 0x57, 0x44, 0x9a, 0xd3, 0x0d, 0x15, 0x18,
|
||||
0x24, 0x9a, 0x5f, 0x56, 0xbb, 0x98, 0x29, 0x4d, 0x4b, 0x6a, 0xc1, 0x2f, 0xfc, 0x86, 0x94, 0x04,
|
||||
0x97, 0xa5, 0xa5, 0x83, 0x7a, 0x6c, 0xf9, 0x46, 0x26, 0x2b, 0x49, 0x45, 0x26, 0xd3, 0x28, 0xc1,
|
||||
0x1e, 0x11, 0x26, 0x38, 0x0f, 0xde, 0x04, 0xc2, 0x4f, 0x91, 0x6d, 0xec, 0x25, 0x08, 0x92, 0xdb,
|
||||
0x09, 0xa6, 0xd7, 0x7c, 0xdb, 0xa3, 0x51, 0x02, 0x40, 0x77, 0x62, 0xcd, 0x8f, 0x4d, 0x05, 0x0d,
|
||||
0xa5, 0x6b, 0xd5, 0x91, 0xad, 0xb5, 0x15, 0xd2, 0x4d, 0x7c, 0xcd, 0x32, 0xcc, 0xa0, 0xd0, 0x5f,
|
||||
0x86, 0x6d, 0x58, 0x35, 0x14, 0xbd, 0x73, 0x24, 0xd5, 0xf3, 0x36, 0x45, 0xe8, 0xed, 0x8b, 0x4a,
|
||||
0x1c, 0xb3, 0xcc, 0x4a, 0x1d, 0x67, 0x98, 0x73, 0x99, 0xf2, 0xa0, 0x9f, 0x5b, 0x3f, 0xb6, 0x8c,
|
||||
0x88, 0xd5, 0xe5, 0xd9, 0x0a, 0xc3, 0x34, 0x92, 0xd6};
|
||||
unsigned int rsa_privkey_pk8_der_len = 633;
|
||||
|
||||
unsigned char dsa_privkey_pk8_der[] = {
|
||||
0x30, 0x82, 0x01, 0x4b, 0x02, 0x01, 0x00, 0x30, 0x82, 0x01, 0x2b, 0x06, 0x07, 0x2a, 0x86, 0x48,
|
||||
0xce, 0x38, 0x04, 0x01, 0x30, 0x82, 0x01, 0x1e, 0x02, 0x81, 0x81, 0x00, 0xa3, 0xf3, 0xe9, 0xb6,
|
||||
0x7e, 0x7d, 0x88, 0xf6, 0xb7, 0xe5, 0xf5, 0x1f, 0x3b, 0xee, 0xac, 0xd7, 0xad, 0xbc, 0xc9, 0xd1,
|
||||
0x5a, 0xf8, 0x88, 0xc4, 0xef, 0x6e, 0x3d, 0x74, 0x19, 0x74, 0xe7, 0xd8, 0xe0, 0x26, 0x44, 0x19,
|
||||
0x86, 0xaf, 0x19, 0xdb, 0x05, 0xe9, 0x3b, 0x8b, 0x58, 0x58, 0xde, 0xe5, 0x4f, 0x48, 0x15, 0x01,
|
||||
0xea, 0xe6, 0x83, 0x52, 0xd7, 0xc1, 0x21, 0xdf, 0xb9, 0xb8, 0x07, 0x66, 0x50, 0xfb, 0x3a, 0x0c,
|
||||
0xb3, 0x85, 0xee, 0xbb, 0x04, 0x5f, 0xc2, 0x6d, 0x6d, 0x95, 0xfa, 0x11, 0x93, 0x1e, 0x59, 0x5b,
|
||||
0xb1, 0x45, 0x8d, 0xe0, 0x3d, 0x73, 0xaa, 0xf2, 0x41, 0x14, 0x51, 0x07, 0x72, 0x3d, 0xa2, 0xf7,
|
||||
0x58, 0xcd, 0x11, 0xa1, 0x32, 0xcf, 0xda, 0x42, 0xb7, 0xcc, 0x32, 0x80, 0xdb, 0x87, 0x82, 0xec,
|
||||
0x42, 0xdb, 0x5a, 0x55, 0x24, 0x24, 0xa2, 0xd1, 0x55, 0x29, 0xad, 0xeb, 0x02, 0x15, 0x00, 0xeb,
|
||||
0xea, 0x17, 0xd2, 0x09, 0xb3, 0xd7, 0x21, 0x9a, 0x21, 0x07, 0x82, 0x8f, 0xab, 0xfe, 0x88, 0x71,
|
||||
0x68, 0xf7, 0xe3, 0x02, 0x81, 0x80, 0x19, 0x1c, 0x71, 0xfd, 0xe0, 0x03, 0x0c, 0x43, 0xd9, 0x0b,
|
||||
0xf6, 0xcd, 0xd6, 0xa9, 0x70, 0xe7, 0x37, 0x86, 0x3a, 0x78, 0xe9, 0xa7, 0x47, 0xa7, 0x47, 0x06,
|
||||
0x88, 0xb1, 0xaf, 0xd7, 0xf3, 0xf1, 0xa1, 0xd7, 0x00, 0x61, 0x28, 0x88, 0x31, 0x48, 0x60, 0xd8,
|
||||
0x11, 0xef, 0xa5, 0x24, 0x1a, 0x81, 0xc4, 0x2a, 0xe2, 0xea, 0x0e, 0x36, 0xd2, 0xd2, 0x05, 0x84,
|
||||
0x37, 0xcf, 0x32, 0x7d, 0x09, 0xe6, 0x0f, 0x8b, 0x0c, 0xc8, 0xc2, 0xa4, 0xb1, 0xdc, 0x80, 0xca,
|
||||
0x68, 0xdf, 0xaf, 0xd2, 0x90, 0xc0, 0x37, 0x58, 0x54, 0x36, 0x8f, 0x49, 0xb8, 0x62, 0x75, 0x8b,
|
||||
0x48, 0x47, 0xc0, 0xbe, 0xf7, 0x9a, 0x92, 0xa6, 0x68, 0x05, 0xda, 0x9d, 0xaf, 0x72, 0x9a, 0x67,
|
||||
0xb3, 0xb4, 0x14, 0x03, 0xae, 0x4f, 0x4c, 0x76, 0xb9, 0xd8, 0x64, 0x0a, 0xba, 0x3b, 0xa8, 0x00,
|
||||
0x60, 0x4d, 0xae, 0x81, 0xc3, 0xc5, 0x04, 0x17, 0x02, 0x15, 0x00, 0x81, 0x9d, 0xfd, 0x53, 0x0c,
|
||||
0xc1, 0x8f, 0xbe, 0x8b, 0xea, 0x00, 0x26, 0x19, 0x29, 0x33, 0x91, 0x84, 0xbe, 0xad, 0x81};
|
||||
unsigned int dsa_privkey_pk8_der_len = 335;
|
||||
|
||||
unsigned char ec_privkey_pk8_der[] = {
|
||||
0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
|
||||
0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02,
|
||||
0x01, 0x01, 0x04, 0x20, 0x73, 0x7c, 0x2e, 0xcd, 0x7b, 0x8d, 0x19, 0x40, 0xbf, 0x29, 0x30, 0xaa,
|
||||
0x9b, 0x4e, 0xd3, 0xff, 0x94, 0x1e, 0xed, 0x09, 0x36, 0x6b, 0xc0, 0x32, 0x99, 0x98, 0x64, 0x81,
|
||||
0xf3, 0xa4, 0xd8, 0x59, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0xbf, 0x85, 0xd7, 0x72, 0x0d, 0x07,
|
||||
0xc2, 0x54, 0x61, 0x68, 0x3b, 0xc6, 0x48, 0xb4, 0x77, 0x8a, 0x9a, 0x14, 0xdd, 0x8a, 0x02, 0x4e,
|
||||
0x3b, 0xdd, 0x8c, 0x7d, 0xdd, 0x9a, 0xb2, 0xb5, 0x28, 0xbb, 0xc7, 0xaa, 0x1b, 0x51, 0xf1, 0x4e,
|
||||
0xbb, 0xbb, 0x0b, 0xd0, 0xce, 0x21, 0xbc, 0xc4, 0x1c, 0x6e, 0xb0, 0x00, 0x83, 0xcf, 0x33, 0x76,
|
||||
0xd1, 0x1f, 0xd4, 0x49, 0x49, 0xe0, 0xb2, 0x18, 0x3b, 0xfe};
|
||||
unsigned int ec_privkey_pk8_der_len = 138;
|
||||
|
||||
struct EVP_PKEY_Delete {
|
||||
void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); }
|
||||
};
|
||||
|
||||
struct EVP_PKEY_CTX_Delete {
|
||||
void operator()(EVP_PKEY_CTX* p) { EVP_PKEY_CTX_free(p); }
|
||||
};
|
||||
|
||||
static bool test_import_rsa(TrustyKeymasterDevice* device) {
|
||||
printf("===================\n");
|
||||
printf("= RSA Import Test =\n");
|
||||
printf("===================\n\n");
|
||||
|
||||
printf("=== Importing RSA keypair === \n");
|
||||
uint8_t* key;
|
||||
size_t size;
|
||||
int error = device->import_keypair(rsa_privkey_pk8_der, rsa_privkey_pk8_der_len, &key, &size);
|
||||
if (error != KM_ERROR_OK) {
|
||||
printf("Error importing key pair: %d\n\n", error);
|
||||
return false;
|
||||
}
|
||||
UniquePtr<uint8_t[]> key_deleter(key);
|
||||
|
||||
printf("=== Signing with imported RSA key ===\n");
|
||||
keymaster_rsa_sign_params_t sign_params = {DIGEST_NONE, PADDING_NONE};
|
||||
size_t message_len = 1024 / 8;
|
||||
UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
|
||||
memset(message.get(), 'a', message_len);
|
||||
uint8_t* signature;
|
||||
size_t signature_len;
|
||||
error = device->sign_data(&sign_params, key, size, message.get(), message_len, &signature,
|
||||
&signature_len);
|
||||
if (error != KM_ERROR_OK) {
|
||||
printf("Error signing data with imported RSA key: %d\n\n", error);
|
||||
return false;
|
||||
}
|
||||
UniquePtr<uint8_t[]> signature_deleter(signature);
|
||||
|
||||
printf("=== Verifying with imported RSA key === \n");
|
||||
error = device->verify_data(&sign_params, key, size, message.get(), message_len, signature,
|
||||
signature_len);
|
||||
if (error != KM_ERROR_OK) {
|
||||
printf("Error verifying data with imported RSA key: %d\n\n", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool test_rsa(TrustyKeymasterDevice* device) {
|
||||
printf("============\n");
|
||||
printf("= RSA Test =\n");
|
||||
printf("============\n\n");
|
||||
|
||||
printf("=== Generating RSA key pair ===\n");
|
||||
keymaster_rsa_keygen_params_t params;
|
||||
params.public_exponent = 65537;
|
||||
params.modulus_size = 2048;
|
||||
|
||||
uint8_t* key;
|
||||
size_t size;
|
||||
int error = device->generate_keypair(TYPE_RSA, ¶ms, &key, &size);
|
||||
if (error != KM_ERROR_OK) {
|
||||
printf("Error generating RSA key pair: %d\n\n", error);
|
||||
return false;
|
||||
}
|
||||
UniquePtr<uint8_t[]> deleter(key);
|
||||
|
||||
printf("=== Signing with RSA key === \n");
|
||||
keymaster_rsa_sign_params_t sign_params = {DIGEST_NONE, PADDING_NONE};
|
||||
size_t message_len = params.modulus_size / 8;
|
||||
UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
|
||||
memset(message.get(), 'a', message_len);
|
||||
uint8_t* signature;
|
||||
size_t signature_len;
|
||||
error = device->sign_data(&sign_params, key, size, message.get(), message_len, &signature,
|
||||
&signature_len);
|
||||
if (error != KM_ERROR_OK) {
|
||||
printf("Error signing data with RSA key: %d\n\n", error);
|
||||
return false;
|
||||
}
|
||||
UniquePtr<uint8_t[]> signature_deleter(signature);
|
||||
|
||||
printf("=== Verifying with RSA key === \n");
|
||||
error = device->verify_data(&sign_params, key, size, message.get(), message_len, signature,
|
||||
signature_len);
|
||||
if (error != KM_ERROR_OK) {
|
||||
printf("Error verifying data with RSA key: %d\n\n", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("=== Exporting RSA public key ===\n");
|
||||
uint8_t* exported_key;
|
||||
size_t exported_size;
|
||||
error = device->get_keypair_public(key, size, &exported_key, &exported_size);
|
||||
if (error != KM_ERROR_OK) {
|
||||
printf("Error exporting RSA public key: %d\n\n", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("=== Verifying with exported key ===\n");
|
||||
const uint8_t* tmp = exported_key;
|
||||
UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(d2i_PUBKEY(NULL, &tmp, exported_size));
|
||||
UniquePtr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
|
||||
if (EVP_PKEY_verify_init(ctx.get()) != 1) {
|
||||
printf("Error initializing openss EVP context\n");
|
||||
return false;
|
||||
}
|
||||
if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) {
|
||||
printf("Exported key was the wrong type?!?\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_NO_PADDING);
|
||||
if (EVP_PKEY_verify(ctx.get(), signature, signature_len, message.get(), message_len) != 1) {
|
||||
printf("Verification with exported pubkey failed.\n");
|
||||
return false;
|
||||
} else {
|
||||
printf("Verification succeeded\n");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool test_import_ecdsa(TrustyKeymasterDevice* device) {
|
||||
printf("=====================\n");
|
||||
printf("= ECDSA Import Test =\n");
|
||||
printf("=====================\n\n");
|
||||
|
||||
printf("=== Importing ECDSA keypair === \n");
|
||||
uint8_t* key;
|
||||
size_t size;
|
||||
int error = device->import_keypair(ec_privkey_pk8_der, ec_privkey_pk8_der_len, &key, &size);
|
||||
if (error != KM_ERROR_OK) {
|
||||
printf("Error importing key pair: %d\n\n", error);
|
||||
return false;
|
||||
}
|
||||
UniquePtr<uint8_t[]> deleter(key);
|
||||
|
||||
printf("=== Signing with imported ECDSA key ===\n");
|
||||
keymaster_ec_sign_params_t sign_params = {DIGEST_NONE};
|
||||
size_t message_len = 30 /* arbitrary */;
|
||||
UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
|
||||
memset(message.get(), 'a', message_len);
|
||||
uint8_t* signature;
|
||||
size_t signature_len;
|
||||
error = device->sign_data(&sign_params, key, size, message.get(), message_len, &signature,
|
||||
&signature_len);
|
||||
if (error != KM_ERROR_OK) {
|
||||
printf("Error signing data with imported ECDSA key: %d\n\n", error);
|
||||
return false;
|
||||
}
|
||||
UniquePtr<uint8_t[]> signature_deleter(signature);
|
||||
|
||||
printf("=== Verifying with imported ECDSA key === \n");
|
||||
error = device->verify_data(&sign_params, key, size, message.get(), message_len, signature,
|
||||
signature_len);
|
||||
if (error != KM_ERROR_OK) {
|
||||
printf("Error verifying data with imported ECDSA key: %d\n\n", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool test_ecdsa(TrustyKeymasterDevice* device) {
|
||||
printf("==============\n");
|
||||
printf("= ECDSA Test =\n");
|
||||
printf("==============\n\n");
|
||||
|
||||
printf("=== Generating ECDSA key pair ===\n");
|
||||
keymaster_ec_keygen_params_t params;
|
||||
params.field_size = 521;
|
||||
uint8_t* key;
|
||||
size_t size;
|
||||
int error = device->generate_keypair(TYPE_EC, ¶ms, &key, &size);
|
||||
if (error != 0) {
|
||||
printf("Error generating ECDSA key pair: %d\n\n", error);
|
||||
return false;
|
||||
}
|
||||
UniquePtr<uint8_t[]> deleter(key);
|
||||
|
||||
printf("=== Signing with ECDSA key === \n");
|
||||
keymaster_ec_sign_params_t sign_params = {DIGEST_NONE};
|
||||
size_t message_len = 30 /* arbitrary */;
|
||||
UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
|
||||
memset(message.get(), 'a', message_len);
|
||||
uint8_t* signature;
|
||||
size_t signature_len;
|
||||
error = device->sign_data(&sign_params, key, size, message.get(), message_len, &signature,
|
||||
&signature_len);
|
||||
if (error != KM_ERROR_OK) {
|
||||
printf("Error signing data with ECDSA key: %d\n\n", error);
|
||||
return false;
|
||||
}
|
||||
UniquePtr<uint8_t[]> signature_deleter(signature);
|
||||
|
||||
printf("=== Verifying with ECDSA key === \n");
|
||||
error = device->verify_data(&sign_params, key, size, message.get(), message_len, signature,
|
||||
signature_len);
|
||||
if (error != KM_ERROR_OK) {
|
||||
printf("Error verifying data with ECDSA key: %d\n\n", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("=== Exporting ECDSA public key ===\n");
|
||||
uint8_t* exported_key;
|
||||
size_t exported_size;
|
||||
error = device->get_keypair_public(key, size, &exported_key, &exported_size);
|
||||
if (error != KM_ERROR_OK) {
|
||||
printf("Error exporting ECDSA public key: %d\n\n", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("=== Verifying with exported key ===\n");
|
||||
const uint8_t* tmp = exported_key;
|
||||
UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(d2i_PUBKEY(NULL, &tmp, exported_size));
|
||||
UniquePtr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
|
||||
if (EVP_PKEY_verify_init(ctx.get()) != 1) {
|
||||
printf("Error initializing openss EVP context\n");
|
||||
return false;
|
||||
}
|
||||
if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) {
|
||||
printf("Exported key was the wrong type?!?\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_verify(ctx.get(), signature, signature_len, message.get(), message_len) != 1) {
|
||||
printf("Verification with exported pubkey failed.\n");
|
||||
return false;
|
||||
} else {
|
||||
printf("Verification succeeded\n");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
|
||||
TrustyKeymasterDevice device(NULL);
|
||||
if (device.session_error() != KM_ERROR_OK) {
|
||||
printf("Failed to initialize Trusty session: %d\n", device.session_error());
|
||||
return 1;
|
||||
}
|
||||
printf("Trusty session initialized\n");
|
||||
|
||||
bool success = true;
|
||||
success &= test_rsa(&device);
|
||||
success &= test_import_rsa(&device);
|
||||
success &= test_ecdsa(&device);
|
||||
success &= test_import_ecdsa(&device);
|
||||
|
||||
if (success) {
|
||||
printf("\nTESTS PASSED!\n");
|
||||
} else {
|
||||
printf("\n!!!!TESTS FAILED!!!\n");
|
||||
}
|
||||
|
||||
return success ? 0 : 1;
|
||||
}
|
Loading…
Reference in New Issue