Skip to content

Commit 10c52ea

Browse files
authored
Merge pull request #26 from pennam/get-cloud-jwt-no-ecc
Get cloud jwt no ecc
2 parents bcb5314 + 9ec6dc4 commit 10c52ea

8 files changed

+290
-56
lines changed

src/ECP256Certificate.cpp

+3-54
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
/* This is needed for memmem */
1616
#define _GNU_SOURCE
1717
#include <string.h>
18+
#include <utility/SElementBase64.h>
1819
#include "ECP256Certificate.h"
1920

2021
/******************************************************************************
@@ -29,58 +30,6 @@
2930
#define ASN1_SEQUENCE 0x30
3031
#define ASN1_SET 0x31
3132

32-
/******************************************************************************
33-
* LOCAL MODULE FUNCTIONS
34-
******************************************************************************/
35-
36-
static String base64Encode(const byte in[], unsigned int length, const char* prefix, const char* suffix) {
37-
static const char* CODES = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
38-
39-
int b;
40-
String out;
41-
42-
int reserveLength = 4 * ((length + 2) / 3) + ((length / 3 * 4) / 76) + strlen(prefix) + strlen(suffix);
43-
out.reserve(reserveLength);
44-
45-
if (prefix) {
46-
out += prefix;
47-
}
48-
49-
for (unsigned int i = 0; i < length; i += 3) {
50-
if (i > 0 && (i / 3 * 4) % 76 == 0) {
51-
out += '\n';
52-
}
53-
54-
b = (in[i] & 0xFC) >> 2;
55-
out += CODES[b];
56-
57-
b = (in[i] & 0x03) << 4;
58-
if (i + 1 < length) {
59-
b |= (in[i + 1] & 0xF0) >> 4;
60-
out += CODES[b];
61-
b = (in[i + 1] & 0x0F) << 2;
62-
if (i + 2 < length) {
63-
b |= (in[i + 2] & 0xC0) >> 6;
64-
out += CODES[b];
65-
b = in[i + 2] & 0x3F;
66-
out += CODES[b];
67-
} else {
68-
out += CODES[b];
69-
out += '=';
70-
}
71-
} else {
72-
out += CODES[b];
73-
out += "==";
74-
}
75-
}
76-
77-
if (suffix) {
78-
out += suffix;
79-
}
80-
81-
return out;
82-
}
83-
8433
/******************************************************************************
8534
* CTOR/DTOR
8635
******************************************************************************/
@@ -184,7 +133,7 @@ int ECP256Certificate::signCSR(byte * signature)
184133

185134
String ECP256Certificate::getCSRPEM()
186135
{
187-
return base64Encode(_certBuffer, _certBufferLen, "-----BEGIN CERTIFICATE REQUEST-----\n", "\n-----END CERTIFICATE REQUEST-----\n");
136+
return b64::pemEncode(_certBuffer, _certBufferLen, "-----BEGIN CERTIFICATE REQUEST-----\n", "\n-----END CERTIFICATE REQUEST-----\n");
188137
}
189138

190139
int ECP256Certificate::buildCert()
@@ -323,7 +272,7 @@ int ECP256Certificate::signCert()
323272

324273
String ECP256Certificate::getCertPEM()
325274
{
326-
return base64Encode(_certBuffer, _certBufferLen, "-----BEGIN CERTIFICATE-----\n", "\n-----END CERTIFICATE-----\n");
275+
return b64::pemEncode(_certBuffer, _certBufferLen, "-----BEGIN CERTIFICATE-----\n", "\n-----END CERTIFICATE-----\n");
327276
}
328277

329278
void ECP256Certificate::getDateFromCompressedData(DateInfo& date) {

src/ECP256Certificate.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@ class ECP256Certificate {
101101
/* Import DER buffer into CertClass*/
102102
int importCert(const byte certDER[], size_t derLen);
103103

104+
protected:
105+
106+
int publicKeyLength();
107+
int appendPublicKey(const byte publicKey[], byte out[]);
108+
104109
private:
105110

106111
struct CertInfo {
@@ -154,7 +159,6 @@ class ECP256Certificate {
154159
int versionLength();
155160
int issuerOrSubjectLength(const CertInfo& issuerOrSubjectData);
156161
int sequenceHeaderLength(int length);
157-
int publicKeyLength();
158162
int signatureLength(const byte signature[]);
159163
int serialNumberLength(const byte serialNumber[], int length);
160164
int authorityKeyIdLength(const byte authorityKeyId[], int length);
@@ -171,7 +175,6 @@ class ECP256Certificate {
171175
int appendVersion(int version, byte out[]);
172176
int appendName(const String& name, int type, byte out[]);
173177
int appendIssuerOrSubject(const CertInfo& issuerOrSubjectData, byte out[]);
174-
int appendPublicKey(const byte publicKey[], byte out[]);
175178
int appendSignature(const byte signature[], byte out[]);
176179
int appendSerialNumber(const byte serialNumber[], int length, byte out[]);
177180
int appendDate(int year, int month, int day, int hour, int minute, int second, byte out[]);
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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+
#include "SElementArduinoCloudJWT.h"
11+
12+
constexpr char JWT_HEADER[] = "{\"alg\":\"ES256\",\"typ\":\"JWT\"}";
13+
String getAIoTCloudJWT(SecureElement &se, String issuer, uint64_t iat, uint8_t slot)
14+
{
15+
SElementJWS jws;
16+
String jwtClaim = "{\"iat\":";
17+
jwtClaim += String((uint32_t)iat);
18+
jwtClaim += ",\"iss\":\"";
19+
jwtClaim += issuer;
20+
jwtClaim += "\"}";
21+
String token = jws.sign(se, slot, JWT_HEADER, jwtClaim.c_str());
22+
return token;
23+
}

src/utility/SElementArduinoCloudJWT.h

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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_AIoTCloud_JWT_H_
12+
#define SECURE_ELEMENT_AIoTCloud_JWT_H_
13+
#include "SElementJWS.h"
14+
15+
String getAIoTCloudJWT(SecureElement &se, String issuer, uint64_t iat, uint8_t slot = 1);
16+
17+
#endif

src/utility/SElementBase64.cpp

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
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+
#include <utility/SElementBase64.h>
12+
13+
namespace arduino { namespace b64 {
14+
15+
String urlEncode(const byte in[], unsigned int length) {
16+
static const char* CODES = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=";
17+
18+
int b;
19+
String out;
20+
21+
int reserveLength = 4 * ((length + 2) / 3);
22+
out.reserve(reserveLength);
23+
24+
for (unsigned int i = 0; i < length; i += 3) {
25+
b = (in[i] & 0xFC) >> 2;
26+
out += CODES[b];
27+
28+
b = (in[i] & 0x03) << 4;
29+
if (i + 1 < length) {
30+
b |= (in[i + 1] & 0xF0) >> 4;
31+
out += CODES[b];
32+
b = (in[i + 1] & 0x0F) << 2;
33+
if (i + 2 < length) {
34+
b |= (in[i + 2] & 0xC0) >> 6;
35+
out += CODES[b];
36+
b = in[i + 2] & 0x3F;
37+
out += CODES[b];
38+
} else {
39+
out += CODES[b];
40+
}
41+
} else {
42+
out += CODES[b];
43+
}
44+
}
45+
46+
while (out.lastIndexOf('=') != -1) {
47+
out.remove(out.length() - 1);
48+
}
49+
50+
return out;
51+
}
52+
53+
String pemEncode(const byte in[], unsigned int length, const char* prefix, const char* suffix) {
54+
static const char* CODES = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
55+
56+
int b;
57+
String out;
58+
59+
int reserveLength = 4 * ((length + 2) / 3) + ((length / 3 * 4) / 76) + strlen(prefix) + strlen(suffix);
60+
out.reserve(reserveLength);
61+
62+
if (prefix) {
63+
out += prefix;
64+
}
65+
66+
for (unsigned int i = 0; i < length; i += 3) {
67+
if (i > 0 && (i / 3 * 4) % 76 == 0) {
68+
out += '\n';
69+
}
70+
71+
b = (in[i] & 0xFC) >> 2;
72+
out += CODES[b];
73+
74+
b = (in[i] & 0x03) << 4;
75+
if (i + 1 < length) {
76+
b |= (in[i + 1] & 0xF0) >> 4;
77+
out += CODES[b];
78+
b = (in[i + 1] & 0x0F) << 2;
79+
if (i + 2 < length) {
80+
b |= (in[i + 2] & 0xC0) >> 6;
81+
out += CODES[b];
82+
b = in[i + 2] & 0x3F;
83+
out += CODES[b];
84+
} else {
85+
out += CODES[b];
86+
out += '=';
87+
}
88+
} else {
89+
out += CODES[b];
90+
out += "==";
91+
}
92+
}
93+
94+
if (suffix) {
95+
out += suffix;
96+
}
97+
98+
return out;
99+
}
100+
101+
}} // arduino::b64

src/utility/SElementBase64.h

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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+
#pragma once
12+
13+
#include <Arduino.h>
14+
15+
namespace arduino { namespace b64 {
16+
17+
String urlEncode(const byte in[], unsigned int length);
18+
String pemEncode(const byte in[], unsigned int length, const char* prefix, const char* suffix);
19+
20+
}} // arduino::b64

src/utility/SElementJWS.cpp

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
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 <utility/SElementBase64.h>
17+
18+
String SElementJWS::publicKey(SecureElement & se, int slot, bool newPrivateKey)
19+
{
20+
if (slot < 0 || slot > 8) {
21+
return "";
22+
}
23+
24+
byte publicKey[64];
25+
26+
if (newPrivateKey) {
27+
if (!se.generatePrivateKey(slot, publicKey)) {
28+
return "";
29+
}
30+
} else {
31+
if (!se.generatePublicKey(slot, publicKey)) {
32+
return "";
33+
}
34+
}
35+
36+
int length = publicKeyLength();
37+
byte out[length];
38+
39+
appendPublicKey(publicKey, out);
40+
41+
return b64::pemEncode(out, length, "-----BEGIN PUBLIC KEY-----\n", "\n-----END PUBLIC KEY-----\n");
42+
}
43+
44+
String SElementJWS::sign(SecureElement & se, int slot, const char* header, const char* payload)
45+
{
46+
if (slot < 0 || slot > 8) {
47+
return "";
48+
}
49+
50+
String encodedHeader = b64::urlEncode((const byte*)header, strlen(header));
51+
String encodedPayload = b64::urlEncode((const byte*)payload, strlen(payload));
52+
53+
String toSign;
54+
toSign.reserve(encodedHeader.length() + 1 + encodedPayload.length());
55+
56+
toSign += encodedHeader;
57+
toSign += '.';
58+
toSign += encodedPayload;
59+
60+
61+
byte toSignSha256[32];
62+
byte signature[64];
63+
64+
se.SHA256((const uint8_t*)toSign.c_str(), toSign.length(), toSignSha256);
65+
66+
if (!se.ecSign(slot, toSignSha256, signature)) {
67+
return "";
68+
}
69+
70+
String encodedSignature = b64::urlEncode(signature, sizeof(signature));
71+
72+
String result;
73+
result.reserve(toSign.length() + 1 + encodedSignature.length());
74+
75+
result += toSign;
76+
result += '.';
77+
result += encodedSignature;
78+
79+
return result;
80+
}
81+
82+
String SElementJWS::sign(SecureElement & se, int slot, const String& header, const String& payload)
83+
{
84+
return sign(se, slot, header.c_str(), payload.c_str());
85+
}

0 commit comments

Comments
 (0)