Skip to content

Commit 771aab9

Browse files
committed
Add Software Secure Element module
- This module emulates what an hardware secure element does. It is not really secure. Data is stored in plaintext
1 parent aefbe0f commit 771aab9

File tree

6 files changed

+841
-0
lines changed

6 files changed

+841
-0
lines changed

UNOR4USBBridge/SSE.cpp

Lines changed: 353 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,353 @@
1+
/*
2+
This file is part of the UNOR4USBBridge project.
3+
4+
Copyright (c) 2024 Arduino SA
5+
6+
This Source Code Form is subject to the terms of the Mozilla Public
7+
License, v. 2.0. If a copy of the MPL was not distributed with this
8+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
11+
/******************************************************************************
12+
INCLUDE
13+
******************************************************************************/
14+
#include <Arduino_DebugUtils.h>
15+
#include <Preferences.h>
16+
17+
#include "mbedtls/pk.h"
18+
#include "mbedtls/ctr_drbg.h"
19+
#include "mbedtls/entropy.h"
20+
21+
#include "mbedtls/error.h"
22+
#include "mbedtls/asn1.h"
23+
#include "mbedtls/asn1write.h"
24+
#include "mbedtls/sha256.h"
25+
26+
#include "SSE.h"
27+
28+
extern Preferences pref;
29+
30+
// New implementation from mbedtls not merged https://github.com/Mbed-TLS/mbedtls/pull/8703/files
31+
32+
/*
33+
* https://github.com/Mbed-TLS/mbedtls/blob/aa3fa98bc4a99d21a973b891bf7bda9a27647068/library/pk_wrap.c#L543
34+
* An ASN.1 encoded signature is a sequence of two ASN.1 integers. Parse one of
35+
* those integers and convert it to the fixed-length encoding expected by PSA.
36+
*/
37+
static int extract_ecdsa_sig_int(unsigned char **from, const unsigned char *end,
38+
unsigned char *to, size_t to_len)
39+
{
40+
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
41+
size_t unpadded_len, padding_len;
42+
43+
if ((ret = mbedtls_asn1_get_tag(from, end, &unpadded_len,
44+
MBEDTLS_ASN1_INTEGER)) != 0) {
45+
return ret;
46+
}
47+
48+
while (unpadded_len > 0 && **from == 0x00) {
49+
(*from)++;
50+
unpadded_len--;
51+
}
52+
53+
if (unpadded_len > to_len || unpadded_len == 0) {
54+
return MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
55+
}
56+
57+
padding_len = to_len - unpadded_len;
58+
memset(to, 0x00, padding_len);
59+
memcpy(to + padding_len, *from, unpadded_len);
60+
(*from) += unpadded_len;
61+
62+
return 0;
63+
}
64+
65+
/*
66+
* https://github.com/Mbed-TLS/mbedtls/blob/aa3fa98bc4a99d21a973b891bf7bda9a27647068/library/pk_wrap.c#L576
67+
* Convert a signature from an ASN.1 sequence of two integers
68+
* to a raw {r,s} buffer. Note: the provided sig buffer must be at least
69+
* twice as big as int_size.
70+
*/
71+
static int extract_ecdsa_sig(unsigned char **p, const unsigned char *end,
72+
unsigned char *sig, size_t int_size)
73+
{
74+
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
75+
size_t tmp_size;
76+
77+
if ((ret = mbedtls_asn1_get_tag(p, end, &tmp_size,
78+
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
79+
return ret;
80+
}
81+
82+
/* Extract r */
83+
if ((ret = extract_ecdsa_sig_int(p, end, sig, int_size)) != 0) {
84+
return ret;
85+
}
86+
/* Extract s */
87+
if ((ret = extract_ecdsa_sig_int(p, end, sig + int_size, int_size)) != 0) {
88+
return ret;
89+
}
90+
91+
return 0;
92+
}
93+
94+
/*
95+
* https://github.com/Mbed-TLS/mbedtls/blob/47c74a477378ec3f0d1ba80547db836e078fa3a0/library/ecdsa.c#L609
96+
* Convert a signature (given by context) to ASN.1
97+
*/
98+
static int ecdsa_signature_to_asn1(const mbedtls_mpi *r, const mbedtls_mpi *s,
99+
unsigned char *sig, size_t sig_size,
100+
size_t *slen)
101+
{
102+
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
103+
unsigned char buf[MBEDTLS_ECDSA_MAX_LEN] = { 0 };
104+
unsigned char *p = buf + sizeof(buf);
105+
size_t len = 0;
106+
107+
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_mpi(&p, buf, s));
108+
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_mpi(&p, buf, r));
109+
110+
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&p, buf, len));
111+
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&p, buf,
112+
MBEDTLS_ASN1_CONSTRUCTED |
113+
MBEDTLS_ASN1_SEQUENCE));
114+
115+
if (len > sig_size) {
116+
return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
117+
}
118+
119+
memcpy(sig, p, len);
120+
*slen = len;
121+
122+
return 0;
123+
}
124+
125+
126+
/******************************************************************************
127+
PUBLIC MEMBER FUNCTIONS
128+
******************************************************************************/
129+
130+
int Arduino_UNOWIFIR4_SSE::generateECKeyPair(unsigned char* der, int maxLen)
131+
{
132+
int ret = 1;
133+
mbedtls_pk_context key;
134+
mbedtls_ctr_drbg_context ctr_drbg;
135+
mbedtls_entropy_context entropy;
136+
const char *pers = "gen_key";
137+
unsigned char tmp[128] = {0};
138+
139+
mbedtls_pk_init(&key);
140+
mbedtls_entropy_init(&entropy);
141+
mbedtls_ctr_drbg_init(&ctr_drbg);
142+
143+
if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) pers, strlen(pers))) != 0) {
144+
DEBUG_ERROR(" failed\n ! mbedtls_ctr_drbg_seed returned -0x%04x\n", (unsigned int) -ret);
145+
goto exit;
146+
}
147+
148+
if ((ret = mbedtls_pk_setup(&key, mbedtls_pk_info_from_type((mbedtls_pk_type_t) MBEDTLS_PK_ECKEY))) != 0) {
149+
DEBUG_ERROR(" failed\n ! mbedtls_pk_setup returned -0x%04x", (unsigned int) -ret);
150+
goto exit;
151+
}
152+
153+
if ((ret = mbedtls_ecp_gen_key((mbedtls_ecp_group_id) MBEDTLS_ECP_DP_SECP256R1, mbedtls_pk_ec(key), mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) {
154+
DEBUG_ERROR(" failed\n ! mbedtls_ecp_gen_key returned -0x%04x", (unsigned int) -ret);
155+
goto exit;
156+
}
157+
158+
if ((ret = mbedtls_pk_write_key_der(&key, tmp, sizeof(tmp))) < 0) {
159+
DEBUG_ERROR(" failed\n ! mbedtls_pk_write_key_der returned -0x%04x", (unsigned int) -ret);
160+
goto exit;
161+
}
162+
163+
memcpy(der, &tmp[sizeof(tmp)- ret], ret);
164+
165+
exit:
166+
mbedtls_ctr_drbg_free(&ctr_drbg);
167+
mbedtls_entropy_free(&entropy);
168+
mbedtls_pk_free(&key);
169+
170+
return ret;
171+
}
172+
173+
int Arduino_UNOWIFIR4_SSE::exportECKeyXY(const unsigned char* der, int len, uint8_t publicKey[])
174+
{
175+
int ret = 1;
176+
mbedtls_pk_context key;
177+
mbedtls_ecp_keypair *ecp;
178+
179+
mbedtls_pk_init(&key);
180+
181+
/* Check if we can use parse public key */
182+
if ((ret = mbedtls_pk_parse_key(&key, der, len, NULL, 0)) != 0) {
183+
DEBUG_ERROR(" failed\n ! mbedtls_pk_parse_key returned -0x%04x", (unsigned int) -ret);
184+
goto exit;
185+
}
186+
187+
if (mbedtls_pk_get_type(&key) != MBEDTLS_PK_ECKEY) {
188+
DEBUG_ERROR(" failed\n ! Not an EC KEY");
189+
goto exit;
190+
}
191+
192+
/* Get elliptic curve point */
193+
ecp = mbedtls_pk_ec(key);
194+
mbedtls_mpi_write_binary(&ecp->Q.X, &publicKey[0], 32);
195+
mbedtls_mpi_write_binary(&ecp->Q.Y, &publicKey[32], 32);
196+
ret = 64;
197+
198+
exit:
199+
mbedtls_pk_free(&key);
200+
return ret;
201+
}
202+
203+
int Arduino_UNOWIFIR4_SSE::importECKeyXY(uint8_t publicKey[], unsigned char* der, int len)
204+
{
205+
int ret = 1;
206+
mbedtls_pk_context key;
207+
unsigned char tmp[128] = {0};
208+
mbedtls_ecp_keypair* ecp;
209+
210+
mbedtls_pk_init(&key);
211+
212+
if ((ret = mbedtls_pk_setup(&key, mbedtls_pk_info_from_type((mbedtls_pk_type_t) MBEDTLS_PK_ECKEY))) != 0) {
213+
DEBUG_ERROR(" failed\n ! mbedtls_pk_setup returned -0x%04x", (unsigned int) -ret);
214+
goto exit;
215+
}
216+
217+
if (mbedtls_pk_get_type(&key) != MBEDTLS_PK_ECKEY) {
218+
DEBUG_ERROR(" failed\n ! Not an EC KEY");
219+
goto exit;
220+
}
221+
222+
ecp = mbedtls_pk_ec(key);
223+
224+
if (( ret = mbedtls_ecp_group_load(&ecp->grp, MBEDTLS_ECP_DP_SECP256R1)) != 0) {
225+
DEBUG_ERROR(" failed\n ! mbedtls_ecp_group_load returned -0x%04x", (unsigned int) -ret);
226+
goto exit;
227+
}
228+
229+
tmp[0] = 0x04;
230+
memcpy(&tmp[1], publicKey, 64);
231+
232+
if (( ret = mbedtls_ecp_point_read_binary(&ecp->grp, &ecp->Q, tmp, 65)) != 0) {
233+
DEBUG_ERROR(" failed\n ! mbedtls_ecp_point_read_binary returned -0x%04x", (unsigned int) -ret);
234+
goto exit;
235+
}
236+
237+
if ((ret = mbedtls_pk_write_pubkey_der(&key, tmp, sizeof(tmp))) < 0) {
238+
DEBUG_ERROR(" failed\n ! mbedtls_pk_write_pubkey_der returned -0x%04x", (unsigned int) -ret);
239+
goto exit;
240+
}
241+
242+
if (ret > len) {
243+
DEBUG_ERROR(" failed\n ! outlen too small -0x%04x", (unsigned int) -ret);
244+
goto exit;
245+
}
246+
memcpy(der, &tmp[sizeof(tmp)- ret], ret);
247+
248+
exit:
249+
mbedtls_pk_free(&key);
250+
return ret;
251+
}
252+
253+
int Arduino_UNOWIFIR4_SSE::sha256(const unsigned char* message, int len, unsigned char* sha256)
254+
{
255+
int ret = 1;
256+
257+
if((ret = mbedtls_sha256_ret(message, len, sha256, 0)) != 0) {
258+
DEBUG_ERROR(" failed\n ! mbedtls_sha256_ret returned -0x%04x\n", (unsigned int) -ret);
259+
return ret;
260+
}
261+
return 32;
262+
}
263+
264+
int Arduino_UNOWIFIR4_SSE::sign(const unsigned char* der, int len, const unsigned char* sha256, unsigned char* signature)
265+
{
266+
int ret = 1;
267+
mbedtls_pk_context key;
268+
mbedtls_ctr_drbg_context ctr_drbg;
269+
mbedtls_entropy_context entropy;
270+
unsigned char tmp[MBEDTLS_PK_SIGNATURE_MAX_SIZE] = {0};
271+
unsigned char * p = (unsigned char *)&tmp[0];
272+
const char *pers = "gen_key";
273+
274+
mbedtls_pk_init(&key);
275+
mbedtls_entropy_init(&entropy);
276+
mbedtls_ctr_drbg_init(&ctr_drbg);
277+
278+
if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) pers, strlen(pers))) != 0) {
279+
DEBUG_ERROR(" failed\n ! mbedtls_ctr_drbg_seed returned -0x%04x\n", (unsigned int) -ret);
280+
goto exit;
281+
}
282+
283+
/* verify if work using only private key*/
284+
if ((ret = mbedtls_pk_parse_key(&key, der, len, NULL, 0)) != 0) {
285+
DEBUG_ERROR(" failed\n ! mbedtls_pk_parse_key returned -0x%04x", (unsigned int) -ret);
286+
goto exit;
287+
}
288+
289+
size_t retSize;
290+
if ((ret = mbedtls_pk_sign(&key, MBEDTLS_MD_SHA256, sha256, 0, tmp, &retSize, mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) {
291+
DEBUG_ERROR(" failed\n ! mbedtls_pk_sign returned -0x%04x", (unsigned int) -ret);
292+
goto exit;
293+
}
294+
295+
#if SSE_DEBUG_ENABLED
296+
log_v("SSE::sign: der signature");
297+
log_buf_v(tmp, retSize);
298+
#endif
299+
300+
/* Extract {r,s} values from DER signature */
301+
extract_ecdsa_sig(&p, &tmp[retSize], signature, 32);
302+
ret = 64;
303+
304+
exit:
305+
mbedtls_ctr_drbg_free(&ctr_drbg);
306+
mbedtls_pk_free(&key);
307+
return ret;
308+
}
309+
310+
int Arduino_UNOWIFIR4_SSE::verify(const unsigned char* der, int len, const unsigned char* sha256, unsigned char* signature)
311+
{
312+
int ret = 1;
313+
mbedtls_pk_context key;
314+
unsigned char tmp[MBEDTLS_PK_SIGNATURE_MAX_SIZE] = {0};
315+
mbedtls_mpi r,s;
316+
size_t retSize = 0;
317+
318+
mbedtls_mpi_init(&r);
319+
mbedtls_mpi_init(&s);
320+
mbedtls_pk_init(&key);
321+
322+
/* Verify is only public key is needed */
323+
if ((ret = mbedtls_pk_parse_public_key(&key, der, len)) != 0) {
324+
DEBUG_ERROR(" failed\n ! mbedtls_pk_parse_public_key returned -0x%04x", (unsigned int) -ret);
325+
goto exit;
326+
}
327+
328+
#if SSE_DEBUG_ENABLED
329+
log_v("SSE::verify: sha256");
330+
log_buf_v((const uint8_t *)sha256, 32);
331+
log_v("SSE::verify: compressed signature");
332+
log_buf_v((const uint8_t *)signature, 64);
333+
#endif
334+
335+
/* Convert signature {r,s} values to DER */
336+
mbedtls_mpi_read_binary( &r, signature, 32 );
337+
mbedtls_mpi_read_binary( &s, signature + 32, 32 );
338+
ecdsa_signature_to_asn1(&r, &s, tmp, MBEDTLS_PK_SIGNATURE_MAX_SIZE, &retSize);
339+
340+
#if SSE_DEBUG_ENABLED
341+
log_v("SSE::verify: der signature");
342+
log_buf_v((const uint8_t *)tmp, retSize);
343+
#endif
344+
345+
if ((ret = mbedtls_pk_verify(&key, MBEDTLS_MD_SHA256, sha256, 32, tmp, retSize)) != 0) {
346+
DEBUG_ERROR(" failed\n ! mbedtls_pk_verify returned -0x%04x", (unsigned int) -ret);
347+
goto exit;
348+
}
349+
350+
exit:
351+
mbedtls_pk_free(&key);
352+
return ret;
353+
}

UNOR4USBBridge/SSE.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
This file is part of the UNOR4USBBridge project.
3+
4+
Copyright (c) 2024 Arduino SA
5+
6+
This Source Code Form is subject to the terms of the Mozilla Public
7+
License, v. 2.0. If a copy of the MPL was not distributed with this
8+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
11+
#ifndef ARDUINO_UNOWIFIR4_SSE_H_
12+
#define ARDUINO_UNOWIFIR4_SSE_H_
13+
14+
#define SSE_DEBUG_ENABLED 0
15+
16+
/******************************************************************************
17+
* CLASS DECLARATION
18+
******************************************************************************/
19+
20+
class Arduino_UNOWIFIR4_SSE
21+
{
22+
23+
public:
24+
static int generateECKeyPair(unsigned char* der, int maxLen);
25+
static int exportECKeyXY(const unsigned char* der, int len, uint8_t publicKey[]);
26+
static int importECKeyXY(uint8_t publicKey[], unsigned char* der, int len);
27+
static int sign(const unsigned char* der, int len, const unsigned char* sha256, unsigned char* signature);
28+
static int verify(const unsigned char* der, int len, const unsigned char* sha256, unsigned char* signature);
29+
static int sha256(const unsigned char* message, int len, unsigned char* sha256);
30+
31+
};
32+
33+
#endif /* Arduino_UNOWIFIR4_SSE */

0 commit comments

Comments
 (0)