зеркало из https://github.com/microsoft/CCF.git
Remove mbedTLS (#3394)
Now that we use OpenSSL for TLS connections, we removed the remaining bits that relied on mbedTLS.
This commit is contained in:
Родитель
0e95e8c0ed
Коммит
8666bbc96f
|
@ -1 +1 @@
|
|||
Daily now!
|
||||
One daily, please!
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the Apache 2.0 License.
|
||||
|
||||
find_path(MBEDTLS_INCLUDE_DIRS mbedtls/ssl.h)
|
||||
|
||||
find_library(MBEDTLS_LIBRARY mbedtls)
|
||||
find_library(MBEDX509_LIBRARY mbedx509)
|
||||
find_library(MBEDCRYPTO_LIBRARY mbedcrypto)
|
||||
|
||||
set(MBEDTLS_LIBRARIES "${MBEDTLS_LIBRARY}" "${MBEDX509_LIBRARY}"
|
||||
"${MBEDCRYPTO_LIBRARY}"
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(
|
||||
MbedTLS DEFAULT_MSG MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY
|
||||
MBEDCRYPTO_LIBRARY
|
||||
)
|
||||
|
||||
mark_as_advanced(
|
||||
MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY
|
||||
)
|
|
@ -35,20 +35,14 @@ find_package(OpenEnclave 0.17.5 CONFIG REQUIRED)
|
|||
# used for our edge cases (eg - for virtual libraries). These do not follow the
|
||||
# standard naming patterns, for example use OE_INCLUDEDIR rather than
|
||||
# OpenEnclave_INCLUDE_DIRS
|
||||
set(OE_CRYPTO_LIB
|
||||
mbedtls
|
||||
CACHE STRING "Crypto library used by enclaves."
|
||||
)
|
||||
|
||||
set(OE_TARGET_LIBC openenclave::oelibc)
|
||||
set(OE_TARGET_ENCLAVE_AND_STD
|
||||
openenclave::oeenclave openenclave::oecryptombedtls openenclave::oelibcxx
|
||||
openenclave::oelibc openenclave::oecryptoopenssl
|
||||
set(OE_TARGET_ENCLAVE_AND_STD openenclave::oeenclave openenclave::oelibcxx
|
||||
openenclave::oelibc openenclave::oecryptoopenssl
|
||||
)
|
||||
# These oe libraries must be linked in specific order
|
||||
set(OE_TARGET_ENCLAVE_CORE_LIBS
|
||||
openenclave::oeenclave openenclave::oecryptombedtls openenclave::oesnmalloc
|
||||
openenclave::oecore openenclave::oesyscall
|
||||
set(OE_TARGET_ENCLAVE_CORE_LIBS openenclave::oeenclave openenclave::oesnmalloc
|
||||
openenclave::oecore openenclave::oesyscall
|
||||
)
|
||||
|
||||
option(LVI_MITIGATIONS "Enable LVI mitigations" ON)
|
||||
|
@ -143,15 +137,6 @@ function(enable_quote_code name)
|
|||
endif()
|
||||
endfunction()
|
||||
|
||||
function(use_client_mbedtls name)
|
||||
target_include_directories(${name} PRIVATE ${CLIENT_MBEDTLS_INCLUDE_DIR})
|
||||
target_link_libraries(${name} PRIVATE ${CLIENT_MBEDTLS_LIBRARIES})
|
||||
endfunction()
|
||||
|
||||
function(use_oe_mbedtls name)
|
||||
target_link_libraries(${name} PRIVATE ${OE_TARGET_ENCLAVE_AND_STD})
|
||||
endfunction()
|
||||
|
||||
# Enclave library wrapper
|
||||
function(add_ccf_app name)
|
||||
|
||||
|
|
|
@ -30,13 +30,6 @@ if(VERBOSE_LOGGING)
|
|||
set(TEST_HOST_LOGGING_LEVEL "debug")
|
||||
endif()
|
||||
|
||||
option(NO_STRICT_TLS_CIPHERSUITES
|
||||
"Disable strict list of valid TLS ciphersuites" OFF
|
||||
)
|
||||
if(NO_STRICT_TLS_CIPHERSUITES)
|
||||
add_compile_definitions(NO_STRICT_TLS_CIPHERSUITES)
|
||||
endif()
|
||||
|
||||
option(USE_NULL_ENCRYPTOR "Turn off encryption of ledger updates - debug only"
|
||||
OFF
|
||||
)
|
||||
|
@ -60,12 +53,6 @@ if(ENABLE_HTTP2)
|
|||
add_compile_definitions(ENABLE_HTTP2)
|
||||
endif()
|
||||
|
||||
option(TLS_PROVIDER_IS_MBEDTLS "Force TLS provider to MbedTLS" OFF)
|
||||
if(TLS_PROVIDER_IS_MBEDTLS)
|
||||
message(STATUS "Using MbedTLS for TLS")
|
||||
add_compile_definitions(TLS_PROVIDER_IS_MBEDTLS)
|
||||
endif()
|
||||
|
||||
option(ENABLE_BFT "Enable experimental BFT consensus at compile time" OFF)
|
||||
if(ENABLE_BFT)
|
||||
add_compile_definitions(ENABLE_BFT)
|
||||
|
@ -90,11 +77,6 @@ set(CCF_3RD_PARTY_INTERNAL_DIR "${CCF_DIR}/3rdparty/internal")
|
|||
include_directories(SYSTEM ${CCF_3RD_PARTY_EXPORTED_DIR})
|
||||
include_directories(SYSTEM ${CCF_3RD_PARTY_INTERNAL_DIR})
|
||||
|
||||
find_package(MbedTLS REQUIRED)
|
||||
|
||||
set(CLIENT_MBEDTLS_INCLUDE_DIR "${MBEDTLS_INCLUDE_DIRS}")
|
||||
set(CLIENT_MBEDTLS_LIBRARIES "${MBEDTLS_LIBRARIES}")
|
||||
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/tools.cmake)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/tools.cmake DESTINATION cmake)
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/ccf_app.cmake)
|
||||
|
@ -332,7 +314,6 @@ install(
|
|||
|
||||
# CCF endpoints libs
|
||||
add_enclave_library(ccf_endpoints.enclave "${CCF_ENDPOINTS_SOURCES}")
|
||||
use_oe_mbedtls(ccf_endpoints.enclave)
|
||||
add_warning_checks(ccf_endpoints.enclave)
|
||||
install(
|
||||
TARGETS ccf_endpoints.enclave
|
||||
|
@ -340,7 +321,6 @@ install(
|
|||
DESTINATION lib
|
||||
)
|
||||
add_host_library(ccf_endpoints.host "${CCF_ENDPOINTS_SOURCES}")
|
||||
use_client_mbedtls(ccf_endpoints.host)
|
||||
add_san(ccf_endpoints.host)
|
||||
add_warning_checks(ccf_endpoints.host)
|
||||
install(
|
||||
|
@ -371,7 +351,6 @@ set(CCF_NETWORK_TEST_ARGS -l ${TEST_HOST_LOGGING_LEVEL} --worker-threads
|
|||
|
||||
if("sgx" IN_LIST COMPILE_TARGETS)
|
||||
add_enclave_library(js_openenclave.enclave ${CCF_DIR}/src/js/openenclave.cpp)
|
||||
use_oe_mbedtls(js_openenclave.enclave)
|
||||
target_link_libraries(js_openenclave.enclave PUBLIC ccf.enclave)
|
||||
add_lvi_mitigations(js_openenclave.enclave)
|
||||
install(
|
||||
|
@ -392,7 +371,6 @@ if("virtual" IN_LIST COMPILE_TARGETS)
|
|||
set_property(
|
||||
TARGET js_openenclave.virtual PROPERTY POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
use_client_mbedtls(js_openenclave.virtual)
|
||||
install(
|
||||
TARGETS js_openenclave.virtual
|
||||
EXPORT ccf
|
||||
|
@ -404,7 +382,6 @@ if("sgx" IN_LIST COMPILE_TARGETS)
|
|||
add_enclave_library(
|
||||
js_generic_base.enclave ${CCF_DIR}/src/apps/js_generic/js_generic_base.cpp
|
||||
)
|
||||
use_oe_mbedtls(js_generic_base.enclave)
|
||||
target_link_libraries(js_generic_base.enclave PUBLIC ccf.enclave)
|
||||
add_lvi_mitigations(js_generic_base.enclave)
|
||||
install(
|
||||
|
@ -429,7 +406,6 @@ if("virtual" IN_LIST COMPILE_TARGETS)
|
|||
set_property(
|
||||
TARGET js_generic_base.virtual PROPERTY POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
use_client_mbedtls(js_generic_base.virtual)
|
||||
install(
|
||||
TARGETS js_generic_base.virtual
|
||||
EXPORT ccf
|
||||
|
|
|
@ -19,7 +19,7 @@ endif()
|
|||
|
||||
# CPack variables for Debian packages
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS
|
||||
"open-enclave (>=0.17.5), libuv1 (>= 1.34.2), libc++1-10, libc++abi1-10"
|
||||
"open-enclave (>=0.17.5), libuv1 (>= 1.34.2), libc++1-10, libc++abi1-10, openssl (>=1.1.1)"
|
||||
)
|
||||
set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT)
|
||||
|
||||
|
|
|
@ -10,25 +10,17 @@ set(CCFCRYPTO_SRC
|
|||
${CCF_DIR}/src/crypto/rsa_key_pair.cpp
|
||||
${CCF_DIR}/src/crypto/verifier.cpp
|
||||
${CCF_DIR}/src/crypto/key_wrap.cpp
|
||||
${CCF_DIR}/src/crypto/mbedtls/symmetric_key.cpp
|
||||
${CCF_DIR}/src/crypto/openssl/symmetric_key.cpp
|
||||
${CCF_DIR}/src/crypto/mbedtls/public_key.cpp
|
||||
${CCF_DIR}/src/crypto/openssl/public_key.cpp
|
||||
${CCF_DIR}/src/crypto/mbedtls/key_pair.cpp
|
||||
${CCF_DIR}/src/crypto/openssl/key_pair.cpp
|
||||
${CCF_DIR}/src/crypto/mbedtls/hash.cpp
|
||||
${CCF_DIR}/src/crypto/openssl/hash.cpp
|
||||
${CCF_DIR}/src/crypto/mbedtls/rsa_public_key.cpp
|
||||
${CCF_DIR}/src/crypto/openssl/rsa_public_key.cpp
|
||||
${CCF_DIR}/src/crypto/mbedtls/rsa_key_pair.cpp
|
||||
${CCF_DIR}/src/crypto/openssl/rsa_key_pair.cpp
|
||||
${CCF_DIR}/src/crypto/mbedtls/verifier.cpp
|
||||
${CCF_DIR}/src/crypto/openssl/verifier.cpp
|
||||
)
|
||||
|
||||
if("sgx" IN_LIST COMPILE_TARGETS)
|
||||
add_enclave_library(ccfcrypto.enclave ${CCFCRYPTO_SRC})
|
||||
use_oe_mbedtls(ccfcrypto.enclave)
|
||||
|
||||
install(
|
||||
TARGETS ccfcrypto.enclave
|
||||
|
@ -43,7 +35,6 @@ target_compile_options(ccfcrypto.host PUBLIC ${COMPILE_LIBCXX})
|
|||
target_link_options(ccfcrypto.host PUBLIC ${LINK_LIBCXX})
|
||||
target_link_libraries(ccfcrypto.host PUBLIC crypto)
|
||||
target_link_libraries(ccfcrypto.host PUBLIC ssl)
|
||||
use_client_mbedtls(ccfcrypto.host)
|
||||
set_property(TARGET ccfcrypto.host PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
install(
|
||||
|
|
|
@ -65,7 +65,6 @@ if(ENABLE_V8)
|
|||
set_property(
|
||||
TARGET js_v8_base.virtual PROPERTY POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
use_client_mbedtls(js_v8_base.virtual)
|
||||
install(
|
||||
TARGETS js_v8_base.virtual
|
||||
EXPORT ccf
|
||||
|
@ -80,7 +79,6 @@ if(ENABLE_V8)
|
|||
add_lvi_mitigations(v8_oe_stubs.enclave)
|
||||
|
||||
add_enclave_library(js_v8_base.enclave ${js_v8_src})
|
||||
use_oe_mbedtls(js_v8_base.enclave)
|
||||
target_include_directories(
|
||||
js_v8_base.enclave PRIVATE ${js_v8_dir} ${v8_sgx_include_dir}
|
||||
)
|
||||
|
|
|
@ -95,7 +95,7 @@ This general signature also allows a handler to see additional caller context. A
|
|||
:end-before: SNIPPET_END: log_record_prefix_cert
|
||||
:dedent:
|
||||
|
||||
This uses mbedTLS to parse the caller's TLS certificate, and prefixes the logged message with the ``Subject`` field extracted from this certificate.
|
||||
This parses the caller's TLS certificate, and prefixes the logged message with the ``Subject`` field extracted from this certificate.
|
||||
|
||||
If a handler makes no writes to the KV, it may be installed as read-only:
|
||||
|
||||
|
|
|
@ -45,8 +45,6 @@ The full list of build switches can be obtained by running:
|
|||
The most common build switches include:
|
||||
|
||||
* **BUILD_TESTS**: Boolean. Build all tests for CCF. Default to ON.
|
||||
* **CLIENT_MBEDTLS_PREFIX**: Path. Prefix to mbedTLS install to be used by test clients. Default to ``/usr/local``.
|
||||
* **NO_STRICT_TLS_CIPHERSUITES**: Boolean. Relax the list of accepted TLS ciphersuites. Default to OFF.
|
||||
* **SAN**: Boolean. Build unit tests with Address and Undefined behaviour sanitizers enabled. Default to OFF.
|
||||
* **COMPILE_TARGETS**: String. List of target compilation platforms. Defaults to ``sgx;virtual``, which builds both "virtual" enclaves and actual SGX enclaves.
|
||||
* **VERBOSE_LOGGING**: Boolean. Enable all logging levels. Default to OFF.
|
||||
|
|
|
@ -34,42 +34,6 @@
|
|||
become: yes
|
||||
when: "'moby-buildx' not in ansible_facts.packages"
|
||||
|
||||
- name: Download mbedtls
|
||||
get_url:
|
||||
url: https://github.com/ARMmbed/mbedtls/archive/{{ mbedtls_src }}
|
||||
dest: "{{ workspace }}/{{ mbedtls_src }}"
|
||||
become: true
|
||||
|
||||
- name: Remove existing mbedtls checkout
|
||||
file:
|
||||
path: "{{ workspace }}/mbedtls-{{ mbedtls_dir }}"
|
||||
state: absent
|
||||
|
||||
- name: Expand mbedtls
|
||||
unarchive:
|
||||
src: "{{ workspace }}/{{ mbedtls_src }}"
|
||||
dest: "{{ workspace }}"
|
||||
copy: no
|
||||
creates: "{{ workspace }}/mbedtls-{{ mbedtls_dir }}/CMakeLists.txt"
|
||||
|
||||
- name: Make mbedtls build dir
|
||||
file:
|
||||
path: "{{ workspace }}/mbedtls-{{ mbedtls_dir }}/build"
|
||||
state: directory
|
||||
|
||||
- name: Build mbedtls
|
||||
shell: |
|
||||
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_POSITION_INDEPENDENT_CODE=ON ..
|
||||
make
|
||||
args:
|
||||
chdir: "{{ workspace }}/mbedtls-{{ mbedtls_dir }}/build"
|
||||
|
||||
- name: Install mbedtls
|
||||
command: make install
|
||||
args:
|
||||
chdir: "{{ workspace }}/mbedtls-{{ mbedtls_dir }}/build"
|
||||
become: true
|
||||
|
||||
- name: Remove doxygen debian package
|
||||
apt:
|
||||
name: doxygen
|
||||
|
|
|
@ -31,10 +31,6 @@ debs:
|
|||
docker_debs:
|
||||
- docker-ce-cli
|
||||
|
||||
mbedtls_ver: "2.16.10"
|
||||
mbedtls_dir: "mbedtls-{{ mbedtls_ver }}"
|
||||
mbedtls_src: "{{ mbedtls_dir }}.tar.gz"
|
||||
|
||||
doxygen_ver: "1.9.3"
|
||||
doxygen_bin: "doxygen-{{ doxygen_ver }}.linux.bin.tar.gz"
|
||||
doxygen_url: "https://doxygen.nl/files/{{ doxygen_bin }}"
|
||||
|
|
|
@ -13,10 +13,7 @@
|
|||
#include "ccf/indexing/seqnos_by_key.h"
|
||||
#include "ccf/user_frontend.h"
|
||||
#include "ccf/version.h"
|
||||
// FIXME: The header below is used for a single check of the certificate and
|
||||
// could be done using OpenSSL. For now, we keep it as is, but we should make
|
||||
// the change once we deprecate, and remove, mbedTLS.
|
||||
#include "crypto/mbedtls/mbedtls_wrappers.h"
|
||||
#include "crypto/verifier.h"
|
||||
|
||||
#include <charconv>
|
||||
#define FMT_HEADER_ONLY
|
||||
|
@ -439,12 +436,13 @@ namespace loggingapp
|
|||
return;
|
||||
}
|
||||
|
||||
auto cert = mbedtls::make_unique<mbedtls::X509Crt>();
|
||||
|
||||
const auto& cert_data = ctx.rpc_ctx->session->caller_cert;
|
||||
const auto ret = mbedtls_x509_crt_parse(
|
||||
cert.get(), cert_data.data(), cert_data.size());
|
||||
if (ret != 0)
|
||||
std::shared_ptr<Verifier> verifier;
|
||||
try
|
||||
{
|
||||
const auto& cert_data = ctx.rpc_ctx->session->caller_cert;
|
||||
verifier = make_verifier(cert_data);
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
ctx.rpc_ctx->set_error(
|
||||
HTTP_STATUS_INTERNAL_SERVER_ERROR,
|
||||
|
@ -453,7 +451,8 @@ namespace loggingapp
|
|||
return;
|
||||
}
|
||||
|
||||
const auto log_line = fmt::format("{}: {}", cert->subject, in.msg);
|
||||
const auto log_line =
|
||||
fmt::format("{}: {}", verifier->subject(), in.msg);
|
||||
auto records_handle = ctx.tx.template rw<RecordsMap>(PRIVATE_RECORDS);
|
||||
records_handle->put(in.id, log_line);
|
||||
update_first_write(ctx.tx, in.id);
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "crypto/mbedtls/error_string.h"
|
||||
#include "crypto/mbedtls/mbedtls_wrappers.h"
|
||||
#include "crypto/pem.h"
|
||||
#include "ds/buffer.h"
|
||||
|
||||
#include <exception>
|
||||
|
||||
// This is a copy of src/tls/ca.h
|
||||
// Moving tls to OpenSSL means this different client implementation needs
|
||||
// to be isolated while we change tls_endpoint. Once that's done, we can
|
||||
// come back here and refactor this too.
|
||||
|
||||
namespace client::tls
|
||||
{
|
||||
enum TlsAuth
|
||||
{
|
||||
tls_auth_default,
|
||||
tls_auth_none,
|
||||
tls_auth_optional,
|
||||
tls_auth_required
|
||||
};
|
||||
|
||||
class TlsCA
|
||||
{
|
||||
private:
|
||||
crypto::mbedtls::X509Crt ca = nullptr;
|
||||
crypto::mbedtls::X509Crl crl = nullptr;
|
||||
|
||||
public:
|
||||
TlsCA(CBuffer ca_ = nullb, CBuffer crl_ = nullb)
|
||||
{
|
||||
auto tmp_ca = crypto::mbedtls::make_unique<crypto::mbedtls::X509Crt>();
|
||||
auto tmp_crl = crypto::mbedtls::make_unique<crypto::mbedtls::X509Crl>();
|
||||
|
||||
if (ca_.n > 0)
|
||||
{
|
||||
crypto::Pem pem_ca(ca_);
|
||||
auto ret =
|
||||
mbedtls_x509_crt_parse(tmp_ca.get(), pem_ca.data(), pem_ca.size());
|
||||
if (ret != 0)
|
||||
throw std::logic_error(
|
||||
"Could not parse TlsCA: " + crypto::error_string(ret));
|
||||
}
|
||||
|
||||
if (crl_.n > 0)
|
||||
{
|
||||
crypto::Pem pem_crl(crl_);
|
||||
auto ret =
|
||||
mbedtls_x509_crl_parse(tmp_crl.get(), pem_crl.data(), pem_crl.size());
|
||||
if (ret != 0)
|
||||
throw std::logic_error(
|
||||
"Could not parse CRL: " + crypto::error_string(ret));
|
||||
}
|
||||
|
||||
ca = std::move(tmp_ca);
|
||||
crl = std::move(tmp_crl);
|
||||
}
|
||||
|
||||
~TlsCA() {}
|
||||
|
||||
void use(mbedtls_ssl_config* cfg)
|
||||
{
|
||||
mbedtls_ssl_conf_ca_chain(cfg, ca.get(), crl.get());
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,147 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "ca.h"
|
||||
#include "crypto/mbedtls/error_string.h"
|
||||
#include "crypto/mbedtls/mbedtls_wrappers.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
// This is a copy of src/tls/cert.h
|
||||
// Moving tls to OpenSSL means this different client implementation needs
|
||||
// to be isolated while we change tls_endpoint. Once that's done, we can
|
||||
// come back here and refactor this too.
|
||||
|
||||
using namespace crypto;
|
||||
|
||||
namespace client::tls
|
||||
{
|
||||
// This class represents the authentication/authorization context for a TLS
|
||||
// session. At least, it contains the peer's CA. At most, it also contains our
|
||||
// own private key/certificate which will be presented in the TLS handshake.
|
||||
// The peer's certificate verification can be overridden with the auth
|
||||
// parameter.
|
||||
class TlsCert
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<TlsCA> peer_ca;
|
||||
std::optional<std::string> peer_hostname;
|
||||
|
||||
mbedtls::X509Crt own_cert = nullptr;
|
||||
mbedtls::PKContext own_pkey = nullptr;
|
||||
bool has_own_cert;
|
||||
|
||||
TlsAuth auth;
|
||||
|
||||
public:
|
||||
TlsCert(
|
||||
std::shared_ptr<TlsCA> peer_ca_,
|
||||
const std::optional<crypto::Pem>& own_cert_ = std::nullopt,
|
||||
const std::optional<crypto::Pem>& own_pkey_ = std::nullopt,
|
||||
CBuffer pw = nullb,
|
||||
TlsAuth tls_auth_ = tls_auth_default,
|
||||
const std::optional<std::string>& peer_hostname_ = std::nullopt) :
|
||||
peer_ca(peer_ca_),
|
||||
peer_hostname(peer_hostname_),
|
||||
has_own_cert(false),
|
||||
auth(tls_auth_)
|
||||
{
|
||||
auto tmp_cert = mbedtls::make_unique<mbedtls::X509Crt>();
|
||||
auto tmp_pkey = mbedtls::make_unique<mbedtls::PKContext>();
|
||||
|
||||
if (own_cert_.has_value() && own_pkey_.has_value())
|
||||
{
|
||||
int rc = mbedtls_x509_crt_parse(
|
||||
tmp_cert.get(), own_cert_->data(), own_cert_->size());
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(
|
||||
"Could not parse certificate: " + error_string(rc));
|
||||
}
|
||||
|
||||
rc = mbedtls_pk_parse_key(
|
||||
tmp_pkey.get(), own_pkey_->data(), own_pkey_->size(), pw.p, pw.n);
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error("Could not parse key: " + error_string(rc));
|
||||
}
|
||||
|
||||
has_own_cert = true;
|
||||
}
|
||||
|
||||
own_cert = std::move(tmp_cert);
|
||||
own_pkey = std::move(tmp_pkey);
|
||||
}
|
||||
|
||||
~TlsCert() {}
|
||||
|
||||
void use(mbedtls_ssl_context* ssl, mbedtls_ssl_config* cfg)
|
||||
{
|
||||
if (peer_hostname.has_value())
|
||||
{
|
||||
// Peer hostname is only checked against peer certificate (SAN
|
||||
// extension) if it is set. This lets us connect to peers that present
|
||||
// certificates with IPAddress in SAN field (mbedtls does not parse
|
||||
// IPAddress in SAN field). This is OK since we check for peer CA
|
||||
// endorsement.
|
||||
mbedtls_ssl_set_hostname(ssl, peer_hostname->c_str());
|
||||
}
|
||||
|
||||
if (peer_ca)
|
||||
{
|
||||
peer_ca->use(cfg);
|
||||
}
|
||||
|
||||
if (auth != tls_auth_default)
|
||||
{
|
||||
mbedtls_ssl_conf_authmode(cfg, authmode(auth));
|
||||
}
|
||||
|
||||
if (has_own_cert)
|
||||
{
|
||||
mbedtls_ssl_conf_own_cert(cfg, own_cert.get(), own_pkey.get());
|
||||
}
|
||||
}
|
||||
|
||||
const mbedtls_x509_crt* raw()
|
||||
{
|
||||
return own_cert.get();
|
||||
}
|
||||
|
||||
private:
|
||||
int authmode(TlsAuth auth)
|
||||
{
|
||||
switch (auth)
|
||||
{
|
||||
case tls_auth_none:
|
||||
{
|
||||
// Peer certificate is not checked
|
||||
return MBEDTLS_SSL_VERIFY_NONE;
|
||||
}
|
||||
|
||||
case tls_auth_optional:
|
||||
{
|
||||
// Peer certificate is checked but handshake continues even if
|
||||
// verification fails
|
||||
return MBEDTLS_SSL_VERIFY_OPTIONAL;
|
||||
}
|
||||
|
||||
case tls_auth_required:
|
||||
{
|
||||
// Peer must present a valid certificate
|
||||
return MBEDTLS_SSL_VERIFY_REQUIRED;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return MBEDTLS_SSL_VERIFY_REQUIRED;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -105,8 +105,8 @@ namespace client
|
|||
HttpRpcTlsClient(
|
||||
const std::string& host,
|
||||
const std::string& port,
|
||||
std::shared_ptr<tls::TlsCA> node_ca = nullptr,
|
||||
std::shared_ptr<tls::TlsCert> cert = nullptr,
|
||||
std::shared_ptr<tls::CA> node_ca = nullptr,
|
||||
std::shared_ptr<tls::Cert> cert = nullptr,
|
||||
const std::string& key_id_ = "Invalid") :
|
||||
TlsClient(host, port, node_ca, cert),
|
||||
parser(*this),
|
||||
|
|
|
@ -2,26 +2,66 @@
|
|||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "ca.h"
|
||||
#include "cert.h"
|
||||
#include "crypto/mbedtls/error_string.h"
|
||||
#include "crypto/openssl/openssl_wrappers.h"
|
||||
#include "ds/buffer.h"
|
||||
#include "ds/logger.h"
|
||||
#include "tls/ca.h"
|
||||
#include "tls/cert.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <mbedtls/config.h>
|
||||
#include <mbedtls/ctr_drbg.h>
|
||||
#include <mbedtls/entropy.h>
|
||||
#include <mbedtls/error.h>
|
||||
#include <mbedtls/net_sockets.h>
|
||||
#include <mbedtls/ssl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace crypto;
|
||||
using namespace crypto::OpenSSL;
|
||||
|
||||
#ifdef _DEBUG
|
||||
static BIO* bio_err = NULL;
|
||||
|
||||
static void apps_ssl_info_callback(const SSL* s, int where, int ret)
|
||||
{
|
||||
const char* str;
|
||||
int w = where & ~SSL_ST_MASK;
|
||||
|
||||
if (w & SSL_ST_CONNECT)
|
||||
str = "SSL_connect";
|
||||
else if (w & SSL_ST_ACCEPT)
|
||||
str = "SSL_accept";
|
||||
else
|
||||
str = "undefined";
|
||||
|
||||
if (where & SSL_CB_LOOP)
|
||||
{
|
||||
BIO_printf(bio_err, "%s:%s\n", str, SSL_state_string_long(s));
|
||||
}
|
||||
else if (where & SSL_CB_ALERT)
|
||||
{
|
||||
str = (where & SSL_CB_READ) ? "read" : "write";
|
||||
BIO_printf(
|
||||
bio_err,
|
||||
"SSL3 alert %s:%s:%s\n",
|
||||
str,
|
||||
SSL_alert_type_string_long(ret),
|
||||
SSL_alert_desc_string_long(ret));
|
||||
}
|
||||
else if (where & SSL_CB_EXIT)
|
||||
{
|
||||
if (ret == 0)
|
||||
{
|
||||
BIO_printf(bio_err, "%s:failed in %s\n", str, SSL_state_string_long(s));
|
||||
}
|
||||
else if (ret < 0)
|
||||
{
|
||||
BIO_printf(bio_err, "%s:error in %s\n", str, SSL_state_string_long(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace client
|
||||
{
|
||||
|
@ -30,98 +70,65 @@ namespace client
|
|||
protected:
|
||||
std::string host;
|
||||
std::string port;
|
||||
std::shared_ptr<tls::TlsCA> node_ca;
|
||||
std::shared_ptr<tls::TlsCert> cert;
|
||||
std::shared_ptr<tls::CA> node_ca;
|
||||
std::shared_ptr<tls::Cert> cert;
|
||||
bool connected = false;
|
||||
|
||||
mbedtls::NetContext server_fd;
|
||||
mbedtls::Entropy entropy;
|
||||
mbedtls::CtrDrbg ctr_drbg;
|
||||
mbedtls::SSLContext ssl;
|
||||
mbedtls::SSLConfig conf;
|
||||
Unique_SSL_CTX ctx;
|
||||
Unique_BIO bio;
|
||||
|
||||
void init()
|
||||
{
|
||||
auto tmp_server_fd = mbedtls::make_unique<mbedtls::NetContext>();
|
||||
auto tmp_entropy = mbedtls::make_unique<mbedtls::Entropy>();
|
||||
auto tmp_ctr_drbg = mbedtls::make_unique<mbedtls::CtrDrbg>();
|
||||
auto tmp_ssl = mbedtls::make_unique<mbedtls::SSLContext>();
|
||||
auto tmp_conf = mbedtls::make_unique<mbedtls::SSLConfig>();
|
||||
SSL_CTX_clear_mode(ctx, SSL_MODE_AUTO_RETRY);
|
||||
|
||||
auto err = mbedtls_ctr_drbg_seed(
|
||||
tmp_ctr_drbg.get(),
|
||||
mbedtls_entropy_func,
|
||||
tmp_entropy.get(),
|
||||
nullptr,
|
||||
0);
|
||||
if (err)
|
||||
throw std::logic_error(crypto::error_string(err));
|
||||
|
||||
err = mbedtls_net_connect(
|
||||
tmp_server_fd.get(), host.c_str(), port.c_str(), MBEDTLS_NET_PROTO_TCP);
|
||||
if (err)
|
||||
throw std::logic_error(crypto::error_string(err));
|
||||
|
||||
err = mbedtls_ssl_config_defaults(
|
||||
tmp_conf.get(),
|
||||
MBEDTLS_SSL_IS_CLIENT,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||
MBEDTLS_SSL_PRESET_DEFAULT);
|
||||
if (err)
|
||||
throw std::logic_error(crypto::error_string(err));
|
||||
|
||||
if (cert != nullptr)
|
||||
cert->use(tmp_ssl.get(), tmp_conf.get());
|
||||
if (node_ca != nullptr)
|
||||
node_ca->use(tmp_conf.get());
|
||||
|
||||
mbedtls_ssl_conf_rng(
|
||||
tmp_conf.get(), mbedtls_ctr_drbg_random, tmp_ctr_drbg.get());
|
||||
mbedtls_ssl_conf_authmode(tmp_conf.get(), MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||
|
||||
err = mbedtls_ssl_setup(tmp_ssl.get(), tmp_conf.get());
|
||||
if (err)
|
||||
throw std::logic_error(crypto::error_string(err));
|
||||
|
||||
if (err)
|
||||
throw std::logic_error(crypto::error_string(err));
|
||||
|
||||
mbedtls_ssl_set_bio(
|
||||
tmp_ssl.get(),
|
||||
tmp_server_fd.get(),
|
||||
mbedtls_net_send,
|
||||
mbedtls_net_recv,
|
||||
nullptr);
|
||||
|
||||
while (true)
|
||||
SSL* ssl;
|
||||
BIO_get_ssl(bio, &ssl);
|
||||
if (!ssl)
|
||||
{
|
||||
err = mbedtls_ssl_handshake(tmp_ssl.get());
|
||||
if (err == 0)
|
||||
break;
|
||||
if (
|
||||
(err != MBEDTLS_ERR_SSL_WANT_READ) &&
|
||||
(err != MBEDTLS_ERR_SSL_WANT_WRITE))
|
||||
throw std::logic_error(crypto::error_string(err));
|
||||
throw std::runtime_error("Couldn't locate SSL pointer");
|
||||
}
|
||||
connected = true;
|
||||
SSL_clear_mode(ssl, SSL_MODE_AUTO_RETRY);
|
||||
|
||||
server_fd = std::move(tmp_server_fd);
|
||||
entropy = std::move(tmp_entropy);
|
||||
ctr_drbg = std::move(tmp_ctr_drbg);
|
||||
ssl = std::move(tmp_ssl);
|
||||
conf = std::move(tmp_conf);
|
||||
#ifdef _DEBUG
|
||||
bio_err = BIO_new_fp(stdout, BIO_NOCLOSE);
|
||||
SSL_CTX_set_info_callback(ctx, apps_ssl_info_callback);
|
||||
SSL_set_info_callback(ssl, apps_ssl_info_callback);
|
||||
#endif
|
||||
|
||||
BIO_set_conn_hostname(bio, host.c_str());
|
||||
BIO_set_conn_port(bio, port.c_str());
|
||||
BIO_set_nbio(bio, 1);
|
||||
|
||||
if (cert)
|
||||
cert->use(ssl, ctx);
|
||||
if (node_ca)
|
||||
node_ca->use(ctx);
|
||||
|
||||
do
|
||||
{
|
||||
BIO_do_connect(bio);
|
||||
} while (BIO_should_retry(bio));
|
||||
|
||||
do
|
||||
{
|
||||
BIO_do_handshake(bio);
|
||||
} while (BIO_should_retry(bio));
|
||||
|
||||
connected = true;
|
||||
}
|
||||
|
||||
public:
|
||||
TlsClient(
|
||||
const std::string& host,
|
||||
const std::string& port,
|
||||
std::shared_ptr<tls::TlsCA> node_ca = nullptr,
|
||||
std::shared_ptr<tls::TlsCert> cert = nullptr) :
|
||||
std::shared_ptr<tls::CA> node_ca = nullptr,
|
||||
std::shared_ptr<tls::Cert> cert = nullptr) :
|
||||
host(host),
|
||||
port(port),
|
||||
node_ca(node_ca),
|
||||
cert(cert)
|
||||
cert(cert),
|
||||
ctx(TLS_client_method()),
|
||||
bio(ctx)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
@ -130,39 +137,53 @@ namespace client
|
|||
host(c.host),
|
||||
port(c.port),
|
||||
node_ca(c.node_ca),
|
||||
cert(c.cert)
|
||||
cert(c.cert),
|
||||
ctx(TLS_client_method()),
|
||||
bio(ctx)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
virtual ~TlsClient()
|
||||
{
|
||||
// Signal the end of the connection
|
||||
if (connected)
|
||||
mbedtls_ssl_close_notify(ssl.get());
|
||||
}
|
||||
virtual ~TlsClient() {}
|
||||
|
||||
auto get_ciphersuite_name()
|
||||
{
|
||||
return mbedtls_ssl_get_ciphersuite(ssl.get());
|
||||
SSL* ssl;
|
||||
BIO_get_ssl(bio, &ssl);
|
||||
return SSL_CIPHER_get_name(SSL_get_current_cipher(ssl));
|
||||
}
|
||||
|
||||
void write(CBuffer b)
|
||||
{
|
||||
for (size_t written = 0; written < b.n;)
|
||||
{
|
||||
auto ret = mbedtls_ssl_write(ssl.get(), b.p + written, b.n - written);
|
||||
if (ret > 0)
|
||||
auto ret = 0;
|
||||
do
|
||||
{
|
||||
ret = BIO_write(bio, b.p + written, b.n - written);
|
||||
} while (ret < 0 && BIO_should_retry(bio));
|
||||
|
||||
if (ret >= 0)
|
||||
{
|
||||
written += ret;
|
||||
}
|
||||
else
|
||||
throw std::logic_error(crypto::error_string(ret));
|
||||
{
|
||||
throw std::logic_error(error_string(ERR_get_error()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> read(size_t read_size)
|
||||
{
|
||||
std::vector<uint8_t> buf(read_size);
|
||||
auto ret = mbedtls_ssl_read(ssl.get(), buf.data(), buf.size());
|
||||
|
||||
auto ret = 0;
|
||||
do
|
||||
{
|
||||
ret = BIO_read(bio, buf.data(), buf.size());
|
||||
} while (ret < 0 && BIO_should_retry(bio));
|
||||
|
||||
if (ret > 0)
|
||||
{
|
||||
buf.resize(ret);
|
||||
|
@ -174,7 +195,7 @@ namespace client
|
|||
}
|
||||
else
|
||||
{
|
||||
throw std::logic_error(crypto::error_string(ret));
|
||||
throw std::logic_error(error_string(ERR_get_error()));
|
||||
}
|
||||
|
||||
return buf;
|
||||
|
@ -182,14 +203,19 @@ namespace client
|
|||
|
||||
bool bytes_available()
|
||||
{
|
||||
return mbedtls_ssl_get_bytes_avail(ssl.get()) > 0;
|
||||
return BIO_pending(bio) > 0;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> read_all()
|
||||
{
|
||||
constexpr auto read_size = 4096;
|
||||
std::vector<uint8_t> buf(read_size);
|
||||
auto ret = mbedtls_ssl_read(ssl.get(), buf.data(), buf.size());
|
||||
auto ret = 0;
|
||||
do
|
||||
{
|
||||
ret = BIO_read(bio, buf.data(), buf.size());
|
||||
} while (ret < 0 && BIO_should_retry(bio));
|
||||
|
||||
if (ret > 0)
|
||||
{
|
||||
buf.resize(ret);
|
||||
|
@ -201,7 +227,7 @@ namespace client
|
|||
}
|
||||
else
|
||||
{
|
||||
throw std::logic_error(crypto::error_string(ret));
|
||||
throw std::logic_error(error_string(ERR_get_error()));
|
||||
}
|
||||
|
||||
return buf;
|
||||
|
@ -210,8 +236,9 @@ namespace client
|
|||
void set_tcp_nodelay(bool on)
|
||||
{
|
||||
int option = on ? 1 : 0;
|
||||
setsockopt(
|
||||
server_fd->fd, IPPROTO_TCP, TCP_NODELAY, (char*)&option, sizeof(int));
|
||||
int fd = -1;
|
||||
BIO_get_fd(bio, &fd);
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&option, sizeof(int));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
|
||||
#include "ccf/entity_id.h"
|
||||
#include "consensus/consensus_types.h"
|
||||
#include "crypto/ecdsa.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "ds/ring_buffer_types.h"
|
||||
#include "enclave/rpc_context.h"
|
||||
#include "enclave/rpc_handler.h"
|
||||
#include "kv/kv_types.h"
|
||||
#include "mbedtls/ecdsa.h"
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
|
@ -151,15 +151,6 @@ namespace aft
|
|||
AppendEntriesResponseType success;
|
||||
};
|
||||
|
||||
struct SignedAppendEntriesResponse : RaftHeader
|
||||
{
|
||||
Term term;
|
||||
Index last_log_idx;
|
||||
Nonce hashed_nonce;
|
||||
uint32_t signature_size;
|
||||
std::array<uint8_t, MBEDTLS_ECDSA_MAX_LEN> sig;
|
||||
};
|
||||
|
||||
struct SignaturesReceivedAck : RaftHeader
|
||||
{
|
||||
Term term;
|
||||
|
@ -202,4 +193,4 @@ namespace aft
|
|||
bool vote_granted;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,13 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
|
||||
#include "mbedtls/base64.h"
|
||||
#include "openssl/base64.h"
|
||||
|
||||
#include "ds/logger.h"
|
||||
#include "openssl/base64.h"
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
#ifdef CRYPTO_PROVIDER_IS_MBEDTLS
|
||||
using Base64Impl = Base64_mbedtls;
|
||||
#else
|
||||
using Base64Impl = Base64_openssl;
|
||||
#endif
|
||||
|
||||
std::vector<uint8_t> raw_from_b64(const std::string_view& b64_string)
|
||||
{
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "entropy.h"
|
||||
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "openssl/entropy.h"
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
|
@ -16,6 +16,6 @@ namespace crypto
|
|||
return intel_drng_ptr;
|
||||
}
|
||||
|
||||
return std::make_shared<Entropy_mbedTLS>();
|
||||
return std::make_shared<Entropy_OpenSSL>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,9 +35,6 @@ namespace crypto
|
|||
Entropy() = default;
|
||||
virtual ~Entropy() = default;
|
||||
|
||||
virtual void* get_data() = 0;
|
||||
virtual rng_func_t get_rng() = 0;
|
||||
|
||||
/// Generate @p len random bytes
|
||||
/// @param len Number of random bytes to generate
|
||||
/// @return vector random bytes
|
||||
|
@ -328,16 +325,6 @@ namespace crypto
|
|||
return 0;
|
||||
}
|
||||
|
||||
rng_func_t get_rng() override
|
||||
{
|
||||
return &rng;
|
||||
}
|
||||
|
||||
void* get_data() override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
static bool is_drng_supported()
|
||||
{
|
||||
return (get_drng_support() & (DRNG_HAS_RDRAND | DRNG_HAS_RDSEED)) ==
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
// Licensed under the Apache 2.0 License.
|
||||
#include "hash.h"
|
||||
|
||||
#include "mbedtls/hash.h"
|
||||
#include "openssl/hash.h"
|
||||
|
||||
#include <openssl/sha.h>
|
||||
|
@ -48,10 +47,6 @@ namespace crypto
|
|||
const std::vector<uint8_t>& salt,
|
||||
const std::vector<uint8_t>& info)
|
||||
{
|
||||
#if defined(CRYPTO_PROVIDER_IS_MBEDTLS)
|
||||
return mbedtls::hkdf(md_type, length, ikm, salt, info);
|
||||
#else
|
||||
return OpenSSL::hkdf(md_type, length, ikm, salt, info);
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -4,16 +4,15 @@
|
|||
|
||||
#include "crypto/entropy.h"
|
||||
#include "crypto/key_pair.h"
|
||||
#include "crypto/mbedtls/error_string.h"
|
||||
#include "crypto/mbedtls/key_pair.h"
|
||||
#include "crypto/openssl/openssl_wrappers.h"
|
||||
#include "crypto/openssl/public_key.h"
|
||||
#include "ds/logger.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <mbedtls/ecdh.h>
|
||||
#include <mbedtls/ecp.h>
|
||||
#include <mbedtls/pk.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/ossl_typ.h>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace tls
|
||||
|
@ -21,182 +20,102 @@ namespace tls
|
|||
class KeyExchangeContext
|
||||
{
|
||||
private:
|
||||
crypto::mbedtls::ECDHContext ctx = nullptr;
|
||||
std::vector<uint8_t> key_share;
|
||||
std::vector<uint8_t> peer_key_share;
|
||||
|
||||
void create_fresh_key_share()
|
||||
{
|
||||
auto tmp_ctx =
|
||||
crypto::mbedtls::make_unique<crypto::mbedtls::ECDHContext>();
|
||||
size_t len = 0;
|
||||
|
||||
int rc = mbedtls_ecp_group_load(&tmp_ctx->grp, domain_parameter);
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(crypto::error_string(rc));
|
||||
}
|
||||
|
||||
crypto::EntropyPtr entropy = crypto::create_entropy();
|
||||
|
||||
key_share.resize(len_public);
|
||||
|
||||
rc = mbedtls_ecdh_make_public(
|
||||
tmp_ctx.get(),
|
||||
&len,
|
||||
key_share.data(),
|
||||
key_share.size(),
|
||||
entropy->get_rng(),
|
||||
entropy->get_data());
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(crypto::error_string(rc));
|
||||
}
|
||||
|
||||
key_share.resize(len);
|
||||
|
||||
ctx = std::move(tmp_ctx);
|
||||
}
|
||||
crypto::KeyPairPtr own_key;
|
||||
crypto::PublicKeyPtr peer_key;
|
||||
crypto::CurveID curve;
|
||||
|
||||
public:
|
||||
static constexpr mbedtls_ecp_group_id domain_parameter =
|
||||
MBEDTLS_ECP_DP_SECP384R1;
|
||||
|
||||
static constexpr size_t len_public = 1024 + 1;
|
||||
static constexpr size_t len_shared_secret = 1024;
|
||||
|
||||
KeyExchangeContext() : key_share(len_public)
|
||||
KeyExchangeContext() : curve(crypto::CurveID::SECP384R1)
|
||||
{
|
||||
create_fresh_key_share();
|
||||
own_key = make_key_pair(curve);
|
||||
}
|
||||
|
||||
KeyExchangeContext(
|
||||
std::shared_ptr<crypto::KeyPair_mbedTLS> own_kp,
|
||||
std::shared_ptr<crypto::PublicKey_mbedTLS> peer_pubk)
|
||||
std::shared_ptr<crypto::KeyPair> own_kp,
|
||||
std::shared_ptr<crypto::PublicKey> peer_pubk) :
|
||||
curve(own_kp->get_curve_id())
|
||||
{
|
||||
auto tmp_ctx =
|
||||
crypto::mbedtls::make_unique<crypto::mbedtls::ECDHContext>();
|
||||
|
||||
int rc = mbedtls_ecdh_get_params(
|
||||
tmp_ctx.get(),
|
||||
mbedtls_pk_ec(*own_kp->get_raw_context()),
|
||||
MBEDTLS_ECDH_OURS);
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(crypto::error_string(rc));
|
||||
}
|
||||
|
||||
rc = mbedtls_ecdh_get_params(
|
||||
tmp_ctx.get(),
|
||||
mbedtls_pk_ec(*peer_pubk->get_raw_context()),
|
||||
MBEDTLS_ECDH_THEIRS);
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(crypto::error_string(rc));
|
||||
}
|
||||
ctx = std::move(tmp_ctx);
|
||||
own_key = own_kp;
|
||||
peer_key = peer_pubk;
|
||||
}
|
||||
|
||||
void free_ctx()
|
||||
{
|
||||
// Should only be called when shared secret has been computed.
|
||||
ctx.reset();
|
||||
}
|
||||
~KeyExchangeContext() {}
|
||||
|
||||
~KeyExchangeContext()
|
||||
std::vector<uint8_t> get_own_key_share() const
|
||||
{
|
||||
free_ctx();
|
||||
|
||||
OPENSSL_cleanse(key_share.data(), key_share.size());
|
||||
}
|
||||
|
||||
const std::vector<uint8_t>& get_own_key_share() const
|
||||
{
|
||||
if (!ctx)
|
||||
if (!own_key)
|
||||
{
|
||||
throw std::runtime_error("Missing key exchange context");
|
||||
throw std::runtime_error("missing node key");
|
||||
}
|
||||
|
||||
if (key_share.empty())
|
||||
{
|
||||
throw std::runtime_error("Missing node key share");
|
||||
}
|
||||
|
||||
// Note that this function returns a vector of bytes
|
||||
// where the first byte represents the
|
||||
// size of the public key
|
||||
return key_share;
|
||||
// For backwards compatibility we need to keep the format we used with
|
||||
// mbedTLS, which is the raw EC point with an extra size byte in the
|
||||
// front.
|
||||
auto tmp = own_key->public_key_raw();
|
||||
tmp.insert(tmp.begin(), tmp.size());
|
||||
return tmp;
|
||||
}
|
||||
|
||||
const std::vector<uint8_t>& get_peer_key_share() const
|
||||
std::vector<uint8_t> get_peer_key_share() const
|
||||
{
|
||||
return peer_key_share;
|
||||
if (!peer_key)
|
||||
{
|
||||
throw std::runtime_error("missing peer key");
|
||||
}
|
||||
|
||||
auto tmp = peer_key->public_key_raw();
|
||||
tmp.insert(tmp.begin(), tmp.size());
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
key_share.clear();
|
||||
peer_key_share.clear();
|
||||
ctx.reset();
|
||||
create_fresh_key_share();
|
||||
peer_key.reset();
|
||||
own_key = make_key_pair(crypto::CurveID::SECP384R1);
|
||||
}
|
||||
|
||||
void load_peer_key_share(const std::vector<uint8_t>& ks)
|
||||
{
|
||||
load_peer_key_share({ks.data(), ks.size()});
|
||||
if (ks.size() == 0)
|
||||
{
|
||||
throw std::runtime_error("missing peer key share");
|
||||
}
|
||||
|
||||
auto tmp = ks;
|
||||
tmp.erase(tmp.begin());
|
||||
|
||||
int nid = crypto::PublicKey_OpenSSL::get_openssl_group_id(curve);
|
||||
auto pk = crypto::key_from_raw_ec_point(tmp, nid);
|
||||
|
||||
if (!pk)
|
||||
{
|
||||
throw std::runtime_error("could not parse peer key share");
|
||||
}
|
||||
|
||||
peer_key = std::make_shared<crypto::PublicKey_OpenSSL>(pk);
|
||||
}
|
||||
|
||||
void load_peer_key_share(CBuffer ks)
|
||||
{
|
||||
if (!ctx)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Missing key exchange context when loading peer key share");
|
||||
}
|
||||
|
||||
if (ks.n == 0)
|
||||
{
|
||||
throw std::runtime_error("Missing peer key share");
|
||||
}
|
||||
|
||||
peer_key_share = {ks.p, ks.p + ks.n};
|
||||
load_peer_key_share({ks.p, ks.p + ks.n});
|
||||
}
|
||||
|
||||
std::vector<uint8_t> compute_shared_secret()
|
||||
{
|
||||
int rc;
|
||||
if (peer_key_share.size() > 0)
|
||||
if (!own_key)
|
||||
{
|
||||
rc = mbedtls_ecdh_read_public(
|
||||
ctx.get(), peer_key_share.data(), peer_key_share.size());
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(crypto::error_string(rc));
|
||||
}
|
||||
throw std::logic_error("missing own key");
|
||||
}
|
||||
|
||||
crypto::EntropyPtr entropy = crypto::create_entropy();
|
||||
|
||||
// Should only be called once, when peer public has been loaded.
|
||||
std::vector<uint8_t> shared_secret(len_shared_secret);
|
||||
size_t len;
|
||||
rc = mbedtls_ecdh_calc_secret(
|
||||
ctx.get(),
|
||||
&len,
|
||||
shared_secret.data(),
|
||||
shared_secret.size(),
|
||||
entropy->get_rng(),
|
||||
entropy->get_data());
|
||||
if (rc != 0)
|
||||
if (!peer_key)
|
||||
{
|
||||
throw std::logic_error(crypto::error_string(rc));
|
||||
throw std::logic_error("missing peer key");
|
||||
}
|
||||
|
||||
shared_secret.resize(len);
|
||||
|
||||
return shared_secret;
|
||||
auto r = own_key->derive_shared_secret(*peer_key);
|
||||
own_key.reset();
|
||||
peer_key.reset();
|
||||
return r;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
#include "key_pair.h"
|
||||
|
||||
#include "mbedtls/key_pair.h"
|
||||
#include "mbedtls/public_key.h"
|
||||
#include "openssl/key_pair.h"
|
||||
#include "openssl/public_key.h"
|
||||
|
||||
|
@ -16,13 +14,8 @@
|
|||
|
||||
namespace crypto
|
||||
{
|
||||
#ifdef CRYPTO_PROVIDER_IS_MBEDTLS
|
||||
using PublicKeyImpl = PublicKey_mbedTLS;
|
||||
using KeyPairImpl = KeyPair_mbedTLS;
|
||||
#else
|
||||
using PublicKeyImpl = PublicKey_OpenSSL;
|
||||
using KeyPairImpl = KeyPair_OpenSSL;
|
||||
#endif
|
||||
|
||||
PublicKeyPtr make_public_key(const Pem& pem)
|
||||
{
|
||||
|
|
|
@ -23,6 +23,7 @@ namespace crypto
|
|||
virtual Pem private_key_pem() const = 0;
|
||||
virtual Pem public_key_pem() const = 0;
|
||||
virtual std::vector<uint8_t> public_key_der() const = 0;
|
||||
virtual std::vector<uint8_t> private_key_der() const = 0;
|
||||
|
||||
virtual bool verify(
|
||||
const std::vector<uint8_t>& contents,
|
||||
|
@ -87,6 +88,13 @@ namespace crypto
|
|||
auto csr = create_csr(subject_name, subject_alt_names);
|
||||
return sign_csr(Pem(0), csr, ca, valid_from, valid_to);
|
||||
}
|
||||
|
||||
virtual std::vector<uint8_t> derive_shared_secret(
|
||||
const PublicKey& peer_key) = 0;
|
||||
|
||||
virtual std::vector<uint8_t> public_key_raw() const = 0;
|
||||
|
||||
virtual CurveID get_curve_id() const = 0;
|
||||
};
|
||||
|
||||
using PublicKeyPtr = std::shared_ptr<PublicKey>;
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "ds/logger.h"
|
||||
#include "error_string.h"
|
||||
|
||||
#include <mbedtls/base64.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
struct Base64_mbedtls
|
||||
{
|
||||
static std::vector<uint8_t> raw_from_b64(const std::string_view& b64_string)
|
||||
{
|
||||
size_t len_written = 0;
|
||||
const auto data = reinterpret_cast<const uint8_t*>(b64_string.data());
|
||||
const auto size = b64_string.size();
|
||||
|
||||
// Obtain the size of the output buffer
|
||||
auto rc = mbedtls_base64_decode(nullptr, 0, &len_written, data, size);
|
||||
if (rc < 0 && rc != MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL)
|
||||
{
|
||||
throw std::logic_error(fmt::format(
|
||||
"MBED: Could not obtain length of decoded base64 buffer: {}",
|
||||
error_string(rc)));
|
||||
}
|
||||
|
||||
std::vector<uint8_t> decoded(len_written);
|
||||
|
||||
rc = mbedtls_base64_decode(
|
||||
decoded.data(), decoded.size(), &len_written, data, size);
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::invalid_argument(fmt::format(
|
||||
"MBED: Could not decode base64 string: {}", error_string(rc)));
|
||||
}
|
||||
|
||||
return decoded;
|
||||
}
|
||||
|
||||
static std::string b64_from_raw(const uint8_t* data, size_t size)
|
||||
{
|
||||
size_t len_written = 0;
|
||||
|
||||
// Obtain required size for output buffer
|
||||
auto rc = mbedtls_base64_encode(nullptr, 0, &len_written, data, size);
|
||||
if (rc < 0 && rc != MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL)
|
||||
{
|
||||
throw std::logic_error(fmt::format(
|
||||
"MBED: Could not obtain length required for encoded base64 buffer: "
|
||||
"{}",
|
||||
error_string(rc)));
|
||||
}
|
||||
|
||||
std::string b64_string(len_written, '\0');
|
||||
auto dest = reinterpret_cast<uint8_t*>(b64_string.data());
|
||||
|
||||
rc = mbedtls_base64_encode(
|
||||
dest, b64_string.size(), &len_written, data, size);
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(fmt::format(
|
||||
"MBED: Could not encode base64 string: {}", error_string(rc)));
|
||||
}
|
||||
|
||||
if (b64_string.size() > 0)
|
||||
{
|
||||
// mbedtls includes the terminating null, but std-string provides this
|
||||
// already
|
||||
b64_string.pop_back();
|
||||
}
|
||||
|
||||
return b64_string;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "crypto/curve.h"
|
||||
#include "crypto/hash.h"
|
||||
|
||||
#include <mbedtls/ecp.h>
|
||||
#include <mbedtls/pk.h>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
// Helper to access elliptic curve id from context
|
||||
inline mbedtls_ecp_group_id get_mbedtls_ec_from_context(
|
||||
const mbedtls_pk_context& ctx)
|
||||
{
|
||||
return mbedtls_pk_ec(ctx)->grp.id;
|
||||
}
|
||||
|
||||
inline mbedtls_md_type_t get_mbedtls_md_for_ec(
|
||||
mbedtls_ecp_group_id ec, bool allow_none = false)
|
||||
{
|
||||
switch (ec)
|
||||
{
|
||||
case MBEDTLS_ECP_DP_SECP384R1:
|
||||
return MBEDTLS_MD_SHA384;
|
||||
case MBEDTLS_ECP_DP_SECP256R1:
|
||||
return MBEDTLS_MD_SHA256;
|
||||
default:
|
||||
{
|
||||
if (allow_none)
|
||||
{
|
||||
return MBEDTLS_MD_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto error = fmt::format("Unhandled ecp group id: {}", ec);
|
||||
throw std::logic_error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "crypto/entropy.h"
|
||||
#include "mbedtls_wrappers.h"
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
class Entropy_mbedTLS : public Entropy
|
||||
{
|
||||
private:
|
||||
mbedtls::Entropy entropy = mbedtls::make_unique<mbedtls::Entropy>();
|
||||
mbedtls::CtrDrbg drbg = mbedtls::make_unique<mbedtls::CtrDrbg>();
|
||||
|
||||
static bool gen(uint64_t& v);
|
||||
|
||||
public:
|
||||
Entropy_mbedTLS()
|
||||
{
|
||||
mbedtls_ctr_drbg_seed(
|
||||
drbg.get(), mbedtls_entropy_func, entropy.get(), nullptr, 0);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> random(size_t len) override
|
||||
{
|
||||
std::vector<uint8_t> data(len);
|
||||
|
||||
if (mbedtls_ctr_drbg_random(drbg.get(), data.data(), data.size()) != 0)
|
||||
throw std::logic_error("Couldn't create random data");
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
uint64_t random64() override
|
||||
{
|
||||
uint64_t rnd;
|
||||
uint64_t len = sizeof(uint64_t);
|
||||
|
||||
if (
|
||||
mbedtls_ctr_drbg_random(
|
||||
drbg.get(), reinterpret_cast<unsigned char*>(&rnd), len) != 0)
|
||||
{
|
||||
throw std::logic_error("Couldn't create random data");
|
||||
}
|
||||
|
||||
return rnd;
|
||||
}
|
||||
|
||||
void random(unsigned char* data, size_t len) override
|
||||
{
|
||||
if (mbedtls_ctr_drbg_random(drbg.get(), data, len) != 0)
|
||||
throw std::logic_error("Couldn't create random data");
|
||||
}
|
||||
|
||||
static int rng(void* ctx, unsigned char* output, size_t len)
|
||||
{
|
||||
return mbedtls_ctr_drbg_random(ctx, output, len);
|
||||
}
|
||||
|
||||
rng_func_t get_rng() override
|
||||
{
|
||||
return &rng;
|
||||
}
|
||||
|
||||
void* get_data() override
|
||||
{
|
||||
return drbg.get();
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include <mbedtls/error.h>
|
||||
#include <string>
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
inline std::string error_string(int err)
|
||||
{
|
||||
constexpr size_t len = 256;
|
||||
char buf[len];
|
||||
mbedtls_strerror(err, buf, len);
|
||||
|
||||
if (strlen(buf) == 0)
|
||||
{
|
||||
return std::to_string(err);
|
||||
}
|
||||
|
||||
return std::string(buf);
|
||||
}
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
|
||||
#include "hash.h"
|
||||
|
||||
#include "ds/buffer.h"
|
||||
#include "mbedtls_wrappers.h"
|
||||
|
||||
#include <mbedtls/sha256.h>
|
||||
#include <stdexcept>
|
||||
|
||||
// Note: Older system packages of mbedTLS may not support HKDF; if this include
|
||||
// file is not found, consider upgrading your mbedTLS.
|
||||
#include <mbedtls/hkdf.h>
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
namespace mbedtls
|
||||
{
|
||||
std::vector<uint8_t> hkdf(
|
||||
MDType md_type,
|
||||
size_t length,
|
||||
const std::vector<uint8_t>& ikm,
|
||||
const std::vector<uint8_t>& salt,
|
||||
const std::vector<uint8_t>& info)
|
||||
{
|
||||
auto md = mbedtls_md_info_from_type(get_md_type(md_type));
|
||||
std::vector<uint8_t> okm(length);
|
||||
int rc = mbedtls_hkdf(
|
||||
md,
|
||||
salt.data(),
|
||||
salt.size(),
|
||||
ikm.data(),
|
||||
ikm.size(),
|
||||
info.data(),
|
||||
info.size(),
|
||||
okm.data(),
|
||||
okm.size());
|
||||
return okm;
|
||||
}
|
||||
}
|
||||
|
||||
using namespace mbedtls;
|
||||
|
||||
void mbedtls_sha256(const CBuffer& data, uint8_t* h)
|
||||
{
|
||||
mbedtls_sha256_context ctx;
|
||||
mbedtls_sha256_init(&ctx);
|
||||
mbedtls_sha256_starts_ret(&ctx, 0);
|
||||
|
||||
mbedtls_sha256_update_ret(&ctx, data.p, data.rawSize());
|
||||
|
||||
mbedtls_sha256_finish_ret(&ctx, h);
|
||||
mbedtls_sha256_free(&ctx);
|
||||
}
|
||||
|
||||
ISha256MbedTLS::ISha256MbedTLS()
|
||||
{
|
||||
ctx = new mbedtls_sha256_context();
|
||||
mbedtls_sha256_starts_ret((mbedtls_sha256_context*)ctx, 0);
|
||||
}
|
||||
|
||||
ISha256MbedTLS::~ISha256MbedTLS()
|
||||
{
|
||||
delete (mbedtls_sha256_context*)ctx;
|
||||
}
|
||||
|
||||
Sha256Hash ISha256MbedTLS::finalise()
|
||||
{
|
||||
if (!ctx)
|
||||
{
|
||||
throw std::logic_error("Attempting to use hash after it was finalised");
|
||||
}
|
||||
|
||||
Sha256Hash r;
|
||||
mbedtls_sha256_finish_ret((mbedtls_sha256_context*)ctx, r.h.data());
|
||||
mbedtls_sha256_free((mbedtls_sha256_context*)ctx);
|
||||
delete (mbedtls_sha256_context*)ctx;
|
||||
ctx = nullptr;
|
||||
return r;
|
||||
}
|
||||
|
||||
void ISha256MbedTLS::update_hash(CBuffer data)
|
||||
{
|
||||
if (!ctx)
|
||||
{
|
||||
throw std::logic_error("Attempting to use hash after it was finalised");
|
||||
}
|
||||
|
||||
mbedtls_sha256_update_ret(
|
||||
(mbedtls_sha256_context*)ctx, data.p, data.rawSize());
|
||||
}
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "crypto/hash_provider.h"
|
||||
#include "ds/buffer.h"
|
||||
|
||||
#include <mbedtls/md.h>
|
||||
#include <mbedtls/pk.h>
|
||||
|
||||
#define FMT_HEADER_ONLY
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
namespace mbedtls
|
||||
{
|
||||
inline mbedtls_md_type_t get_md_type(MDType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MDType::NONE:
|
||||
return MBEDTLS_MD_NONE;
|
||||
case MDType::SHA1:
|
||||
return MBEDTLS_MD_SHA1;
|
||||
case MDType::SHA256:
|
||||
return MBEDTLS_MD_SHA256;
|
||||
case MDType::SHA384:
|
||||
return MBEDTLS_MD_SHA384;
|
||||
case MDType::SHA512:
|
||||
return MBEDTLS_MD_SHA512;
|
||||
default:
|
||||
throw std::runtime_error("Unsupported hash algorithm");
|
||||
}
|
||||
return MBEDTLS_MD_NONE;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> hkdf(
|
||||
MDType md_type,
|
||||
size_t length,
|
||||
const std::vector<uint8_t>& ikm,
|
||||
const std::vector<uint8_t>& salt = {},
|
||||
const std::vector<uint8_t>& info = {});
|
||||
}
|
||||
|
||||
class MBedHashProvider : public HashProvider
|
||||
{
|
||||
public:
|
||||
virtual HashBytes Hash(const uint8_t* data, size_t size, MDType type) const
|
||||
{
|
||||
HashBytes r;
|
||||
const auto mbedtls_md_type = mbedtls::get_md_type(type);
|
||||
const auto info = mbedtls_md_info_from_type(mbedtls_md_type);
|
||||
const auto hash_size = mbedtls_md_get_size(info);
|
||||
|
||||
r.resize(hash_size);
|
||||
|
||||
if (mbedtls_md(info, data, size, r.data()) != 0)
|
||||
r.clear();
|
||||
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
class ISha256MbedTLS : public ISha256Hash
|
||||
{
|
||||
public:
|
||||
ISha256MbedTLS();
|
||||
~ISha256MbedTLS();
|
||||
virtual void update_hash(CBuffer data);
|
||||
virtual Sha256Hash finalise();
|
||||
|
||||
protected:
|
||||
void* ctx;
|
||||
};
|
||||
|
||||
void mbedtls_sha256(const CBuffer& data, uint8_t* h);
|
||||
}
|
|
@ -1,357 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
|
||||
#include "key_pair.h"
|
||||
|
||||
#include "curve.h"
|
||||
#include "ds/net.h"
|
||||
#include "entropy.h"
|
||||
#include "error_string.h"
|
||||
#include "hash.h"
|
||||
|
||||
#define FMT_HEADER_ONLY
|
||||
#include <fmt/format.h>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <mbedtls/asn1write.h>
|
||||
#include <mbedtls/bignum.h>
|
||||
#include <mbedtls/error.h>
|
||||
#include <mbedtls/md.h>
|
||||
#include <mbedtls/oid.h>
|
||||
#include <mbedtls/pem.h>
|
||||
#include <mbedtls/pk.h>
|
||||
#include <mbedtls/x509.h>
|
||||
#include <mbedtls/x509_crt.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
using namespace mbedtls;
|
||||
|
||||
static mbedtls_ecp_group_id get_mbedtls_group_id(CurveID gid)
|
||||
{
|
||||
switch (gid)
|
||||
{
|
||||
case CurveID::NONE:
|
||||
return MBEDTLS_ECP_DP_NONE;
|
||||
case CurveID::SECP384R1:
|
||||
return MBEDTLS_ECP_DP_SECP384R1;
|
||||
case CurveID::SECP256R1:
|
||||
return MBEDTLS_ECP_DP_SECP256R1;
|
||||
default:
|
||||
throw std::logic_error(fmt::format("unsupported CurveID {}", gid));
|
||||
}
|
||||
return MBEDTLS_ECP_DP_NONE;
|
||||
}
|
||||
|
||||
KeyPair_mbedTLS::KeyPair_mbedTLS(CurveID cid) : PublicKey_mbedTLS()
|
||||
{
|
||||
mbedtls_ecp_group_id ec = get_mbedtls_group_id(cid);
|
||||
EntropyPtr entropy = create_entropy();
|
||||
|
||||
int rc =
|
||||
mbedtls_pk_setup(ctx.get(), mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(
|
||||
"Could not set up ECDSA context: " + error_string(rc));
|
||||
}
|
||||
|
||||
rc = mbedtls_ecp_gen_key(
|
||||
ec, mbedtls_pk_ec(*ctx), entropy->get_rng(), entropy->get_data());
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(
|
||||
"Could not generate ECDSA keypair: " + error_string(rc));
|
||||
}
|
||||
|
||||
const auto actual_ec = get_mbedtls_ec_from_context(*ctx);
|
||||
if (actual_ec != ec)
|
||||
{
|
||||
throw std::logic_error(
|
||||
"Created key and received unexpected type: " +
|
||||
std::to_string(actual_ec) + " != " + error_string(ec));
|
||||
}
|
||||
}
|
||||
|
||||
KeyPair_mbedTLS::KeyPair_mbedTLS(const Pem& pem, CBuffer pw)
|
||||
{
|
||||
// keylen is +1 to include terminating null byte
|
||||
int rc =
|
||||
mbedtls_pk_parse_key(ctx.get(), pem.data(), pem.size(), pw.p, pw.n);
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(
|
||||
"Could not parse private key: " + error_string(rc));
|
||||
}
|
||||
}
|
||||
|
||||
KeyPair_mbedTLS::KeyPair_mbedTLS(mbedtls::PKContext&& k) :
|
||||
PublicKey_mbedTLS(std::move(k))
|
||||
{}
|
||||
|
||||
Pem KeyPair_mbedTLS::private_key_pem() const
|
||||
{
|
||||
uint8_t data[max_pem_key_size];
|
||||
|
||||
int rc = mbedtls_pk_write_key_pem(ctx.get(), data, max_pem_key_size);
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error("mbedtls_pk_write_key_pem: " + error_string(rc));
|
||||
}
|
||||
|
||||
const size_t len = strlen((char const*)data);
|
||||
return Pem(data, len);
|
||||
}
|
||||
|
||||
Pem KeyPair_mbedTLS::public_key_pem() const
|
||||
{
|
||||
return PublicKey_mbedTLS::public_key_pem();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> KeyPair_mbedTLS::public_key_der() const
|
||||
{
|
||||
return PublicKey_mbedTLS::public_key_der();
|
||||
}
|
||||
|
||||
bool KeyPair_mbedTLS::verify(
|
||||
const std::vector<uint8_t>& contents, const std::vector<uint8_t>& signature)
|
||||
{
|
||||
return PublicKey_mbedTLS::verify(contents, signature);
|
||||
}
|
||||
|
||||
bool KeyPair_mbedTLS::verify(
|
||||
const uint8_t* contents,
|
||||
size_t contents_size,
|
||||
const uint8_t* signature,
|
||||
size_t signature_size)
|
||||
{
|
||||
return PublicKey_mbedTLS::verify(
|
||||
contents, contents_size, signature, signature_size);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> KeyPair_mbedTLS::sign(CBuffer d, MDType md_type) const
|
||||
{
|
||||
if (md_type == MDType::NONE)
|
||||
{
|
||||
md_type = get_md_for_ec(get_curve_id());
|
||||
}
|
||||
MBedHashProvider hp;
|
||||
HashBytes hash = hp.Hash(d.p, d.rawSize(), md_type);
|
||||
return sign_hash(hash.data(), hash.size());
|
||||
}
|
||||
|
||||
int KeyPair_mbedTLS::sign(
|
||||
CBuffer d, size_t* sig_size, uint8_t* sig, MDType md_type) const
|
||||
{
|
||||
if (md_type == MDType::NONE)
|
||||
{
|
||||
md_type = get_md_for_ec(get_curve_id());
|
||||
}
|
||||
MBedHashProvider hp;
|
||||
HashBytes hash = hp.Hash(d.p, d.rawSize(), md_type);
|
||||
return sign_hash(hash.data(), hash.size(), sig_size, sig);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> KeyPair_mbedTLS::sign_hash(
|
||||
const uint8_t* hash, size_t hash_size) const
|
||||
{
|
||||
std::vector<uint8_t> sig(MBEDTLS_ECDSA_MAX_LEN);
|
||||
size_t written = sizeof(sig);
|
||||
|
||||
if (sign_hash(hash, hash_size, &written, sig.data()) != 0)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
sig.resize(written);
|
||||
return sig;
|
||||
}
|
||||
|
||||
static int ecdsa_sign_nondet(
|
||||
mbedtls_pk_context* ctx,
|
||||
const uint8_t* hash,
|
||||
size_t hash_size,
|
||||
uint8_t* sig,
|
||||
size_t* sig_size)
|
||||
{
|
||||
EntropyPtr entropy = create_entropy();
|
||||
mbedtls_ecdsa_context* ecdsa_ctx = (mbedtls_ecdsa_context*)ctx->pk_ctx;
|
||||
|
||||
mbedtls_mpi sr, ss;
|
||||
mbedtls_mpi_init(&sr);
|
||||
mbedtls_mpi_init(&ss);
|
||||
|
||||
int r = mbedtls_ecdsa_sign(
|
||||
&ecdsa_ctx->grp,
|
||||
&sr,
|
||||
&ss,
|
||||
&ecdsa_ctx->d,
|
||||
hash,
|
||||
hash_size,
|
||||
entropy->get_rng(),
|
||||
entropy->get_data());
|
||||
|
||||
unsigned char buf[MBEDTLS_ECDSA_MAX_LEN];
|
||||
unsigned char* p = buf + sizeof(buf);
|
||||
size_t len = 0;
|
||||
len += mbedtls_asn1_write_mpi(&p, buf, &ss);
|
||||
len += mbedtls_asn1_write_mpi(&p, buf, &sr);
|
||||
len += mbedtls_asn1_write_len(&p, buf, len);
|
||||
len += mbedtls_asn1_write_tag(
|
||||
&p, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
|
||||
memcpy(sig, p, len);
|
||||
*sig_size = len;
|
||||
|
||||
mbedtls_mpi_free(&sr);
|
||||
mbedtls_mpi_free(&ss);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int KeyPair_mbedTLS::sign_hash(
|
||||
const uint8_t* hash, size_t hash_size, size_t* sig_size, uint8_t* sig) const
|
||||
{
|
||||
EntropyPtr entropy = create_entropy();
|
||||
|
||||
const auto mmdt = get_md_type(get_md_for_ec(get_curve_id()));
|
||||
|
||||
#ifdef DETERMINISTIC_ECDSA
|
||||
return mbedtls_pk_sign(
|
||||
ctx.get(),
|
||||
mmdt,
|
||||
hash,
|
||||
hash_size,
|
||||
sig,
|
||||
sig_size,
|
||||
entropy->get_rng(),
|
||||
entropy->get_data());
|
||||
#else
|
||||
return ecdsa_sign_nondet(ctx.get(), hash, hash_size, sig, sig_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
Pem KeyPair_mbedTLS::create_csr(
|
||||
const std::string& subject_name,
|
||||
const std::vector<SubjectAltName>& subject_alt_names) const
|
||||
{
|
||||
// mbedtls does not support parsing x509v3 extensions from a CSR
|
||||
// (https://github.com/ARMmbed/mbedtls/issues/2912) so disallow CSR creation
|
||||
// if any SAN is specified (use OpenSSL implementation instead)
|
||||
if (!subject_alt_names.empty())
|
||||
{
|
||||
throw std::logic_error("mbedtls cannot create CSR with SAN");
|
||||
}
|
||||
|
||||
auto csr = mbedtls::make_unique<mbedtls::X509WriteCsr>();
|
||||
mbedtls_x509write_csr_set_md_alg(csr.get(), MBEDTLS_MD_SHA512);
|
||||
|
||||
if (
|
||||
mbedtls_x509write_csr_set_subject_name(csr.get(), subject_name.c_str()) !=
|
||||
0)
|
||||
return {};
|
||||
|
||||
mbedtls_x509write_csr_set_key(csr.get(), ctx.get());
|
||||
|
||||
uint8_t buf[4096];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
EntropyPtr entropy = create_entropy();
|
||||
|
||||
if (
|
||||
mbedtls_x509write_csr_pem(
|
||||
csr.get(), buf, sizeof(buf), entropy->get_rng(), entropy->get_data()) !=
|
||||
0)
|
||||
return {};
|
||||
|
||||
auto len = strlen((char*)buf);
|
||||
return Pem(buf, len);
|
||||
}
|
||||
|
||||
static void MCHK(int rc)
|
||||
{
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(
|
||||
fmt::format("mbedTLS error: {}", error_string(rc)));
|
||||
}
|
||||
}
|
||||
|
||||
Pem KeyPair_mbedTLS::sign_csr(
|
||||
const Pem& issuer_cert,
|
||||
const Pem& signing_request,
|
||||
bool ca,
|
||||
const std::optional<std::string>& valid_from,
|
||||
const std::optional<std::string>& valid_to) const
|
||||
{
|
||||
auto entropy = create_entropy();
|
||||
auto csr = mbedtls::make_unique<mbedtls::X509Csr>();
|
||||
auto serial = mbedtls::make_unique<mbedtls::MPI>();
|
||||
auto crt = mbedtls::make_unique<mbedtls::X509WriteCrt>();
|
||||
auto icrt = mbedtls::make_unique<mbedtls::X509Crt>();
|
||||
|
||||
MCHK(mbedtls_x509_csr_parse(
|
||||
csr.get(), signing_request.data(), signing_request.size()));
|
||||
|
||||
// Verify self-signed CSR
|
||||
const auto info = mbedtls_md_info_from_type(csr->sig_md);
|
||||
const auto hash_size = mbedtls_md_get_size(info);
|
||||
HashBytes h(hash_size);
|
||||
MCHK(mbedtls_md(info, csr->cri.p, csr->cri.len, h.data()));
|
||||
MCHK(mbedtls_pk_verify(
|
||||
&csr->pk, csr->sig_md, h.data(), h.size(), csr->sig.p, csr->sig.len));
|
||||
|
||||
char subject[512];
|
||||
mbedtls_x509_dn_gets(subject, sizeof(subject), &csr->subject);
|
||||
|
||||
mbedtls_x509write_crt_set_md_alg(
|
||||
crt.get(), get_mbedtls_md_for_ec(get_mbedtls_ec_from_context(*ctx)));
|
||||
mbedtls_x509write_crt_set_subject_key(crt.get(), &csr->pk);
|
||||
|
||||
if (!issuer_cert.empty())
|
||||
{
|
||||
MCHK(mbedtls_x509_crt_parse(
|
||||
icrt.get(), issuer_cert.data(), issuer_cert.size()));
|
||||
mbedtls_x509write_crt_set_issuer_key(crt.get(), ctx.get());
|
||||
char issuer_name[512];
|
||||
mbedtls_x509_dn_gets(issuer_name, sizeof(issuer_name), &icrt->subject);
|
||||
MCHK(mbedtls_x509write_crt_set_issuer_name(crt.get(), issuer_name));
|
||||
}
|
||||
else
|
||||
{
|
||||
mbedtls_x509write_crt_set_issuer_key(crt.get(), ctx.get());
|
||||
MCHK(mbedtls_x509write_crt_set_issuer_name(crt.get(), subject));
|
||||
}
|
||||
|
||||
MCHK(mbedtls_mpi_fill_random(
|
||||
serial.get(), 16, entropy->get_rng(), entropy->get_data()));
|
||||
MCHK(mbedtls_x509write_crt_set_subject_name(crt.get(), subject));
|
||||
MCHK(mbedtls_x509write_crt_set_serial(crt.get(), serial.get()));
|
||||
|
||||
// Note: 825-day validity range
|
||||
// https://support.apple.com/en-us/HT210176
|
||||
// Note: For the mbedtls implementation, we do not check that valid_from and
|
||||
// valid_to are valid or chronological. See OpenSSL equivalent call for a
|
||||
// safer implementation.
|
||||
MCHK(mbedtls_x509write_crt_set_validity(
|
||||
crt.get(),
|
||||
valid_from.value_or("20210311000000").c_str(),
|
||||
valid_to.value_or("20230611235959").c_str()));
|
||||
|
||||
MCHK(mbedtls_x509write_crt_set_basic_constraints(crt.get(), ca ? 1 : 0, 0));
|
||||
MCHK(mbedtls_x509write_crt_set_subject_key_identifier(crt.get()));
|
||||
MCHK(mbedtls_x509write_crt_set_authority_key_identifier(crt.get()));
|
||||
|
||||
// Warn: Because mbedtls does not support parsing x509v3 extensions from a
|
||||
// CSR (https://github.com/ARMmbed/mbedtls/issues/2912), so those are
|
||||
// ignored and not set in the certificate
|
||||
|
||||
uint8_t buf[4096];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
MCHK(mbedtls_x509write_crt_pem(
|
||||
crt.get(), buf, sizeof(buf), entropy->get_rng(), entropy->get_data()));
|
||||
|
||||
auto len = strlen((char*)buf);
|
||||
return Pem(buf, len);
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "../key_pair.h"
|
||||
#include "../san.h"
|
||||
#include "mbedtls_wrappers.h"
|
||||
#include "public_key.h"
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
class KeyPair_mbedTLS : public PublicKey_mbedTLS, public KeyPair
|
||||
{
|
||||
public:
|
||||
KeyPair_mbedTLS(CurveID cid);
|
||||
KeyPair_mbedTLS(const Pem& pem, CBuffer pw = nullb);
|
||||
KeyPair_mbedTLS(mbedtls::PKContext&& k);
|
||||
KeyPair_mbedTLS(const KeyPair_mbedTLS&) = delete;
|
||||
virtual ~KeyPair_mbedTLS() = default;
|
||||
|
||||
virtual Pem private_key_pem() const override;
|
||||
virtual Pem public_key_pem() const override;
|
||||
virtual std::vector<uint8_t> public_key_der() const override;
|
||||
|
||||
using PublicKey_mbedTLS::verify;
|
||||
|
||||
virtual bool verify(
|
||||
const std::vector<uint8_t>& contents,
|
||||
const std::vector<uint8_t>& signature) override;
|
||||
|
||||
virtual bool verify(
|
||||
const uint8_t* contents,
|
||||
size_t contents_size,
|
||||
const uint8_t* signature,
|
||||
size_t signature_size) override;
|
||||
|
||||
virtual std::vector<uint8_t> sign(
|
||||
CBuffer d, MDType md_type = {}) const override;
|
||||
|
||||
int sign(
|
||||
CBuffer d, size_t* sig_size, uint8_t* sig, MDType md_type = {}) const;
|
||||
|
||||
std::vector<uint8_t> sign_hash(
|
||||
const uint8_t* hash, size_t hash_size) const override;
|
||||
|
||||
virtual int sign_hash(
|
||||
const uint8_t* hash,
|
||||
size_t hash_size,
|
||||
size_t* sig_size,
|
||||
uint8_t* sig) const override;
|
||||
|
||||
virtual Pem create_csr(
|
||||
const std::string& subject_name,
|
||||
const std::vector<SubjectAltName>& subject_alt_names) const override;
|
||||
|
||||
virtual Pem sign_csr(
|
||||
const Pem& issuer_cert,
|
||||
const Pem& signing_request,
|
||||
bool ca = false,
|
||||
const std::optional<std::string>& valid_from = std::nullopt,
|
||||
const std::optional<std::string>& valid_to = std::nullopt) const override;
|
||||
};
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include <mbedtls/ctr_drbg.h>
|
||||
#include <mbedtls/entropy.h>
|
||||
#include <mbedtls/error.h>
|
||||
#include <mbedtls/gcm.h>
|
||||
#include <mbedtls/net_sockets.h>
|
||||
#include <mbedtls/sha256.h>
|
||||
#include <mbedtls/ssl.h>
|
||||
#include <mbedtls/x509.h>
|
||||
#include <mbedtls/x509_crt.h>
|
||||
#include <mbedtls/x509_csr.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
namespace mbedtls
|
||||
{
|
||||
template <typename T>
|
||||
T make_unique();
|
||||
|
||||
#define DEFINE_MBEDTLS_WRAPPER( \
|
||||
NEW_TYPE, MBED_TYPE, MBED_INIT_FN, MBED_FREE_FN) \
|
||||
struct NEW_TYPE##Deleter \
|
||||
{ \
|
||||
void operator()(MBED_TYPE* ptr) \
|
||||
{ \
|
||||
MBED_FREE_FN(ptr); \
|
||||
delete ptr; \
|
||||
} \
|
||||
}; \
|
||||
using NEW_TYPE = std::unique_ptr<MBED_TYPE, NEW_TYPE##Deleter>; \
|
||||
template <> \
|
||||
inline NEW_TYPE make_unique<NEW_TYPE>() \
|
||||
{ \
|
||||
auto p = new MBED_TYPE; \
|
||||
MBED_INIT_FN(p); \
|
||||
return NEW_TYPE(p); \
|
||||
}
|
||||
|
||||
DEFINE_MBEDTLS_WRAPPER(
|
||||
CtrDrbg,
|
||||
mbedtls_ctr_drbg_context,
|
||||
mbedtls_ctr_drbg_init,
|
||||
mbedtls_ctr_drbg_free);
|
||||
DEFINE_MBEDTLS_WRAPPER(
|
||||
ECDHContext, mbedtls_ecdh_context, mbedtls_ecdh_init, mbedtls_ecdh_free);
|
||||
DEFINE_MBEDTLS_WRAPPER(
|
||||
Entropy,
|
||||
mbedtls_entropy_context,
|
||||
mbedtls_entropy_init,
|
||||
mbedtls_entropy_free);
|
||||
DEFINE_MBEDTLS_WRAPPER(
|
||||
GcmContext, mbedtls_gcm_context, mbedtls_gcm_init, mbedtls_gcm_free);
|
||||
DEFINE_MBEDTLS_WRAPPER(
|
||||
MPI, mbedtls_mpi, mbedtls_mpi_init, mbedtls_mpi_free);
|
||||
DEFINE_MBEDTLS_WRAPPER(
|
||||
NetContext, mbedtls_net_context, mbedtls_net_init, mbedtls_net_free);
|
||||
DEFINE_MBEDTLS_WRAPPER(
|
||||
PKContext, mbedtls_pk_context, mbedtls_pk_init, mbedtls_pk_free);
|
||||
DEFINE_MBEDTLS_WRAPPER(
|
||||
SSLConfig,
|
||||
mbedtls_ssl_config,
|
||||
mbedtls_ssl_config_init,
|
||||
mbedtls_ssl_config_free);
|
||||
DEFINE_MBEDTLS_WRAPPER(
|
||||
SSLContext, mbedtls_ssl_context, mbedtls_ssl_init, mbedtls_ssl_free);
|
||||
DEFINE_MBEDTLS_WRAPPER(
|
||||
X509Crl, mbedtls_x509_crl, mbedtls_x509_crl_init, mbedtls_x509_crl_free);
|
||||
DEFINE_MBEDTLS_WRAPPER(
|
||||
X509Crt, mbedtls_x509_crt, mbedtls_x509_crt_init, mbedtls_x509_crt_free);
|
||||
DEFINE_MBEDTLS_WRAPPER(
|
||||
X509Csr, mbedtls_x509_csr, mbedtls_x509_csr_init, mbedtls_x509_csr_free);
|
||||
DEFINE_MBEDTLS_WRAPPER(
|
||||
X509WriteCrt,
|
||||
mbedtls_x509write_cert,
|
||||
mbedtls_x509write_crt_init,
|
||||
mbedtls_x509write_crt_free);
|
||||
DEFINE_MBEDTLS_WRAPPER(
|
||||
X509WriteCsr,
|
||||
mbedtls_x509write_csr,
|
||||
mbedtls_x509write_csr_init,
|
||||
mbedtls_x509write_csr_free);
|
||||
DEFINE_MBEDTLS_WRAPPER(
|
||||
SHA256Ctx,
|
||||
mbedtls_sha256_context,
|
||||
mbedtls_sha256_init,
|
||||
mbedtls_sha256_free);
|
||||
|
||||
#undef DEFINE_MBEDTLS_WRAPPER
|
||||
}
|
||||
}
|
|
@ -1,157 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
|
||||
#include "curve.h"
|
||||
#include "ds/net.h"
|
||||
#include "entropy.h"
|
||||
#include "error_string.h"
|
||||
#include "hash.h"
|
||||
#include "key_pair.h"
|
||||
|
||||
#define FMT_HEADER_ONLY
|
||||
#include <fmt/format.h>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <mbedtls/asn1write.h>
|
||||
#include <mbedtls/bignum.h>
|
||||
#include <mbedtls/error.h>
|
||||
#include <mbedtls/oid.h>
|
||||
#include <mbedtls/pem.h>
|
||||
#include <mbedtls/pk.h>
|
||||
#include <mbedtls/x509.h>
|
||||
#include <mbedtls/x509_crt.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
using namespace mbedtls;
|
||||
|
||||
PublicKey_mbedTLS::PublicKey_mbedTLS() {}
|
||||
|
||||
PublicKey_mbedTLS::PublicKey_mbedTLS(const Pem& pem)
|
||||
{
|
||||
int rc = mbedtls_pk_parse_public_key(ctx.get(), pem.data(), pem.size());
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(fmt::format(
|
||||
"Could not parse public key PEM: {}\n\n(Key: {})",
|
||||
error_string(rc),
|
||||
pem.str()));
|
||||
}
|
||||
}
|
||||
|
||||
PublicKey_mbedTLS::PublicKey_mbedTLS(const std::vector<uint8_t>& der)
|
||||
{
|
||||
int rc = mbedtls_pk_parse_public_key(ctx.get(), der.data(), der.size());
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(
|
||||
fmt::format("Could not parse public key DER: {}", error_string(rc)));
|
||||
}
|
||||
}
|
||||
|
||||
static CurveID get_curve_id(const mbedtls_pk_context* pk_ctx)
|
||||
{
|
||||
if (mbedtls_pk_can_do(pk_ctx, MBEDTLS_PK_ECKEY))
|
||||
{
|
||||
auto grp_id = mbedtls_pk_ec(*pk_ctx)->grp.id;
|
||||
switch (grp_id)
|
||||
{
|
||||
case MBEDTLS_ECP_DP_SECP384R1:
|
||||
return CurveID::SECP384R1;
|
||||
case MBEDTLS_ECP_DP_SECP256R1:
|
||||
return CurveID::SECP256R1;
|
||||
default:
|
||||
throw std::logic_error(
|
||||
fmt::format("unsupported mbedTLS group ID {}", grp_id));
|
||||
}
|
||||
}
|
||||
|
||||
return CurveID::NONE;
|
||||
}
|
||||
|
||||
CurveID PublicKey_mbedTLS::get_curve_id() const
|
||||
{
|
||||
return crypto::get_curve_id(ctx.get());
|
||||
}
|
||||
|
||||
PublicKey_mbedTLS::PublicKey_mbedTLS(mbedtls::PKContext&& c) :
|
||||
ctx(std::move(c))
|
||||
{}
|
||||
|
||||
bool PublicKey_mbedTLS::verify(
|
||||
const uint8_t* contents,
|
||||
size_t contents_size,
|
||||
const uint8_t* sig,
|
||||
size_t sig_size,
|
||||
MDType md_type,
|
||||
HashBytes& bytes)
|
||||
{
|
||||
if (md_type == MDType::NONE)
|
||||
{
|
||||
md_type = get_md_for_ec(get_curve_id());
|
||||
}
|
||||
MBedHashProvider hp;
|
||||
bytes = hp.Hash(contents, contents_size, md_type);
|
||||
return verify_hash(bytes.data(), bytes.size(), sig, sig_size, md_type);
|
||||
}
|
||||
|
||||
bool PublicKey_mbedTLS::verify_hash(
|
||||
const uint8_t* hash,
|
||||
size_t hash_size,
|
||||
const uint8_t* sig,
|
||||
size_t sig_size,
|
||||
MDType md_type)
|
||||
{
|
||||
if (md_type == MDType::NONE)
|
||||
{
|
||||
md_type = get_md_for_ec(get_curve_id());
|
||||
}
|
||||
|
||||
const auto mmdt = get_md_type(md_type);
|
||||
|
||||
int rc = mbedtls_pk_verify(ctx.get(), mmdt, hash, hash_size, sig, sig_size);
|
||||
|
||||
if (rc)
|
||||
LOG_DEBUG_FMT("Failed to verify signature: {}", error_string(rc));
|
||||
|
||||
return rc == 0;
|
||||
}
|
||||
|
||||
Pem PublicKey_mbedTLS::public_key_pem() const
|
||||
{
|
||||
uint8_t data[max_pem_key_size];
|
||||
|
||||
int rc = mbedtls_pk_write_pubkey_pem(ctx.get(), data, max_pem_key_size);
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(
|
||||
"mbedtls_pk_write_pubkey_pem: " + error_string(rc));
|
||||
}
|
||||
|
||||
const size_t len = strlen((char const*)data);
|
||||
return Pem(data, len);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> PublicKey_mbedTLS::public_key_der() const
|
||||
{
|
||||
uint8_t data[max_der_key_size];
|
||||
|
||||
int len = mbedtls_pk_write_pubkey_der(ctx.get(), data, max_der_key_size);
|
||||
if (len < 0)
|
||||
{
|
||||
throw std::logic_error(
|
||||
"mbedtls_pk_write_pubkey_der: " + error_string(len));
|
||||
}
|
||||
|
||||
return {data + max_der_key_size - len, data + max_der_key_size};
|
||||
};
|
||||
|
||||
mbedtls_pk_context* PublicKey_mbedTLS::get_raw_context() const
|
||||
{
|
||||
return ctx.get();
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "../public_key.h"
|
||||
#include "../san.h"
|
||||
#include "mbedtls_wrappers.h"
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
class PublicKey_mbedTLS : public PublicKey
|
||||
{
|
||||
protected:
|
||||
mbedtls::PKContext ctx = mbedtls::make_unique<mbedtls::PKContext>();
|
||||
PublicKey_mbedTLS();
|
||||
CurveID get_curve_id() const;
|
||||
|
||||
public:
|
||||
static constexpr size_t max_pem_key_size = 2048;
|
||||
static constexpr size_t max_der_key_size = 2048;
|
||||
|
||||
PublicKey_mbedTLS(PublicKey_mbedTLS&& pk) = default;
|
||||
PublicKey_mbedTLS(mbedtls::PKContext&& c);
|
||||
PublicKey_mbedTLS(const Pem& pem);
|
||||
PublicKey_mbedTLS(const std::vector<uint8_t>& der);
|
||||
virtual ~PublicKey_mbedTLS() = default;
|
||||
|
||||
using PublicKey::verify;
|
||||
using PublicKey::verify_hash;
|
||||
|
||||
virtual bool verify(
|
||||
const uint8_t* contents,
|
||||
size_t contents_size,
|
||||
const uint8_t* sig,
|
||||
size_t sig_size,
|
||||
MDType md_type,
|
||||
HashBytes& bytes) override;
|
||||
|
||||
virtual bool verify_hash(
|
||||
const uint8_t* hash,
|
||||
size_t hash_size,
|
||||
const uint8_t* sig,
|
||||
size_t sig_size,
|
||||
MDType md_type) override;
|
||||
|
||||
virtual Pem public_key_pem() const override;
|
||||
virtual std::vector<uint8_t> public_key_der() const override;
|
||||
|
||||
mbedtls_pk_context* get_raw_context() const;
|
||||
};
|
||||
}
|
|
@ -1,162 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
|
||||
#include "rsa_key_pair.h"
|
||||
|
||||
#include "crypto/mbedtls/hash.h"
|
||||
#include "crypto/mbedtls/rsa_public_key.h"
|
||||
#include "entropy.h"
|
||||
#include "error_string.h"
|
||||
#include "hash.h"
|
||||
#include "mbedtls_wrappers.h"
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
using namespace mbedtls;
|
||||
|
||||
RSAKeyPair_mbedTLS::RSAKeyPair_mbedTLS(
|
||||
size_t public_key_size, size_t public_exponent)
|
||||
{
|
||||
EntropyPtr entropy = create_entropy();
|
||||
|
||||
int rc =
|
||||
mbedtls_pk_setup(ctx.get(), mbedtls_pk_info_from_type(MBEDTLS_PK_RSA));
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(
|
||||
"Could not set up RSA context: " + error_string(rc));
|
||||
}
|
||||
|
||||
rc = mbedtls_rsa_gen_key(
|
||||
mbedtls_pk_rsa(*ctx.get()),
|
||||
entropy->get_rng(),
|
||||
entropy->get_data(),
|
||||
public_key_size,
|
||||
public_exponent);
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(
|
||||
"Could not generate RSA keypair: " + error_string(rc));
|
||||
}
|
||||
}
|
||||
|
||||
RSAKeyPair_mbedTLS::RSAKeyPair_mbedTLS(mbedtls::PKContext&& k) :
|
||||
RSAPublicKey_mbedTLS(std::move(k))
|
||||
{}
|
||||
|
||||
RSAKeyPair_mbedTLS::RSAKeyPair_mbedTLS(const Pem& pem, CBuffer pw) :
|
||||
RSAPublicKey_mbedTLS()
|
||||
{
|
||||
// keylen is +1 to include terminating null byte
|
||||
int rc =
|
||||
mbedtls_pk_parse_key(ctx.get(), pem.data(), pem.size(), pw.p, pw.n);
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(
|
||||
"Could not parse private key: " + error_string(rc));
|
||||
}
|
||||
}
|
||||
|
||||
size_t RSAKeyPair_mbedTLS::key_size() const
|
||||
{
|
||||
return RSAPublicKey_mbedTLS::key_size();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> RSAKeyPair_mbedTLS::rsa_oaep_unwrap(
|
||||
const std::vector<uint8_t>& input,
|
||||
const std::optional<std::vector<std::uint8_t>>& label)
|
||||
{
|
||||
mbedtls_rsa_context* rsa_ctx = mbedtls_pk_rsa(*ctx.get());
|
||||
mbedtls_rsa_set_padding(rsa_ctx, rsa_padding_mode, rsa_padding_digest_id);
|
||||
|
||||
std::vector<uint8_t> output_buf(rsa_ctx->len);
|
||||
auto entropy = create_entropy();
|
||||
|
||||
const unsigned char* label_ = NULL;
|
||||
size_t label_size = 0;
|
||||
if (label.has_value())
|
||||
{
|
||||
if (label->empty())
|
||||
{
|
||||
throw std::logic_error("empty wrapping label");
|
||||
}
|
||||
label_ = reinterpret_cast<const unsigned char*>(label->data());
|
||||
label_size = label->size();
|
||||
}
|
||||
|
||||
size_t olen;
|
||||
auto rc = mbedtls_rsa_rsaes_oaep_decrypt(
|
||||
rsa_ctx,
|
||||
entropy->get_rng(),
|
||||
entropy->get_data(),
|
||||
MBEDTLS_RSA_PRIVATE,
|
||||
label_,
|
||||
label_size,
|
||||
&olen,
|
||||
input.data(),
|
||||
output_buf.data(),
|
||||
output_buf.size());
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(
|
||||
fmt::format("Error during RSA OEAP unwrap: {}", error_string(rc)));
|
||||
}
|
||||
|
||||
output_buf.resize(olen);
|
||||
return output_buf;
|
||||
}
|
||||
|
||||
Pem RSAKeyPair_mbedTLS::private_key_pem() const
|
||||
{
|
||||
unsigned char data[max_pem_key_size];
|
||||
|
||||
int rc = mbedtls_pk_write_key_pem(ctx.get(), data, sizeof(data));
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error("mbedtls_pk_write_key_pem: " + error_string(rc));
|
||||
}
|
||||
|
||||
const size_t len = strlen((char const*)data);
|
||||
return Pem(data, len);
|
||||
}
|
||||
|
||||
Pem RSAKeyPair_mbedTLS::public_key_pem() const
|
||||
{
|
||||
return PublicKey_mbedTLS::public_key_pem();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> RSAKeyPair_mbedTLS::public_key_der() const
|
||||
{
|
||||
return PublicKey_mbedTLS::public_key_der();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> RSAKeyPair_mbedTLS::sign(CBuffer d, MDType md_type) const
|
||||
{
|
||||
std::vector<uint8_t> r(2048);
|
||||
auto hash = MBedHashProvider().Hash(d.p, d.n, md_type);
|
||||
EntropyPtr entropy = create_entropy();
|
||||
size_t olen = r.size();
|
||||
int rc = mbedtls_pk_sign(
|
||||
ctx.get(),
|
||||
get_md_type(md_type),
|
||||
hash.data(),
|
||||
hash.size(),
|
||||
r.data(),
|
||||
&olen,
|
||||
entropy->get_rng(),
|
||||
entropy->get_data());
|
||||
r.resize(olen);
|
||||
return r;
|
||||
}
|
||||
|
||||
bool RSAKeyPair_mbedTLS::verify(
|
||||
const uint8_t* contents,
|
||||
size_t contents_size,
|
||||
const uint8_t* signature,
|
||||
size_t signature_size,
|
||||
MDType md_type)
|
||||
{
|
||||
return RSAPublicKey_mbedTLS::verify(
|
||||
contents, contents_size, signature, signature_size, md_type);
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "crypto/rsa_key_pair.h"
|
||||
#include "mbedtls_wrappers.h"
|
||||
#include "rsa_public_key.h"
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
class RSAKeyPair_mbedTLS : public RSAPublicKey_mbedTLS, public RSAKeyPair
|
||||
{
|
||||
public:
|
||||
RSAKeyPair_mbedTLS(
|
||||
size_t public_key_size = default_public_key_size,
|
||||
size_t public_exponent = default_public_exponent);
|
||||
|
||||
RSAKeyPair_mbedTLS(mbedtls::PKContext&& k);
|
||||
RSAKeyPair_mbedTLS(const RSAKeyPair&) = delete;
|
||||
RSAKeyPair_mbedTLS(const Pem& pem, CBuffer pw = nullb);
|
||||
|
||||
virtual size_t key_size() const override;
|
||||
|
||||
virtual ~RSAKeyPair_mbedTLS() = default;
|
||||
|
||||
virtual std::vector<uint8_t> rsa_oaep_unwrap(
|
||||
const std::vector<uint8_t>& input,
|
||||
const std::optional<std::vector<std::uint8_t>>& label =
|
||||
std::nullopt) override;
|
||||
|
||||
virtual Pem private_key_pem() const override;
|
||||
virtual Pem public_key_pem() const override;
|
||||
virtual std::vector<uint8_t> public_key_der() const override;
|
||||
|
||||
virtual std::vector<uint8_t> sign(
|
||||
CBuffer d, MDType md_type = MDType::NONE) const override;
|
||||
|
||||
virtual bool verify(
|
||||
const uint8_t* contents,
|
||||
size_t contents_size,
|
||||
const uint8_t* signature,
|
||||
size_t signature_size,
|
||||
MDType md_type = MDType::NONE) override;
|
||||
};
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
|
||||
#include "rsa_public_key.h"
|
||||
|
||||
#include "crypto/mbedtls/curve.h"
|
||||
#include "crypto/mbedtls/hash.h"
|
||||
#include "entropy.h"
|
||||
#include "error_string.h"
|
||||
#include "mbedtls_wrappers.h"
|
||||
|
||||
#include <mbedtls/md.h>
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
using namespace mbedtls;
|
||||
|
||||
RSAPublicKey_mbedTLS::RSAPublicKey_mbedTLS(mbedtls::PKContext&& c) :
|
||||
PublicKey_mbedTLS(std::move(c))
|
||||
{}
|
||||
|
||||
RSAPublicKey_mbedTLS::RSAPublicKey_mbedTLS(const Pem& pem) :
|
||||
PublicKey_mbedTLS(pem)
|
||||
{
|
||||
if (!mbedtls_pk_can_do(ctx.get(), MBEDTLS_PK_RSA))
|
||||
{
|
||||
throw std::logic_error("invalid RSA key");
|
||||
}
|
||||
}
|
||||
|
||||
RSAPublicKey_mbedTLS::RSAPublicKey_mbedTLS(const std::vector<uint8_t>& der) :
|
||||
PublicKey_mbedTLS(der)
|
||||
{
|
||||
if (!mbedtls_pk_can_do(ctx.get(), MBEDTLS_PK_RSA))
|
||||
{
|
||||
throw std::logic_error("invalid RSA key");
|
||||
}
|
||||
}
|
||||
|
||||
size_t RSAPublicKey_mbedTLS::key_size() const
|
||||
{
|
||||
return mbedtls_rsa_get_len(mbedtls_pk_rsa(*ctx.get())) * 8;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> RSAPublicKey_mbedTLS::rsa_oaep_wrap(
|
||||
const uint8_t* input,
|
||||
size_t input_size,
|
||||
const uint8_t* label,
|
||||
size_t label_size)
|
||||
{
|
||||
mbedtls_rsa_context* rsa_ctx = mbedtls_pk_rsa(*ctx.get());
|
||||
mbedtls_rsa_set_padding(rsa_ctx, rsa_padding_mode, rsa_padding_digest_id);
|
||||
|
||||
std::vector<uint8_t> output_buf(rsa_ctx->len);
|
||||
auto entropy = create_entropy();
|
||||
|
||||
// Note that the maximum input size to wrap is k - 2*hLen - 2
|
||||
// where hLen is the hash size (32 bytes = SHA256) and
|
||||
// k the wrapping key modulus size (e.g. 256 bytes = 2048 bits).
|
||||
// In this example, it would be 190 bytes (1520 bits) max.
|
||||
// This is enough for wrapping AES keys for example.
|
||||
auto rc = mbedtls_rsa_rsaes_oaep_encrypt(
|
||||
rsa_ctx,
|
||||
entropy->get_rng(),
|
||||
entropy->get_data(),
|
||||
MBEDTLS_RSA_PUBLIC,
|
||||
label,
|
||||
label_size,
|
||||
input_size,
|
||||
input,
|
||||
output_buf.data());
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(
|
||||
fmt::format("Error during RSA OEAP wrap: {}", error_string(rc)));
|
||||
}
|
||||
|
||||
return output_buf;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> RSAPublicKey_mbedTLS::rsa_oaep_wrap(
|
||||
const std::vector<uint8_t>& input,
|
||||
const std::optional<std::vector<std::uint8_t>>& label)
|
||||
{
|
||||
const unsigned char* label_ = NULL;
|
||||
size_t label_size = 0;
|
||||
if (label.has_value())
|
||||
{
|
||||
if (label->empty())
|
||||
{
|
||||
throw std::logic_error("empty wrapping label");
|
||||
}
|
||||
label_ = reinterpret_cast<const unsigned char*>(label->data());
|
||||
label_size = label->size();
|
||||
}
|
||||
|
||||
return rsa_oaep_wrap(input.data(), input.size(), label_, label_size);
|
||||
}
|
||||
|
||||
Pem RSAPublicKey_mbedTLS::public_key_pem() const
|
||||
{
|
||||
return PublicKey_mbedTLS::public_key_pem();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> RSAPublicKey_mbedTLS::public_key_der() const
|
||||
{
|
||||
return PublicKey_mbedTLS::public_key_der();
|
||||
}
|
||||
|
||||
bool RSAPublicKey_mbedTLS::verify(
|
||||
const uint8_t* contents,
|
||||
size_t contents_size,
|
||||
const uint8_t* signature,
|
||||
size_t signature_size,
|
||||
MDType md_type)
|
||||
{
|
||||
auto hash = MBedHashProvider().Hash(contents, contents_size, md_type);
|
||||
auto mbed_md = get_md_type(md_type);
|
||||
int rc = mbedtls_pk_verify(
|
||||
ctx.get(), mbed_md, hash.data(), hash.size(), signature, signature_size);
|
||||
return rc == 0;
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "crypto/rsa_public_key.h"
|
||||
#include "mbedtls_wrappers.h"
|
||||
#include "public_key.h"
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
class RSAPublicKey_mbedTLS : public PublicKey_mbedTLS, public RSAPublicKey
|
||||
{
|
||||
public:
|
||||
// Compatible with Azure HSM encryption schemes (see
|
||||
// https://docs.microsoft.com/en-gb/azure/key-vault/keys/about-keys#wrapkeyunwrapkey-encryptdecrypt)
|
||||
static constexpr auto rsa_padding_mode = MBEDTLS_RSA_PKCS_V21;
|
||||
static constexpr auto rsa_padding_digest_id = MBEDTLS_MD_SHA256;
|
||||
|
||||
RSAPublicKey_mbedTLS() = default;
|
||||
virtual ~RSAPublicKey_mbedTLS() = default;
|
||||
|
||||
RSAPublicKey_mbedTLS(mbedtls::PKContext&& c);
|
||||
RSAPublicKey_mbedTLS(const Pem& pem);
|
||||
RSAPublicKey_mbedTLS(const std::vector<uint8_t>& der);
|
||||
|
||||
virtual size_t key_size() const override;
|
||||
|
||||
virtual std::vector<uint8_t> rsa_oaep_wrap(
|
||||
const uint8_t* input,
|
||||
size_t input_size,
|
||||
const uint8_t* label = nullptr,
|
||||
size_t label_size = 0) override;
|
||||
|
||||
virtual std::vector<uint8_t> rsa_oaep_wrap(
|
||||
const std::vector<uint8_t>& input,
|
||||
const std::optional<std::vector<std::uint8_t>>& label =
|
||||
std::nullopt) override;
|
||||
|
||||
virtual Pem public_key_pem() const override;
|
||||
virtual std::vector<uint8_t> public_key_der() const override;
|
||||
|
||||
virtual bool verify(
|
||||
const uint8_t* contents,
|
||||
size_t contents_size,
|
||||
const uint8_t* signature,
|
||||
size_t signature_size,
|
||||
MDType md_type = MDType::NONE) override;
|
||||
};
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
|
||||
#include "symmetric_key.h"
|
||||
|
||||
#include "error_string.h"
|
||||
|
||||
#include <mbedtls/aes.h>
|
||||
#include <mbedtls/error.h>
|
||||
#include <mbedtls/pk.h>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
using namespace mbedtls;
|
||||
|
||||
KeyAesGcm_mbedTLS::KeyAesGcm_mbedTLS(CBuffer rawKey)
|
||||
{
|
||||
for (uint32_t i = 0; i < ctxs.size(); ++i)
|
||||
{
|
||||
ctxs[i] = mbedtls::make_unique<mbedtls::GcmContext>();
|
||||
|
||||
size_t n_bits;
|
||||
const auto n = static_cast<unsigned int>(rawKey.rawSize() * 8);
|
||||
if (n >= 256)
|
||||
{
|
||||
n_bits = 256;
|
||||
}
|
||||
else if (n >= 192)
|
||||
{
|
||||
n_bits = 192;
|
||||
}
|
||||
else if (n >= 128)
|
||||
{
|
||||
n_bits = 128;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::logic_error(
|
||||
fmt::format("Need at least {} bits, only have {}", 128, n));
|
||||
}
|
||||
|
||||
int rc = mbedtls_gcm_setkey(
|
||||
ctxs[i].get(), MBEDTLS_CIPHER_ID_AES, rawKey.p, n_bits);
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(error_string(rc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t KeyAesGcm_mbedTLS::key_size() const
|
||||
{
|
||||
auto ctx = ctxs[threading::get_current_thread_id()].get();
|
||||
return ctx->cipher_ctx.key_bitlen;
|
||||
}
|
||||
|
||||
void KeyAesGcm_mbedTLS::encrypt(
|
||||
CBuffer iv,
|
||||
CBuffer plain,
|
||||
CBuffer aad,
|
||||
uint8_t* cipher,
|
||||
uint8_t tag[GCM_SIZE_TAG]) const
|
||||
{
|
||||
auto ctx = ctxs[threading::get_current_thread_id()].get();
|
||||
int rc = mbedtls_gcm_crypt_and_tag(
|
||||
ctx,
|
||||
MBEDTLS_GCM_ENCRYPT,
|
||||
plain.n,
|
||||
iv.p,
|
||||
iv.n,
|
||||
aad.p,
|
||||
aad.n,
|
||||
plain.p,
|
||||
cipher,
|
||||
GCM_SIZE_TAG,
|
||||
tag);
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(error_string(rc));
|
||||
}
|
||||
}
|
||||
|
||||
bool KeyAesGcm_mbedTLS::decrypt(
|
||||
CBuffer iv,
|
||||
const uint8_t tag[GCM_SIZE_TAG],
|
||||
CBuffer cipher,
|
||||
CBuffer aad,
|
||||
uint8_t* plain) const
|
||||
{
|
||||
auto ctx = ctxs[threading::get_current_thread_id()].get();
|
||||
return !mbedtls_gcm_auth_decrypt(
|
||||
ctx,
|
||||
cipher.n,
|
||||
iv.p,
|
||||
iv.n,
|
||||
aad.p,
|
||||
aad.n,
|
||||
tag,
|
||||
GCM_SIZE_TAG,
|
||||
cipher.p,
|
||||
plain);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "crypto/symmetric_key.h"
|
||||
#include "mbedtls_wrappers.h"
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
class KeyAesGcm_mbedTLS : public KeyAesGcm
|
||||
{
|
||||
private:
|
||||
mutable std::
|
||||
array<mbedtls::GcmContext, threading::ThreadMessaging::max_num_threads>
|
||||
ctxs;
|
||||
|
||||
public:
|
||||
KeyAesGcm_mbedTLS(CBuffer rawKey);
|
||||
KeyAesGcm_mbedTLS(const KeyAesGcm_mbedTLS& that) = delete;
|
||||
KeyAesGcm_mbedTLS(KeyAesGcm_mbedTLS&& that);
|
||||
virtual ~KeyAesGcm_mbedTLS() = default;
|
||||
|
||||
virtual void encrypt(
|
||||
CBuffer iv,
|
||||
CBuffer plain,
|
||||
CBuffer aad,
|
||||
uint8_t* cipher,
|
||||
uint8_t tag[GCM_SIZE_TAG]) const override;
|
||||
|
||||
virtual bool decrypt(
|
||||
CBuffer iv,
|
||||
const uint8_t tag[GCM_SIZE_TAG],
|
||||
CBuffer cipher,
|
||||
CBuffer aad,
|
||||
uint8_t* plain) const override;
|
||||
|
||||
virtual size_t key_size() const override;
|
||||
};
|
||||
}
|
|
@ -1,220 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
|
||||
#include "verifier.h"
|
||||
|
||||
#include "error_string.h"
|
||||
#include "public_key.h"
|
||||
#include "rsa_key_pair.h"
|
||||
|
||||
#include <mbedtls/pem.h>
|
||||
#include <mbedtls/x509_crt.h>
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
using namespace mbedtls;
|
||||
|
||||
static constexpr size_t max_pem_cert_size = 4096;
|
||||
|
||||
// As these are not exposed by mbedTLS, define them here to allow simple
|
||||
// conversion from DER to PEM format
|
||||
static constexpr auto PEM_CERTIFICATE_HEADER =
|
||||
"-----BEGIN CERTIFICATE-----\n";
|
||||
static constexpr auto PEM_CERTIFICATE_FOOTER = "-----END CERTIFICATE-----\n";
|
||||
|
||||
static inline std::string to_x509_time_string(const mbedtls_x509_time& time)
|
||||
{
|
||||
// Returns ASN1 time string (YYYYMMDDHHMMSSZ)
|
||||
return fmt::format(
|
||||
"{:02}{:02}{:02}{:02}{:02}{:02}Z",
|
||||
time.year,
|
||||
time.mon,
|
||||
time.day,
|
||||
time.hour,
|
||||
time.min,
|
||||
time.sec);
|
||||
}
|
||||
|
||||
MDType Verifier_mbedTLS::get_md_type(mbedtls_md_type_t mdt) const
|
||||
{
|
||||
switch (mdt)
|
||||
{
|
||||
case MBEDTLS_MD_NONE:
|
||||
return MDType::NONE;
|
||||
case MBEDTLS_MD_SHA1:
|
||||
return MDType::SHA1;
|
||||
case MBEDTLS_MD_SHA256:
|
||||
return MDType::SHA256;
|
||||
case MBEDTLS_MD_SHA384:
|
||||
return MDType::SHA384;
|
||||
case MBEDTLS_MD_SHA512:
|
||||
return MDType::SHA512;
|
||||
default:
|
||||
return MDType::NONE;
|
||||
}
|
||||
return MDType::NONE;
|
||||
}
|
||||
|
||||
Verifier_mbedTLS::Verifier_mbedTLS(const std::vector<uint8_t>& c) : Verifier()
|
||||
{
|
||||
cert = mbedtls::make_unique<mbedtls::X509Crt>();
|
||||
int rc = mbedtls_x509_crt_parse(cert.get(), c.data(), c.size());
|
||||
if (rc)
|
||||
{
|
||||
throw std::invalid_argument(
|
||||
fmt::format("Failed to parse certificate: {}", error_string(rc)));
|
||||
}
|
||||
if (cert.get()->next != nullptr)
|
||||
{
|
||||
throw std::invalid_argument(
|
||||
"PEM string contains more than one certificate");
|
||||
}
|
||||
|
||||
// public_key expects to have unique ownership of the context and so does
|
||||
// `cert`, so we duplicate the key context here.
|
||||
unsigned char buf[2048];
|
||||
rc = mbedtls_pk_write_pubkey_pem(&cert->pk, buf, sizeof(buf));
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
fmt::format("PEM export failed: {}", error_string(rc)));
|
||||
}
|
||||
|
||||
Pem pem(buf, sizeof(buf));
|
||||
|
||||
if (mbedtls_pk_can_do(&cert->pk, MBEDTLS_PK_ECKEY))
|
||||
{
|
||||
public_key = std::make_unique<PublicKey_mbedTLS>(pem);
|
||||
}
|
||||
else if (mbedtls_pk_can_do(&cert->pk, MBEDTLS_PK_RSA))
|
||||
{
|
||||
public_key = std::make_unique<RSAPublicKey_mbedTLS>(pem);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::logic_error("unsupported public key type");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Verifier_mbedTLS::cert_der()
|
||||
{
|
||||
return {cert->raw.p, cert->raw.p + cert->raw.len};
|
||||
}
|
||||
|
||||
Pem Verifier_mbedTLS::cert_pem()
|
||||
{
|
||||
unsigned char buf[max_pem_cert_size];
|
||||
size_t len;
|
||||
|
||||
auto rc = mbedtls_pem_write_buffer(
|
||||
PEM_CERTIFICATE_HEADER,
|
||||
PEM_CERTIFICATE_FOOTER,
|
||||
cert->raw.p,
|
||||
cert->raw.len,
|
||||
buf,
|
||||
max_pem_cert_size,
|
||||
&len);
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(
|
||||
"mbedtls_pem_write_buffer failed: " + error_string(rc));
|
||||
}
|
||||
|
||||
return Pem(buf, len);
|
||||
}
|
||||
|
||||
class CertificateChain
|
||||
{
|
||||
public:
|
||||
mbedtls_x509_crt raw;
|
||||
|
||||
CertificateChain()
|
||||
{
|
||||
mbedtls_x509_crt_init(&raw);
|
||||
}
|
||||
|
||||
void add(const std::vector<const Pem*>& certs)
|
||||
{
|
||||
for (auto& cert : certs)
|
||||
{
|
||||
int rc = mbedtls_x509_crt_parse(&raw, cert->data(), cert->size());
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Could not parse PEM certificate: " + error_string(rc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add(const uint8_t* der, size_t len)
|
||||
{
|
||||
int rc = mbedtls_x509_crt_parse_der(&raw, der, len);
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Could not parse DER certificate: " + error_string(rc));
|
||||
}
|
||||
}
|
||||
|
||||
~CertificateChain()
|
||||
{
|
||||
mbedtls_x509_crt_free(&raw);
|
||||
}
|
||||
};
|
||||
|
||||
bool Verifier_mbedTLS::verify_certificate(
|
||||
const std::vector<const Pem*>& trusted_certs,
|
||||
const std::vector<const Pem*>& chain)
|
||||
{
|
||||
CertificateChain trusted;
|
||||
trusted.add(trusted_certs);
|
||||
|
||||
mbedtls_x509_crt* crt;
|
||||
|
||||
CertificateChain target_and_chain;
|
||||
if (chain.empty())
|
||||
{
|
||||
// Fast-path, avoids extra parse step.
|
||||
crt = cert.get();
|
||||
}
|
||||
else
|
||||
{
|
||||
target_and_chain.add(cert.get()->raw.p, cert.get()->raw.len);
|
||||
target_and_chain.add(chain);
|
||||
crt = &target_and_chain.raw;
|
||||
}
|
||||
|
||||
uint32_t flags;
|
||||
int rc = mbedtls_x509_crt_verify(
|
||||
crt, &trusted.raw, NULL, NULL, &flags, NULL, NULL);
|
||||
|
||||
return rc == 0 && flags == 0;
|
||||
}
|
||||
|
||||
bool Verifier_mbedTLS::is_self_signed() const
|
||||
{
|
||||
return (cert->issuer_raw.len == cert->subject_raw.len) &&
|
||||
memcmp(cert->issuer_raw.p, cert->subject_raw.p, cert->subject_raw.len) ==
|
||||
0;
|
||||
}
|
||||
|
||||
std::string Verifier_mbedTLS::serial_number() const
|
||||
{
|
||||
char buf[64];
|
||||
int rc = mbedtls_x509_serial_gets(buf, sizeof(buf), &cert->serial);
|
||||
if (rc < 0)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"mbedtls_x509_serial_gets failed: " + error_string(rc));
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> Verifier_mbedTLS::validity_period() const
|
||||
{
|
||||
return std::make_pair(
|
||||
to_x509_time_string(cert->valid_from),
|
||||
to_x509_time_string(cert->valid_to));
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "crypto/verifier.h"
|
||||
#include "mbedtls_wrappers.h"
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
class Verifier_mbedTLS : public Verifier
|
||||
{
|
||||
protected:
|
||||
mutable mbedtls::X509Crt cert;
|
||||
|
||||
MDType get_md_type(mbedtls_md_type_t mdt) const;
|
||||
|
||||
public:
|
||||
Verifier_mbedTLS(const std::vector<uint8_t>& c);
|
||||
Verifier_mbedTLS(const Verifier_mbedTLS&) = delete;
|
||||
virtual ~Verifier_mbedTLS() = default;
|
||||
|
||||
virtual std::vector<uint8_t> cert_der() override;
|
||||
virtual Pem cert_pem() override;
|
||||
|
||||
virtual bool verify_certificate(
|
||||
const std::vector<const Pem*>& trusted_certs,
|
||||
const std::vector<const Pem*>& chain = {}) override;
|
||||
|
||||
virtual bool is_self_signed() const override;
|
||||
|
||||
virtual std::string serial_number() const override;
|
||||
|
||||
virtual std::pair<std::string, std::string> validity_period()
|
||||
const override;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "crypto/entropy.h"
|
||||
#include "openssl_wrappers.h"
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <openssl/rand.h>
|
||||
#include <vector>
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
class Entropy_OpenSSL : public Entropy
|
||||
{
|
||||
private:
|
||||
static bool gen(uint64_t& v);
|
||||
|
||||
public:
|
||||
Entropy_OpenSSL() {}
|
||||
|
||||
std::vector<uint8_t> random(size_t len) override
|
||||
{
|
||||
std::vector<uint8_t> data(len);
|
||||
|
||||
if (RAND_bytes(data.data(), data.size()) != 1)
|
||||
throw std::logic_error("Couldn't create random data");
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
uint64_t random64() override
|
||||
{
|
||||
uint64_t rnd;
|
||||
|
||||
if (RAND_bytes((unsigned char*)&rnd, sizeof(uint64_t)) != 1)
|
||||
{
|
||||
throw std::logic_error("Couldn't create random data");
|
||||
}
|
||||
|
||||
return rnd;
|
||||
}
|
||||
|
||||
void random(unsigned char* data, size_t len) override
|
||||
{
|
||||
if (RAND_bytes(data, len) != 1)
|
||||
{
|
||||
throw std::logic_error("Couldn't create random data");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
|
@ -25,23 +25,6 @@ namespace crypto
|
|||
{
|
||||
using namespace OpenSSL;
|
||||
|
||||
static inline int get_openssl_group_id(CurveID gid)
|
||||
{
|
||||
switch (gid)
|
||||
{
|
||||
case CurveID::NONE:
|
||||
return NID_undef;
|
||||
case CurveID::SECP384R1:
|
||||
return NID_secp384r1;
|
||||
case CurveID::SECP256R1:
|
||||
return NID_X9_62_prime256v1;
|
||||
default:
|
||||
throw std::logic_error(
|
||||
fmt::format("unsupported OpenSSL CurveID {}", gid));
|
||||
}
|
||||
return MBEDTLS_ECP_DP_NONE;
|
||||
}
|
||||
|
||||
static std::map<std::string, std::string> parse_name(const std::string& name)
|
||||
{
|
||||
std::map<std::string, std::string> result;
|
||||
|
@ -100,6 +83,17 @@ namespace crypto
|
|||
return PublicKey_OpenSSL::public_key_der();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> KeyPair_OpenSSL::private_key_der() const
|
||||
{
|
||||
Unique_BIO buf;
|
||||
|
||||
OpenSSL::CHECK1(i2d_PrivateKey_bio(buf, key));
|
||||
|
||||
BUF_MEM* bptr;
|
||||
BIO_get_mem_ptr(buf, &bptr);
|
||||
return {bptr->data, bptr->data + bptr->length};
|
||||
}
|
||||
|
||||
bool KeyPair_OpenSSL::verify(
|
||||
const std::vector<uint8_t>& contents, const std::vector<uint8_t>& signature)
|
||||
{
|
||||
|
@ -343,4 +337,35 @@ namespace crypto
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
CurveID KeyPair_OpenSSL::get_curve_id() const
|
||||
{
|
||||
return PublicKey_OpenSSL::get_curve_id();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> KeyPair_OpenSSL::public_key_raw() const
|
||||
{
|
||||
return PublicKey_OpenSSL::public_key_raw();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> KeyPair_OpenSSL::derive_shared_secret(
|
||||
const PublicKey& peer_key)
|
||||
{
|
||||
crypto::CurveID cid = peer_key.get_curve_id();
|
||||
int nid = crypto::PublicKey_OpenSSL::get_openssl_group_id(cid);
|
||||
auto pk = key_from_raw_ec_point(peer_key.public_key_raw(), nid);
|
||||
|
||||
std::vector<uint8_t> shared_secret;
|
||||
size_t shared_secret_length = 0;
|
||||
Unique_EVP_PKEY_CTX ctx(key);
|
||||
CHECK1(EVP_PKEY_derive_init(ctx));
|
||||
CHECK1(EVP_PKEY_derive_set_peer(ctx, pk));
|
||||
CHECK1(EVP_PKEY_derive(ctx, NULL, &shared_secret_length));
|
||||
shared_secret.resize(shared_secret_length);
|
||||
CHECK1(EVP_PKEY_derive(ctx, shared_secret.data(), &shared_secret_length));
|
||||
|
||||
EVP_PKEY_free(pk);
|
||||
|
||||
return shared_secret;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ namespace crypto
|
|||
virtual Pem private_key_pem() const override;
|
||||
virtual Pem public_key_pem() const override;
|
||||
virtual std::vector<uint8_t> public_key_der() const override;
|
||||
virtual std::vector<uint8_t> private_key_der() const override;
|
||||
|
||||
using PublicKey_OpenSSL::verify;
|
||||
|
||||
|
@ -60,5 +61,12 @@ namespace crypto
|
|||
bool ca = false,
|
||||
const std::optional<std::string>& valid_from = std::nullopt,
|
||||
const std::optional<std::string>& valid_to = std::nullopt) const override;
|
||||
|
||||
virtual std::vector<uint8_t> derive_shared_secret(
|
||||
const PublicKey& peer_key) override;
|
||||
|
||||
virtual CurveID get_curve_id() const override;
|
||||
|
||||
virtual std::vector<uint8_t> public_key_raw() const override;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -130,6 +130,10 @@ namespace crypto
|
|||
Unique_SSL_OBJECT(
|
||||
BIO_new_mem_buf(pem.data(), -1), [](auto x) { BIO_free(x); })
|
||||
{}
|
||||
Unique_BIO(SSL_CTX* ctx) :
|
||||
Unique_SSL_OBJECT(
|
||||
BIO_new_ssl_connect(ctx), [](auto x) { BIO_free_all(x); })
|
||||
{}
|
||||
};
|
||||
|
||||
struct Unique_SSL_CTX : public Unique_SSL_OBJECT<SSL_CTX, nullptr, nullptr>
|
||||
|
@ -176,18 +180,22 @@ namespace crypto
|
|||
: public Unique_SSL_OBJECT<X509_CRL, X509_CRL_new, X509_CRL_free>
|
||||
{
|
||||
using Unique_SSL_OBJECT::Unique_SSL_OBJECT;
|
||||
Unique_X509_CRL(BIO* mem) :
|
||||
Unique_SSL_OBJECT(
|
||||
PEM_read_bio_X509_CRL(mem, NULL, NULL, NULL), X509_CRL_free)
|
||||
{}
|
||||
};
|
||||
|
||||
struct Unique_X509 : public Unique_SSL_OBJECT<X509, X509_new, X509_free>
|
||||
{
|
||||
using Unique_SSL_OBJECT::Unique_SSL_OBJECT;
|
||||
// p == nullptr is OK (e.g. wrong format)
|
||||
Unique_X509(BIO* mem, bool pem) :
|
||||
Unique_X509(BIO* mem, bool pem, bool check_null = false) :
|
||||
Unique_SSL_OBJECT(
|
||||
pem ? PEM_read_bio_X509(mem, NULL, NULL, NULL) :
|
||||
d2i_X509_bio(mem, NULL),
|
||||
X509_free,
|
||||
/*check_null=*/false)
|
||||
check_null)
|
||||
{}
|
||||
Unique_X509(X509* cert, bool check_null) :
|
||||
Unique_SSL_OBJECT(cert, X509_free, check_null)
|
||||
|
@ -266,5 +274,37 @@ namespace crypto
|
|||
Unique_SSL_OBJECT(t, ASN1_TIME_free, /*check_null=*/false)
|
||||
{}
|
||||
};
|
||||
|
||||
struct Unique_BN_CTX
|
||||
: public Unique_SSL_OBJECT<BN_CTX, BN_CTX_new, BN_CTX_free>
|
||||
{
|
||||
using Unique_SSL_OBJECT::Unique_SSL_OBJECT;
|
||||
};
|
||||
|
||||
struct Unique_EC_GROUP
|
||||
: public Unique_SSL_OBJECT<EC_GROUP, nullptr, nullptr>
|
||||
{
|
||||
Unique_EC_GROUP(int nid) :
|
||||
Unique_SSL_OBJECT(
|
||||
EC_GROUP_new_by_curve_name(nid), EC_GROUP_free, /*check_null=*/true)
|
||||
{}
|
||||
};
|
||||
|
||||
struct Unique_EC_POINT
|
||||
: public Unique_SSL_OBJECT<EC_POINT, nullptr, nullptr>
|
||||
{
|
||||
Unique_EC_POINT(EC_GROUP* group) :
|
||||
Unique_SSL_OBJECT(
|
||||
EC_POINT_new(group), EC_POINT_free, /*check_null=*/true)
|
||||
{}
|
||||
};
|
||||
|
||||
struct Unique_EC_KEY : public Unique_SSL_OBJECT<EC_KEY, nullptr, nullptr>
|
||||
{
|
||||
Unique_EC_KEY(int nid) :
|
||||
Unique_SSL_OBJECT(
|
||||
EC_KEY_new_by_curve_name(nid), EC_KEY_free, /*check_null=*/true)
|
||||
{}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
#include <openssl/engine.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/ossl_typ.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
@ -63,6 +65,29 @@ namespace crypto
|
|||
return CurveID::NONE;
|
||||
}
|
||||
|
||||
int PublicKey_OpenSSL::get_openssl_group_id() const
|
||||
{
|
||||
return EC_GROUP_get_curve_name(
|
||||
EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(key)));
|
||||
}
|
||||
|
||||
int PublicKey_OpenSSL::get_openssl_group_id(CurveID gid)
|
||||
{
|
||||
switch (gid)
|
||||
{
|
||||
case CurveID::NONE:
|
||||
return NID_undef;
|
||||
case CurveID::SECP384R1:
|
||||
return NID_secp384r1;
|
||||
case CurveID::SECP256R1:
|
||||
return NID_X9_62_prime256v1;
|
||||
default:
|
||||
throw std::logic_error(
|
||||
fmt::format("unsupported OpenSSL CurveID {}", gid));
|
||||
}
|
||||
return NID_undef;
|
||||
}
|
||||
|
||||
bool PublicKey_OpenSSL::verify(
|
||||
const uint8_t* contents,
|
||||
size_t contents_size,
|
||||
|
@ -134,4 +159,39 @@ namespace crypto
|
|||
BIO_get_mem_ptr(buf, &bptr);
|
||||
return {bptr->data, bptr->data + bptr->length};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> PublicKey_OpenSSL::public_key_raw() const
|
||||
{
|
||||
Unique_BIO buf;
|
||||
|
||||
unsigned char* p = NULL;
|
||||
size_t n = i2d_PublicKey(key, &p);
|
||||
|
||||
std::vector<uint8_t> r;
|
||||
if (p)
|
||||
{
|
||||
r = {p, p + n};
|
||||
}
|
||||
free(p);
|
||||
return r;
|
||||
}
|
||||
|
||||
Unique_PKEY key_from_raw_ec_point(const std::vector<uint8_t>& raw, int nid)
|
||||
{
|
||||
// To extract a raw encoding of the EC point, OpenSSL has i2d_PublicKey,
|
||||
// but the converse in d2i_PublicKey is useless until we switch to 3.0
|
||||
// (see also https://github.com/openssl/openssl/issues/16989).
|
||||
// So, instead we reconstruct the key the long way round.
|
||||
|
||||
Unique_BN_CTX bn_ctx;
|
||||
Unique_EC_GROUP group(nid);
|
||||
Unique_EC_POINT p(group);
|
||||
CHECK1(EC_POINT_oct2point(group, p, raw.data(), raw.size(), bn_ctx));
|
||||
Unique_EC_KEY ec_key(nid);
|
||||
CHECK1(EC_KEY_set_public_key(ec_key, p));
|
||||
Unique_PKEY pk;
|
||||
CHECK1(EVP_PKEY_set1_EC_KEY(pk, ec_key));
|
||||
EVP_PKEY_up_ref(pk);
|
||||
return pk;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "../public_key.h"
|
||||
#include "openssl_wrappers.h"
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
|
@ -16,7 +17,6 @@ namespace crypto
|
|||
protected:
|
||||
EVP_PKEY* key = nullptr;
|
||||
PublicKey_OpenSSL();
|
||||
CurveID get_curve_id() const;
|
||||
|
||||
public:
|
||||
PublicKey_OpenSSL(PublicKey_OpenSSL&& key) = default;
|
||||
|
@ -45,5 +45,19 @@ namespace crypto
|
|||
|
||||
virtual Pem public_key_pem() const override;
|
||||
virtual std::vector<uint8_t> public_key_der() const override;
|
||||
virtual std::vector<uint8_t> public_key_raw() const override;
|
||||
|
||||
virtual CurveID get_curve_id() const override;
|
||||
|
||||
int get_openssl_group_id() const;
|
||||
static int get_openssl_group_id(CurveID gid);
|
||||
|
||||
operator EVP_PKEY*() const
|
||||
{
|
||||
return key;
|
||||
}
|
||||
};
|
||||
|
||||
OpenSSL::Unique_PKEY key_from_raw_ec_point(
|
||||
const std::vector<uint8_t>& raw, int nid);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
// Licensed under the Apache 2.0 License.
|
||||
#include "symmetric_key.h"
|
||||
|
||||
#include "../mbedtls/symmetric_key.h"
|
||||
#include "crypto/openssl/openssl_wrappers.h"
|
||||
#include "crypto/symmetric_key.h"
|
||||
#include "ds/logger.h"
|
||||
|
|
|
@ -157,4 +157,14 @@ namespace crypto
|
|||
to_x509_time_string(X509_get0_notBefore(cert)),
|
||||
to_x509_time_string(X509_get0_notAfter(cert)));
|
||||
}
|
||||
|
||||
std::string Verifier_OpenSSL::subject() const
|
||||
{
|
||||
X509_NAME* name = X509_get_subject_name(cert);
|
||||
Unique_BIO mem;
|
||||
X509_NAME_print_ex(mem, name, 0, 0);
|
||||
BUF_MEM* bptr;
|
||||
BIO_get_mem_ptr(mem, &bptr);
|
||||
return std::string(bptr->data, bptr->length);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,5 +35,7 @@ namespace crypto
|
|||
|
||||
virtual std::pair<std::string, std::string> validity_period()
|
||||
const override;
|
||||
|
||||
virtual std::string subject() const override;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -126,5 +126,15 @@ namespace crypto
|
|||
* Get the public key in DER format
|
||||
*/
|
||||
virtual std::vector<uint8_t> public_key_der() const = 0;
|
||||
|
||||
/**
|
||||
* Get the raw bytes of the public key
|
||||
*/
|
||||
virtual std::vector<uint8_t> public_key_raw() const = 0;
|
||||
|
||||
/**
|
||||
* The curve ID
|
||||
*/
|
||||
virtual CurveID get_curve_id() const = 0;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,20 +1,14 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
|
||||
#include "mbedtls/rsa_key_pair.h"
|
||||
|
||||
#include "openssl/rsa_key_pair.h"
|
||||
|
||||
#include "rsa_key_pair.h"
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
#ifdef CRYPTO_PROVIDER_IS_MBEDTLS
|
||||
using RSAPublicKeyImpl = RSAPublicKey_mbedTLS;
|
||||
using RSAKeyPairImpl = RSAKeyPair_mbedTLS;
|
||||
#else
|
||||
using RSAPublicKeyImpl = RSAPublicKey_OpenSSL;
|
||||
using RSAKeyPairImpl = RSAKeyPair_OpenSSL;
|
||||
#endif
|
||||
|
||||
RSAPublicKeyPtr make_rsa_public_key(const Pem& public_pem)
|
||||
{
|
||||
|
|
|
@ -1,23 +1,16 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
|
||||
#include "crypto/mbedtls/symmetric_key.h"
|
||||
|
||||
#include "crypto/openssl/symmetric_key.h"
|
||||
|
||||
#include "crypto/rsa_key_pair.h"
|
||||
#include "symmetric_key.h"
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
using namespace mbedtls;
|
||||
|
||||
std::unique_ptr<KeyAesGcm> make_key_aes_gcm(CBuffer rawKey)
|
||||
{
|
||||
#ifdef CRYPTO_PROVIDER_IS_MBEDTLS
|
||||
return std::make_unique<KeyAesGcm_mbedTLS>(rawKey);
|
||||
#else
|
||||
return std::make_unique<KeyAesGcm_OpenSSL>(rawKey);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<uint8_t> aes_gcm_encrypt(
|
||||
|
|
|
@ -4,10 +4,6 @@
|
|||
#include "crypto/hash.h"
|
||||
#include "crypto/hash_provider.h"
|
||||
#include "crypto/key_pair.h"
|
||||
#include "crypto/mbedtls/base64.h"
|
||||
#include "crypto/mbedtls/hash.h"
|
||||
#include "crypto/mbedtls/key_pair.h"
|
||||
#include "crypto/mbedtls/rsa_key_pair.h"
|
||||
#include "crypto/openssl/base64.h"
|
||||
#include "crypto/openssl/hash.h"
|
||||
#include "crypto/openssl/key_pair.h"
|
||||
|
@ -118,23 +114,14 @@ const std::vector<int> sizes = {10};
|
|||
PICOBENCH_SUITE("sign secp384r1");
|
||||
namespace SIGN_SECP384R1
|
||||
{
|
||||
auto sign_384_mbed_1byte =
|
||||
benchmark_sign<KeyPair_mbedTLS, CurveID::SECP384R1, 1>;
|
||||
PICOBENCH(sign_384_mbed_1byte).PICO_SUFFIX(CurveID::SECP384R1);
|
||||
auto sign_384_ossl_1byte =
|
||||
benchmark_sign<KeyPair_OpenSSL, CurveID::SECP384R1, 1>;
|
||||
PICOBENCH(sign_384_ossl_1byte).PICO_SUFFIX(CurveID::SECP384R1);
|
||||
|
||||
auto sign_384_mbed_1k =
|
||||
benchmark_sign<KeyPair_mbedTLS, CurveID::SECP384R1, 1024>;
|
||||
PICOBENCH(sign_384_mbed_1k).PICO_SUFFIX(CurveID::SECP384R1);
|
||||
auto sign_384_ossl_1k =
|
||||
benchmark_sign<KeyPair_OpenSSL, CurveID::SECP384R1, 1024>;
|
||||
PICOBENCH(sign_384_ossl_1k).PICO_SUFFIX(CurveID::SECP384R1);
|
||||
|
||||
auto sign_384_mbed_100k =
|
||||
benchmark_sign<KeyPair_mbedTLS, CurveID::SECP384R1, 102400>;
|
||||
PICOBENCH(sign_384_mbed_100k).PICO_SUFFIX(CurveID::SECP384R1);
|
||||
auto sign_384_ossl_100k =
|
||||
benchmark_sign<KeyPair_OpenSSL, CurveID::SECP384R1, 102400>;
|
||||
PICOBENCH(sign_384_ossl_100k).PICO_SUFFIX(CurveID::SECP384R1);
|
||||
|
@ -143,23 +130,14 @@ namespace SIGN_SECP384R1
|
|||
PICOBENCH_SUITE("sign secp256r1");
|
||||
namespace SIGN_SECP256R1
|
||||
{
|
||||
auto sign_256r1_mbed_1byte =
|
||||
benchmark_sign<KeyPair_mbedTLS, CurveID::SECP256R1, 1>;
|
||||
PICOBENCH(sign_256r1_mbed_1byte).PICO_SUFFIX(CurveID::SECP256R1);
|
||||
auto sign_256r1_ossl_1byte =
|
||||
benchmark_sign<KeyPair_OpenSSL, CurveID::SECP256R1, 1>;
|
||||
PICOBENCH(sign_256r1_ossl_1byte).PICO_SUFFIX(CurveID::SECP256R1);
|
||||
|
||||
auto sign_256r1_mbed_1k =
|
||||
benchmark_sign<KeyPair_mbedTLS, CurveID::SECP256R1, 1024>;
|
||||
PICOBENCH(sign_256r1_mbed_1k).PICO_SUFFIX(CurveID::SECP256R1);
|
||||
auto sign_256r1_ossl_1k =
|
||||
benchmark_sign<KeyPair_OpenSSL, CurveID::SECP256R1, 1024>;
|
||||
PICOBENCH(sign_256r1_ossl_1k).PICO_SUFFIX(CurveID::SECP256R1);
|
||||
|
||||
auto sign_256r1_mbed_100k =
|
||||
benchmark_sign<KeyPair_mbedTLS, CurveID::SECP256R1, 102400>;
|
||||
PICOBENCH(sign_256r1_mbed_100k).PICO_SUFFIX(CurveID::SECP256R1);
|
||||
auto sign_256r1_ossl_100k =
|
||||
benchmark_sign<KeyPair_OpenSSL, CurveID::SECP256R1, 102400>;
|
||||
PICOBENCH(sign_256r1_ossl_100k).PICO_SUFFIX(CurveID::SECP256R1);
|
||||
|
@ -168,19 +146,10 @@ namespace SIGN_SECP256R1
|
|||
PICOBENCH_SUITE("verify secp384r1");
|
||||
namespace SECP384R1
|
||||
{
|
||||
auto verify_384_mbed_1byte =
|
||||
benchmark_verify<KeyPair_mbedTLS, PublicKey_mbedTLS, CurveID::SECP384R1, 1>;
|
||||
PICOBENCH(verify_384_mbed_1byte).PICO_SUFFIX(CurveID::SECP384R1);
|
||||
auto verify_384_ossl_1byte =
|
||||
benchmark_verify<KeyPair_OpenSSL, PublicKey_OpenSSL, CurveID::SECP384R1, 1>;
|
||||
PICOBENCH(verify_384_ossl_1byte).PICO_SUFFIX(CurveID::SECP384R1);
|
||||
|
||||
auto verify_384_mbed_1k = benchmark_verify<
|
||||
KeyPair_mbedTLS,
|
||||
PublicKey_mbedTLS,
|
||||
CurveID::SECP384R1,
|
||||
1024>;
|
||||
PICOBENCH(verify_384_mbed_1k).PICO_SUFFIX(CurveID::SECP384R1);
|
||||
auto verify_384_ossl_1k = benchmark_verify<
|
||||
KeyPair_OpenSSL,
|
||||
PublicKey_OpenSSL,
|
||||
|
@ -188,12 +157,6 @@ namespace SECP384R1
|
|||
1024>;
|
||||
PICOBENCH(verify_384_ossl_1k).PICO_SUFFIX(CurveID::SECP384R1);
|
||||
|
||||
auto verify_384_mbed_100k = benchmark_verify<
|
||||
KeyPair_mbedTLS,
|
||||
PublicKey_mbedTLS,
|
||||
CurveID::SECP384R1,
|
||||
102400>;
|
||||
PICOBENCH(verify_384_mbed_100k).PICO_SUFFIX(CurveID::SECP384R1);
|
||||
auto verify_384_ossl_100k = benchmark_verify<
|
||||
KeyPair_OpenSSL,
|
||||
PublicKey_OpenSSL,
|
||||
|
@ -205,19 +168,10 @@ namespace SECP384R1
|
|||
PICOBENCH_SUITE("verify secp256r1");
|
||||
namespace SECP256R1
|
||||
{
|
||||
auto verify_256r1_mbed_1byte =
|
||||
benchmark_verify<KeyPair_mbedTLS, PublicKey_mbedTLS, CurveID::SECP256R1, 1>;
|
||||
PICOBENCH(verify_256r1_mbed_1byte).PICO_SUFFIX(CurveID::SECP256R1);
|
||||
auto verify_256r1_ossl_1byte =
|
||||
benchmark_verify<KeyPair_OpenSSL, PublicKey_OpenSSL, CurveID::SECP256R1, 1>;
|
||||
PICOBENCH(verify_256r1_ossl_1byte).PICO_SUFFIX(CurveID::SECP256R1);
|
||||
|
||||
auto verify_256r1_mbed_1k = benchmark_verify<
|
||||
KeyPair_mbedTLS,
|
||||
PublicKey_mbedTLS,
|
||||
CurveID::SECP256R1,
|
||||
1024>;
|
||||
PICOBENCH(verify_256r1_mbed_1k).PICO_SUFFIX(CurveID::SECP256R1);
|
||||
auto verify_256r1_ossl_1k = benchmark_verify<
|
||||
KeyPair_OpenSSL,
|
||||
PublicKey_OpenSSL,
|
||||
|
@ -225,12 +179,6 @@ namespace SECP256R1
|
|||
1024>;
|
||||
PICOBENCH(verify_256r1_ossl_1k).PICO_SUFFIX(CurveID::SECP256R1);
|
||||
|
||||
auto verify_256r1_mbed_100k = benchmark_verify<
|
||||
KeyPair_mbedTLS,
|
||||
PublicKey_mbedTLS,
|
||||
CurveID::SECP256R1,
|
||||
102400>;
|
||||
PICOBENCH(verify_256r1_mbed_100k).PICO_SUFFIX(CurveID::SECP256R1);
|
||||
auto verify_256r1_ossl_100k = benchmark_verify<
|
||||
KeyPair_OpenSSL,
|
||||
PublicKey_OpenSSL,
|
||||
|
@ -261,18 +209,12 @@ namespace SIGN_RSA2048
|
|||
|
||||
auto sign_rsa_ossl_1byte = benchmark_sign<RSAKeyPair_OpenSSL, 2048, 1>;
|
||||
PICOBENCH(sign_rsa_ossl_1byte).PICO_SUFFIX();
|
||||
auto sign_rsa_mbed_1byte = benchmark_sign<RSAKeyPair_mbedTLS, 2048, 1>;
|
||||
PICOBENCH(sign_rsa_mbed_1byte).PICO_SUFFIX();
|
||||
|
||||
auto sign_rsa_ossl_1k = benchmark_sign<RSAKeyPair_OpenSSL, 2048, 1024>;
|
||||
PICOBENCH(sign_rsa_ossl_1k).PICO_SUFFIX();
|
||||
auto sign_rsa_mbed_1k = benchmark_sign<RSAKeyPair_mbedTLS, 2048, 1024>;
|
||||
PICOBENCH(sign_rsa_mbed_1k).PICO_SUFFIX();
|
||||
|
||||
auto sign_rsa_ossl_100k = benchmark_sign<RSAKeyPair_OpenSSL, 2048, 102400>;
|
||||
PICOBENCH(sign_rsa_ossl_100k).PICO_SUFFIX();
|
||||
auto sign_rsa_mbed_100k = benchmark_sign<RSAKeyPair_mbedTLS, 2048, 102400>;
|
||||
PICOBENCH(sign_rsa_mbed_100k).PICO_SUFFIX();
|
||||
}
|
||||
|
||||
PICOBENCH_SUITE("verify RSA-2048");
|
||||
|
@ -306,32 +248,18 @@ namespace VERIFY_RSA2048
|
|||
|
||||
auto verify_rsa_ossl_1byte = benchmark_verify<RSAKeyPair_OpenSSL, 2048, 1>;
|
||||
PICOBENCH(verify_rsa_ossl_1byte).PICO_SUFFIX();
|
||||
auto verify_rsa_mbed_1byte = benchmark_verify<RSAKeyPair_mbedTLS, 2048, 1>;
|
||||
PICOBENCH(verify_rsa_mbed_1byte).PICO_SUFFIX();
|
||||
|
||||
auto verify_rsa_ossl_1k = benchmark_verify<RSAKeyPair_OpenSSL, 2048, 1024>;
|
||||
PICOBENCH(verify_rsa_ossl_1k).PICO_SUFFIX();
|
||||
auto verify_rsa_mbed_1k = benchmark_verify<RSAKeyPair_mbedTLS, 2048, 1024>;
|
||||
PICOBENCH(verify_rsa_mbed_1k).PICO_SUFFIX();
|
||||
|
||||
auto verify_rsa_ossl_100k =
|
||||
benchmark_verify<RSAKeyPair_OpenSSL, 2048, 102400>;
|
||||
PICOBENCH(verify_rsa_ossl_100k).PICO_SUFFIX();
|
||||
auto verify_rsa_mbed_100k =
|
||||
benchmark_verify<RSAKeyPair_mbedTLS, 2048, 102400>;
|
||||
PICOBENCH(verify_rsa_mbed_100k).PICO_SUFFIX();
|
||||
}
|
||||
|
||||
PICOBENCH_SUITE("hash");
|
||||
namespace Hashes
|
||||
{
|
||||
auto sha_384_mbed_1byte = benchmark_hash<MBedHashProvider, MDType::SHA384, 1>;
|
||||
PICOBENCH(sha_384_mbed_1byte).PICO_HASH_SUFFIX().baseline();
|
||||
auto sha_256_mbed_1byte = benchmark_hash<MBedHashProvider, MDType::SHA256, 1>;
|
||||
PICOBENCH(sha_256_mbed_1byte).PICO_HASH_SUFFIX();
|
||||
auto sha_512_mbed_1byte = benchmark_hash<MBedHashProvider, MDType::SHA512, 1>;
|
||||
PICOBENCH(sha_512_mbed_1byte).PICO_HASH_SUFFIX();
|
||||
|
||||
auto sha_384_ossl_1byte =
|
||||
benchmark_hash<OpenSSLHashProvider, MDType::SHA384, 1>;
|
||||
PICOBENCH(sha_384_ossl_1byte).PICO_HASH_SUFFIX();
|
||||
|
@ -342,13 +270,6 @@ namespace Hashes
|
|||
benchmark_hash<OpenSSLHashProvider, MDType::SHA512, 1>;
|
||||
PICOBENCH(sha_512_ossl_1byte).PICO_HASH_SUFFIX();
|
||||
|
||||
auto sha_384_mbed_1k = benchmark_hash<MBedHashProvider, MDType::SHA384, 1024>;
|
||||
PICOBENCH(sha_384_mbed_1k).PICO_HASH_SUFFIX();
|
||||
auto sha_256_mbed_1k = benchmark_hash<MBedHashProvider, MDType::SHA256, 1024>;
|
||||
PICOBENCH(sha_256_mbed_1k).PICO_HASH_SUFFIX();
|
||||
auto sha_512_mbed_1k = benchmark_hash<MBedHashProvider, MDType::SHA512, 1024>;
|
||||
PICOBENCH(sha_512_mbed_1k).PICO_HASH_SUFFIX();
|
||||
|
||||
auto sha_384_ossl_1k =
|
||||
benchmark_hash<OpenSSLHashProvider, MDType::SHA384, 1024>;
|
||||
PICOBENCH(sha_384_ossl_1k).PICO_HASH_SUFFIX();
|
||||
|
@ -359,16 +280,6 @@ namespace Hashes
|
|||
benchmark_hash<OpenSSLHashProvider, MDType::SHA512, 1024>;
|
||||
PICOBENCH(sha_512_ossl_1k).PICO_HASH_SUFFIX();
|
||||
|
||||
auto sha_384_mbed_100k =
|
||||
benchmark_hash<MBedHashProvider, MDType::SHA384, 102400>;
|
||||
PICOBENCH(sha_384_mbed_100k).PICO_HASH_SUFFIX();
|
||||
auto sha_256_mbed_100k =
|
||||
benchmark_hash<MBedHashProvider, MDType::SHA256, 102400>;
|
||||
PICOBENCH(sha_256_mbed_100k).PICO_HASH_SUFFIX();
|
||||
auto sha_512_mbed_100k =
|
||||
benchmark_hash<MBedHashProvider, MDType::SHA512, 102400>;
|
||||
PICOBENCH(sha_512_mbed_100k).PICO_HASH_SUFFIX();
|
||||
|
||||
auto sha_384_ossl_100k =
|
||||
benchmark_hash<OpenSSLHashProvider, MDType::SHA384, 102400>;
|
||||
PICOBENCH(sha_384_ossl_100k).PICO_HASH_SUFFIX();
|
||||
|
@ -380,16 +291,10 @@ namespace Hashes
|
|||
PICOBENCH(sha_512_ossl_100k).PICO_HASH_SUFFIX();
|
||||
}
|
||||
|
||||
enum Impl
|
||||
{
|
||||
mbedtls,
|
||||
openssl
|
||||
};
|
||||
|
||||
PICOBENCH_SUITE("digest sha256");
|
||||
namespace SHA256_bench
|
||||
{
|
||||
template <Impl IMPL, size_t size>
|
||||
template <size_t size>
|
||||
static void sha256_bench(picobench::state& s)
|
||||
{
|
||||
std::vector<uint8_t> v(size);
|
||||
|
@ -403,48 +308,31 @@ namespace SHA256_bench
|
|||
s.start_timer();
|
||||
for (size_t i = 0; i < 10; ++i)
|
||||
{
|
||||
if constexpr (IMPL == Impl::mbedtls)
|
||||
{
|
||||
crypto::mbedtls_sha256(v, h.h.data());
|
||||
}
|
||||
else if constexpr (IMPL == Impl::openssl)
|
||||
{
|
||||
crypto::openssl_sha256(v, h.h.data());
|
||||
}
|
||||
crypto::openssl_sha256(v, h.h.data());
|
||||
}
|
||||
s.stop_timer();
|
||||
}
|
||||
|
||||
auto mbedtls_sha256_base = sha256_bench<Impl::mbedtls, 2 << 6>;
|
||||
PICOBENCH(mbedtls_sha256_base).PICO_HASH_SUFFIX().baseline();
|
||||
auto openssl_sha256_base = sha256_bench<Impl::openssl, 2 << 6>;
|
||||
auto openssl_sha256_base = sha256_bench<2 << 6>;
|
||||
PICOBENCH(openssl_sha256_base).PICO_HASH_SUFFIX();
|
||||
|
||||
auto mbedtls_sha256_8 = sha256_bench<Impl::mbedtls, 2 << 8>;
|
||||
PICOBENCH(mbedtls_sha256_8).PICO_HASH_SUFFIX();
|
||||
auto openssl_sha256_8 = sha256_bench<Impl::openssl, 2 << 8>;
|
||||
auto openssl_sha256_8 = sha256_bench<2 << 8>;
|
||||
PICOBENCH(openssl_sha256_8).PICO_HASH_SUFFIX();
|
||||
|
||||
auto mbedtls_sha256_12 = sha256_bench<Impl::mbedtls, 2 << 12>;
|
||||
PICOBENCH(mbedtls_sha256_12).PICO_HASH_SUFFIX();
|
||||
auto openssl_sha256_12 = sha256_bench<Impl::openssl, 2 << 12>;
|
||||
auto openssl_sha256_12 = sha256_bench<2 << 12>;
|
||||
PICOBENCH(openssl_sha256_12).PICO_HASH_SUFFIX();
|
||||
|
||||
auto mbedtls_sha256_16 = sha256_bench<Impl::mbedtls, 2 << 16>;
|
||||
PICOBENCH(mbedtls_sha256_16).PICO_HASH_SUFFIX();
|
||||
auto openssl_sha256_16 = sha256_bench<Impl::openssl, 2 << 16>;
|
||||
auto openssl_sha256_16 = sha256_bench<2 << 16>;
|
||||
PICOBENCH(openssl_sha256_16).PICO_HASH_SUFFIX();
|
||||
|
||||
auto mbedtls_sha256_18 = sha256_bench<Impl::mbedtls, 2 << 18>;
|
||||
PICOBENCH(mbedtls_sha256_18).PICO_HASH_SUFFIX();
|
||||
auto openssl_sha256_18 = sha256_bench<Impl::openssl, 2 << 18>;
|
||||
auto openssl_sha256_18 = sha256_bench<2 << 18>;
|
||||
PICOBENCH(openssl_sha256_18).PICO_HASH_SUFFIX();
|
||||
}
|
||||
|
||||
PICOBENCH_SUITE("base64");
|
||||
namespace Base64_bench
|
||||
{
|
||||
template <Impl IMPL, size_t size>
|
||||
template <size_t size>
|
||||
static void base64_bench(picobench::state& s)
|
||||
{
|
||||
std::vector<uint8_t> v(size);
|
||||
|
@ -457,51 +345,30 @@ namespace Base64_bench
|
|||
for (size_t i = 0; i < 10; ++i)
|
||||
{
|
||||
// We don't check the outputs as this is done elsewhere
|
||||
if constexpr (IMPL == Impl::mbedtls)
|
||||
{
|
||||
std::string encoded =
|
||||
crypto::Base64_mbedtls::b64_from_raw(v.data(), v.size());
|
||||
crypto::Base64_mbedtls::raw_from_b64(encoded);
|
||||
}
|
||||
else if constexpr (IMPL == Impl::openssl)
|
||||
{
|
||||
std::string encoded =
|
||||
crypto::Base64_openssl::b64_from_raw(v.data(), v.size());
|
||||
crypto::Base64_openssl::raw_from_b64(encoded);
|
||||
}
|
||||
std::string encoded =
|
||||
crypto::Base64_openssl::b64_from_raw(v.data(), v.size());
|
||||
crypto::Base64_openssl::raw_from_b64(encoded);
|
||||
}
|
||||
s.stop_timer();
|
||||
}
|
||||
|
||||
// Single line is 64 chars (48 bytes)
|
||||
auto mbedtls_base64_base = base64_bench<Impl::mbedtls, 45>;
|
||||
PICOBENCH(mbedtls_base64_base).PICO_HASH_SUFFIX().baseline();
|
||||
auto openssl_base64_base = base64_bench<Impl::openssl, 45>;
|
||||
auto openssl_base64_base = base64_bench<45>;
|
||||
PICOBENCH(openssl_base64_base).PICO_HASH_SUFFIX();
|
||||
|
||||
// Small double line
|
||||
auto mbedtls_base64_50 = base64_bench<Impl::mbedtls, 50>;
|
||||
PICOBENCH(mbedtls_base64_50).PICO_HASH_SUFFIX();
|
||||
auto openssl_base64_50 = base64_bench<Impl::openssl, 50>;
|
||||
auto openssl_base64_50 = base64_bench<50>;
|
||||
PICOBENCH(openssl_base64_50).PICO_HASH_SUFFIX();
|
||||
|
||||
auto mbedtls_base64_100 = base64_bench<Impl::mbedtls, 100>;
|
||||
PICOBENCH(mbedtls_base64_100).PICO_HASH_SUFFIX();
|
||||
auto openssl_base64_100 = base64_bench<Impl::openssl, 100>;
|
||||
auto openssl_base64_100 = base64_bench<100>;
|
||||
PICOBENCH(openssl_base64_100).PICO_HASH_SUFFIX();
|
||||
|
||||
auto mbedtls_base64_500 = base64_bench<Impl::mbedtls, 500>;
|
||||
PICOBENCH(mbedtls_base64_500).PICO_HASH_SUFFIX();
|
||||
auto openssl_base64_500 = base64_bench<Impl::openssl, 500>;
|
||||
auto openssl_base64_500 = base64_bench<500>;
|
||||
PICOBENCH(openssl_base64_500).PICO_HASH_SUFFIX();
|
||||
|
||||
auto mbedtls_base64_1000 = base64_bench<Impl::mbedtls, 1000>;
|
||||
PICOBENCH(mbedtls_base64_1000).PICO_HASH_SUFFIX();
|
||||
auto openssl_base64_1000 = base64_bench<Impl::openssl, 1000>;
|
||||
auto openssl_base64_1000 = base64_bench<1000>;
|
||||
PICOBENCH(openssl_base64_1000).PICO_HASH_SUFFIX();
|
||||
|
||||
auto mbedtls_base64_5000 = base64_bench<Impl::mbedtls, 5000>;
|
||||
PICOBENCH(mbedtls_base64_5000).PICO_HASH_SUFFIX();
|
||||
auto openssl_base64_5000 = base64_bench<Impl::openssl, 5000>;
|
||||
auto openssl_base64_5000 = base64_bench<5000>;
|
||||
PICOBENCH(openssl_base64_5000).PICO_HASH_SUFFIX();
|
||||
}
|
||||
|
|
|
@ -6,12 +6,6 @@
|
|||
#include "crypto/entropy.h"
|
||||
#include "crypto/key_pair.h"
|
||||
#include "crypto/key_wrap.h"
|
||||
#include "crypto/mbedtls/entropy.h"
|
||||
#include "crypto/mbedtls/key_pair.h"
|
||||
#include "crypto/mbedtls/public_key.h"
|
||||
#include "crypto/mbedtls/rsa_key_pair.h"
|
||||
#include "crypto/mbedtls/symmetric_key.h"
|
||||
#include "crypto/mbedtls/verifier.h"
|
||||
#include "crypto/openssl/key_pair.h"
|
||||
#include "crypto/openssl/rsa_key_pair.h"
|
||||
#include "crypto/openssl/symmetric_key.h"
|
||||
|
@ -172,16 +166,6 @@ void run_alt()
|
|||
CHECK(kp2.verify(contents, signature));
|
||||
}
|
||||
|
||||
TEST_CASE("Sign, verify with alternate implementation")
|
||||
{
|
||||
run_alt<KeyPair_mbedTLS, PublicKey_mbedTLS, CurveID::SECP256R1>();
|
||||
run_alt<KeyPair_OpenSSL, PublicKey_OpenSSL, CurveID::SECP256R1>();
|
||||
run_alt<KeyPair_OpenSSL, PublicKey_mbedTLS, CurveID::SECP384R1>();
|
||||
run_alt<KeyPair_mbedTLS, PublicKey_OpenSSL, CurveID::SECP384R1>();
|
||||
run_alt<KeyPair_OpenSSL, PublicKey_mbedTLS, CurveID::SECP256R1>();
|
||||
run_alt<KeyPair_mbedTLS, PublicKey_OpenSSL, CurveID::SECP256R1>();
|
||||
}
|
||||
|
||||
TEST_CASE("Sign, verify with certificate")
|
||||
{
|
||||
for (const auto curve : supported_curves)
|
||||
|
@ -342,38 +326,6 @@ TEST_CASE("Wrap, unwrap with RSAKeyPair")
|
|||
}
|
||||
}
|
||||
|
||||
TEST_CASE("RSA-OAEP mbedTLS vs OpenSSL")
|
||||
{
|
||||
std::vector<uint8_t> input = create_entropy()->random(32);
|
||||
|
||||
size_t key_sz = 2048;
|
||||
|
||||
auto kp_mbed = std::make_shared<RSAKeyPair_mbedTLS>(key_sz);
|
||||
auto pk_mbed =
|
||||
std::make_shared<RSAPublicKey_mbedTLS>(kp_mbed->public_key_pem());
|
||||
|
||||
auto kp_ossl =
|
||||
std::make_shared<RSAKeyPair_OpenSSL>(kp_mbed->private_key_pem());
|
||||
auto pk_ossl =
|
||||
std::make_shared<RSAPublicKey_OpenSSL>(pk_mbed->public_key_pem());
|
||||
|
||||
INFO("mbedTLS -> OpenSSL");
|
||||
{
|
||||
auto wrapped = pk_mbed->rsa_oaep_wrap(input);
|
||||
REQUIRE(wrapped.size() == key_sz / 8);
|
||||
auto unwrapped = kp_ossl->rsa_oaep_unwrap(wrapped);
|
||||
REQUIRE(input == unwrapped);
|
||||
}
|
||||
|
||||
INFO("OpenSSL -> mbedTLS");
|
||||
{
|
||||
auto wrapped = pk_ossl->rsa_oaep_wrap(input);
|
||||
REQUIRE(wrapped.size() == key_sz / 8);
|
||||
auto unwrapped = kp_mbed->rsa_oaep_unwrap(wrapped);
|
||||
REQUIRE(input == unwrapped);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Extract public key from cert")
|
||||
{
|
||||
for (const auto curve : supported_curves)
|
||||
|
@ -400,7 +352,6 @@ void create_csr_and_extract_pubk()
|
|||
|
||||
TEST_CASE("Extract public key from csr")
|
||||
{
|
||||
create_csr_and_extract_pubk<KeyPair_mbedTLS>();
|
||||
create_csr_and_extract_pubk<KeyPair_OpenSSL>();
|
||||
}
|
||||
|
||||
|
@ -455,9 +406,6 @@ TEST_CASE("Create sign and verify certificates")
|
|||
bool corrupt_csr = false;
|
||||
do
|
||||
{
|
||||
run_csr<KeyPair_mbedTLS, Verifier_mbedTLS>(corrupt_csr);
|
||||
run_csr<KeyPair_mbedTLS, Verifier_OpenSSL>(corrupt_csr);
|
||||
run_csr<KeyPair_OpenSSL, Verifier_mbedTLS>(corrupt_csr);
|
||||
run_csr<KeyPair_OpenSSL, Verifier_OpenSSL>(corrupt_csr);
|
||||
corrupt_csr = !corrupt_csr;
|
||||
} while (corrupt_csr);
|
||||
|
@ -484,101 +432,6 @@ TEST_CASE("ExtendedIv0")
|
|||
REQUIRE(k2->decrypt(h.get_iv(), h.tag, p, nullb, p.p));
|
||||
}
|
||||
|
||||
TEST_CASE("AES mbedTLS vs OpenSSL")
|
||||
{
|
||||
auto key = getRawKey();
|
||||
|
||||
GcmHeader<1234> h;
|
||||
|
||||
{ // mbedTLS -> OpenSSL
|
||||
auto mbed = std::make_unique<KeyAesGcm_mbedTLS>(key);
|
||||
auto ossl = std::make_unique<KeyAesGcm_OpenSSL>(key);
|
||||
|
||||
std::vector<uint8_t> encrypted(contents_.size());
|
||||
mbed->encrypt(h.get_iv(), contents_, nullb, encrypted.data(), h.tag);
|
||||
|
||||
std::vector<unsigned char> rawP(contents_.size(), 'x');
|
||||
Buffer p{rawP.data(), rawP.size()};
|
||||
|
||||
std::vector<uint8_t> decrypted(contents_.size());
|
||||
REQUIRE(ossl->decrypt(
|
||||
h.get_iv(),
|
||||
h.tag,
|
||||
{encrypted.data(), encrypted.size()},
|
||||
nullb,
|
||||
decrypted.data()));
|
||||
|
||||
REQUIRE(decrypted == contents);
|
||||
}
|
||||
|
||||
{ // OpenSSL -> mbedTLS
|
||||
auto mbed = std::make_unique<KeyAesGcm_mbedTLS>(key);
|
||||
auto ossl = std::make_unique<KeyAesGcm_OpenSSL>(key);
|
||||
|
||||
std::vector<uint8_t> encrypted(contents_.size());
|
||||
ossl->encrypt(h.get_iv(), contents_, nullb, encrypted.data(), h.tag);
|
||||
|
||||
std::vector<unsigned char> rawP(contents_.size(), 'x');
|
||||
Buffer p{rawP.data(), rawP.size()};
|
||||
|
||||
std::vector<uint8_t> decrypted(contents_.size());
|
||||
CBuffer encbuf{encrypted.data(), encrypted.size()};
|
||||
REQUIRE(mbed->decrypt(h.get_iv(), h.tag, encbuf, nullb, decrypted.data()));
|
||||
|
||||
REQUIRE(decrypted == contents);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("AES mbedTLS vs OpenSSL + AAD")
|
||||
{
|
||||
auto key = getRawKey();
|
||||
|
||||
GcmHeader<1234> h;
|
||||
std::vector<uint8_t> aad(123, 'y');
|
||||
|
||||
{
|
||||
INFO("mbedTLS -> OpenSSL");
|
||||
|
||||
auto mbed = std::make_unique<KeyAesGcm_mbedTLS>(key);
|
||||
auto ossl = std::make_unique<KeyAesGcm_OpenSSL>(key);
|
||||
|
||||
std::vector<uint8_t> encrypted(contents_.size());
|
||||
mbed->encrypt(h.get_iv(), contents_, aad, encrypted.data(), h.tag);
|
||||
|
||||
std::vector<unsigned char> rawP(contents_.size(), 'x');
|
||||
Buffer p{rawP.data(), rawP.size()};
|
||||
|
||||
std::vector<uint8_t> decrypted(contents_.size());
|
||||
REQUIRE(ossl->decrypt(
|
||||
h.get_iv(),
|
||||
h.tag,
|
||||
{encrypted.data(), encrypted.size()},
|
||||
aad,
|
||||
decrypted.data()));
|
||||
|
||||
REQUIRE(decrypted == contents);
|
||||
}
|
||||
|
||||
{
|
||||
INFO("OpenSSL -> mbedTLS");
|
||||
|
||||
auto mbed = std::make_unique<KeyAesGcm_mbedTLS>(key);
|
||||
auto ossl = std::make_unique<KeyAesGcm_OpenSSL>(key);
|
||||
|
||||
std::vector<uint8_t> encrypted(contents_.size());
|
||||
ossl->encrypt(h.get_iv(), contents_, aad, encrypted.data(), h.tag);
|
||||
|
||||
std::vector<unsigned char> rawP(contents_.size(), 'x');
|
||||
Buffer p{rawP.data(), rawP.size()};
|
||||
|
||||
std::vector<uint8_t> decrypted(contents_.size());
|
||||
CBuffer encbuf{encrypted.data(), encrypted.size()};
|
||||
REQUIRE(mbed->decrypt(h.get_iv(), h.tag, encbuf, aad, decrypted.data()));
|
||||
|
||||
REQUIRE(decrypted == contents);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("AES Key wrap with padding")
|
||||
{
|
||||
auto key = getRawKey();
|
||||
|
@ -729,26 +582,3 @@ TEST_CASE("x509 time")
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("check equality of DER encodings")
|
||||
{
|
||||
{
|
||||
KeyPair_OpenSSL key_ossl(CurveID::SECP384R1);
|
||||
auto der_ossl = key_ossl.public_key_der();
|
||||
PublicKey_mbedTLS pub_mbed(der_ossl);
|
||||
auto der_mbed = pub_mbed.public_key_der();
|
||||
REQUIRE(der_ossl == der_mbed);
|
||||
PublicKey_OpenSSL pub_ossl(pub_mbed.public_key_der());
|
||||
REQUIRE(der_mbed == der_ossl);
|
||||
}
|
||||
|
||||
{
|
||||
KeyPair_mbedTLS key_mbed(CurveID::SECP384R1);
|
||||
auto der_mbed = key_mbed.public_key_der();
|
||||
PublicKey_OpenSSL pub_ossl(der_mbed);
|
||||
auto der_ossl = pub_ossl.public_key_der();
|
||||
REQUIRE(der_ossl == der_mbed);
|
||||
PublicKey_mbedTLS pub_mbed(pub_ossl.public_key_der());
|
||||
REQUIRE(der_mbed == der_ossl);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#include "crypto/key_exchange.h"
|
||||
|
||||
#include "crypto/openssl/key_pair.h"
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
TEST_CASE("Simple key exchange")
|
||||
|
@ -54,9 +56,9 @@ TEST_CASE("Simple key exchange")
|
|||
|
||||
TEST_CASE("Key exchange from static shares")
|
||||
{
|
||||
auto peer1_kp = std::make_shared<crypto::KeyPair_mbedTLS>(
|
||||
auto peer1_kp = std::make_shared<crypto::KeyPair_OpenSSL>(
|
||||
crypto::service_identity_curve_choice);
|
||||
auto peer2_kp = std::make_shared<crypto::KeyPair_mbedTLS>(
|
||||
auto peer2_kp = std::make_shared<crypto::KeyPair_OpenSSL>(
|
||||
crypto::service_identity_curve_choice);
|
||||
|
||||
auto peer1_ctx = tls::KeyExchangeContext(peer1_kp, peer2_kp);
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
|
||||
#include "crypto/mbedtls/verifier.h"
|
||||
#include "verifier.h"
|
||||
|
||||
#include "crypto/openssl/verifier.h"
|
||||
#include "verifier.h"
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
|
@ -13,20 +12,12 @@ namespace crypto
|
|||
|
||||
VerifierUniquePtr make_unique_verifier(const std::vector<uint8_t>& cert)
|
||||
{
|
||||
#ifdef CRYPTO_PROVIDER_IS_MBEDTLS
|
||||
return std::make_unique<Verifier_mbedTLS>(cert);
|
||||
#else
|
||||
return std::make_unique<Verifier_OpenSSL>(cert);
|
||||
#endif
|
||||
}
|
||||
|
||||
VerifierPtr make_verifier(const std::vector<uint8_t>& cert)
|
||||
{
|
||||
#ifdef CRYPTO_PROVIDER_IS_MBEDTLS
|
||||
return std::make_shared<Verifier_mbedTLS>(cert);
|
||||
#else
|
||||
return std::make_shared<Verifier_OpenSSL>(cert);
|
||||
#endif
|
||||
}
|
||||
|
||||
VerifierUniquePtr make_unique_verifier(const Pem& pem)
|
||||
|
|
|
@ -197,6 +197,9 @@ namespace crypto
|
|||
|
||||
/** The validity period of the certificate */
|
||||
virtual std::pair<std::string, std::string> validity_period() const = 0;
|
||||
|
||||
/** The subject name of the certificate */
|
||||
virtual std::string subject() const = 0;
|
||||
};
|
||||
|
||||
using VerifierPtr = std::shared_ptr<Verifier>;
|
||||
|
|
|
@ -191,10 +191,8 @@ namespace enclave
|
|||
|
||||
// Caller authentication is done by each frontend by looking up
|
||||
// the caller's certificate in the relevant store table. The caller
|
||||
// certificate does not have to be signed by a known CA (nullptr,
|
||||
// tls::auth_optional).
|
||||
cert = std::make_shared<tls::Cert>(
|
||||
nullptr, cert_, pk, nullb, tls::auth_optional);
|
||||
// certificate does not have to be signed by a known CA (nullptr).
|
||||
cert = std::make_shared<tls::Cert>(nullptr, cert_, pk, tls::auth_default);
|
||||
}
|
||||
|
||||
void accept(tls::ConnID id, const ListenInterfaceID& listen_interface_id)
|
||||
|
|
|
@ -9,9 +9,7 @@
|
|||
#include "enclave/endpoint.h"
|
||||
#include "tls/context.h"
|
||||
#include "tls/msg_types.h"
|
||||
// These headers are temporary, until we have a single TLS implementation
|
||||
#include "tls/mbedtls/tls.h"
|
||||
#include "tls/openssl/tls.h"
|
||||
#include "tls/tls.h"
|
||||
|
||||
#include <exception>
|
||||
|
||||
|
@ -71,13 +69,7 @@ namespace enclave
|
|||
{
|
||||
execution_thread =
|
||||
threading::ThreadMessaging::get_execution_thread(session_id);
|
||||
// The functions we pass are different so this can only be done
|
||||
// with an ifdef. Remove once we get rid of mbedTLS.
|
||||
#ifdef TLS_PROVIDER_IS_MBEDTLS
|
||||
ctx->set_bio(this, send_callback, recv_callback, dbg_callback);
|
||||
#else
|
||||
ctx->set_bio(this, send_callback_openssl, recv_callback_openssl, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
~TLSEndpoint()
|
||||
|
@ -565,7 +557,6 @@ namespace enclave
|
|||
// emulate MbedTLS.
|
||||
// Once we get rid of MbedTLS we can move the callbacks above to handle BIOs
|
||||
// directly and hopefully remove the complexity below.
|
||||
#ifndef TLS_PROVIDER_IS_MBEDTLS
|
||||
static long send_callback_openssl(
|
||||
BIO* b,
|
||||
int oper,
|
||||
|
@ -680,8 +671,6 @@ namespace enclave
|
|||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Remove this function once MbedTLS is gone.
|
||||
static void dbg_callback(
|
||||
void*, int, const char* file, int line, const char* str)
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <mbedtls/ecdh.h>
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
// -Wpedantic flags token pasting of __VA_ARGS__
|
||||
|
@ -701,7 +700,6 @@ namespace ccf
|
|||
void establish()
|
||||
{
|
||||
auto shared_secret = kex_ctx.compute_shared_secret();
|
||||
kex_ctx.free_ctx();
|
||||
|
||||
{
|
||||
const std::string label_from = peer_id.value() + self.value();
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "entities.h"
|
||||
#include "service_map.h"
|
||||
|
||||
#include <mbedtls/md.h>
|
||||
#include <vector>
|
||||
|
||||
namespace ccf
|
||||
|
@ -41,4 +40,4 @@ namespace ccf
|
|||
};
|
||||
DECLARE_JSON_TYPE(SignedReq)
|
||||
DECLARE_JSON_REQUIRED_FIELDS(SignedReq, sig, req, request_body, md, key_id)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include <string.h>
|
||||
|
||||
#define HAVE_OPENSSL
|
||||
#define HAVE_MBEDTLS
|
||||
// merklecpp traces are off by default, even when CCF tracing is enabled
|
||||
// #include "merklecpp_trace.h"
|
||||
#include <merklecpp/merklecpp.h>
|
||||
|
|
|
@ -243,12 +243,7 @@ namespace ccf
|
|||
auto jwks_url_port = !jwks_url.port.empty() ? jwks_url.port : "443";
|
||||
|
||||
auto ca_cert = std::make_shared<tls::Cert>(
|
||||
ca,
|
||||
std::nullopt,
|
||||
std::nullopt,
|
||||
nullb,
|
||||
tls::auth_required,
|
||||
jwks_url.host);
|
||||
ca, std::nullopt, std::nullopt, tls::auth_required, jwks_url.host);
|
||||
|
||||
LOG_DEBUG_FMT(
|
||||
"JWT key auto-refresh: Requesting JWKS at https://{}:{}{}",
|
||||
|
@ -313,7 +308,6 @@ namespace ccf
|
|||
ca,
|
||||
std::nullopt,
|
||||
std::nullopt,
|
||||
nullb,
|
||||
tls::auth_required,
|
||||
metadata_url.host);
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ TEST_CASE("Check signature verification")
|
|||
auto txs = primary_store.create_tx();
|
||||
auto sigs = txs.rw(signatures);
|
||||
ccf::PrimarySignature bogus(kv::test::PrimaryNodeId, 0);
|
||||
bogus.sig = std::vector<uint8_t>(MBEDTLS_ECDSA_MAX_LEN, 1);
|
||||
bogus.sig = std::vector<uint8_t>(256, 1);
|
||||
sigs->put(bogus);
|
||||
REQUIRE(txs.commit() == kv::CommitResult::FAIL_NO_REPLICATE);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#include "crypto/mbedtls/hash.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "kv/test/stub_consensus.h"
|
||||
#include "node/history.h"
|
||||
|
||||
|
@ -59,7 +59,7 @@ static void hash_only(picobench::state& s)
|
|||
(void)_;
|
||||
auto data = txs[idx++];
|
||||
crypto::Sha256Hash h;
|
||||
crypto::mbedtls_sha256({data}, h.h.data());
|
||||
crypto::default_sha256({data}, h.h.data());
|
||||
do_not_optimize(h);
|
||||
clobber_memory();
|
||||
}
|
||||
|
@ -166,4 +166,4 @@ int main(int argc, char* argv[])
|
|||
picobench::runner runner;
|
||||
runner.parse_cmd_line(argc, argv);
|
||||
return runner.run();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -204,7 +204,7 @@ namespace client
|
|||
private:
|
||||
crypto::Pem key = {};
|
||||
std::string key_id = "Invalid";
|
||||
std::shared_ptr<tls::TlsCert> tls_cert = nullptr;
|
||||
std::shared_ptr<tls::Cert> tls_cert = nullptr;
|
||||
|
||||
// Process reply to an RPC. Records time reply was received. Calls
|
||||
// check_response for derived-overridable validation
|
||||
|
@ -305,8 +305,8 @@ namespace client
|
|||
auto cert_der = crypto::cert_pem_to_der(raw_cert);
|
||||
key_id = crypto::Sha256Hash(cert_der).hex_str();
|
||||
|
||||
tls_cert = std::make_shared<tls::TlsCert>(
|
||||
std::make_shared<tls::TlsCA>(ca), raw_cert, key);
|
||||
tls_cert = std::make_shared<tls::Cert>(
|
||||
std::make_shared<tls::CA>(ca), raw_cert, key);
|
||||
}
|
||||
|
||||
const auto [host, port] = ccf::split_net_address(options.server_address);
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
#define FMT_HEADER_ONLY
|
||||
#include <fmt/format.h>
|
||||
#include <mbedtls/asn1.h>
|
||||
|
||||
namespace timing
|
||||
{
|
||||
|
|
|
@ -1,4 +1,70 @@
|
|||
# TLS
|
||||
# OpenSSL TLS Implementation
|
||||
|
||||
This directory implements a set of wrappers around mbedtls. The only directories
|
||||
it should depend on is `ds` and `crypto`.
|
||||
This is a TLS implementation using OpenSSL that mimics the existing MbedTLS
|
||||
one in a similar fashion. Because of that, some structures and call backs
|
||||
look odd and have some work-arounds to make it fit the current workflow.
|
||||
|
||||
Once we completely deprecate the MbedTLS implementation from CCF, we should
|
||||
re-write the TLS implementation to fit the OpenSSL coding flow, which would
|
||||
make it much simpler and easier to use.
|
||||
|
||||
## CAs and Certificates
|
||||
|
||||
In the MbedTLS world, certificates can be null and have methods to change
|
||||
some configurations in the TLS config/session objects. There isn't a lot of
|
||||
cross-over, so updating the config does the trick.
|
||||
|
||||
However, in OpenSSL, session objects (ssl) are created from config objects
|
||||
(cfg) and inherit all its properties. Therefore, to emulate MbedTLS, we need
|
||||
to do to the session object every action we do to the config object, which is
|
||||
not only redundant, but could be unsafe, if the calls are slightly different.
|
||||
|
||||
### Validation
|
||||
|
||||
Certificate validation can be complex to handle if you can accept connections
|
||||
with certificates or not, and if they come, when and how to validate.
|
||||
|
||||
MbedTLS is a lot more lenient on checks. For example, CAs are not tested for
|
||||
validity of actually signing other certificates, while OpenSSL has extensive
|
||||
checks, which can fail functionality that was previously passing.
|
||||
|
||||
For this reason, a number of extra checks in the OpenSSL side were disabled.
|
||||
Once we get rid of MbedTLS we should revisit those checks again and improve
|
||||
CCF's usage of TLS, and perhaps also creating weaker checks for non-CA
|
||||
certificates, etc.
|
||||
|
||||
## Context
|
||||
|
||||
### BIOs
|
||||
|
||||
MbedTLS operates reads and writes solely via callbacks, with a buffer in the
|
||||
session object acting as async I/O. This is in stark contrast with OpenSSL
|
||||
which uses BIO objects to pass information back and forth, and only have
|
||||
callbacks for debug or very specialized cases.
|
||||
|
||||
We had to implement callbacks and specialize our case, but it could really be
|
||||
just done with BIOs between the ring buffer and the context, but we'd have to
|
||||
change a lot of code outside of the TLS implementation to add that.
|
||||
|
||||
### Reads and Writes
|
||||
|
||||
Reading and writing in MbedTLS returns a positive value for success (number of
|
||||
bytes written) or a negative value for error (pre-defined error codes) including
|
||||
WANTS_READ and WANTS_WRITE.
|
||||
|
||||
In OpenSSL, those methods return 1 for success and 0 or -1 for errors (depending
|
||||
on the version), with all errors, including WANTS_READ and WANTS_WRITE
|
||||
accessible through `SSL_get_error`. This imposes a number of hacks needed to
|
||||
mimic the MbedTLS implementation, including:
|
||||
|
||||
- Multiple `#define`s with common error messages in `tls.h`
|
||||
- Having to negate the error code to match
|
||||
- Multiple checks to `SSL_want_read` and `SSL_want_write`
|
||||
|
||||
### Error Handling
|
||||
|
||||
As discussed above, the error handling is slightly different and promotes
|
||||
verbose code in OpenSSL's side.
|
||||
|
||||
Another example is `verify_result` and `get_verify_error` that is very long
|
||||
in the OpenSSL implementation and two one-liners in MbedTLS.
|
||||
|
|
52
src/tls/ca.h
52
src/tls/ca.h
|
@ -2,8 +2,50 @@
|
|||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#ifdef TLS_PROVIDER_IS_MBEDTLS
|
||||
# include "mbedtls/ca.h"
|
||||
#else
|
||||
# include "openssl/ca.h"
|
||||
#endif
|
||||
#include "crypto/openssl/openssl_wrappers.h"
|
||||
#include "crypto/pem.h"
|
||||
#include "ds/buffer.h"
|
||||
|
||||
#include <exception>
|
||||
|
||||
using namespace crypto;
|
||||
using namespace crypto::OpenSSL;
|
||||
|
||||
namespace tls
|
||||
{
|
||||
enum Auth
|
||||
{
|
||||
auth_default,
|
||||
auth_none,
|
||||
auth_required
|
||||
};
|
||||
|
||||
class CA
|
||||
{
|
||||
private:
|
||||
Unique_X509 ca;
|
||||
|
||||
public:
|
||||
CA(CBuffer ca_ = nullb)
|
||||
{
|
||||
if (ca_.n > 0)
|
||||
{
|
||||
Unique_BIO bio(ca_.p, ca_.n);
|
||||
if (!(ca = Unique_X509(bio, true)))
|
||||
{
|
||||
throw std::logic_error(
|
||||
"Could not parse CA: " + error_string(ERR_get_error()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~CA() = default;
|
||||
|
||||
void use(SSL_CTX* ssl_ctx)
|
||||
{
|
||||
X509_STORE* store = X509_STORE_new();
|
||||
CHECK1(X509_STORE_add_cert(store, ca));
|
||||
SSL_CTX_set_cert_store(ssl_ctx, store);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
127
src/tls/cert.h
127
src/tls/cert.h
|
@ -2,8 +2,125 @@
|
|||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#ifdef TLS_PROVIDER_IS_MBEDTLS
|
||||
# include "mbedtls/cert.h"
|
||||
#else
|
||||
# include "openssl/cert.h"
|
||||
#endif
|
||||
#include "crypto/openssl/key_pair.h"
|
||||
#include "crypto/openssl/openssl_wrappers.h"
|
||||
#include "tls/ca.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <openssl/x509.h>
|
||||
#include <optional>
|
||||
|
||||
using namespace crypto;
|
||||
using namespace crypto::OpenSSL;
|
||||
|
||||
namespace tls
|
||||
{
|
||||
// This class represents the authentication/authorization context for a TLS
|
||||
// session. At least, it contains the peer's CA. At most, it also contains our
|
||||
// own private key/certificate which will be presented in the TLS handshake.
|
||||
// The peer's certificate verification can be overridden with the auth
|
||||
// parameter.
|
||||
class Cert
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<CA> peer_ca;
|
||||
std::optional<std::string> peer_hostname;
|
||||
Auth auth;
|
||||
|
||||
Unique_X509 own_cert;
|
||||
std::shared_ptr<KeyPair_OpenSSL> own_pkey;
|
||||
bool has_own_cert = false;
|
||||
|
||||
public:
|
||||
Cert(
|
||||
std::shared_ptr<CA> peer_ca_,
|
||||
const std::optional<crypto::Pem>& own_cert_ = std::nullopt,
|
||||
const std::optional<crypto::Pem>& own_pkey_ = std::nullopt,
|
||||
Auth auth_ = auth_default,
|
||||
const std::optional<std::string>& peer_hostname_ = std::nullopt) :
|
||||
peer_ca(peer_ca_),
|
||||
peer_hostname(peer_hostname_),
|
||||
auth(auth_)
|
||||
{
|
||||
if (own_cert_.has_value() && own_pkey_.has_value())
|
||||
{
|
||||
Unique_BIO certbio(*own_cert_);
|
||||
own_cert = Unique_X509(certbio, true);
|
||||
own_pkey = std::make_shared<KeyPair_OpenSSL>(*own_pkey_);
|
||||
has_own_cert = true;
|
||||
}
|
||||
}
|
||||
|
||||
~Cert() = default;
|
||||
|
||||
void use(SSL* ssl, SSL_CTX* ssl_ctx)
|
||||
{
|
||||
if (peer_hostname.has_value())
|
||||
{
|
||||
// Peer hostname is only checked against peer certificate (SAN
|
||||
// extension) if it is set. This lets us connect to peers that present
|
||||
// certificates with IPAddress in SAN field (mbedtls does not parse
|
||||
// IPAddress in SAN field). This is OK since we check for peer CA
|
||||
// endorsement.
|
||||
SSL_set1_host(ssl, peer_hostname->c_str());
|
||||
}
|
||||
|
||||
if (peer_ca)
|
||||
{
|
||||
peer_ca->use(ssl_ctx);
|
||||
}
|
||||
|
||||
if (auth != auth_default)
|
||||
{
|
||||
SSL_CTX_set_verify(ssl_ctx, authmode(auth), NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Calling set_verify with SSL_VERIFY_PEER forces the handshake to
|
||||
// request a peer certificate. The server always sends it to the client
|
||||
// but not the other way around. Some code relies on the server doing
|
||||
// that, so we set this here. We return 1 from the validation callback
|
||||
// (a common pattern in OpenSSL implementations) because we don't want
|
||||
// to verify it here, just request it.
|
||||
SSL_CTX_set_verify(
|
||||
ssl_ctx, SSL_VERIFY_PEER, [](int precheck, x509_store_ctx_st* st) {
|
||||
(void)precheck;
|
||||
(void)st;
|
||||
return 1;
|
||||
});
|
||||
SSL_set_verify(
|
||||
ssl, SSL_VERIFY_PEER, [](int precheck, x509_store_ctx_st* st) {
|
||||
(void)precheck;
|
||||
(void)st;
|
||||
return 1;
|
||||
});
|
||||
}
|
||||
|
||||
if (has_own_cert)
|
||||
{
|
||||
CHECK1(SSL_CTX_use_cert_and_key(ssl_ctx, own_cert, *own_pkey, NULL, 1));
|
||||
CHECK1(SSL_use_cert_and_key(ssl, own_cert, *own_pkey, NULL, 1));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int authmode(Auth auth)
|
||||
{
|
||||
switch (auth)
|
||||
{
|
||||
case auth_none:
|
||||
{
|
||||
// Peer certificate is not checked
|
||||
return SSL_VERIFY_NONE;
|
||||
}
|
||||
|
||||
case auth_required:
|
||||
default:
|
||||
{
|
||||
return SSL_VERIFY_PEER;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2,8 +2,21 @@
|
|||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#ifdef TLS_PROVIDER_IS_MBEDTLS
|
||||
# include "mbedtls/client.h"
|
||||
#else
|
||||
# include "openssl/client.h"
|
||||
#endif
|
||||
#include "context.h"
|
||||
|
||||
namespace tls
|
||||
{
|
||||
class Client : public Context
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<Cert> cert;
|
||||
|
||||
public:
|
||||
Client(std::shared_ptr<Cert> cert_, bool dtls = false) :
|
||||
Context(true, dtls),
|
||||
cert(cert_)
|
||||
{
|
||||
cert->use(ssl, cfg);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2,8 +2,518 @@
|
|||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#ifdef TLS_PROVIDER_IS_MBEDTLS
|
||||
# include "mbedtls/context.h"
|
||||
#else
|
||||
# include "openssl/context.h"
|
||||
#endif
|
||||
#include "cert.h"
|
||||
#include "crypto/base64.h"
|
||||
#include "crypto/entropy.h"
|
||||
#include "ds/logger.h"
|
||||
#include "tls/tls.h"
|
||||
|
||||
#include <memory>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
using namespace crypto;
|
||||
|
||||
namespace tls
|
||||
{
|
||||
class Context
|
||||
{
|
||||
protected:
|
||||
crypto::OpenSSL::Unique_SSL_CTX cfg;
|
||||
crypto::OpenSSL::Unique_SSL ssl;
|
||||
|
||||
public:
|
||||
Context(bool client, bool dtls) :
|
||||
cfg(
|
||||
dtls ? (client ? DTLS_client_method() : DTLS_server_method()) :
|
||||
(client ? TLS_client_method() : TLS_server_method())),
|
||||
ssl(cfg)
|
||||
{
|
||||
// Require at least TLS 1.2, support up to 1.3
|
||||
SSL_CTX_set_min_proto_version(
|
||||
cfg, dtls ? DTLS1_2_VERSION : TLS1_2_VERSION);
|
||||
SSL_set_min_proto_version(ssl, dtls ? DTLS1_2_VERSION : TLS1_2_VERSION);
|
||||
|
||||
// Disable renegotiation to avoid DoS
|
||||
SSL_CTX_set_options(
|
||||
cfg,
|
||||
SSL_OP_CIPHER_SERVER_PREFERENCE |
|
||||
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
|
||||
SSL_OP_NO_RENEGOTIATION);
|
||||
SSL_set_options(
|
||||
ssl,
|
||||
SSL_OP_CIPHER_SERVER_PREFERENCE |
|
||||
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
|
||||
SSL_OP_NO_RENEGOTIATION);
|
||||
|
||||
// Set cipher for TLS 1.2 (TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
|
||||
SSL_CTX_set_cipher_list(
|
||||
cfg,
|
||||
"ECDHE-ECDSA-AES256-GCM-SHA384:"
|
||||
"ECDHE-ECDSA-AES128-GCM-SHA256");
|
||||
SSL_set_cipher_list(
|
||||
ssl,
|
||||
"ECDHE-ECDSA-AES256-GCM-SHA384:"
|
||||
"ECDHE-ECDSA-AES128-GCM-SHA256");
|
||||
|
||||
// Set cipher for TLS 1.3 (same as above)
|
||||
SSL_CTX_set_ciphersuites(
|
||||
cfg,
|
||||
"TLS_AES_256_GCM_SHA384:"
|
||||
"TLS_AES_128_GCM_SHA256");
|
||||
SSL_set_ciphersuites(
|
||||
ssl,
|
||||
"TLS_AES_256_GCM_SHA384:"
|
||||
"TLS_AES_128_GCM_SHA256");
|
||||
|
||||
// Restrict the curves to approved ones
|
||||
SSL_CTX_set1_curves_list(cfg, "P-521:P-384");
|
||||
SSL_set1_curves_list(ssl, "P-521:P-384");
|
||||
|
||||
// Initialise connection
|
||||
if (client)
|
||||
SSL_set_connect_state(ssl);
|
||||
else
|
||||
SSL_set_accept_state(ssl);
|
||||
}
|
||||
|
||||
virtual ~Context() = default;
|
||||
|
||||
void set_bio(
|
||||
void* cb_obj,
|
||||
BIO_callback_fn_ex send,
|
||||
BIO_callback_fn_ex recv,
|
||||
BIO_callback_fn_ex dbg)
|
||||
{
|
||||
// Read/Write BIOs will be used by TLS
|
||||
BIO* rbio = BIO_new(BIO_s_mem());
|
||||
BIO_set_mem_eof_return(rbio, -1);
|
||||
BIO_set_callback_arg(rbio, (char*)cb_obj);
|
||||
BIO_set_callback_ex(rbio, recv);
|
||||
SSL_set0_rbio(ssl, rbio);
|
||||
|
||||
BIO* wbio = BIO_new(BIO_s_mem());
|
||||
BIO_set_mem_eof_return(wbio, -1);
|
||||
BIO_set_callback_arg(wbio, (char*)cb_obj);
|
||||
BIO_set_callback_ex(wbio, send);
|
||||
SSL_set0_wbio(ssl, wbio);
|
||||
}
|
||||
|
||||
int handshake()
|
||||
{
|
||||
if (SSL_is_init_finished(ssl))
|
||||
return 0;
|
||||
|
||||
int rc = SSL_do_handshake(ssl);
|
||||
// Success in OpenSSL is 1, MBed is 0
|
||||
if (rc > 0)
|
||||
{
|
||||
LOG_TRACE_FMT("Context::handshake() : Success");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Want read/write needs special return
|
||||
if (SSL_want_read(ssl))
|
||||
{
|
||||
return TLS_ERR_WANT_READ;
|
||||
}
|
||||
else if (SSL_want_write(ssl))
|
||||
{
|
||||
return TLS_ERR_WANT_WRITE;
|
||||
}
|
||||
|
||||
// So does x509 validation
|
||||
if (verify_result() != 0)
|
||||
{
|
||||
return TLS_ERR_X509_VERIFY;
|
||||
}
|
||||
|
||||
// Everything else falls here.
|
||||
LOG_TRACE_FMT("Context::handshake() : Error code {}", rc);
|
||||
|
||||
// As an MBedTLS emulation, we return negative for errors.
|
||||
return -SSL_get_error(ssl, rc);
|
||||
}
|
||||
|
||||
int read(uint8_t* buf, size_t len)
|
||||
{
|
||||
if (len == 0)
|
||||
return 0;
|
||||
size_t readbytes = 0;
|
||||
int rc = SSL_read_ex(ssl, buf, len, &readbytes);
|
||||
if (rc > 0)
|
||||
{
|
||||
return readbytes;
|
||||
}
|
||||
if (SSL_want_read(ssl))
|
||||
{
|
||||
return TLS_ERR_WANT_READ;
|
||||
}
|
||||
|
||||
// Everything else falls here.
|
||||
LOG_TRACE_FMT("Context::read() : Error code {}", rc);
|
||||
|
||||
// As an MBedTLS emulation, we return negative for errors.
|
||||
return -SSL_get_error(ssl, rc);
|
||||
}
|
||||
|
||||
int write(const uint8_t* buf, size_t len)
|
||||
{
|
||||
if (len == 0)
|
||||
return 0;
|
||||
size_t written = 0;
|
||||
int rc = SSL_write_ex(ssl, buf, len, &written);
|
||||
if (rc > 0)
|
||||
{
|
||||
return written;
|
||||
}
|
||||
if (SSL_want_write(ssl))
|
||||
{
|
||||
return TLS_ERR_WANT_WRITE;
|
||||
}
|
||||
|
||||
// Everything else falls here.
|
||||
LOG_TRACE_FMT("Context::write() : Error code {}", rc);
|
||||
|
||||
// As an MBedTLS emulation, we return negative for errors.
|
||||
return -SSL_get_error(ssl, rc);
|
||||
}
|
||||
|
||||
int close()
|
||||
{
|
||||
LOG_TRACE_FMT("Context::close() : Shutdown");
|
||||
return SSL_shutdown(ssl);
|
||||
}
|
||||
|
||||
// This is a hack to make it work like MBedTLS (with negative return
|
||||
// values as error), and to differentiate in get_verify_error if the error
|
||||
// is because we don't have a peer cert or something else.
|
||||
// We may find that this is unnecessary (alongside all of the error messages
|
||||
// in get_verify_error), but that's a cleanup that will need a bit more
|
||||
// research.
|
||||
#define TLS_ERR_X509_NO_PEER_CERT -1
|
||||
#define TLS_ERR_X509_INVALID_RESULT -2
|
||||
|
||||
int verify_result()
|
||||
{
|
||||
if (SSL_get_verify_result(ssl) == X509_V_OK)
|
||||
{
|
||||
// Verify can return OK when no certificate is presented
|
||||
// We want that to be an error
|
||||
X509* cert = SSL_get_peer_certificate(ssl);
|
||||
if (cert)
|
||||
{
|
||||
X509_free(cert);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return TLS_ERR_X509_NO_PEER_CERT;
|
||||
}
|
||||
}
|
||||
return TLS_ERR_X509_INVALID_RESULT;
|
||||
}
|
||||
|
||||
std::string get_verify_error()
|
||||
{
|
||||
int rc = verify_result();
|
||||
if (rc == TLS_ERR_X509_NO_PEER_CERT)
|
||||
{
|
||||
return "Certificate verify error: No peer certificate";
|
||||
}
|
||||
|
||||
switch (rc)
|
||||
{
|
||||
case X509_V_ERR_UNSPECIFIED:
|
||||
return "Unspecified error; should not happen.";
|
||||
|
||||
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
|
||||
return "The issuer certificate of a looked up certificate could not "
|
||||
"be found. This normally means the list of trusted "
|
||||
"certificates is not complete.";
|
||||
|
||||
case X509_V_ERR_UNABLE_TO_GET_CRL:
|
||||
return "The CRL of a certificate could not be found.";
|
||||
|
||||
case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
|
||||
return "The certificate signature could not be decrypted. This means "
|
||||
"that the actual signature value could not be determined "
|
||||
"rather than it not matching the expected value";
|
||||
|
||||
case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
|
||||
return "The CRL signature could not be decrypted: this means that "
|
||||
"the actual signature value could not be determined rather "
|
||||
"than it not matching the expected value. Unused.";
|
||||
|
||||
case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
|
||||
return "The public key in the certificate SubjectPublicKeyInfo could "
|
||||
"not be read.";
|
||||
|
||||
case X509_V_ERR_CERT_SIGNATURE_FAILURE:
|
||||
return "The signature of the certificate is invalid.";
|
||||
|
||||
case X509_V_ERR_CRL_SIGNATURE_FAILURE:
|
||||
return "The signature of the certificate is invalid.";
|
||||
|
||||
case X509_V_ERR_CERT_NOT_YET_VALID:
|
||||
return "The certificate is not yet valid: the notBefore date is "
|
||||
"after the current time.";
|
||||
|
||||
case X509_V_ERR_CERT_HAS_EXPIRED:
|
||||
return "The certificate has expired: that is the notAfter date is "
|
||||
"before the current time.";
|
||||
|
||||
case X509_V_ERR_CRL_NOT_YET_VALID:
|
||||
return "The CRL is not yet valid.";
|
||||
|
||||
case X509_V_ERR_CRL_HAS_EXPIRED:
|
||||
return "The CRL has expired.";
|
||||
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
|
||||
return "The certificate notBefore field contains an invalid time.";
|
||||
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
|
||||
return "The certificate notAfter field contains an invalid time.";
|
||||
|
||||
case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
|
||||
return "The CRL lastUpdate field contains an invalid time.";
|
||||
|
||||
case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
|
||||
return "The CRL nextUpdate field contains an invalid time.";
|
||||
|
||||
case X509_V_ERR_OUT_OF_MEM:
|
||||
return "An error occurred trying to allocate memory. This should "
|
||||
"never happen.";
|
||||
|
||||
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
|
||||
return "The passed certificate is self-signed and the same "
|
||||
"certificate cannot be found in the list of trusted "
|
||||
"certificates.";
|
||||
|
||||
case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
|
||||
return "The certificate chain could be built up using the untrusted "
|
||||
"certificates but the root could not be found locally.";
|
||||
|
||||
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
|
||||
return "The issuer certificate could not be found: this occurs if "
|
||||
"the issuer certificate of an untrusted certificate cannot be "
|
||||
"found.";
|
||||
|
||||
case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
|
||||
return "No signatures could be verified because the chain contains "
|
||||
"only one certificate and it is not self signed.";
|
||||
|
||||
case X509_V_ERR_CERT_CHAIN_TOO_LONG:
|
||||
return "The certificate chain length is greater than the supplied "
|
||||
"maximum depth. Unused.";
|
||||
|
||||
case X509_V_ERR_CERT_REVOKED:
|
||||
return "The certificate has been revoked.";
|
||||
|
||||
case X509_V_ERR_INVALID_CA:
|
||||
return "A CA certificate is invalid. Either it is not a CA or its "
|
||||
"extensions are not consistent with the supplied purpose.";
|
||||
|
||||
case X509_V_ERR_PATH_LENGTH_EXCEEDED:
|
||||
return "The basicConstraints pathlength parameter has been exceeded.";
|
||||
|
||||
case X509_V_ERR_INVALID_PURPOSE:
|
||||
return "The supplied certificate cannot be used for the specified "
|
||||
"purpose.";
|
||||
|
||||
case X509_V_ERR_CERT_UNTRUSTED:
|
||||
return "The root CA is not marked as trusted for the specified "
|
||||
"purpose.";
|
||||
|
||||
case X509_V_ERR_CERT_REJECTED:
|
||||
return "The root CA is marked to reject the specified purpose.";
|
||||
|
||||
case X509_V_ERR_SUBJECT_ISSUER_MISMATCH:
|
||||
return "Not used as of OpenSSL 1.1.0 as a result of the deprecation "
|
||||
"of the -issuer_checks option.";
|
||||
|
||||
case X509_V_ERR_AKID_SKID_MISMATCH:
|
||||
return "Not used as of OpenSSL 1.1.0 as a result of the deprecation "
|
||||
"of the -issuer_checks option.";
|
||||
|
||||
case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH:
|
||||
return "Not used as of OpenSSL 1.1.0 as a result of the deprecation "
|
||||
"of the -issuer_checks option.";
|
||||
|
||||
case X509_V_ERR_KEYUSAGE_NO_CERTSIGN:
|
||||
return "Not used as of OpenSSL 1.1.0 as a result of the deprecation "
|
||||
"of the -issuer_checks option.";
|
||||
|
||||
case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
|
||||
return "Unable to get CRL issuer certificate.";
|
||||
|
||||
case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION:
|
||||
return "Unhandled critical extension.";
|
||||
|
||||
case X509_V_ERR_KEYUSAGE_NO_CRL_SIGN:
|
||||
return "Key usage does not include CRL signing.";
|
||||
|
||||
case X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION:
|
||||
return "Unhandled critical CRL extension.";
|
||||
|
||||
case X509_V_ERR_INVALID_NON_CA:
|
||||
return "Invalid non-CA certificate has CA markings.";
|
||||
|
||||
case X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED:
|
||||
return "Proxy path length constraint exceeded.";
|
||||
|
||||
case X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE:
|
||||
return "Key usage does not include digital signature.";
|
||||
|
||||
case X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED:
|
||||
return "Proxy certificates not allowed";
|
||||
|
||||
case X509_V_ERR_INVALID_EXTENSION:
|
||||
return "Invalid or inconsistent certificate extension.";
|
||||
|
||||
case X509_V_ERR_INVALID_POLICY_EXTENSION:
|
||||
return "Invalid or inconsistent certificate policy extension.";
|
||||
|
||||
case X509_V_ERR_NO_EXPLICIT_POLICY:
|
||||
return "No explicit policy.";
|
||||
|
||||
case X509_V_ERR_DIFFERENT_CRL_SCOPE:
|
||||
return "Different CRL scope.";
|
||||
|
||||
case X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE:
|
||||
return "Unsupported extension feature.";
|
||||
|
||||
case X509_V_ERR_UNNESTED_RESOURCE:
|
||||
return "RFC 3779 resource not subset of parent's resources.";
|
||||
|
||||
case X509_V_ERR_PERMITTED_VIOLATION:
|
||||
return "Permitted subtree violation.";
|
||||
|
||||
case X509_V_ERR_EXCLUDED_VIOLATION:
|
||||
return "Excluded subtree violation.";
|
||||
|
||||
case X509_V_ERR_SUBTREE_MINMAX:
|
||||
return "Name constraints minimum and maximum not supported.";
|
||||
|
||||
case X509_V_ERR_APPLICATION_VERIFICATION:
|
||||
return "Application verification failure. Unused.";
|
||||
|
||||
case X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE:
|
||||
return "Unsupported name constraint type.";
|
||||
|
||||
case X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX:
|
||||
return "Unsupported or invalid name constraint syntax.";
|
||||
|
||||
case X509_V_ERR_UNSUPPORTED_NAME_SYNTAX:
|
||||
return "Unsupported or invalid name syntax.";
|
||||
|
||||
case X509_V_ERR_CRL_PATH_VALIDATION_ERROR:
|
||||
return "CRL path validation error.";
|
||||
|
||||
case X509_V_ERR_PATH_LOOP:
|
||||
return "Path loop.";
|
||||
|
||||
case X509_V_ERR_SUITE_B_INVALID_VERSION:
|
||||
return "Suite B: certificate version invalid.";
|
||||
|
||||
case X509_V_ERR_SUITE_B_INVALID_ALGORITHM:
|
||||
return "Suite B: invalid public key algorithm.";
|
||||
|
||||
case X509_V_ERR_SUITE_B_INVALID_CURVE:
|
||||
return "Suite B: invalid ECC curve.";
|
||||
|
||||
case X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM:
|
||||
return "Suite B: invalid signature algorithm.";
|
||||
|
||||
case X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED:
|
||||
return "Suite B: curve not allowed for this LOS.";
|
||||
|
||||
case X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256:
|
||||
return "Suite B: cannot sign P-384 with P-256.";
|
||||
|
||||
case X509_V_ERR_HOSTNAME_MISMATCH:
|
||||
return "Hostname mismatch.";
|
||||
|
||||
case X509_V_ERR_EMAIL_MISMATCH:
|
||||
return "Email address mismatch.";
|
||||
|
||||
case X509_V_ERR_IP_ADDRESS_MISMATCH:
|
||||
return "IP address mismatch.";
|
||||
|
||||
case X509_V_ERR_DANE_NO_MATCH:
|
||||
return "DANE TLSA authentication is enabled";
|
||||
|
||||
case X509_V_ERR_EE_KEY_TOO_SMALL:
|
||||
return "EE certificate key too weak.";
|
||||
|
||||
case X509_V_ERR_INVALID_CALL:
|
||||
return "nvalid certificate verification context.";
|
||||
|
||||
case X509_V_ERR_STORE_LOOKUP:
|
||||
return "Issuer certificate lookup error.";
|
||||
|
||||
case X509_V_ERR_NO_VALID_SCTS:
|
||||
return "Certificate Transparency required";
|
||||
|
||||
case X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION:
|
||||
return "Proxy subject name violation.";
|
||||
|
||||
case X509_V_ERR_OCSP_VERIFY_NEEDED:
|
||||
return "Returned by the verify callback to indicate an OCSP "
|
||||
"verification is needed.";
|
||||
|
||||
case X509_V_ERR_OCSP_VERIFY_FAILED:
|
||||
return "Returned by the verify callback to indicate OCSP "
|
||||
"verification failed.";
|
||||
|
||||
case X509_V_ERR_OCSP_CERT_UNKNOWN:
|
||||
return "Returned by the verify callback to indicate that the "
|
||||
"certificate is not recognized by the OCSP responder.";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
virtual std::string host()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> peer_cert()
|
||||
{
|
||||
// Get the certificate into a BIO as DER
|
||||
crypto::OpenSSL::Unique_X509 cert(
|
||||
SSL_get_peer_certificate(ssl), /*check_null=*/false);
|
||||
if (!cert)
|
||||
{
|
||||
LOG_TRACE_FMT("Empty peer cert");
|
||||
return {};
|
||||
}
|
||||
crypto::OpenSSL::Unique_BIO bio;
|
||||
if (!i2d_X509_bio(bio, cert))
|
||||
{
|
||||
LOG_TRACE_FMT("Can't convert X509 to DER");
|
||||
return {};
|
||||
}
|
||||
|
||||
// Get the total length of the DER representation
|
||||
auto len = BIO_get_mem_data(bio, nullptr);
|
||||
if (!len)
|
||||
{
|
||||
LOG_TRACE_FMT("Null X509 peer cert");
|
||||
return {};
|
||||
}
|
||||
|
||||
// Get the BIO memory pointer
|
||||
BUF_MEM* ptr = nullptr;
|
||||
if (!BIO_get_mem_ptr(bio, &ptr))
|
||||
{
|
||||
LOG_TRACE_FMT("Invalid X509 peer cert");
|
||||
return {};
|
||||
}
|
||||
|
||||
// Return its contents as a vector
|
||||
auto ret = std::vector<uint8_t>(ptr->data, ptr->data + len);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "crypto/mbedtls/error_string.h"
|
||||
#include "crypto/mbedtls/mbedtls_wrappers.h"
|
||||
#include "crypto/pem.h"
|
||||
#include "ds/buffer.h"
|
||||
|
||||
#include <exception>
|
||||
|
||||
namespace tls
|
||||
{
|
||||
class CA
|
||||
{
|
||||
private:
|
||||
crypto::mbedtls::X509Crt ca = nullptr;
|
||||
crypto::mbedtls::X509Crl crl = nullptr;
|
||||
|
||||
public:
|
||||
CA(CBuffer ca_ = nullb, CBuffer crl_ = nullb)
|
||||
{
|
||||
auto tmp_ca = crypto::mbedtls::make_unique<crypto::mbedtls::X509Crt>();
|
||||
auto tmp_crl = crypto::mbedtls::make_unique<crypto::mbedtls::X509Crl>();
|
||||
|
||||
if (ca_.n > 0)
|
||||
{
|
||||
crypto::Pem pem_ca(ca_);
|
||||
auto ret =
|
||||
mbedtls_x509_crt_parse(tmp_ca.get(), pem_ca.data(), pem_ca.size());
|
||||
if (ret != 0)
|
||||
throw std::logic_error(
|
||||
"Could not parse CA: " + crypto::error_string(ret));
|
||||
}
|
||||
|
||||
if (crl_.n > 0)
|
||||
{
|
||||
crypto::Pem pem_crl(crl_);
|
||||
auto ret =
|
||||
mbedtls_x509_crl_parse(tmp_crl.get(), pem_crl.data(), pem_crl.size());
|
||||
if (ret != 0)
|
||||
throw std::logic_error(
|
||||
"Could not parse CRL: " + crypto::error_string(ret));
|
||||
}
|
||||
|
||||
ca = std::move(tmp_ca);
|
||||
crl = std::move(tmp_crl);
|
||||
}
|
||||
|
||||
~CA() {}
|
||||
|
||||
void use(mbedtls_ssl_config* cfg)
|
||||
{
|
||||
mbedtls_ssl_conf_ca_chain(cfg, ca.get(), crl.get());
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,160 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "ca.h"
|
||||
#include "crypto/mbedtls/error_string.h"
|
||||
#include "crypto/mbedtls/mbedtls_wrappers.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
using namespace crypto;
|
||||
|
||||
namespace tls
|
||||
{
|
||||
enum Auth
|
||||
{
|
||||
auth_default,
|
||||
auth_none,
|
||||
auth_optional,
|
||||
auth_required
|
||||
};
|
||||
|
||||
// This class represents the authentication/authorization context for a TLS
|
||||
// session. At least, it contains the peer's CA. At most, it also contains our
|
||||
// own private key/certificate which will be presented in the TLS handshake.
|
||||
// The peer's certificate verification can be overridden with the auth
|
||||
// parameter.
|
||||
class Cert
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<CA> peer_ca;
|
||||
std::optional<std::string> peer_hostname;
|
||||
|
||||
mbedtls::X509Crt own_cert = nullptr;
|
||||
mbedtls::PKContext own_pkey = nullptr;
|
||||
bool has_own_cert;
|
||||
|
||||
// DEBUG ONLY
|
||||
std::string cert_str;
|
||||
|
||||
Auth auth;
|
||||
|
||||
public:
|
||||
Cert(
|
||||
std::shared_ptr<CA> peer_ca_,
|
||||
const std::optional<crypto::Pem>& own_cert_ = std::nullopt,
|
||||
const std::optional<crypto::Pem>& own_pkey_ = std::nullopt,
|
||||
CBuffer pw = nullb,
|
||||
Auth auth_ = auth_default,
|
||||
const std::optional<std::string>& peer_hostname_ = std::nullopt) :
|
||||
peer_ca(peer_ca_),
|
||||
peer_hostname(peer_hostname_),
|
||||
has_own_cert(false),
|
||||
auth(auth_)
|
||||
{
|
||||
auto tmp_cert = mbedtls::make_unique<mbedtls::X509Crt>();
|
||||
auto tmp_pkey = mbedtls::make_unique<mbedtls::PKContext>();
|
||||
|
||||
if (own_cert_.has_value() && own_pkey_.has_value())
|
||||
{
|
||||
cert_str =
|
||||
std::string((const char*)own_cert_->data(), own_cert_->size());
|
||||
int rc = mbedtls_x509_crt_parse(
|
||||
tmp_cert.get(), own_cert_->data(), own_cert_->size());
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(
|
||||
"Could not parse certificate: " + error_string(rc));
|
||||
}
|
||||
|
||||
rc = mbedtls_pk_parse_key(
|
||||
tmp_pkey.get(), own_pkey_->data(), own_pkey_->size(), pw.p, pw.n);
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error("Could not parse key: " + error_string(rc));
|
||||
}
|
||||
|
||||
has_own_cert = true;
|
||||
}
|
||||
|
||||
own_cert = std::move(tmp_cert);
|
||||
own_pkey = std::move(tmp_pkey);
|
||||
}
|
||||
|
||||
~Cert() {}
|
||||
|
||||
void use(mbedtls_ssl_context* ssl, mbedtls_ssl_config* cfg)
|
||||
{
|
||||
if (peer_hostname.has_value())
|
||||
{
|
||||
// Peer hostname is only checked against peer certificate (SAN
|
||||
// extension) if it is set. This lets us connect to peers that present
|
||||
// certificates with IPAddress in SAN field (mbedtls does not parse
|
||||
// IPAddress in SAN field). This is OK since we check for peer CA
|
||||
// endorsement.
|
||||
mbedtls_ssl_set_hostname(ssl, peer_hostname->c_str());
|
||||
}
|
||||
|
||||
if (peer_ca)
|
||||
{
|
||||
peer_ca->use(cfg);
|
||||
}
|
||||
|
||||
if (auth != auth_default)
|
||||
{
|
||||
mbedtls_ssl_conf_authmode(cfg, authmode(auth));
|
||||
}
|
||||
|
||||
if (has_own_cert)
|
||||
{
|
||||
mbedtls_ssl_conf_own_cert(cfg, own_cert.get(), own_pkey.get());
|
||||
}
|
||||
}
|
||||
|
||||
const mbedtls_x509_crt* raw()
|
||||
{
|
||||
return own_cert.get();
|
||||
}
|
||||
|
||||
const std::string str() const
|
||||
{
|
||||
return cert_str;
|
||||
}
|
||||
|
||||
private:
|
||||
int authmode(Auth auth)
|
||||
{
|
||||
switch (auth)
|
||||
{
|
||||
case auth_none:
|
||||
{
|
||||
// Peer certificate is not checked
|
||||
return MBEDTLS_SSL_VERIFY_NONE;
|
||||
}
|
||||
|
||||
case auth_optional:
|
||||
{
|
||||
// Peer certificate is checked but handshake continues even if
|
||||
// verification fails
|
||||
return MBEDTLS_SSL_VERIFY_OPTIONAL;
|
||||
}
|
||||
|
||||
case auth_required:
|
||||
{
|
||||
// Peer must present a valid certificate
|
||||
return MBEDTLS_SSL_VERIFY_REQUIRED;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return MBEDTLS_SSL_VERIFY_REQUIRED;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "context.h"
|
||||
|
||||
namespace tls
|
||||
{
|
||||
class Client : public Context
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<Cert> cert;
|
||||
|
||||
public:
|
||||
Client(std::shared_ptr<Cert> cert_, bool dtls = false) :
|
||||
Context(true, dtls),
|
||||
cert(cert_)
|
||||
{
|
||||
cert->use(ssl.get(), cfg.get());
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,129 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "cert.h"
|
||||
#include "crypto/entropy.h"
|
||||
#include "crypto/mbedtls/error_string.h"
|
||||
#include "crypto/mbedtls/mbedtls_wrappers.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
using namespace crypto;
|
||||
|
||||
namespace tls
|
||||
{
|
||||
class Context
|
||||
{
|
||||
protected:
|
||||
mbedtls::SSLContext ssl = nullptr;
|
||||
mbedtls::SSLConfig cfg = nullptr;
|
||||
crypto::EntropyPtr entropy;
|
||||
|
||||
#ifndef NO_STRICT_TLS_CIPHERSUITES
|
||||
const int ciphersuites[2] = {
|
||||
MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0};
|
||||
#endif
|
||||
|
||||
public:
|
||||
Context(bool client, bool dgram) : entropy(crypto::create_entropy())
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
auto tmp_ssl = mbedtls::make_unique<mbedtls::SSLContext>();
|
||||
auto tmp_cfg = mbedtls::make_unique<mbedtls::SSLConfig>();
|
||||
|
||||
mbedtls_ssl_conf_rng(
|
||||
tmp_cfg.get(), entropy->get_rng(), entropy->get_data());
|
||||
|
||||
rc = mbedtls_ssl_config_defaults(
|
||||
tmp_cfg.get(),
|
||||
client ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER,
|
||||
dgram ? MBEDTLS_SSL_TRANSPORT_DATAGRAM : MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||
MBEDTLS_SSL_PRESET_DEFAULT);
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(fmt::format(
|
||||
"mbedtls_ssl_config_defaults failed: {}", error_string(rc)));
|
||||
}
|
||||
#ifndef NO_STRICT_TLS_CIPHERSUITES
|
||||
if (!client)
|
||||
mbedtls_ssl_conf_ciphersuites(tmp_cfg.get(), ciphersuites);
|
||||
#endif
|
||||
|
||||
// Require TLS 1.2
|
||||
mbedtls_ssl_conf_min_version(
|
||||
tmp_cfg.get(),
|
||||
MBEDTLS_SSL_MAJOR_VERSION_3,
|
||||
MBEDTLS_SSL_MINOR_VERSION_3);
|
||||
|
||||
rc = mbedtls_ssl_setup(tmp_ssl.get(), tmp_cfg.get());
|
||||
if (rc != 0)
|
||||
{
|
||||
throw std::logic_error(
|
||||
fmt::format("mbedtls_ssl_setup failed: {}", error_string(rc)));
|
||||
}
|
||||
|
||||
ssl = std::move(tmp_ssl);
|
||||
cfg = std::move(tmp_cfg);
|
||||
}
|
||||
|
||||
virtual ~Context() {}
|
||||
|
||||
void set_bio(
|
||||
void* enclave,
|
||||
mbedtls_ssl_send_t send,
|
||||
mbedtls_ssl_recv_t recv,
|
||||
void (*dbg)(void*, int, const char*, int, const char*))
|
||||
{
|
||||
mbedtls_ssl_conf_dbg(cfg.get(), dbg, enclave);
|
||||
mbedtls_ssl_set_bio(ssl.get(), enclave, send, recv, nullptr);
|
||||
}
|
||||
|
||||
int handshake()
|
||||
{
|
||||
return mbedtls_ssl_handshake(ssl.get());
|
||||
}
|
||||
|
||||
int read(uint8_t* buf, size_t len)
|
||||
{
|
||||
return mbedtls_ssl_read(ssl.get(), buf, len);
|
||||
}
|
||||
|
||||
int write(const uint8_t* buf, size_t len)
|
||||
{
|
||||
return mbedtls_ssl_write(ssl.get(), buf, len);
|
||||
}
|
||||
|
||||
int close()
|
||||
{
|
||||
return mbedtls_ssl_close_notify(ssl.get());
|
||||
}
|
||||
|
||||
int verify_result()
|
||||
{
|
||||
return mbedtls_ssl_get_verify_result(ssl.get());
|
||||
}
|
||||
|
||||
std::string get_verify_error()
|
||||
{
|
||||
std::vector<char> buf(512);
|
||||
mbedtls_x509_crt_verify_info(
|
||||
buf.data(), buf.size(), "Certificate verify failed: ", verify_result());
|
||||
return std::string(buf.data(), buf.size());
|
||||
}
|
||||
|
||||
virtual std::string host()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> peer_cert()
|
||||
{
|
||||
auto cert = mbedtls_ssl_get_peer_cert(ssl.get());
|
||||
if (cert == nullptr)
|
||||
return {};
|
||||
return std::vector<uint8_t>(cert->raw.p, cert->raw.p + cert->raw.len);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "context.h"
|
||||
|
||||
namespace tls
|
||||
{
|
||||
class Server : public Context
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<Cert> cert;
|
||||
|
||||
public:
|
||||
Server(std::shared_ptr<Cert> cert_, bool dtls = false) :
|
||||
Context(false, dtls),
|
||||
cert(cert_)
|
||||
{
|
||||
cert->use(ssl.get(), cfg.get());
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include <mbedtls/ctr_drbg.h>
|
||||
#include <mbedtls/debug.h>
|
||||
#include <mbedtls/entropy.h>
|
||||
#include <mbedtls/entropy_poll.h>
|
||||
#include <mbedtls/error.h>
|
||||
#include <mbedtls/net_sockets.h>
|
||||
#include <mbedtls/oid.h>
|
||||
#include <mbedtls/rsa.h>
|
||||
#include <mbedtls/sha256.h>
|
||||
#include <mbedtls/ssl.h>
|
||||
#include <mbedtls/x509.h>
|
||||
#include <mbedtls/x509_crt.h>
|
||||
#include <mbedtls/x509_csr.h>
|
||||
|
||||
// Macros provided to interface MbedTLS and OpenSSL on the same implementation.
|
||||
#ifdef TLS_PROVIDER_IS_MBEDTLS
|
||||
// These macros setup return values for when the connection is reading/writing
|
||||
// and needs more data. In MbedTLS, the return value is straight WANT_READ and
|
||||
// WANT_WRITE, which are negative and the API knows how to handle it.
|
||||
# define TLS_READING MBEDTLS_ERR_SSL_WANT_READ
|
||||
# define TLS_WRITING MBEDTLS_ERR_SSL_WANT_WRITE
|
||||
// These macros are errors from read/write, including during handshake.
|
||||
// Depending on the error, the connection needs to close with success, failure
|
||||
// or auth-failure.
|
||||
# define TLS_ERR_WANT_READ MBEDTLS_ERR_SSL_WANT_READ
|
||||
# define TLS_ERR_WANT_WRITE MBEDTLS_ERR_SSL_WANT_WRITE
|
||||
# define TLS_ERR_CONN_RESET MBEDTLS_ERR_NET_CONN_RESET
|
||||
# define TLS_ERR_CONN_CLOSE_NOTIFY MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY
|
||||
# define TLS_ERR_NEED_CERT MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE
|
||||
# define TLS_ERR_PEER_VERIFY MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED
|
||||
# define TLS_ERR_X509_VERIFY MBEDTLS_ERR_X509_CERT_VERIFY_FAILED
|
||||
|
||||
namespace tls
|
||||
{
|
||||
/// Returns the error string from an error code
|
||||
/// this is a copy of crypto's to all control via TLS_PROVIDER_IS_MBEDTLS
|
||||
inline std::string error_string(int err)
|
||||
{
|
||||
constexpr size_t len = 256;
|
||||
char buf[len];
|
||||
mbedtls_strerror(err, buf, len);
|
||||
|
||||
if (strlen(buf) == 0)
|
||||
{
|
||||
return std::to_string(err);
|
||||
}
|
||||
|
||||
return std::string(buf);
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,70 +0,0 @@
|
|||
# OpenSSL TLS Implementation
|
||||
|
||||
This is a TLS implementation using OpenSSL that mimics the existing MbedTLS
|
||||
one in a similar fashion. Because of that, some structures and call backs
|
||||
look odd and have some work-arounds to make it fit the current workflow.
|
||||
|
||||
Once we completely deprecate the MbedTLS implementation from CCF, we should
|
||||
re-write the TLS implementation to fit the OpenSSL coding flow, which would
|
||||
make it much simpler and easier to use.
|
||||
|
||||
## CAs and Certificates
|
||||
|
||||
In the MbedTLS world, certificates can be null and have methods to change
|
||||
some configurations in the TLS config/session objects. There isn't a lot of
|
||||
cross-over, so updating the config does the trick.
|
||||
|
||||
However, in OpenSSL, session objects (ssl) are created from config objects
|
||||
(cfg) and inherit all its properties. Therefore, to emulate MbedTLS, we need
|
||||
to do to the session object every action we do to the config object, which is
|
||||
not only redundant, but could be unsafe, if the calls are slightly different.
|
||||
|
||||
### Validation
|
||||
|
||||
Certificate validation can be complex to handle if you can accept connections
|
||||
with certificates or not, and if they come, when and how to validate.
|
||||
|
||||
MbedTLS is a lot more lenient on checks. For example, CAs are not tested for
|
||||
validity of actually signing other certificates, while OpenSSL has extensive
|
||||
checks, which can fail functionality that was previously passing.
|
||||
|
||||
For this reason, a number of extra checks in the OpenSSL side were disabled.
|
||||
Once we get rid of MbedTLS we should revisit those checks again and improve
|
||||
CCF's usage of TLS, and perhaps also creating weaker checks for non-CA
|
||||
certificates, etc.
|
||||
|
||||
## Context
|
||||
|
||||
### BIOs
|
||||
|
||||
MbedTLS operates reads and writes solely via callbacks, with a buffer in the
|
||||
session object acting as async I/O. This is in stark contrast with OpenSSL
|
||||
which uses BIO objects to pass information back and forth, and only have
|
||||
callbacks for debug or very specialized cases.
|
||||
|
||||
We had to implement callbacks and specialize our case, but it could really be
|
||||
just done with BIOs between the ring buffer and the context, but we'd have to
|
||||
change a lot of code outside of the TLS implementation to add that.
|
||||
|
||||
### Reads and Writes
|
||||
|
||||
Reading and writing in MbedTLS returns a positive value for success (number of
|
||||
bytes written) or a negative value for error (pre-defined error codes) including
|
||||
WANTS_READ and WANTS_WRITE.
|
||||
|
||||
In OpenSSL, those methods return 1 for success and 0 or -1 for errors (depending
|
||||
on the version), with all errors, including WANTS_READ and WANTS_WRITE
|
||||
accessible through `SSL_get_error`. This imposes a number of hacks needed to
|
||||
mimic the MbedTLS implementation, including:
|
||||
|
||||
- Multiple `#define`s with common error messages in `tls.h`
|
||||
- Having to negate the error code to match
|
||||
- Multiple checks to `SSL_want_read` and `SSL_want_write`
|
||||
|
||||
### Error Handling
|
||||
|
||||
As discussed above, the error handling is slightly different and promotes
|
||||
verbose code in OpenSSL's side.
|
||||
|
||||
Another example is `verify_result` and `get_verify_error` that is very long
|
||||
in the OpenSSL implementation and two one-liners in MbedTLS.
|
|
@ -1,74 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "crypto/openssl/openssl_wrappers.h"
|
||||
#include "crypto/pem.h"
|
||||
#include "ds/buffer.h"
|
||||
#include "ds/logger.h"
|
||||
|
||||
#include <exception>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509v3.h>
|
||||
|
||||
namespace tls
|
||||
{
|
||||
class CA
|
||||
{
|
||||
private:
|
||||
mutable crypto::OpenSSL::Unique_X509 ca;
|
||||
mutable crypto::OpenSSL::Unique_X509_CRL crl;
|
||||
|
||||
public:
|
||||
CA(CBuffer ca_ = nullb, CBuffer crl_ = nullb)
|
||||
{
|
||||
crypto::OpenSSL::Unique_X509 tmp_ca;
|
||||
crypto::OpenSSL::Unique_X509_CRL tmp_crl;
|
||||
|
||||
if (ca_.n > 0)
|
||||
{
|
||||
crypto::Pem pem_ca(ca_);
|
||||
LOG_TRACE_FMT("CA::ctor: PEM: {}", pem_ca.str());
|
||||
BIO* certBio = BIO_new(BIO_s_mem());
|
||||
BIO_write(certBio, pem_ca.data(), pem_ca.size());
|
||||
X509* res = PEM_read_bio_X509(certBio, NULL, NULL, NULL);
|
||||
BIO_free(certBio);
|
||||
if (!res)
|
||||
{
|
||||
auto err_str = crypto::OpenSSL::error_string(ERR_get_error());
|
||||
LOG_FAIL_FMT("CA::ctor: Could not parse CA: {}", err_str);
|
||||
throw std::logic_error("Could not parse CA: " + err_str);
|
||||
}
|
||||
// The PEM_read function above checks the validity of the certificate,
|
||||
// but not if it's a CA or cn be used as such. This is what MbedTLS
|
||||
// checks, so we keep it simple here. Some code uses this as a
|
||||
// "certificate check" not necessarily a CA check, so we need to keep it
|
||||
// compatible.
|
||||
// To cater to that usage, we should create a generic helper in crypto
|
||||
// to do the certificate check and add X509_check_ca() here to be more
|
||||
// robust on our verification.
|
||||
tmp_ca.reset(res);
|
||||
}
|
||||
|
||||
if (crl_.n > 0)
|
||||
{
|
||||
// We don't seem to be using CRL anywhere in CCF, so we should
|
||||
// really remove this option once MbedTLS is gone.
|
||||
LOG_FAIL_FMT("CA::ctor: Using CRL in OpenSSL CA");
|
||||
throw std::logic_error("Using CRL in OpenSSL CA");
|
||||
}
|
||||
|
||||
ca = std::move(tmp_ca);
|
||||
crl = std::move(tmp_crl);
|
||||
}
|
||||
|
||||
~CA() {}
|
||||
|
||||
void use(SSL* ssl, SSL_CTX* cfg)
|
||||
{
|
||||
SSL_CTX_use_certificate(cfg, ca);
|
||||
SSL_use_certificate(ssl, ca);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,178 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "ca.h"
|
||||
#include "ds/logger.h"
|
||||
#include "tls/openssl/tls.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <openssl/ssl.h>
|
||||
#include <optional>
|
||||
|
||||
using namespace crypto;
|
||||
|
||||
namespace tls
|
||||
{
|
||||
enum Auth
|
||||
{
|
||||
auth_default,
|
||||
auth_none,
|
||||
auth_optional,
|
||||
auth_required
|
||||
};
|
||||
|
||||
// This class represents the authentication/authorization context for a TLS
|
||||
// session. At least, it contains the peer's CA. At most, it also contains our
|
||||
// own private key/certificate which will be presented in the TLS handshake.
|
||||
// The peer's certificate verification can be overridden with the auth
|
||||
// parameter.
|
||||
class Cert
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<CA> peer_ca;
|
||||
std::optional<std::string> peer_hostname;
|
||||
|
||||
crypto::OpenSSL::Unique_X509 own_cert;
|
||||
crypto::OpenSSL::Unique_PKEY own_pkey;
|
||||
bool has_own_cert;
|
||||
|
||||
Auth auth;
|
||||
|
||||
public:
|
||||
Cert(
|
||||
std::shared_ptr<CA> peer_ca_,
|
||||
const std::optional<crypto::Pem>& own_cert_ = std::nullopt,
|
||||
const std::optional<crypto::Pem>& own_pkey_ = std::nullopt,
|
||||
CBuffer pw = nullb,
|
||||
Auth auth_ = auth_default,
|
||||
const std::optional<std::string>& peer_hostname_ = std::nullopt) :
|
||||
peer_ca(peer_ca_),
|
||||
peer_hostname(peer_hostname_),
|
||||
has_own_cert(false),
|
||||
auth(auth_)
|
||||
{
|
||||
crypto::OpenSSL::Unique_X509 tmp_cert;
|
||||
crypto::OpenSSL::Unique_PKEY tmp_pkey;
|
||||
|
||||
if (own_cert_.has_value() && own_pkey_.has_value())
|
||||
{
|
||||
BIO* certBio = BIO_new(BIO_s_mem());
|
||||
BIO_write(certBio, own_cert_->data(), own_cert_->size());
|
||||
X509* cert = PEM_read_bio_X509(certBio, NULL, NULL, NULL);
|
||||
BIO_free(certBio);
|
||||
if (!cert)
|
||||
{
|
||||
auto err_str = tls::error_string(ERR_get_error());
|
||||
LOG_FAIL_FMT("Cert::ctor: Could not parse certificate: {}", err_str);
|
||||
throw std::logic_error("Could not parse certificate: " + err_str);
|
||||
}
|
||||
tmp_cert.reset(cert);
|
||||
|
||||
BIO* pkBio = BIO_new(BIO_s_mem());
|
||||
BIO_write(pkBio, own_pkey_->data(), own_pkey_->size());
|
||||
EVP_PKEY* pk = PEM_read_bio_PrivateKey(pkBio, NULL, NULL, NULL);
|
||||
BIO_free(pkBio);
|
||||
if (!pk)
|
||||
{
|
||||
auto err_str = tls::error_string(ERR_get_error());
|
||||
LOG_FAIL_FMT("Cert::ctor: Could not parse key: {}", err_str);
|
||||
throw std::logic_error("Could not parse key: " + err_str);
|
||||
}
|
||||
tmp_pkey.reset(pk);
|
||||
|
||||
has_own_cert = true;
|
||||
}
|
||||
|
||||
own_cert = std::move(tmp_cert);
|
||||
own_pkey = std::move(tmp_pkey);
|
||||
|
||||
if (pw.n)
|
||||
{
|
||||
// We don't seem to be using PW anywhere in CCF, so we should
|
||||
// really remove this option once MbedTLS is gone.
|
||||
LOG_FAIL_FMT("Cert::ctor: Unused password");
|
||||
throw std::logic_error(
|
||||
"Unused password: " + std::string((const char*)pw.p));
|
||||
}
|
||||
}
|
||||
|
||||
~Cert() {}
|
||||
|
||||
void use(SSL* ssl, SSL_CTX* cfg)
|
||||
{
|
||||
if (peer_hostname.has_value())
|
||||
{
|
||||
LOG_TRACE_FMT(
|
||||
"Cert::use() : Hostname has value '{}'", peer_hostname->c_str());
|
||||
// Peer hostname is only checked against peer certificate (SAN
|
||||
// extension) if it is set. This lets us connect to peers that present
|
||||
// certificates with IPAddress in SAN field (mbedtls does not parse
|
||||
// IPAddress in SAN field). This is OK since we check for peer CA
|
||||
// endorsement.
|
||||
SSL_set1_host(ssl, peer_hostname->c_str());
|
||||
}
|
||||
|
||||
if (peer_ca)
|
||||
{
|
||||
LOG_TRACE_FMT("Cert::use() : Peer CA use cfg");
|
||||
peer_ca->use(ssl, cfg);
|
||||
}
|
||||
|
||||
// Calling set_verify with SSL_VERIFY_PEER forces the handshake to request
|
||||
// a peer certificate. The server always sends it to the client but not
|
||||
// the other way around. Some code relies on the server doing that, so we
|
||||
// set this here.
|
||||
// We return 1 from the validation callback (a common patter in OpenSSL
|
||||
// implementations) because we don't want to verify it here, just request
|
||||
// it.
|
||||
SSL_CTX_set_verify(
|
||||
cfg, SSL_VERIFY_PEER, [](int precheck, x509_store_ctx_st* st) {
|
||||
(void)precheck;
|
||||
(void)st;
|
||||
return 1;
|
||||
});
|
||||
SSL_set_verify(
|
||||
ssl, SSL_VERIFY_PEER, [](int precheck, x509_store_ctx_st* st) {
|
||||
(void)precheck;
|
||||
(void)st;
|
||||
return 1;
|
||||
});
|
||||
// The MBedTLS implementation adds some verification, but any
|
||||
// further flags in OpenSSL's set_verify fail when MBedTLS doesn't.
|
||||
// We still need to request the peer cert every time, even if it's empty,
|
||||
// but it would be good to have some more strict checks on the actual
|
||||
// certificate at this level without leaving it for later.
|
||||
// This would probably be done after we remove MbedTLS and refactor
|
||||
// OpenSSL TLS to match OpenSSL's behaviour.
|
||||
|
||||
if (has_own_cert)
|
||||
{
|
||||
LOG_TRACE_FMT("Cert::use() : Has own cert & PK");
|
||||
// Chain of X509 certificates is 'nullptr', as we haven't established a
|
||||
// chain yet. Overrides = 0, only sets cert&key once, since they don't
|
||||
// change with repeated calls to use().
|
||||
int rc = SSL_CTX_use_cert_and_key(cfg, own_cert, own_pkey, nullptr, 1);
|
||||
if (!rc)
|
||||
{
|
||||
auto err_str = tls::error_string(ERR_get_error());
|
||||
LOG_FAIL_FMT("Cert::ctor: Invalid CTX certificate or key: ", err_str);
|
||||
throw std::logic_error("Invalid CTX certificate or key: " + err_str);
|
||||
}
|
||||
rc = SSL_use_cert_and_key(ssl, own_cert, own_pkey, nullptr, 1);
|
||||
if (!rc)
|
||||
{
|
||||
auto err_str = tls::error_string(ERR_get_error());
|
||||
LOG_FAIL_FMT("Cert::ctor: Invalid SSL certificate or key: ", err_str);
|
||||
throw std::logic_error("Invalid SSL certificate or key: " + err_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const X509* raw()
|
||||
{
|
||||
return own_cert;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "context.h"
|
||||
|
||||
namespace tls
|
||||
{
|
||||
class Client : public Context
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<Cert> cert;
|
||||
|
||||
public:
|
||||
Client(std::shared_ptr<Cert> cert_, bool dtls = false) :
|
||||
Context(true, dtls),
|
||||
cert(cert_)
|
||||
{
|
||||
cert->use(ssl, cfg);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,524 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "cert.h"
|
||||
#include "crypto/base64.h"
|
||||
#include "crypto/entropy.h"
|
||||
#include "ds/logger.h"
|
||||
#include "tls/openssl/tls.h"
|
||||
|
||||
#include <memory>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
using namespace crypto;
|
||||
|
||||
namespace tls
|
||||
{
|
||||
class Context
|
||||
{
|
||||
protected:
|
||||
crypto::OpenSSL::Unique_SSL_CTX cfg;
|
||||
crypto::OpenSSL::Unique_SSL ssl;
|
||||
|
||||
public:
|
||||
Context(bool client, bool dtls) :
|
||||
cfg(
|
||||
dtls ? (client ? DTLS_client_method() : DTLS_server_method()) :
|
||||
(client ? TLS_client_method() : TLS_server_method())),
|
||||
ssl(cfg)
|
||||
{
|
||||
// Require at least TLS 1.2, support up to 1.3
|
||||
SSL_CTX_set_min_proto_version(
|
||||
cfg, dtls ? DTLS1_2_VERSION : TLS1_2_VERSION);
|
||||
SSL_set_min_proto_version(ssl, dtls ? DTLS1_2_VERSION : TLS1_2_VERSION);
|
||||
|
||||
// Disable renegotiation to avoid DoS
|
||||
SSL_CTX_set_options(
|
||||
cfg,
|
||||
SSL_OP_CIPHER_SERVER_PREFERENCE |
|
||||
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
|
||||
SSL_OP_NO_RENEGOTIATION);
|
||||
SSL_set_options(
|
||||
ssl,
|
||||
SSL_OP_CIPHER_SERVER_PREFERENCE |
|
||||
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
|
||||
SSL_OP_NO_RENEGOTIATION);
|
||||
|
||||
// Set cipher for TLS 1.2 (TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
|
||||
SSL_CTX_set_cipher_list(
|
||||
cfg,
|
||||
"ECDHE-ECDSA-AES256-GCM-SHA384:"
|
||||
"ECDHE-ECDSA-AES128-GCM-SHA256");
|
||||
SSL_set_cipher_list(
|
||||
ssl,
|
||||
"ECDHE-ECDSA-AES256-GCM-SHA384:"
|
||||
"ECDHE-ECDSA-AES128-GCM-SHA256");
|
||||
|
||||
// Set cipher for TLS 1.3 (same as above)
|
||||
SSL_CTX_set_ciphersuites(
|
||||
cfg,
|
||||
"TLS_AES_256_GCM_SHA384:"
|
||||
"TLS_AES_128_GCM_SHA256");
|
||||
SSL_set_ciphersuites(
|
||||
ssl,
|
||||
"TLS_AES_256_GCM_SHA384:"
|
||||
"TLS_AES_128_GCM_SHA256");
|
||||
|
||||
// Restrict the curves to approved ones
|
||||
SSL_CTX_set1_curves_list(cfg, "P-521:P-384");
|
||||
SSL_set1_curves_list(ssl, "P-521:P-384");
|
||||
|
||||
// Initialise connection
|
||||
if (client)
|
||||
SSL_set_connect_state(ssl);
|
||||
else
|
||||
SSL_set_accept_state(ssl);
|
||||
}
|
||||
|
||||
virtual ~Context() {}
|
||||
|
||||
void set_bio(
|
||||
void* cb_obj,
|
||||
BIO_callback_fn_ex send,
|
||||
BIO_callback_fn_ex recv,
|
||||
BIO_callback_fn_ex dbg)
|
||||
{
|
||||
// Read/Write BIOs will be used by TLS
|
||||
BIO* rbio = BIO_new(BIO_s_mem());
|
||||
BIO_set_mem_eof_return(rbio, -1);
|
||||
BIO_set_callback_arg(rbio, (char*)cb_obj);
|
||||
BIO_set_callback_ex(rbio, recv);
|
||||
SSL_set0_rbio(ssl, rbio);
|
||||
|
||||
BIO* wbio = BIO_new(BIO_s_mem());
|
||||
BIO_set_mem_eof_return(wbio, -1);
|
||||
BIO_set_callback_arg(wbio, (char*)cb_obj);
|
||||
BIO_set_callback_ex(wbio, send);
|
||||
SSL_set0_wbio(ssl, wbio);
|
||||
|
||||
// We don't need debug callbacks and the other two already have
|
||||
// enough debug messages. Once we get rid of MbedTLS, we can remove this
|
||||
// argument.
|
||||
(void)dbg;
|
||||
}
|
||||
|
||||
int handshake()
|
||||
{
|
||||
if (SSL_is_init_finished(ssl))
|
||||
return 0;
|
||||
|
||||
int rc = SSL_do_handshake(ssl);
|
||||
// Success in OpenSSL is 1, MBed is 0
|
||||
if (rc > 0)
|
||||
{
|
||||
LOG_TRACE_FMT("Context::handshake() : Success");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Want read/write needs special return
|
||||
if (SSL_want_read(ssl))
|
||||
{
|
||||
return TLS_ERR_WANT_READ;
|
||||
}
|
||||
else if (SSL_want_write(ssl))
|
||||
{
|
||||
return TLS_ERR_WANT_WRITE;
|
||||
}
|
||||
|
||||
// So does x509 validation
|
||||
if (verify_result() != 0)
|
||||
{
|
||||
return TLS_ERR_X509_VERIFY;
|
||||
}
|
||||
|
||||
// Everything else falls here.
|
||||
LOG_TRACE_FMT("Context::handshake() : Error code {}", rc);
|
||||
|
||||
// As an MBedTLS emulation, we return negative for errors.
|
||||
return -SSL_get_error(ssl, rc);
|
||||
}
|
||||
|
||||
int read(uint8_t* buf, size_t len)
|
||||
{
|
||||
if (len == 0)
|
||||
return 0;
|
||||
size_t readbytes = 0;
|
||||
int rc = SSL_read_ex(ssl, buf, len, &readbytes);
|
||||
if (rc > 0)
|
||||
{
|
||||
return readbytes;
|
||||
}
|
||||
if (SSL_want_read(ssl))
|
||||
{
|
||||
return TLS_ERR_WANT_READ;
|
||||
}
|
||||
|
||||
// Everything else falls here.
|
||||
LOG_TRACE_FMT("Context::read() : Error code {}", rc);
|
||||
|
||||
// As an MBedTLS emulation, we return negative for errors.
|
||||
return -SSL_get_error(ssl, rc);
|
||||
}
|
||||
|
||||
int write(const uint8_t* buf, size_t len)
|
||||
{
|
||||
if (len == 0)
|
||||
return 0;
|
||||
size_t written = 0;
|
||||
int rc = SSL_write_ex(ssl, buf, len, &written);
|
||||
if (rc > 0)
|
||||
{
|
||||
return written;
|
||||
}
|
||||
if (SSL_want_write(ssl))
|
||||
{
|
||||
return TLS_ERR_WANT_WRITE;
|
||||
}
|
||||
|
||||
// Everything else falls here.
|
||||
LOG_TRACE_FMT("Context::write() : Error code {}", rc);
|
||||
|
||||
// As an MBedTLS emulation, we return negative for errors.
|
||||
return -SSL_get_error(ssl, rc);
|
||||
}
|
||||
|
||||
int close()
|
||||
{
|
||||
LOG_TRACE_FMT("Context::close() : Shutdown");
|
||||
return SSL_shutdown(ssl);
|
||||
}
|
||||
|
||||
// This is a hack to make it work like MBedTLS (with negative return
|
||||
// values as error), and to differentiate in get_verify_error if the error
|
||||
// is because we don't have a peer cert or something else.
|
||||
// We may find that this is unnecessary (alongside all of the error messages
|
||||
// in get_verify_error), but that's a cleanup that will need a bit more
|
||||
// research.
|
||||
#define TLS_ERR_X509_NO_PEER_CERT -1
|
||||
#define TLS_ERR_X509_INVALID_RESULT -2
|
||||
|
||||
int verify_result()
|
||||
{
|
||||
if (SSL_get_verify_result(ssl) == X509_V_OK)
|
||||
{
|
||||
// Verify can return OK when no certificate is presented
|
||||
// We want that to be an error
|
||||
X509* cert = SSL_get_peer_certificate(ssl);
|
||||
if (cert)
|
||||
{
|
||||
X509_free(cert);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return TLS_ERR_X509_NO_PEER_CERT;
|
||||
}
|
||||
}
|
||||
return TLS_ERR_X509_INVALID_RESULT;
|
||||
}
|
||||
|
||||
std::string get_verify_error()
|
||||
{
|
||||
int rc = verify_result();
|
||||
if (rc == TLS_ERR_X509_NO_PEER_CERT)
|
||||
{
|
||||
return "Certificate verify error: No peer certificate";
|
||||
}
|
||||
|
||||
switch (rc)
|
||||
{
|
||||
case X509_V_ERR_UNSPECIFIED:
|
||||
return "Unspecified error; should not happen.";
|
||||
|
||||
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
|
||||
return "The issuer certificate of a looked up certificate could not "
|
||||
"be found. This normally means the list of trusted "
|
||||
"certificates is not complete.";
|
||||
|
||||
case X509_V_ERR_UNABLE_TO_GET_CRL:
|
||||
return "The CRL of a certificate could not be found.";
|
||||
|
||||
case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
|
||||
return "The certificate signature could not be decrypted. This means "
|
||||
"that the actual signature value could not be determined "
|
||||
"rather than it not matching the expected value";
|
||||
|
||||
case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
|
||||
return "The CRL signature could not be decrypted: this means that "
|
||||
"the actual signature value could not be determined rather "
|
||||
"than it not matching the expected value. Unused.";
|
||||
|
||||
case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
|
||||
return "The public key in the certificate SubjectPublicKeyInfo could "
|
||||
"not be read.";
|
||||
|
||||
case X509_V_ERR_CERT_SIGNATURE_FAILURE:
|
||||
return "The signature of the certificate is invalid.";
|
||||
|
||||
case X509_V_ERR_CRL_SIGNATURE_FAILURE:
|
||||
return "The signature of the certificate is invalid.";
|
||||
|
||||
case X509_V_ERR_CERT_NOT_YET_VALID:
|
||||
return "The certificate is not yet valid: the notBefore date is "
|
||||
"after the current time.";
|
||||
|
||||
case X509_V_ERR_CERT_HAS_EXPIRED:
|
||||
return "The certificate has expired: that is the notAfter date is "
|
||||
"before the current time.";
|
||||
|
||||
case X509_V_ERR_CRL_NOT_YET_VALID:
|
||||
return "The CRL is not yet valid.";
|
||||
|
||||
case X509_V_ERR_CRL_HAS_EXPIRED:
|
||||
return "The CRL has expired.";
|
||||
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
|
||||
return "The certificate notBefore field contains an invalid time.";
|
||||
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
|
||||
return "The certificate notAfter field contains an invalid time.";
|
||||
|
||||
case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
|
||||
return "The CRL lastUpdate field contains an invalid time.";
|
||||
|
||||
case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
|
||||
return "The CRL nextUpdate field contains an invalid time.";
|
||||
|
||||
case X509_V_ERR_OUT_OF_MEM:
|
||||
return "An error occurred trying to allocate memory. This should "
|
||||
"never happen.";
|
||||
|
||||
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
|
||||
return "The passed certificate is self-signed and the same "
|
||||
"certificate cannot be found in the list of trusted "
|
||||
"certificates.";
|
||||
|
||||
case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
|
||||
return "The certificate chain could be built up using the untrusted "
|
||||
"certificates but the root could not be found locally.";
|
||||
|
||||
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
|
||||
return "The issuer certificate could not be found: this occurs if "
|
||||
"the issuer certificate of an untrusted certificate cannot be "
|
||||
"found.";
|
||||
|
||||
case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
|
||||
return "No signatures could be verified because the chain contains "
|
||||
"only one certificate and it is not self signed.";
|
||||
|
||||
case X509_V_ERR_CERT_CHAIN_TOO_LONG:
|
||||
return "The certificate chain length is greater than the supplied "
|
||||
"maximum depth. Unused.";
|
||||
|
||||
case X509_V_ERR_CERT_REVOKED:
|
||||
return "The certificate has been revoked.";
|
||||
|
||||
case X509_V_ERR_INVALID_CA:
|
||||
return "A CA certificate is invalid. Either it is not a CA or its "
|
||||
"extensions are not consistent with the supplied purpose.";
|
||||
|
||||
case X509_V_ERR_PATH_LENGTH_EXCEEDED:
|
||||
return "The basicConstraints pathlength parameter has been exceeded.";
|
||||
|
||||
case X509_V_ERR_INVALID_PURPOSE:
|
||||
return "The supplied certificate cannot be used for the specified "
|
||||
"purpose.";
|
||||
|
||||
case X509_V_ERR_CERT_UNTRUSTED:
|
||||
return "The root CA is not marked as trusted for the specified "
|
||||
"purpose.";
|
||||
|
||||
case X509_V_ERR_CERT_REJECTED:
|
||||
return "The root CA is marked to reject the specified purpose.";
|
||||
|
||||
case X509_V_ERR_SUBJECT_ISSUER_MISMATCH:
|
||||
return "Not used as of OpenSSL 1.1.0 as a result of the deprecation "
|
||||
"of the -issuer_checks option.";
|
||||
|
||||
case X509_V_ERR_AKID_SKID_MISMATCH:
|
||||
return "Not used as of OpenSSL 1.1.0 as a result of the deprecation "
|
||||
"of the -issuer_checks option.";
|
||||
|
||||
case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH:
|
||||
return "Not used as of OpenSSL 1.1.0 as a result of the deprecation "
|
||||
"of the -issuer_checks option.";
|
||||
|
||||
case X509_V_ERR_KEYUSAGE_NO_CERTSIGN:
|
||||
return "Not used as of OpenSSL 1.1.0 as a result of the deprecation "
|
||||
"of the -issuer_checks option.";
|
||||
|
||||
case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
|
||||
return "Unable to get CRL issuer certificate.";
|
||||
|
||||
case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION:
|
||||
return "Unhandled critical extension.";
|
||||
|
||||
case X509_V_ERR_KEYUSAGE_NO_CRL_SIGN:
|
||||
return "Key usage does not include CRL signing.";
|
||||
|
||||
case X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION:
|
||||
return "Unhandled critical CRL extension.";
|
||||
|
||||
case X509_V_ERR_INVALID_NON_CA:
|
||||
return "Invalid non-CA certificate has CA markings.";
|
||||
|
||||
case X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED:
|
||||
return "Proxy path length constraint exceeded.";
|
||||
|
||||
case X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE:
|
||||
return "Key usage does not include digital signature.";
|
||||
|
||||
case X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED:
|
||||
return "Proxy certificates not allowed";
|
||||
|
||||
case X509_V_ERR_INVALID_EXTENSION:
|
||||
return "Invalid or inconsistent certificate extension.";
|
||||
|
||||
case X509_V_ERR_INVALID_POLICY_EXTENSION:
|
||||
return "Invalid or inconsistent certificate policy extension.";
|
||||
|
||||
case X509_V_ERR_NO_EXPLICIT_POLICY:
|
||||
return "No explicit policy.";
|
||||
|
||||
case X509_V_ERR_DIFFERENT_CRL_SCOPE:
|
||||
return "Different CRL scope.";
|
||||
|
||||
case X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE:
|
||||
return "Unsupported extension feature.";
|
||||
|
||||
case X509_V_ERR_UNNESTED_RESOURCE:
|
||||
return "RFC 3779 resource not subset of parent's resources.";
|
||||
|
||||
case X509_V_ERR_PERMITTED_VIOLATION:
|
||||
return "Permitted subtree violation.";
|
||||
|
||||
case X509_V_ERR_EXCLUDED_VIOLATION:
|
||||
return "Excluded subtree violation.";
|
||||
|
||||
case X509_V_ERR_SUBTREE_MINMAX:
|
||||
return "Name constraints minimum and maximum not supported.";
|
||||
|
||||
case X509_V_ERR_APPLICATION_VERIFICATION:
|
||||
return "Application verification failure. Unused.";
|
||||
|
||||
case X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE:
|
||||
return "Unsupported name constraint type.";
|
||||
|
||||
case X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX:
|
||||
return "Unsupported or invalid name constraint syntax.";
|
||||
|
||||
case X509_V_ERR_UNSUPPORTED_NAME_SYNTAX:
|
||||
return "Unsupported or invalid name syntax.";
|
||||
|
||||
case X509_V_ERR_CRL_PATH_VALIDATION_ERROR:
|
||||
return "CRL path validation error.";
|
||||
|
||||
case X509_V_ERR_PATH_LOOP:
|
||||
return "Path loop.";
|
||||
|
||||
case X509_V_ERR_SUITE_B_INVALID_VERSION:
|
||||
return "Suite B: certificate version invalid.";
|
||||
|
||||
case X509_V_ERR_SUITE_B_INVALID_ALGORITHM:
|
||||
return "Suite B: invalid public key algorithm.";
|
||||
|
||||
case X509_V_ERR_SUITE_B_INVALID_CURVE:
|
||||
return "Suite B: invalid ECC curve.";
|
||||
|
||||
case X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM:
|
||||
return "Suite B: invalid signature algorithm.";
|
||||
|
||||
case X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED:
|
||||
return "Suite B: curve not allowed for this LOS.";
|
||||
|
||||
case X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256:
|
||||
return "Suite B: cannot sign P-384 with P-256.";
|
||||
|
||||
case X509_V_ERR_HOSTNAME_MISMATCH:
|
||||
return "Hostname mismatch.";
|
||||
|
||||
case X509_V_ERR_EMAIL_MISMATCH:
|
||||
return "Email address mismatch.";
|
||||
|
||||
case X509_V_ERR_IP_ADDRESS_MISMATCH:
|
||||
return "IP address mismatch.";
|
||||
|
||||
case X509_V_ERR_DANE_NO_MATCH:
|
||||
return "DANE TLSA authentication is enabled";
|
||||
|
||||
case X509_V_ERR_EE_KEY_TOO_SMALL:
|
||||
return "EE certificate key too weak.";
|
||||
|
||||
case X509_V_ERR_INVALID_CALL:
|
||||
return "nvalid certificate verification context.";
|
||||
|
||||
case X509_V_ERR_STORE_LOOKUP:
|
||||
return "Issuer certificate lookup error.";
|
||||
|
||||
case X509_V_ERR_NO_VALID_SCTS:
|
||||
return "Certificate Transparency required";
|
||||
|
||||
case X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION:
|
||||
return "Proxy subject name violation.";
|
||||
|
||||
case X509_V_ERR_OCSP_VERIFY_NEEDED:
|
||||
return "Returned by the verify callback to indicate an OCSP "
|
||||
"verification is needed.";
|
||||
|
||||
case X509_V_ERR_OCSP_VERIFY_FAILED:
|
||||
return "Returned by the verify callback to indicate OCSP "
|
||||
"verification failed.";
|
||||
|
||||
case X509_V_ERR_OCSP_CERT_UNKNOWN:
|
||||
return "Returned by the verify callback to indicate that the "
|
||||
"certificate is not recognized by the OCSP responder.";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
virtual std::string host()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> peer_cert()
|
||||
{
|
||||
// Get the certificate into a BIO as DER
|
||||
crypto::OpenSSL::Unique_X509 cert(
|
||||
SSL_get_peer_certificate(ssl), /*check_null=*/false);
|
||||
if (!cert)
|
||||
{
|
||||
LOG_TRACE_FMT("Empty peer cert");
|
||||
return {};
|
||||
}
|
||||
crypto::OpenSSL::Unique_BIO bio;
|
||||
if (!i2d_X509_bio(bio, cert))
|
||||
{
|
||||
LOG_TRACE_FMT("Can't convert X509 to DER");
|
||||
return {};
|
||||
}
|
||||
|
||||
// Get the total length of the DER representation
|
||||
auto len = BIO_get_mem_data(bio, nullptr);
|
||||
if (!len)
|
||||
{
|
||||
LOG_TRACE_FMT("Null X509 peer cert");
|
||||
return {};
|
||||
}
|
||||
|
||||
// Get the BIO memory pointer
|
||||
BUF_MEM* ptr = nullptr;
|
||||
if (!BIO_get_mem_ptr(bio, &ptr))
|
||||
{
|
||||
LOG_TRACE_FMT("Invalid X509 peer cert");
|
||||
return {};
|
||||
}
|
||||
|
||||
// Return its contents as a vector
|
||||
auto ret = std::vector<uint8_t>(ptr->data, ptr->data + len);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#include "context.h"
|
||||
|
||||
namespace tls
|
||||
{
|
||||
class Server : public Context
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<Cert> cert;
|
||||
|
||||
public:
|
||||
Server(std::shared_ptr<Cert> cert_, bool dtls = false) :
|
||||
Context(false, dtls),
|
||||
cert(cert_)
|
||||
{
|
||||
cert->use(ssl, cfg);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -2,8 +2,21 @@
|
|||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
#ifdef TLS_PROVIDER_IS_MBEDTLS
|
||||
# include "mbedtls/server.h"
|
||||
#else
|
||||
# include "openssl/server.h"
|
||||
#endif
|
||||
#include "context.h"
|
||||
|
||||
namespace tls
|
||||
{
|
||||
class Server : public Context
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<Cert> cert;
|
||||
|
||||
public:
|
||||
Server(std::shared_ptr<Cert> cert_, bool dtls = false) :
|
||||
Context(false, dtls),
|
||||
cert(cert_)
|
||||
{
|
||||
cert->use(ssl, cfg);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -3,9 +3,7 @@
|
|||
#include "crypto/certs.h"
|
||||
#include "crypto/key_pair.h"
|
||||
#include "crypto/verifier.h"
|
||||
// These headers are temporary, until we have a single TLS implementation
|
||||
#include "tls/mbedtls/tls.h"
|
||||
#include "tls/openssl/tls.h"
|
||||
#include "tls/tls.h"
|
||||
|
||||
#include <openssl/err.h>
|
||||
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
|
||||
|
@ -94,8 +92,6 @@ int recv(void* ctx, uint8_t* buf, size_t len)
|
|||
return rc;
|
||||
}
|
||||
|
||||
#ifndef TLS_PROVIDER_IS_MBEDTLS
|
||||
|
||||
// These are OpenSSL callbacks that call onto the MbedTLS ones. They have the
|
||||
// same name but different signatures, so when using OpenSSL, these are the ones
|
||||
// that set_bio() will take, and call the ones above by using the correct
|
||||
|
@ -175,8 +171,6 @@ long recv(
|
|||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/// Performs a TLS handshake, looping until there's nothing more to read/write.
|
||||
/// Returns 0 on success, throws a runtime error with SSL error str on failure.
|
||||
int handshake(Context* ctx)
|
||||
|
@ -261,7 +255,7 @@ unique_ptr<tls::Cert> get_dummy_cert(NetworkCA& net_ca, string name, Auth auth)
|
|||
|
||||
// Create a tls::Cert with the CA, the signed certificate and the private key
|
||||
auto pk = kp->private_key_pem();
|
||||
return make_unique<Cert>(move(ca), crt, pk, nullb, auth);
|
||||
return make_unique<Cert>(move(ca), crt, pk, auth);
|
||||
}
|
||||
|
||||
/// Helper to write past the maximum buffer (16k)
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// Licensed under the Apache 2.0 License.
|
||||
#pragma once
|
||||
|
||||
// Macros provided to interface MbedTLS and OpenSSL on the same implementation.
|
||||
#ifndef TLS_PROVIDER_IS_MBEDTLS
|
||||
// These macros setup return values for when the connection is reading/writing
|
||||
// and needs more data or has an error.
|
||||
//
|
||||
|
@ -17,27 +15,25 @@
|
|||
// Some MbedTLS errors are not matched by OpenSSL, so we set some ridiculous
|
||||
// negative number that will never match. This allows us to place the macro as
|
||||
// a switch-case and not duplicate cases but also never match.
|
||||
# define TLS_READING -SSL_READING
|
||||
# define TLS_WRITING -SSL_WRITING
|
||||
# define TLS_ERR_WANT_READ -SSL_ERROR_WANT_READ
|
||||
# define TLS_ERR_WANT_WRITE -SSL_ERROR_WANT_WRITE
|
||||
# define TLS_ERR_CONN_CLOSE_NOTIFY -SSL_ERROR_ZERO_RETURN
|
||||
# define TLS_ERR_NEED_CERT -SSL_ERROR_WANT_X509_LOOKUP
|
||||
#define TLS_READING -SSL_READING
|
||||
#define TLS_WRITING -SSL_WRITING
|
||||
#define TLS_ERR_WANT_READ -SSL_ERROR_WANT_READ
|
||||
#define TLS_ERR_WANT_WRITE -SSL_ERROR_WANT_WRITE
|
||||
#define TLS_ERR_CONN_CLOSE_NOTIFY -SSL_ERROR_ZERO_RETURN
|
||||
#define TLS_ERR_NEED_CERT -SSL_ERROR_WANT_X509_LOOKUP
|
||||
// No counterpart in OpenSSL
|
||||
# define TLS_ERR_CONN_RESET INT_MIN
|
||||
# define TLS_ERR_PEER_VERIFY INT_MIN + 1
|
||||
# define TLS_ERR_X509_VERIFY INT_MIN + 2
|
||||
#define TLS_ERR_CONN_RESET INT_MIN
|
||||
#define TLS_ERR_PEER_VERIFY INT_MIN + 1
|
||||
#define TLS_ERR_X509_VERIFY INT_MIN + 2
|
||||
|
||||
# include <openssl/err.h>
|
||||
# include <string>
|
||||
#include "crypto/openssl/openssl_wrappers.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace tls
|
||||
{
|
||||
/// Returns the error string from an error code
|
||||
/// this is a copy of crypto's to allow control via TLS_PROVIDER_IS_MBEDTLS
|
||||
inline std::string error_string(int ec)
|
||||
{
|
||||
return ERR_error_string((unsigned long)ec, nullptr);
|
||||
return crypto::OpenSSL::error_string(ec);
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -59,14 +59,6 @@ benchmark_specs = {
|
|||
"D": "2048",
|
||||
},
|
||||
],
|
||||
"digest_bench.csv": [
|
||||
{
|
||||
"_name": "mbedtls sha256 (/s)^",
|
||||
"Suite": "mbedtls_digest_sha256",
|
||||
"Benchmark": "SHA-256",
|
||||
"D": "524288",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
Загрузка…
Ссылка в новой задаче