#include "cbor.h"
#include "cbor_encoding.h"
#include "crypto/random.h"
+#include "exception.h"
#include "log/log.h"
#include "tunnel_server_domain.h"
#include <chrono>
#include <iomanip>
#include <sstream>
-#include <webauthn-hal.h>
using namespace std;
return extraKey;
}
-wauthn_error_e Cbor::EncodeQRContents(const CryptoBuffer &publicKey,
- const CryptoBuffer &qrSecret,
- const Hint &hint,
- bool stateAssisted,
- string &fidoUri)
+void Cbor::EncodeQRContents(const CryptoBuffer &publicKey,
+ const CryptoBuffer &qrSecret,
+ const Hint &hint,
+ bool stateAssisted,
+ string &fidoUri)
{
size_t buffSize = 73; // epoch is int64 which may take up to 8B (9B with key) in CBOR
size_t mapElements = 6;
// Integer value < 24 uses only one byte, larger value use more bytes
if (ASSIGNED_TUNNEL_SERVER_DOMAINS.size() >= 24) {
LogError("larger encoding needed!");
- return WAUTHN_ERROR_ENCODING_FAILED;
+ throw EncodingFailed{};
}
bool extraKey = getGrease();
cbor_encoder_init(&encoder, buffer.data(), buffer.size(), 0);
if ((err = cbor_encoder_create_map(&encoder, &mapEncoder, mapElements))) {
LogError("cbor_encoder_create_map error");
- goto cborError;
+ throw EncodingFailed{};
}
// key 0 - public key
if ((err = cbor_encode_int(&mapEncoder, 0))) {
LogError("cbor_encode_int error in public key encoding");
- goto cborError;
+ throw EncodingFailed{};
}
if ((err = cbor_encode_byte_string(&mapEncoder, publicKey.data(), publicKey.size()))) {
LogError("cbor_encode_byte_string error in public key encoding");
- goto cborError;
+ throw EncodingFailed{};
}
// key 1 - QR Secret
if ((err = cbor_encode_int(&mapEncoder, 1))) {
LogError("cbor_encode_int error in QR secret encoding");
- goto cborError;
+ throw EncodingFailed{};
}
if ((err = cbor_encode_byte_string(&mapEncoder, qrSecret.data(), qrSecret.size()))) {
LogError("cbor_encode_byte_string error in QR secret encoding");
- goto cborError;
+ throw EncodingFailed{};
}
// key 2 - assigned tunnel servers domains
if ((err = cbor_encode_int(&mapEncoder, 2))) {
LogError("cbor_encode_int error in tunnel servers domains encoding");
- goto cborError;
+ throw EncodingFailed{};
}
if ((err = cbor_encode_int(&mapEncoder, ASSIGNED_TUNNEL_SERVER_DOMAINS.size()))) {
LogError("cbor_encode_int error in tunnel servers domains encoding");
- goto cborError;
+ throw EncodingFailed{};
}
// key 3 - current time
if ((err = cbor_encode_int(&mapEncoder, 3))) {
LogError("cbor_encode_int error in time encoding");
- goto cborError;
+ throw EncodingFailed{};
}
if ((err = cbor_encode_int(&mapEncoder, getEpoch()))) {
LogError("cbor_encode_int error in time encoding");
- goto cborError;
+ throw EncodingFailed{};
}
// key 4 - state assisted transactions
if ((err = cbor_encode_int(&mapEncoder, 4))) {
LogError("cbor_encode_int error in state assisted transactions encoding");
- goto cborError;
+ throw EncodingFailed{};
}
if ((err = cbor_encode_boolean(&mapEncoder, stateAssisted))) {
LogError("cbor_encode_boolean error in state assisted transactions encoding");
- goto cborError;
+ throw EncodingFailed{};
}
// key 5 - "ga" if get assertion and "mc" if make credential
if ((err = cbor_encode_int(&mapEncoder, 5))) {
LogError("cbor_encode_int error in hint encoding");
- goto cborError;
+ throw EncodingFailed{};
}
// Here specification says byte string with which Android does not work. webauthn.io uses text
// string which works.
if ((err = cbor_encode_text_string(&mapEncoder, hint.data(), hint.size()))) {
LogError("cbor_encode_text_string error in hint encoding");
- goto cborError;
+ throw EncodingFailed{};
}
// key 6 - when GREASE is true
if (extraKey) {
if ((err = cbor_encode_int(&mapEncoder, 65535))) {
LogError("cbor_encode_int error in GREASE");
- goto cborError;
+ throw EncodingFailed{};
}
if ((err = cbor_encode_int(&mapEncoder, 0))) {
LogError("cbor_encode_int error in GREASE");
- goto cborError;
+ throw EncodingFailed{};
}
}
if ((err = cbor_encoder_close_container(&encoder, &mapEncoder))) {
LogError("Cbor encode error: cannot close container");
- goto cborError;
+ throw EncodingFailed{};
}
buffSize = cbor_encoder_get_buffer_size(&encoder, buffer.data());
buffer.resize(buffSize);
fidoUri = "FIDO:/" + DigitEncode(buffer);
- return WAUTHN_ERROR_NONE;
-
-cborError:
- return WAUTHN_ERROR_ENCODING_FAILED;
}
} // namespace CborEncoding
#include "crypto/common.h"
#include <string>
-#include <webauthn-types.h>
namespace CborEncoding {
Cbor &operator=(Cbor &&) = delete;
virtual ~Cbor() = default;
- wauthn_error_e EncodeQRContents(const CryptoBuffer &publicKey,
- const CryptoBuffer &qrSecret,
- const Hint &hint,
- bool stateAssisted,
- std::string &fidoUri);
+ // Throws on error.
+ void EncodeQRContents(const CryptoBuffer &publicKey,
+ const CryptoBuffer &qrSecret,
+ const Hint &hint,
+ bool stateAssisted,
+ std::string &fidoUri);
protected:
virtual int64_t getEpoch() const;
auto qrSecret = Crypto::RandomBytes(16);
auto identityKeyCompressed = Crypto::GenerateCompressedX9_62_P_256_Key();
- auto qrErr = ShowQRCode(qrSecret, identityKeyCompressed);
- if (qrErr != WAUTHN_ERROR_NONE)
- return qrErr;
+ ShowQRCode(qrSecret, identityKeyCompressed);
auto eidKey = DeriveKey(qrSecret, {}, KeyPurpose::EIDKey, 64);
return WAUTHN_ERROR_NONE;
}
-wauthn_error_e Request::ShowQRCode(const CryptoBuffer &qrSecret,
- const CryptoBuffer &identityKeyCompressed)
+void Request::ShowQRCode(const CryptoBuffer &qrSecret, const CryptoBuffer &identityKeyCompressed)
{
std::string fidoUri;
CborEncoding::Cbor cbor;
- wauthn_error_e ret =
- cbor.EncodeQRContents(identityKeyCompressed, qrSecret, GetHint(), StateAssisted(), fidoUri);
-
- if (ret != WAUTHN_ERROR_NONE)
- return ret;
+ cbor.EncodeQRContents(identityKeyCompressed, qrSecret, GetHint(), StateAssisted(), fidoUri);
QRCallback(fidoUri);
-
- return WAUTHN_ERROR_NONE;
}
bool StateAssisted() const { return LinkData() != nullptr; }
- wauthn_error_e ShowQRCode(const CryptoBuffer &qrSecret,
- const CryptoBuffer &identityKeyCompressed);
+ void ShowQRCode(const CryptoBuffer &qrSecret, const CryptoBuffer &identityKeyCompressed);
virtual Hint GetHint() const = 0;
private:
TEST(WebAuthnBleTest, testCborEncodeCurrTime)
{
- int ret = WAUTHN_ERROR_NONE;
std::string str;
CborEncoding::Cbor cb;
- ret = cb.EncodeQRContents(PUBKEY1, SECRET1, GA, false, str);
-
- EXPECT_EQ(ret, WAUTHN_ERROR_NONE) << "[EncodeQRContents] failed. " << std::endl;
+ EXPECT_NO_THROW(cb.EncodeQRContents(PUBKEY1, SECRET1, GA, false, str));
}
TEST(WebAuthnBleTest, testCborEncodeGivenTime)
{
- int ret = WAUTHN_ERROR_NONE;
std::string str;
DT = {4, 46, 30, 7, 6, 2023};
EXTRAKEY = true;
MockCbor cb;
- ret = cb.EncodeQRContents(PUBKEY1, SECRET1, MC, false, str);
-
- EXPECT_EQ(ret, WAUTHN_ERROR_NONE) << "[EncodeQRContents] failed. " << std::endl;
+ EXPECT_NO_THROW(cb.EncodeQRContents(PUBKEY1, SECRET1, MC, false, str));
}
TEST(WebAuthnBleTest, testCborEncodeMaxLength)
int64_t getEpoch() const override { return INT64_MAX; }
} cb;
- int ret = WAUTHN_ERROR_NONE;
std::string str;
EXTRAKEY = true;
- ret = cb.EncodeQRContents(PUBKEY1, SECRET1, MC, false, str);
-
- EXPECT_EQ(ret, WAUTHN_ERROR_NONE) << "[EncodeQRContents] failed. " << std::endl;
+ EXPECT_NO_THROW(cb.EncodeQRContents(PUBKEY1, SECRET1, MC, false, str));
}
TEST(WebAuthnBleTest, testCborEncodeExtraKey)
{
- int ret = WAUTHN_ERROR_NONE;
std::string str;
EXTRAKEY = true;
MockRandCbor cb;
- ret = cb.EncodeQRContents(PUBKEY1, SECRET1, MC, false, str);
-
- EXPECT_EQ(ret, WAUTHN_ERROR_NONE) << "[EncodeQRContents] failed. " << std::endl;
+ EXPECT_NO_THROW(cb.EncodeQRContents(PUBKEY1, SECRET1, MC, false, str));
}
TEST(WebAuthnBleTest, testCborEncodeStateAssisted)
{
- int ret = WAUTHN_ERROR_NONE;
std::string str;
EXTRAKEY = false;
MockRandCbor cb;
- ret = cb.EncodeQRContents(PUBKEY1, SECRET1, MC, true, str);
-
- EXPECT_EQ(ret, WAUTHN_ERROR_NONE) << "[EncodeQRContents] failed. " << std::endl;
+ EXPECT_NO_THROW(cb.EncodeQRContents(PUBKEY1, SECRET1, MC, true, str));
}
TEST(WebAuthnBleTest, testCborDocsExample1)
{
- int ret = WAUTHN_ERROR_NONE;
std::string str;
// this string is an CBOR map generated via cbor.me based on parameters used in this test
EXTRAKEY = true;
MockCbor cb;
- ret = cb.EncodeQRContents(PUBKEY_EXAMPLE_1, SECRET_EXAMPLE_1, MC, true, str);
-
- EXPECT_EQ(ret, WAUTHN_ERROR_NONE) << "[EncodeQRContents] failed. " << std::endl;
-
+ EXPECT_NO_THROW(cb.EncodeQRContents(PUBKEY_EXAMPLE_1, SECRET_EXAMPLE_1, MC, true, str));
EXPECT_EQ(str, exp) << "[EncodeQRContents] failed." << std::endl;
}
TEST(WebAuthnBleTest, testCborDocsExample2)
{
- int ret = WAUTHN_ERROR_NONE;
std::string str;
// this string is an CBOR map generated via cbor.me based on parameters used in this test
EXTRAKEY = false;
MockCbor cb;
- ret = cb.EncodeQRContents(PUBKEY_EXAMPLE_2, SECRET_EXAMPLE_2, GA, true, str);
-
- EXPECT_EQ(ret, WAUTHN_ERROR_NONE) << "[EncodeQRContents] failed." << std::endl;
+ EXPECT_NO_THROW(cb.EncodeQRContents(PUBKEY_EXAMPLE_2, SECRET_EXAMPLE_2, GA, true, str));
EXPECT_EQ(str, exp) << "[EncodeQRContents] failed." << std::endl;
}