Skip to content

Commit 9cc5833

Browse files
committed
Use ECC508 for ECDSA verify if present
1 parent 12acbd3 commit 9cc5833

File tree

5 files changed

+141
-9
lines changed

5 files changed

+141
-9
lines changed

src/BearSSLClient.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#include "ArduinoBearSSL.h"
22
#include "BearSSLTrustAnchors.h"
33
#include "utility/ECC508.h"
4+
#include "utility/ecc508_asn1.h"
5+
46

57
#include "BearSSLClient.h"
68

@@ -159,7 +161,11 @@ int BearSSLClient::connectSSL(const char* host)
159161
// inject entropy in engine
160162
unsigned char entropy[32];
161163

162-
if (!ECC508.begin() || !ECC508.random(entropy, sizeof(entropy))) {
164+
if (ECC508.begin() && ECC508.random(entropy, sizeof(entropy))) {
165+
// ECC508 random success, add custom ECDSA vfry
166+
br_ssl_engine_set_ecdsa(&_sc.eng, ecc508_vrfy_asn1);
167+
br_x509_minimal_set_ecdsa(&_xc, br_ssl_engine_get_ec(&_sc.eng), br_ssl_engine_get_ecdsa(&_sc.eng));
168+
} else {
163169
// no ECC508 or random failed, fallback to pseudo random
164170
for (size_t i = 0; i < sizeof(entropy); i++) {
165171
entropy[i] = random(0, 255);

src/utility/ECC508.cpp

Lines changed: 78 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,15 @@ int ECC508Class::random(byte data[], size_t length)
6262
return 1;
6363
}
6464

65+
int ECC508Class::ecdsaVerify(const byte message[], const byte signature[], const byte pubkey[])
66+
{
67+
if (!challenge(message)) {
68+
return 0;
69+
}
70+
71+
return verify(signature, pubkey);
72+
}
73+
6574
int ECC508Class::wakeup()
6675
{
6776
_wire->beginTransmission(0x00);
@@ -126,20 +135,83 @@ int ECC508Class::version()
126135
return version;
127136
}
128137

129-
int ECC508Class::sendCommand(uint8_t opcode, uint8_t param1, uint16_t param2)
138+
int ECC508Class::challenge(const byte message[])
139+
{
140+
uint8_t status;
141+
142+
if (!wakeup()) {
143+
return 0;
144+
}
145+
146+
// Nounce, pass through
147+
if (!sendCommand(0x16, 0x03, 0x0000, message, 32)) {
148+
return 0;
149+
}
150+
151+
delay(7);
152+
153+
if (!receiveResponse(&status, sizeof(status))) {
154+
return 0;
155+
}
156+
157+
delay(1);
158+
idle();
159+
160+
if (status != 0) {
161+
return 0;
162+
}
163+
164+
return 1;
165+
}
166+
167+
int ECC508Class::verify(const byte signature[], const byte pubkey[])
168+
{
169+
uint8_t status;
170+
171+
if (!wakeup()) {
172+
return 0;
173+
}
174+
175+
byte data[128];
176+
memcpy(&data[0], signature, 64);
177+
memcpy(&data[64], pubkey, 64);
178+
179+
// Verify, external, P256
180+
if (!sendCommand(0x45, 0x02, 0x0004, data, sizeof(data))) {
181+
return 0;
182+
}
183+
184+
delay(58);
185+
186+
if (!receiveResponse(&status, sizeof(status))) {
187+
return 0;
188+
}
189+
190+
delay(1);
191+
idle();
192+
193+
if (status != 0) {
194+
return 0;
195+
}
196+
197+
return 1;
198+
}
199+
200+
int ECC508Class::sendCommand(uint8_t opcode, uint8_t param1, uint16_t param2, const byte data[], size_t dataLength)
130201
{
131-
byte command[8]; // 1 for type, 1 for length, 1 for opcode, 1 for param1, 2 for param2, 2 for crc
202+
byte command[8 + dataLength]; // 1 for type, 1 for length, 1 for opcode, 1 for param1, 2 for param2, 2 for crc
132203

133204
command[0] = 0x03;
134205
command[1] = sizeof(command) - 1;
135206
command[2] = opcode;
136207
command[3] = param1;
137208
memcpy(&command[4], &param2, sizeof(param2));
209+
memcpy(&command[6], data, dataLength);
138210

139-
uint16_t crc = crc16(&command[1], sizeof(command) - 3);
140-
memcpy(&command[6], &crc, sizeof(crc));
211+
uint16_t crc = crc16(&command[1], 8 - 3 + dataLength);
212+
memcpy(&command[6 + dataLength], &crc, sizeof(crc));
141213

142-
if (_wire->sendTo(_address, command, sizeof(command)) != 0) {
214+
if (_wire->sendTo(_address, command, 8 + dataLength) != 0) {
143215
return 0;
144216
}
145217

@@ -170,7 +242,7 @@ int ECC508Class::receiveResponse(void* response, size_t length)
170242
return 1;
171243
}
172244

173-
uint16_t ECC508Class::crc16(byte data[], size_t length)
245+
uint16_t ECC508Class::crc16(const byte data[], size_t length)
174246
{
175247
if (data == NULL || length == 0) {
176248
return 0;

src/utility/ECC508.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef _ECC508_H_
22
#define _ECC508_H_
33

4+
#include <Arduino.h>
45
#include <Wire.h>
56

67
class ECC508Class
@@ -14,16 +15,20 @@ class ECC508Class
1415

1516
int random(byte data[], size_t length);
1617

18+
int ecdsaVerify(const byte message[], const byte signature[], const byte pubkey[]);
19+
1720
private:
1821
int wakeup();
1922
int sleep();
2023
int idle();
2124

2225
int version();
26+
int challenge(const byte message[]);
27+
int verify(const byte signature[], const byte pubkey[]);
2328

24-
int sendCommand(uint8_t opcode, uint8_t param1, uint16_t param2);
29+
int sendCommand(uint8_t opcode, uint8_t param1, uint16_t param2, const byte data[] = NULL, size_t dataLength = 0);
2530
int receiveResponse(void* response, size_t length);
26-
uint16_t crc16(byte data[], size_t length);
31+
uint16_t crc16(const byte data[], size_t length);
2732

2833
private:
2934
TwoWire* _wire;

src/utility/ecc508_asn1.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#ifndef _ECC508_ASN1_H_
2+
#define _ECC508_ASN1_H_
3+
4+
#include "bearssl/bearssl.h"
5+
6+
uint32_t
7+
ecc508_vrfy_asn1(const br_ec_impl *impl,
8+
const void *hash, size_t hash_len,
9+
const br_ec_public_key *pk,
10+
const void *sig, size_t sig_len);
11+
12+
#endif

src/utility/ecc508_vrfy_asn1.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include "ecc508_asn1.h"
2+
3+
#include "ECC508.h"
4+
5+
#define BR_MAX_EC_SIZE 528
6+
#define FIELD_LEN ((BR_MAX_EC_SIZE + 7) >> 3)
7+
8+
uint32_t
9+
ecc508_vrfy_asn1(const br_ec_impl * /*impl*/,
10+
const void *hash, size_t hash_len,
11+
const br_ec_public_key *pk,
12+
const void *sig, size_t sig_len)
13+
{
14+
/*
15+
* We use a double-sized buffer because a malformed ASN.1 signature
16+
* may trigger a size expansion when converting to "raw" format.
17+
*/
18+
unsigned char rsig[(FIELD_LEN << 2) + 24];
19+
20+
if (sig_len > ((sizeof rsig) >> 1)) {
21+
return 0;
22+
}
23+
24+
memcpy(rsig, sig, sig_len);
25+
sig_len = br_ecdsa_asn1_to_raw(rsig, sig_len);
26+
27+
if (hash_len != 32 || pk->curve != BR_EC_secp256r1 || pk->qlen != 65 || sig_len != 64) {
28+
return 0;
29+
}
30+
31+
// TODO: understand why the public key is &pk->q[1] instead of &pk->q[0] ...
32+
if (!ECC508.ecdsaVerify((const uint8_t*)hash, (const uint8_t*)rsig, (const uint8_t*)&pk->q[1])) {
33+
return 0;
34+
}
35+
36+
return 1;
37+
}

0 commit comments

Comments
 (0)