Skip to content

Commit ec3dea2

Browse files
valeriosettinashif
authored andcommitted
jwt: reshape and add alternative for ECDSA using PSA
This commit: - creates 2 new files, jwt_ecdsa.c and jwt_rsa.c, to hold the implementations of the corresponding ECDSA/RSA signature algorithms; - RSA signature is stil done through Mbed TLS's PK module which can optionally make use of PSA (if enabled); - ECDSA signature will instead use PSA, if possible, or TinyCrypt as fallback. Signed-off-by: Valerio Setti <[email protected]>
1 parent c60d060 commit ec3dea2

File tree

7 files changed

+276
-124
lines changed

7 files changed

+276
-124
lines changed

subsys/jwt/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,9 @@
22

33
zephyr_library()
44
zephyr_library_sources(jwt.c)
5+
6+
zephyr_library_sources_ifdef(CONFIG_JWT_SIGN_ECDSA_LEGACY jwt_legacy_ecdsa.c)
7+
zephyr_library_sources_ifdef(CONFIG_JWT_SIGN_RSA_LEGACY jwt_legacy_rsa.c)
8+
zephyr_library_sources_ifdef(CONFIG_JWT_USE_PSA jwt_psa.c)
9+
510
zephyr_library_link_libraries_ifdef(CONFIG_MBEDTLS mbedTLS)

subsys/jwt/Kconfig

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Copyright (c) 2018 Linaro
2+
# Copyright (c) 2024 BayLibre SAS
23
# SPDX-License-Identifier: Apache-2.0
34

45
menuconfig JWT
@@ -7,27 +8,73 @@ menuconfig JWT
78
help
89
Enable creation of JWT tokens
910

11+
if JWT
12+
1013
choice
1114
prompt "JWT signature algorithm"
1215
default JWT_SIGN_RSA
13-
depends on JWT
1416
help
1517
Select which algorithm to use for signing JWT tokens.
1618

1719
config JWT_SIGN_RSA
1820
bool "Use RSA signature (RS-256)"
19-
depends on CSPRNG_ENABLED
20-
select MBEDTLS
21-
select MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
22-
select PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY if PSA_CRYPTO_CLIENT
23-
select PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT if PSA_CRYPTO_CLIENT
2421

2522
config JWT_SIGN_ECDSA
2623
bool "Use ECDSA signature (ES-256)"
24+
25+
endchoice
26+
27+
choice
28+
default JWT_USE_PSA
29+
prompt "Select crypto library to be used"
30+
31+
config JWT_USE_PSA
32+
bool "PSA crypto API library"
33+
select MBEDTLS if !BUILD_WITH_TFM
34+
select MBEDTLS_PSA_CRYPTO_C if !BUILD_WITH_TFM
35+
36+
config JWT_USE_LEGACY
37+
bool "Legacy library: TinyCrypt for ECDSA, Mbed TLS for RSA"
38+
39+
endchoice
40+
41+
# Prompless Kconfigs to effectively select which algorithm and library will be used
42+
# to sign the JWT. User's selections on the above choices will determine which
43+
# element will be picked here.
44+
config JWT_SIGN_ECDSA_PSA
45+
bool
46+
default y
47+
depends on JWT_SIGN_ECDSA && JWT_USE_PSA
48+
select PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT
49+
select PSA_WANT_ALG_ECDSA
50+
select PSA_WANT_ECC_SECP_R1_256
51+
select PSA_WANT_ALG_SHA_256
52+
53+
config JWT_SIGN_ECDSA_LEGACY
54+
bool
55+
default y
56+
depends on JWT_SIGN_ECDSA && JWT_USE_LEGACY
2757
select TINYCRYPT
2858
select TINYCRYPT_SHA256
2959
select TINYCRYPT_ECC_DSA
3060
select TINYCRYPT_CTR_PRNG
3161
select TINYCRYPT_AES
3262

33-
endchoice
63+
config JWT_SIGN_RSA_PSA
64+
bool
65+
default y
66+
depends on JWT_SIGN_RSA && JWT_USE_PSA
67+
select PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY
68+
select PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT
69+
select PSA_WANT_ALG_RSA_PKCS1V15_SIGN
70+
select PSA_WANT_ALG_SHA_256
71+
72+
config JWT_SIGN_RSA_LEGACY
73+
bool
74+
default y
75+
depends on JWT_SIGN_RSA && JWT_USE_LEGACY
76+
depends on CSPRNG_ENABLED
77+
select MBEDTLS
78+
select MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
79+
80+
endif # JWT

subsys/jwt/jwt.c

Lines changed: 13 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (C) 2018 Linaro Ltd
3+
* Copyright (C) 2024 BayLibre SAS
34
*
45
* SPDX-License-Identifier: Apache-2.0
56
*/
@@ -11,20 +12,12 @@
1112
#include <zephyr/data/jwt.h>
1213
#include <zephyr/data/json.h>
1314

14-
#ifdef CONFIG_JWT_SIGN_RSA
15-
#include <mbedtls/pk.h>
16-
#include <mbedtls/rsa.h>
17-
#include <mbedtls/sha256.h>
18-
#include <zephyr/random/random.h>
19-
#endif
15+
#include "jwt.h"
2016

21-
#ifdef CONFIG_JWT_SIGN_ECDSA
22-
#include <tinycrypt/ctr_prng.h>
23-
#include <tinycrypt/sha256.h>
24-
#include <tinycrypt/ecc_dsa.h>
25-
#include <tinycrypt/constants.h>
26-
27-
#include <zephyr/random/random.h>
17+
#if defined(CONFIG_JWT_SIGN_RSA)
18+
#define JWT_SIGNATURE_LEN 256
19+
#else /* CONFIG_JWT_SIGN_ECDSA */
20+
#define JWT_SIGNATURE_LEN 64
2821
#endif
2922

3023
/*
@@ -153,8 +146,7 @@ static int jwt_add_header(struct jwt_builder *builder)
153146
#ifdef CONFIG_JWT_SIGN_RSA
154147
/* {"alg":"RS256","typ":"JWT"} */
155148
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9";
156-
#endif
157-
#ifdef CONFIG_JWT_SIGN_ECDSA
149+
#else /* CONFIG_JWT_SIGN_ECDSA */
158150
/* {"alg":"ES256","typ":"JWT"} */
159151
"eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9";
160152
#endif
@@ -190,120 +182,24 @@ int jwt_add_payload(struct jwt_builder *builder,
190182
return res;
191183
}
192184

193-
#ifdef CONFIG_JWT_SIGN_RSA
194-
195-
static int csprng_wrapper(void *ctx, unsigned char *dest, size_t size)
196-
{
197-
ARG_UNUSED(ctx);
198-
199-
return sys_csrand_get((void *)dest, size);
200-
}
201-
202-
int jwt_sign(struct jwt_builder *builder,
203-
const char *der_key,
204-
size_t der_key_len)
205-
{
206-
int res;
207-
mbedtls_pk_context ctx;
208-
209-
mbedtls_pk_init(&ctx);
210-
211-
res = mbedtls_pk_parse_key(&ctx, der_key, der_key_len,
212-
NULL, 0, csprng_wrapper, NULL);
213-
if (res != 0) {
214-
return res;
215-
}
216-
217-
uint8_t hash[32], sig[256];
218-
size_t sig_len = sizeof(sig);
219-
220-
/*
221-
* The '0' indicates to mbedtls to do a SHA256, instead of
222-
* 224.
223-
*/
224-
mbedtls_sha256(builder->base, builder->buf - builder->base,
225-
hash, 0);
226-
227-
res = mbedtls_pk_sign(&ctx, MBEDTLS_MD_SHA256,
228-
hash, sizeof(hash),
229-
sig, sig_len, &sig_len,
230-
csprng_wrapper, NULL);
231-
if (res != 0) {
232-
return res;
233-
}
234-
235-
base64_outch(builder, '.');
236-
base64_append_bytes(sig, sig_len, builder);
237-
base64_flush(builder);
238-
239-
return builder->overflowed ? -ENOMEM : 0;
240-
}
241-
#endif
242-
243-
#ifdef CONFIG_JWT_SIGN_ECDSA
244-
static TCCtrPrng_t prng_state;
245-
static bool prng_init;
246-
247-
static const char personalize[] = "zephyr:drivers/jwt/jwt.c";
248-
249-
static int setup_prng(void)
250-
{
251-
if (prng_init) {
252-
return 0;
253-
}
254-
prng_init = true;
255-
256-
uint8_t entropy[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
257-
258-
sys_rand_get(entropy, sizeof(entropy));
259-
260-
int res = tc_ctr_prng_init(&prng_state,
261-
(const uint8_t *) &entropy, sizeof(entropy),
262-
personalize,
263-
sizeof(personalize));
264-
265-
return res == TC_CRYPTO_SUCCESS ? 0 : -EINVAL;
266-
}
267-
268-
int default_CSPRNG(uint8_t *dest, unsigned int size)
269-
{
270-
int res = tc_ctr_prng_generate(&prng_state, NULL, 0, dest, size);
271-
return res;
272-
}
273-
274185
int jwt_sign(struct jwt_builder *builder,
275186
const char *der_key,
276187
size_t der_key_len)
277188
{
278-
struct tc_sha256_state_struct ctx;
279-
uint8_t hash[32], sig[64];
280-
int res;
281-
282-
tc_sha256_init(&ctx);
283-
tc_sha256_update(&ctx, builder->base, builder->buf - builder->base);
284-
tc_sha256_final(hash, &ctx);
189+
int ret;
190+
unsigned char sig[JWT_SIGNATURE_LEN];
285191

286-
res = setup_prng();
287-
288-
if (res != 0) {
289-
return res;
290-
}
291-
uECC_set_rng(&default_CSPRNG);
292-
293-
/* Note that tinycrypt only supports P-256. */
294-
res = uECC_sign(der_key, hash, sizeof(hash),
295-
sig, &curve_secp256r1);
296-
if (res != TC_CRYPTO_SUCCESS) {
297-
return -EINVAL;
192+
ret = jwt_sign_impl(builder, der_key, der_key_len, sig, sizeof(sig));
193+
if (ret < 0) {
194+
return ret;
298195
}
299196

300197
base64_outch(builder, '.');
301198
base64_append_bytes(sig, sizeof(sig), builder);
302199
base64_flush(builder);
303200

304-
return 0;
201+
return builder->overflowed ? -ENOMEM : 0;
305202
}
306-
#endif
307203

308204
int jwt_init_builder(struct jwt_builder *builder,
309205
char *buffer,

subsys/jwt/jwt.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
* Copyright (C) 2024 BayLibre SAS
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_SUBSYS_JWT_JWT_H_
8+
#define ZEPHYR_SUBSYS_JWT_JWT_H_
9+
10+
#include <zephyr/data/jwt.h>
11+
12+
int jwt_sign_impl(struct jwt_builder *builder, const unsigned char *der_key,
13+
size_t der_key_len, unsigned char *sig, size_t sig_size);
14+
15+
#endif /* ZEPHYR_SUBSYS_JWT_JWT_H_ */

subsys/jwt/jwt_legacy_ecdsa.c

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Copyright (C) 2024 BayLibre SAS
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <string.h>
8+
#include <zephyr/types.h>
9+
#include <errno.h>
10+
11+
#include <zephyr/data/jwt.h>
12+
#include <zephyr/data/json.h>
13+
#include <zephyr/random/random.h>
14+
15+
#include <tinycrypt/ctr_prng.h>
16+
#include <tinycrypt/sha256.h>
17+
#include <tinycrypt/ecc_dsa.h>
18+
#include <tinycrypt/constants.h>
19+
20+
#include "jwt.h"
21+
22+
static TCCtrPrng_t prng_state;
23+
static bool prng_init;
24+
25+
static const char personalize[] = "zephyr:drivers/jwt/jwt.c";
26+
27+
static int setup_prng(void)
28+
{
29+
if (prng_init) {
30+
return 0;
31+
}
32+
prng_init = true;
33+
34+
uint8_t entropy[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
35+
36+
sys_rand_get(entropy, sizeof(entropy));
37+
38+
int res = tc_ctr_prng_init(&prng_state, (const uint8_t *)&entropy, sizeof(entropy),
39+
personalize, sizeof(personalize));
40+
41+
return res == TC_CRYPTO_SUCCESS ? 0 : -EINVAL;
42+
}
43+
44+
/* This function is declared in
45+
* modules/crypto/tinycrypt/lib/include/tinycrypt/ecc_platform_specific.h.
46+
*
47+
* TinyCrypt expects this function to be implemented somewhere when using the
48+
* ECC module.
49+
*/
50+
int default_CSPRNG(uint8_t *dest, unsigned int size)
51+
{
52+
int res = tc_ctr_prng_generate(&prng_state, NULL, 0, dest, size);
53+
return res;
54+
}
55+
56+
int jwt_sign_impl(struct jwt_builder *builder, const unsigned char *der_key, size_t der_key_len,
57+
unsigned char *sig, size_t sig_size)
58+
{
59+
struct tc_sha256_state_struct ctx;
60+
uint8_t hash[32];
61+
int res;
62+
63+
ARG_UNUSED(sig_size);
64+
65+
tc_sha256_init(&ctx);
66+
tc_sha256_update(&ctx, builder->base, builder->buf - builder->base);
67+
tc_sha256_final(hash, &ctx);
68+
69+
res = setup_prng();
70+
71+
if (res != 0) {
72+
return res;
73+
}
74+
75+
/* Note that tinycrypt only supports P-256. */
76+
res = uECC_sign(der_key, hash, sizeof(hash), sig, &curve_secp256r1);
77+
if (res != TC_CRYPTO_SUCCESS) {
78+
return -EINVAL;
79+
}
80+
81+
return 0;
82+
}

0 commit comments

Comments
 (0)