#include <cstring>
#include <iostream>
#include <mv_barcode.h>
+#include <optional>
#include <string_view>
#include <vector>
#include <webauthn.h>
namespace {
+template <class T>
+wauthn_const_buffer_s ToWauthnConstBuff(T &x) noexcept
+{
+ static_assert(sizeof(decltype(*x.data())) == 1, "for reinterpret_cast below");
+ // reinterpret_cast is for std::string input values
+ return wauthn_const_buffer_s{reinterpret_cast<const uint8_t *>(x.data()), x.size()};
+}
+
+inline wauthn_const_buffer_s ToWauthnConstBuff(const char *stringLiteral) noexcept
+{
+ return wauthn_const_buffer_s{reinterpret_cast<const u_int8_t *>(stringLiteral),
+ std::strlen(stringLiteral)};
+}
+
+typedef std::vector<uint8_t> Buffer;
+
+Buffer ToBuffer(wauthn_const_buffer_s buff)
+{
+ return Buffer{buff.data, buff.data + buff.size};
+}
+
+struct LinkedData {
+ Buffer contactId;
+ Buffer linkId;
+ Buffer linkSecret;
+ Buffer authenticatorPubKey;
+ Buffer authenticatorName;
+ Buffer signature;
+ Buffer tunnelServerDomain;
+ Buffer identityKey;
+};
+
template <class Bytes>
std::string LowercaseHexStringOf(const Bytes &bytes)
{
return res;
}
-typedef std::vector<uint8_t> Buffer;
-
struct TestContents {
int status;
std::string path;
Buffer credentialRawId;
Buffer userId;
unsigned transports = WAUTHN_TRANSPORT_NONE;
- bool negative = false;
-};
+ std::optional<LinkedData> linkedData;
+ bool negative;
+ void UpdateLinkedData(const wauthn_hybrid_linked_data_s *ld)
+ {
+ if (ld) {
+ linkedData.emplace();
+ linkedData->contactId = ToBuffer(*ld->contact_id);
+ linkedData->linkId = ToBuffer(*ld->link_id);
+ linkedData->linkSecret = ToBuffer(*ld->link_secret);
+ linkedData->authenticatorPubKey = ToBuffer(*ld->authenticator_pubkey);
+ linkedData->authenticatorName = ToBuffer(*ld->authenticator_name);
+ linkedData->signature = ToBuffer(*ld->signature);
+ linkedData->tunnelServerDomain = ToBuffer(*ld->tunnel_server_domain);
+ linkedData->identityKey = ToBuffer(*ld->identity_key);
+ } else {
+ linkedData = std::nullopt;
+ }
+ }
+};
void DisplayQR(struct TestContents &contents)
{
GenerateAndDisplayQR(encoded, *testContents);
}
-Buffer ToBuffer(wauthn_const_buffer_s buff) { return Buffer{buff.data, buff.data + buff.size}; }
-
void MCCallback(const wauthn_pubkey_credential_attestation_s *pubkey_cred,
wauthn_error_e result,
void *data)
{
auto *testContents = static_cast<TestContents *>(data);
- if (pubkey_cred == nullptr || result != WAUTHN_ERROR_NONE || testContents->path.empty()) {
+ if (pubkey_cred == nullptr || result != WAUTHN_ERROR_NONE) {
std::cout << __FUNCTION__ << ": response_callback failed\n"
<< "Error code: " << result << std::endl;
testContents->status = -1;
<< std::endl;
testContents->transports = pubkey_cred->response->transports;
testContents->status = 1;
+ if (pubkey_cred->linked_device != nullptr)
+ testContents->UpdateLinkedData(pubkey_cred->linked_device);
}
void GACallback(const wauthn_pubkey_credential_assertion_s *pubkey_cred,
void *data)
{
auto *testContents = static_cast<TestContents *>(data);
- if (pubkey_cred == nullptr || result != WAUTHN_ERROR_NONE || testContents->path.empty()) {
+ if (pubkey_cred == nullptr || result != WAUTHN_ERROR_NONE) {
std::cout << __FUNCTION__ << ": response_callback failed\n"
<< "Error code: " << result << std::endl;
testContents->status = -1;
}
}
testContents->status = 2;
+ if (pubkey_cred->linked_device != nullptr)
+ testContents->UpdateLinkedData(pubkey_cred->linked_device);
}
-/* TBD
+
void UpdateLinkedDataCallback(const wauthn_hybrid_linked_data_s *linked_data,
wauthn_error_e result,
- void *user_data)
+ void *data)
{
+ auto *testContents = static_cast<TestContents *>(data);
+ if (result != WAUTHN_ERROR_NONE && result != WAUTHN_ERROR_NONE_AND_WAIT) {
+ std::cout << __FUNCTION__ << ": failed\n"
+ << "Error code: " << result << std::endl;
+ testContents->status = -1;
+ return;
+ }
+ if (testContents->status == 1)
+ testContents->status = 10;
+ else if (testContents->status == 2)
+ testContents->status = 20;
+ if (linked_data != nullptr)
+ testContents->UpdateLinkedData(linked_data);
}
-*/
+
bool Test(struct TestContents &testContents)
{
/* MakeCredential */
wauthn_mc_callbacks_s mcCallbacks;
mcCallbacks.qrcode_callback = DisplayQRCallback;
mcCallbacks.response_callback = MCCallback;
- // TODO: Add UpdateLinkedDataCallback with the webauthn-ble's update
+ mcCallbacks.linked_data_callback = UpdateLinkedDataCallback;
mcCallbacks.user_data = &testContents;
int ret = wauthn_make_credential(&clientData, &mcOptions, &mcCallbacks);
return false;
}
+ // Checking whether the update_linked_data callback is called or not
+ // The callback would called 1 sec after called response callback
+ // TODO: Need to be checked concurrently after webauthn-ble is updated
+ sleep(2);
+ if (testContents.status != 10) {
+ return false;
+ }
+
+
/* GetAssertion */
std::cout << "Step for Get Assertion" << std::endl;
- constexpr auto toWauthnConstBuff = [](const Buffer &buff) {
- return wauthn_const_buffer_s{buff.data(), buff.size()};
- };
- wauthn_const_buffer_s credentialId = toWauthnConstBuff(testContents.credentialRawId);
+ wauthn_const_buffer_s credentialId = ToWauthnConstBuff(testContents.credentialRawId);
wauthn_pubkey_cred_descriptor_s pubkeyCredDescriptor;
pubkeyCredDescriptor.type = PCT_PUBLIC_KEY;
pubkeyCredDescriptors.size = 1;
pubkeyCredDescriptors.descriptors = &pubkeyCredDescriptor;
+ wauthn_const_buffer_s contactId;
+ wauthn_const_buffer_s linkId;
+ wauthn_const_buffer_s linkSecret;
+ wauthn_const_buffer_s authenticatorPubKey;
+ wauthn_const_buffer_s authenticatorName;
+ wauthn_const_buffer_s signature;
+ wauthn_const_buffer_s tunnelServerDomain;
+ wauthn_const_buffer_s identityKey;
+
+ wauthn_hybrid_linked_data_s linkedDevice;
+ if (testContents.linkedData) {
+ std::cout << "linkedData is exist" << std::endl;
+ contactId = ToWauthnConstBuff(testContents.linkedData->contactId);
+ linkId = ToWauthnConstBuff(testContents.linkedData->linkId);
+ linkSecret = ToWauthnConstBuff(testContents.linkedData->linkSecret);
+ authenticatorPubKey = ToWauthnConstBuff(testContents.linkedData->authenticatorPubKey);
+ authenticatorName = ToWauthnConstBuff(testContents.linkedData->authenticatorName);
+ signature = ToWauthnConstBuff(testContents.linkedData->signature);
+ tunnelServerDomain = ToWauthnConstBuff(testContents.linkedData->tunnelServerDomain);
+ identityKey = ToWauthnConstBuff(testContents.linkedData->identityKey);
+
+ linkedDevice.contact_id = &contactId;
+ linkedDevice.link_id = &linkId;
+ linkedDevice.link_secret = &linkSecret;
+ linkedDevice.authenticator_pubkey = &authenticatorPubKey;
+ linkedDevice.authenticator_name = &authenticatorName;
+ linkedDevice.signature = &signature;
+ linkedDevice.tunnel_server_domain = &tunnelServerDomain;
+ linkedDevice.identity_key = &identityKey;
+ }
+
wauthn_pubkey_cred_request_options_s gaOptions;
gaOptions.timeout = 60000; // 60s
gaOptions.rpId = rpId;
gaOptions.attestation = AP_NONE;
gaOptions.attestation_formats = nullptr;
gaOptions.extensions = nullptr;
- gaOptions.linked_device = nullptr;
+ gaOptions.linked_device = testContents.linkedData ? &linkedDevice : nullptr;
wauthn_ga_callbacks_s gaCallbacks;
gaCallbacks.qrcode_callback = DisplayQRCallback;
gaCallbacks.response_callback = GACallback;
- // TODO: Add UpdateLinkedDataCallback with the webauthn-ble's update
+ gaCallbacks.linked_data_callback = UpdateLinkedDataCallback;
gaCallbacks.user_data = &testContents;
ret = wauthn_get_assertion(&clientData, &gaOptions, &gaCallbacks);
std::cout << "ret: " << wauthn_error_to_string(ret) << std::endl;
timeCount = 120;
std::cout << "Waiting for 120 seconds.." << std::endl;
- while (testContents.status == 1 && timeCount != 0)
+ while (testContents.status == 10 && timeCount != 0)
{
std::cout << " " << timeCount;
sleep(1);
if (testContents.status != 2) {
return false;
}
+ // Checking whether the update_linked_data callback is called or not
+ // The callback would called 1 sec after called response callback
+ // TODO: Need to be checked concurrently after webauthn-ble is updated
+ sleep(2);
+ if (testContents.status != 20) {
+ return false;
+ }
return true;
}
int main(int argc, char *argv[])
{
TestContents testContents = {0, "/tmp/webauthn-qrcode.png",
- {}, {}, WAUTHN_TRANSPORT_NONE};
+ {}, {}, WAUTHN_TRANSPORT_NONE,
+ std::nullopt, false};
if (argc == 2)
{