Skip to content

Commit 8512f01

Browse files
degjorvanordicjm
authored andcommitted
nrf_security: cracen: Add IK support directly to cracen_psa
Add support for signing with identity key to cracen_psa Remove support for using identity key through sicrypto Remove sitask usage from ecc sign and verify Signed-off-by: Dag Erik Gjørvad <[email protected]>
1 parent 13f1018 commit 8512f01

File tree

5 files changed

+257
-165
lines changed

5 files changed

+257
-165
lines changed

subsys/nrf_security/src/drivers/cracen/cracenpsa/cracenpsa.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ list(APPEND cracen_driver_sources
1717
${CMAKE_CURRENT_LIST_DIR}/src/ec_helpers.c
1818
${CMAKE_CURRENT_LIST_DIR}/src/ecc.c
1919
${CMAKE_CURRENT_LIST_DIR}/src/rndinrange.c
20+
${CMAKE_CURRENT_LIST_DIR}/src/ikg_signature.c
2021

2122
# Note: We always need to have blkcipher.c and ctr_drbg.c since it
2223
# is used directly by many Cracen drivers.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
#ifndef CRACEN_PSA_IKG_H
8+
#define CRACEN_PSA_IKG_H
9+
10+
#include <stddef.h>
11+
#include <stdbool.h>
12+
#include <stdint.h>
13+
14+
int cracen_ikg_sign_message(int identity_key_index, const struct sxhashalg *hashalg,
15+
const struct sx_pk_ecurve *curve, const uint8_t *message,
16+
size_t message_length, uint8_t *signature);
17+
18+
int cracen_ikg_sign_digest(int identity_key_index, const struct sxhashalg *hashalg,
19+
const struct sx_pk_ecurve *curve, const uint8_t *digest,
20+
size_t digest_length, uint8_t *signature);
21+
22+
int cracen_ikg_create_pub_key(int identity_key_index, uint8_t *pub_key);
23+
24+
#endif /* CRACEN_PSA_IKG_H */
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/* Isolated key operations (signature generation, ...)
2+
*
3+
* Copyright (c) 2025 Nordic Semiconductor ASA
4+
*
5+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
6+
*
7+
* Workmem layout for the sign operation:
8+
* 1. Hash digest of the message to be signed (size: digestsz).
9+
*
10+
* Workmem layout for the sign digest operation:
11+
* 1. Hash digest of the message to be signed (size: digestsz).
12+
*
13+
* Other IKG tasks don't need workmem memory.
14+
*/
15+
16+
#include <stdint.h>
17+
#include <string.h>
18+
#include <silexpk/core.h>
19+
#include <silexpk/iomem.h>
20+
#include <sxsymcrypt/hash.h>
21+
#include <sxsymcrypt/hashdefs.h>
22+
#include <silexpk/ik.h>
23+
#include <cracen/statuscodes.h>
24+
#include <cracen_psa_ikg.h>
25+
#include <cracen_psa_primitives.h>
26+
#include "common.h"
27+
28+
#define MAX_ECDSA_ATTEMPTS 255
29+
30+
/** Convert a digest into an operand for ECDSA
31+
*
32+
* The raw digest may need to be padded or truncated to fit the curve
33+
* operand used for ECDSA.
34+
*
35+
* Conversion could also imply byte order inversion, but that is not
36+
* implemented here. It's expected that SilexPK takes big endian
37+
* operands here.
38+
*
39+
* As the digest size is expressed in bytes, this procedure does not
40+
* work for curves which have sizes not multiples of 8 bits.
41+
*/
42+
static void digest2op(const uint8_t *digest, size_t sz, uint8_t *dst, size_t opsz)
43+
{
44+
if (opsz > sz) {
45+
sx_clrpkmem(dst, opsz - sz);
46+
dst += opsz - sz;
47+
}
48+
sx_wrpkmem(dst, digest, opsz);
49+
}
50+
51+
static void ecdsa_read_sig(struct ecdsa_signature *sig, const uint8_t *r, const uint8_t *s,
52+
size_t opsz)
53+
{
54+
sx_rdpkmem(sig->r, r, opsz);
55+
if (!sig->s) {
56+
sig->s = sig->r + opsz;
57+
}
58+
sx_rdpkmem(sig->s, s, opsz);
59+
}
60+
61+
static int exit_ikg(struct sx_pk_acq_req *pkreq)
62+
{
63+
64+
int status;
65+
66+
sx_pk_release_req(pkreq->req);
67+
*pkreq = sx_pk_acquire_req(SX_PK_CMD_IK_EXIT);
68+
pkreq->status = sx_pk_list_ik_inslots(pkreq->req, 0, NULL);
69+
if (pkreq->status) {
70+
return pkreq->status;
71+
}
72+
sx_pk_run(pkreq->req);
73+
status = sx_pk_wait(pkreq->req);
74+
if (status != SX_OK) {
75+
return status;
76+
}
77+
sx_pk_release_req(pkreq->req);
78+
return SX_OK;
79+
}
80+
81+
int cracen_ikg_sign_message(int identity_key_index, const struct sxhashalg *hashalg,
82+
const struct sx_pk_ecurve *curve, const uint8_t *message,
83+
size_t message_length, uint8_t *signature)
84+
{
85+
int status;
86+
size_t digestsz = sx_hash_get_alg_digestsz(hashalg);
87+
uint8_t digest[digestsz];
88+
89+
status = hash_input(message, message_length, hashalg, digest);
90+
if (status != SX_OK) {
91+
return status;
92+
}
93+
94+
return cracen_ikg_sign_digest(identity_key_index, hashalg, curve, digest, digestsz,
95+
signature);
96+
}
97+
98+
int cracen_ikg_sign_digest(int identity_key_index, const struct sxhashalg *hashalg,
99+
const struct sx_pk_ecurve *curve, const uint8_t *digest,
100+
size_t digest_length, uint8_t *signature)
101+
{
102+
int status;
103+
size_t opsz = sx_pk_curve_opsize(curve);
104+
struct sx_pk_acq_req pkreq;
105+
struct sx_pk_inops_ik_ecdsa_sign inputs;
106+
size_t digestsz = sx_hash_get_alg_digestsz(hashalg);
107+
const uint8_t *curve_n;
108+
uint8_t workmem[digestsz];
109+
struct ecdsa_signature internal_signature = {0};
110+
111+
memcpy(workmem, digest, digest_length);
112+
curve_n = sx_pk_curve_order(curve);
113+
114+
internal_signature.r = signature;
115+
internal_signature.s = signature + opsz;
116+
117+
for (int i = 0; i <= MAX_ECDSA_ATTEMPTS; i++) {
118+
119+
pkreq = sx_pk_acquire_req(SX_PK_CMD_IK_ECDSA_SIGN);
120+
if (pkreq.status) {
121+
return pkreq.status;
122+
}
123+
pkreq.status = sx_pk_list_ik_inslots(pkreq.req, identity_key_index,
124+
(struct sx_pk_slot *)&inputs);
125+
if (pkreq.status) {
126+
return pkreq.status;
127+
}
128+
129+
digest2op(workmem, digestsz, inputs.h.addr, opsz);
130+
sx_pk_run(pkreq.req);
131+
status = sx_pk_wait(pkreq.req);
132+
if (status != SX_OK) {
133+
return status;
134+
}
135+
136+
/* SX_ERR_NOT_INVERTIBLE may be due to silexpk countermeasures. */
137+
if ((status == SX_ERR_INVALID_SIGNATURE) || (status == SX_ERR_NOT_INVERTIBLE)) {
138+
sx_pk_release_req(pkreq.req);
139+
if (i == MAX_ECDSA_ATTEMPTS) {
140+
return SX_ERR_TOO_MANY_ATTEMPTS;
141+
}
142+
} else {
143+
break;
144+
}
145+
}
146+
if (status != SX_OK) {
147+
sx_pk_release_req(pkreq.req);
148+
return status;
149+
}
150+
151+
const uint8_t **outputs = (const uint8_t **)sx_pk_get_output_ops(pkreq.req);
152+
153+
ecdsa_read_sig(&internal_signature, outputs[0], outputs[1], opsz);
154+
safe_memzero(workmem, digestsz);
155+
156+
return exit_ikg(&pkreq);
157+
}
158+
159+
int cracen_ikg_create_pub_key(int identity_key_index, uint8_t *pub_key)
160+
{
161+
int status;
162+
struct sx_pk_acq_req pkreq;
163+
164+
pkreq = sx_pk_acquire_req(SX_PK_CMD_IK_PUBKEY_GEN);
165+
if (pkreq.status) {
166+
return pkreq.status;
167+
}
168+
pkreq.status = sx_pk_list_ik_inslots(pkreq.req, identity_key_index, NULL);
169+
if (pkreq.status) {
170+
return pkreq.status;
171+
}
172+
173+
sx_pk_run(pkreq.req);
174+
status = sx_pk_wait(pkreq.req);
175+
if (status != SX_OK) {
176+
return status;
177+
}
178+
const uint8_t **outputs = (const uint8_t **)sx_pk_get_output_ops(pkreq.req);
179+
const int opsz = sx_pk_get_opsize(pkreq.req);
180+
181+
sx_rdpkmem(pub_key, outputs[0], opsz);
182+
sx_rdpkmem(pub_key + opsz, outputs[1], opsz);
183+
184+
return exit_ikg(&pkreq);
185+
}

subsys/nrf_security/src/drivers/cracen/cracenpsa/src/key_management.c

Lines changed: 12 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@
88
#include <cracen/ec_helpers.h>
99
#include <cracen/mem_helpers.h>
1010
#include "cracen_psa.h"
11+
#include "cracen_psa_ecdsa.h"
1112
#include "cracen_psa_eddsa.h"
1213
#include "cracen_psa_montgomery.h"
1314
#include "platform_keys/platform_keys.h"
1415
#include <nrf_security_mutexes.h>
1516
#include <sicrypto/drbghash.h>
1617
#include "ecc.h"
17-
#include <sicrypto/ed448.h>
18+
#include <cracen_psa_ikg.h>
1819
#include <sicrypto/rsa_keygen.h>
1920
#include <sicrypto/util.h>
20-
#include <silexpk/ed448.h>
2121
#include <silexpk/sxops/rsa.h>
2222
#include <sicrypto/ik.h>
2323
#include <silexpk/ik.h>
@@ -569,30 +569,22 @@ static size_t get_expected_pub_key_size(psa_ecc_family_t psa_curve, size_t key_b
569569
}
570570

571571
static psa_status_t handle_identity_key(const uint8_t *key_buffer, size_t key_buffer_size,
572-
const struct sx_pk_ecurve *sx_curve, uint8_t *data,
573-
struct si_sig_privkey *priv_key,
574-
struct si_sig_pubkey *pub_key)
572+
const struct sx_pk_ecurve *sx_curve, uint8_t *data)
575573
{
576574
if (key_buffer_size != sizeof(ikg_opaque_key)) {
577575
return PSA_ERROR_INVALID_ARGUMENT;
578576
}
579577

580578
if (IS_ENABLED(PSA_NEED_CRACEN_ECDSA_SECP_R1_256)) {
581-
*priv_key = si_sig_fetch_ikprivkey(sx_curve, *key_buffer);
582579
data[0] = SI_ECC_PUBKEY_UNCOMPRESSED;
583-
pub_key->key.eckey.qx = &data[1];
584-
pub_key->key.eckey.qy = &data[1 + sx_pk_curve_opsize(sx_curve)];
585-
} else {
586-
return PSA_ERROR_NOT_SUPPORTED;
580+
return silex_statuscodes_to_psa(cracen_ikg_create_pub_key(key_buffer[0], data + 1));
587581
}
588-
return PSA_SUCCESS;
582+
return PSA_ERROR_NOT_SUPPORTED;
589583
}
590584

591585
static psa_status_t handle_curve_family(psa_ecc_family_t psa_curve, size_t key_bits_attr,
592586
const uint8_t *key_buffer, uint8_t *data,
593-
const struct sx_pk_ecurve *sx_curve,
594-
struct si_sig_privkey *priv_key,
595-
struct si_sig_pubkey *pub_key)
587+
const struct sx_pk_ecurve *sx_curve)
596588
{
597589

598590
switch (psa_curve) {
@@ -629,9 +621,10 @@ static psa_status_t handle_curve_family(psa_ecc_family_t psa_curve, size_t key_b
629621
cracen_ed25519_create_pubkey(key_buffer, data));
630622
} else if (key_bits_attr == 448 &&
631623
IS_ENABLED(PSA_NEED_CRACEN_PURE_EDDSA_TWISTED_EDWARDS_448)) {
632-
priv_key->def = si_sig_def_ed448;
633-
priv_key->key.ed448 = (struct sx_ed448_v *)key_buffer;
634-
pub_key->key.ed448 = (struct sx_ed448_pt *)data;
624+
/* This if-statement is kept to make it easier to add ed448 in the future
625+
* even though it does nothing.
626+
*/
627+
return PSA_ERROR_NOT_SUPPORTED;
635628
} else {
636629
return PSA_ERROR_NOT_SUPPORTED;
637630
}
@@ -644,22 +637,11 @@ static psa_status_t handle_curve_family(psa_ecc_family_t psa_curve, size_t key_b
644637
return PSA_SUCCESS;
645638
}
646639

647-
static bool requires_sitask(const psa_key_attributes_t *attributes, psa_ecc_family_t curve)
648-
{
649-
if (!IS_ENABLED(PSA_NEED_CRACEN_ECDSA_SECP_R1_256)) {
650-
return false;
651-
}
652-
return PSA_KEY_LIFETIME_GET_LOCATION(psa_get_key_lifetime(attributes)) ==
653-
PSA_KEY_LOCATION_CRACEN;
654-
}
655-
656640
static psa_status_t export_ecc_public_key_from_keypair(const psa_key_attributes_t *attributes,
657641
const uint8_t *key_buffer,
658642
size_t key_buffer_size, uint8_t *data,
659643
size_t data_size, size_t *data_length)
660644
{
661-
struct si_sig_privkey priv_key;
662-
struct si_sig_pubkey pub_key;
663645
psa_status_t status;
664646

665647
size_t key_bits_attr = psa_get_key_bits(attributes);
@@ -679,31 +661,14 @@ static psa_status_t export_ecc_public_key_from_keypair(const psa_key_attributes_
679661

680662
if (PSA_KEY_LIFETIME_GET_LOCATION(psa_get_key_lifetime(attributes)) ==
681663
PSA_KEY_LOCATION_CRACEN) {
682-
status = handle_identity_key(key_buffer, key_buffer_size, sx_curve, data, &priv_key,
683-
&pub_key);
664+
status = handle_identity_key(key_buffer, key_buffer_size, sx_curve, data);
684665
} else {
685-
status = handle_curve_family(psa_curve, key_bits_attr, key_buffer, data, sx_curve,
686-
&priv_key, &pub_key);
666+
status = handle_curve_family(psa_curve, key_bits_attr, key_buffer, data, sx_curve);
687667
}
688668
if (status != PSA_SUCCESS) {
689669
return status;
690670
}
691-
bool is_sitask = requires_sitask(attributes, psa_curve);
692-
693-
if (is_sitask) {
694-
char workmem[SX_ED448_DGST_SZ] = {};
695-
struct sitask t;
696-
697-
si_task_init(&t, workmem, sizeof(workmem));
698-
si_sig_create_pubkey(&t, &priv_key, &pub_key);
699-
si_task_run(&t);
700671

701-
status = silex_statuscodes_to_psa(si_task_wait(&t));
702-
safe_memzero(workmem, sizeof(workmem));
703-
if (status != PSA_SUCCESS) {
704-
return status;
705-
}
706-
}
707672
*data_length = expected_pub_key_size;
708673
return PSA_SUCCESS;
709674
}

0 commit comments

Comments
 (0)