LogDebug("Hybrid hint removed");
} else {
m_testContents.prefLevel.push_back(WAUTHN_PUBKEY_CRED_HINT_HYBRID);
- LogDebug("Hybrid hint removed");
+ LogDebug("Hybrid hint added");
}
}
std::string hintsText = " { ";
auto appGUI = static_cast<AppGUI *>(data);
if (appGUI->m_testContents.status != TestState::REG_SUCCCEEDED)
- elm_object_text_set(appGUI->m_testInfo, _("<color=#FF0000FF>REGISTRATION FAILED!</color>"));
+ {
+ elm_object_text_set(appGUI->m_testResult,
+ _("<color=#FF0000FF>REGISTRATION FAILED!</color>"));
+ std::string coloredMsg = "<color=#FF0000FF>"
+ + appGUI->m_testContents.testMsg
+ + "</color>";
+ elm_object_text_set(appGUI->m_resultInfo, _(coloredMsg.c_str()));
+ }
else
- elm_object_text_set(appGUI->m_testInfo,
+ elm_object_text_set(appGUI->m_testResult,
_("<color=#00FF00FF>REGISTRATION COMPLETED!</color>"));
return NULL;
auto appGUI = static_cast<AppGUI *>(data);
if (appGUI->m_testContents.status != TestState::AUTH_SUCCCEEDED)
- elm_object_text_set(appGUI->m_testInfo,
+ {
+ elm_object_text_set(appGUI->m_testResult,
_("<color=#FF0000FF>AUTHENTICATION FAILED!</color>"));
+ std::string coloredMsg = "<color=#FF0000FF>"
+ + appGUI->m_testContents.testMsg
+ + "</color>";
+ elm_object_text_set(appGUI->m_resultInfo, _(coloredMsg.c_str()));
+ }
else
- elm_object_text_set(appGUI->m_testInfo,
+ elm_object_text_set(appGUI->m_testResult,
_("<color=#00FF00FF>AUTHENTICATION COMPLETED!</color>"));
return NULL;
}
+void *AppGUI::UpdateCreatedUserIds(void *data)
+{
+ auto appGUI = static_cast<AppGUI *>(data);
+
+ std::string userIdsText = "Created usernames: { ";
+ for (auto const& cred : appGUI->m_testContents.createdCredDescs)
+ {
+ userIdsText += std::string(cred.first.begin(), cred.first.end());
+ }
+ userIdsText += "} ";
+ std::cout << userIdsText.c_str() << std::endl;
+ elm_object_text_set(appGUI->m_createdUserIds, userIdsText.c_str());
+
+ return NULL;
+}
+
void AppGUI::RegisterStaticCb(void *data, Ecore_Thread *thread EINA_UNUSED)
{
auto appGUI = static_cast<AppGUI *>(data);
TestMC(m_testContents);
ecore_main_loop_thread_safe_call_sync(CleanQRFieldAndEnableUI, this);
ecore_main_loop_thread_safe_call_sync(UpdateRegStatus, this);
+ ecore_main_loop_thread_safe_call_sync(UpdateCreatedUserIds, this);
}
void AppGUI::RegisterButtonClickedStaticCb(void *data,
{
std::ostringstream log;
- elm_object_text_set(m_testInfo, "");
+ elm_object_text_set(m_testResult, "");
+ elm_object_text_set(m_resultInfo, "");
+ m_testContents.username = elm_object_text_get(m_entry);
+ log << "Registering username: " << m_testContents.username << std::endl;
+ LogDebug(log.str().c_str());
+ size_t userIdLength = strlen(m_testContents.username);
+ if(userIdLength == 0)
+ {
+ m_testContents.testMsg = "Username is required for register";
+ ecore_main_loop_thread_safe_call_sync(UpdateAuthStatus, this);
+ return;
+ }
+
DisableUIComponents(EINA_TRUE);
evas_object_show(m_cancelBt);
- m_testContents.status = TestState::REG_IN_PROCESS;
- m_testContents.username = elm_object_text_get(m_entry);
- log << "Registering username: " << m_testContents.username << std::endl;
- LogDebug(log.str().c_str());
+ m_testContents.status = TestState::REG_IN_PROCESS;
ecore_thread_run(RegisterStaticCb, NULL, NULL, this);
}
TestGA(m_testContents);
ecore_main_loop_thread_safe_call_sync(CleanQRFieldAndEnableUI, this);
ecore_main_loop_thread_safe_call_sync(UpdateAuthStatus, this);
+ ecore_main_loop_thread_safe_call_sync(UpdateCreatedUserIds, this);
}
void AppGUI::AuthenticateButtonClickedCb()
{
std::ostringstream log;
- if ((m_testContents.status != TestState::AUTH_SUCCCEEDED) &&
- (m_testContents.status != TestState::REG_SUCCCEEDED)) {
+ elm_object_text_set(m_testResult, "");
+ elm_object_text_set(m_resultInfo, "");
+ if (m_testContents.createdCredDescs.size() == 0) {
std::cout << "Cannot authenticate, you need to register first!\n";
+ m_testContents.testMsg = "There is no created credential";
ecore_main_loop_thread_safe_call_sync(UpdateAuthStatus, this);
return;
}
-
- elm_object_text_set(m_testInfo, "");
DisableUIComponents(EINA_TRUE);
evas_object_show(m_cancelBt);
int ret = CancelTest();
if (ret != 0) {
elm_object_text_set(
- m_testInfo, _("<color=#FF0000FF>CANNOT CANCEL! WAIT FOR END OF THE SCENARIO</color>"));
+ m_testResult,
+ _("<color=#FF0000FF>CANNOT CANCEL! WAIT FOR END OF THE SCENARIO</color>"));
return;
}
Evas_Object *labelUN = nullptr;
m_uiComp->AddLabel("Username", &labelUN);
m_uiComp->AddEntry("testUser", &m_entry);
+ m_uiComp->AddLabel("Created usernames: { }", &m_createdUserIds);
+
+ /* Run scenarios buttons */
+ m_uiComp->AddButton("Register", &m_regBt, RegisterButtonClickedStaticCb, DARK_BLUE, this);
+ m_uiComp->AddButton(
+ "Authenticate", &m_authBt, AuthenticateButtonClickedStaticCb, DARK_BLUE, this);
+ m_uiComp->AddButton("Terminate", &m_terBt, WindowDeleteCb, DARK_BLUE, this, true);
+ m_uiComp->AddLabel(" ", &m_testResult);
+ m_uiComp->AddLabel(" ", &m_resultInfo);
+
+ m_uiComp->AddCancelButton("Cancel", &m_cancelBt, CancelButtonStaticCb, DARK_BLUE, this);
/* Public Key Algorithms */
Evas_Object *labelPKA = nullptr;
m_uiComp->AddButton("None", &m_atteBtNone, AttestationButtonStaticCb, PURPLE, this);
m_uiComp->AddButton("Direct", &m_atteBtDir, AttestationButtonStaticCb, LIGHT_BLUE, this, true);
- /* Run scenarios buttons */
- m_uiComp->AddButton("Register", &m_regBt, RegisterButtonClickedStaticCb, DARK_BLUE, this);
- m_uiComp->AddButton(
- "Authenticate", &m_authBt, AuthenticateButtonClickedStaticCb, DARK_BLUE, this);
- m_uiComp->AddButton("Terminate", &m_terBt, WindowDeleteCb, DARK_BLUE, this, true);
- m_uiComp->AddLabel(" ", &m_testInfo);
-
- m_uiComp->AddCancelButton("Cancel...", &m_cancelBt, CancelButtonStaticCb, DARK_BLUE, this);
m_uiComp->ShowWindow();
}
constexpr inline char RP_ID[] = "webauthn-manual-test-rpID";
wauthn_rp_entity_s RP_ENTITY = {RP_NAME, RP_ID};
-// names and an identifier for the user account
-constexpr inline char USER_ID_RAW[] = "\x64\x47\x56\x7a\x64\x44\x4d\x79\x4d\x77";
-wauthn_const_buffer_s USER_ID = {reinterpret_cast<const uint8_t *>(USER_ID_RAW),
- sizeof(USER_ID_RAW) - 1};
-
constexpr unsigned long TIMEOUT = 120'000;
// client data
if (!ret) {
std::cout << "mv_barcode_generate_image failed\n"
- << "Error code: " << ret << std::endl;
+ << "Error code: " << get_error_message(ret) << std::endl;
goto callback_failed;
} else {
std::cout << "mv_barcode_generate_image PASSED\n";
wauthn_error_e result,
void *data)
{
+ Buffer credRawId;
+ CredDescriptor credDesc;
std::cout << "MC: response_callback() was called." << std::endl;
TestContents *contents = static_cast<TestContents *>(data);
if (result == WAUTHN_ERROR_TIMED_OUT) {
- std::cout << "MC: request timed out" << std::endl;
+ contents->testMsg = "Timed out";
goto callback_failed;
}
if (result != WAUTHN_ERROR_NONE) {
- std::cout << "MC: Response_callback failed, Error code: " << result << std::endl;
+ contents->testMsg = "Response_callback Error: " + std::string(get_error_message(result));
goto callback_failed;
}
if (!pubkey_cred) {
- std::cout << "MC: pubkey_cred is null\n";
+ contents->testMsg = "pubkey_cred is NULL";
goto callback_failed;
}
if (!pubkey_cred->rawId) {
- std::cout << "MC: pubkey_cred->rawId is NULL\n";
+ contents->testMsg = "pubkey_cred->rawId is NULL";
goto callback_failed;
}
if (!pubkey_cred->response) {
- std::cout << "MC: pubkey_cred->response is NULL\n";
+ contents->testMsg = "pubkey_cred->response is NULL";
goto callback_failed;
}
-
- contents->credentialRawId = ToBuffer(*pubkey_cred->rawId);
- std::cout << "MC: credentialRawId: " << LowercaseHexStringOf(contents->credentialRawId)
- << std::endl;
- contents->transports = pubkey_cred->response->transports;
+ credRawId = ToBuffer(*pubkey_cred->rawId);
+ credDesc = {pubkey_cred->type, credRawId, pubkey_cred->response->transports};
+ std::cout << "MC: credentialRawId: " << LowercaseHexStringOf(credRawId) << std::endl;
+ contents->createdCredDescs[contents->userId] = credDesc;
+ std::cout << "MakeCredential: awaiting potential CTAP UPDATE messages..." << std::endl;
contents->UpdateLinkedData(pubkey_cred->linked_device);
return;
callback_failed:
+ std::cout << "MC: " << contents->testMsg.c_str() << std::endl;
contents->status = TestState::RESP_MC_CB_FAILED;
contents->finished = true;
contents->cv.notify_one();
Buffer credentialRawId;
if (result == WAUTHN_ERROR_TIMED_OUT) {
- std::cout << "GA: request timed out" << std::endl;
+ contents->testMsg = "Timed out";
}
if (result != WAUTHN_ERROR_NONE) {
- std::cout << "GA: response_callback failed with code " << result << std::endl;
+ contents->testMsg = "Response_callback Error: " + std::string(get_error_message(result));
goto callback_failed;
}
if (!pubkey_cred) {
- std::cout << "GA: pubkey_cred is NULL" << std::endl;
+ contents->testMsg = "pubkey_cred is NULL";
goto callback_failed;
}
if (!pubkey_cred->rawId) {
- std::cout << "GA: pubkey_cred->rawId is NULL" << std::endl;
+ contents->testMsg = "pubkey_cred->rawId is NULL";
goto callback_failed;
}
if (!pubkey_cred->response) {
- std::cout << "GA: pubkey_cred->response is NULL" << std::endl;
+ contents->testMsg = "pubkey_cred->response is NULL";
goto callback_failed;
}
+ // Check credential is valid
credentialRawId = ToBuffer(*pubkey_cred->rawId);
- if (credentialRawId != contents->credentialRawId) {
- std::cout << "Error: invalid credentialRawId in GA: "
- << LowercaseHexStringOf(credentialRawId) << std::endl;
- goto callback_failed;
+ if (strlen(contents->username) != 0) // with username
+ {
+ if (pubkey_cred->response->user_handle)
+ {
+ auto userHandle = ToBuffer(*pubkey_cred->response->user_handle);
+ if (userHandle != contents->userId)
+ {
+ std::cout << "Error: invalid userHandle in GA: "
+ << LowercaseHexStringOf(userHandle)
+ << std::endl;
+ contents->testMsg = "Invalid username";
+ goto callback_failed;
+ }
+ }
+ auto it = contents->createdCredDescs.find(contents->userId);
+ if (it == contents->createdCredDescs.end()
+ || it->second.id != credentialRawId)
+ {
+ std::cout << "Error: invalid credentialRawId in GA: "
+ << LowercaseHexStringOf(credentialRawId)
+ << " and found(" << LowercaseHexStringOf(it->second.id)
+ << ")" << std::endl;
+ contents->testMsg = "Invalid credentialRawId";
+ goto callback_failed;
+ }
+ else
+ {
+ std::cout << "Found credential of username(" << LowercaseHexStringOf(it->first)
+ << "): "<< LowercaseHexStringOf(credentialRawId) << std::endl;
+ }
}
-
- if (pubkey_cred->response->user_handle) {
- auto userHandle = ToBuffer(*pubkey_cred->response->user_handle);
- if (userHandle != contents->userId) {
- std::cout << "Error: invalid userHandle in GA: " << LowercaseHexStringOf(userHandle)
- << std::endl;
+ else // without username
+ {
+ bool isFound = false;
+ for (auto const& cred : contents->createdCredDescs)
+ {
+ if (cred.second.id == credentialRawId) // Found
+ {
+ contents->userId == cred.first;
+ isFound = true;
+ std::cout << "Found credential of userId(" << LowercaseHexStringOf(cred.first)
+ << "): "<< LowercaseHexStringOf(credentialRawId) << std::endl;
+ break;
+ }
+ }
+ if (!isFound)
+ {
+ std::cout << "Error: unrecognized credentialRawId in GA: "
+ << LowercaseHexStringOf(credentialRawId) << std::endl;
+ contents->testMsg = "Unrecognized credentialRawId";
goto callback_failed;
}
}
-
contents->UpdateLinkedData(pubkey_cred->linked_device);
std::cout << "GetAssertion: awaiting potential CTAP UPDATE messages..." << std::endl;
return;
callback_failed:
+ std::cout << "MC: " << contents->testMsg.c_str() << std::endl;
contents->status = TestState::RESP_GA_CB_FAILED;
contents->finished = true;
contents->cv.notify_one();
void MCScenario::Test()
{
std::cout << "[MAKE CREDENTIAL]: START" << std::endl;
+
wauthn_pubkey_cred_creation_options_s m_options;
std::memset(&m_options, 0, sizeof(m_options));
else {
if (m_contents.algorithms[0])
params.push_back(
- {WAUTHN_PUBKEY_CRED_TYPE_PUBLIC_KEY, WAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256});
+ {WAUTHN_PUBKEY_CRED_TYPE_PUBLIC_KEY,
+ WAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256});
if (m_contents.algorithms[1])
params.push_back({WAUTHN_PUBKEY_CRED_TYPE_PUBLIC_KEY,
WAUTHN_COSE_ALGORITHM_RSASSA_PKCS1_V1_5_WITH_SHA256});
}
// Entity ID
+ wauthn_const_buffer_s userId = {reinterpret_cast<const uint8_t *>(m_contents.username),
+ strlen(m_contents.username)};
+ m_contents.userId = ToBuffer(userId);
wauthn_user_entity_s userEntity = {const_cast<char *>(m_contents.username),
- &TestData::USER_ID,
+ &userId,
const_cast<char *>(m_contents.username)};
// Authenticator selection data
m_options.attestation = m_contents.attPref;
m_contents.status = TestState::REG_IN_PROCESS;
- m_contents.credentialRawId = {};
- m_contents.userId = ToBuffer(TestData::USER_ID);
- m_contents.transports = WAUTHN_TRANSPORT_NONE;
m_contents.linkedData = std::nullopt;
m_contents.seenLastMCUpdateCb = false;
m_contents.seenLastGAUpdateCb = false;
std::cout << "TestMakeCredential failed with status: "
<< TestStateToString(m_contents.status) << std::endl;
m_contents.status = TestState::REG_FAILED;
+ m_contents.testMsg = "Failed with status: "
+ + std::string(TestStateToString(m_contents.status));
return;
}
} else {
- std::cout << "wauthn_make_credential command failed, error: " << res
+ std::cout << "wauthn_make_credential command failed, error: "
+ << get_error_message(res)
<< "\nTestMakeCredential failed with status: "
<< TestStateToString(m_contents.status) << std::endl;
+ m_contents.testMsg = "Failed with status: "
+ + std::string(TestStateToString(m_contents.status));
m_contents.status = TestState::REG_FAILED;
return;
}
std::cout << "TestMakeCredential passed!\n";
m_contents.seenLastGAUpdateCb = false;
}
-
std::cout << "[MAKE CREDENTIAL]: END" << std::endl;
+ std::cout << "Current size of createdCreds: " << m_contents.createdCredDescs.size()
+ << std::endl;
}
void GAScenario::SetCallbacks()
void GAScenario::Test()
{
- std::cout << "[GET ASSERTION]: START" << std::endl;
+ std::cout << "[GET ASSERTION]: START";
m_contents.status = TestState::AUTH_IN_PROCESS;
+ // set userId and allowCredentials
+ size_t userIdLength = strlen(m_contents.username);
+ wauthn_const_buffer_s userId = {reinterpret_cast<const uint8_t *>(m_contents.username),
+ userIdLength};
+ m_contents.userId = ToBuffer(userId);
+ std::vector<wauthn_pubkey_cred_descriptor_s> vCredDescriptors;
+ std::map<Buffer, wauthn_const_buffer_s> mBuffer;
+ if (userIdLength == 0)
+ {
+ std::cout << "Set allowCredentials with size: " << m_contents.createdCredDescs.size()
+ << std::endl;
+ for (auto const& cred : m_contents.createdCredDescs)
+ {
+ mBuffer[cred.first] = ToWauthnConstBuff(cred.second.id);
+ vCredDescriptors.push_back({cred.second.type, &mBuffer[cred.first],
+ cred.second.transports});
+ std::cout << "userId: " << LowercaseHexStringOf(cred.first)
+ << ", credId: " << LowercaseHexStringOf(cred.second.id) << std::endl;
+ }
+ }
+ else if(m_contents.createdCredDescs.count(m_contents.userId) == 0)
+ {
+ std::cout << "That username has no registered credentials: "
+ << m_contents.username << std::endl;
+ m_contents.testMsg = "That username is not registered";
+ m_contents.status = TestState::AUTH_FAILED;
+ return;
+ }
+ else
+ {
+ auto it = m_contents.createdCredDescs.find(m_contents.userId);
+ wauthn_const_buffer_s credId = ToWauthnConstBuff(it->second.id);
+ vCredDescriptors.push_back({it->second.type, &credId, it->second.transports});
+ std::cout << "Set an allowCredential id: " << LowercaseHexStringOf(it->second.id)
+ << std::endl;
+ }
+
+ wauthn_pubkey_cred_descriptors_s allowCredentials = {vCredDescriptors.size(),
+ vCredDescriptors.data()};
+
+ std::cout << "size: " << allowCredentials.size << std::endl;
+ for (size_t i = 0; i < allowCredentials.size; ++i)
+ {
+ std::cout << "id: " << LowercaseHexStringOf(ToBuffer(*allowCredentials.descriptors[i].id))
+ << std::endl;
+ std::cout << "type: " << allowCredentials.descriptors[i].type << std::endl;
+ std::cout << "transport: " << allowCredentials.descriptors[i].transports << std::endl;
+ }
wauthn_pubkey_cred_request_options_s m_options;
std::memset(&m_options, 0, sizeof(m_options));
wauthn_const_buffer_s tunnelServerDomain;
wauthn_const_buffer_s identityKey;
- wauthn_const_buffer_s credentialId = ToWauthnConstBuff(m_contents.credentialRawId);
-
- wauthn_pubkey_cred_descriptor_s pubkeyCredDescriptor;
- pubkeyCredDescriptor.type = WAUTHN_PUBKEY_CRED_TYPE_PUBLIC_KEY;
- pubkeyCredDescriptor.id = &credentialId;
- pubkeyCredDescriptor.transports = m_contents.transports;
-
- wauthn_pubkey_cred_descriptors_s pubkeyCredDescriptors;
- pubkeyCredDescriptors.size = 1;
- pubkeyCredDescriptors.descriptors = &pubkeyCredDescriptor;
-
wauthn_hybrid_linked_data_s linkedDevice;
if (m_contents.linkedData) {
std::cout << "linked data exists\n";
m_options.timeout = TestData::TIMEOUT;
m_options.rpId = const_cast<char *>(TestData::RP_ID);
+ m_options.allow_credentials = &allowCredentials;
m_options.user_verification = m_contents.userVerification;
m_options.attestation = m_contents.attPref;
- m_options.allow_credentials = &pubkeyCredDescriptors;
m_options.linked_device = m_contents.linkedData ? &linkedDevice : nullptr;
m_options.attestation_formats = nullptr;
m_options.extensions = nullptr;
if (m_contents.status != TestState::LD_UPDATED) {
std::cout << "TestGetAssertion failed with status: "
<< TestStateToString(m_contents.status) << std::endl;
+ m_contents.testMsg = "Failed with status: "
+ + std::string(TestStateToString(m_contents.status));
m_contents.status = TestState::AUTH_FAILED;
return;
}
std::cout
<< "wauthn_get_assertion command failed\nTestGetAssertion failed with status: "
<< TestStateToString(m_contents.status) << std::endl;
+ m_contents.testMsg = "Failed with status: "
+ + std::string(TestStateToString(m_contents.status));
m_contents.status = TestState::AUTH_FAILED;
return;
}
m_contents.seenLastGAUpdateCb = false;
}
std::cout << "[GET ASSERTION]: END" << std::endl;
+ std::cout << "Current size of createdCreds: " << m_contents.createdCredDescs.size()
+ << std::endl;
}
} // namespace ManTestScenario