Skip to content
This repository was archived by the owner on Aug 2, 2022. It is now read-only.

Commit c54aca0

Browse files
authored
Merge pull request #659 from EOSIO/feature/webauthn-support
WebAuthN Support
2 parents 0e25f58 + 1c518a5 commit c54aca0

File tree

6 files changed

+124
-56
lines changed

6 files changed

+124
-56
lines changed

libraries/eosiolib/capi/eosio/types.h

+6-4
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,18 @@
3030
typedef uint64_t capi_name;
3131

3232
/**
33-
* EOSIO Public Key. It is 34 bytes.
33+
* EOSIO Public Key. K1 and R1 keys are 34 bytes. Newer keys can be variable-sized
3434
*/
35-
struct capi_public_key {
35+
struct __attribute__((deprecated("newer public key types cannot be represented as a fixed size structure", "char[]")))
36+
capi_public_key {
3637
char data[34];
3738
};
3839

3940
/**
40-
* EOSIO Signature. It is 66 bytes.
41+
* EOSIO Signature. K1 and R1 signatures are 66 bytes. Newer signatures can be variable-sized
4142
*/
42-
struct capi_signature {
43+
struct __attribute__((deprecated("newer signature types cannot be represented as a fixed size structure", "char[]")))
44+
capi_signature {
4345
uint8_t data[66];
4446
};
4547

libraries/eosiolib/core/eosio/crypto.hpp

+99-37
Original file line numberDiff line numberDiff line change
@@ -20,37 +20,76 @@ namespace eosio {
2020
*/
2121

2222
/**
23-
* EOSIO Public Key
23+
* EOSIO ECC public key data
24+
*
25+
* Fixed size representation of either a K1 or R1 compressed public key
26+
27+
* @ingroup public_key
28+
*/
29+
using ecc_public_key = std::array<char, 33>;
30+
31+
/**
32+
* EOSIO WebAuthN public key
2433
*
2534
* @ingroup public_key
2635
*/
27-
struct public_key {
36+
struct webauthn_public_key {
37+
/**
38+
* Enumeration of the various results of a Test of User Presence
39+
* @see https://w3c.github.io/webauthn/#test-of-user-presence
40+
*/
41+
enum class user_presence_t : uint8_t {
42+
USER_PRESENCE_NONE,
43+
USER_PRESENCE_PRESENT,
44+
USER_PRESENCE_VERIFIED
45+
};
46+
2847
/**
29-
* Type of the public key, could be either K1 or R1
48+
* The ECC key material
3049
*/
31-
unsigned_int type;
50+
ecc_public_key key;
3251

3352
/**
34-
* Bytes of the public key
53+
* expected result of the test of user presence for a valid signature
54+
* @see https://w3c.github.io/webauthn/#test-of-user-presence
3555
*/
36-
std::array<char,33> data;
56+
user_presence_t user_presence;
57+
58+
/**
59+
* the Relying Party Identifier for WebAuthN
60+
* @see https://w3c.github.io/webauthn/#relying-party-identifier
61+
*/
62+
std::string rpid;
3763

3864
/// @cond OPERATORS
3965

40-
friend bool operator == ( const public_key& a, const public_key& b ) {
41-
return std::tie(a.type,a.data) == std::tie(b.type,b.data);
66+
friend bool operator == ( const webauthn_public_key& a, const webauthn_public_key& b ) {
67+
return std::tie(a.key,a.user_presence,a.rpid) == std::tie(b.key,b.user_presence,b.rpid);
4268
}
43-
friend bool operator != ( const public_key& a, const public_key& b ) {
44-
return std::tie(a.type,a.data) != std::tie(b.type,b.data);
69+
friend bool operator != ( const webauthn_public_key& a, const webauthn_public_key& b ) {
70+
return std::tie(a.key,a.user_presence,a.rpid) != std::tie(b.key,b.user_presence,b.rpid);
4571
}
4672

4773
/// @cond
4874
};
4975

76+
/**
77+
* EOSIO Public Key
78+
*
79+
* A public key is a variant of
80+
* 0 : a ECC K1 public key
81+
* 1 : a ECC R1 public key
82+
* 2 : a WebAuthN public key (requires the host chain to activate the WEBAUTHN_KEY consensus upgrade)
83+
*
84+
* @ingroup public_key
85+
*/
86+
using public_key = std::variant<ecc_public_key, ecc_public_key, webauthn_public_key>;
87+
88+
5089
/// @cond IMPLEMENTATIONS
5190

5291
/**
53-
* Serialize an eosio::public_key into a stream
92+
* Serialize an eosio::webauthn_public_key into a stream
5493
*
5594
* @ingroup public_key
5695
* @param ds - The stream to write
@@ -59,14 +98,13 @@ namespace eosio {
5998
* @return DataStream& - Reference to the datastream
6099
*/
61100
template<typename DataStream>
62-
inline DataStream& operator<<(DataStream& ds, const eosio::public_key& pubkey) {
63-
ds << pubkey.type;
64-
ds.write( pubkey.data.data(), pubkey.data.size() );
101+
inline DataStream& operator<<(DataStream& ds, const eosio::webauthn_public_key& pubkey) {
102+
ds << pubkey.key << pubkey.user_presence << pubkey.rpid;
65103
return ds;
66104
}
67105

68106
/**
69-
* Deserialize an eosio::public_key from a stream
107+
* Deserialize an eosio::webauthn_public_key from a stream
70108
*
71109
* @ingroup public_key
72110
* @param ds - The stream to read
@@ -75,9 +113,8 @@ namespace eosio {
75113
* @return DataStream& - Reference to the datastream
76114
*/
77115
template<typename DataStream>
78-
inline DataStream& operator>>(DataStream& ds, eosio::public_key& pubkey) {
79-
ds >> pubkey.type;
80-
ds.read( pubkey.data.data(), pubkey.data.size() );
116+
inline DataStream& operator>>(DataStream& ds, eosio::webauthn_public_key& pubkey) {
117+
ds >> pubkey.key >> pubkey.user_presence >> pubkey.rpid;
81118
return ds;
82119
}
83120

@@ -91,63 +128,88 @@ namespace eosio {
91128
*/
92129

93130
/**
94-
* EOSIO Signature
131+
* EOSIO ECC signature data
95132
*
133+
* Fixed size representation of either a K1 or R1 ECC compact signature
134+
96135
* @ingroup signature
97136
*/
98-
struct signature {
137+
using ecc_signature = std::array<char, 65>;
99138

139+
/**
140+
* EOSIO WebAuthN signature
141+
*
142+
* @ingroup signature
143+
*/
144+
struct webauthn_signature {
100145
/**
101-
* Type of the signature, could be either K1 or R1
146+
* The ECC signature data
102147
*/
103-
unsigned_int type;
148+
ecc_signature compact_signature;
104149

105150
/**
106-
* Bytes of the signature
151+
* The Encoded Authenticator Data returned from WebAuthN ceremony
152+
* @see https://w3c.github.io/webauthn/#sctn-authenticator-data
107153
*/
108-
std::array<char,65> data;
154+
std::vector<uint8_t> auth_data;
155+
156+
/**
157+
* the JSON encoded Collected Client Data from a WebAuthN ceremony
158+
* @see https://w3c.github.io/webauthn/#dictdef-collectedclientdata
159+
*/
160+
std::string client_json;
109161

110162
/// @cond OPERATORS
111163

112-
friend bool operator == ( const signature& a, const signature& b ) {
113-
return std::tie(a.type,a.data) == std::tie(b.type,b.data);
164+
friend bool operator == ( const webauthn_signature& a, const webauthn_signature& b ) {
165+
return std::tie(a.compact_signature,a.auth_data,a.client_json) == std::tie(b.compact_signature,b.auth_data,b.client_json);
114166
}
115-
friend bool operator != ( const signature& a, const signature& b ) {
116-
return std::tie(a.type,a.data) != std::tie(b.type,b.data);
167+
friend bool operator != ( const webauthn_signature& a, const webauthn_signature& b ) {
168+
return std::tie(a.compact_signature,a.auth_data,a.client_json) != std::tie(b.compact_signature,b.auth_data,b.client_json);
117169
}
118170

119-
/// @endcond
171+
/// @cond
120172
};
121173

174+
/**
175+
* EOSIO Signature
176+
*
177+
* A signature is a variant of
178+
* 0 : a ECC K1 signature
179+
* 1 : a ECC R1 signatre
180+
* 2 : a WebAuthN signature (requires the host chain to activate the WEBAUTHN_KEY consensus upgrade)
181+
*
182+
* @ingroup signature
183+
*/
184+
using signature = std::variant<ecc_signature, ecc_signature, webauthn_signature>;
185+
122186
/// @cond IMPLEMENTATIONS
123187

124188
/**
125-
* Serialize an eosio::signature into a stream
189+
* Serialize an eosio::webauthn_signature into a stream
126190
*
127191
* @param ds - The stream to write
128192
* @param sig - The value to serialize
129193
* @tparam DataStream - Type of datastream buffer
130194
* @return DataStream& - Reference to the datastream
131195
*/
132196
template<typename DataStream>
133-
inline DataStream& operator<<(DataStream& ds, const eosio::signature& sig) {
134-
ds << sig.type;
135-
ds.write( sig.data.data(), sig.data.size() );
197+
inline DataStream& operator<<(DataStream& ds, const eosio::webauthn_signature& sig) {
198+
ds << sig.compact_signature << sig.auth_data << sig.client_json;
136199
return ds;
137200
}
138201

139202
/**
140-
* Deserialize an eosio::signature from a stream
203+
* Deserialize an eosio::webauthn_signature from a stream
141204
*
142205
* @param ds - The stream to read
143206
* @param sig - The destination for deserialized value
144207
* @tparam DataStream - Type of datastream buffer
145208
* @return DataStream& - Reference to the datastream
146209
*/
147210
template<typename DataStream>
148-
inline DataStream& operator>>(DataStream& ds, eosio::signature& sig) {
149-
ds >> sig.type;
150-
ds.read( sig.data.data(), sig.data.size() );
211+
inline DataStream& operator>>(DataStream& ds, eosio::webauthn_signature& sig) {
212+
ds >> sig.compact_signature >> sig.auth_data >> sig.client_json;
151213
return ds;
152214
}
153215

libraries/eosiolib/core/eosio/datastream.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ void deserialize(datastream<Stream>& ds, std::variant<Ts...>& var, int i) {
340340
if (i == I) {
341341
std::variant_alternative_t<I, std::variant<Ts...>> tmp;
342342
ds >> tmp;
343-
var = std::move(tmp);
343+
var.template emplace<I>(std::move(tmp));
344344
} else {
345345
deserialize<I+1>(ds,var,i);
346346
}

libraries/eosiolib/types.h

+6-4
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,18 @@ extern "C" {
2929
typedef uint64_t capi_name;
3030

3131
/**
32-
* EOSIO Public Key. It is 34 bytes.
32+
* EOSIO Public Key. K1 and R1 keys are 34 bytes. Newer keys can be variable-sized
3333
*/
34-
struct capi_public_key {
34+
struct __attribute__((deprecated("newer public key types cannot be represented as a fixed size structure", "char[]")))
35+
capi_public_key {
3536
char data[34];
3637
};
3738

3839
/**
39-
* EOSIO Signature. It is 66 bytes.
40+
* EOSIO Signature. K1 and R1 signatures are 66 bytes. Newer signatures can be variable-sized
4041
*/
41-
struct capi_signature {
42+
struct __attribute__((deprecated("newer signature types cannot be represented as a fixed size structure", "char[]")))
43+
capi_signature {
4244
uint8_t data[66];
4345
};
4446

tests/unit/crypto_tests.cpp

+8-8
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,26 @@ using eosio::signature;
1313
EOSIO_TEST_BEGIN(public_key_type_test)
1414
// -----------------------------------------------------
1515
// bool operator==(const public_key&, const public_key&)
16-
CHECK_EQUAL( (public_key{0, std::array<char, 33>{}} == public_key{0, std::array<char, 33>{}}), true )
17-
CHECK_EQUAL( (public_key{0, std::array<char, 33>{1}} == public_key{0, std::array<char, 33>{}}), false )
16+
CHECK_EQUAL( (public_key(std::in_place_index<0>, std::array<char, 33>{}) == public_key(std::in_place_index<0>, std::array<char, 33>{})), true )
17+
CHECK_EQUAL( (public_key(std::in_place_index<0>, std::array<char, 33>{1}) == public_key(std::in_place_index<0>, std::array<char, 33>{})), false )
1818

1919
// -----------------------------------------------------
2020
// bool operator!=(const public_key&, const public_key&)
21-
CHECK_EQUAL( (public_key{0, std::array<char, 33>{}} != public_key{0, std::array<char, 33>{}}), false )
22-
CHECK_EQUAL( (public_key{0, std::array<char, 33>{1}} != public_key{0, std::array<char, 33>{}}), true )
21+
CHECK_EQUAL( (public_key(std::in_place_index<0>, std::array<char, 33>{}) != public_key(std::in_place_index<0>, std::array<char, 33>{})), false )
22+
CHECK_EQUAL( (public_key(std::in_place_index<0>, std::array<char, 33>{1}) != public_key(std::in_place_index<0>, std::array<char, 33>{})), true )
2323
EOSIO_TEST_END
2424

2525
// Definitions in `eosio.cdt/libraries/eosio/crypto.hpp`
2626
EOSIO_TEST_BEGIN(signature_type_test)
2727
// ---------------------------------------------------
2828
// bool operator==(const signature&, const signature&)
29-
CHECK_EQUAL( (signature{0, std::array<char, 65>{}} == signature{0, std::array<char, 65>{}}), true )
30-
CHECK_EQUAL( (signature{0, std::array<char, 65>{1}} == signature{0, std::array<char, 65>{}}), false )
29+
CHECK_EQUAL( (signature(std::in_place_index<0>, std::array<char, 65>{}) == signature(std::in_place_index<0>, std::array<char, 65>{})), true )
30+
CHECK_EQUAL( (signature(std::in_place_index<0>, std::array<char, 65>{1}) == signature(std::in_place_index<0>, std::array<char, 65>{})), false )
3131

3232
// ---------------------------------------------------
3333
// bool operator!=(const signature&, const signature&)
34-
CHECK_EQUAL( (signature{0, std::array<char, 65>{1}} != signature{0, std::array<char, 65>{}}), true )
35-
CHECK_EQUAL( (signature{0, std::array<char, 65>{}} != signature{0, std::array<char, 65>{}}), false )
34+
CHECK_EQUAL( (signature(std::in_place_index<0>, std::array<char, 65>{1}) != signature(std::in_place_index<0>, std::array<char, 65>{})), true )
35+
CHECK_EQUAL( (signature(std::in_place_index<0>, std::array<char, 65>{}) != signature(std::in_place_index<0>, std::array<char, 65>{})), false )
3636
EOSIO_TEST_END
3737

3838
int main(int argc, char* argv[]) {

tests/unit/datastream_tests.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ using eosio::ignore;
3939
using eosio::ignore_wrapper;
4040
using eosio::pack;
4141
using eosio::pack_size;
42+
using eosio::ecc_public_key;
4243
using eosio::public_key;
44+
using eosio::ecc_signature;
4345
using eosio::signature;
4446
using eosio::symbol;
4547
using eosio::symbol_code;
@@ -507,7 +509,7 @@ EOSIO_TEST_BEGIN(datastream_stream_test)
507509
// eosio::public_key
508510
ds.seekp(0);
509511
fill(begin(datastream_buffer), end(datastream_buffer), 0);
510-
static const public_key cpubkey{{},'a','b','c','d','e','f','g','h','i'};
512+
static const public_key cpubkey(std::in_place_index<0>,ecc_public_key{'a','b','c','d','e','f','g','h','i'});
511513
public_key pubkey{};
512514
ds << cpubkey;
513515
ds.seekp(0);
@@ -518,7 +520,7 @@ EOSIO_TEST_BEGIN(datastream_stream_test)
518520
// eosio::signature
519521
ds.seekp(0);
520522
fill(begin(datastream_buffer), end(datastream_buffer), 0);
521-
static const signature csig{{},'a','b','c','d','e','f','g','h','i'};
523+
static const signature csig(std::in_place_index<0>,ecc_signature{'a','b','c','d','e','f','g','h','i'});
522524
signature sig{};
523525
ds << csig;
524526
ds.seekp(0);

0 commit comments

Comments
 (0)