[crypto] add support for ECDSA signing (#3218)

This commit is contained in:
Łukasz Duda
2018-10-30 12:23:10 -07:00
committed by Jonathan Hui
parent e99ce0cf1f
commit 014514442d
9 changed files with 300 additions and 4 deletions
+4 -3
View File
@@ -62,6 +62,7 @@ python --version || die
--enable-dhcp6-server \
--enable-diag \
--enable-dns-client \
--enable-ecdsa \
--enable-ftd \
--enable-jam-detection \
--enable-joiner \
@@ -117,7 +118,7 @@ python --version || die
git checkout -- . || die
git clean -xfd || die
./bootstrap || die
BORDER_ROUTER=1 COAP=1 COMMISSIONER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 DNS_CLIENT=1 FULL_LOGS=1 JOINER=1 LINK_RAW=1 MAC_FILTER=1 MTD_NETDIAG=1 SERVICE=1 UDP_PROXY=1 make -f examples/Makefile-nrf52840 || die
BORDER_ROUTER=1 COAP=1 COMMISSIONER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 DNS_CLIENT=1 ECDSA=1 FULL_LOGS=1 JOINER=1 LINK_RAW=1 MAC_FILTER=1 MTD_NETDIAG=1 SERVICE=1 UDP_PROXY=1 make -f examples/Makefile-nrf52840 || die
arm-none-eabi-size output/nrf52840/bin/ot-cli-ftd || die
arm-none-eabi-size output/nrf52840/bin/ot-cli-mtd || die
arm-none-eabi-size output/nrf52840/bin/ot-ncp-ftd || die
@@ -195,7 +196,7 @@ python --version || die
git checkout -- . || die
git clean -xfd || die
./bootstrap || die
BORDER_ROUTER=1 COAP=1 COMMISSIONER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 DNS_CLIENT=1 FULL_LOGS=1 JOINER=1 MAC_FILTER=1 MTD_NETDIAG=1 SERVICE=1 UDP_PROXY=1 make -f examples/Makefile-nrf52840 || die
BORDER_ROUTER=1 COAP=1 COMMISSIONER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 DNS_CLIENT=1 ECDSA=1 FULL_LOGS=1 JOINER=1 MAC_FILTER=1 MTD_NETDIAG=1 SERVICE=1 UDP_PROXY=1 make -f examples/Makefile-nrf52840 || die
arm-none-eabi-size output/nrf52840/bin/ot-cli-ftd || die
arm-none-eabi-size output/nrf52840/bin/ot-cli-mtd || die
arm-none-eabi-size output/nrf52840/bin/ot-ncp-ftd || die
@@ -273,7 +274,7 @@ python --version || die
git checkout -- . || die
git clean -xfd || die
./bootstrap || die
BORDER_ROUTER=1 COAP=1 COMMISSIONER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 DNS_CLIENT=1 FULL_LOGS=1 JOINER=1 MAC_FILTER=1 MTD_NETDIAG=1 SERVICE=1 UDP_PROXY=1 make -f examples/Makefile-nrf52840 || die
BORDER_ROUTER=1 COAP=1 COMMISSIONER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 DNS_CLIENT=1 ECDSA=1 FULL_LOGS=1 JOINER=1 MAC_FILTER=1 MTD_NETDIAG=1 SERVICE=1 UDP_PROXY=1 make -f examples/Makefile-nrf52840 || die
arm-none-eabi-size output/nrf52840/bin/ot-cli-ftd || die
arm-none-eabi-size output/nrf52840/bin/ot-cli-mtd || die
arm-none-eabi-size output/nrf52840/bin/ot-ncp-ftd || die
+34
View File
@@ -1498,6 +1498,39 @@ AC_ARG_WITH(
AC_SUBST(OPENTHREAD_CUSTOM_LINKER_FILE)
AM_CONDITIONAL([OPENTHREAD_ENABLE_CUSTOM_LINKER_FILE], [test "${with_custom_linker_file}" = "yes"])
#
# Support for ECDSA
#
AC_MSG_CHECKING([whether to build with ECDSA support])
AC_ARG_ENABLE(ecdsa,
[AS_HELP_STRING([--enable-ecdsa], [Enable ECDSA support @<:@default=no@:>@.])],
[
case "${enableval}" in
no|yes)
enable_ecdsa=${enableval}
;;
*)
AC_MSG_ERROR([Invalid value ${enable_ecdsa} for --enable-ecdsa])
;;
esac
],
[enable_ecdsa=no])
if test "$enable_ecdsa" = "yes"; then
OPENTHREAD_ENABLE_ECDSA=1
else
OPENTHREAD_ENABLE_ECDSA=0
fi
AC_MSG_RESULT(${enable_ecdsa})
AC_SUBST(OPENTHREAD_ENABLE_ECDSA)
AM_CONDITIONAL([OPENTHREAD_ENABLE_ECDSA], [test "${enable_ecdsa}" = "yes"])
AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_ECDSA], [${OPENTHREAD_ENABLE_ECDSA}], [Define to 1 if you want to enable ECDSA support])
#
# Examples
#
@@ -1888,6 +1921,7 @@ AC_MSG_NOTICE([
OpenThread Border Agent support : ${enable_border_agent}
OpenThread Border Router support : ${enable_border_router}
OpenThread Service support : ${enable_service}
OpenThread ECDSA support : ${enable_ecdsa}
OpenThread Examples : ${with_examples}
OpenThread POSIX Application : ${enable_posix_app}
+4
View File
@@ -87,6 +87,10 @@ ifeq ($(DNS_CLIENT),1)
configure_OPTIONS += --enable-dns-client
endif
ifeq ($(ECDSA),1)
configure_OPTIONS += --enable-ecdsa
endif
ifeq ($(JAM_DETECTION),1)
configure_OPTIONS += --enable-jam-detection
endif
+24
View File
@@ -38,6 +38,8 @@
#include <stdbool.h>
#include <stdint.h>
#include <openthread/error.h>
#ifdef __cplusplus
extern "C" {
#endif
@@ -103,6 +105,28 @@ void otCryptoAesCcm(const uint8_t *aKey,
bool aEncrypt,
void * aTag);
/**
* This method creates ECDSA sign.
*
* @param[out] aOutput An output buffer where ECDSA sign should be stored.
* @param[inout] aOutputLength The length of the @p aOutput buffer.
* @param[in] aInputHash An input hash.
* @param[in] aInputHashLength The length of the @p aClaims buffer.
* @param[in] aPrivateKey A private key in PEM format.
* @param[in] aPrivateKeyLength The length of the @p aPrivateKey buffer.
*
* @retval OT_ERROR_NONE ECDSA sign has been created successfully.
* @retval OT_ERROR_NO_BUFS Output buffer is too small.
* @retval OT_ERROR_INVALID_ARGS Private key is not valid EC Private Key.
* @rerval OT_ERROR_FAILED Error during signing.
*/
otError otCryptoEcdsaSign(uint8_t * aOutput,
uint16_t * aOutputLength,
const uint8_t *aInputHash,
uint16_t aInputHashLength,
const uint8_t *aPrivateKey,
uint16_t aPrivateKeyLength);
/**
* @}
*
+2
View File
@@ -147,6 +147,7 @@ SOURCES_COMMON = \
common/trickle_timer.cpp \
crypto/aes_ccm.cpp \
crypto/aes_ecb.cpp \
crypto/ecdsa.cpp \
crypto/hmac_sha256.cpp \
crypto/mbedtls.cpp \
crypto/pbkdf2_cmac.cpp \
@@ -304,6 +305,7 @@ HEADERS_COMMON = \
common/trickle_timer.hpp \
crypto/aes_ccm.hpp \
crypto/aes_ecb.hpp \
crypto/ecdsa.hpp \
crypto/hmac_sha256.hpp \
crypto/mbedtls.hpp \
crypto/pbkdf2_cmac.h \
+16
View File
@@ -33,10 +33,12 @@
#include "openthread-core-config.h"
#include <openthread/crypto.h>
#include <openthread/error.h>
#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "crypto/aes_ccm.hpp"
#include "crypto/ecdsa.hpp"
#include "crypto/hmac_sha256.hpp"
using namespace ot::Crypto;
@@ -91,3 +93,17 @@ void otCryptoAesCcm(const uint8_t *aKey,
exit:
return;
}
#if OPENTHREAD_ENABLE_ECDSA
otError otCryptoEcdsaSign(uint8_t * aOutput,
uint16_t * aOutputLength,
const uint8_t *aInputHash,
uint16_t aInputHashLength,
const uint8_t *aPrivateKey,
uint16_t aPrivateKeyLength)
{
return Ecdsa::Sign(aOutput, aOutputLength, aInputHash, aInputHashLength, aPrivateKey, aPrivateKeyLength);
}
#endif // OPENTHREAD_ENABLE_ECDSA
+112
View File
@@ -0,0 +1,112 @@
/*
* Copyright (c) 2018, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file implements ECDSA signing.
*/
#include "ecdsa.hpp"
#include <assert.h>
#include <mbedtls/ecdsa.h>
#include <mbedtls/pk.h>
#include "common/code_utils.hpp"
#include "common/random.hpp"
namespace ot {
namespace Crypto {
#if OPENTHREAD_ENABLE_ECDSA
otError Ecdsa::Sign(uint8_t * aOutput,
uint16_t * aOutputLength,
const uint8_t *aInputHash,
uint16_t aInputHashLength,
const uint8_t *aPrivateKey,
uint16_t aPrivateKeyLength)
{
otError error = OT_ERROR_NONE;
mbedtls_ecdsa_context ctx;
mbedtls_pk_context pkCtx;
mbedtls_ecp_keypair * keypair;
mbedtls_mpi rMpi;
mbedtls_mpi sMpi;
mbedtls_pk_init(&pkCtx);
mbedtls_ecdsa_init(&ctx);
// Parse a private key in PEM format.
VerifyOrExit(mbedtls_pk_parse_key(&pkCtx, aPrivateKey, aPrivateKeyLength, NULL, 0) == 0,
error = OT_ERROR_INVALID_ARGS);
VerifyOrExit(mbedtls_pk_get_type(&pkCtx) == MBEDTLS_PK_ECKEY, error = OT_ERROR_INVALID_ARGS);
keypair = mbedtls_pk_ec(pkCtx);
assert(keypair != NULL);
VerifyOrExit(mbedtls_ecdsa_from_keypair(&ctx, keypair) == 0, error = OT_ERROR_FAILED);
mbedtls_mpi_init(&rMpi);
mbedtls_mpi_init(&sMpi);
// Sign using ECDSA.
VerifyOrExit(mbedtls_ecdsa_sign(&ctx.grp, &rMpi, &sMpi, &ctx.d, aInputHash, aInputHashLength, FillRandom, NULL) ==
0,
error = OT_ERROR_FAILED);
VerifyOrExit(mbedtls_mpi_size(&rMpi) + mbedtls_mpi_size(&sMpi) <= *aOutputLength, error = OT_ERROR_NO_BUFS);
// Concatenate the two octet sequences in the order R and then S.
VerifyOrExit(mbedtls_mpi_write_binary(&rMpi, aOutput, mbedtls_mpi_size(&rMpi)) == 0, error = OT_ERROR_FAILED);
*aOutputLength = mbedtls_mpi_size(&rMpi);
VerifyOrExit(mbedtls_mpi_write_binary(&sMpi, aOutput + *aOutputLength, mbedtls_mpi_size(&sMpi)) == 0,
error = OT_ERROR_FAILED);
*aOutputLength += mbedtls_mpi_size(&sMpi);
exit:
mbedtls_mpi_free(&rMpi);
mbedtls_mpi_free(&sMpi);
mbedtls_ecdsa_free(&ctx);
mbedtls_pk_free(&pkCtx);
return error;
}
int Ecdsa::FillRandom(void *, unsigned char *aBuffer, size_t aSize)
{
Random::FillBuffer(aBuffer, aSize);
return 0;
}
#endif // OPENTHREAD_ENABLE_ECDSA
} // namespace Crypto
} // namespace ot
+95
View File
@@ -0,0 +1,95 @@
/*
* Copyright (c) 2018, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes definitions for performing ECDSA signing.
*/
#ifndef ECDSA_HPP_
#define ECDSA_HPP_
#include "openthread-core-config.h"
#include <stdlib.h>
#include "utils/wrap_stdint.h"
#include <openthread/error.h>
namespace ot {
namespace Crypto {
/**
* @addtogroup core-security
*
* @{
*
*/
/**
* This class implements ECDSA signing.
*
*/
class Ecdsa
{
public:
/**
* This method creates ECDSA sign.
*
* @param[out] aOutput An output buffer where ECDSA sign should be stored.
* @param[inout] aOutputLength The length of the @p aOutput buffer.
* @param[in] aInputHash An input hash.
* @param[in] aInputHashLength The length of the @p aInputHash buffer.
* @param[in] aPrivateKey A private key in PEM format.
* @param[in] aPrivateKeyLength The length of the @p aPrivateKey buffer.
*
* @retval OT_ERROR_NONE ECDSA sign has been created successfully.
* @retval OT_ERROR_NO_BUFS Output buffer is too small.
* @retval OT_ERROR_INVALID_ARGS Private key is not valid EC Private Key.
* @rerval OT_ERROR_FAILED Error during signing.
*/
static otError Sign(uint8_t * aOutput,
uint16_t * aOutputLength,
const uint8_t *aInputHash,
uint16_t aInputHashLength,
const uint8_t *aPrivateKey,
uint16_t aPrivateKeyLength);
private:
static int FillRandom(void *, unsigned char *aBuffer, size_t aSize);
};
/**
* @}
*
*/
} // namespace Crypto
} // namespace ot
#endif // ECDSA_HPP_
+9 -1
View File
@@ -119,6 +119,14 @@ __inline int windows_kernel_snprintf(char * s, size_t n, const char * format, ..
#define MBEDTLS_X509_CRT_PARSE_C
#endif
#if OPENTHREAD_ENABLE_ECDSA
#define MBEDTLS_BASE64_C
#define MBEDTLS_ECDH_C
#define MBEDTLS_ECDSA_C
#define MBEDTLS_OID_C
#define MBEDTLS_PEM_PARSE_C
#endif
#define MBEDTLS_MPI_WINDOW_SIZE 1 /**< Maximum windows size used. */
#define MBEDTLS_MPI_MAX_SIZE 32 /**< Maximum number of bytes for usable MPIs. */
#define MBEDTLS_ECP_MAX_BITS 256 /**< Maximum bit size of groups */
@@ -127,7 +135,7 @@ __inline int windows_kernel_snprintf(char * s, size_t n, const char * format, ..
#define MBEDTLS_ENTROPY_MAX_SOURCES 1 /**< Maximum number of sources supported */
#if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
#define MBEDTLS_PLATFORM_STD_CALLOC otPlatCAlloc /**< Default allocator to use, can be undefined */
#define MBEDTLS_PLATFORM_STD_CALLOC otPlatCAlloc /**< Default allocator to use, can be undefined */
#define MBEDTLS_PLATFORM_STD_FREE otPlatFree /**< Default free to use, can be undefined */
#else
#define MBEDTLS_MEMORY_BUFFER_ALLOC_C