-1

I'm working on an implementation of an EST(Enrollment over Secure Transport)-client over CoAPs for the OpenThread stack. For this, i want to write a CSR (Certificate Signing Request) by using mbedTLS, which is part of the stack as a third party software. My problem now is that i get some "undefined reference" error from the linker when i build the code (i'm using GCC on an Ubuntu 18.04.2 LTS machine).

As there are multiple functions for which the error occurs, i will provide code for just one example. here is my source file:

openthread/src/core/crypto/ecp.cpp:

#include "ecp.hpp"

#include <mbedtls/ctr_drbg.h>
#include <mbedtls/ecp.h>
#include <mbedtls/pk.h>

#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "common/random.hpp"

#include "openthread/entropy.h"
#include "openthread/random_crypto.h"

namespace ot {
namespace Crypto {

#if OPENTHREAD_ENABLE_EST_CLIENT && OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE

otError Ecp::KeyPairGeneration(const uint8_t *aPersonalSeed,
                               uint32_t       aPersonalSeedLength,
                               uint8_t *      aPrivateKey,
                               uint32_t *     aPrivateKeyLength,
                               uint8_t *      aPublicKey,
                               uint32_t *     aPublicKeyLength)
{
    otError error = OT_ERROR_NONE;
    mbedtls_pk_context keypair;

    OT_UNUSED_VARIABLE(aPersonalSeed);
    OT_UNUSED_VARIABLE(aPersonalSeedLength);

    mbedtls_pk_init(&keypair);

    // Generate keypair
    VerifyOrExit(mbedtls_pk_setup(&keypair, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)),
                 error = OT_ERROR_FAILED);

    VerifyOrExit(mbedtls_ecp_group_load(&mbedtls_pk_ec(keypair)->grp, MBEDTLS_ECP_DP_SECP256R1) == 0,
                 error = OT_ERROR_FAILED);

    VerifyOrExit(mbedtls_ecp_gen_keypair(&mbedtls_pk_ec(keypair)->grp, &mbedtls_pk_ec(keypair)->d,
                                         &mbedtls_pk_ec(keypair)->Q, mbedtls_ctr_drbg_random,
                                         Random::Crypto::MbedTlsContextGet()) == 0,
                 error = OT_ERROR_FAILED);

    VerifyOrExit(mbedtls_pk_write_pubkey_pem(&keypair, (unsigned char*)aPublicKey,
                                             *aPublicKeyLength) == 0,
                 error = OT_ERROR_INVALID_ARGS);

    VerifyOrExit(mbedtls_pk_write_key_pem(&keypair, (unsigned char*)aPrivateKey,
                                          *aPrivateKeyLength) == 0,
                 error = OT_ERROR_INVALID_ARGS);

exit:
    mbedtls_pk_free(&keypair);

    return error;
}

#endif // OPENTHREAD_ENABLE_EST_CLIENT

} // namespace Crypto
} // namespace ot

my header file:

openthread/src/core/crypto/ecp.hpp


#ifndef ECP_HPP_
#define ECP_HPP_

#include "openthread-core-config.h"

#include <stdint.h>
#include <stdlib.h>

#include <openthread/error.h>

namespace ot {
namespace Crypto {

/**
 * @addtogroup core-security
 *
 * @{
 *
 */

/**
 * This class implements elliptic curve key generation.
 *
 */
class Ecp
{
public:
    /**
     * This method generate a Elliptic Curve key pair.
     *
     * @param[in]       aPersonalSeed       An additional seed for the entropy. Can be NULL.
     * @param[in]       aPersonalSeedLengh  The length of the @p aPersonalSeed.
     * @param[out]      aPrivateKey         An output buffer where the private key should be stored.
     * @param[inout]    aPrivateKeyLength   The length of the @p aPrivateKey buffer.
     * @param[out]      aPublicKey          An output buffer where the private key should be stored.
     * @param[inout]    aPublicKeyLength    The length of the @p aPublicKey buffer.
     *
     * @retval  OT_ERROR_NONE       EC key pairs has been created successfully.
     *          OT_ERROR_NO_BUFS    Key buffers are too small or mbedtls heap too small.
     */
    static otError KeyPairGeneration(const uint8_t *aPersonalSeed,
                                     uint32_t       aPersonalSeedLength,
                                     uint8_t *      aPrivateKey,
                                     uint32_t *     aPrivateKeyLength,
                                     uint8_t *      aPublicKey,
                                     uint32_t *     aPublicKeyLength);
};

/**
 * @}
 *
 */

} // namespace Crypto
} // namespace ot

#endif // ECP_HPP_

The functions which cause the error are here mbedtls_pk_write_pubkey_pem and mbedtls_pk_write_key_pem.

Here is also a part of the console output:

Making all in apps
Making all in cli
  CC       ot_cli_ftd-main.o
  CC       ot_cli_mtd-main.o
  CCLD     ot-cli-ftd
  CCLD     ot-cli-mtd
/opt/gcc-arm-none-eabi-8-2018-q4-major/bin/../lib/gcc/arm-none-eabi/8.2.1/../../../../arm-none-eabi/bin/ld: ../../../src/core/libopenthread-mtd.a(libopenthread_mtd_a-ecp.o): in function `ot::Crypto::Ecp::KeyPairGeneration(unsigned char const*, unsigned long, unsigned char*, unsigned long*, unsigned char*, unsigned long*)':
/home/scnm/eclipse-workspace/openthread/examples/../src/core/crypto/ecp.cpp:79: undefined reference to `mbedtls_pk_write_pubkey_pem'
/opt/gcc-arm-none-eabi-8-2018-q4-major/bin/../lib/gcc/arm-none-eabi/8.2.1/../../../../arm-none-eabi/bin/ld: /home/scnm/eclipse-workspace/openthread/examples/../src/core/crypto/ecp.cpp:83: undefined reference to `mbedtls_pk_write_key_pem'
collect2: error: ld returned 1 exit status
Makefile:1249: recipe for target 'ot-cli-mtd' failed
make[5]: *** [ot-cli-mtd] Error 1

I first thougth it was because i was missing some #define to actually use these functions, but i compared it with other OpenThread code which uses mbedtls and i can't see what i did wrong. As far as i've understood it, i have to modify the "openthread/third_party/mbedtls/mbedtls-config.h" file so that these funtions are build, so this is what i did:

#ifndef MBEDTLS_CONFIG_H
#define MBEDTLS_CONFIG_H

#include <stdio.h>
#include <stdlib.h>

#include <openthread/config.h>
#include <openthread/platform/logging.h>
#include <openthread/platform/memory.h>

#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf

#define MBEDTLS_AES_C
#define MBEDTLS_AES_ROM_TABLES
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_ASN1_WRITE_C
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_CCM_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_CMAC_C
#define MBEDTLS_CTR_DRBG_C
#define MBEDTLS_ECJPAKE_C
#define MBEDTLS_ECP_C
#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
#define MBEDTLS_ECP_NIST_OPTIM
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_HAVE_ASM
#define MBEDTLS_HMAC_DRBG_C
#define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED
#define MBEDTLS_MD_C
#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
#define MBEDTLS_NO_PLATFORM_ENTROPY
#define MBEDTLS_PK_C
#define MBEDTLS_PK_PARSE_C
#define MBEDTLS_PLATFORM_C
#define MBEDTLS_PLATFORM_MEMORY
#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
#define MBEDTLS_SHA256_C
#define MBEDTLS_SHA256_SMALLER
#define MBEDTLS_SSL_CLI_C
#define MBEDTLS_SSL_DTLS_ANTI_REPLAY
#define MBEDTLS_SSL_DTLS_HELLO_VERIFY
#define MBEDTLS_SSL_EXPORT_KEYS
#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
#define MBEDTLS_SSL_PROTO_TLS1_2
#define MBEDTLS_SSL_PROTO_DTLS
#define MBEDTLS_SSL_TLS_C

#if OPENTHREAD_ENABLE_BORDER_AGENT || OPENTHREAD_ENABLE_COMMISSIONER || OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#define MBEDTLS_SSL_COOKIE_C
#define MBEDTLS_SSL_SRV_C
#endif

#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#if OPENTHREAD_ENABLE_EST_CLIENT
#define MBEDTLS_PEM_WRITE_C
#define MBEDTLS_PK_WRITE_C
#define MBEDTLS_X509_CSR_WRITE_C
#define MBEDTLS_X509_CREATE_C
#endif
#endif

#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#define MBEDTLS_BASE64_C
#define MBEDTLS_ECDH_C
#define MBEDTLS_ECDSA_C
#define MBEDTLS_OID_C
#define MBEDTLS_PEM_PARSE_C
#define MBEDTLS_X509_USE_C
#define MBEDTLS_X509_CRT_PARSE_C
#define MBEDTLS_X509_USE_C
#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 */
#define MBEDTLS_ECP_WINDOW_SIZE            2 /**< Maximum window size used */
#define MBEDTLS_ECP_FIXED_POINT_OPTIM      0 /**< Enable fixed-point speed-up */
#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_FREE        otPlatFree /**< Default free to use, can be undefined */
#else
#define MBEDTLS_MEMORY_BUFFER_ALLOC_C
#endif

#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#define MBEDTLS_SSL_MAX_CONTENT_LEN      900 /**< Maxium fragment length in bytes */
#else
#define MBEDTLS_SSL_MAX_CONTENT_LEN      768 /**< Maxium fragment length in bytes */
#endif

#define MBEDTLS_SSL_CIPHERSUITES         MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8

#if defined(MBEDTLS_USER_CONFIG_FILE)
#include MBEDTLS_USER_CONFIG_FILE
#endif

#if defined(MBEDTLS_ECP_ALT) && !defined(MBEDTLS_ECP_RESTARTABLE)
typedef void mbedtls_ecp_restart_ctx;
#endif

#include "mbedtls/check_config.h"

#endif /* MBEDTLS_CONFIG_H */

It resolved the "not defined in this scope" errors i've had before, but instead i have now the above described errors.

Here is what i've edited in the common-switch file:

openthread/examples/common-switches.mk

ECDSA               ?= 0
// my code begin
EST_CLIENT          ?= 0
// my code end
JAM_DETECTION       ?= 0
ifeq ($(ECDSA),1)
configure_OPTIONS              += --enable-ecdsa
endif

// my code begin
ifeq ($(EST_CLIENT),1)
configure_OPTIONS              += --enable-est-client --enable-application-coap-secure
endif
// my code end

ifeq ($(JAM_DETECTION),1)
configure_OPTIONS              += --enable-jam-detection
endif

and her what i've added to configure:

openthread/configure.ac

#
# EST Client
#

AC_ARG_ENABLE(est_client,
    [AS_HELP_STRING([--enable-est-client],[Enable EST client support @<:@default=no@:>@.])],
    [
        case "${enableval}" in

        no|yes)
            enable_est_client=${enableval}
            ;;

        *)
            AC_MSG_ERROR([Invalid value ${enable_est_client} for --enable-est-client])
            ;;
        esac
    ],
    [enable_est_client=no])

if test "$enable_est_client" = "yes"; then
    OPENTHREAD_ENABLE_EST_CLIENT=1
else
    OPENTHREAD_ENABLE_EST_CLIENT=0
fi

AC_SUBST(OPENTHREAD_ENABLE_EST_CLIENT)
AM_CONDITIONAL([OPENTHREAD_ENABLE_EST_CLIENT], [test "${enable_est_client}" = "yes"])
AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_EST_CLIENT],[${OPENTHREAD_ENABLE_EST_CLIENT}],[Define to 1 if you want to enable EST Client])
  OpenThread DNS Client support             : ${enable_dns_client}
// my code begin
  OpenThread EST Client support             : ${enable_est_client}
// my code end
  OpenThread SNTP Client support            : ${enable_sntp_client}

I've also edited the makefile:

openthread/src/core/Makefile.am

    crypto/ecdsa.hpp                  \
    crypto/ecp.hpp                    \
    crypto/hmac_sha256.hpp            \
    crypto/ecdsa.cpp                  \
    crypto/ecp.cpp                    \
    crypto/hmac_sha256.cpp            \

My build command is "make -f examples/Makefile-nrf52840 EST_CLIENT=1".

I think once this problem is solved, i can solve the others by myself as the root of the problem seems to be the same.

Thanks.

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
  • 1
    this error occurs during the **link**, you missed to specify the lib defining `mbedtls_pk_write_pubkey_pem` – bruno Jun 26 '19 at 15:35
  • The lib you missed to specify can can be `libmbedcrypto.a` / `libmbedcrypto.so` – bruno Jun 26 '19 at 15:41

1 Answers1

0

You have an error during the link, the symbol mbedtls_pk_write_pubkey_pem is not defined, that means you missed to specify the lib defining it. Looking on the web it seems you need to link with mbedcrypto, so add libmbedcrypto.a or -lmbedcrypto (and may be use the option -L to specify the path)

It seems you also use X509, if you have missing symbols *X509* link with mbedx509, so add libmbedx509.a or -lmbedx509 (and may be use the option -L to specify the path)

bruno
  • 32,421
  • 7
  • 25
  • 37