Add RP ID validation 43/307843/9
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Wed, 13 Mar 2024 16:37:24 +0000 (17:37 +0100)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Fri, 22 Mar 2024 13:57:54 +0000 (14:57 +0100)
Change-Id: Ie10bf02aaeaed029a4f47db258baebd31b4222c9

srcs/exception.h
srcs/message.cpp
srcs/message.h
tests/message_tests.cpp

index eea336f0bb5478f2a89708427ae421e0bea22a2a..e7f4af1102bf972fd785b0019c0c05049cee31e2 100644 (file)
@@ -63,3 +63,4 @@ typedef Exception<WAUTHN_ERROR_CANCELLED> Cancelled;
 #define THROW_CANCELLED() LOGGED_THROW(Exception::Cancelled, "Operation cancelled")
 #define THROW_ENCODING(...) LOGGED_THROW(Exception::EncodingFailed, __VA_ARGS__)
 #define THROW_MEMORY() LOGGED_THROW(Exception::MemoryError, "Memory error")
+#define THROW_INVALID_PARAM(...) LOGGED_THROW(Exception::InvalidParam, __VA_ARGS__)
index 8ffb196914d32313ed18b31e9dd4fe55d61685ae..34e2cff26f24de7896bc62df9acf958093b2d42a 100644 (file)
@@ -18,6 +18,8 @@
 #include "exception.h"
 #include "message.h"
 
+#include <regex>
+
 namespace {
 
 // Get Info response
@@ -49,6 +51,20 @@ constexpr int64_t KEY_GI_RSP_LONG_TOUCH_FOR_RESET = 0x18;
 
 } // namespace
 
+void ValidateDomain(const char *rpId)
+{
+    if (!rpId)
+        THROW_INVALID_PARAM("rpId is NULL");
+
+    if (strlen(rpId) > 253)
+        THROW_INVALID_PARAM("Relying party ID '" << rpId << "' exceeds 253 characters");
+
+    const std::regex pattern{
+        R"(^[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$)"};
+    if (!std::regex_match(rpId, pattern))
+        THROW_INVALID_PARAM("Relying party ID '" << rpId << "' is not a valid domain string");
+}
+
 void PostHandshakeResponse::Deserialize(BufferView &input)
 {
     auto helper = CborParsing::Parser::Create(input.data(), input.size());
index b38ad6135a5cd0e79d188e8a0fbc06a87ec9576e..e1ccd259c8e020e9d732325168aa4007ee001312 100644 (file)
@@ -71,3 +71,4 @@ public:
     std::optional<bool> m_longTouchForReset;
 };
 
+void ValidateDomain(const char *rpId);
index 57c6633cc16ce724356a0087d37be8e6df81d03a..1b025783faf65c25a444ec2d1f9b1a2d438361a0 100644 (file)
@@ -14,6 +14,7 @@
  *  limitations under the License
  */
 
+#include "exception.h"
 #include "message.h"
 
 #include <gtest/gtest.h>
@@ -126,3 +127,39 @@ TEST(Messages, ParsePostHandshakeMessage2)
     ASSERT_FALSE(msg.m_uvCountSinceLastPinEntry.has_value());
     ASSERT_FALSE(msg.m_longTouchForReset.has_value());
 }
+
+TEST(Messages, DomainName)
+{
+    std::string notTooLongLabel(63, 'a');
+    std::string tooLongLabel(64, 'a');
+    std::string tooLongDomain = notTooLongLabel;
+    while (tooLongDomain.size() < 254)
+        tooLongDomain += "." + notTooLongLabel;
+    tooLongDomain.resize(254);
+    assert(tooLongDomain.back() != '.');
+
+    ASSERT_NO_THROW(ValidateDomain("acme"));
+    ASSERT_NO_THROW(ValidateDomain("acme.com"));
+    ASSERT_NO_THROW(ValidateDomain("acme.acme.com"));
+    ASSERT_NO_THROW(ValidateDomain("a-cme.acme.com"));
+    ASSERT_NO_THROW(ValidateDomain("a-cme.ac-me.com"));
+    ASSERT_NO_THROW(ValidateDomain("a-cme.ac-me.c-om"));
+    ASSERT_NO_THROW(ValidateDomain("a-c5me.ac-me.c-om"));
+    ASSERT_NO_THROW(ValidateDomain("a-c5me.ac-5me.c-om"));
+    ASSERT_NO_THROW(ValidateDomain("a-c5me.ac-m5e.c-5om"));
+    ASSERT_NO_THROW(ValidateDomain("a-c5me.ac-m5e.c--5om"));
+    ASSERT_NO_THROW(ValidateDomain(notTooLongLabel.c_str()));
+    ASSERT_NO_THROW(ValidateDomain(tooLongDomain.c_str() + 1));
+    ASSERT_THROW(ValidateDomain(nullptr), Exception::InvalidParam);
+    ASSERT_THROW(ValidateDomain("acme."), Exception::InvalidParam);
+    ASSERT_THROW(ValidateDomain(".acme"), Exception::InvalidParam);
+    ASSERT_THROW(ValidateDomain("-acme.com"), Exception::InvalidParam);
+    ASSERT_THROW(ValidateDomain("acme..com"), Exception::InvalidParam);
+    ASSERT_THROW(ValidateDomain("acme-.com"), Exception::InvalidParam);
+    ASSERT_THROW(ValidateDomain("acme.-com"), Exception::InvalidParam);
+    ASSERT_THROW(ValidateDomain("acme.com-"), Exception::InvalidParam);
+    ASSERT_THROW(ValidateDomain("a_cme.com"), Exception::InvalidParam);
+    ASSERT_THROW(ValidateDomain("a?cme.com"), Exception::InvalidParam);
+    ASSERT_THROW(ValidateDomain(tooLongLabel.c_str()), Exception::InvalidParam);
+    ASSERT_THROW(ValidateDomain(tooLongDomain.c_str()), Exception::InvalidParam);
+}