Skip to content

Commit

Permalink
Add crypto API to generate a Certificate Signing Request (#2537)
Browse files Browse the repository at this point in the history
* Add crypto API to generate a CSR

* Restyled by clang-format

* Enable mbedTLS X509 write in EFR32 configuration

* Fix example compilation errors

* Add more mbedTLS specific flags

* Fix nrf builds

* Fix more targets

* Review comments

* Restyled by clang-format

* address review comments

Co-authored-by: Restyled.io <[email protected]>
  • Loading branch information
pan-apple and restyled-commits authored Sep 9, 2020
1 parent 4d33b15 commit 7438e5c
Show file tree
Hide file tree
Showing 8 changed files with 231 additions and 2 deletions.
3 changes: 3 additions & 0 deletions config/nrfconnect/nrfconnect-app.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ include(chip-lib)
set(CHIP_COMMON_FLAGS
-D_SYS__PTHREADTYPES_H_
-DMBEDTLS_CONFIG_FILE=<nrf-config.h>
-DMBEDTLS_PK_WRITE_C
-DMBEDTLS_X509_CREATE_C
-DMBEDTLS_X509_CSR_WRITE_C
-isystem${ZEPHYR_BASE}/include/posix
-isystem${ZEPHYR_BASE}/../mbedtls/include
-I${CMAKE_CURRENT_SOURCE_DIR}
Expand Down
7 changes: 6 additions & 1 deletion examples/lighting-app/nrf5/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@ nrf5_sdk("sdk") {
defines += [ "BUILD_RELEASE=1" ]
}

defines += [ "USE_APP_CONFIG" ]
defines += [
"USE_APP_CONFIG",
"MBEDTLS_PK_WRITE_C",
"MBEDTLS_X509_CREATE_C",
"MBEDTLS_X509_CSR_WRITE_C",
]
}

nrf5_executable("lighting_app") {
Expand Down
7 changes: 6 additions & 1 deletion examples/lock-app/nrf5/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@ nrf5_sdk("sdk") {
defines += [ "BUILD_RELEASE=1" ]
}

defines += [ "USE_APP_CONFIG" ]
defines += [
"USE_APP_CONFIG",
"MBEDTLS_PK_WRITE_C",
"MBEDTLS_X509_CREATE_C",
"MBEDTLS_X509_CSR_WRITE_C",
]
}

nrf5_executable("lock_app") {
Expand Down
10 changes: 10 additions & 0 deletions src/crypto/CHIPCryptoPAL.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const size_t kMax_ECDSA_Signature_Length = 72;
const size_t kMAX_FE_Length = kP256_FE_Length;
const size_t kMAX_Point_Length = kP256_Point_Length;
const size_t kMAX_Hash_Length = kSHA256_Hash_Length;
const size_t kMAX_CSR_Length = 512;

const size_t kP256_PrivateKey_Length = 32;
const size_t kP256_PublicKey_Length = 65;
Expand Down Expand Up @@ -308,6 +309,15 @@ CHIP_ERROR pbkdf2_sha256(const uint8_t * password, size_t plen, const uint8_t *
**/
CHIP_ERROR NewECPKeypair(ECPKey & pubkey, ECPKey & privkey);

/** @brief Generate a new Certificate Signing Request (CSR).
* @param pubkey public key that'll be inserted in the CSR
* @param privkey private key to sign the CSR
* @param csr Newly generated CSR
* @param csr_length The caller provides the length of input buffer (csr). The function returns the actual length of generated CSR.
* @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
**/
CHIP_ERROR NewCertificateSigningRequest(ECPKey & pubkey, ECPKey & privkey, uint8_t * csr, size_t & csr_length);

/**
* The below class implements the draft 01 version of the Spake2+ protocol as
* defined in https://www.ietf.org/id/draft-bar-cfrg-spake2plus-01.html.
Expand Down
136 changes: 136 additions & 0 deletions src/crypto/CHIPCryptoPALOpenSSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@
#include <openssl/hmac.h>
#include <openssl/kdf.h>
#include <openssl/ossl_typ.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include <openssl/x509.h>

#include <core/CHIPSafeCasts.h>
#include <support/CodeUtils.h>
Expand Down Expand Up @@ -874,6 +876,140 @@ CHIP_ERROR NewECPKeypair(ECPKey & pubkey, ECPKey & privkey)
return error;
}

CHIP_ERROR NewCertificateSigningRequest(ECPKey & pubkey, ECPKey & privkey, uint8_t * out_csr, size_t & csr_length)
{
ERR_clear_error();
CHIP_ERROR error = CHIP_NO_ERROR;
int result = 0;
int nid = NID_undef;

X509_REQ * x509_req = X509_REQ_new();
EVP_PKEY * evp_pkey = nullptr;
BIGNUM * pvt_key = nullptr;
EC_GROUP * group = nullptr;
EC_POINT * key_point = nullptr;

EC_KEY * ec_key = nullptr;
ECName curve = MapECName(pubkey.Type());

BIO * bioMem = nullptr;
BUF_MEM * bptr = nullptr;

VerifyOrExit(curve == MapECName(privkey.Type()), error = CHIP_ERROR_INVALID_ARGUMENT);

nid = _nidForCurve(curve);
VerifyOrExit(nid != NID_undef, error = CHIP_ERROR_INVALID_ARGUMENT);

result = X509_REQ_set_version(x509_req, 0);
VerifyOrExit(result == 1, error = CHIP_ERROR_INTERNAL);

group = EC_GROUP_new_by_curve_name(nid);
VerifyOrExit(group != nullptr, error = CHIP_ERROR_INTERNAL);

key_point = EC_POINT_new(group);
VerifyOrExit(key_point != nullptr, error = CHIP_ERROR_INTERNAL);

result = EC_POINT_oct2point(group, key_point, Uint8::to_const_uchar(pubkey), pubkey.Length(), nullptr);
VerifyOrExit(result == 1, error = CHIP_ERROR_INTERNAL);

ec_key = EC_KEY_new_by_curve_name(nid);
VerifyOrExit(ec_key != nullptr, error = CHIP_ERROR_INTERNAL);

result = EC_KEY_set_public_key(ec_key, key_point);
VerifyOrExit(result == 1, error = CHIP_ERROR_INTERNAL);

result = EC_KEY_check_key(ec_key);
VerifyOrExit(result == 1, error = CHIP_ERROR_INTERNAL);

evp_pkey = EVP_PKEY_new();
VerifyOrExit(evp_pkey != nullptr, error = CHIP_ERROR_INTERNAL);

result = EVP_PKEY_set1_EC_KEY(evp_pkey, ec_key);
VerifyOrExit(result == 1, error = CHIP_ERROR_INTERNAL);

result = X509_REQ_set_pubkey(x509_req, evp_pkey);
VerifyOrExit(result == 1, error = CHIP_ERROR_INTERNAL);

EC_KEY_free(ec_key);
EVP_PKEY_free(evp_pkey);

ec_key = EC_KEY_new_by_curve_name(nid);
VerifyOrExit(ec_key != nullptr, error = CHIP_ERROR_INTERNAL);

pvt_key = BN_bin2bn(Uint8::to_const_uchar(privkey), privkey.Length(), nullptr);
VerifyOrExit(pvt_key != nullptr, error = CHIP_ERROR_INTERNAL);

result = EC_KEY_set_private_key(ec_key, pvt_key);
VerifyOrExit(result == 1, error = CHIP_ERROR_INTERNAL);

evp_pkey = EVP_PKEY_new();
VerifyOrExit(evp_pkey != nullptr, error = CHIP_ERROR_INTERNAL);

result = EVP_PKEY_set1_EC_KEY(evp_pkey, ec_key);
VerifyOrExit(result == 1, error = CHIP_ERROR_INTERNAL);

result = X509_REQ_sign(x509_req, evp_pkey, EVP_sha256());
VerifyOrExit(result > 0, error = CHIP_ERROR_INTERNAL);

bioMem = BIO_new(BIO_s_mem());
VerifyOrExit(bioMem != nullptr, error = CHIP_ERROR_INTERNAL);

result = PEM_write_bio_X509_REQ(bioMem, x509_req);
VerifyOrExit(result == 1, error = CHIP_ERROR_INTERNAL);

BIO_get_mem_ptr(bioMem, &bptr);
{
size_t input_length = csr_length;
csr_length = bptr->length;
VerifyOrExit(bptr->length <= input_length, error = CHIP_ERROR_BUFFER_TOO_SMALL);
memset(out_csr, 0, input_length);
}

BIO_read(bioMem, out_csr, bptr->length);

exit:
if (ec_key != nullptr)
{
EC_KEY_free(ec_key);
ec_key = nullptr;
}

if (group != nullptr)
{
EC_GROUP_free(group);
group = nullptr;
}

if (evp_pkey != nullptr)
{
EVP_PKEY_free(evp_pkey);
evp_pkey = nullptr;
}

if (bioMem != nullptr)
{
BIO_free(bioMem);
bioMem = nullptr;
}

if (pvt_key != nullptr)
{
BN_free(pvt_key);
pvt_key = nullptr;
}

if (key_point != nullptr)
{
EC_POINT_free(key_point);
key_point = nullptr;
}

X509_REQ_free(x509_req);

_logSSLError();
return error;
}

#define init_point(_point_) \
do \
{ \
Expand Down
53 changes: 53 additions & 0 deletions src/crypto/CHIPCryptoPALmbedTLS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <mbedtls/md.h>
#include <mbedtls/pkcs5.h>
#include <mbedtls/sha256.h>
#include <mbedtls/x509_csr.h>

#include <core/CHIPSafeCasts.h>
#include <support/CodeUtils.h>
Expand Down Expand Up @@ -577,6 +578,58 @@ CHIP_ERROR NewECPKeypair(ECPKey & pubkey, ECPKey & privkey)
return error;
}

CHIP_ERROR NewCertificateSigningRequest(ECPKey & pubkey, ECPKey & privkey, uint8_t * out_csr, size_t & csr_length)
{
CHIP_ERROR error = CHIP_NO_ERROR;
int result = 0;
size_t length = csr_length;

mbedtls_ecp_keypair * keypair = nullptr;

mbedtls_x509write_csr csr;
mbedtls_x509write_csr_init(&csr);

mbedtls_pk_context pk;
mbedtls_pk_init(&pk);

mbedtls_ecp_group_id group = MapECPGroupId(pubkey.Type());

const mbedtls_pk_info_t * pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY);
VerifyOrExit(pk_info != nullptr, error = CHIP_ERROR_INTERNAL);

result = mbedtls_pk_setup(&pk, pk_info);
VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL);

keypair = mbedtls_pk_ec(pk);
mbedtls_ecp_keypair_init(keypair);

VerifyOrExit(group == MapECPGroupId(privkey.Type()), error = CHIP_ERROR_INVALID_ARGUMENT);

result = mbedtls_ecp_group_load(&keypair->grp, group);
VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL);

result = mbedtls_ecp_point_read_binary(&keypair->grp, &keypair->Q, Uint8::to_const_uchar(pubkey), pubkey.Length());
VerifyOrExit(result == 0, error = CHIP_ERROR_INVALID_ARGUMENT);

result = mbedtls_mpi_read_binary(&keypair->d, Uint8::to_const_uchar(privkey), privkey.Length());
VerifyOrExit(result == 0, error = CHIP_ERROR_INVALID_ARGUMENT);

mbedtls_x509write_csr_set_key(&csr, &pk);

mbedtls_x509write_csr_set_md_alg(&csr, MBEDTLS_MD_SHA256);

result = mbedtls_x509write_csr_pem(&csr, out_csr, length, CryptoRNG, nullptr);
VerifyOrExit(result >= 0, error = CHIP_ERROR_INTERNAL);
csr_length = result;
result = 0;

exit:
mbedtls_x509write_csr_free(&csr);
mbedtls_pk_free(&pk);
_log_mbedTLS_error(result);
return error;
}

typedef struct Spake2p_Context
{
mbedtls_ecp_group curve;
Expand Down
12 changes: 12 additions & 0 deletions src/crypto/tests/CHIPCryptoPALTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,17 @@ static void TestP256_Keygen(nlTestSuite * inSuite, void * inContext)
ECDSA_validate_msg_signature(test_msg, msglen, pubkey, pubkey.Length(), test_sig, siglen) == CHIP_NO_ERROR);
}

static void TestCSR_Gen(nlTestSuite * inSuite, void * inContext)
{
P256PublicKey pubkey;
P256PrivateKey privkey;
uint8_t csr[kMAX_CSR_Length];
size_t length = sizeof(csr);

NL_TEST_ASSERT(inSuite, NewECPKeypair(pubkey, privkey) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, NewCertificateSigningRequest(pubkey, privkey, csr, length) == CHIP_NO_ERROR);
}

static void TestSPAKE2P_spake2p_FEMul(nlTestSuite * inSuite, void * inContext)
{
uint8_t fe_out[kMAX_FE_Length];
Expand Down Expand Up @@ -1349,6 +1360,7 @@ static const nlTest sTests[] = {
NL_TEST_DEF("Test adding entropy sources", TestAddEntropySources),
NL_TEST_DEF("Test PBKDF2 SHA256", TestPBKDF2_SHA256_TestVectors),
NL_TEST_DEF("Test P256 Keygen", TestP256_Keygen),
NL_TEST_DEF("Test CSR Generation", TestCSR_Gen),
NL_TEST_DEF("Test Spake2p_spake2p FEMul", TestSPAKE2P_spake2p_FEMul),
NL_TEST_DEF("Test Spake2p_spake2p FELoad/FEWrite", TestSPAKE2P_spake2p_FELoadWrite),
NL_TEST_DEF("Test Spake2p_spake2p Mac", TestSPAKE2P_spake2p_Mac),
Expand Down
5 changes: 5 additions & 0 deletions src/platform/EFR32/efr32-chip-mbedtls-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ typedef void mbedtls_ecp_restart_ctx;
#define MBEDTLS_NO_PLATFORM_ENTROPY
#define MBEDTLS_PK_C
#define MBEDTLS_PK_PARSE_C
#define MBEDTLS_PK_WRITE_C
#define MBEDTLS_PLATFORM_C
#define MBEDTLS_PLATFORM_MEMORY
#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
Expand All @@ -205,6 +206,10 @@ typedef void mbedtls_ecp_restart_ctx;
#define MBEDTLS_SSL_TLS_C
#define MBEDTLS_ERROR_STRERROR_DUMMY
#define MBEDTLS_HKDF_C
#define MBEDTLS_X509_CREATE_C
#define MBEDTLS_X509_CSR_WRITE_C
#define MBEDTLS_BASE64_C
#define MBEDTLS_PEM_WRITE_C

#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE || OPENTHREAD_CONFIG_COMMISSIONER_ENABLE || OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
#define MBEDTLS_SSL_COOKIE_C
Expand Down

0 comments on commit 7438e5c

Please sign in to comment.