Add discoverable credential option to manual test 80/314680/6
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Wed, 17 Jul 2024 08:17:18 +0000 (10:17 +0200)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Thu, 18 Jul 2024 09:29:42 +0000 (11:29 +0200)
Also disallow empty credentials (note that CTAP2.2 forbids empty list
only for allowList).

Update unit-tests.

Change-Id: I20fa15ae0f68b2df5ffdfb2cc68a3a8d1daabd3c

srcs/message.cpp
tests/man_tests.cpp
tests/message_tests.cpp

index 971aaaa7e536a25f626d9e765aafa90cdaf05569..776cc8e614a99f8c3b17b0e68314d06b6f2172cf 100644 (file)
@@ -213,8 +213,8 @@ void SerializePubkeyCredDescriptors(CborEncoding::SortedMap &map,
                                     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++) {
index 6a52e549dec11c148c3615ba2e6fd1d0bc71dcc8..d5b1e428b3b56ccde3899973145488b42f262619 100644 (file)
@@ -61,6 +61,7 @@ struct TestContents {
     std::optional<LinkedData> linkedData;
     bool seenLastMCUpdateCallback;
     bool seenLastGAUpdateCallback;
+    bool allowNonDiscoverable;
 
     std::thread GAThread;
 
@@ -240,6 +241,12 @@ void TestMC(struct TestContents &testContents)
     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;
@@ -247,7 +254,8 @@ void TestMC(struct TestContents &testContents)
     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;
@@ -321,7 +329,8 @@ void TestGA(struct TestContents &testContents)
     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;
@@ -528,7 +537,9 @@ void PrintHelp(char **argv)
            "                                      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)
@@ -571,6 +582,7 @@ int main(int argc, char *argv[])
                                  std::nullopt,
                                  false,
                                  false,
+                                 false,
                                  {}};
 
     for (int i = 1; i < argc; ++i) {
@@ -590,6 +602,8 @@ int main(int argc, char *argv[])
                 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);
index 59bdbbd357994311ffa50a16735297fff2d8eec8..d06f212a187fcd55108c4c413b64839f5eaf2c3c 100644 (file)
@@ -19,6 +19,7 @@
 #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>
@@ -183,6 +184,44 @@ constexpr inline uint8_t SAMPLE_GET_ASSERTION_REQUEST[] = {
     // 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)
@@ -376,6 +415,8 @@ TEST(Messages, SerializeMakeCredential1)
             "\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)
@@ -445,6 +486,8 @@ 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)
@@ -507,6 +550,8 @@ 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)