psa_generate_key failed with error (-134)

When running the ECDSA Example from Nordic, the keys are generated successfully. But when I add the code for generating CSR it fails with the error code -134 which bby my knowledge is PSA_ERROR_NOT_SUPPORTED. Requesting help with this issue. 

using NRF Connect v2.6.1 and board nrf5340 in secure environment.

# The Zephyr CMSIS emulation assumes that ticks are ms, currently
CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000

CONFIG_MAIN_STACK_SIZE=8192
CONFIG_HEAP_MEM_POOL_SIZE=8192

# Enable logging
CONFIG_CONSOLE=y
CONFIG_LOG=y

# Enable nordic security backend and PSA APIs
CONFIG_NRF_SECURITY=y
CONFIG_MBEDTLS_PSA_CRYPTO_C=y

# Enable persistent storage APIs
CONFIG_MBEDTLS_PSA_CRYPTO_STORAGE_C=y
#CONFIG_PSA_NATIVE_ITS=y

CONFIG_MBEDTLS_ENABLE_HEAP=y
CONFIG_MBEDTLS_HEAP_SIZE=8192

CONFIG_PSA_WANT_ALG_ECDSA=y
CONFIG_PSA_WANT_KEY_TYPE_ECC_KEY_PAIR=y
CONFIG_PSA_WANT_ECC_SECP_R1_256=y
CONFIG_PSA_WANT_ALG_SHA_256=y

# For key generation
CONFIG_PSA_WANT_GENERATE_RANDOM=y

CONFIG_MBEDTLS=y
CONFIG_MBEDTLS_USE_PSA_CRYPTO=y
CONFIG_MBEDTLS_PK_C=y
CONFIG_MBEDTLS_TLS_LIBRARY=y
CONFIG_MBEDTLS_LEGACY_CRYPTO_C=y

CONFIG_MBEDTLS_X509_USE_C=y
CONFIG_MBEDTLS_X509_CSR_WRITE_C=y
CONFIG_MBEDTLS_X509_LIBRARY=y

CONFIG_MBEDTLS_PK_WRITE_C=y
CONFIG_MBEDTLS_X509_CRT_PARSE_C=y
CONFIG_MBEDTLS_X509_CREATE_C=y
CONFIG_MBEDTLS_X509_CSR_PARSE_C=y

CONFIG_MBEDTLS_PK_PARSE_C=y
CONFIG_MBEDTLS_PK_PARSE_EC_EXTENDED=y

CONFIG_MBEDTLS_KEY_EXCHANGE_ALL_ENABLED=y
CONFIG_PSA_CRYPTO_DRIVER_OBERON=n
CONFIG_PSA_CRYPTO_DRIVER_CC3XX=y

CONFIG_MBEDTLS_LIBRARY_NRF_SECURITY=y
CONFIG_MBEDTLS_SHA256_C=y
CONFIG_MBEDTLS_ECP_C=y
CONFIG_MBEDTLS_ECDSA_C=y
CONFIG_MBEDTLS_ECDH_C=y

CONFIG_MBEDTLS_CTR_DRBG_C=y
CONFIG_MBEDTLS_MD_C=y
CONFIG_PSA_WANT_ALG_ECDSA_ANY=y

And my code is :

/*
 * Copyright (c) 2021 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 */

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/logging/log.h>
#include <stdio.h>
#include <stdlib.h>
#include <psa/crypto.h>
#include <psa/crypto_extra.h>

#ifdef CONFIG_BUILD_WITH_TFM
#include <tfm_ns_interface.h>
#endif

#include <mbedtls/pk.h>
#include <mbedtls/x509.h>
#include <mbedtls/x509_csr.h>


#define APP_SUCCESS		(0)
#define APP_ERROR		(-1)
#define APP_SUCCESS_MESSAGE "Example finished successfully!"
#define APP_ERROR_MESSAGE "Example exited with error!"
#define SEC_LIB_CSR_SUBJECT_NAME "C=TIH Foundation for IoT and IoE,O=TIH,OU=Networking,CN=TIH-IoT"
#define PRINT_HEX(p_label, p_text, len)\
	({\
		LOG_INF("---- %s (len: %u): ----", p_label, len);\
		LOG_HEXDUMP_INF(p_text, len, "Content:");\
		LOG_INF("---- %s end  ----", p_label);\
	})

LOG_MODULE_REGISTER(ecdsa, LOG_LEVEL_DBG);

/* ====================================================================== */
/*				Global variables/defines for the ECDSA example			  */

#define NRF_CRYPTO_EXAMPLE_ECDSA_TEXT_SIZE (100)

#define NRF_CRYPTO_EXAMPLE_ECDSA_PUBLIC_KEY_SIZE (65)
#define NRF_CRYPTO_EXAMPLE_ECDSA_SIGNATURE_SIZE (64)
#define NRF_CRYPTO_EXAMPLE_ECDSA_HASH_SIZE (32)

/* Below text is used as plaintext for signing/verification */
//static uint8_t m_plain_text[NRF_CRYPTO_EXAMPLE_ECDSA_TEXT_SIZE] = {
//	"Example string to demonstrate basic usage of ECDSA."
//};

static uint8_t m_pub_key[NRF_CRYPTO_EXAMPLE_ECDSA_PUBLIC_KEY_SIZE];

//static uint8_t m_signature[NRF_CRYPTO_EXAMPLE_ECDSA_SIGNATURE_SIZE];
//static uint8_t m_hash[NRF_CRYPTO_EXAMPLE_ECDSA_HASH_SIZE];

static psa_key_id_t keypair_id;
static psa_key_id_t pub_key_id;
/* ====================================================================== */

int crypto_init(void)
{
	psa_status_t status;

	/* Initialize PSA Crypto */
	status = psa_crypto_init();
	if (status != PSA_SUCCESS) {
		LOG_INF("psa_crypto_init failed! (Error: %d)", status);
		return APP_ERROR;
	}

	return APP_SUCCESS;
}

int crypto_finish(void)
{
	psa_status_t status;

	/* Destroy the key handle */
	status = psa_destroy_key(keypair_id);
	if (status != PSA_SUCCESS) {
		LOG_INF("psa_destroy_key failed! (Error: %d)", status);
		return APP_ERROR;
	}

	status = psa_destroy_key(pub_key_id);
	if (status != PSA_SUCCESS) {
		LOG_INF("psa_destroy_key failed! (Error: %d)", status);
		return APP_ERROR;
	}

	return APP_SUCCESS;
}

int generate_ecdsa_keypair(void)
{
	psa_status_t status;
	size_t olen;

	LOG_INF("Generating random ECDSA keypair...");

	/* Configure the key attributes */
	psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;

	/* Configure the key attributes */
	psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_SIGN_HASH);
	psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE);
	psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
	psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
	psa_set_key_bits(&key_attributes, 256);

	/* Generate a random keypair. The keypair is not exposed to the application,
	 * we can use it to sign hashes.
	 */
	#define SAMPLE_PERS_KEY_ID PSA_KEY_ID_USER_MIN
	psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_PERSISTENT);
	psa_set_key_id(&key_attributes, SAMPLE_PERS_KEY_ID);
	psa_destroy_key(SAMPLE_PERS_KEY_ID);

	status = psa_generate_key(&key_attributes, &keypair_id);
	if (status != PSA_SUCCESS) {
		LOG_INF("psa_generate_key failed! (Error: %d)", status);
		return APP_ERROR;
	}

	/* Export the public key */
	status = psa_export_public_key(keypair_id, m_pub_key, sizeof(m_pub_key), &olen);
	if (status != PSA_SUCCESS) {
		LOG_INF("psa_export_public_key failed! (Error: %d)", status);
		return APP_ERROR;
	}

	/* Reset key attributes and free any allocated resources. */
	psa_reset_key_attributes(&key_attributes);

	return APP_SUCCESS;
}

int import_ecdsa_pub_key(void)
{
	/* Configure the key attributes */
	psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
	psa_status_t status;

	/* Configure the key attributes */
	psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_VERIFY_HASH);
	psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE);
	psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
	psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
	psa_set_key_bits(&key_attributes, 256);

	status = psa_import_key(&key_attributes, m_pub_key, sizeof(m_pub_key), &pub_key_id);
	if (status != PSA_SUCCESS) {
		LOG_INF("psa_import_key failed! (Error: %d)", status);
		return APP_ERROR;
	}

	/* Reset key attributes and free any allocated resources. */
	psa_reset_key_attributes(&key_attributes);

	return APP_SUCCESS;
}

// int sign_message(void)
// {
// 	uint32_t output_len;
// 	psa_status_t status;

// 	LOG_INF("Signing a message using ECDSA...");

// 	/* Compute the SHA256 hash*/
// 	status = psa_hash_compute(PSA_ALG_SHA_256,
// 				  m_plain_text,
// 				  sizeof(m_plain_text),
// 				  m_hash,
// 				  sizeof(m_hash),
// 				  &output_len);
// 	if (status != PSA_SUCCESS) {
// 		LOG_INF("psa_hash_compute failed! (Error: %d)", status);
// 		return APP_ERROR;
// 	}

// 	/* Sign the hash */
// 	status = psa_sign_hash(keypair_id,
// 			       PSA_ALG_ECDSA(PSA_ALG_SHA_256),
// 			       m_hash,
// 			       sizeof(m_hash),
// 			       m_signature,
// 			       sizeof(m_signature),
// 			       &output_len);
// 	if (status != PSA_SUCCESS) {
// 		LOG_INF("psa_sign_hash failed! (Error: %d)", status);
// 		return APP_ERROR;
// 	}

// 	LOG_INF("Message signed successfully!");
// 	PRINT_HEX("Plaintext", m_plain_text, sizeof(m_plain_text));
// 	PRINT_HEX("SHA256 hash", m_hash, sizeof(m_hash));
// 	PRINT_HEX("Signature", m_signature, sizeof(m_signature));

// 	return APP_SUCCESS;
// }

// int verify_message(void)
// {
// 	psa_status_t status;

// 	LOG_INF("Verifying ECDSA signature...");

// 	/* Verify the signature of the hash */
// 	status = psa_verify_hash(pub_key_id,
// 				 PSA_ALG_ECDSA(PSA_ALG_SHA_256),
// 				 m_hash,
// 				 sizeof(m_hash),
// 				 m_signature,
// 				 sizeof(m_signature));
// 	if (status != PSA_SUCCESS) {
// 		LOG_INF("psa_verify_hash failed! (Error: %d)", status);
// 		return APP_ERROR;
// 	}

// 	LOG_INF("Signature verification was successful!");

// 	return APP_SUCCESS;
// }

static int psa_rng_for_mbedtls(void *p_rng,
			       unsigned char *output, size_t output_len)
{
	(void)p_rng;

	return psa_generate_random(output, output_len);
}

int generate_csr()
{
	psa_status_t status;
	//psa_key_handle_t key_handle;
	
	unsigned char output_buf[1024];
	memset(output_buf, 0, sizeof(output_buf));

	mbedtls_pk_context pk_key_container;
	mbedtls_x509write_csr csr_ctx;
	mbedtls_pk_init(&pk_key_container);
	// pk_key_container.private_pk_ctx=m_pub_key;
	// pk_key_container.private_pk_info=pub_key_id;
	mbedtls_pk_setup_opaque(&pk_key_container, keypair_id);
	//mbedtls_pk_setup(&pk_key_container, &key_handle);

	// Prepare CSR context
	mbedtls_x509write_csr_init(&csr_ctx); LOG_INF("Write CSR initialised");
    mbedtls_x509write_csr_set_key_usage(&csr_ctx, MBEDTLS_X509_KU_DIGITAL_SIGNATURE); 		LOG_INF("Key usage of CSR is set");
    mbedtls_x509write_csr_set_subject_name(&csr_ctx, SEC_LIB_CSR_SUBJECT_NAME); 			LOG_INF("Added subject name to CSR");
    mbedtls_x509write_csr_set_md_alg(&csr_ctx, MBEDTLS_MD_SHA256); 							LOG_INF(" Hashing algorithm of CSR is set");
    mbedtls_x509write_csr_set_key(&csr_ctx, &pk_key_container);

	// Create CSR
	status = mbedtls_x509write_csr_der(&csr_ctx,output_buf,sizeof(output_buf),psa_rng_for_mbedtls, NULL);

	if(status != 0)
    {
        return APP_ERROR;
    }

	mbedtls_x509write_csr_free(&csr_ctx);
	mbedtls_pk_free(&pk_key_container);
	printk("%s",&output_buf);
	return	APP_SUCCESS;
}


int main(void)
{
	int status;

	LOG_INF("Starting ECDSA example...");

	status = crypto_init();
	if (status != APP_SUCCESS) {
		LOG_INF(APP_ERROR_MESSAGE);
		return APP_ERROR;
	}

	status = generate_ecdsa_keypair();
	if (status != APP_SUCCESS) {
		LOG_INF(APP_ERROR_MESSAGE);
		return APP_ERROR;
	}

	status = import_ecdsa_pub_key();
	if (status != APP_SUCCESS) {
		LOG_INF(APP_ERROR_MESSAGE);
		return APP_ERROR;
	}

	status = generate_csr();
	if (status != APP_SUCCESS) {
		LOG_INF(APP_ERROR_MESSAGE);
		return APP_ERROR;
	}

	// status = sign_message();
	// if (status != APP_SUCCESS) {
	// 	LOG_INF(APP_ERROR_MESSAGE);
	// 	return APP_ERROR;
	// }

	// status = verify_message();
	// if (status != APP_SUCCESS) {
	// 	LOG_INF(APP_ERROR_MESSAGE);
	// 	return APP_ERROR;
	// }

	status = crypto_finish();
	if (status != APP_SUCCESS) {
		LOG_INF(APP_ERROR_MESSAGE);
		return APP_ERROR;
	}

	LOG_INF(APP_SUCCESS_MESSAGE);

	return APP_SUCCESS;
}

Parents Reply Children
  • Hi,

    It is certainly possible and we are workign to support it. But it requiers quite a bit of changes to do properly, and not just a small workaround (it is not a bug). I cannot make any promisses, but we hope to have it in the next nRF Connect SDK release.

    From what I can see the customer that report he got it working in the other thread did not share the details, but it could be worth asking if he can share the full set of changes he did to get it working.

  • Yes, I can confirm we have the exactly the same problem - flags that allow x509 functions to be built and exported also disable psa_* functionality.

  • Thank you for your quick and useful replies, I really appreciate it. 

    As for CSR vs PSA support, it would be nice to have it working as soon as possible, but I understand it's not an easy task - I guess we will just for now stick with generating keys outside of the nrf sdk mbedtls implementation so we can at least somehow get this (generating CSRs) working.

    I know it's hard, but can you at least roughly tell when you expect this support to be implemented? From your github, it looks like minor SDK releases come every 3 or 4 months.

Related