Skip to content

Commit 89fc33d

Browse files
committed
Add JWS support utilty and setup sketch
1 parent 7db43f9 commit 89fc33d

File tree

3 files changed

+319
-0
lines changed

3 files changed

+319
-0
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
ArduinoECCX08 - JWS Public Key
3+
4+
This sketch can be used to generate a PEM public key for a private key
5+
generated in an ECC508/ECC608 crypto chip slot.
6+
7+
If the ECC508/ECC608 is not configured and locked it prompts
8+
the user to configure and lock the chip with a default TLS
9+
configuration.
10+
11+
The user can also select a slot number to use for the private key
12+
A new private key can also be generated in this slot.
13+
14+
The circuit:
15+
- Arduino MKR board equipped with ECC508 or ECC608 chip
16+
17+
This example code is in the public domain.
18+
*/
19+
20+
#include <ArduinoECCX08.h>
21+
#include <utility/ECCX08JWS.h>
22+
#include <utility/ECCX08DefaultTLSConfig.h>
23+
24+
void setup() {
25+
Serial.begin(9600);
26+
while (!Serial);
27+
28+
if (!ECCX08.begin()) {
29+
Serial.println("No ECCX08 present!");
30+
while (1);
31+
}
32+
33+
if (!ECCX08.locked()) {
34+
String lock = promptAndReadLine("The ECCX08 on your board is not locked, would you like to PERMANENTLY configure and lock it now? (y/N)", "N");
35+
lock.toLowerCase();
36+
37+
if (!lock.startsWith("y")) {
38+
Serial.println("Unfortunately you can't proceed without locking it :(");
39+
while (1);
40+
}
41+
42+
if (!ECCX08.writeConfiguration(ECCX08_DEFAULT_TLS_CONFIG)) {
43+
Serial.println("Writing ECCX08 configuration failed!");
44+
while (1);
45+
}
46+
47+
if (!ECCX08.lock()) {
48+
Serial.println("Locking ECCX08 configuration failed!");
49+
while (1);
50+
}
51+
52+
Serial.println("ECCX08 locked successfully");
53+
Serial.println();
54+
}
55+
56+
Serial.println("Hi there, in order to generate a PEM public key for your board, we'll need the following information ...");
57+
Serial.println();
58+
59+
String slot = promptAndReadLine("What slot would you like to use? (0 - 4)", "0");
60+
String generateNewKey = promptAndReadLine("Would you like to generate a new private key? (Y/n)", "Y");
61+
62+
Serial.println();
63+
64+
generateNewKey.toLowerCase();
65+
66+
String publicKeyPem = ECCX08JWS.publicKey(slot.toInt(), generateNewKey.startsWith("y"));
67+
68+
if (!publicKeyPem || publicKeyPem == "") {
69+
Serial.println("Error generating public key!");
70+
while (1);
71+
}
72+
73+
Serial.println("Here's your public key PEM, enjoy!");
74+
Serial.println();
75+
Serial.println(publicKeyPem);
76+
}
77+
78+
void loop() {
79+
// do nothing
80+
}
81+
82+
String promptAndReadLine(const char* prompt, const char* defaultValue) {
83+
Serial.print(prompt);
84+
Serial.print(" [");
85+
Serial.print(defaultValue);
86+
Serial.print("]: ");
87+
88+
String s = readLine();
89+
90+
if (s.length() == 0) {
91+
s = defaultValue;
92+
}
93+
94+
Serial.println(s);
95+
96+
return s;
97+
}
98+
99+
String readLine() {
100+
String line;
101+
102+
while (1) {
103+
if (Serial.available()) {
104+
char c = Serial.read();
105+
106+
if (c == '\r') {
107+
// ignore
108+
continue;
109+
} else if (c == '\n') {
110+
break;
111+
}
112+
113+
line += c;
114+
}
115+
}
116+
117+
return line;
118+
}

src/utility/ECCX08JWS.cpp

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*
2+
This file is part of the ArduinoECCX08 library.
3+
Copyright (c) 2019 Arduino SA. All rights reserved.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
#include "ECCX08.h"
21+
22+
#include "ASN1Utils.h"
23+
#include "PEMUtils.h"
24+
25+
#include "ECCX08JWS.h"
26+
27+
static String base64urlEncode(const byte in[], unsigned int length)
28+
{
29+
static const char* CODES = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=";
30+
31+
int b;
32+
String out;
33+
34+
int reserveLength = 4 * ((length + 2) / 3);
35+
out.reserve(reserveLength);
36+
37+
for (unsigned int i = 0; i < length; i += 3) {
38+
b = (in[i] & 0xFC) >> 2;
39+
out += CODES[b];
40+
41+
b = (in[i] & 0x03) << 4;
42+
if (i + 1 < length) {
43+
b |= (in[i + 1] & 0xF0) >> 4;
44+
out += CODES[b];
45+
b = (in[i + 1] & 0x0F) << 2;
46+
if (i + 2 < length) {
47+
b |= (in[i + 2] & 0xC0) >> 6;
48+
out += CODES[b];
49+
b = in[i + 2] & 0x3F;
50+
out += CODES[b];
51+
} else {
52+
out += CODES[b];
53+
}
54+
} else {
55+
out += CODES[b];
56+
}
57+
}
58+
59+
while (out.lastIndexOf('=') != -1) {
60+
out.remove(out.length() - 1);
61+
}
62+
63+
return out;
64+
}
65+
66+
ECCX08JWSClass::ECCX08JWSClass()
67+
{
68+
}
69+
70+
ECCX08JWSClass::~ECCX08JWSClass()
71+
{
72+
}
73+
74+
String ECCX08JWSClass::publicKey(int slot, bool newPrivateKey)
75+
{
76+
if (slot < 0 || slot > 8) {
77+
return "";
78+
}
79+
80+
byte publicKey[64];
81+
82+
if (newPrivateKey) {
83+
if (!ECCX08.generatePrivateKey(slot, publicKey)) {
84+
return "";
85+
}
86+
} else {
87+
if (!ECCX08.generatePublicKey(slot, publicKey)) {
88+
return "";
89+
}
90+
}
91+
92+
int length = ASN1Utils.publicKeyLength();
93+
byte out[length];
94+
95+
ASN1Utils.appendPublicKey(publicKey, out);
96+
97+
return PEMUtils.base64Encode(out, length, "-----BEGIN PUBLIC KEY-----\n", "\n-----END PUBLIC KEY-----\n");
98+
}
99+
100+
String ECCX08JWSClass::sign(int slot, const char* header, const char* payload)
101+
{
102+
if (slot < 0 || slot > 8) {
103+
return "";
104+
}
105+
106+
String encodedHeader = base64urlEncode((const byte*)header, strlen(header));
107+
String encodedPayload = base64urlEncode((const byte*)payload, strlen(payload));
108+
109+
String toSign;
110+
toSign.reserve(encodedHeader.length() + 1 + encodedPayload.length());
111+
112+
toSign += encodedHeader;
113+
toSign += '.';
114+
toSign += encodedPayload;
115+
116+
117+
byte toSignSha256[32];
118+
byte signature[64];
119+
120+
if (!ECCX08.beginSHA256()) {
121+
return "";
122+
}
123+
124+
for (unsigned int i = 0; i < toSign.length(); i += 64) {
125+
int chunkLength = toSign.length() - i;
126+
127+
if (chunkLength > 64) {
128+
chunkLength = 64;
129+
}
130+
131+
if (chunkLength == 64) {
132+
if (!ECCX08.updateSHA256((const byte*)toSign.c_str() + i)) {
133+
return "";
134+
}
135+
} else {
136+
if (!ECCX08.endSHA256((const byte*)toSign.c_str() + i, chunkLength, toSignSha256)) {
137+
return "";
138+
}
139+
}
140+
}
141+
142+
if (!ECCX08.ecSign(slot, toSignSha256, signature)) {
143+
return "";
144+
}
145+
146+
String encodedSignature = base64urlEncode(signature, sizeof(signature));
147+
148+
String result;
149+
result.reserve(toSign.length() + 1 + encodedSignature.length());
150+
151+
result += toSign;
152+
result += '.';
153+
result += encodedSignature;
154+
155+
return result;
156+
}
157+
158+
String ECCX08JWSClass::sign(int slot, const String& header, const String& payload)
159+
{
160+
return sign(slot, header.c_str(), payload.c_str());
161+
}
162+
163+
ECCX08JWSClass ECCX08JWS;

src/utility/ECCX08JWS.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
This file is part of the ArduinoECCX08 library.
3+
Copyright (c) 2019 Arduino SA. All rights reserved.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
#ifndef _ECCX08_JWS_H_
21+
#define _ECCX08_JWS_H_
22+
23+
#include <Arduino.h>
24+
25+
class ECCX08JWSClass {
26+
public:
27+
ECCX08JWSClass();
28+
virtual ~ECCX08JWSClass();
29+
30+
String publicKey(int slot, bool newPrivateKey = true);
31+
32+
String sign(int slot, const char* header, const char* payload);
33+
String sign(int slot, const String& header, const String& payload);
34+
};
35+
36+
extern ECCX08JWSClass ECCX08JWS;
37+
38+
#endif

0 commit comments

Comments
 (0)