const CborEncoding::Key &key,
const wauthn_pubkey_cred_descriptors_s &credentials)
{
- if (!credentials.descriptors)
- THROW_INVALID_PARAM("Credential descriptors are NULL");
+ if (!credentials.descriptors || credentials.size == 0)
+ THROW_INVALID_PARAM("Empty credential descriptors");
auto credListArray = map.OpenArrayAt(key, credentials.size);
for (size_t i = 0; i < credentials.size; i++) {
std::optional<LinkedData> linkedData;
bool seenLastMCUpdateCallback;
bool seenLastGAUpdateCallback;
+ bool allowNonDiscoverable;
std::thread GAThread;
exclude_credentials.descriptors = excluded_credentials.data();
exclude_credentials.size = excluded_credentials.size();
+ wauthn_authenticator_sel_cri_s authenticator_selection;
+ authenticator_selection.attachment = AA_CROSS_PLATFORM;
+ authenticator_selection.require_resident_key = true;
+ authenticator_selection.resident_key = RKR_REQUIRED;
+ authenticator_selection.user_verification = UVR_REQUIRED;
+
wauthn_pubkey_cred_creation_options_s mcOptions;
std::memset(&mcOptions, 0, sizeof(mcOptions));
mcOptions.rp = &rp;
mcOptions.pubkey_cred_params = &pubkeyCredParams;
mcOptions.timeout = 60000; // 60s
mcOptions.exclude_credentials = exclude_credentials.size > 0 ? &exclude_credentials : nullptr;
- mcOptions.authenticator_selection = nullptr;
+ mcOptions.authenticator_selection =
+ testContents.allowNonDiscoverable ? nullptr : &authenticator_selection;
mcOptions.hints = nullptr;
mcOptions.attestation = AP_NONE;
mcOptions.attestation_formats = nullptr;
std::memset(&gaOptions, 0, sizeof(gaOptions)); // For future compatibility.
gaOptions.timeout = 60000; // 60s
gaOptions.rpId = RP_ID;
- gaOptions.allow_credentials = &pubkeyCredDescriptors;
+ gaOptions.allow_credentials =
+ testContents.allowNonDiscoverable ? &pubkeyCredDescriptors : nullptr;
gaOptions.user_verification = UVR_REQUIRED;
gaOptions.hints = nullptr;
gaOptions.attestation = AP_NONE;
" containing CREDENTIAL_ID. To exclude several\n"
" credentials, specify this option multiple\n"
" times. CREDENTIAL_ID must be a hex string. E.g.\n"
- " 91ef2e74f47bd06a6c5c4053ab8de1f6845f460a3ded.\n";
+ " 91ef2e74f47bd06a6c5c4053ab8de1f6845f460a3ded.\n"
+ << " --allow-non-discoverable Do not force discoverable/resident key creation\n"
+ " in MakeCredential command\n";
}
std::optional<Buffer> HexStringToBuffer(std::string_view hexString)
std::nullopt,
false,
false,
+ false,
{}};
for (int i = 1; i < argc; ++i) {
return 3;
}
testContents.excludedCredentialsIds.emplace_back(std::move(*credentialId));
+ } else if (arg == "--allow-non-discoverable") {
+ testContents.allowNonDiscoverable = true;
} else {
std::cout << "Unrecognized option: " << arg << '\n';
PrintHelp(argv);
#include "exception.h"
#include "message.h"
#include "message_examples.h"
+#include "to_wauthn_const_buff.h"
#include "wauthn_const_buff_equals.h"
#include <ctap_message_processor.h>
// clang-format on
};
+wauthn_pubkey_cred_descriptor_s &GetPubkeyDescriptor()
+{
+ static auto pubkeyCredDescriptor = [] {
+ static const auto CREDENTIAL_ID_BUFFER = BUFFER_VIEW("\x00\x01\x02\x03\x04");
+ static auto credentialId = ToWauthnConstBuff(CREDENTIAL_ID_BUFFER);
+
+ wauthn_pubkey_cred_descriptor_s descriptor;
+ descriptor.type = PCT_PUBLIC_KEY;
+ descriptor.id = &credentialId;
+ descriptor.transports = WAUTHN_TRANSPORT_NONE;
+ return descriptor;
+ }();
+ return pubkeyCredDescriptor;
+}
+
+template <typename T>
+void TestCredentials(T &msg, wauthn_pubkey_cred_descriptors_s *&credentials)
+{
+ auto &pubkeyCredDescriptor = GetPubkeyDescriptor();
+
+ wauthn_pubkey_cred_descriptors_s pubkeyCredDescriptors;
+ credentials = &pubkeyCredDescriptors;
+
+ auto test = [&](wauthn_pubkey_cred_descriptor_s *descriptors, size_t size) {
+ Buffer buffer;
+ pubkeyCredDescriptors.descriptors = descriptors;
+ pubkeyCredDescriptors.size = size;
+ msg.Serialize(buffer);
+ };
+
+ EXPECT_THROW(test(nullptr, 0), Exception::InvalidParam);
+ EXPECT_THROW(test(nullptr, 1), Exception::InvalidParam);
+ EXPECT_THROW(test(&pubkeyCredDescriptor, 0), Exception::InvalidParam);
+ EXPECT_NO_THROW(test(&pubkeyCredDescriptor, 1));
+
+ credentials = nullptr;
+}
+
} // namespace
TEST(Messages, ParsePostHandshakeMessage1)
"\x65\x6a\x70\x75\x62\x6c\x69\x63\x2d\x6b\x65\x79\xa2\x63\x61\x6c\x67\x39\x01\x01\x64"
"\x74\x79\x70\x65\x6a\x70\x75\x62\x6c\x69\x63\x2d\x6b\x65\x79\xa2\x63\x61\x6c\x67\x39"
"\x01\x02\x64\x74\x79\x70\x65\x6a\x70\x75\x62\x6c\x69\x63\x2d\x6b\x65\x79"));
+
+ TestCredentials(msg, options.exclude_credentials);
}
TEST(Messages, SerializeMakeCredential2)
ASSERT_NO_THROW(msg.Serialize(buffer));
EXPECT_EQ(ToBufferView(buffer),
(BufferView{SAMPLE_MAKE_CREDENTIAL_REQUEST, sizeof(SAMPLE_MAKE_CREDENTIAL_REQUEST)}));
+
+ TestCredentials(msg, options.exclude_credentials);
}
TEST(Messages, SerializeGetAssertion)
ASSERT_NO_THROW(msg.Serialize(buffer));
EXPECT_EQ(ToBufferView(buffer),
(BufferView{SAMPLE_GET_ASSERTION_REQUEST, sizeof(SAMPLE_GET_ASSERTION_REQUEST)}));
+
+ TestCredentials(msg, options.allow_credentials);
}
TEST(Messages, ShutdownMessage)