Fix formatting MakeCredential response->attestation_object 28/314428/3
authorKrzysztof Malysa <k.malysa@samsung.com>
Thu, 11 Jul 2024 11:48:09 +0000 (13:48 +0200)
committerKrzysztof Malysa <k.malysa@samsung.com>
Tue, 16 Jul 2024 10:25:54 +0000 (12:25 +0200)
Change-Id: I890c3bf1725559ab54f1c96fc070f8f631e83db1

srcs/message.cpp
tests/ctap_message_processor_tests.cpp
tests/message_examples.h
tests/message_tests.cpp

index 481637467fce594c473247dc8da410581b5d9d4d..971aaaa7e536a25f626d9e765aafa90cdaf05569 100644 (file)
@@ -709,31 +709,42 @@ void MakeCredentialResponse::Deserialize(BufferView &input)
 {
     CtapResponse::Deserialize(input);
 
-    // see https://www.w3.org/TR/webauthn-2/#fig-attStructs
-
-    m_attestationObject.assign(input.begin(), input.end());
+    auto inputSize = input.size();
+    {
+        auto helper = CborParsing::Parser::Create(input.data(), input.size());
+        auto map = helper.EnterMap();
 
-    auto helper = CborParsing::Parser::Create(input.data(), input.size());
-    auto map = helper.EnterMap();
+        // "packed", "tpm", "android-key", "android-safetynet", "fido-u2f", "none", "apple"
+        // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
+        m_format = map.GetTextStringAt(KEY_MC_RSP_FMT).value();
 
-    // "packed", "tpm", "android-key", "android-safetynet", "fido-u2f", "none", "apple"
-    // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
-    m_format = map.GetTextStringAt(KEY_MC_RSP_FMT).value();
+        // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
+        DeserializeAuthData(map.GetByteStringAt(KEY_MC_RSP_AUTH_DATA).value());
 
-    // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
-    DeserializeAuthData(map.GetByteStringAt(KEY_MC_RSP_AUTH_DATA).value());
+        if (!m_authData.m_attestationData.has_value())
+            THROW_UNKNOWN("Missing attestation data in Make Credential response");
 
-    if (!m_authData.m_attestationData.has_value())
-        THROW_UNKNOWN("Missing attestation data in Make Credential response");
+        if (auto attStmtMap = map.EnterMapAt(KEY_MC_RSP_ATT_STMT)) {
+            // TODO it depends on the m_format, in a sample response the format was 'none' and this
+            // map was empty.
+        }
+        m_epAtt = map.GetBooleanAt(KEY_MC_RSP_EP_ATT);
+        m_largeBlobKey = map.GetByteStringAt(KEY_MC_RSP_LARGE_BLOB_KEY).value_or(Buffer{});
 
-    if (auto attStmtMap = map.EnterMapAt(KEY_MC_RSP_ATT_STMT)) {
-        // TODO it depends on the m_format, in a sample response the format was 'none' and this
-        // map was empty.
+        // TODO KEY_MC_RSP_UNSIGNED_EXTENSIONS_OUTPUT
     }
-    m_epAtt = map.GetBooleanAt(KEY_MC_RSP_EP_ATT);
-    m_largeBlobKey = map.GetByteStringAt(KEY_MC_RSP_LARGE_BLOB_KEY).value_or(Buffer{});
 
-    // TODO KEY_MC_RSP_UNSIGNED_EXTENSIONS_OUTPUT
+    // see https://www.w3.org/TR/webauthn-3/#fig-attStructs
+    Buffer output(inputSize + 100);
+    auto encoder = CborEncoding::Encoder::Create(output.data(), output.size());
+    {
+        auto map = encoder.OpenMap(3);
+        map.AppendTextStringAt("fmt", m_format);
+        map.OpenMapAt("attStmt", 0); // TODO: copy raw contents of the map if possible
+        map.AppendByteStringAt("authData", m_authDataRaw);
+    }
+    output.resize(encoder.GetBufferSize());
+    m_attestationObject.assign(output.begin(), output.end());
 }
 
 void GetAssertionResponse::Deserialize(BufferView &input)
index 99dce00b183e630e9380f4beaed654563e172528..235da04fd4038e088be8b5c1b8a15679125a19be 100644 (file)
@@ -258,7 +258,8 @@ TEST(CtapMessageProcessor, IphoneExampleMakeCredential)
     // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
     EXPECT_EQ(res.response.m_authData.m_attestationData->m_alg,
               WAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256);
-    EXPECT_EQ(ToBufferView(res.response.m_attestationObject), rawMCResp.substr(2));
+    EXPECT_EQ(ToBufferView(res.response.m_attestationObject),
+              BUFFER_VIEW(IPHONE_EXAMPLE_MAKE_CREDENTIAL_RAW_RESPONSE_ATTESTATION_OBJECT));
     EXPECT_EQ(res.response.m_format, "none");
     EXPECT_EQ(res.response.m_epAtt, std::nullopt);
     EXPECT_EQ(res.response.m_largeBlobKey, Buffer{});
@@ -300,7 +301,8 @@ TEST(CtapMessageProcessor, AndroidExampleMakeCredentialWithoutUpdateMessage)
     // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
     EXPECT_EQ(res.response.m_authData.m_attestationData->m_alg,
               WAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256);
-    EXPECT_EQ(ToBufferView(res.response.m_attestationObject), rawMCResp.substr(2));
+    EXPECT_EQ(ToBufferView(res.response.m_attestationObject),
+              BUFFER_VIEW(ANDROID_EXAMPLE_MAKE_CREDENTIAL_RAW_RESPONSE_ATTESTATION_OBJECT));
     EXPECT_EQ(res.response.m_format, "none");
     EXPECT_EQ(res.response.m_epAtt, std::nullopt);
     EXPECT_EQ(res.response.m_largeBlobKey, Buffer{});
@@ -344,7 +346,8 @@ TEST(CtapMessageProcessor, AndroidExampleMakeCredentialWithUpdateMessage)
     // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
     EXPECT_EQ(res.response.m_authData.m_attestationData->m_alg,
               WAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256);
-    EXPECT_EQ(ToBufferView(res.response.m_attestationObject), rawMCResp.substr(2));
+    EXPECT_EQ(ToBufferView(res.response.m_attestationObject),
+              BUFFER_VIEW(ANDROID_EXAMPLE_MAKE_CREDENTIAL_RAW_RESPONSE_ATTESTATION_OBJECT));
     EXPECT_EQ(res.response.m_format, "none");
     EXPECT_EQ(res.response.m_epAtt, std::nullopt);
     EXPECT_EQ(res.response.m_largeBlobKey, Buffer{});
index a791c20b2f10f661e11b55ae249c975e60628da0..39ce2249e8c841faaaa911c8c33a5db94556e468 100644 (file)
@@ -60,6 +60,17 @@ constexpr inline char IPHONE_EXAMPLE_MAKE_CREDENTIAL_RAW_RESPONSE_ATTESTATION_DA
     "\x4d\x37\x28\x0a\xbe\x86\x37\x13\x6c\x71\xca\x22\x58\x20\x35\x57\xa0\x4e\x67\x8b\x96\x87\x3c"
     "\x00\xc2\x97\xf7\xf3\x5b\x60\x97\x2a\x18\x06\x48\xe5\x5a\xcb\x33\xbe\x8d\x47\x17\x56\x5a\xd0";
 
+// Parsed attestation object of the IPHONE_EXAMPLE_MAKE_CREDENTIAL_RAW_RESPONSE
+constexpr inline char IPHONE_EXAMPLE_MAKE_CREDENTIAL_RAW_RESPONSE_ATTESTATION_OBJECT[] =
+    "\xa3\x63\x66\x6d\x74\x64\x6e\x6f\x6e\x65\x67\x61\x74\x74\x53\x74\x6d\x74\xa0\x68\x61\x75\x74"
+    "\x68\x44\x61\x74\x61\x58\x98\x11\x94\x22\x8d\xa8\xfd\xbd\xee\xfd\x26\x1b\xd7\xb6\x59\x5c\xfd"
+    "\x70\xa5\x0d\x70\xc6\x40\x7b\xcf\x01\x3d\xe9\x6d\x4e\xfb\x17\xde\x5d\x00\x00\x00\x00\xfb\xfc"
+    "\x30\x07\x15\x4e\x4e\xcc\x8c\x0b\x6e\x02\x05\x57\xd7\xbd\x00\x14\x7c\xe0\x64\xdc\xae\x09\x40"
+    "\x6a\x9a\x2f\xae\x13\x5e\x01\x63\x4a\xbd\x50\xb5\xd2\xa5\x01\x02\x03\x26\x20\x01\x21\x58\x20"
+    "\x70\x9a\xdb\x3b\x95\x96\x6b\xc0\x9c\x68\x31\xf2\xf7\x38\xfe\x19\x1d\x7c\x55\xb7\xbf\xde\xb7"
+    "\x11\x5a\x5e\xab\xef\x10\xaf\xb4\x6d\x22\x58\x20\xab\x15\xf0\x1d\x37\x94\xcb\x9b\xaf\xd3\x92"
+    "\xc3\x0a\x07\x03\x82\xa8\xc7\xc5\x88\x8e\xed\xdf\xaf\xb0\x80\x39\x4d\x4e\x67\x8c\xd1";
+
 // Parsed public key DER part of the IPHONE_EXAMPLE_MAKE_CREDENTIAL_RAW_RESPONSE
 constexpr inline char IPHONE_EXAMPLE_MAKE_CREDENTIAL_RAW_RESPONSE_PUBLIC_KEY_DER[] =
     "\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07"
@@ -89,6 +100,18 @@ constexpr inline char ANDROID_EXAMPLE_MAKE_CREDENTIAL_RAW_RESPONSE[] =
     "\x5d\x54\xc8\x22\x58\x20\xc2\x9f\x0d\xc8\x8d\x81\x8f\x57\x51\x46\x93\x31\xc0\x59\xce\x13\x5f"
     "\xbb\x3d\x65\x39\xc2\x89\x68\x77\x52\xb8\x80\x0c\x86\xf9\xd6\x03\xa0";
 
+// Parsed attestation object of the ANDROID_EXAMPLE_MAKE_CREDENTIAL_RAW_RESPONSE
+constexpr inline char ANDROID_EXAMPLE_MAKE_CREDENTIAL_RAW_RESPONSE_ATTESTATION_OBJECT[] =
+    "\xa3\x63\x66\x6d\x74\x64\x6e\x6f\x6e\x65\x67\x61\x74\x74\x53\x74\x6d\x74\xa0\x68\x61\x75\x74"
+    "\x68\x44\x61\x74\x61\x58\xa4\x11\x94\x22\x8d\xa8\xfd\xbd\xee\xfd\x26\x1b\xd7\xb6\x59\x5c\xfd"
+    "\x70\xa5\x0d\x70\xc6\x40\x7b\xcf\x01\x3d\xe9\x6d\x4e\xfb\x17\xde\x45\x00\x00\x00\x00\x53\x41"
+    "\x4d\x53\x55\x4e\x47\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xde\x2f\x46\x7f\xb4\xf6\xc7"
+    "\xbe\x49\x42\xdb\x80\xa4\x3d\xcd\xf2\x1b\xc9\xf7\x31\x54\x9c\x7b\x58\xc8\x2b\x22\x46\x1d\x17"
+    "\x43\x1d\xa5\x01\x02\x03\x26\x20\x01\x21\x58\x20\x9f\x80\x80\xc9\xac\xf9\x92\x66\x12\x3a\xcf"
+    "\x0e\xf8\x7e\x5c\x3f\xbf\xb4\x34\xc8\x96\xa0\xe2\x54\xbe\xeb\x8c\x62\xb2\x5d\x54\xc8\x22\x58"
+    "\x20\xc2\x9f\x0d\xc8\x8d\x81\x8f\x57\x51\x46\x93\x31\xc0\x59\xce\x13\x5f\xbb\x3d\x65\x39\xc2"
+    "\x89\x68\x77\x52\xb8\x80\x0c\x86\xf9\xd6";
+
 // Parsed public key DER part of the ANDROID_EXAMPLE_MAKE_CREDENTIAL_RAW_RESPONSE
 constexpr inline char ANDROID_EXAMPLE_MAKE_CREDENTIAL_RAW_RESPONSE_PUBLIC_KEY_DER[] =
     "\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07"
index be5a418df61ec0c77a991e1c7e39929d0d0b5a37..59bdbbd357994311ffa50a16735297fff2d8eec8 100644 (file)
@@ -539,7 +539,8 @@ TEST(Messages, ParseMakeCredentialResponseFromIphone)
     // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
     EXPECT_EQ(msg.m_authData.m_attestationData->m_alg,
               WAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256);
-    EXPECT_EQ(ToBufferView(msg.m_attestationObject), view);
+    EXPECT_EQ(ToBufferView(msg.m_attestationObject),
+              BUFFER_VIEW(IPHONE_EXAMPLE_MAKE_CREDENTIAL_RAW_RESPONSE_ATTESTATION_OBJECT));
     EXPECT_EQ(msg.m_format, "none");
     EXPECT_EQ(msg.m_epAtt, std::nullopt);
     EXPECT_EQ(msg.m_largeBlobKey, Buffer{});
@@ -567,7 +568,8 @@ TEST(Messages, ParseMakeCredentialResponseFromAndroid)
     // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
     EXPECT_EQ(msg.m_authData.m_attestationData->m_alg,
               WAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256);
-    EXPECT_EQ(ToBufferView(msg.m_attestationObject), view);
+    EXPECT_EQ(ToBufferView(msg.m_attestationObject),
+              BUFFER_VIEW(ANDROID_EXAMPLE_MAKE_CREDENTIAL_RAW_RESPONSE_ATTESTATION_OBJECT));
     EXPECT_EQ(msg.m_format, "none");
     EXPECT_EQ(msg.m_epAtt, std::nullopt);
     EXPECT_EQ(msg.m_largeBlobKey, Buffer{});