1#define BOOST_TEST_MODULE webauthn_test_mod 
    2#include <boost/test/included/unit_test.hpp> 
    3#include <boost/algorithm/string.hpp> 
   12using namespace std::literals;
 
   15                                                         std::vector<uint8_t>& auth_data,
 
   16                                                         const std::string& 
json) {
 
   21   e.
write((
char*)auth_data.data(), auth_data.size());
 
   45BOOST_AUTO_TEST_SUITE(webauthn_suite)
 
   49   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
   52   std::vector<uint8_t> auth_data(37);
 
   54   memcpy(auth_data.data(), origin_hash.
data(), 
sizeof(origin_hash));
 
   56   BOOST_CHECK_EQUAL(wa_pub, make_webauthn_sig(priv, auth_data, 
json).recover(d, 
true));
 
 
   61   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_PRESENT, 
"fctesting.invalid");
 
   64   std::vector<uint8_t> auth_data(37);
 
   65   memcpy(auth_data.data(), origin_hash.
data(), 
sizeof(origin_hash));
 
   66   auth_data[32] |= 0x04; 
 
   68   BOOST_CHECK_NE(wa_pub, make_webauthn_sig(priv, auth_data, 
json).recover(d, 
true));
 
 
   73   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_PRESENT, 
"fctesting.invalid");
 
   76   std::vector<uint8_t> auth_data(37);
 
   78   memcpy(auth_data.data(), mallory_origin_hash.
data(), 
sizeof(mallory_origin_hash));
 
   80   BOOST_CHECK_NE(wa_pub, make_webauthn_sig(priv, auth_data, 
json).recover(d, 
true));
 
 
   85   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
   88   std::vector<uint8_t> auth_data(37);
 
   89   memcpy(auth_data.data(), origin_hash.
data(), 
sizeof(origin_hash));
 
   91   BOOST_CHECK_EXCEPTION(make_webauthn_sig(priv, auth_data, 
json).recover(d, 
true), fc::assert_exception, [](
const fc::assert_exception& e) {
 
   92      return e.to_detail_string().find(
"webauthn origin must begin with https://") != std::string::npos;
 
 
   98   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
  101   std::vector<uint8_t> auth_data(37);
 
  102   memcpy(auth_data.data(), origin_hash.
data(), 
sizeof(origin_hash));
 
  104   BOOST_CHECK_EXCEPTION(make_webauthn_sig(priv, auth_data, 
json).recover(d, 
true), fc::assert_exception, [](
const fc::assert_exception& e) {
 
  105      return e.to_detail_string().find(
"webauthn origin must begin with https://") != std::string::npos;
 
 
  111   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
  114   std::vector<uint8_t> auth_data(37);
 
  115   memcpy(auth_data.data(), origin_hash.
data(), 
sizeof(origin_hash));
 
  117   BOOST_CHECK_EXCEPTION(make_webauthn_sig(priv, auth_data, 
json).recover(d, 
true), fc::assert_exception, [](
const fc::assert_exception& e) {
 
  118      return e.to_detail_string().find(
"webauthn origin must begin with https://") != std::string::npos;
 
 
  124   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
  127   std::vector<uint8_t> auth_data(37);
 
  128   memcpy(auth_data.data(), origin_hash.
data(), 
sizeof(origin_hash));
 
  130   BOOST_CHECK_EQUAL(wa_pub, make_webauthn_sig(priv, auth_data, 
json).recover(d, 
true));
 
 
  135   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
  138   std::vector<uint8_t> auth_data(37);
 
  139   memcpy(auth_data.data(), origin_hash.
data(), 
sizeof(origin_hash));
 
  141   BOOST_CHECK_EQUAL(wa_pub, make_webauthn_sig(priv, auth_data, 
json).recover(d, 
true));
 
 
  146   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
  147   std::string 
json = 
"{\"origin\":\"https://fctesting.invalid\",\"type\":\"webauthn.get\",\"challenge\":\"" + 
"blahBLAH"s + 
"\"}";
 
  149   std::vector<uint8_t> auth_data(37);
 
  150   memcpy(auth_data.data(), origin_hash.
data(), 
sizeof(origin_hash));
 
  153      return e.
to_detail_string().find(
"sha256: size mismatch") != std::string::npos;
 
 
  159   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
  160   std::string 
json = 
"{\"origin\":\"https://fctesting.invalid\",\"type\":\"webauthn.get\",\"challenge\":\"" + 
"hello@world$"s + 
"\"}";
 
  162   std::vector<uint8_t> auth_data(37);
 
  163   memcpy(auth_data.data(), origin_hash.
data(), 
sizeof(origin_hash));
 
  166      return e.
to_detail_string().find(
"encountered non-base64 character") != std::string::npos;
 
 
  172   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
  174   std::string 
json = 
"{\"origin\":\"https://fctesting.invalid\",\"type\":\"webauthn.get\",\"challenge\":\"" + 
fc::base64url_encode(other_digest.
data(), other_digest.
data_size()) + 
"\"}";
 
  176   std::vector<uint8_t> auth_data(37);
 
  177   memcpy(auth_data.data(), origin_hash.
data(), 
sizeof(origin_hash));
 
  179   BOOST_CHECK_EXCEPTION(make_webauthn_sig(priv, auth_data, 
json).recover(d, 
true), fc::assert_exception, [](
const fc::assert_exception& e) {
 
  180      return e.to_detail_string().find(
"Wrong webauthn challenge") != std::string::npos;
 
 
  187   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
  190   std::vector<uint8_t> auth_data(37);
 
  191   memcpy(auth_data.data(), origin_hash.
data(), 
sizeof(origin_hash));
 
  193   BOOST_CHECK_EXCEPTION(make_webauthn_sig(priv, auth_data, 
json).recover(d, 
true), fc::assert_exception, [](
const fc::assert_exception& e) {
 
  194      return e.to_detail_string().find(
"webauthn signature type not an assertion") != std::string::npos;
 
 
  200   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
  203   std::vector<uint8_t> auth_data(37);
 
  205   memcpy(auth_data.data(), origin_hash_corrupt.
data(), 
sizeof(origin_hash_corrupt));
 
  208   BOOST_CHECK_EXCEPTION(make_webauthn_sig(priv, auth_data, 
json).recover(d, 
true), fc::assert_exception, [](
const fc::assert_exception& e) {
 
  209      return e.to_detail_string().find(
"webauthn rpid hash doesn't match origin") != std::string::npos;
 
 
  215   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
  218   std::vector<uint8_t> auth_data(1);
 
  220   BOOST_CHECK_EXCEPTION(make_webauthn_sig(priv, auth_data, 
json).recover(d, 
true), fc::assert_exception, [](
const fc::assert_exception& e) {
 
  221      return e.to_detail_string().find(
"auth_data not as large as required") != std::string::npos;
 
 
  227   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
  230   std::vector<uint8_t> auth_data(37);
 
  231   memcpy(auth_data.data(), origin_hash.
data(), 
sizeof(origin_hash));
 
  233   BOOST_CHECK_EXCEPTION(make_webauthn_sig(priv, auth_data, 
json).recover(d, 
true), fc::assert_exception, [](
const fc::assert_exception& e) {
 
  234      return e.to_detail_string().find(
"webauthn origin must begin with https://") != std::string::npos;
 
 
  240   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
  243   std::vector<uint8_t> auth_data(37);
 
  244   memcpy(auth_data.data(), origin_hash.
data(), 
sizeof(origin_hash));
 
  246   BOOST_CHECK_EXCEPTION(make_webauthn_sig(priv, auth_data, 
json).recover(d, 
true), fc::assert_exception, [](
const fc::assert_exception& e) {
 
  247      return e.to_detail_string().find(
"webauthn signature type not an assertion") != std::string::npos;
 
 
  253   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
  254   std::string 
json = 
"{\"origin\":\"https://fctesting.invalid\",\"type\":\"webauthn.get\"}";
 
  256   std::vector<uint8_t> auth_data(37);
 
  257   memcpy(auth_data.data(), origin_hash.
data(), 
sizeof(origin_hash));
 
  260      return e.
to_detail_string().find(
"sha256: size mismatch") != std::string::npos;
 
 
  266   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
  267   std::string 
json = 
"{\"origin\":\"https://fctesting.invalid\",\"cool\":\"beans\",\"obj\":{\"array\":[4, 5, 6]}," 
  270   std::vector<uint8_t> auth_data(37);
 
  271   memcpy(auth_data.data(), origin_hash.
data(), 
sizeof(origin_hash));
 
  273   BOOST_CHECK_EQUAL(wa_pub, make_webauthn_sig(priv, auth_data, 
json).recover(d, 
true));
 
 
  278   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
  279   std::string 
json = 
"hey man"s;
 
  281   std::vector<uint8_t> auth_data(37);
 
  282   memcpy(auth_data.data(), origin_hash.
data(), 
sizeof(origin_hash));
 
  284   BOOST_CHECK_EXCEPTION(make_webauthn_sig(priv, auth_data, 
json).recover(d, 
true), fc::assert_exception, [](
const fc::assert_exception& e) {
 
  285      return e.to_detail_string().find(
"Failed to parse client data JSON") != std::string::npos;
 
 
  291   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
  294   std::vector<uint8_t> auth_data(37);
 
  295   memcpy(auth_data.data(), origin_hash.
data(), 
sizeof(origin_hash));
 
  305   bool failed_recovery = 
false;
 
  306   bool failed_compare = 
false;
 
  310      recovered_pub = sig.
recover(d, 
true);
 
  311      failed_compare = !(wa_pub == recovered_pub);
 
  314      failed_recovery = e.
to_detail_string().find(
"unable to reconstruct public key from signature") != std::string::npos;
 
  318   BOOST_CHECK_EQUAL(failed_recovery || failed_compare, 
true);
 
 
  323   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
  326   std::vector<uint8_t> auth_data(37);
 
  327   memcpy(auth_data.data(), origin_hash.
data(), 
sizeof(origin_hash));
 
  337   bool failed_recovery = 
false;
 
  338   bool failed_compare = 
false;
 
  342      recovered_pub = sig.
recover(d, 
true);
 
  343      failed_compare = !(wa_pub == recovered_pub);
 
  346      failed_recovery = e.
to_detail_string().find(
"unable to reconstruct public key from signature") != std::string::npos;
 
  350   BOOST_CHECK_EQUAL(failed_recovery || failed_compare, 
true);
 
 
  357   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
  360   std::vector<uint8_t> auth_data(37);
 
  361   memcpy(auth_data.data(), origin_hash.
data(), 
sizeof(origin_hash));
 
  363   BOOST_CHECK_NE(wa_pub, make_webauthn_sig(other_priv, auth_data, 
json).recover(d, 
true));
 
 
  368   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
  371   std::vector<uint8_t> auth_data(37);
 
  372   memcpy(auth_data.data(), origin_hash.
data(), 
sizeof(origin_hash));
 
  374   BOOST_CHECK_EXCEPTION(make_webauthn_sig(priv, auth_data, 
json).recover(d, 
true), fc::assert_exception, [](
const fc::assert_exception& e) {
 
  375      return e.to_detail_string().find(
"Failed to parse client data JSON") != std::string::npos;
 
 
  385   BOOST_CHECK_EXCEPTION(
fc::raw::unpack(ds, 
pubkey), fc::assert_exception, [](
const fc::assert_exception& e) {
 
  386      return e.to_detail_string().find(
"webauthn pubkey must have non empty rpid") != std::string::npos;
 
 
  392   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
  395   boost::erase_all(
json, 
"=");
 
  397   std::vector<uint8_t> auth_data(37);
 
  398   memcpy(auth_data.data(), origin_hash.
data(), 
sizeof(origin_hash));
 
  400   BOOST_CHECK_EQUAL(wa_pub, make_webauthn_sig(priv, auth_data, 
json).recover(d, 
true));
 
 
  407   webauthn::public_key wa_pub(pub.serialize(), webauthn::public_key::user_presence_t::USER_PRESENCE_NONE, 
"fctesting.invalid");
 
  410   boost::erase_all(
json, 
"=");
 
  412   std::vector<uint8_t> auth_data(37);
 
  413   memcpy(auth_data.data(), origin_hash.
data(), 
sizeof(origin_hash));
 
  416      return e.
to_detail_string().find(
"encountered non-base64 character") != std::string::npos;
 
 
  420BOOST_AUTO_TEST_SUITE_END()
 
an elliptic curve private key.
 
compact_signature sign_compact(const fc::sha256 &digest) const
 
static private_key generate()
 
contains only the public point of an elliptic curve key.
 
public_key recover(const sha256 &digest, bool check_canonical) const
 
Used to generate a useful error report when an exception is thrown.
 
std::string to_detail_string(log_level ll=log_level::all) const
 
void write(const char *d, uint32_t dlen)
 
static sha256 hash(const char *d, uint32_t dlen)
 
const char * data() const
 
void unpack(Stream &s, std::deque< T > &value)
 
void pack(Stream &s, const std::deque< T > &value)
 
std::string base64url_encode(unsigned char const *bytes_to_encode, unsigned int in_len)
 
BOOST_AUTO_TEST_CASE(good)
 
memcpy((char *) pInfo->slotDescription, s, l)