Add CBOR parsing & encoding helpers 07/307507/10
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Mon, 11 Mar 2024 09:31:35 +0000 (10:31 +0100)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Tue, 19 Mar 2024 19:29:18 +0000 (20:29 +0100)
Change-Id: I974f510f5e52ff18b54b1df838e7acdfedcc32af

srcs/CMakeLists.txt
srcs/cbor_encoding.cpp
srcs/cbor_encoding.h
srcs/cbor_parsing.cpp [new file with mode: 0644]
srcs/cbor_parsing.h [new file with mode: 0644]
srcs/common.h
srcs/exception.h
srcs/log/log.h

index ba72cfc76a806861cb1df3684f491dc34647f52c..2cb3adb423494c20cbb6224e04833488791ace80 100644 (file)
@@ -80,6 +80,7 @@ SET(WEBAUTHN_BLE_SOURCES
     ${CMAKE_CURRENT_SOURCE_DIR}/handshake.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/encrypted_tunnel.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/base64.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/cbor_parsing.cpp
 )
 SET(WEBAUTHN_BLE_SOURCES ${WEBAUTHN_BLE_SOURCES} PARENT_SCOPE)
 
index 9d6e94850b1abf94c529dc49573744a85188bf6b..016858bccc4687c0c778df49f71066c7a03ec33f 100644 (file)
@@ -14,7 +14,6 @@
  *  limitations under the License
  */
 
-#include "cbor.h"
 #include "cbor_encoding.h"
 #include "crypto/random.h"
 #include "exception.h"
@@ -203,4 +202,179 @@ void Cbor::EncodeQRContents(const CryptoBuffer &publicKey,
     fidoUri = "FIDO:/" + DigitEncode(buffer);
 }
 
+void Container::CloseContainer(const CborEncoder &mapEncoder) noexcept
+{
+    assert(m_appendingToChild);
+
+    CborError err = cbor_encoder_close_container(&m_encoder, &mapEncoder);
+    if (err != CborNoError)
+        TRY_LOG_ERROR("cbor_encoder_close_container() failed with " << static_cast<int>(err));
+
+    m_appendingToChild = false;
+}
+
+void Container::AppendTextStringZ(const char *value)
+{
+    assert(!m_appendingToChild);
+
+    CborError err;
+    err = cbor_encode_text_stringz(&m_encoder, value);
+    if (err != CborNoError)
+        THROW_ENCODING("cbor_encode_text_stringz() failed with " << static_cast<int>(err));
+}
+
+void Container::AppendTextString(const std::string_view& text)
+{
+    assert(!m_appendingToChild);
+
+    CborError err;
+    err = cbor_encode_text_string(&m_encoder, text.data(), text.size());
+    if (err != CborNoError)
+        THROW_ENCODING("cbor_encode_text_string() failed with " << static_cast<int>(err));
+}
+
+void Container::AppendInt64(int64_t value)
+{
+    assert(!m_appendingToChild);
+
+    CborError err = cbor_encode_int(&m_encoder, value);
+    if (err != CborNoError)
+        THROW_ENCODING("cbor_encode_int() failed with " << static_cast<int>(err));
+}
+
+void Container::AppendByteString(const Buffer &value)
+{
+    assert(!m_appendingToChild);
+
+    CborError err = cbor_encode_byte_string(&m_encoder, value.data(), value.size());
+    if (err != CborNoError)
+        THROW_ENCODING("cbor_encode_byte_string() failed with " << static_cast<int>(err));
+}
+
+void Container::AppendByteString(const wauthn_const_buffer_s &value)
+{
+    assert(!m_appendingToChild);
+    assert(value.data);
+
+    CborError err = cbor_encode_byte_string(&m_encoder, value.data, value.size);
+    if (err != CborNoError)
+        THROW_ENCODING("cbor_encode_byte_string() failed with " << static_cast<int>(err));
+}
+
+void Container::AppendBoolean(bool value)
+{
+    assert(!m_appendingToChild);
+
+    CborError err = cbor_encode_boolean(&m_encoder, value);
+    if (err != CborNoError)
+        THROW_ENCODING("cbor_encode_boolean() failed with " << static_cast<int>(err));
+}
+
+Container Container::OpenArray(size_t elements)
+{
+    assert(!m_appendingToChild);
+
+    CborEncoder arrayEncoder;
+    CborError err = cbor_encoder_create_array(&m_encoder, &arrayEncoder, elements);
+    if (err != CborNoError)
+        THROW_ENCODING("cbor_encoder_create_array() failed with " << static_cast<int>(err));
+
+    m_appendingToChild = true;
+    return Container(std::move(arrayEncoder), this);
+}
+
+SortedMap Container::OpenMap(size_t elements)
+{
+    assert(!m_appendingToChild);
+
+    CborEncoder mapEncoder;
+    CborError err = cbor_encoder_create_map(&m_encoder, &mapEncoder, elements);
+    if (err != CborNoError)
+        THROW_ENCODING("cbor_encoder_create_map() failed with " << static_cast<int>(err));
+
+    m_appendingToChild = true;
+    return SortedMap(std::move(mapEncoder), this);
+}
+
+Container::~Container()
+{
+    assert(!m_appendingToChild);
+
+    if (m_parent)
+        m_parent->CloseContainer(m_encoder);
+}
+
+void SortedMap::AppendByteStringAt(const Key &key, const Buffer &value)
+{
+    AddKey(key);
+    AppendByteString(value);
+}
+
+void SortedMap::AppendByteStringAt(const Key &key, const wauthn_const_buffer_s &value)
+{
+    AddKey(key);
+    AppendByteString(value);
+}
+
+void SortedMap::AppendTextStringZAt(const Key &key, const char *value)
+{
+    assert(value);
+
+    AddKey(key);
+    AppendTextStringZ(value);
+}
+
+void SortedMap::AppendOptionalTextStringZAt(const Key &key, const char *value)
+{
+    if (!value)
+        return;
+
+    AppendTextStringZAt(key, value);
+}
+
+void SortedMap::AppendInt64At(const Key &key, int64_t value)
+{
+    AddKey(key);
+    AppendInt64(value);
+}
+
+void SortedMap::AppendBooleanAt(const Key &key, bool value)
+{
+    AddKey(key);
+    AppendBoolean(value);
+}
+
+Container SortedMap::OpenArrayAt(const Key &key, size_t elements)
+{
+    AddKey(key);
+    return OpenArray(elements);
+}
+
+SortedMap SortedMap::OpenMapAt(const Key &key, size_t elements)
+{
+    AddKey(key);
+    return OpenMap(elements);
+}
+
+void SortedMap::AddKey(const Key &key)
+{
+    if (std::holds_alternative<int64_t>(key)) {
+        AppendInt64(std::get<int64_t>(key));
+    } else if (std::holds_alternative<std::string_view>(key)) {
+        AppendTextString(std::get<std::string_view>(key));
+    } else {
+        THROW_UNKNOWN("Unexpected variant type");
+    }
+}
+
+Encoder Encoder::Create(uint8_t *output, size_t size)
+{
+    assert(output);
+    CborEncoder encoder;
+    cbor_encoder_init(&encoder, output, size, 0);
+    return Encoder(std::move(encoder), output);
+}
+
+size_t Encoder::GetBufferSize() const { return cbor_encoder_get_buffer_size(&m_encoder, m_output); }
+
 } // namespace CborEncoding
index f346838908c583b982f43b85256318aa25b80fbc..4df09a8ebf264cee727b173f6a87e67389e3164e 100644 (file)
 
 #pragma once
 
+#include "cbor.h"
 #include "common.h"
 #include "crypto/common.h"
 
 #include <string>
+#include <variant>
+#include <webauthn-types.h>
 
 namespace CborEncoding {
 
@@ -44,4 +47,73 @@ protected:
     virtual bool getGrease() const;
 };
 
+class SortedMap;
+
+class Container {
+public:
+    Container(CborEncoder &&encoder, Container *parent = nullptr)
+    : m_encoder(std::move(encoder)), m_parent(parent)
+    {
+    }
+
+    Container(const Container &) = delete;
+    Container(Container &&) = delete;
+    Container &operator=(const Container &) = delete;
+    Container &operator=(Container &&) = delete;
+
+    void AppendTextStringZ(const char *value);
+    void AppendTextString(const std::string_view& text);
+    void AppendInt64(int64_t value);
+    void AppendByteString(const Buffer &value);
+    void AppendByteString(const wauthn_const_buffer_s &value);
+    void AppendBoolean(bool value);
+    Container OpenArray(size_t elements);
+    SortedMap OpenMap(size_t elements);
+
+    virtual ~Container();
+
+private:
+    void CloseContainer(const CborEncoder &containerEncoder) noexcept;
+
+protected:
+    CborEncoder m_encoder;
+
+private:
+    bool m_appendingToChild = false;
+    Container *m_parent;
+};
+
+typedef std::variant<int64_t, std::string_view> Key;
+
+class SortedMap : protected Container {
+public:
+    using Container::Container;
+
+    void AppendByteStringAt(const Key &key, const Buffer &value);
+    void AppendByteStringAt(const Key &key, const wauthn_const_buffer_s &value);
+    void AppendTextStringZAt(const Key &key, const char *value);
+    void AppendOptionalTextStringZAt(const Key &key, const char *value);
+    void AppendInt64At(const Key &key, int64_t value);
+    void AppendBooleanAt(const Key &key, bool value);
+    Container OpenArrayAt(const Key &key, size_t elements);
+    SortedMap OpenMapAt(const Key &key, size_t elements);
+
+private:
+    void AddKey(const Key &key);
+};
+
+class Encoder : public Container {
+public:
+    static Encoder Create(uint8_t *output, size_t size);
+    size_t GetBufferSize() const;
+
+private:
+    Encoder(CborEncoder &&encoder, uint8_t *output)
+    : Container(std::move(encoder)), m_output(output)
+    {
+    }
+
+    uint8_t *m_output;
+};
+
 } // namespace CborEncoding
diff --git a/srcs/cbor_parsing.cpp b/srcs/cbor_parsing.cpp
new file mode 100644 (file)
index 0000000..7f3bddd
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ *  Copyright (c) 2024 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+#include "cbor_parsing.h"
+#include "exception.h"
+
+#include <utility>
+
+namespace {
+constexpr auto CBOR_FLAGS = CborValidateShortestIntegrals | CborValidateNoIndeterminateLength |
+    CborValidateMapIsSorted | CborValidateNoTags | CborValidateMapKeysAreUnique |
+    CborValidateCompleteData;
+} // namespace
+
+namespace CborParsing {
+
+const Key CURRENT_KEY;
+
+Container::Container(Container &&other)
+: m_it(std::move(other.m_it)),
+  m_length(other.m_length),
+  m_parsingChild(std::exchange(other.m_parsingChild, false)),
+  m_parent(std::exchange(other.m_parent, nullptr))
+{
+}
+
+Container &Container::operator=(Container &&other)
+{
+    if (this != &other) {
+        m_parent = std::exchange(other.m_parent, nullptr);
+        m_it = std::move(other.m_it);
+        m_length = other.m_length;
+        m_parsingChild = std::exchange(other.m_parsingChild, false);
+    }
+    return *this;
+}
+
+Container::~Container()
+{
+    assert(!m_parsingChild);
+
+    if (!m_parent)
+        return;
+
+    // Skip remaining unparsed values before leaving the container
+    CborError err;
+    while (!cbor_value_at_end(&m_it)) {
+        err = cbor_value_advance(&m_it);
+        if (err != CborNoError)
+            TRY_LOG_ERROR("cbor_value_advance failed with " << static_cast<int>(err));
+    }
+
+    m_parent->LeaveContainer(m_it);
+}
+
+SortedMap Container::EnterMap()
+{
+    assert(!m_parsingChild);
+
+    CborType type = cbor_value_get_type(&m_it);
+    if (type != CborMapType)
+        THROW_UNKNOWN("Expected map type, got " << static_cast<int>(type));
+
+    size_t length;
+    auto err = cbor_value_get_map_length(&m_it, &length);
+    if (err != CborNoError)
+        THROW_UNKNOWN("cbor_value_get_map_length failed with " << static_cast<int>(err));
+
+    CborValue mapIt;
+    err = cbor_value_enter_container(&m_it, &mapIt);
+    if (err != CborNoError)
+        THROW_UNKNOWN("cbor_value_enter_container failed with " << static_cast<int>(err));
+
+    m_parsingChild = true;
+    return SortedMap(std::move(mapIt), this, length);
+}
+
+Container Container::EnterArray()
+{
+    assert(!m_parsingChild);
+
+    CborType type = cbor_value_get_type(&m_it);
+    if (type != CborArrayType)
+        THROW_UNKNOWN("Expected array type, got " << static_cast<int>(type));
+
+    size_t length;
+    auto err = cbor_value_get_array_length(&m_it, &length);
+    if (err != CborNoError)
+        THROW_UNKNOWN("cbor_value_get_array_length failed with " << static_cast<int>(err));
+
+    CborValue arrayIt;
+    err = cbor_value_enter_container(&m_it, &arrayIt);
+    if (err != CborNoError)
+        THROW_UNKNOWN("cbor_value_enter_container failed with " << static_cast<int>(err));
+
+    m_parsingChild = true;
+    return Container(std::move(arrayIt), this, length);
+}
+
+void Container::LeaveContainer(CborValue &childIt) noexcept
+{
+    assert(m_parsingChild);
+
+    // set parent iterator to point to the next element after the child container
+    auto err = cbor_value_leave_container(&m_it, &childIt);
+    if (err != CborNoError)
+        TRY_LOG_ERROR("cbor_value_leave_container failed with " << static_cast<int>(err));
+
+    m_parsingChild = false;
+}
+
+void Container::Advance()
+{
+    assert(!m_parsingChild);
+
+    auto err = cbor_value_advance(&m_it);
+    if (err != CborNoError)
+        THROW_UNKNOWN("cbor_value_advance failed with " << static_cast<int>(err));
+}
+
+int64_t Container::GetInt64()
+{
+    assert(!m_parsingChild);
+
+    if (!cbor_value_is_integer(&m_it))
+        THROW_UNKNOWN("Value is not an integer");
+
+    int64_t value;
+    auto err = cbor_value_get_int64_checked(&m_it, &value);
+    if (err != CborNoError)
+        THROW_UNKNOWN("cbor_value_get_int64_checked failed with " << static_cast<int>(err));
+
+    // skip to the next value
+    Advance();
+    return value;
+}
+
+std::string Container::GetTextString()
+{
+    assert(!m_parsingChild);
+
+    if (!cbor_value_is_text_string(&m_it))
+        THROW_UNKNOWN("Value is not a text string");
+
+    size_t length;
+    auto err = cbor_value_get_string_length(&m_it, &length);
+    if (err != CborNoError)
+        THROW_UNKNOWN("cbor_value_get_string_length failed with " << static_cast<int>(err));
+
+    std::string value(length, '\0');
+
+    // It advances the m_it too
+    err = cbor_value_copy_text_string(&m_it, value.data(), &length, &m_it);
+    if (err != CborNoError)
+        THROW_UNKNOWN("cbor_value_copy_text_string failed with " << static_cast<int>(err));
+
+    return value;
+}
+
+bool Container::GetBoolean()
+{
+    assert(!m_parsingChild);
+
+    if (!cbor_value_is_boolean(&m_it))
+        THROW_UNKNOWN("Value is not a boolean");
+
+    bool value;
+    auto err = cbor_value_get_boolean(&m_it, &value);
+    if (err != CborNoError)
+        THROW_UNKNOWN("cbor_value_get_boolean failed with " << static_cast<int>(err));
+
+    Advance();
+    return value;
+}
+
+uint64_t Container::GetUint64()
+{
+    assert(!m_parsingChild);
+
+    if (!cbor_value_is_unsigned_integer(&m_it))
+        THROW_UNKNOWN("Value is not an unsigned integer");
+
+    uint64_t value;
+    auto err = cbor_value_get_uint64(&m_it, &value);
+    if (err != CborNoError)
+        THROW_UNKNOWN("cbor_value_get_uint64 failed with " << static_cast<int>(err));
+
+    Advance();
+    return value;
+}
+
+Buffer Container::GetByteString()
+{
+    assert(!m_parsingChild);
+
+    if (!cbor_value_is_byte_string(&m_it))
+        THROW_UNKNOWN("Value is not a byte string");
+
+    size_t length;
+    auto err = cbor_value_get_string_length(&m_it, &length);
+    if (err != CborNoError)
+        THROW_UNKNOWN("cbor_value_get_string_length failed with " << static_cast<int>(err));
+
+    Buffer value(length);
+
+    // It advances the m_it too
+    err = cbor_value_copy_byte_string(&m_it, value.data(), &length, &m_it);
+    if (err != CborNoError)
+        THROW_UNKNOWN("cbor_value_copy_byte_string failed with " << static_cast<int>(err));
+
+    return value;
+}
+
+bool SortedMap::LocateKey(const Key &key)
+{
+    assert(!m_parsingChild);
+
+    auto backup = m_it;
+    for (;;) {
+        if (cbor_value_at_end(&m_it))
+            return false;
+
+        if (std::holds_alternative<int64_t>(key)) {
+            auto keyInt = std::get<int64_t>(key);
+            auto tmpKey = GetInt64(); // skips key
+
+            if (tmpKey > keyInt)
+                break; // bigger key found
+
+            if (tmpKey == keyInt)
+                return true;
+        } else if (std::holds_alternative<std::string_view>(key)) {
+            auto &keyStr = std::get<std::string_view>(key);
+            auto tmpKey = GetTextString(); // skips key
+
+            if (tmpKey.size() > keyStr.size() ||
+                (tmpKey.size() == keyStr.size() && tmpKey > keyStr))
+                break; // bigger key found
+
+            if (tmpKey == keyStr)
+                return true;
+        } else if (std::holds_alternative<std::monostate>(key)) {
+            Advance(); // skip key
+            return true;
+        } else {
+            THROW_UNKNOWN("Unexpeceted variant type");
+        }
+
+        // skip value
+        Advance();
+    }
+    m_it = backup; // restore the iterator if key is not found
+    return false;
+}
+
+std::optional<SortedMap> SortedMap::EnterMapAt(const Key &key)
+{
+    if (!LocateKey(key))
+        return std::nullopt;
+
+    return EnterMap();
+}
+
+std::optional<Container> SortedMap::EnterArrayAt(const Key &key)
+{
+    if (!LocateKey(key))
+        return std::nullopt;
+
+    return EnterArray();
+}
+
+std::optional<int64_t> SortedMap::GetInt64At(const Key &key)
+{
+    if (!LocateKey(key))
+        return std::nullopt;
+
+    return GetInt64();
+}
+
+std::optional<std::string> SortedMap::GetTextStringAt(const Key &key)
+{
+    if (!LocateKey(key))
+        return std::nullopt;
+
+    return GetTextString();
+}
+
+std::optional<Buffer> SortedMap::GetByteStringAt(const Key &key)
+{
+    if (!LocateKey(key))
+        return std::nullopt;
+
+    return GetByteString();
+}
+
+std::optional<bool> SortedMap::GetBooleanAt(const Key &key)
+{
+    if (!LocateKey(key))
+        return std::nullopt;
+
+    return GetBoolean();
+}
+
+std::optional<uint64_t> SortedMap::GetUint64At(const Key &key)
+{
+    if (!LocateKey(key))
+        return std::nullopt;
+
+    return GetUint64();
+}
+
+KeyCopy SortedMap::PeekKey()
+{
+    assert(!m_parsingChild);
+
+    if (cbor_value_at_end(&m_it))
+        THROW_UNKNOWN("No more keys");
+
+    CborError err;
+    if (cbor_value_is_integer(&m_it)) {
+        int64_t value;
+        err = cbor_value_get_int64_checked(&m_it, &value);
+        if (err != CborNoError)
+            THROW_UNKNOWN("cbor_value_get_int64_checked failed with " << static_cast<int>(err));
+
+        return value;
+    } else if (cbor_value_is_text_string(&m_it)) {
+        size_t length;
+        err = cbor_value_get_string_length(&m_it, &length);
+        if (err != CborNoError)
+            THROW_UNKNOWN("cbor_value_get_string_length failed with " << static_cast<int>(err));
+
+        std::string value(length, '\0');
+        auto backup = m_it;
+        err = cbor_value_copy_text_string(&m_it, value.data(), &length, &m_it);
+        if (err != CborNoError)
+            THROW_UNKNOWN("cbor_value_copy_text_string failed with " << static_cast<int>(err));
+
+        m_it = backup;
+        return value;
+    }
+
+    THROW_UNKNOWN("Unexpected key type");
+}
+
+Parser::Parser(std::unique_ptr<CborParser> &&parser, CborValue &&root)
+: Container(std::move(root)), m_parser(std::move(parser))
+{
+}
+
+Parser Parser::Create(const uint8_t *input, size_t size)
+{
+    assert(input);
+
+    // root gets a pointer to parser so we can't move it
+    auto parser = std::make_unique<CborParser>();
+    CborValue root;
+
+    auto err = cbor_parser_init(input, size, 0, parser.get(), &root);
+    if (err != CborNoError)
+        THROW_UNKNOWN("cbor_parser_init failed with " << static_cast<int>(err));
+
+    err = cbor_value_validate(&root, CBOR_FLAGS);
+    if (err != CborNoError)
+        THROW_UNKNOWN("CBOR validation failed with " << static_cast<int>(err));
+
+    return Parser(std::move(parser), std::move(root));
+}
+
+} // namespace CborParsing
diff --git a/srcs/cbor_parsing.h b/srcs/cbor_parsing.h
new file mode 100644 (file)
index 0000000..34d3183
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ *  Copyright (c) 2024 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+#pragma once
+
+#include "cbor.h"
+#include "common.h"
+
+#include <memory>
+#include <optional>
+#include <variant>
+
+namespace CborParsing {
+
+class SortedMap;
+
+class Container {
+public:
+    Container(Container &&other);
+    Container &operator=(Container &&other);
+    virtual ~Container();
+
+    SortedMap EnterMap();
+    Container EnterArray();
+
+    int64_t GetInt64();
+    std::string GetTextString();
+    Buffer GetByteString();
+    bool GetBoolean();
+    uint64_t GetUint64();
+
+    size_t Length() const { return m_length; }
+
+protected:
+    Container(CborValue &&it, Container *parent = nullptr, size_t length = 0)
+    : m_it(std::move(it)), m_length(length), m_parent(parent)
+    {
+    }
+
+    void Advance();
+
+private:
+    Container(const Container &) = delete;
+    Container &operator=(const Container &) = delete;
+    void LeaveContainer(CborValue &childIt) noexcept;
+
+protected:
+    CborValue m_it;
+    size_t m_length = 0;
+    bool m_parsingChild = false;
+
+private:
+    Container *m_parent;
+};
+
+typedef std::variant<std::monostate, int64_t, std::string_view> Key;
+typedef std::variant<int64_t, std::string> KeyCopy;
+extern const Key CURRENT_KEY;
+
+class SortedMap : protected Container {
+private:
+    bool LocateKey(const Key &key);
+
+public:
+    using Container::Container;
+
+    std::optional<SortedMap> EnterMapAt(const Key &key);
+    std::optional<Container> EnterArrayAt(const Key &key);
+
+    std::optional<int64_t> GetInt64At(const Key &key);
+    std::optional<std::string> GetTextStringAt(const Key &key);
+    std::optional<Buffer> GetByteStringAt(const Key &key);
+    std::optional<bool> GetBooleanAt(const Key &key);
+    std::optional<uint64_t> GetUint64At(const Key &key);
+
+    KeyCopy PeekKey();
+
+    size_t Length() const { return m_length; }
+};
+
+class Parser : public Container {
+public:
+    static Parser Create(const uint8_t *input, size_t size);
+
+private:
+    Parser(std::unique_ptr<CborParser> &&parser, CborValue &&root);
+
+    std::unique_ptr<CborParser> m_parser;
+};
+
+} // namespace CborParsing
index 35bdfab677cc54fff85337f2364a4c552cc7273e..edf089dceb2d947ead1a8ef534ff049d1b730c72 100644 (file)
@@ -20,6 +20,7 @@
 #include <cstddef>
 #include <string_view>
 #include <utility> // for std::move
+#include <vector>
 
 constexpr size_t QR_SECRET_LEN = 16;
 constexpr size_t BLUETOOTH_ADVERT_LEN = 16;
@@ -37,4 +38,5 @@ private:
     T m_cleanupFn;
 };
 
+typedef std::vector<uint8_t> Buffer;
 typedef std::basic_string_view<uint8_t> BufferView;
index b24ec3fb3c6eccbe4db9c4078cb6190bb6c775e9..d09097528dd9f1d799d08d641830c47f795902e6 100644 (file)
@@ -61,3 +61,4 @@ typedef Exception<WAUTHN_ERROR_CANCELLED> Cancelled;
 #define THROW_UNKNOWN(...) LOGGED_THROW(Exception::Unknown, __VA_ARGS__)
 #define THROW_INVALID_STATE(...) LOGGED_THROW(Exception::InvalidState, __VA_ARGS__)
 #define THROW_CANCELLED() LOGGED_THROW(Exception::Cancelled, "Operation cancelled")
+#define THROW_ENCODING(...) LOGGED_THROW(Exception::EncodingFailed, __VA_ARGS__)
index ba3fe198ca75f276f1f62cdcb125f662ec99b6ad..3a1e8c336cb4be3c8821baefbf2f9dd1930766ad 100644 (file)
@@ -123,10 +123,10 @@ public:
     } catch (...) {               \
     }
 
-#define LOGGED_THROW(exceptionType, msg)                        \
-    do {                                                        \
-        std::ostringstream message;                             \
-        message << msg;                                         \
-        TRY_LOG_ERROR("Throwing exception: " << message.str()); \
-        throw exceptionType(message.str());                     \
+#define LOGGED_THROW(exceptionType, msg)                    \
+    do {                                                    \
+        std::ostringstream oss;                             \
+        oss << msg;                                         \
+        TRY_LOG_ERROR("Throwing exception: " << oss.str()); \
+        throw exceptionType(oss.str());                     \
     } while (false)