{
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)
// 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{});
// 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{});
// 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{});
"\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"
"\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"
// 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{});
// 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{});