@@ -4,3 +4,6 @@ | |||
[submodule "3rd/openssl"] | |||
path = 3rd/openssl | |||
url = https://github.com/openssl/openssl.git | |||
[submodule "3rd/gbench"] | |||
path = 3rd/gbench | |||
url = git@github.com:henrydcase/benchmark.git |
@@ -0,0 +1 @@ | |||
Subproject commit 048ddbb65d00a923d09be7e18616c09ac7153c29 |
@@ -17,6 +17,8 @@ set(OPENSSL_INCLUDE_DIR ${OPENSSL_BUILD_INSTALL_ROOT}/include) | |||
# ${OPENSSL_PREFIX_OPENSSLDIR} | |||
set(OPENSSL_PREFIX_OPENSSLDIR ${CMAKE_INSTALL_PREFIX}${PQSDK_INSTALL_DIR}/openssl) | |||
include(libdefs.cmake) | |||
set(OPENSSL_CONFIG_CMD "config" CACHE STRING "Command used to configure OpenSSL (default ./config)") | |||
set(OPENSSL_CONFIG_TARGET "" CACHE STRING "Platform for which OpenSSL should be compiled (default native)") | |||
message("OpenSSL root dir: ${OPENSSL_ROOT_DIR}") | |||
message("OpenSSL install dir: ${OPENSSL_BUILD_INSTALL_ROOT}") | |||
@@ -24,7 +26,7 @@ message("OpenSSL include dir: ${OPENSSL_INCLUDE_DIR}") | |||
message("OpenSSL crypto lib: ${OPENSSL_LIB_CRYPTO}") | |||
message("OpenSSL ssl lib: ${OPENSSL_LIB_SSL}") | |||
# TODO: add no-deprecated. Need to get rid of ERR_load_crypto_strings and OBJ_cleanup first | |||
set(OPENSSL_CONFIG_ARGS no-shared shared threads) | |||
set(OPENSSL_CONFIG_ARGS no-shared shared threads no-md2 no-md4 no-sm2 no-sm3 no-sm4) | |||
if(DEBUG) | |||
set(OPENSSL_CONFIG_ARGS ${OPENSSL_CONFIG_ARGS} -d -g3 -O0 no-asm -fno-omit-frame-pointer -fno-inline-functions) | |||
@@ -44,14 +46,14 @@ add_dependencies( | |||
ExternalProject_Add(OpenSSL | |||
SOURCE_DIR ${OPENSSL_ROOT_DIR} | |||
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/openssl-build | |||
CONFIGURE_COMMAND <SOURCE_DIR>/config -debug ${OPENSSL_CONFIG_ARGS} --prefix=${OPENSSL_PREFIX_OPENSSLDIR} --openssldir=${OPENSSL_PREFIX_OPENSSLDIR} --strict-warnings | |||
CONFIGURE_COMMAND <SOURCE_DIR>/${OPENSSL_CONFIG_CMD} ${OPENSSL_CONFIG_TARGET} ${OPENSSL_CONFIG_ARGS} --prefix=${OPENSSL_PREFIX_OPENSSLDIR} --openssldir=${OPENSSL_PREFIX_OPENSSLDIR} --strict-warnings | |||
BUILD_COMMAND ${MAKE_PROGRAM} CC=${CMAKE_C_COMPILER} CXX=${CMAKE_CXX_COMPILER} LD=${CMAKE_LINKER} | |||
INSTALL_DIR / | |||
INSTALL_COMMAND make DESTDIR=${OPENSSL_BUILD_INSTALL_ROOT} install | |||
) | |||
install(DIRECTORY ${OPENSSL_BUILD_INSTALL_ROOT}/${OPENSSL_PREFIX_OPENSSLDIR}/.. DESTINATION ${OPENSSL_PREFIX_OPENSSLDIR}) | |||
install(DIRECTORY ${OPENSSL_BUILD_INSTALL_ROOT}${OPENSSL_PREFIX_OPENSSLDIR}/bin/ DESTINATION | |||
${OPENSSL_PREFIX_OPENSSLDIR}/bin | |||
FILE_PERMISSIONS OWNER_EXECUTE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ) | |||
#install(DIRECTORY ${OPENSSL_BUILD_INSTALL_ROOT}/${OPENSSL_PREFIX_OPENSSLDIR}/.. DESTINATION ${OPENSSL_PREFIX_OPENSSLDIR}) | |||
#install(DIRECTORY ${OPENSSL_BUILD_INSTALL_ROOT}${OPENSSL_PREFIX_OPENSSLDIR}/bin/ DESTINATION | |||
# ${OPENSSL_PREFIX_OPENSSLDIR}/bin | |||
# FILE_PERMISSIONS OWNER_EXECUTE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ) | |||
set_property(GLOBAL PROPERTY openssl_build_dir_property ${OPENSSL_BUILD_DIR}) |
@@ -10,45 +10,36 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "~/.cmake/Modules") | |||
set(CMAKE_CXX_STANDARD 11) | |||
set(CMAKE_POSITION_INDEPENDENT_CODE ON) | |||
set(INSTALL_GTEST OFF CACHE BOOL "" FORCE) | |||
set(OPTEE_ENGINE_INSTALL_DIR /usr/local/softs) | |||
set(OPTEE_ENGINE_INSTALL_DIR /opt) | |||
# --- Configuration --- | |||
# Arch settings | |||
if(CMAKE_C_COMPILER_ID MATCHES "Clang") | |||
set(CLANG 1) | |||
# OP-TEE | |||
if (NOT OPTEE_BUILD_DIR) | |||
message(FATAL_ERROR "Must specify -DOPTEE_BUILD_DIR") | |||
endif() | |||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") | |||
set(CMAKE_C_COMPILER /usr/bin/cc CACHE PATH "" FORCE) | |||
set(CMAKE_CXX_COMPILER /usr/bin/c++ CACHE PATH "" FORCE) | |||
set(OPTEE_ENG_LD_FLAGS "-Wl") | |||
else() | |||
set(OPTEE_ENG_LD_FLAGS "-W") | |||
if (NOT PLATFORM) | |||
message(FATAL_ERROR "Must specify -DPLATFORM=V where V is either qemu or hikey960") | |||
endif() | |||
set(OPTEE_ROOT_DIR ${OPTEE_BUILD_DIR}) | |||
set(OPTEE_REE_LIB_DIR ${OPTEE_ROOT_DIR}/out-br/target/usr/lib) | |||
set(OPTEE_REE_INCLUDE_DIR ${OPTEE_ROOT_DIR}/optee_client/public) | |||
set(CMAKE_C_COMPILER ${OPTEE_ROOT_DIR}/toolchains/aarch64/bin/aarch64-linux-gnu-gcc CACHE PATH "" FORCE) | |||
set(CMAKE_CXX_COMPILER ${OPTEE_ROOT_DIR}/toolchains/aarch64/bin/aarch64-linux-gnu-g++ CACHE PATH "" FORCE) | |||
# Build OpenSSL if not provided, otherwise define | |||
# OpenSSL_ssl_shared and OpenSSL_crypto_shared | |||
if (BUILD_OPENSSL) | |||
add_subdirectory(3rd/openssl-cmake) | |||
else() | |||
if (NOT OPENSSL_INSTALL_DIR) | |||
message(FATAL_ERROR "Must specify -DOPENSSL_INSTALL_DIR") | |||
endif() | |||
set(OPENSSL_BUILD_INSTALL_ROOT ${OPENSSL_INSTALL_DIR}) | |||
set(OPENSSL_PREFIX_OPENSSLDIR ${CMAKE_INSTALL_PREFIX}${OPTEE_ENGINE_INSTALL_DIR}/openssl) | |||
include(3rd/openssl-cmake/libdefs.cmake) | |||
endif() | |||
# 3rd Parties | |||
# OpenSSL config targets | |||
set(OPENSSL_CONFIG_CMD "Configure" CACHE STRING "Command used to configure OpenSSL (default ./config)") | |||
set(OPENSSL_CONFIG_TARGET "linux-aarch64" CACHE STRING "Platform for which OpenSSL should be compiled (default native)") | |||
add_subdirectory(3rd/openssl-cmake) | |||
# Gtest | |||
add_subdirectory(3rd/gtest) | |||
get_property(OPENSSL_INSTALL_DIR GLOBAL PROPERTY openssl_build_install_dir_property) | |||
set(OPENSSL_INCLUDE_DIR ${OPENSSL_INSTALL_DIR}/include) | |||
# Trusted Application sources | |||
set(TA_DELEGATOR_ROOT ${CMAKE_SOURCE_DIR}/src/ta) | |||
# Build gtest | |||
add_subdirectory(3rd/gtest) | |||
# Global configuration | |||
set(C_CXX_FLAGS "\ | |||
-Wno-ignored-qualifiers \ | |||
@@ -60,12 +51,6 @@ set(C_CXX_FLAGS "\ | |||
-Wundef \ | |||
-Wunused-result") | |||
if(CLANG) | |||
set(C_CXX_FLAGS | |||
"-Wconditional-uninitialized \ | |||
-Wmissing-variable-declarations") | |||
endif() | |||
# Control Debug/Release mode | |||
IF(${CMAKE_BUILD_TYPE} MATCHES "Debug") | |||
set(C_CXX_FLAGS "${C_CXX_FLAGS} -g3 -O0 -Wno-unused") | |||
@@ -73,22 +58,8 @@ else() | |||
set(C_CXX_FLAGS "${C_CXX_FLAGS} -O3") | |||
endif() | |||
# Add possibility to build Client Application with ASAN | |||
if(ASAN) | |||
set(CLANG 1) | |||
set(C_CXX_FLAGS "${C_CXX_FLAGS} -fsanitize=undefined,address,leak -fno-omit-frame-pointer") | |||
set(LDFLAGS "${LDFLAGS} -fsanitize=undefined,address,leak") | |||
endif() | |||
set(CMAKE_C_FLAGS ${C_CXX_FLAGS}) | |||
set(CMAKE_CXX_FLAGS ${C_CXX_FLAGS}) | |||
if(CLANG) | |||
if(NOT CMAKE_C_COMPILER_ID MATCHES "Clang" OR NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") | |||
message(FATAL_ERROR "Clang required for this build") | |||
endif() | |||
set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wnewline-eof -fcolor-diagnostics") | |||
endif() | |||
# --- Build targets --- | |||
@@ -133,8 +104,99 @@ target_link_directories( | |||
target_link_libraries( | |||
optee_eng | |||
OpenSSL_crypto_shared | |||
teec | |||
${CMAKE_DL_LIBS}) | |||
IF(${CMAKE_BUILD_TYPE} MATCHES "Debug") | |||
target_compile_definitions(optee_eng PRIVATE BUILD_DEBUG) | |||
endif() | |||
# Key management app | |||
add_executable( | |||
optee_keymgnt | |||
src/optee_engine/keymgnt.c | |||
) | |||
target_include_directories( | |||
optee_keymgnt PRIVATE | |||
${OPENSSL_INCLUDE_DIR} | |||
${OPTEE_REE_INCLUDE_DIR} | |||
${TA_DELEGATOR_ROOT}/include) | |||
target_link_directories( | |||
optee_keymgnt PRIVATE | |||
${OPTEE_REE_LIB_DIR}) | |||
target_link_libraries( | |||
optee_keymgnt | |||
OpenSSL_crypto_shared | |||
teec | |||
${OPTEE_ENG_LD_FLAGS} | |||
${CMAKE_DL_LIBS}) | |||
ExternalProject_Add(optee_eng_ta | |||
SOURCE_DIR ${TA_DELEGATOR_ROOT} | |||
CONFIGURE_COMMAND "" | |||
BUILD_COMMAND OPTEE_ROOT=${OPTEE_BUILD_DIR} O=${CMAKE_CURRENT_BINARY_DIR} ${MAKE_PROGRAM} | |||
BUILD_IN_SOURCE TRUE | |||
INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/ta | |||
INSTALL_COMMAND "" | |||
BUILD_ALWAYS TRUE | |||
) | |||
# Google benchmark settings | |||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE) | |||
# Target for benchmark - it also builds gtest library | |||
set(BENCHMARK_ENABLE_GTEST_TESTS OFF CACHE BOOL "Enable testing of the benchmark library." FORCE) | |||
set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "Disable benchmark tests" FORCE) | |||
set(GOOGLETEST_PATH "${CMAKE_CURRENT_SOURCE_DIR}/3rd/gtest" CACHE PATH "Path to the gtest sources" FORCE) | |||
set(BENCHMARK_OS_WINDOWS OFF CACHE BOOL "" FORCE) | |||
set(HAVE_POSIX_REGEX OFF CACHE BOOL "" FORCE) | |||
set(BENCHMARK_ENABLE_EXCEPTIONS OFF CACHE BOOL "" FORCE) | |||
set(BENCHMARK_ENABLE_INSTALL OFF CACHE BOOL "" FORCE) | |||
add_subdirectory(3rd/gbench) | |||
add_executable( | |||
speed | |||
src/optee_engine/speed.cc) | |||
target_include_directories( | |||
speed PRIVATE | |||
${OPENSSL_INCLUDE_DIR} | |||
) | |||
target_link_libraries( | |||
speed | |||
gtest | |||
pthread | |||
OpenSSL_crypto_shared | |||
benchmark::benchmark) | |||
# Install copies needed files to the buildroot overlay. | |||
# OpenVPN config | |||
install(FILES ${PROJECT_SOURCE_DIR}/cfg/openvpn_cli.conf | |||
DESTINATION ${OPTEE_ROOT_DIR}/build/br-ext/board/${PLATFORM}/overlay/etc/openvpn/ | |||
RENAME client.conf) | |||
install(FILES | |||
${PROJECT_SOURCE_DIR}/cfg/certs/ca.cert | |||
${PROJECT_SOURCE_DIR}/cfg/certs/client.cert | |||
${PROJECT_SOURCE_DIR}/cfg/certs/client.key | |||
DESTINATION ${OPTEE_ROOT_DIR}/build/br-ext/board/${PLATFORM}/overlay/etc/openvpn/certs/) | |||
# OpenSSL config | |||
install(FILES ${PROJECT_SOURCE_DIR}/cfg/openssl_optee.cnf | |||
DESTINATION ${OPTEE_ROOT_DIR}/build/br-ext/board/${PLATFORM}/overlay/etc/ssl/ | |||
RENAME openssl.cnf) | |||
# OpTEE engine | |||
install(TARGETS optee_eng | |||
LIBRARY DESTINATION ${OPTEE_ROOT_DIR}/build/br-ext/board/${PLATFORM}/overlay/opt/ | |||
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) | |||
# TA | |||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/8aaaf200-2450-11e4-0060-0dc0ffee0000.ta | |||
DESTINATION ${OPTEE_ROOT_DIR}/build/br-ext/board/${PLATFORM}/overlay/lib/optee_armtz) | |||
# Must be empty and have same name as the TEE key ID | |||
install(FILES /dev/null | |||
DESTINATION ${OPTEE_ROOT_DIR}/build/br-ext/board/${PLATFORM}/overlay/etc/openvpn/ | |||
RENAME vpn.testlab.com) | |||
# Key management app | |||
install(TARGETS optee_keymgnt | |||
RUNTIME DESTINATION ${OPTEE_ROOT_DIR}/build/br-ext/board/${PLATFORM}/overlay/usr/bin/ | |||
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ WORLD_READ) | |||
# Speed app | |||
install(TARGETS speed | |||
RUNTIME DESTINATION ${OPTEE_ROOT_DIR}/build/br-ext/board/${PLATFORM}/overlay/usr/bin/ | |||
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ WORLD_READ) |
@@ -0,0 +1,9 @@ | |||
# OPTEE OpenSSL ENGINE for TLS | |||
Typically, a TLS server uses an X509 Certificate and associated Private Key to sign TLS session. Both certificate and private key used for signing the certificate form an asymmetric cryptographic key-pair. Revealing the traffic-private-key makes it possible to perform men-in-the-middle type of attacks. Typically private-key is stored on the server’s hard disk. Even if it is stored in encrypted form, at some point HTTPS server needs to have a possibility to decrypt it to use for signing. It means that at runtime the key in the plaintext will be available in memory of an HTTPS process. In the case of software errors, attackers may be able to steal a private key (see [Heartbleed](https://heartbleed.com/)). From the other hand, in multiple domains, there is a need for binding of secret keys to the hardware on which software is running comes with multiple (IoT devices, software deployments on the edge networks). | |||
Secure Trusted Execution Environments may address those needs. The repository provides a PoC implementation of Trusted Application that can be run in the ARM's TrustZone and be used for storing secret key of a TLS server as well as perform signing operation with that key. The implementation uses [OPTEE](https://www.op-tee.org/) as an implementation of the TEE. The secret key is stored in the encrypted form on secure storage. The secure storage is encrypted with device Device Unique Key (HUK) and hence it can be only used by any other hardware after being copied from one device to the other. | |||
The plugin to OpenSSL provides integration between Trusted Application running in Trust Zone and TLS stack. Namely, the plugin implements OpenSSL ENGINE API and hence it can be dynamically loaded by OpenSSL, eliminating a need to modify OpenSSL source code. | |||
The idea was initially described on a blog [here](https://www.amongbytes.com/post/201904-tee-sign-delegator/). The main improvement provided by software in this repository is the implementation of the OpenSSL plugin. |
@@ -0,0 +1 @@ | |||
server.cert |
@@ -0,0 +1,13 @@ | |||
-----BEGIN CERTIFICATE----- | |||
MIIB4jCCAYegAwIBAgIUUAWISiMN6taMN9o92ZeCmvF/hWEwCgYIKoZIzj0EAwIw | |||
PjElMCMGA1UECgwcQW1vbmcgQnl0ZXMsIHZwbi50ZXN0bGFiLmNvbTEVMBMGA1UE | |||
AwwMUm9vdCBDZXJ0IEcxMB4XDTIxMDIwNzIzNDQ0NFoXDTQ4MDYyNDIzNDQ0NFow | |||
PjElMCMGA1UECgwcQW1vbmcgQnl0ZXMsIHZwbi50ZXN0bGFiLmNvbTEVMBMGA1UE | |||
AwwMUm9vdCBDZXJ0IEcxMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELti1AngN | |||
Z5mpgfL/IEfwP4d28l5qqj3qagHproif80C0L7mkGmseO7gdLQHyU7UlelGxAFZD | |||
vC4NOufG2c6fS6NjMGEwHQYDVR0OBBYEFI+sqwD8xeuHR2qtcnS/hBPfUA4vMB8G | |||
A1UdIwQYMBaAFI+sqwD8xeuHR2qtcnS/hBPfUA4vMA8GA1UdEwEB/wQFMAMBAf8w | |||
DgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA0kAMEYCIQCn4bViwS6ALu7HtXjp | |||
SaEJgkSjLj/Fw/5/XohAx/ta/QIhAJrdETBDyaqN7kZjT3mI12vOb1vdA2oHYCZw | |||
OsL1I5yO | |||
-----END CERTIFICATE----- |
@@ -0,0 +1,8 @@ | |||
-----BEGIN EC PARAMETERS----- | |||
BggqhkjOPQMBBw== | |||
-----END EC PARAMETERS----- | |||
-----BEGIN EC PRIVATE KEY----- | |||
MHcCAQEEIM2kewhtexp7AZonkZqAYKk4pNTImjxDpX5GeGxkb0IDoAoGCCqGSM49 | |||
AwEHoUQDQgAELti1AngNZ5mpgfL/IEfwP4d28l5qqj3qagHproif80C0L7mkGmse | |||
O7gdLQHyU7UlelGxAFZDvC4NOufG2c6fSw== | |||
-----END EC PRIVATE KEY----- |
@@ -0,0 +1 @@ | |||
725588E0FAE750D03BC5D4B1254454A2C85ECBBB |
@@ -0,0 +1,14 @@ | |||
-----BEGIN CERTIFICATE----- | |||
MIICNTCCAdygAwIBAgIUclWI4PrnUNA7xdSxJURUoshey7swCgYIKoZIzj0EAwIw | |||
PjElMCMGA1UECgwcQW1vbmcgQnl0ZXMsIHZwbi50ZXN0bGFiLmNvbTEVMBMGA1UE | |||
AwwMUm9vdCBDZXJ0IEcxMB4XDTIxMDIwNzIzNDQ0NFoXDTQ4MDYyNDIzNDQ0NFow | |||
MTEZMBcGA1UECgwQQ2VydCBUZXN0aW5nIE9SRzEUMBIGA1UEAwwLQ2xpZW50IENl | |||
cnQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQU41Tkm38N15yBrlUdrrIhcfXO | |||
aav9SY+OHoEYpR6FvZvvhEtmSLMe0tBlXLq/SBwWDERMwCb4ksnMYuRk81wko4HE | |||
MIHBMAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgWgMDIGCWCGSAGG+EIBDQQl | |||
FiNBbW9uZyBCeXRlcywgTGFiIFRlc3RuZywgVExTIENsaWVudDAdBgNVHQ4EFgQU | |||
TfNbUInWGruGey7vUaXiWdZUBIcwHwYDVR0jBBgwFoAUj6yrAPzF64dHaq1ydL+E | |||
E99QDi8wDgYDVR0PAQH/BAQDAgXgMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF | |||
BQcDBDAKBggqhkjOPQQDAgNHADBEAiAaN2sorsRKG9GeEcqUSag/FS+cRVt70vG/ | |||
AN+3XKlmeAIgKKSwTm8JuHYJO1bHQzVBJOFtjQQvc1NINEE3yIvTc6M= | |||
-----END CERTIFICATE----- |
@@ -0,0 +1,7 @@ | |||
-----BEGIN CERTIFICATE REQUEST----- | |||
MIHsMIGTAgEAMDExGTAXBgNVBAoMEENlcnQgVGVzdGluZyBPUkcxFDASBgNVBAMM | |||
C0NsaWVudCBDZXJ0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFONU5Jt/Ddec | |||
ga5VHa6yIXH1zmmr/UmPjh6BGKUehb2b74RLZkizHtLQZVy6v0gcFgxETMAm+JLJ | |||
zGLkZPNcJKAAMAoGCCqGSM49BAMCA0gAMEUCIQCvWl41LYMmGyfsGMKoNrc3kXac | |||
4/vTZbt/3F5N3MnfIAIgKhkxJ8K8leLqsUnasAINKqV7goVXdOncZXFZWB3Z/zs= | |||
-----END CERTIFICATE REQUEST----- |
@@ -0,0 +1,8 @@ | |||
-----BEGIN EC PARAMETERS----- | |||
BggqhkjOPQMBBw== | |||
-----END EC PARAMETERS----- | |||
-----BEGIN EC PRIVATE KEY----- | |||
MHcCAQEEINy9shU4Xzqh+R47QxCvTFkaAWK5V35J1ynaPU29LlRKoAoGCCqGSM49 | |||
AwEHoUQDQgAEFONU5Jt/Ddecga5VHa6yIXH1zmmr/UmPjh6BGKUehb2b74RLZkiz | |||
HtLQZVy6v0gcFgxETMAm+JLJzGLkZPNcJA== | |||
-----END EC PRIVATE KEY----- |
@@ -0,0 +1 @@ | |||
ca.cert |
@@ -0,0 +1,18 @@ | |||
-----BEGIN CERTIFICATE----- | |||
MIIC0TCCAnegAwIBAgIUclWI4PrnUNA7xdSxJURUoshey7owCgYIKoZIzj0EAwIw | |||
PjElMCMGA1UECgwcQW1vbmcgQnl0ZXMsIHZwbi50ZXN0bGFiLmNvbTEVMBMGA1UE | |||
AwwMUm9vdCBDZXJ0IEcxMB4XDTIxMDIwNzIzNDQ0NFoXDTQ4MDYyNDIzNDQ0NFow | |||
NTEZMBcGA1UECgwQQ2VydCBUZXN0aW5nIE9SRzEYMBYGA1UEAwwPdnBuLnRlc3Rs | |||
YWIuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEQKMXJu5XByLVq1Mo7oek | |||
MzDLQWBulUcDH6CXxXJSRVDOHapNMTNsjEIzLvManD7tXRaxDNINXvAJ/ze6eA+0 | |||
FaOCAVowggFWMAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgZAMDIGCWCGSAGG | |||
+EIBDQQlFiNBbW9uZyBCeXRlcywgTGFiIFRlc3RuZywgVExTIFNlcnZlcjAdBgNV | |||
HQ4EFgQUFzD2JhWfK/YeOd9Yd5h9aONsFigweQYDVR0jBHIwcIAUj6yrAPzF64dH | |||
aq1ydL+EE99QDi+hQqRAMD4xJTAjBgNVBAoMHEFtb25nIEJ5dGVzLCB2cG4udGVz | |||
dGxhYi5jb20xFTATBgNVBAMMDFJvb3QgQ2VydCBHMYIUUAWISiMN6taMN9o92ZeC | |||
mvF/hWEwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMEMGA1Ud | |||
EQQ8MDqCDXd3dy5wcXNkay5jb22CDWlvdC5wcXNkay5jb22CDXZwbi5wcXNkay5j | |||
b22CCyoucHFzZGsuY29tMAoGCCqGSM49BAMCA0gAMEUCIQDKpmDVh3TTkojSMDLV | |||
Fzq6kk7RSvD48lG2FTMwWtE0NAIgdPeRd9DQcuCBCT8/kHxevfcoBXI60o5MVpNo | |||
sY8hFVo= | |||
-----END CERTIFICATE----- |
@@ -0,0 +1,8 @@ | |||
-----BEGIN CERTIFICATE REQUEST----- | |||
MIHwMIGXAgEAMDUxGTAXBgNVBAoMEENlcnQgVGVzdGluZyBPUkcxGDAWBgNVBAMM | |||
D3Zwbi50ZXN0bGFiLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABECjFybu | |||
Vwci1atTKO6HpDMwy0FgbpVHAx+gl8VyUkVQzh2qTTEzbIxCMy7zGpw+7V0WsQzS | |||
DV7wCf83ungPtBWgADAKBggqhkjOPQQDAgNIADBFAiEAwoYmOPkC6fHjInldqob/ | |||
sIkBNQoQG3IG50JZNaXDQ94CIByydf2CoqABEjMJ49/YhgikQ8Cp88qw23M0uCdZ | |||
avEs | |||
-----END CERTIFICATE REQUEST----- |
@@ -0,0 +1,8 @@ | |||
-----BEGIN EC PARAMETERS----- | |||
BggqhkjOPQMBBw== | |||
-----END EC PARAMETERS----- | |||
-----BEGIN EC PRIVATE KEY----- | |||
MHcCAQEEIGS/md9a764Wd2z6+eaIpT+c4pcxMOPY5+KCeZ88xdbEoAoGCCqGSM49 | |||
AwEHoUQDQgAEQKMXJu5XByLVq1Mo7oekMzDLQWBulUcDH6CXxXJSRVDOHapNMTNs | |||
jEIzLvManD7tXRaxDNINXvAJ/ze6eA+0FQ== | |||
-----END EC PRIVATE KEY----- |
@@ -0,0 +1,83 @@ | |||
#!/bin/sh | |||
# Re-creates certificates for server and client VPN | |||
OPENSSL_BIN=openssl | |||
OPENSSL_REHASH_BIN=c_rehash | |||
TMP_DIR=certs | |||
set -x | |||
create_openvpn_pki() | |||
{ | |||
# Create CA key and certificate | |||
${OPENSSL_BIN} ecparam \ | |||
-name secp256r1 \ | |||
-genkey \ | |||
-out ${TMP_DIR}/ca.key || exit; | |||
${OPENSSL_BIN} req \ | |||
-new \ | |||
-config openssl.cnf \ | |||
-x509 \ | |||
-extensions v3_ca \ | |||
-key ${TMP_DIR}/ca.key \ | |||
-out ${TMP_DIR}/ca.cert \ | |||
-days 9999 \ | |||
-subj "/O=Among Bytes, vpn.testlab.com/CN=Root Cert G1" \ | |||
-batch || exit; | |||
# Create server certificate | |||
${OPENSSL_BIN} ecparam \ | |||
-name secp256r1 \ | |||
-genkey \ | |||
-out ${TMP_DIR}/server.key || exit; | |||
${OPENSSL_BIN} req \ | |||
-new \ | |||
-config openssl.cnf \ | |||
-key ${TMP_DIR}/server.key \ | |||
-out ${TMP_DIR}/server.csr \ | |||
-subj "/O=Cert Testing ORG/CN=vpn.testlab.com" \ | |||
-batch || exit; | |||
${OPENSSL_BIN} x509 \ | |||
-extfile openssl.cnf \ | |||
-extensions server_cert \ | |||
-req \ | |||
-CA ${TMP_DIR}/ca.cert \ | |||
-CAkey ${TMP_DIR}/ca.key \ | |||
-CAcreateserial \ | |||
-in ${TMP_DIR}/server.csr \ | |||
-out ${TMP_DIR}/server.cert \ | |||
-days 9999 || exit; | |||
OPENSSL=${OPENSSL_BIN} ${OPENSSL_REHASH_BIN} ${TMP_DIR} | |||
${OPENSSL_BIN} verify \ | |||
-CApath ${TMP_DIR} \ | |||
${TMP_DIR}/server.cert || exit; | |||
# Create client certificate | |||
${OPENSSL_BIN} ecparam \ | |||
-name secp256r1 \ | |||
-genkey \ | |||
-out ${TMP_DIR}/client.key || exit; | |||
${OPENSSL_BIN} req \ | |||
-new \ | |||
-config openssl.cnf \ | |||
-key ${TMP_DIR}/client.key \ | |||
-out ${TMP_DIR}/client.csr \ | |||
-subj "/O=Cert Testing ORG/CN=Client Cert" \ | |||
-batch || exit; | |||
${OPENSSL_BIN} x509 \ | |||
-extfile openssl.cnf \ | |||
-extensions client_cert \ | |||
-req \ | |||
-CA ${TMP_DIR}/ca.cert \ | |||
-CAkey ${TMP_DIR}/ca.key \ | |||
-CAcreateserial \ | |||
-in ${TMP_DIR}/client.csr \ | |||
-out ${TMP_DIR}/client.cert \ | |||
-days 9999 || exit; | |||
${OPENSSL_BIN} verify \ | |||
-CApath ${TMP_DIR}/ \ | |||
${TMP_DIR}/client.cert || exit; | |||
} | |||
rm -rf ${TMP_DIR} | |||
mkdir -p ${TMP_DIR} | |||
create_openvpn_pki |
@@ -0,0 +1,137 @@ | |||
[ ca ] | |||
# `man ca` | |||
default_ca = CA_default | |||
[ CA_default ] | |||
# Directory and file locations. | |||
dir = . | |||
certs = $dir/certs | |||
crl_dir = $dir/crl | |||
new_certs_dir = $dir/newcerts | |||
database = $dir/index.txt | |||
serial = $dir/serial | |||
RANDFILE = $dir/private/.rand | |||
# The root key and root certificate. | |||
private_key = $dir/root.key | |||
certificate = $dir/root.pem | |||
# For certificate revocation lists. | |||
crlnumber = $dir/crlnumber | |||
crl = $dir/crl/intermediate.crl.pem | |||
crl_extensions = crl_ext | |||
default_crl_days = 30 | |||
# SHA-1 is deprecated, so use SHA-2 instead. | |||
default_md = sha256 | |||
name_opt = ca_default | |||
cert_opt = ca_default | |||
default_days = 9999 | |||
preserve = no | |||
policy = policy_loose | |||
[ policy_strict ] | |||
# The root CA should only sign intermediate certificates that match. | |||
# See the POLICY FORMAT section of `man ca`. | |||
countryName = match | |||
stateOrProvinceName = match | |||
organizationName = match | |||
organizationalUnitName = optional | |||
commonName = supplied | |||
emailAddress = optional | |||
[ policy_loose ] | |||
# Allow the intermediate CA to sign a more diverse range of certificates. | |||
# See the POLICY FORMAT section of the `ca` man page. | |||
countryName = optional | |||
stateOrProvinceName = optional | |||
localityName = optional | |||
organizationName = optional | |||
organizationalUnitName = optional | |||
commonName = supplied | |||
emailAddress = optional | |||
[ req ] | |||
# Options for the `req` tool (`man req`). | |||
default_bits = 4096 | |||
distinguished_name = req_distinguished_name | |||
string_mask = utf8only | |||
[ req_distinguished_name ] | |||
countryName = Country Name (2 letter code) | |||
stateOrProvinceName = State or Province Name (full name) | |||
localityName = Locality Name (eg, city) | |||
organizationalUnitName = Organizational Unit Name (eg, section) | |||
commonName = Common Name | |||
stateOrProvinceName_default = City of London | |||
countryName_default = UK | |||
localityName_default = London | |||
organizationalUnitName_default = Among Bytes, Lab Testng | |||
commonName_default = www.pqsdk.com | |||
commonName_max = 64 | |||
[ v3_ca ] | |||
# Extensions for a typical CA (`man x509v3_config`). | |||
subjectKeyIdentifier = hash | |||
authorityKeyIdentifier = keyid:always,issuer | |||
basicConstraints = critical, CA:true | |||
keyUsage = critical, digitalSignature, cRLSign, keyCertSign | |||
[ v3_intermediate_ca ] | |||
# Extensions for a typical intermediate CA (`man x509v3_config`). | |||
subjectKeyIdentifier = hash | |||
authorityKeyIdentifier = keyid:always,issuer | |||
basicConstraints = critical, CA:true | |||
keyUsage = critical, digitalSignature, cRLSign, keyCertSign | |||
extendedKeyUsage = serverAuth, clientAuth | |||
[ usr_cert ] | |||
# Extensions for client certificates (`man x509v3_config`). | |||
basicConstraints = CA:FALSE | |||
nsCertType = client, email | |||
nsComment = 'Among Bytes, Lab Testng, Intermediate Cert' | |||
subjectKeyIdentifier = hash | |||
authorityKeyIdentifier = keyid,issuer | |||
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment | |||
extendedKeyUsage = clientAuth, emailProtection | |||
[ server_cert ] | |||
# Extensions for server certificates (`man x509v3_config`). | |||
basicConstraints = CA:FALSE | |||
nsCertType = server | |||
nsComment = 'Among Bytes, Lab Testng, TLS Server' | |||
subjectKeyIdentifier = hash | |||
authorityKeyIdentifier = keyid,issuer:always | |||
keyUsage = critical, digitalSignature, keyEncipherment | |||
extendedKeyUsage = serverAuth | |||
subjectAltName = @alt_names | |||
[ client_cert ] | |||
# Extensions for server certificates (`man x509v3_config`). | |||
basicConstraints = CA:FALSE | |||
nsCertType = client, email | |||
nsComment = 'Among Bytes, Lab Testng, TLS Client' | |||
subjectKeyIdentifier = hash | |||
authorityKeyIdentifier = keyid,issuer | |||
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment | |||
extendedKeyUsage = clientAuth, emailProtection | |||
[ crl_ext ] | |||
# Extension for CRLs (`man x509v3_config`). | |||
authorityKeyIdentifier = keyid:always | |||
[ ocsp ] | |||
# Extension for OCSP signing certificates (`man ocsp`). | |||
basicConstraints = CA:FALSE | |||
subjectKeyIdentifier = hash | |||
authorityKeyIdentifier = keyid,issuer | |||
keyUsage = critical, digitalSignature | |||
extendedKeyUsage = critical, OCSPSigning | |||
[alt_names] | |||
DNS.1 = www.pqsdk.com | |||
DNS.2 = iot.pqsdk.com | |||
DNS.3 = vpn.pqsdk.com | |||
DNS.4 = *.pqsdk.com |
@@ -0,0 +1,366 @@ | |||
# | |||
# OpenSSL example configuration file. | |||
# This is mostly being used for generation of certificate requests. | |||
# | |||
# Note that you can include other files from the main configuration | |||
# file using the .include directive. | |||
#.include filename | |||
# This definition stops the following lines choking if HOME isn't | |||
# defined. | |||
HOME = . | |||
# Extra OBJECT IDENTIFIER info: | |||
#oid_file = $ENV::HOME/.oid | |||
oid_section = new_oids | |||
# System default | |||
openssl_conf = default_conf | |||
# To use this configuration file with the "-extfile" option of the | |||
# "openssl x509" utility, name here the section containing the | |||
# X.509v3 extensions to use: | |||
# extensions = | |||
# (Alternatively, use a configuration file that has only | |||
# X.509v3 extensions in its main [= default] section.) | |||
[ new_oids ] | |||
# We can add new OIDs in here for use by 'ca', 'req' and 'ts'. | |||
# Add a simple OID like this: | |||
# testoid1=1.2.3.4 | |||
# Or use config file substitution like this: | |||
# testoid2=${testoid1}.5.6 | |||
# Policies used by the TSA examples. | |||
tsa_policy1 = 1.2.3.4.1 | |||
tsa_policy2 = 1.2.3.4.5.6 | |||
tsa_policy3 = 1.2.3.4.5.7 | |||
#################################################################### | |||
[ ca ] | |||
default_ca = CA_default # The default ca section | |||
#################################################################### | |||
[ CA_default ] | |||
dir = /etc/ssl # Where everything is kept | |||
certs = $dir/certs # Where the issued certs are kept | |||
crl_dir = $dir/crl # Where the issued crl are kept | |||
database = $dir/index.txt # database index file. | |||
#unique_subject = no # Set to 'no' to allow creation of | |||
# several certs with same subject. | |||
new_certs_dir = $dir/newcerts # default place for new certs. | |||
certificate = $dir/cacert.pem # The CA certificate | |||
serial = $dir/serial # The current serial number | |||
crlnumber = $dir/crlnumber # the current crl number | |||
# must be commented out to leave a V1 CRL | |||
crl = $dir/crl.pem # The current CRL | |||
private_key = $dir/private/cakey.pem# The private key | |||
x509_extensions = usr_cert # The extensions to add to the cert | |||
# Comment out the following two lines for the "traditional" | |||
# (and highly broken) format. | |||
name_opt = ca_default # Subject Name options | |||
cert_opt = ca_default # Certificate field options | |||
# Extension copying option: use with caution. | |||
# copy_extensions = copy | |||
# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs | |||
# so this is commented out by default to leave a V1 CRL. | |||
# crlnumber must also be commented out to leave a V1 CRL. | |||
# crl_extensions = crl_ext | |||
default_days = 365 # how long to certify for | |||
default_crl_days= 30 # how long before next CRL | |||
default_md = default # use public key default MD | |||
preserve = no # keep passed DN ordering | |||
# A few difference way of specifying how similar the request should look | |||
# For type CA, the listed attributes must be the same, and the optional | |||
# and supplied fields are just that :-) | |||
policy = policy_match | |||
# For the CA policy | |||
[ policy_match ] | |||
countryName = match | |||
stateOrProvinceName = match | |||
organizationName = match | |||
organizationalUnitName = optional | |||
commonName = supplied | |||
emailAddress = optional | |||
# For the 'anything' policy | |||
# At this point in time, you must list all acceptable 'object' | |||
# types. | |||
[ policy_anything ] | |||
countryName = optional | |||
stateOrProvinceName = optional | |||
localityName = optional | |||
organizationName = optional | |||
organizationalUnitName = optional | |||
commonName = supplied | |||
emailAddress = optional | |||
#################################################################### | |||
[ req ] | |||
default_bits = 2048 | |||
default_keyfile = privkey.pem | |||
distinguished_name = req_distinguished_name | |||
attributes = req_attributes | |||
x509_extensions = v3_ca # The extensions to add to the self signed cert | |||
# Passwords for private keys if not present they will be prompted for | |||
# input_password = secret | |||
# output_password = secret | |||
# This sets a mask for permitted string types. There are several options. | |||
# default: PrintableString, T61String, BMPString. | |||
# pkix : PrintableString, BMPString (PKIX recommendation before 2004) | |||
# utf8only: only UTF8Strings (PKIX recommendation after 2004). | |||
# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). | |||
# MASK:XXXX a literal mask value. | |||
# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. | |||
string_mask = utf8only | |||
# req_extensions = v3_req # The extensions to add to a certificate request | |||
[ req_distinguished_name ] | |||
countryName = Country Name (2 letter code) | |||
countryName_default = AU | |||
countryName_min = 2 | |||
countryName_max = 2 | |||
stateOrProvinceName = State or Province Name (full name) | |||
stateOrProvinceName_default = Some-State | |||
localityName = Locality Name (eg, city) | |||
0.organizationName = Organization Name (eg, company) | |||
0.organizationName_default = Internet Widgits Pty Ltd | |||
# we can do this but it is not needed normally :-) | |||
#1.organizationName = Second Organization Name (eg, company) | |||
#1.organizationName_default = World Wide Web Pty Ltd | |||
organizationalUnitName = Organizational Unit Name (eg, section) | |||
#organizationalUnitName_default = | |||
commonName = Common Name (e.g. server FQDN or YOUR name) | |||
commonName_max = 64 | |||
emailAddress = Email Address | |||
emailAddress_max = 64 | |||
# SET-ex3 = SET extension number 3 | |||
[ req_attributes ] | |||
challengePassword = A challenge password | |||
challengePassword_min = 4 | |||
challengePassword_max = 20 | |||
unstructuredName = An optional company name | |||
[ usr_cert ] | |||
# These extensions are added when 'ca' signs a request. | |||
# This goes against PKIX guidelines but some CAs do it and some software | |||
# requires this to avoid interpreting an end user certificate as a CA. | |||
basicConstraints=CA:FALSE | |||
# Here are some examples of the usage of nsCertType. If it is omitted | |||
# the certificate can be used for anything *except* object signing. | |||
# This is OK for an SSL server. | |||
# nsCertType = server | |||
# For an object signing certificate this would be used. | |||
# nsCertType = objsign | |||
# For normal client use this is typical | |||
# nsCertType = client, email | |||
# and for everything including object signing: | |||
# nsCertType = client, email, objsign | |||
# This is typical in keyUsage for a client certificate. | |||
# keyUsage = nonRepudiation, digitalSignature, keyEncipherment | |||
# This will be displayed in Netscape's comment listbox. | |||
nsComment = "OpenSSL Generated Certificate" | |||
# PKIX recommendations harmless if included in all certificates. | |||
subjectKeyIdentifier=hash | |||
authorityKeyIdentifier=keyid,issuer | |||
# This stuff is for subjectAltName and issuerAltname. | |||
# Import the email address. | |||
# subjectAltName=email:copy | |||
# An alternative to produce certificates that aren't | |||
# deprecated according to PKIX. | |||
# subjectAltName=email:move | |||
# Copy subject details | |||
# issuerAltName=issuer:copy | |||
#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem | |||
#nsBaseUrl | |||
#nsRevocationUrl | |||
#nsRenewalUrl | |||
#nsCaPolicyUrl | |||
#nsSslServerName | |||
# This is required for TSA certificates. | |||
# extendedKeyUsage = critical,timeStamping | |||
[ v3_req ] | |||
# Extensions to add to a certificate request | |||
basicConstraints = CA:FALSE | |||
keyUsage = nonRepudiation, digitalSignature, keyEncipherment | |||
[ v3_ca ] | |||
# Extensions for a typical CA | |||
# PKIX recommendation. | |||
subjectKeyIdentifier=hash | |||
authorityKeyIdentifier=keyid:always,issuer | |||
basicConstraints = critical,CA:true | |||
# Key usage: this is typical for a CA certificate. However since it will | |||
# prevent it being used as an test self-signed certificate it is best | |||
# left out by default. | |||
# keyUsage = cRLSign, keyCertSign | |||
# Some might want this also | |||
# nsCertType = sslCA, emailCA | |||
# Include email address in subject alt name: another PKIX recommendation | |||
# subjectAltName=email:copy | |||
# Copy issuer details | |||
# issuerAltName=issuer:copy | |||
# DER hex encoding of an extension: beware experts only! | |||
# obj=DER:02:03 | |||
# Where 'obj' is a standard or added object | |||
# You can even override a supported extension: | |||
# basicConstraints= critical, DER:30:03:01:01:FF | |||
[ crl_ext ] | |||
# CRL extensions. | |||
# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. | |||
# issuerAltName=issuer:copy | |||
authorityKeyIdentifier=keyid:always | |||
[ proxy_cert_ext ] | |||
# These extensions should be added when creating a proxy certificate | |||
# This goes against PKIX guidelines but some CAs do it and some software | |||
# requires this to avoid interpreting an end user certificate as a CA. | |||
basicConstraints=CA:FALSE | |||
# Here are some examples of the usage of nsCertType. If it is omitted | |||
# the certificate can be used for anything *except* object signing. | |||
# This is OK for an SSL server. | |||
# nsCertType = server | |||
# For an object signing certificate this would be used. | |||
# nsCertType = objsign | |||
# For normal client use this is typical | |||
# nsCertType = client, email | |||
# and for everything including object signing: | |||
# nsCertType = client, email, objsign | |||
# This is typical in keyUsage for a client certificate. | |||
# keyUsage = nonRepudiation, digitalSignature, keyEncipherment | |||
# This will be displayed in Netscape's comment listbox. | |||
nsComment = "OpenSSL Generated Certificate" | |||
# PKIX recommendations harmless if included in all certificates. | |||
subjectKeyIdentifier=hash | |||
authorityKeyIdentifier=keyid,issuer | |||
# This stuff is for subjectAltName and issuerAltname. | |||
# Import the email address. | |||
# subjectAltName=email:copy | |||
# An alternative to produce certificates that aren't | |||
# deprecated according to PKIX. | |||
# subjectAltName=email:move | |||
# Copy subject details | |||
# issuerAltName=issuer:copy | |||
#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem | |||
#nsBaseUrl | |||
#nsRevocationUrl | |||
#nsRenewalUrl | |||
#nsCaPolicyUrl | |||
#nsSslServerName | |||
# This really needs to be in place for it to be a proxy certificate. | |||
proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo | |||
#################################################################### | |||
[ tsa ] | |||
default_tsa = tsa_config1 # the default TSA section | |||
[ tsa_config1 ] | |||
# These are used by the TSA reply generation only. | |||
dir = /etc/ssl # TSA root directory | |||
serial = $dir/tsaserial # The current serial number (mandatory) | |||
crypto_device = builtin # OpenSSL engine to use for signing | |||
signer_cert = $dir/tsacert.pem # The TSA signing certificate | |||
# (optional) | |||
certs = $dir/cacert.pem # Certificate chain to include in reply | |||
# (optional) | |||
signer_key = $dir/private/tsakey.pem # The TSA private key (optional) | |||
signer_digest = sha256 # Signing digest to use. (Optional) | |||
default_policy = tsa_policy1 # Policy if request did not specify it | |||
# (optional) | |||
other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) | |||
digests = sha1, sha256, sha384, sha512 # Acceptable message digests (mandatory) | |||
accuracy = secs:1, millisecs:500, microsecs:100 # (optional) | |||
clock_precision_digits = 0 # number of digits after dot. (optional) | |||
ordering = yes # Is ordering defined for timestamps? | |||
# (optional, default: no) | |||
tsa_name = yes # Must the TSA name be included in the reply? | |||
# (optional, default: no) | |||
ess_cert_id_chain = no # Must the ESS cert id chain be included? | |||
# (optional, default: no) | |||
ess_cert_id_alg = sha1 # algorithm to compute certificate | |||
# identifier (optional, default: sha1) | |||
# | |||
# | |||
[default_conf] | |||
engines = engine_section | |||
[engine_section] | |||
optee = optee_section | |||
[optee_section] | |||
engine_id = optee | |||
dynamic_path = /opt/liboptee_eng.so | |||
init = 1 |
@@ -0,0 +1,22 @@ | |||
client | |||
proto udp4 | |||
# Deliberatelly same IP as tun0 on a host system, to easily connect from QEMU | |||
remote 172.16.0.1 1194 | |||
# remote vpn.testlab.com 1194 | |||
dev tun | |||
resolv-retry infinite | |||
nobind | |||
dh none | |||
remote-cert-tls server | |||
cipher AES-256-GCM | |||
persist-key | |||
persist-tun | |||
verb 3 | |||
# Certificates | |||
ca certs/ca.cert | |||
cert certs/client.cert | |||
key vpn.testlab.com | |||
# Load 'optee' engine, to perform private key operation in the TEE | |||
engine optee |
@@ -0,0 +1,19 @@ | |||
port 1194 | |||
proto udp4 | |||
dev tun | |||
dh none | |||
topology subnet | |||
server 172.16.0.0 255.255.0.0 | |||
ifconfig-pool-persist ipp.txt | |||
keepalive 10 120 | |||
cipher AES-256-GCM | |||
persist-key | |||
persist-tun | |||
status openvpn-status.log | |||
verb 1 | |||
explicit-exit-notify 1 | |||
# Certificates | |||
ca certs/ca.cert | |||
cert certs/server.cert | |||
key certs/server.key |
@@ -0,0 +1,35 @@ | |||
From ff9a4702a79d2e10156f5ce748a542b98abfae4d Mon Sep 17 00:00:00 2001 | |||
From: Kris Kwiatkowski <contact@amongbytes.com> | |||
Date: Wed, 13 Jan 2021 15:44:20 +0000 | |||
Subject: [PATCH] openvpn 2.4.9 -> 2.5.0 because of engine support | |||
--- | |||
package/openvpn/openvpn.hash | 2 +- | |||
package/openvpn/openvpn.mk | 2 +- | |||
2 files changed, 2 insertions(+), 2 deletions(-) | |||
diff --git a/package/openvpn/openvpn.hash b/package/openvpn/openvpn.hash | |||
index b9b0a4d..1a16d90 100644 | |||
--- a/package/openvpn/openvpn.hash | |||
@@ -1,3 +1,3 @@ | |||
# Locally calculated after checking signature | |||
-sha256 641f3add8694b2ccc39fd4fd92554e4f089ad16a8db6d2b473ec284839a5ebe2 openvpn-2.4.9.tar.xz | |||
+sha256 029a426e44d656cb4e1189319c95fe6fc9864247724f5599d99df9c4c3478fbd openvpn-2.5.0.tar.xz | |||
sha256 1fcb78d7e478bb8a9408010bdc91b36e213b1facfad093df3f7ce7e28af19043 COPYRIGHT.GPL | |||
diff --git a/package/openvpn/openvpn.mk b/package/openvpn/openvpn.mk | |||
index 4234675..9881426 100644 | |||
--- a/package/openvpn/openvpn.mk | |||
@@ -4,7 +4,7 @@ | |||
# | |||
################################################################################ | |||
-OPENVPN_VERSION = 2.4.9 | |||
+OPENVPN_VERSION = 2.5.0 | |||
OPENVPN_SOURCE = openvpn-$(OPENVPN_VERSION).tar.xz | |||
OPENVPN_SITE = http://swupdate.openvpn.net/community/releases | |||
OPENVPN_DEPENDENCIES = host-pkgconf openssl | |||
-- | |||
2.28.0 | |||
@@ -0,0 +1,48 @@ | |||
diff --git a/common.mk b/common.mk | |||
index 169b99c..361405f 100644 | |||
--- a/common.mk | |||
@@ -74,23 +74,23 @@ endif | |||
# # Then in QEMU, run: | |||
# # $ mount -t 9p -o trans=virtio host <mount_point> | |||
# # Or enable QEMU_VIRTFS_AUTOMOUNT | |||
-QEMU_VIRTFS_ENABLE ?= n | |||
-QEMU_VIRTFS_HOST_DIR ?= $(ROOT) | |||
+QEMU_VIRTFS_ENABLE ?= n | |||
+QEMU_VIRTFS_HOST_DIR ?= $(ROOT) | |||
# Persistent Secure Storage via shared folder | |||
# # Set QEMU_PSS_ENABLE to 'y' and adjust QEMU_PSS_HOST_DIR | |||
# # Then in QEMU, run: | |||
# # $ mount -t 9p -o trans=virtio secure /data/tee | |||
# # Or enable QEMU_PSS_AUTOMOUNT | |||
-QEMU_PSS_ENABLE ?= n | |||
-QEMU_PSS_HOST_DIR ?= /tmp/qemu-data-tee | |||
+QEMU_PSS_ENABLE ?= y | |||
+QEMU_PSS_HOST_DIR ?= /tmp/ | |||
# Warning: when these variables are modified, you must remake the buildroot | |||
# target directory. This can be done without rebuilding everything as follows: | |||
# rm -rf ../out-br/target; find ../out-br/ -name .stamp_target_installed | xargs rm | |||
# make <flags> run | |||
-QEMU_VIRTFS_AUTOMOUNT ?= n | |||
-QEMU_PSS_AUTOMOUNT ?= n | |||
+QEMU_VIRTFS_AUTOMOUNT ?= y | |||
+QEMU_PSS_AUTOMOUNT ?= y | |||
# Mount point for the shared directory inside QEMU | |||
# Used by the post-build script, this is written to /etc/fstab as the mount | |||
# point of the shared directory | |||
@@ -246,9 +246,12 @@ BUILDROOT_TOOLCHAIN=toolchain-aarch$(COMPILE_NS_USER)-legacy | |||
endif | |||
endif | |||
+BR2_PACKAGE_OPENSSL ?= y | |||
+BR2_PACKAGE_OPENVPN ?= y | |||
BR2_PACKAGE_LIBOPENSSL ?= y | |||
+BR2_PACKAGE_LIBOPENSSL_BIN ?= y | |||
+BR2_PACKAGE_LIBOPENSSL_ENGINES ?= y | |||
BR2_PACKAGE_MMC_UTILS ?= y | |||
-BR2_PACKAGE_OPENSSL ?= y | |||
BR2_PACKAGE_OPTEE_BENCHMARK_EXT ?= $(CFG_TEE_BENCHMARK) | |||
BR2_PACKAGE_OPTEE_BENCHMARK_EXT_SITE ?= $(BENCHMARK_APP_PATH) | |||
BR2_PACKAGE_OPTEE_CLIENT_EXT_SITE ?= $(OPTEE_CLIENT_PATH) |
@@ -1,171 +1,184 @@ | |||
#include <string.h> | |||
#include <assert.h> | |||
#include <err.h> | |||
// OpenSSL | |||
#include <openssl/engine.h> | |||
#include <openssl/evp.h> | |||
// OpTEE | |||
#include <tee_client_api.h> | |||
#include <user_ta_header_defines.h> | |||
#include "back.h" | |||
#include "log.h" | |||
#include "utils.h" | |||
// Only ECDSA/p256 scheme is supported | |||
#define CURVE_ID NID_X9_62_prime256v1 | |||
// Coordinate byte size in the NIST-P256 | |||
#define ECC_POINT_BSZ 32 | |||
// Extended data index for EC key | |||
static int ec_ex_index = 0; | |||
// OZAPTF: remove | |||
static const EC_POINT *ec_pub_key; | |||
static const BIGNUM *ec_prv_key; | |||
// Context | |||
struct tee_ctx_t { | |||
// Stores hash of key ID of a key stored in the TEE | |||
uint8_t key_id[32]; | |||
// OZAPTF: remove | |||
const BIGNUM *prv; | |||
struct session_t { | |||
// TEE session context | |||
TEEC_Context ctx; | |||
// Handle to the TEE session | |||
TEEC_Session tee_sess; | |||
// SHA-256 hash of a key ID, used for key indexing inside TEE | |||
uint8_t key_id[SHA256_SIZE]; | |||
}; | |||
// OZAPTF helper to remove | |||
static int parse_key_from_file(const char *path) { | |||
int ret = 0; | |||
BIO *bp; | |||
EVP_PKEY *key; | |||
EC_KEY *ec_key; | |||
const EC_GROUP *group; | |||
BIGNUM *x, *y; | |||
bp = BIO_new(BIO_s_file()); | |||
if (!bp) { | |||
// Creates session with the TEE. On success, sets the sess and returns | |||
// true, otherwise false. | |||
static bool create_tee_session(struct session_t *sess) { | |||
TEEC_Result res; | |||
uint32_t err_origin; | |||
TEEC_UUID uuid = TA_UUID; | |||
// Initialize a context connecting us to the TEE | |||
res = TEEC_InitializeContext(NULL, &sess->ctx); | |||
if (res != TEEC_SUCCESS) { | |||
info("TEEC_InitializeContext failed with code 0x%x", res); | |||
goto end; | |||
} | |||
if (!BIO_read_filename(bp, path)) { | |||
fprintf(stderr, "Failed to open private key file %s", path); | |||
// Open a session with TEE | |||
res = TEEC_OpenSession(&sess->ctx, &sess->tee_sess, &uuid, | |||
TEEC_LOGIN_PUBLIC, NULL, NULL, &err_origin); | |||
if (res != TEEC_SUCCESS) { | |||
info("TEEC_Opensession failed with code 0x%x origin 0x%x", | |||
res, err_origin); | |||
goto end; | |||
} | |||
key = PEM_read_bio_PrivateKey(bp, 0, 0, 0); | |||
if (!key) { | |||
goto end; | |||
} | |||
BN_CTX *ctx = BN_CTX_new(); | |||
if (!ctx) goto end; | |||
// Get curve | |||
ec_key = EVP_PKEY_get1_EC_KEY(key); | |||
if (!ec_key) goto end; | |||
ec_pub_key = EC_KEY_get0_public_key(ec_key); | |||
if (!ec_pub_key) goto end; | |||
// Get private key | |||
ec_prv_key = EC_KEY_get0_private_key(ec_key); | |||
ret = 1; | |||
end: | |||
BIO_free(bp); | |||
return ret; | |||
return res == TEEC_SUCCESS; | |||
} | |||
int OPTEE_ENG_evp_cb_sign( | |||
EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *sigsz, | |||
const unsigned char *tb, size_t tbsz) { | |||
ENTRY; | |||
// Creates session with the TEE. Returns true on success, otherwise false. | |||
static void close_tee_session(struct session_t *sess) { | |||
if(!sess) { | |||
return; | |||
} | |||
TEEC_CloseSession(&sess->tee_sess); | |||
TEEC_FinalizeContext(&sess->ctx); | |||
} | |||
EC_KEY *ec = 0; | |||
EVP_MD *md = 0; | |||
EVP_PKEY *pkey = 0; | |||
const EC_GROUP *group = 0; | |||
struct tee_ctx_t *op_ctx = 0; | |||
unsigned int sltmp; | |||
int ret = 0; | |||
// Load public key. This implementation loads it from TEE | |||
static const EC_POINT* get_public_ec_point_from_tee( | |||
struct session_t *sess) { | |||
ENTRY; | |||
// OZAPTF: not sure if 64 | |||
static const size_t max_signature_length = 64; | |||
const EC_POINT *ec_pub_key = 0; | |||
uint8_t coord_x[ECC_POINT_BSZ] = {0}; | |||
uint8_t coord_y[ECC_POINT_BSZ] = {0}; | |||
BIGNUM *x_bn = 0, *y_bn = 0; | |||
EC_POINT *point = 0; | |||
EC_GROUP *group = 0; | |||
EC_KEY *ec_key = 0; | |||
BN_CTX *ctx = 0; | |||
int res; | |||
uint32_t err_origin; | |||
TEEC_Operation op; | |||
memset(&op, 0, sizeof(op)); | |||
op.paramTypes = TEEC_PARAM_TYPES( | |||
TEEC_MEMREF_TEMP_INPUT, | |||
TEEC_MEMREF_TEMP_INOUT, | |||
TEEC_MEMREF_TEMP_INOUT, | |||
TEEC_NONE); | |||
op.params[0].tmpref.buffer = sess->key_id; | |||
op.params[0].tmpref.size = ARRAY_SIZE(sess->key_id); | |||
op.params[1].tmpref.buffer = coord_x; | |||
op.params[1].tmpref.size = ECC_POINT_BSZ; | |||
op.params[2].tmpref.buffer = coord_y; | |||
op.params[2].tmpref.size = ECC_POINT_BSZ; | |||
if (!create_tee_session(sess)) { | |||
crit("TEE session: can't create"); | |||
return 0; | |||
} | |||
res = TEEC_InvokeCommand(&sess->tee_sess, TA_GET_PUB_KEY, &op, &err_origin); | |||
close_tee_session(sess); | |||
// if sig not set, return maximum length of the signature buffer | |||
if (!sig && sigsz) { | |||
*sigsz = max_signature_length; | |||
ret = 0; | |||
goto end; | |||
if (res != TEEC_SUCCESS) { | |||
crit("TEE session: TEEC_InvokeCommand failed with code 0x%x origin 0x%x", | |||
res, err_origin); | |||
return 0; | |||
} | |||
if (*sigsz < max_signature_length) { | |||
/* Signature buffer is to small. The documentation, here: | |||
https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_sign.html | |||
doesn't specify what to do in this case. The choices are | |||
either fail or return truncated signature. I'll just fail | |||
as truncated ECDSA signature can't be verified. */ | |||
*sigsz = 0; | |||
goto end; | |||
if ((op.params[1].tmpref.size != ECC_POINT_BSZ) || | |||
(op.params[2].tmpref.size != ECC_POINT_BSZ)) { | |||
crit("Wrong length of public key received"); | |||
return 0; | |||
} | |||
pkey = EVP_PKEY_CTX_get0_pkey(ctx); | |||
TEST_NULL(pkey); | |||
// Convert received affine coordinate into EC public key | |||
ctx = BN_CTX_new(); | |||
group = EC_GROUP_new_by_curve_name(CURVE_ID); | |||
point = EC_POINT_new(group); | |||
ec_key = EC_KEY_new(); | |||
if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC) { | |||
info("Only ECDSA supported for signing"); | |||
ret = -2; // doc says to set -2 in this case | |||
TEST_NULL(ctx); | |||
TEST_NULL(group); | |||
TEST_NULL(point); | |||
TEST_NULL(ec_key); | |||
x_bn = BN_bin2bn(op.params[1].tmpref.buffer, | |||
op.params[1].tmpref.size, x_bn); | |||
y_bn = BN_bin2bn(op.params[2].tmpref.buffer, | |||
op.params[2].tmpref.size, y_bn); | |||
if (!x_bn||!y_bn) { | |||
crit("Can't convert octet strings to BN"); | |||
goto end; | |||
} | |||
if (!EVP_PKEY_CTX_get_signature_md(ctx, &md) || | |||
(md != EVP_sha256())) { | |||
// We only support ECDSA+P-256+SHA256 | |||
info("Only SHA256 supported for signing"); | |||
ret = -2; | |||
if (!EC_POINT_set_affine_coordinates_GFp(group, point, x_bn, y_bn, ctx)) { | |||
crit("Can't convert BN to point"); | |||
goto end; | |||
} | |||
ec = EVP_PKEY_get1_EC_KEY(pkey); | |||
TEST_NULL(ec); | |||
group = EC_KEY_get0_group(ec); | |||
TEST_NULL(group); | |||
if (NID_X9_62_prime256v1 != EC_GROUP_get_curve_name(group)) { | |||
info("Only p-256 supported"); | |||
ret = -2; | |||
if (!EC_KEY_set_group(ec_key, group) || | |||
!EC_KEY_set_public_key(ec_key, point)) { | |||
crit("Can't set public key"); | |||
goto end; | |||
} | |||
// Get TEE context as crypto extended data and set it as signing key | |||
op_ctx = EC_KEY_get_ex_data(ec, ec_ex_index); | |||
TEST_NULL(op_ctx); | |||
TEST_OSSL( | |||
EC_KEY_set_private_key(ec, ec_prv_key), | |||
INVALID_KEY); | |||
TEST_OSSL( | |||
ECDSA_sign(NID_sha256, tb, tbsz, sig, &sltmp, ec), | |||
CANNOT_SIGN); | |||
*sigsz = sltmp; | |||
ec_pub_key = EC_KEY_get0_public_key(ec_key); | |||
// That's all, folks! | |||
ret = 1; | |||
end: | |||
if (ec) EC_KEY_free(ec); | |||
return ret; | |||
BN_free(x_bn); | |||
BN_free(y_bn); | |||
EC_POINT_free(point); | |||
EC_GROUP_free(group); | |||
BN_CTX_free(ctx); | |||
return ec_pub_key; | |||
} | |||
// generate key pair for the ECC key and | |||
static EVP_PKEY* get_ecc_key_pair( | |||
ENGINE *e, | |||
struct tee_ctx_t *op, | |||
int ecc_group_id) { | |||
// Construct EVP_PKEY with private key stored in the TEE | |||
static EVP_PKEY* load_key_pair_ec( | |||
struct session_t *sess, | |||
ENGINE *e) { | |||
ENTRY; | |||
const EC_POINT *ec_pub_key = 0; | |||
EVP_PKEY_CTX *evp_ctx = 0; | |||
EVP_PKEY *evp_key = 0; | |||
EC_KEY *ec_key = 0; | |||
uint8_t *hash_key_id = 0; | |||
int ret = 0; | |||
// Generate parameters for ECDSA-P256 | |||
evp_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, e); | |||
TEST_NULL(evp_ctx); | |||
TEST_OSSL( | |||
EVP_PKEY_paramgen_init(evp_ctx), | |||
BAD_PARAMETERS); | |||
// Generate parameters for ECDSA-P256 | |||
TEST_OSSL( | |||
EVP_PKEY_CTX_set_ec_paramgen_curve_nid(evp_ctx, ecc_group_id), | |||
EVP_PKEY_CTX_set_ec_paramgen_curve_nid(evp_ctx, CURVE_ID), | |||
BAD_PARAMETERS); | |||
TEST_OSSL( | |||
EVP_PKEY_paramgen(evp_ctx, &evp_key), | |||
@@ -189,27 +202,25 @@ static EVP_PKEY* get_ecc_key_pair( | |||
* Normal World, on Client Application request. Second option is | |||
* implemented here, as that's easier. | |||
*/ | |||
// OZAPTF: set public key received from TEE | |||
ec_pub_key = get_public_ec_point_from_tee(sess); | |||
TEST_NULL(ec_pub_key); | |||
TEST_OSSL( | |||
EC_KEY_set_public_key(ec_key, ec_pub_key), | |||
BAD_PARAMETERS); | |||
// Set handle to private key, stored in the TEE | |||
EC_KEY_set_ex_data(ec_key, ec_ex_index, op); | |||
// Set ID of a private key, stored in the TEE | |||
hash_key_id = (void*)malloc(SHA256_SIZE); | |||
TEST_NULL(hash_key_id); | |||
memcpy(hash_key_id, sess->key_id, SHA256_SIZE); | |||
EC_KEY_set_ex_data(ec_key, ec_ex_index, hash_key_id); | |||
TEST_OSSL( | |||
EVP_PKEY_set1_engine(evp_key, e), | |||
INTERNAL); | |||
ret = 1; | |||
end: | |||
if (ec_key) { | |||
// must be "free'd" as EVP_PKEY_get1 was used | |||
EC_KEY_free(ec_key); | |||
} | |||
if (evp_ctx) { | |||
EVP_PKEY_CTX_free(evp_ctx); | |||
} | |||
EC_KEY_free(ec_key); | |||
EVP_PKEY_CTX_free(evp_ctx); | |||
if (!ret && evp_key) { | |||
EVP_PKEY_free(evp_key); | |||
evp_key = 0; | |||
@@ -217,41 +228,33 @@ end: | |||
return evp_key; | |||
} | |||
// ENGINE_set_load_privkey_function callback. Retrieves public key | |||
// from TEE and sets a handler for the private key stored in the TEE. | |||
EVP_PKEY* OPTEE_ENG_load_private_key( | |||
ENGINE *e, const char *key_name, UI_METHOD *ui_method, | |||
void *callback_data) { | |||
ENTRY; | |||
NOP(callback_data), NOP(ui_method); | |||
struct tee_ctx_t *op_ctx = 0; | |||
EVP_PKEY_CTX *evp_ctx = 0; | |||
ENTRY; | |||
EVP_PKEY *evp_key = 0; | |||
uint8_t key_digest[32] = {0}; | |||
struct session_t sess; | |||
int ret = 0; | |||
/* read key from file */ | |||
// OZAPTF | |||
TEST_OSSL( | |||
parse_key_from_file(getenv("PRV_KEY")), | |||
BAD_PARAMETERS); | |||
// Calculate key-id used internally. It is a sha256 | |||
// caller provided of key name. | |||
TEST_OSSL( | |||
EVP_Digest(key_name, strlen(key_name), key_digest, NULL, EVP_sha256(), NULL), | |||
EVP_Digest(key_name, | |||
strlen(key_name), sess.key_id, NULL, EVP_sha256(), NULL), | |||
BAD_PARAMETERS); | |||
// Create internal TEE context | |||
op_ctx = malloc(sizeof(*op_ctx)); | |||
TEST_NULL(op_ctx); | |||
op_ctx->prv = ec_prv_key; | |||
memcpy(op_ctx->key_id, key_digest, ARRAY_SIZE(op_ctx->key_id)); | |||
// create EVP_PKEY_CTX object for ECDSA-P256 signing | |||
evp_key = get_ecc_key_pair(e, op_ctx, NID_X9_62_prime256v1); | |||
// Create EVP_PKEY object. Currently only ECDSA/p256 is supported. | |||
// Normally it would be a switch-case for all supported methods. | |||
evp_key = load_key_pair_ec(&sess, e); | |||
TEST_NULL(evp_key); | |||
// Some calls related to EVP_PKEY must be forwaded to | |||
// OpTEE engine. | |||
if (EVP_PKEY_set1_engine(evp_key, e) != 1) { | |||
info("Can't set engine for EVP_PKEY"); | |||
EVP_PKEY_free(evp_key); | |||
@@ -261,12 +264,132 @@ EVP_PKEY* OPTEE_ENG_load_private_key( | |||
end: | |||
if (!ret) { | |||
if (op_ctx && !evp_key) { | |||
free(op_ctx); | |||
} | |||
if (evp_key) { | |||
EVP_PKEY_free(evp_key); | |||
} | |||
EVP_PKEY_free(evp_key); | |||
} | |||
return evp_key; | |||
} | |||
int OPTEE_ENG_evp_cb_sign( | |||
EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *sigsz, | |||
const uint8_t *tb, size_t tbsz) { | |||
ENTRY; | |||
const EC_GROUP *group = 0; | |||
EVP_PKEY *pkey = 0; | |||
EC_KEY *ec = 0; | |||
EVP_MD *md = 0; | |||
ECDSA_SIG *sig_ob = 0; | |||
BIGNUM *r = 0, *s = 0; | |||
TEEC_Operation op; | |||
uint8_t *hash_key_id = 0; | |||
int ret = 0; | |||
uint32_t err_origin; | |||
struct session_t sess = {0}; | |||
uint8_t sign[64] = {0}; | |||
TEST_NULL(sigsz); | |||
pkey = EVP_PKEY_CTX_get0_pkey(ctx); | |||
TEST_NULL(pkey); | |||
// Check if ECDSA/p256-SHA256 signature was requested | |||
if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC) { | |||
info("Only ECDSA supported for signing"); | |||
ret = -2; // doc says to set -2 in this case | |||
goto end; | |||
} | |||
if (!EVP_PKEY_CTX_get_signature_md(ctx, &md) || | |||
(md != EVP_sha256())) { | |||
// We only support ECDSA+P-256+SHA256 | |||
info("Only SHA256 supported for signing"); | |||
ret = -2; | |||
goto end; | |||
} | |||
ec = EVP_PKEY_get1_EC_KEY(pkey); | |||
TEST_NULL(ec); | |||
group = EC_KEY_get0_group(ec); | |||
TEST_NULL(group); | |||
if (CURVE_ID != EC_GROUP_get_curve_name(group)) { | |||
info("Only NIST P-256 supported"); | |||
ret = -2; | |||
goto end; | |||
} | |||
// Request message singing from TEE | |||
memset(&op, 0, sizeof(op)); | |||
hash_key_id = EC_KEY_get_ex_data(ec, ec_ex_index); | |||
TEST_NULL(hash_key_id); | |||
op.paramTypes = TEEC_PARAM_TYPES( | |||
TEEC_MEMREF_TEMP_INPUT, | |||
TEEC_MEMREF_TEMP_INPUT, | |||
TEEC_MEMREF_TEMP_INOUT, | |||
TEEC_NONE); | |||
op.params[0].tmpref.buffer = hash_key_id; | |||
op.params[0].tmpref.size = SHA256_SIZE; | |||
op.params[1].tmpref.buffer = (uint8_t*)tb; | |||
op.params[1].tmpref.size = tbsz; | |||
op.params[2].tmpref.buffer = sign; | |||
op.params[2].tmpref.size = ARRAY_SIZE(sign); | |||
if (!create_tee_session(&sess)) { | |||
info("TEE session: can't create"); | |||
goto end; | |||
} | |||
ret = TEEC_InvokeCommand(&sess.tee_sess, TA_SIGN_ECC, &op, &err_origin); | |||
close_tee_session(&sess); | |||
if (ret != TEEC_SUCCESS) { | |||
info("TEEC_InvokeCommand failed with code 0x%x origin 0x%x", | |||
ret, err_origin); | |||
goto end; | |||
} | |||
// Convert raw ECDSA signature (r,s) into DER encoded signature. | |||
const size_t h = ARRAY_SIZE(sign)/2; | |||
r = BN_bin2bn(sign+0, h, r); | |||
s = BN_bin2bn(sign+h, h, s); | |||
if (!r||!s) { | |||
info("Can't create r&s of ECDSA SIGN"); | |||
goto end; | |||
} | |||
sig_ob = ECDSA_SIG_new(); | |||
// r,s are not NULL, so this call never fails | |||
(void)ECDSA_SIG_set0(sig_ob, r, s); | |||
// if sig not set, return maximum length of the signature buffer | |||
if (!sig && sigsz) { | |||
*sigsz = i2d_ECDSA_SIG(sig_ob, 0); | |||
goto end; | |||
} | |||
if (*sigsz < i2d_ECDSA_SIG(sig_ob, 0)) { | |||
/* Signature buffer is to small. The documentation, here: | |||
https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_sign.html | |||
doesn't specify what to do in this case. The choices are | |||
either fail or return truncated signature. I'll just fail | |||
as truncated ECDSA signature can't be verified. */ | |||
goto end; | |||
} | |||
*sigsz = i2d_ECDSA_SIG(sig_ob, &sig); | |||
if (!*sigsz) { | |||
info("Can't DER encode signature"); | |||
goto end; | |||
} | |||
// That's all, folks! | |||
ret = 1; | |||
end: | |||
if (ec) EC_KEY_free(ec); | |||
if (!sig_ob) { | |||
// Calling ECDSA_SIG_set0 transfers the ownership of | |||
// r,s to the ECDSA_SIG object. The ECDSA_SIG_free | |||
// takes care of freeing it. | |||
ECDSA_SIG_free(sig_ob); | |||
} else { | |||
BN_free(r); | |||
BN_free(s); | |||
} | |||
return ret; | |||
} |
@@ -12,10 +12,10 @@ EVP_PKEY* OPTEE_ENG_load_private_key( | |||
void * callback_data); | |||
int OPTEE_ENG_evp_cb_sign( | |||
EVP_PKEY_CTX * ctx, | |||
unsigned char * sig, | |||
size_t * sigsz, | |||
const unsigned char *tb, | |||
size_t tbsz); | |||
EVP_PKEY_CTX * ctx, | |||
uint8_t * sig, | |||
size_t * sigsz, | |||
const uint8_t *tb, | |||
size_t tbsz); | |||
#endif // BACK_H_ |
@@ -10,7 +10,7 @@ | |||
#ifdef OPTEE_ENG_ENGINE_ID | |||
#undef OPTEE_ENG_ENGINE_ID | |||
#endif | |||
#define OPTEE_ENG_ENGINE_ID "optee_eng" | |||
#define OPTEE_ENG_ENGINE_ID "optee" | |||
#ifdef OPTEE_ENG_ENGINE_NAME | |||
#undef OPTEE_ENG_ENGINE_NAME | |||
@@ -18,7 +18,6 @@ | |||
#define OPTEE_ENG_ENGINE_NAME "OpTEE OpenSSL ENGINE." | |||
BIO *bio_err = NULL; | |||
static bool is_initialized = false; | |||
static int lib_code = 0; | |||
static int error_loaded = 0; | |||
@@ -118,11 +117,6 @@ static int OPTEE_ENG_pkey_meths( | |||
return 1; | |||
} | |||
static int OPTEE_ENG_register_engine(ENGINE *e) { | |||
ENGINE_set_pkey_meths(e, OPTEE_ENG_pkey_meths); | |||
return 1; | |||
} | |||
static int OPTEE_ENG_bind(ENGINE *e, const char *id) { | |||
if (!ERR_load_crypto_strings()) { | |||
fprintf(stderr, "ERR_load_crypto_strings failed\n"); | |||
@@ -130,7 +124,7 @@ static int OPTEE_ENG_bind(ENGINE *e, const char *id) { | |||
} | |||
if (!OPENSSL_init_crypto( | |||
OPENSSL_INIT_LOAD_CONFIG | OPENSSL_INIT_ENGINE_DYNAMIC, NULL)) { | |||
OPENSSL_INIT_ENGINE_DYNAMIC, NULL)) { | |||
fprintf(stderr, "OPENSSL_init_crypto failed\n"); | |||
return 0; | |||
} | |||
@@ -138,7 +132,7 @@ static int OPTEE_ENG_bind(ENGINE *e, const char *id) { | |||
NOP(id); | |||
TEST_P(OPTEE_ENG_err_strings()); | |||
/* we set logs here to get potential error traces | |||
/* We set logs here to get potential error traces | |||
* from library initialization. */ | |||
unsigned level = TEE_DEFAULT_LOG_LEVEL; | |||
(void)get_env_log_level(&level); | |||
@@ -150,7 +144,7 @@ static int OPTEE_ENG_bind(ENGINE *e, const char *id) { | |||
TEST_P(ENGINE_set_name(e, OPTEE_ENG_ENGINE_NAME)); | |||
TEST_P(ENGINE_set_destroy_function(e, OPTEE_ENG_destroy)); | |||
TEST_P(ENGINE_set_load_privkey_function(e, OPTEE_ENG_load_private_key)); | |||
TEST_P(OPTEE_ENG_register_engine(e)); | |||
TEST_P(ENGINE_set_pkey_meths(e, OPTEE_ENG_pkey_meths)); | |||
debug("Registration done"); | |||
return 1; | |||
@@ -0,0 +1,243 @@ | |||
/* | |||
* Copyright (c) 2016, Linaro Limited | |||
* All rights reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright notice, | |||
* this list of conditions and the following disclaimer. | |||
* | |||
* 2. Redistributions in binary form must reproduce the above copyright notice, | |||
* this list of conditions and the following disclaimer in the documentation | |||
* and/or other materials provided with the distribution. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
* POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
#include <stdint.h> | |||
#include <stdbool.h> | |||
#include <err.h> | |||
#include <stdio.h> | |||
#include <string.h> | |||
#include <libgen.h> | |||
#include <assert.h> | |||
#include <openssl/ssl.h> | |||
#include <openssl/err.h> | |||
#include <openssl/conf.h> | |||
#include <openssl/evp.h> | |||
#include <openssl/ec.h> | |||
#include <openssl/x509.h> | |||
#include <openssl/obj_mac.h> | |||
/* OP-TEE TEE client API (built by optee_client) */ | |||
#include <tee_client_api.h> | |||
/* To the the UUID (found the the TA's h-file(s)) */ | |||
#include <user_ta_header_defines.h> | |||
#define TEE_ECC_CURVE_NIST_P256 0x00000003 | |||
static uint32_t curve_openssl_to_tee(int openssl_id) { | |||
if (openssl_id != NID_X9_62_prime256v1) { | |||
return 0; | |||
} | |||
return TEE_ECC_CURVE_NIST_P256; | |||
} | |||
// kp_bncpy(): | |||
// * buf : either destination buffer or NULL. If NULL buffer is initialized | |||
static void kp_bncpy(struct keybuf_t *b, const BIGNUM *bn) { | |||
b->sz = BN_num_bytes(bn); | |||
// Ensure field is not empty | |||
assert(b->sz); | |||
// Ensure allocation hasn't failed | |||
(void)BN_bn2bin(bn, &b->b[0]); | |||
} | |||
static bool get_keypair(EVP_PKEY *key, struct keypair_t *keypair) { | |||
switch (EVP_PKEY_type(EVP_PKEY_id(key))) { | |||
case EVP_PKEY_EC: { | |||
EC_KEY *ec_key; | |||
const EC_POINT *ec_pub_key; | |||
const EC_GROUP *group; | |||
BIGNUM *x, *y; | |||
keypair->type = KEYTYPE_ECC; | |||
BN_CTX *ctx = BN_CTX_new(); | |||
if (!ctx) return false; | |||
// Get curve | |||
ec_key = EVP_PKEY_get1_EC_KEY(key); | |||
if (!ec_key) return false; | |||
ec_pub_key = EC_KEY_get0_public_key(ec_key); | |||
if (!ec_pub_key) return false; | |||
group = EC_KEY_get0_group(ec_key); | |||
if (!group) return false; | |||
// Get private key | |||
const BIGNUM *bn = EC_KEY_get0_private_key(ec_key); | |||
kp_bncpy(&keypair->u.ecc.scalar, bn); | |||
// Get public key | |||
keypair->u.ecc.curve_id | |||
= curve_openssl_to_tee(EC_GROUP_get_curve_name(group)); | |||
x = BN_new(); y = BN_new(); | |||
if (!x || !y) return false; | |||
if (!EC_POINT_get_affine_coordinates_GFp(group, ec_pub_key, x, y, ctx)) { | |||
BN_free(x); BN_free(y); | |||
return false; | |||
} | |||
kp_bncpy(&keypair->u.ecc.x, x); | |||
kp_bncpy(&keypair->u.ecc.y, y); | |||
OPENSSL_free(ctx); | |||
BN_free(x); BN_free(y); // OMG, refactoring is necessairy | |||
break; | |||
} | |||
default: | |||
errx(1, "Unsupported key type"); | |||
return false; | |||
} | |||
return true; | |||
} | |||
// parse_key_from_file: adds a private key from a file location | |||
static int parse_key_from_file( | |||
const char *path, | |||
struct keypair_t *kp) { | |||
BIO *bp; | |||
EVP_PKEY *key; | |||
int ret = 0; | |||
bp = BIO_new(BIO_s_file()); | |||
if (!bp) { | |||
goto end; | |||
} | |||
if (!BIO_read_filename(bp, path)) { | |||
errx(1, "Failed to open private key file %s", path); | |||
goto end; | |||
} | |||
key = PEM_read_bio_PrivateKey(bp, 0, 0, 0); | |||
if (!key) { | |||
errx(1, "PEM_read_bio_PrivateKey: failed"); | |||
goto end; | |||
} | |||
if (!get_keypair(key, kp)) { | |||
errx(1, "get_keypair: failed"); | |||
goto end; | |||
} | |||
ret = 1; | |||
end: | |||
BIO_free(bp); | |||
return ret; | |||
} | |||
int main(int argc, char *argv[]) | |||
{ | |||
TEEC_Result res; | |||
TEEC_Context ctx; | |||
TEEC_Session sess; | |||
TEEC_Operation op; | |||
TEEC_UUID uuid = TA_UUID; | |||
uint32_t cmd; | |||
struct keypair_t kp = {0}; | |||
uint32_t err_origin; | |||
uint8_t key_id[32]; | |||
// Initialize a context connecting us to the TEE | |||
res = TEEC_InitializeContext(NULL, &ctx); | |||
if (res != TEEC_SUCCESS) | |||
errx(1, "TEEC_InitializeContext failed with code 0x%x", res); | |||
// Open a session to the TA identified by uuid | |||
res = TEEC_OpenSession(&ctx, &sess, &uuid, | |||
TEEC_LOGIN_PUBLIC, NULL, NULL, &err_origin); | |||
if (res != TEEC_SUCCESS) | |||
errx(1, "TEEC_Opensession failed with code 0x%x origin 0x%x", | |||
res, err_origin); | |||
/* Clear the TEEC_Operation struct */ | |||
memset(&op, 0, sizeof(op)); | |||
/* | |||
* TA_INSTALL_KEYS is the actual function in the TA to be | |||
* called. | |||
*/ | |||
if (argc < 2) { | |||
errx(1, "Key name not provided"); | |||
} | |||
if (!EVP_Digest(argv[2], strlen(argv[2]), key_id, NULL, EVP_sha256(), NULL)) { | |||
errx(1, "EVP_Digest"); | |||
} | |||
if (!strncmp(argv[1], "put", 3)) { | |||
cmd = TA_INSTALL_KEYS; | |||
if (argc < 3) { | |||
errx(1, "Filename missing\n"); | |||
} | |||
if (!parse_key_from_file(argv[3], &kp)) { | |||
errx(1, "parse_key_from_file() failed"); | |||
} | |||
op.paramTypes = TEEC_PARAM_TYPES( | |||
TEEC_MEMREF_TEMP_INPUT, | |||
TEEC_MEMREF_TEMP_INPUT, | |||
TEEC_NONE, | |||
TEEC_NONE); | |||
op.params[0].tmpref.buffer = (void*) &kp; | |||
op.params[0].tmpref.size = sizeof(kp); | |||
op.params[1].tmpref.buffer = key_id; | |||
op.params[1].tmpref.size = 32; | |||
} else if (!strncmp(argv[1], "del", 3)) { | |||
cmd = TA_DEL_KEYS; | |||
op.paramTypes = TEEC_PARAM_TYPES( | |||
TEEC_MEMREF_TEMP_INPUT, | |||
TEEC_NONE, | |||
TEEC_NONE, | |||
TEEC_NONE); | |||
op.params[0].tmpref.buffer = key_id; | |||
op.params[0].tmpref.size = 32; | |||
} else { | |||
errx(1, "E: Command must be 'put <key_name> filename' or 'del <key_name>'"); | |||
} | |||
res = TEEC_InvokeCommand(&sess, cmd, &op, &err_origin); | |||
if (res != TEEC_SUCCESS) { | |||
errx(1, "TEEC_InvokeCommand failed with code 0x%x origin 0x%x", | |||
res, err_origin); | |||
} | |||
/* | |||
* We're done with the TA, close the session and | |||
* destroy the context. | |||
*/ | |||
TEEC_CloseSession(&sess); | |||
TEEC_FinalizeContext(&ctx); | |||
return 0; | |||
} |
@@ -0,0 +1,101 @@ | |||
#include <stdint.h> | |||
#include <vector> | |||
#include <gtest/gtest.h> | |||
#include <openssl/crypto.h> | |||
#include <openssl/evp.h> | |||
#include <openssl/engine.h> | |||
#include <benchmark/benchmark.h> | |||
// Size of the input message. It doesn't matter | |||
// for speed as hashing is done in the REE anyway | |||
#define MSG_SIZE 32 | |||
// Name of the key stored in the TEE | |||
#define KEY_NAME "bench_key" | |||
// Path to the engine library | |||
#define OPTEE_ENG_PATH "/opt/liboptee_eng.so" | |||
// Engine ID | |||
#define OPTEE_ID "optee" | |||
static void SignREE(benchmark::State& state) { | |||
unsigned char msg[MSG_SIZE]; | |||
EVP_MD_CTX * mctx = EVP_MD_CTX_new(); | |||
EVP_PKEY * pkey = NULL, *params = NULL; | |||
EVP_PKEY_CTX *pctx, *kctx; | |||
ASSERT_TRUE(mctx); | |||
// Initialize parameters for NIST P-256 curve | |||
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, 0); | |||
ASSERT_TRUE(pctx); | |||
ASSERT_TRUE(EVP_PKEY_paramgen_init(pctx)); | |||
ASSERT_TRUE(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1)); | |||
ASSERT_TRUE(EVP_PKEY_paramgen(pctx, ¶ms)); | |||
kctx = EVP_PKEY_CTX_new(params, NULL); | |||
ASSERT_TRUE(kctx); | |||
// Generate key with paramters stored in kctx | |||
ASSERT_EQ(EVP_PKEY_keygen_init(kctx), 1); | |||
ASSERT_EQ(EVP_PKEY_keygen(kctx, &pkey), 1); | |||
ASSERT_TRUE(pkey); | |||
// Setup buffer for signature | |||
size_t siglen = EVP_PKEY_size(pkey); | |||
std::vector<uint8_t> sig; | |||
sig.reserve(siglen); | |||
// Perform benchmarking for signing | |||
ASSERT_EQ(EVP_DigestSignInit(mctx, NULL, 0, 0, pkey), 1); | |||
for (auto _ : state) { | |||
ASSERT_EQ(EVP_DigestSign(mctx, sig.data(), &siglen, msg, MSG_SIZE), 1); | |||
siglen = EVP_PKEY_size(pkey); | |||
} | |||
EVP_MD_CTX_free(mctx); | |||
EVP_PKEY_free(pkey); | |||
EVP_PKEY_free(params); | |||
EVP_PKEY_CTX_free(pctx); | |||
EVP_PKEY_CTX_free(kctx); | |||
} | |||
static void SignTEE(benchmark::State& state) { | |||
const char key_name[] = "bench_key\0"; | |||
// load engine | |||
unsigned char msg[MSG_SIZE]; | |||
EVP_PKEY * pkey = NULL; | |||
EVP_MD_CTX * mctx = EVP_MD_CTX_new(); | |||
ENGINE *e = NULL; | |||
ENGINE_load_dynamic(); | |||
e = ENGINE_by_id("dynamic"); | |||
ASSERT_TRUE(e); | |||
ENGINE_ctrl_cmd_string(e, "SO_PATH", OPTEE_ENG_PATH, 0); | |||
ENGINE_ctrl_cmd_string(e, "ID", OPTEE_ID, 0); | |||
ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0); | |||
ENGINE_set_default(e, ENGINE_METHOD_ALL); | |||
ERR_clear_error(); | |||
pkey = ENGINE_load_private_key(e, key_name, 0, 0); | |||
ASSERT_TRUE(pkey); | |||
size_t siglen = EVP_PKEY_size(pkey); | |||
std::vector<uint8_t> sig; | |||
sig.reserve(siglen); | |||
ASSERT_EQ(EVP_DigestSignInit(mctx, NULL, 0, 0, pkey), 1); | |||
for (auto _ : state) { | |||
EVP_DigestSign(mctx, sig.data(), &siglen, msg, sizeof msg); | |||
siglen = EVP_PKEY_size(pkey); | |||
} | |||
EVP_MD_CTX_free(mctx); | |||
EVP_PKEY_free(pkey); | |||
} | |||
BENCHMARK(SignREE); | |||
BENCHMARK(SignTEE); | |||
BENCHMARK_MAIN(); |
@@ -63,26 +63,9 @@ enum { | |||
#define ERR_R_LIST(_) \ | |||
_(SUCCESS, "Success") \ | |||
_(GENERIC, "Generic") \ | |||
_(CANNOT_ALLOCATE_KEY, "key allocation") \ | |||
_(BAD_SIGNATURE, "bad signature") \ | |||
_(CANNOT_SIGN, "signing operation failed") \ | |||
_(CANNOT_GEN_KEY, "failed to generate keys") \ | |||
_(INVALID_ENCODING, "invalid encoding") \ | |||
_(INVALID_KEY, "invalid key") \ | |||
_(INVALID_PEER_KEY, "invalid peer key") \ | |||
_(WRONG_PRVKEY_BUF, "invalid private key") \ | |||
_(WRONG_PUBKEY_BUF, "invalid public key") \ | |||
_(KEYS_NOT_SET, "keys not set") \ | |||
_(MISSING_NID_DATA, "failed to get nid_data struct pointer") \ | |||
_(MISSING_PRIVATE_KEY, "missing private key") \ | |||
_(RNG_FAILED, "random number generation failed") \ | |||
_(BAD_PARAMETERS, "bad parameters found") \ | |||
_(PASSED_NULL_PARAMETER, "null pointer provided") \ | |||
_(NOT_SUPPORTED, "not supported") \ | |||
_(WRONG_LENGTH, "wrong length") \ | |||
_(OUT_OF_MEMORY, "not enough memory") \ | |||
_(INTERNAL, "internal error") \ | |||
_(VALUE_NOT_SET, "value not set") | |||
_(INTERNAL, "internal error") | |||
enum { | |||
TEE_R_NONE = 100, | |||
@@ -0,0 +1,19 @@ | |||
# The UUID for the Trusted Application | |||
BINARY=8aaaf200-2450-11e4-0060-0dc0ffee0000 | |||
CFG_TEE_TA_LOG_LEVEL = 4 | |||
CPPFLAGS += -O2 -DCFG_TEE_TA_LOG_LEVEL=$(CFG_TEE_TA_LOG_LEVEL) | |||
TA_DEV_KIT_DIR=$(OPTEE_ROOT)/optee_os/out/arm/export-ta_arm64 | |||
TEEC_EXPORT=$(OPTEE_ROOT)/optee_client/public | |||
HOST_CROSS_COMPILE=$(OPTEE_ROOT)/toolchains/aarch64/bin/aarch64-linux-gnu- | |||
CROSS_COMPILE=${HOST_CROSS_COMPILE} | |||
-include $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk | |||
ifeq ($(wildcard $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk), ) | |||
clean: | |||
@echo 'Note: $$(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk not found, cannot clean TA' | |||
@echo 'Note: TA_DEV_KIT_DIR=$(TA_DEV_KIT_DIR)' | |||
rm -rf ${BINARY}.* | |||
rm -rf *.o | |||
endif |
@@ -0,0 +1,345 @@ | |||
#include <stdio.h> | |||
#include <string.h> | |||
#include <user_ta_header_defines.h> | |||
#include <tee_internal_api.h> | |||
#include <tee_internal_api_extensions.h> | |||
#ifdef ATTR_REF | |||
#undef ATTR_REF | |||
#endif | |||
#define ATTR_REF(CNT, ATTR, BUF) \ | |||
TEE_InitRefAttribute(&attrs[(CNT)++], (ATTR), (BUF).b, (BUF).sz) | |||
#define LOG_RET(ret) \ | |||
if((ret)!=TEE_SUCCESS) { \ | |||
EMSG("ERR: %d %X", __LINE__, ret); \ | |||
return ret; \ | |||
} | |||
// Calculates size of an array | |||
#define ARRAY_SIZE(a) ((sizeof((a))) / sizeof((a)[0])) | |||
/* | |||
* Called when the instance of the TA is created. This is the first call in | |||
* the TA. | |||
*/ | |||
TEE_Result TA_CreateEntryPoint(void) | |||
{ | |||
DMSG("has been called"); | |||
return TEE_SUCCESS; | |||
} | |||
/* | |||
* Called when the instance of the TA is destroyed if the TA has not | |||
* crashed or panicked. This is the last call in the TA. | |||
*/ | |||
void TA_DestroyEntryPoint(void) { | |||
DMSG("has been called"); | |||
} | |||
/* | |||
* Called when a new session is opened to the TA. *sess_ctx can be updated | |||
* with a value to be able to identify this session in subsequent calls to the | |||
* TA. In this function you will normally do the global initialization for the | |||
* TA. | |||
*/ | |||
TEE_Result TA_OpenSessionEntryPoint(uint32_t param_types, | |||
TEE_Param __maybe_unused params[4], | |||
void __maybe_unused **sess_ctx) { | |||
const uint32_t exp_param_types = | |||
TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE, | |||
TEE_PARAM_TYPE_NONE, | |||
TEE_PARAM_TYPE_NONE, | |||
TEE_PARAM_TYPE_NONE); | |||
DMSG("has been called"); | |||
if (param_types != exp_param_types) { | |||
return TEE_ERROR_BAD_PARAMETERS; | |||
} | |||
/* Unused parameters */ | |||
(void)¶ms; | |||
(void)&sess_ctx; | |||
/* | |||
* The DMSG() macro is non-standard, TEE Internal API doesn't | |||
* specify any means to logging from a TA. | |||
*/ | |||
/* If return value != TEE_SUCCESS the session will not be created. */ | |||
return TEE_SUCCESS; | |||
} | |||
/* | |||
* Called when a session is closed, sess_ctx hold the value that was | |||
* assigned by TA_OpenSessionEntryPoint(). | |||
*/ | |||
void TA_CloseSessionEntryPoint(void __maybe_unused *sess_ctx) | |||
{ | |||
(void)&sess_ctx; /* Unused parameter */ | |||
EMSG("Session closed\n"); | |||
} | |||
// Creates new ECC key | |||
static TEE_ObjectHandle create_ecc_key(struct keypair_t *kp) { | |||
TEE_Result res; | |||
TEE_ObjectHandle obj = TEE_HANDLE_NULL; | |||
TEE_Attribute attrs[4]; | |||
struct ECC_t *ecc; | |||
size_t cnt = 0; | |||
ecc = &kp->u.ecc; | |||
res = TEE_AllocateTransientObject( | |||
TEE_TYPE_ECDSA_KEYPAIR, | |||
ecc->x.sz * 8, | |||
&obj); | |||
if (res != TEE_SUCCESS) { | |||
EMSG("E: TEE_AllocateTransientObject failed"); | |||
goto err; | |||
} | |||
ATTR_REF(cnt, TEE_ATTR_ECC_PRIVATE_VALUE, ecc->scalar); | |||
ATTR_REF(cnt, TEE_ATTR_ECC_PUBLIC_VALUE_X, ecc->x); | |||
ATTR_REF(cnt, TEE_ATTR_ECC_PUBLIC_VALUE_Y, ecc->y); | |||
TEE_InitValueAttribute(&attrs[cnt++], TEE_ATTR_ECC_CURVE,ecc->curve_id, 0); | |||
// TODO: ecc->scalar shouldn't be extractable, but we store it with | |||
// the public key, and I need to be able to extract it. | |||
// It would be better to store public and private key separately. | |||
res = TEE_RestrictObjectUsage1(obj, TEE_USAGE_EXTRACTABLE|TEE_USAGE_SIGN); | |||
if (res != TEE_SUCCESS ) { | |||
EMSG("E: TEE_RestrictObjectUsage1 failed"); | |||
goto err; | |||
} | |||
res = TEE_PopulateTransientObject(obj, attrs, cnt); | |||
if (res != TEE_SUCCESS) { | |||
EMSG("E: TEE_PopulateTransientObject failed"); | |||
goto err; | |||
} | |||
return obj; | |||
err: | |||
TEE_FreeTransientObject(obj); | |||
return TEE_HANDLE_NULL; | |||
} | |||
// Puts the key to the storage | |||
static TEE_Result install_key(uint32_t param_types, TEE_Param params[4]) { | |||
TEE_Result ret; | |||
TEE_ObjectHandle transient_obj = TEE_HANDLE_NULL; | |||
TEE_ObjectHandle persistant_obj = TEE_HANDLE_NULL; | |||
uint32_t exp_param_types; | |||
struct keypair_t *kp; | |||
uint8_t key_id[SHA256_SIZE]; | |||
exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, | |||
TEE_PARAM_TYPE_MEMREF_INPUT, | |||
TEE_PARAM_TYPE_NONE, | |||
TEE_PARAM_TYPE_NONE); | |||
if (param_types != exp_param_types || | |||
params[1].memref.size != ARRAY_SIZE(key_id)) { | |||
return TEE_ERROR_BAD_PARAMETERS; | |||
} | |||
kp = (struct keypair_t*)params[0].memref.buffer; | |||
if (sizeof(*kp) != params[0].memref.size) { | |||
EMSG("E: wrong size of keypair_t struct"); | |||
return TEE_ERROR_BAD_PARAMETERS; | |||
} | |||
// Only ECC supported | |||
if (kp->type != KEYTYPE_ECC) { | |||
EMSG("E: only ECC keys supported"); | |||
return TEE_ERROR_BAD_PARAMETERS; | |||
} | |||
transient_obj = create_ecc_key(kp); | |||
if (transient_obj == TEE_HANDLE_NULL) { | |||
EMSG("E: Can't create transient object"); | |||
return TEE_ERROR_BAD_PARAMETERS; | |||
} | |||
// Input TEE_CreatePersistentObject can't be NWd shared buffer | |||
memcpy(key_id, params[1].memref.buffer, params[1].memref.size); | |||
ret = TEE_CreatePersistentObject( | |||
TEE_STORAGE_PRIVATE, | |||
key_id, ARRAY_SIZE(key_id), | |||
TEE_DATA_FLAG_ACCESS_WRITE, | |||
transient_obj, | |||
NULL/*data*/, 0 /*data_len*/, &persistant_obj); | |||
if (ret) { | |||
EMSG("E: Create"); | |||
return ret; | |||
} | |||
IMSG("New key [%02X%02X%02X%02X%02X] registered", | |||
key_id[0], key_id[1], key_id[2], key_id[3], key_id[4]); | |||
TEE_FreeTransientObject(transient_obj); | |||
TEE_CloseObject(persistant_obj); | |||
return TEE_SUCCESS; | |||
} | |||
// Performs key deletion from the secure storage | |||
static TEE_Result del_key(uint32_t param_types, TEE_Param params[4]) { | |||
TEE_Result ret; | |||
char key_id[SHA256_SIZE] = {0}; | |||
TEE_ObjectHandle obj = TEE_HANDLE_NULL; | |||
const uint32_t exp_param_types = | |||
TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, | |||
TEE_PARAM_TYPE_NONE, | |||
TEE_PARAM_TYPE_NONE, | |||
TEE_PARAM_TYPE_NONE); | |||
if (param_types != exp_param_types) | |||
return TEE_ERROR_BAD_PARAMETERS; | |||
if (params[0].memref.size > sizeof(key_id)) { | |||
EMSG("E: filename too long (>255)"); | |||
return TEE_ERROR_BAD_PARAMETERS; | |||
} | |||
memcpy(key_id, params[0].memref.buffer, | |||
params[0].memref.size); | |||
ret = TEE_OpenPersistentObject( | |||
TEE_STORAGE_PRIVATE, | |||
key_id, params[0].memref.size, | |||
TEE_DATA_FLAG_ACCESS_WRITE_META, &obj); | |||
if (ret) { | |||
EMSG("E: Can't open"); | |||
return ret; | |||
} | |||
IMSG("Key [%02X%02X%02X%02X%02X] unregistered", | |||
key_id[0], key_id[1], key_id[2], key_id[3], key_id[4]); | |||
TEE_CloseAndDeletePersistentObject(obj); | |||
return TEE_SUCCESS; | |||
} | |||
// returns public key of installed key-pair to the normal world | |||
static TEE_Result get_public_key(uint32_t param_types, TEE_Param params[4]) { | |||
uint32_t exp_param_types; | |||
char key_id[SHA256_SIZE] = {0}; | |||
TEE_Result ret; | |||
TEE_ObjectHandle obj = TEE_HANDLE_NULL; | |||
exp_param_types = TEE_PARAM_TYPES( | |||
TEE_PARAM_TYPE_MEMREF_INPUT, | |||
TEE_PARAM_TYPE_MEMREF_INOUT, | |||
TEE_PARAM_TYPE_MEMREF_INOUT, | |||
TEE_PARAM_TYPE_NONE); | |||
if (param_types != exp_param_types) { | |||
EMSG("Unexpected params"); | |||
return TEE_ERROR_BAD_PARAMETERS; | |||
} | |||
if (params[0].memref.size < SHA256_SIZE) { | |||
EMSG("key-id must be SHA256 hash"); | |||
return TEE_ERROR_BAD_PARAMETERS; | |||
} | |||
memcpy(key_id, params[0].memref.buffer, params[0].memref.size); | |||
ret = TEE_OpenPersistentObject( | |||
TEE_STORAGE_PRIVATE, | |||
key_id, ARRAY_SIZE(key_id), | |||
TEE_DATA_FLAG_ACCESS_READ, &obj); | |||
if (ret) { | |||
EMSG("E: Open 0x%X", ret); | |||
return ret; | |||
} | |||
ret = TEE_SUCCESS; | |||
ret |= TEE_GetObjectBufferAttribute(obj, TEE_ATTR_ECC_PUBLIC_VALUE_X, | |||
params[1].memref.buffer, ¶ms[1].memref.size); | |||
ret |= TEE_GetObjectBufferAttribute(obj, TEE_ATTR_ECC_PUBLIC_VALUE_Y, | |||
params[2].memref.buffer, ¶ms[2].memref.size); | |||
if (ret) { | |||
EMSG("E: Can't extract public attributes for ECC key"); | |||
goto end; | |||
} | |||
IMSG("Public key for ID [%02X%02X%02X%02X%02X] returned", | |||
key_id[0], key_id[1], key_id[2], key_id[3], key_id[4]); | |||
end: | |||
TEE_CloseObject(obj); | |||
return TEE_SUCCESS; | |||
} | |||
// Performs ECDSA signing with a key from secure storage | |||
static TEE_Result sign_ecdsa(uint32_t param_types, TEE_Param params[4]) { | |||
TEE_Result ret; | |||
TEE_OperationHandle op = TEE_HANDLE_NULL; | |||
TEE_ObjectHandle obj = TEE_HANDLE_NULL; | |||
uint8_t key_id[SHA256_SIZE]; | |||
const uint32_t exp_param_types = | |||
TEE_PARAM_TYPES( | |||
TEE_PARAM_TYPE_MEMREF_INPUT, | |||
TEE_PARAM_TYPE_MEMREF_INPUT, | |||
TEE_PARAM_TYPE_MEMREF_INOUT, | |||
TEE_PARAM_TYPE_NONE); | |||
if ((param_types != exp_param_types) || | |||
(params[0].memref.size > ARRAY_SIZE(key_id))) { | |||
return TEE_ERROR_BAD_PARAMETERS; | |||
} | |||
// Must be local | |||
memcpy(key_id, params[0].memref.buffer, params[0].memref.size); | |||
IMSG("Sign for a key ID [%02X%02X%02X%02X%02X] requested", | |||
key_id[0], key_id[1], key_id[2], key_id[3], key_id[4]); | |||
ret = TEE_OpenPersistentObject( | |||
TEE_STORAGE_PRIVATE, | |||
key_id, ARRAY_SIZE(key_id), | |||
TEE_DATA_FLAG_ACCESS_READ, &obj); | |||
if (ret) { | |||
EMSG("E: Can't open"); | |||
return ret; | |||
} | |||
// perform ECDSA sigining | |||
ret = TEE_AllocateOperation(&op, TEE_ALG_ECDSA_P256, TEE_MODE_SIGN, 256); | |||
LOG_RET(ret); | |||
ret = TEE_SetOperationKey(op, obj); | |||
LOG_RET(ret); | |||
ret = TEE_AsymmetricSignDigest(op, NULL, 0, | |||
params[1].memref.buffer, params[1].memref.size, | |||
params[2].memref.buffer, ¶ms[2].memref.size); | |||
LOG_RET(ret); | |||
TEE_CloseObject(obj); | |||
TEE_FreeOperation(op); | |||
IMSG("Message signed with key ID [%02X%02X%02X%02X%02X]", | |||
key_id[0], key_id[1], key_id[2], key_id[3], key_id[4]); | |||
return TEE_SUCCESS; | |||
} | |||
/* | |||
* Called when a TA is invoked. sess_ctx hold that value that was | |||
* assigned by TA_OpenSessionEntryPoint(). The rest of the paramters | |||
* comes from normal world. | |||
*/ | |||
TEE_Result TA_InvokeCommandEntryPoint(void __maybe_unused *sess_ctx, | |||
uint32_t cmd_id, | |||
uint32_t param_types, TEE_Param params[4]) { | |||
(void)&sess_ctx; /* Unused parameter */ | |||
switch (cmd_id) { | |||
case TA_INSTALL_KEYS: | |||
return install_key(param_types, params); | |||
case TA_DEL_KEYS: | |||
return del_key(param_types, params); | |||
case TA_GET_PUB_KEY: | |||
return get_public_key(param_types, params); | |||
case TA_SIGN_ECC: | |||
return sign_ecdsa(param_types, params); | |||
default: | |||
EMSG("Request not supported"); | |||
return TEE_ERROR_BAD_PARAMETERS; | |||
} | |||
} |
@@ -0,0 +1,67 @@ | |||
#ifndef TA_DELEGATOR_TZ_H | |||
#define TA_DELEGATOR_TZ_H | |||
#include <stdint.h> | |||
#include <stddef.h> | |||
/* | |||
* This UUID is generated with uuidgen | |||
* the ITU-T UUID generator at http://www.itu.int/ITU-T/asn1/uuid.html | |||
*/ | |||
#define TA_UUID \ | |||
{ 0x8aaaf200, 0x2450, 0x11e4, \ | |||
{ 0x00, 0x60, 0x0d, 0xc0, 0xff, 0xee, 0x00, 0x00}} | |||
/* | |||
* TA properties: multi-instance TA, no specific attribute | |||
* TA_FLAG_EXEC_DDR is meaningless but mandated. | |||
*/ | |||
#define TA_FLAGS TA_FLAG_EXEC_DDR | |||
/* Provisioned stack size */ | |||
#define TA_STACK_SIZE (1 * 1024) | |||
/* Provisioned heap size for TEE_Malloc() and friends */ | |||
#define TA_DATA_SIZE (1 * 1024) | |||
/* Extra properties (give a version id and a string name) */ | |||
#define TA_CURRENT_TA_EXT_PROPERTIES \ | |||
{ "gp.ta.description", USER_TA_PROP_TYPE_STRING, "TLS signer TZ" }, \ | |||
{ "gp.ta.version", USER_TA_PROP_TYPE_U32, &(const uint32_t){ 0x0010 } \ | |||
} | |||
/* The function IDs implemented in this TA */ | |||
#define TA_INSTALL_KEYS 0 | |||
#define TA_DEL_KEYS 1 | |||
#define TA_SIGN_ECC 2 | |||
#define TA_GET_PUB_KEY 3 | |||
// SHA-256 output size | |||
#define SHA256_SIZE 32 | |||
#define MAX_KEY_SIZE 512 | |||
struct keybuf_t { | |||
uint8_t b[MAX_KEY_SIZE]; | |||
size_t sz; | |||
}; | |||
typedef enum { | |||
KEYTYPE_ECC = 1, | |||
// ... RSA, PQ ... | |||
} keytype_t; | |||
struct keypair_t { | |||
keytype_t type; | |||
union { | |||
struct ECC_t { | |||
uint32_t curve_id; | |||
struct keybuf_t scalar; | |||
struct keybuf_t x; | |||
struct keybuf_t y; | |||
} ecc; | |||
// rsa, pq, ... | |||
} u; | |||
}; | |||
#endif /*TA_DELEGATOR_TZ_H*/ |
@@ -0,0 +1,2 @@ | |||
global-incdirs-y += include | |||
srcs-y += delegator_tz.c |