#include <stdexcept>
#include <thread>
#include <unistd.h>
-#include <utils.h>
#include <connection.h>
#include <message-buffer.h>
#include <protocols.h>
-#include <webauthn-log.h>
+#include <utils.h>
#include <webauthn-types.h>
namespace WA {
template <typename A, typename B>
void cb_worker(std::shared_ptr<GenericClientRequest> request, A &callbacks, B cred)
{
+ static constexpr const char *REQUEST_KIND_PREFIX =
+ std::is_same_v<B, wauthn_pubkey_credential_attestation_s*> ? "MC: " : "GA: ";
+
int ret = try_catch([&]() -> int {
if (callbacks->qrcode_callback == nullptr)
- LogDebug("There is no qrcode_callback");
+ LogDebug(REQUEST_KIND_PREFIX << "There is no qrcode_callback");
else{ //callbacks->qrcode_callback != nullptr
std::string qr_code;
if (request->Recv(qr_code).Failed())
- LogError("Error on receive qrcode");
- LogDebug("Received qr_contents: " << qr_code);
+ LogError(REQUEST_KIND_PREFIX << "Error on receive qrcode");
+ LogDebug(REQUEST_KIND_PREFIX << "Received qr_contents: " << qr_code);
callbacks->qrcode_callback(qr_code.c_str(), callbacks->user_data);
}
request->Recv(&cred);
callbacks->user_data);
if(request->Failed())
{
- LogError("Error on receive response: " << request->GetStatus());
+ LogError(REQUEST_KIND_PREFIX << "Error on receive response: " << request->GetStatus());
return WAUTHN_ERROR_INVALID_STATE;
}
while (request->Recv(&linked_data).Incompleted())
{
+ LogLinkedDevice(REQUEST_KIND_PREFIX, "[linked_data_callback]", linked_data);
callbacks->linked_data_callback(linked_data, wauthn_error_e(request->GetStatus()),
callbacks->user_data);
- LogDebug("More update linked_data can be received. Waiting to recv()");
+ LogDebug(REQUEST_KIND_PREFIX << "More update linked_data can be received. Waiting to recv()");
}
- LogDebug("There is no more updated linked_data");
+ LogLinkedDevice(REQUEST_KIND_PREFIX, "[linked_data_callback]", linked_data);
+ LogDebug(REQUEST_KIND_PREFIX << "There is no more updated linked_data");
callbacks->linked_data_callback(linked_data, wauthn_error_e(request->GetStatus()),
callbacks->user_data);
return WAUTHN_ERROR_NONE;
});
if (ret != WAUTHN_ERROR_NONE)
- LogError("Error on handling callbacks");
+ LogError(REQUEST_KIND_PREFIX << "Error on handling callbacks");
}
template <typename T>
typename T::Callbacks *callbacks)
{
return try_catch([&]() -> int {
- checkParameters(client_data, options, callbacks);
if (options->linked_device != nullptr) // The qrcode_callback should not be called.
{
LogDebug("Adjust qrcode_callback to null");
namespace WA {
-void checkParameters(const wauthn_client_data_s *client_data)
+void CheckParameters(const wauthn_client_data_s *client_data)
{
if (client_data == nullptr)
ThrowMsg(ClientException::InvalidParameter, "Invalid client_data");
}
-void checkParameters(const wauthn_pubkey_cred_creation_options_s *options)
+void CheckParameters(const wauthn_pubkey_cred_creation_options_s *options)
{
if (options == nullptr)
ThrowMsg(ClientException::InvalidParameter, "Invalid options");
}
-void checkParameters(const wauthn_pubkey_cred_request_options_s *options)
+void CheckParameters(const wauthn_pubkey_cred_request_options_s *options)
{
if (options == nullptr)
ThrowMsg(ClientException::InvalidParameter, "Invalid options");
}
-void checkParameters(wauthn_mc_callbacks_s *callbacks)
+void CheckParameters(wauthn_mc_callbacks_s *callbacks)
{
if (callbacks == nullptr || callbacks->response_callback == nullptr
|| callbacks->linked_data_callback == nullptr)
ThrowMsg(ClientException::InvalidParameter, "Invalid callback");
}
-void checkParameters(wauthn_ga_callbacks_s *callbacks)
+void CheckParameters(wauthn_ga_callbacks_s *callbacks)
{
if (callbacks == nullptr || callbacks->response_callback == nullptr
|| callbacks->linked_data_callback == nullptr)
ThrowMsg(ClientException::InvalidParameter, "Invalid callback");
}
-void checkParameters(wauthn_hybrid_linked_data_s *linked_device,
+void CheckParameters(wauthn_hybrid_linked_data_s *linked_device,
wauthn_cb_display_qrcode qrcode_callback)
{
if (linked_device == nullptr && qrcode_callback == nullptr)
ThrowMsg(ClientException::InvalidParameter, "The qrcode_callback is missed");
}
-void checkParameters(const wauthn_client_data_s *client_data,
+void CheckParameters(const wauthn_client_data_s *client_data,
const wauthn_pubkey_cred_creation_options_s *options,
wauthn_mc_callbacks_s *callbacks)
{
- checkParameters(client_data);
- checkParameters(options);
- checkParameters(callbacks);
- checkParameters(options->linked_device, callbacks->qrcode_callback);
+ CheckParameters(client_data);
+ CheckParameters(options);
+ CheckParameters(callbacks);
+ CheckParameters(options->linked_device, callbacks->qrcode_callback);
}
-void checkParameters(const wauthn_client_data_s *client_data,
+void CheckParameters(const wauthn_client_data_s *client_data,
const wauthn_pubkey_cred_request_options_s *options,
wauthn_ga_callbacks_s *callbacks)
{
- checkParameters(client_data);
- checkParameters(options);
- checkParameters(callbacks);
- checkParameters(options->linked_device, callbacks->qrcode_callback);
+ CheckParameters(client_data);
+ CheckParameters(options);
+ CheckParameters(callbacks);
+ CheckParameters(options->linked_device, callbacks->qrcode_callback);
}
} /* namespace WebAuthn */
return ptr != NULL ? ptr + 1 : filename;
}
+#ifdef BUILD_TYPE_DEBUG
+std::string ToStr(const char *str)
+{
+ if (!str)
+ return "null";
+ std::string res = "\"";
+ res += str;
+ res += '"';
+ return res;
+}
+
+std::string ToStr(wauthn_const_buffer_s *wcb)
+{
+ if (!wcb)
+ return "null";
+
+ std::string str = "\"";
+ str.append(wcb->data, wcb->data + wcb->size);
+ str += '"';
+ return str;
+}
+
+std::string ToHexStr(wauthn_const_buffer_s *wcb)
+{
+ return wcb ? LowercaseHexStringOf(BufferView{wcb->data, wcb->size}) : "null";
+}
+
+std::string ToStr(wauthn_cose_algorithm_e alg)
+{
+ switch (alg) {
+ case WAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256: return "ES256";
+ case WAUTHN_COSE_ALGORITHM_ECDSA_P384_WITH_SHA384: return "ES384";
+ case WAUTHN_COSE_ALGORITHM_ECDSA_P521_WITH_SHA512: return "ES512";
+ case WAUTHN_COSE_ALGORITHM_EDDSA: return "EdDSA";
+ case WAUTHN_COSE_ALGORITHM_RSA_PSS_WITH_SHA256: return "PS256";
+ case WAUTHN_COSE_ALGORITHM_RSA_PSS_WITH_SHA384: return "PS384";
+ case WAUTHN_COSE_ALGORITHM_RSA_PSS_WITH_SHA512: return "PS512";
+ case WAUTHN_COSE_ALGORITHM_RSASSA_PKCS1_V1_5_WITH_SHA256: return "RS256";
+ case WAUTHN_COSE_ALGORITHM_RSASSA_PKCS1_V1_5_WITH_SHA384: return "RS384";
+ case WAUTHN_COSE_ALGORITHM_RSASSA_PKCS1_V1_5_WITH_SHA512: return "RS512";
+ }
+ return std::to_string(alg);
+}
+
+std::string ToStr(wauthn_pubkey_cred_type_e pct)
+{
+ switch (pct) {
+ case PCT_PUBLIC_KEY: return "public-key";
+ }
+ return std::to_string(pct);
+}
+
+std::string ToStr(wauthn_authenticator_attachment_e authenticatorAttachment)
+{
+ switch (authenticatorAttachment) {
+ case AA_NONE: return "none";
+ case AA_PLATFORM: return "platform";
+ case AA_CROSS_PLATFORM: return "cross-platform";
+ }
+ return std::to_string(authenticatorAttachment);
+}
+
+std::string ToStr(wauthn_resident_key_requirement_e residentKeyRequirement)
+{
+ switch (residentKeyRequirement) {
+ case RKR_NONE: return "none";
+ case RKR_DISCOURAGED: return "discouraged";
+ case RKR_PREFERRED: return "preferred";
+ case RKR_REQUIRED: return "required";
+ }
+ return std::to_string(residentKeyRequirement);
+}
+
+std::string ToStr(wauthn_user_verification_requirement_e userVerificationRequirement)
+{
+ switch (userVerificationRequirement) {
+ case UVR_NONE: return "none";
+ case UVR_REQUIRED: return "required";
+ case UVR_PREFERRED: return "preferred";
+ case UVR_DISCOURAGED: return "discouraged";
+ }
+ return std::to_string(userVerificationRequirement);
+}
+
+std::string ToStr(wauthn_pubkey_cred_hint_e credHint)
+{
+ switch (credHint) {
+ case PCH_NONE: return "none";
+ case PCH_SECURITY_KEY: return "security-key";
+ case PCH_CLIENT_DEVICE: return "client-device";
+ case PCH_HYBRID: return "hybrid";
+ }
+ return std::to_string(credHint);
+}
+
+std::string ToStr(wauthn_attestation_pref_e attestationPref)
+{
+ switch (attestationPref) {
+ case AP_NONE: return "none";
+ case AP_INDIRECT: return "indirect";
+ case AP_DIRECT: return "direct";
+ case AP_ENTERPRISE: return "enterprise";
+ }
+ return std::to_string(attestationPref);
+}
+
+std::string TransportsToStr(unsigned int transports)
+{
+ if (transports == WAUTHN_TRANSPORT_NONE)
+ return "none";
+
+ struct TransportInfo {
+ wauthn_authenticator_transport_e mask;
+ const char *name;
+ };
+
+ static constexpr auto TRANSPORTS = std::array{
+ TransportInfo{WAUTHN_TRANSPORT_USB, "usb" },
+ TransportInfo{WAUTHN_TRANSPORT_NFC, "nfc" },
+ TransportInfo{WAUTHN_TRANSPORT_BLE, "ble" },
+ TransportInfo{WAUTHN_TRANSPORT_SMARTCARD, "smart-card"},
+ TransportInfo{WAUTHN_TRANSPORT_HYBRID, "hybrid" },
+ TransportInfo{WAUTHN_TRANSPORT_INTERNAL, "internal" },
+ };
+
+ std::string transportsStr;
+ auto transportsLeft = transports;
+ constexpr auto SEPARATOR = std::string_view{" | "};
+ for (const auto &ti : TRANSPORTS) {
+ if (transports & ti.mask) {
+ transportsStr += ti.name;
+ transportsStr += SEPARATOR;
+ transportsLeft &= ~ti.mask;
+ }
+ }
+ if (transportsLeft != 0)
+ transportsStr += std::to_string(transportsLeft);
+ else
+ transportsStr.resize(transportsStr.size() - SEPARATOR.size());
+
+ return transportsStr;
+}
+
+void LogExtensions(const char *prefix1,
+ const char *prefix2,
+ const wauthn_authentication_exts_s *extensions)
+{
+ if (!extensions)
+ LogDebug(prefix1 << prefix2 << "->extensions: null");
+ else {
+ LogDebug(prefix1 << prefix2 << "->extensions->size: " << extensions->size);
+ for (size_t i = 0; i < extensions->size; ++i) {
+ LogDebug(prefix1 << prefix2 << "->extensions[" << i
+ << "]: " << ToStr(extensions->extensions[i].extension_id) << " -> "
+ << ToHexStr(extensions->extensions[i].extension_value));
+ }
+ }
+}
+#endif
+
+void LogLinkedDevice(const char *prefix1,
+ const char *prefix2,
+ const wauthn_hybrid_linked_data_s *linkedDevice)
+{
+#ifdef BUILD_TYPE_DEBUG
+ if (!linkedDevice)
+ LogDebug(prefix1 << prefix2 << "linked_device: null");
+ else {
+ LogDebug(prefix1 << prefix2
+ << "linked_device->contact_id: " << ToHexStr(linkedDevice->contact_id));
+ LogDebug(prefix1 << prefix2
+ << "linked_device->link_id: " << ToHexStr(linkedDevice->link_id));
+ LogDebug(prefix1 << prefix2
+ << "linked_device->link_secret: " << ToHexStr(linkedDevice->link_secret));
+ LogDebug(prefix1 << prefix2 << "linked_device->authenticator_pubkey: "
+ << ToHexStr(linkedDevice->authenticator_pubkey));
+ LogDebug(prefix1 << prefix2 << "linked_device->authenticator_name: "
+ << ToHexStr(linkedDevice->authenticator_name)
+ << " == " << ToStr(linkedDevice->authenticator_name));
+ LogDebug(prefix1 << prefix2
+ << "linked_device->signature: " << ToHexStr(linkedDevice->signature));
+ LogDebug(prefix1 << prefix2 << "linked_device->tunnel_server_domain: "
+ << ToHexStr(linkedDevice->tunnel_server_domain)
+ << " == " << ToStr(linkedDevice->tunnel_server_domain));
+ LogDebug(prefix1 << prefix2 << "linked_device->identity_key: "
+ << ToHexStr(linkedDevice->identity_key));
+ }
+#else
+ (void)prefix1;
+ (void)prefix2;
+ (void) linkedDevice;
+#endif
+}
+
+template <RequestKind REQUEST_KIND>
+void LogRequest(
+ const wauthn_client_data_s &clientData,
+ const std::conditional_t<REQUEST_KIND == RequestKind::MC,
+ wauthn_pubkey_cred_creation_options_s,
+ wauthn_pubkey_cred_request_options_s> &options)
+
+{
+#ifdef BUILD_TYPE_DEBUG
+ static constexpr const char *REQUEST_KIND_PREFIX =
+ REQUEST_KIND == RequestKind::MC ? "MC: " : "GA: ";
+ if (!clientData.client_data_json)
+ LogDebug(REQUEST_KIND_PREFIX << "client_data->client_data_json: null");
+ else {
+ LogDebug(REQUEST_KIND_PREFIX
+ << "client_data->client_data_json: " << ToHexStr(clientData.client_data_json)
+ << " == " << ToStr(clientData.client_data_json));
+ }
+
+ LogDebug(REQUEST_KIND_PREFIX << "client_data->hash_alg: " << [&]() -> std::string {
+ switch (clientData.hash_alg) {
+ case WAUTHN_HASH_ALGORITHM_SHA_256: return "SHA-256";
+ }
+ return std::to_string(clientData.hash_alg);
+ }());
+
+ if constexpr (REQUEST_KIND == RequestKind::MC) {
+ if (!options.rp)
+ LogDebug(REQUEST_KIND_PREFIX << "options->rp: null");
+ else {
+ LogDebug(REQUEST_KIND_PREFIX << "options->rp->name: " << ToStr(options.rp->name));
+ LogDebug(REQUEST_KIND_PREFIX << "options->rp->id: " << ToStr(options.rp->id));
+ }
+
+ if (!options.user)
+ LogDebug(REQUEST_KIND_PREFIX << "options->user: null");
+ else {
+ LogDebug(REQUEST_KIND_PREFIX << "options->user->name: " << ToStr(options.user->name));
+ LogDebug(REQUEST_KIND_PREFIX << "options->user->id: " << ToHexStr(options.user->id));
+ LogDebug(REQUEST_KIND_PREFIX << "options->user->display_name: "
+ << ToStr(options.user->display_name));
+ }
+
+ if (!options.pubkey_cred_params)
+ LogDebug(REQUEST_KIND_PREFIX << "options->pubkey_cred_params: null");
+ else {
+ LogDebug(REQUEST_KIND_PREFIX << "options->pubkey_cred_params->size: "
+ << options.pubkey_cred_params->size);
+ for (size_t i = 0; i < options.pubkey_cred_params->size; ++i) {
+ LogDebug(REQUEST_KIND_PREFIX
+ << "options->pubkey_cred_params->params[" << i
+ << "]: {type: " << ToStr(options.pubkey_cred_params->params[i].type)
+ << ", alg: " << ToStr(options.pubkey_cred_params->params[i].alg) << "}");
+ }
+ }
+ }
+
+ LogDebug(REQUEST_KIND_PREFIX << "options->timeout: " << options.timeout << " ms");
+
+ static constexpr auto logCredDescriptors =
+ [](const char *fieldName, wauthn_pubkey_cred_descriptors_s *credDescriptors) {
+ if (!credDescriptors)
+ LogDebug(REQUEST_KIND_PREFIX << "options->" << fieldName << ": null");
+ else {
+ LogDebug(REQUEST_KIND_PREFIX << "options->" << fieldName
+ << "->size: " << credDescriptors->size);
+ for (size_t i = 0; i < credDescriptors->size; ++i) {
+ LogDebug(REQUEST_KIND_PREFIX
+ << "options->" << fieldName << "->descriptors[" << i
+ << "].type: " << ToStr(credDescriptors->descriptors[i].type));
+ LogDebug(REQUEST_KIND_PREFIX
+ << "options->" << fieldName << "->descriptors[" << i
+ << "].id: " << ToHexStr(credDescriptors->descriptors[i].id));
+ LogDebug(REQUEST_KIND_PREFIX
+ << "options->" << fieldName << "->descriptors[" << i
+ << "].transports: "
+ << TransportsToStr(credDescriptors->descriptors[i].transports));
+ }
+ }
+ };
+
+ if constexpr (REQUEST_KIND == RequestKind::MC) {
+ logCredDescriptors("exclude_credentials", options.exclude_credentials);
+ if (!options.authenticator_selection)
+ LogDebug(REQUEST_KIND_PREFIX << "options->authenticator_selection: null");
+ else {
+ LogDebug(REQUEST_KIND_PREFIX << "options->authenticator_selection->attachment: "
+ << ToStr(options.authenticator_selection->attachment));
+ LogDebug(REQUEST_KIND_PREFIX << "options->authenticator_selection->resident_key: "
+ << ToStr(options.authenticator_selection->resident_key));
+ LogDebug(REQUEST_KIND_PREFIX
+ << "options->authenticator_selection->require_resident_key: "
+ << (options.authenticator_selection->require_resident_key ? "true" : "false"));
+ LogDebug(REQUEST_KIND_PREFIX
+ << "options->authenticator_selection->user_verification: "
+ << ToStr(options.authenticator_selection->user_verification));
+ }
+ } else {
+ LogDebug(REQUEST_KIND_PREFIX << "options->rpId: " << ToStr(options.rpId));
+ logCredDescriptors("allow_credentials", options.allow_credentials);
+ LogDebug(REQUEST_KIND_PREFIX << "options->user_verification: "
+ << ToStr(options.user_verification));
+ }
+
+ if (!options.hints)
+ LogDebug(REQUEST_KIND_PREFIX << "options->hints: null");
+ else {
+ LogDebug(REQUEST_KIND_PREFIX << "options->hints->size: " << options.hints->size);
+ for (size_t i = 0; i < options.hints->size; ++i)
+ LogDebug(REQUEST_KIND_PREFIX << "options->hints->hints[" << i
+ << "]: " << ToStr(options.hints->hints[i]));
+ }
+
+ LogDebug(REQUEST_KIND_PREFIX << "options->attestation: " << ToStr(options.attestation));
+
+ if (!options.attestation_formats)
+ LogDebug(REQUEST_KIND_PREFIX << "options->attestation_formats: null");
+ else {
+ LogDebug(REQUEST_KIND_PREFIX << "options->attestation_formats->size: "
+ << options.attestation_formats->size);
+ for (size_t i = 0; i < options.attestation_formats->size; ++i)
+ LogDebug(REQUEST_KIND_PREFIX
+ << "options->attestation_formats->attestation_formats[" << i
+ << "]: " << ToHexStr(options.attestation_formats->attestation_formats + i)
+ << " == " << ToStr(options.attestation_formats->attestation_formats + i));
+ }
+
+ LogExtensions(REQUEST_KIND_PREFIX, "options", options.extensions);
+ LogLinkedDevice(REQUEST_KIND_PREFIX, "options->", options.linked_device);
+#else
+ (void)clientData;
+ (void)options;
+#endif
+}
+
+template void
+LogRequest<RequestKind::MC>(const wauthn_client_data_s &clientData,
+ const wauthn_pubkey_cred_creation_options_s &options);
+
+template void
+LogRequest<RequestKind::GA>(const wauthn_client_data_s &clientData,
+ const wauthn_pubkey_cred_request_options_s &options);
+
} // namespace WebAuthn
\ No newline at end of file