Skip to content

Commit 6d89f65

Browse files
committed
Add JWS utility
1 parent bcb5314 commit 6d89f65

File tree

3 files changed

+168
-0
lines changed

3 files changed

+168
-0
lines changed

.github/workflows/compile-examples.yml

+6
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ jobs:
102102
platforms: |
103103
# Install Arduino mbed_nano Boards via Boards Manager
104104
- name: arduino:mbed_nicla
105+
libraries: |
106+
- name: ArduinoECCX08
105107
- board:
106108
platform-name: arduino:mbed_opta
107109
platforms: |
@@ -121,11 +123,15 @@ jobs:
121123
platforms: |
122124
# Install Arduino renesas_portenta Boards via Boards Manager
123125
- name: arduino:renesas_portenta
126+
libraries: |
127+
- name: ArduinoECCX08
124128
- board:
125129
platform-name: arduino:renesas_uno
126130
platforms: |
127131
# Install Arduino renesas_uno Boards via Boards Manager
128132
- name: arduino:renesas_uno
133+
libraries: |
134+
- name: ArduinoECCX08
129135
130136
steps:
131137
- name: Checkout

src/utility/SElementJWS.cpp

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
This file is part of the Arduino_SecureElement library.
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+
15+
#include <utility/SElementJWS.h>
16+
#include <ArduinoECCX08.h>
17+
#include <utility/ASN1Utils.h>
18+
#include <utility/PEMUtils.h>
19+
20+
static String base64urlEncode(const byte in[], unsigned int length)
21+
{
22+
static const char* CODES = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=";
23+
24+
int b;
25+
String out;
26+
27+
int reserveLength = 4 * ((length + 2) / 3);
28+
out.reserve(reserveLength);
29+
30+
for (unsigned int i = 0; i < length; i += 3) {
31+
b = (in[i] & 0xFC) >> 2;
32+
out += CODES[b];
33+
34+
b = (in[i] & 0x03) << 4;
35+
if (i + 1 < length) {
36+
b |= (in[i + 1] & 0xF0) >> 4;
37+
out += CODES[b];
38+
b = (in[i + 1] & 0x0F) << 2;
39+
if (i + 2 < length) {
40+
b |= (in[i + 2] & 0xC0) >> 6;
41+
out += CODES[b];
42+
b = in[i + 2] & 0x3F;
43+
out += CODES[b];
44+
} else {
45+
out += CODES[b];
46+
}
47+
} else {
48+
out += CODES[b];
49+
}
50+
}
51+
52+
while (out.lastIndexOf('=') != -1) {
53+
out.remove(out.length() - 1);
54+
}
55+
56+
return out;
57+
}
58+
59+
String SElementJWS::publicKey(SecureElement & se, int slot, bool newPrivateKey)
60+
{
61+
if (slot < 0 || slot > 8) {
62+
return "";
63+
}
64+
65+
byte publicKey[64];
66+
67+
if (newPrivateKey) {
68+
if (!se.generatePrivateKey(slot, publicKey)) {
69+
return "";
70+
}
71+
} else {
72+
if (!se.generatePublicKey(slot, publicKey)) {
73+
return "";
74+
}
75+
}
76+
77+
int length = ASN1Utils.publicKeyLength();
78+
byte out[length];
79+
80+
ASN1Utils.appendPublicKey(publicKey, out);
81+
82+
return PEMUtils.base64Encode(out, length, "-----BEGIN PUBLIC KEY-----\n", "\n-----END PUBLIC KEY-----\n");
83+
}
84+
85+
String SElementJWS::sign(SecureElement & se, int slot, const char* header, const char* payload)
86+
{
87+
if (slot < 0 || slot > 8) {
88+
return "";
89+
}
90+
91+
String encodedHeader = base64urlEncode((const byte*)header, strlen(header));
92+
String encodedPayload = base64urlEncode((const byte*)payload, strlen(payload));
93+
94+
String toSign;
95+
toSign.reserve(encodedHeader.length() + 1 + encodedPayload.length());
96+
97+
toSign += encodedHeader;
98+
toSign += '.';
99+
toSign += encodedPayload;
100+
101+
102+
byte toSignSha256[32];
103+
byte signature[64];
104+
105+
se.SHA256((const uint8_t*)toSign.c_str(), toSign.length(), toSignSha256);
106+
107+
if (!se.ecSign(slot, toSignSha256, signature)) {
108+
return "";
109+
}
110+
111+
String encodedSignature = base64urlEncode(signature, sizeof(signature));
112+
113+
String result;
114+
result.reserve(toSign.length() + 1 + encodedSignature.length());
115+
116+
result += toSign;
117+
result += '.';
118+
result += encodedSignature;
119+
120+
return result;
121+
}
122+
123+
String SElementJWS::sign(SecureElement & se, int slot, const String& header, const String& payload)
124+
{
125+
return sign(se, slot, header.c_str(), payload.c_str());
126+
}

src/utility/SElementJWS.h

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
This file is part of the Arduino_SecureElement library.
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 SECURE_ELEMENT_JWS_H_
12+
#define SECURE_ELEMENT_JWS_H_
13+
14+
/******************************************************************************
15+
* INCLUDE
16+
******************************************************************************/
17+
18+
#include <Arduino_SecureElement.h>
19+
20+
/******************************************************************************
21+
* CLASS DECLARATION
22+
******************************************************************************/
23+
24+
class SElementJWS
25+
{
26+
public:
27+
28+
String publicKey(SecureElement & se, int slot, bool newPrivateKey = true);
29+
30+
String sign(SecureElement & se, int slot, const char* header, const char* payload);
31+
String sign(SecureElement & se, int slot, const String& header, const String& payload);
32+
33+
};
34+
35+
36+
#endif /* SECURE_ELEMENT_JWS_H_ */

0 commit comments

Comments
 (0)