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

WebAuthN Support #659

Merged
merged 2 commits into from
Sep 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions libraries/eosiolib/capi/eosio/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,18 @@
typedef uint64_t capi_name;

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

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

Expand Down
136 changes: 99 additions & 37 deletions libraries/eosiolib/core/eosio/crypto.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,37 +20,76 @@ namespace eosio {
*/

/**
* EOSIO Public Key
* EOSIO ECC public key data
*
* Fixed size representation of either a K1 or R1 compressed public key

* @ingroup public_key
*/
using ecc_public_key = std::array<char, 33>;

/**
* EOSIO WebAuthN public key
*
* @ingroup public_key
*/
struct public_key {
struct webauthn_public_key {
/**
* Enumeration of the various results of a Test of User Presence
* @see https://w3c.github.io/webauthn/#test-of-user-presence
*/
enum class user_presence_t : uint8_t {
USER_PRESENCE_NONE,
USER_PRESENCE_PRESENT,
USER_PRESENCE_VERIFIED
};

/**
* Type of the public key, could be either K1 or R1
* The ECC key material
*/
unsigned_int type;
ecc_public_key key;

/**
* Bytes of the public key
* expected result of the test of user presence for a valid signature
* @see https://w3c.github.io/webauthn/#test-of-user-presence
*/
std::array<char,33> data;
user_presence_t user_presence;

/**
* the Relying Party Identifier for WebAuthN
* @see https://w3c.github.io/webauthn/#relying-party-identifier
*/
std::string rpid;

/// @cond OPERATORS

friend bool operator == ( const public_key& a, const public_key& b ) {
return std::tie(a.type,a.data) == std::tie(b.type,b.data);
friend bool operator == ( const webauthn_public_key& a, const webauthn_public_key& b ) {
return std::tie(a.key,a.user_presence,a.rpid) == std::tie(b.key,b.user_presence,b.rpid);
}
friend bool operator != ( const public_key& a, const public_key& b ) {
return std::tie(a.type,a.data) != std::tie(b.type,b.data);
friend bool operator != ( const webauthn_public_key& a, const webauthn_public_key& b ) {
return std::tie(a.key,a.user_presence,a.rpid) != std::tie(b.key,b.user_presence,b.rpid);
}

/// @cond
};

/**
* EOSIO Public Key
*
* A public key is a variant of
* 0 : a ECC K1 public key
* 1 : a ECC R1 public key
* 2 : a WebAuthN public key (requires the host chain to activate the WEBAUTHN_KEY consensus upgrade)
*
* @ingroup public_key
*/
using public_key = std::variant<ecc_public_key, ecc_public_key, webauthn_public_key>;


/// @cond IMPLEMENTATIONS

/**
* Serialize an eosio::public_key into a stream
* Serialize an eosio::webauthn_public_key into a stream
*
* @ingroup public_key
* @param ds - The stream to write
Expand All @@ -59,14 +98,13 @@ namespace eosio {
* @return DataStream& - Reference to the datastream
*/
template<typename DataStream>
inline DataStream& operator<<(DataStream& ds, const eosio::public_key& pubkey) {
ds << pubkey.type;
ds.write( pubkey.data.data(), pubkey.data.size() );
inline DataStream& operator<<(DataStream& ds, const eosio::webauthn_public_key& pubkey) {
ds << pubkey.key << pubkey.user_presence << pubkey.rpid;
return ds;
}

/**
* Deserialize an eosio::public_key from a stream
* Deserialize an eosio::webauthn_public_key from a stream
*
* @ingroup public_key
* @param ds - The stream to read
Expand All @@ -75,9 +113,8 @@ namespace eosio {
* @return DataStream& - Reference to the datastream
*/
template<typename DataStream>
inline DataStream& operator>>(DataStream& ds, eosio::public_key& pubkey) {
ds >> pubkey.type;
ds.read( pubkey.data.data(), pubkey.data.size() );
inline DataStream& operator>>(DataStream& ds, eosio::webauthn_public_key& pubkey) {
ds >> pubkey.key >> pubkey.user_presence >> pubkey.rpid;
return ds;
}

Expand All @@ -91,63 +128,88 @@ namespace eosio {
*/

/**
* EOSIO Signature
* EOSIO ECC signature data
*
* Fixed size representation of either a K1 or R1 ECC compact signature

* @ingroup signature
*/
struct signature {
using ecc_signature = std::array<char, 65>;

/**
* EOSIO WebAuthN signature
*
* @ingroup signature
*/
struct webauthn_signature {
/**
* Type of the signature, could be either K1 or R1
* The ECC signature data
*/
unsigned_int type;
ecc_signature compact_signature;

/**
* Bytes of the signature
* The Encoded Authenticator Data returned from WebAuthN ceremony
* @see https://w3c.github.io/webauthn/#sctn-authenticator-data
*/
std::array<char,65> data;
std::vector<uint8_t> auth_data;

/**
* the JSON encoded Collected Client Data from a WebAuthN ceremony
* @see https://w3c.github.io/webauthn/#dictdef-collectedclientdata
*/
std::string client_json;

/// @cond OPERATORS

friend bool operator == ( const signature& a, const signature& b ) {
return std::tie(a.type,a.data) == std::tie(b.type,b.data);
friend bool operator == ( const webauthn_signature& a, const webauthn_signature& b ) {
return std::tie(a.compact_signature,a.auth_data,a.client_json) == std::tie(b.compact_signature,b.auth_data,b.client_json);
}
friend bool operator != ( const signature& a, const signature& b ) {
return std::tie(a.type,a.data) != std::tie(b.type,b.data);
friend bool operator != ( const webauthn_signature& a, const webauthn_signature& b ) {
return std::tie(a.compact_signature,a.auth_data,a.client_json) != std::tie(b.compact_signature,b.auth_data,b.client_json);
}

/// @endcond
/// @cond
};

/**
* EOSIO Signature
*
* A signature is a variant of
* 0 : a ECC K1 signature
* 1 : a ECC R1 signatre
* 2 : a WebAuthN signature (requires the host chain to activate the WEBAUTHN_KEY consensus upgrade)
*
* @ingroup signature
*/
using signature = std::variant<ecc_signature, ecc_signature, webauthn_signature>;

/// @cond IMPLEMENTATIONS

/**
* Serialize an eosio::signature into a stream
* Serialize an eosio::webauthn_signature into a stream
*
* @param ds - The stream to write
* @param sig - The value to serialize
* @tparam DataStream - Type of datastream buffer
* @return DataStream& - Reference to the datastream
*/
template<typename DataStream>
inline DataStream& operator<<(DataStream& ds, const eosio::signature& sig) {
ds << sig.type;
ds.write( sig.data.data(), sig.data.size() );
inline DataStream& operator<<(DataStream& ds, const eosio::webauthn_signature& sig) {
ds << sig.compact_signature << sig.auth_data << sig.client_json;
return ds;
}

/**
* Deserialize an eosio::signature from a stream
* Deserialize an eosio::webauthn_signature from a stream
*
* @param ds - The stream to read
* @param sig - The destination for deserialized value
* @tparam DataStream - Type of datastream buffer
* @return DataStream& - Reference to the datastream
*/
template<typename DataStream>
inline DataStream& operator>>(DataStream& ds, eosio::signature& sig) {
ds >> sig.type;
ds.read( sig.data.data(), sig.data.size() );
inline DataStream& operator>>(DataStream& ds, eosio::webauthn_signature& sig) {
ds >> sig.compact_signature >> sig.auth_data >> sig.client_json;
return ds;
}

Expand Down
2 changes: 1 addition & 1 deletion libraries/eosiolib/core/eosio/datastream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ void deserialize(datastream<Stream>& ds, std::variant<Ts...>& var, int i) {
if (i == I) {
std::variant_alternative_t<I, std::variant<Ts...>> tmp;
ds >> tmp;
var = std::move(tmp);
var.template emplace<I>(std::move(tmp));
} else {
deserialize<I+1>(ds,var,i);
}
Expand Down
10 changes: 6 additions & 4 deletions libraries/eosiolib/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,18 @@ extern "C" {
typedef uint64_t capi_name;

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

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

Expand Down
16 changes: 8 additions & 8 deletions tests/unit/crypto_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,26 @@ using eosio::signature;
EOSIO_TEST_BEGIN(public_key_type_test)
// -----------------------------------------------------
// bool operator==(const public_key&, const public_key&)
CHECK_EQUAL( (public_key{0, std::array<char, 33>{}} == public_key{0, std::array<char, 33>{}}), true )
CHECK_EQUAL( (public_key{0, std::array<char, 33>{1}} == public_key{0, std::array<char, 33>{}}), false )
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 )
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 )

// -----------------------------------------------------
// bool operator!=(const public_key&, const public_key&)
CHECK_EQUAL( (public_key{0, std::array<char, 33>{}} != public_key{0, std::array<char, 33>{}}), false )
CHECK_EQUAL( (public_key{0, std::array<char, 33>{1}} != public_key{0, std::array<char, 33>{}}), true )
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 )
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 )
EOSIO_TEST_END

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

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

int main(int argc, char* argv[]) {
Expand Down
6 changes: 4 additions & 2 deletions tests/unit/datastream_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ using eosio::ignore;
using eosio::ignore_wrapper;
using eosio::pack;
using eosio::pack_size;
using eosio::ecc_public_key;
using eosio::public_key;
using eosio::ecc_signature;
using eosio::signature;
using eosio::symbol;
using eosio::symbol_code;
Expand Down Expand Up @@ -507,7 +509,7 @@ EOSIO_TEST_BEGIN(datastream_stream_test)
// eosio::public_key
ds.seekp(0);
fill(begin(datastream_buffer), end(datastream_buffer), 0);
static const public_key cpubkey{{},'a','b','c','d','e','f','g','h','i'};
static const public_key cpubkey(std::in_place_index<0>,ecc_public_key{'a','b','c','d','e','f','g','h','i'});
public_key pubkey{};
ds << cpubkey;
ds.seekp(0);
Expand All @@ -518,7 +520,7 @@ EOSIO_TEST_BEGIN(datastream_stream_test)
// eosio::signature
ds.seekp(0);
fill(begin(datastream_buffer), end(datastream_buffer), 0);
static const signature csig{{},'a','b','c','d','e','f','g','h','i'};
static const signature csig(std::in_place_index<0>,ecc_signature{'a','b','c','d','e','f','g','h','i'});
signature sig{};
ds << csig;
ds.seekp(0);
Expand Down