Refactoring serialization to avoid strict aliasing violation 66/315766/5
authorDongsun Lee <ds73.lee@samsung.com>
Tue, 30 Jul 2024 03:43:16 +0000 (12:43 +0900)
committerKrzysztof Malysa <k.malysa@samsung.com>
Tue, 15 Oct 2024 16:31:37 +0000 (18:31 +0200)
Change-Id: I5319c060c61459c97a0bef24ee52020cf2b101bf

14 files changed:
srcs/client/client-request-ga.h
srcs/client/client-request-mc.h
srcs/client/client-request.h
srcs/common/istream.h [new file with mode: 0644]
srcs/common/message-buffer.h
srcs/common/serialization.cpp
srcs/common/serialization.h
srcs/server/request-ga.h
srcs/server/request-mc.h
srcs/server/request.h
srcs/server/service.cpp
srcs/server/service.h
tests/client-request-test.cpp
tests/serialization-test.cpp

index 8daee05b0eb707aa7c4e091bf8ddcac3458d3715..0c897699bf0a455d7fa5cccea183b1e03633aeab 100644 (file)
@@ -31,6 +31,9 @@ public:
     typedef wauthn_ga_callbacks_s Callbacks;
     typedef wauthn_pubkey_credential_assertion_s PubKeyCred;
 
+    typedef PubKeyCredRequestOptionsSerializer OptionsSerializer;
+    typedef PubkeyCredentialAssertionDeserializer PubKeyCredDeserializer;
+
     explicit ClientRequestGA() : ClientRequest(WebAuthnCall::GET_ASSERTION)
     {
     }
index 60a3dd2dbe949e6cc55fdebb9120e6087c2cb001..a81703190f18e7db136681a49e7818e511eb3814 100644 (file)
@@ -31,6 +31,9 @@ public:
     typedef wauthn_mc_callbacks_s Callbacks;
     typedef wauthn_pubkey_credential_attestation_s PubKeyCred;
 
+    typedef PubKeyCredCreationOptionsSerializer OptionsSerializer;
+    typedef PubkeyCredentialAttestationDeserializer PubKeyCredDeserializer;
+
     explicit ClientRequestMC() : ClientRequest(WebAuthnCall::MAKE_CREDENTIAL)
     {
     }
index dffdf357c70c03838ebd46e7cb89e5b956e279b0..ee58a0815e6231ee232ad4126d66b916bc5996b3 100644 (file)
@@ -235,11 +235,11 @@ void cb_worker(std::shared_ptr<Request> request, const typename Request::Callbac
                 << qr_code);
             callbacks.qrcode_callback(qr_code.c_str(), callbacks.user_data);
         }
-        typename Request::PubKeyCred *cred = nullptr;
-        request->Recv(&cred);
+        typename Request::PubKeyCredDeserializer credDeserializer;
+        request->Recv(credDeserializer);
         LogInfo(REQUEST_KIND_PREFIX << "Calling response_callback");
-        callbacks.response_callback(cred, wauthn_error_e(request->GetStatus()),
-                                    callbacks.user_data);
+        callbacks.response_callback(credDeserializer.getRawPtr(),
+                                    wauthn_error_e(request->GetStatus()), callbacks.user_data);
         if(request->Failed())
         {
             LogError(REQUEST_KIND_PREFIX << "Error on received response: "
@@ -247,17 +247,18 @@ void cb_worker(std::shared_ptr<Request> request, const typename Request::Callbac
             return request->GetStatus();
         }
 
-        wauthn_hybrid_linked_data_s *linked_data = nullptr;
-
-        while (request->Recv(&linked_data).Incompleted())
+        HybridLinkedDataDeserializer linkedDataDeserializer;
+        while (request->Recv(linkedDataDeserializer).Incompleted())
         {
-            LogLinkedDevice(REQUEST_KIND_PREFIX, "[Update Waiting]", linked_data);
-            callbacks.linked_data_callback(linked_data, wauthn_error_e(request->GetStatus()),
+            LogLinkedDevice(REQUEST_KIND_PREFIX, "[Update Waiting]",
+                            linkedDataDeserializer.getRawPtr());
+            callbacks.linked_data_callback(linkedDataDeserializer.getRawPtr(),
+                                           wauthn_error_e(request->GetStatus()),
                                            callbacks.user_data);
         }
-        LogLinkedDevice(REQUEST_KIND_PREFIX, "[Update Done]", linked_data);
-        callbacks.linked_data_callback(linked_data, wauthn_error_e(request->GetStatus()),
-                                       callbacks.user_data);
+        LogLinkedDevice(REQUEST_KIND_PREFIX, "[Update Done]", linkedDataDeserializer.getRawPtr());
+        callbacks.linked_data_callback(linkedDataDeserializer.getRawPtr(),
+                                       wauthn_error_e(request->GetStatus()), callbacks.user_data);
         return WAUTHN_ERROR_NONE;
     });
     LogInfo(REQUEST_KIND_PREFIX << "Exiting with result: " << get_error_message(ret));
@@ -280,7 +281,9 @@ int wauthn_process(const wauthn_client_data_s *client_data,
         if (ret != WAUTHN_ERROR_NONE)
             return ret;
 
-        if (request->SendRequest(client_data, options).Failed())
+        ClientDataSerializer clientDataSerializer(client_data);
+        typename T::OptionsSerializer optionsSerializer(options);
+        if (request->SendRequest(clientDataSerializer, optionsSerializer).Failed())
             return request->GetStatus();
         LogInfo("SendRequest: " << get_error_message(request->GetStatus()));
 
diff --git a/srcs/common/istream.h b/srcs/common/istream.h
new file mode 100644 (file)
index 0000000..1e755cd
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ *  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
+ *
+ *
+ * @file        istream.h
+ * @version     1.0
+ * @brief       Abstract data stream buffer
+ */
+
+#pragma once
+
+#include <cstddef>
+
+namespace WA {
+
+// Abstract data stream buffer
+class IStream
+{
+  public:
+    virtual void Read(size_t num, void * bytes) = 0;
+    virtual void Write(size_t num, const void * bytes) = 0;
+    virtual ~IStream(){}
+};
+
+} // namespace WA
index cd5b34021c1884613380a57e727795d1cc0f1f6d..f3c36d68abf1f6f8b02e5d2d6b1457c83abb532e 100644 (file)
 #pragma once
 
 #include <exception.h>
-#include <serialization.h>
 
 #include <cassert>
 #include <webauthn-log.h>
 
+#include "istream.h"
+
 namespace WA {
 
 /**
index 8291e7e60a0548b639a5cdc94faace7b83c8d48b..2ed0af2b160d10a7e354429f9d3e4df482b33003 100644 (file)
 
 #include <cstring>
 #include <iostream>
-
-#include <serialization.h>
-#include <message-buffer.h>
-
+#include "serialization.h"
+#include "message-buffer.h"
 
 namespace WA {
 
-// For alignment
-constexpr size_t __getAlignSize() {
-    return sizeof(size_t);
+void __checkValidity(const void* data, size_t length) {
+    if (data == nullptr && length != 0)
+        ThrowMsg(SerializationException::InvalidStreamData,
+            "Empty data with length=" << length);
+    if (length > MAX_BUFFER_SIZE)
+        ThrowMsg(SerializationException::InvalidStreamData,
+            "Too large length of data to write: length=" << length);
 }
-
-size_t __getPaddingSize(size_t data_size) {
-    constexpr size_t alignSize = __getAlignSize();
-    return (alignSize - (data_size % alignSize)) % alignSize;
+void __serialize(IStream& stream, const void* data, size_t length) {
+    __checkValidity(data, length);
+    stream.Write(sizeof(size_t), &length);
+    if (length != 0)
+        stream.Write(length, data);
 }
+size_t __deserialize(MessageBuffer& buffer, void* data, size_t data_len) {
+    size_t length = 0;
+    if (data == nullptr)
+        ThrowMsg(SerializationException::InvalidStreamData,
+            "nullptr data or length. data=" << data );
 
-void __addAlignmentPadding(IStream& stream, size_t data_size) {
-    size_t paddingSize = __getPaddingSize(data_size);
-    if (paddingSize > 0) {
-        size_t padding = 0;
-        stream.Write(paddingSize, &padding);
-    }
-}
+    buffer.Read(sizeof(size_t), &length);
+    if (data_len < length)
+        ThrowMsg(SerializationException::InvalidStreamData,
+            "Read data is too big. buff_size=" << data_len << ", length=" << length);
+    if (length > 0)
+        buffer.Read(length, data);
 
-void __removeAlignmentPadding(IStream& stream, size_t data_size) {
-    size_t paddingSize = __getPaddingSize(data_size);
-    if (paddingSize > 0) {
-        size_t padding = 0;
-        stream.Read(paddingSize, &padding);
-    }
+    __checkValidity(data, length);
+    return length;
 }
-
-void __checkAlignment(const char *name, const void *ptr) {
-    constexpr size_t alignSize = __getAlignSize();
-    size_t pointer = reinterpret_cast<size_t>(ptr);
-    if ( (ptr != nullptr) && (pointer % alignSize != 0) ) {
+template <typename T>
+size_t __deserializeWithNewArray(MessageBuffer& buffer, std::unique_ptr<T[]>& data) {
+    size_t length = 0;
+    buffer.Read(sizeof(size_t), &length);
+    if (length > MAX_BUFFER_SIZE)
         ThrowMsg(SerializationException::InvalidStreamData,
-                "Invalid Alignment of Pointer: pointer addr=" << pointer
-                << ", name=" << name << std::endl);
+            "Too large data length: length=" << length);
+    if (length == 0) {
+        data.reset(); // set to nullptr
+    } else {
+        data = std::make_unique<T[]>(length);
+        buffer.Read(length, data.get());
     }
+    return length;
 }
 
-// For array item
-void __serializeArrayItem(IStream& stream, const void *data, size_t struct_size) {
-    stream.Write(struct_size, data);
-}
-void __deserializeArrayItem(IStream& stream, void **data, size_t struct_size) {
-    MessageBuffer& buffer = dynamic_cast<MessageBuffer&>(stream);
-    *data = buffer.Ptr();
-    char buf[struct_size];
-    buffer.Read(struct_size, buf); // for moving internal offset.
+// For char*
+void __serialize(IStream& stream, const char* data) {
+    size_t length = (data != nullptr) ? strlen(data) + 1 : 0;
+    __checkValidity(data, length);
+    stream.Write(sizeof(size_t), &length);
+    if (length != 0)
+        stream.Write(length, data);
 }
+// For array
 void __checkArraySize(size_t size) {
     if (size > MAX_ARRAY_COUNT)
         ThrowMsg(SerializationException::InvalidStreamData,
                 "Too big array size: size=" << size);
 }
-
-void __serializeArray(IStream& stream, size_t array_cnt, const unsigned char *data, size_t struct_size) {
-    for(size_t i=0; i < array_cnt; i++)
-        __serializeArrayItem(stream, data + (i * struct_size), struct_size);
-    __addAlignmentPadding(stream, array_cnt * struct_size);
+void __serializeBinaryArray(IStream& stream, size_t array_cnt, const void *data,
+                            size_t struct_size) {
+    stream.Write(array_cnt * struct_size, data);
+}
+template <typename T>
+void __deserializeBinaryArray(MessageBuffer& buffer, size_t array_cnt, std::unique_ptr<T[]>& data,
+                              size_t struct_size) {
+    if (array_cnt == 0)
+        return;
+    size_t length = array_cnt * struct_size;
+    data = std::make_unique<T[]>(length);
+    buffer.Read(length, data.get());
+}
+template<typename Serializer, typename CType>
+void __serializeBinaryArray(IStream& stream, size_t array_cnt, CType* data) {
+    for (size_t i = 0; i < array_cnt; i++) {
+        Serializer serializer(data + i);
+        serializer.Serialize(stream);
+    }
+}
+template <typename Deserializer>
+void __deserializeBinaryArray(IStream& stream, size_t array_cnt,
+                              std::unique_ptr<Deserializer[]>& deserializers) {
+    for (size_t i = 0; i < array_cnt; i++) {
+        deserializers[i].Deserialize(stream);
+    }
 }
 
-void __deserializeArray(IStream& stream, size_t array_cnt, unsigned char **data, size_t struct_size) {
-    unsigned char *tmp = nullptr;
-    for(size_t i=0; i < array_cnt; i++) {
-        __deserializeArrayItem(stream, reinterpret_cast<void **>(&tmp), struct_size);
-        if (i == 0) // set pointer to the first parameter
-            *data = tmp;
+// For array other than binary array
+template <typename Serializer, typename T>
+void __serializeArray(IStream& stream, size_t array_cnt, T *data) {
+    for (size_t i = 0; i < array_cnt; i++) {
+        Serializer serializer(data + i);
+        serializer.Serialize(stream);
+    }
+}
+template <typename Deserializer, typename CType>
+void __deserializeArray(MessageBuffer& buffer, size_t array_cnt,
+                        std::unique_ptr<CType[]>& array,
+                        std::unique_ptr<Deserializer[]>& deserializers) {
+    array = std::unique_ptr<CType[]>(new CType[array_cnt]);
+    deserializers = std::unique_ptr<Deserializer[]>(new Deserializer[array_cnt]);
+    for (size_t i = 0; i < array_cnt; i++) {
+        deserializers[i].Deserialize(buffer);
+        std::memcpy(array.get() + i, deserializers[i].getRawPtr(), sizeof(CType));
     }
-    __removeAlignmentPadding(stream, array_cnt * struct_size);
 }
 
 // For struct body itself
-void WAuthnCtypeSerializer::serializeStructBody(IStream& stream, const void *data, size_t struct_size) {
+void __serializeStructBody(IStream& stream, const void *data, size_t struct_size) {
     size_t length = (data == nullptr) ? 0 : struct_size;
-    serialize(stream, reinterpret_cast<const unsigned char*>(data), length);
-    __addAlignmentPadding(stream, struct_size);
+    __serialize(stream, data, length);
 }
-void WAuthnCtypeSerializer::deserializeStructBody(IStream& stream, void **data, size_t struct_size) {
+size_t __deserializeStructBody(MessageBuffer& buffer, void *data, size_t struct_size) {
     if (data == nullptr)
         ThrowMsg(SerializationException::InvalidStreamData, "nullptr data.");
-    size_t length = 0;
-    deserialize(stream, const_cast<const unsigned char**>(reinterpret_cast<unsigned char**>(data)), &length);
+    size_t length = __deserialize(buffer, data, struct_size);
     if (length != 0 && length != struct_size)
         ThrowMsg(SerializationException::InvalidStreamData, "Invalid length: length=" << length
                                                             << ", struct_size=" << struct_size);
-    __removeAlignmentPadding(stream, struct_size);
-}
-
- // For unsigned char*
-void __checkValidity(const unsigned char* data, size_t length) {
-    if (data == nullptr && length != 0)
-        ThrowMsg(SerializationException::InvalidStreamData,
-            "Empty data with length=" << length);
-    if (length > MAX_BUFFER_SIZE)
-        ThrowMsg(SerializationException::InvalidStreamData,
-            "Too large length of data to write: length=" << length);
-}
-void WAuthnCtypeSerializer::serialize(IStream& stream, const unsigned char* data, size_t length) {
-    __checkValidity(data, length);
-    stream.Write(sizeof(size_t), &length);
-    if (length != 0)
-        stream.Write(length, data);
-    __addAlignmentPadding(stream, length);
-}
-void WAuthnCtypeSerializer::deserialize(IStream& stream, const unsigned char** data, size_t* length) {
-    if (data == nullptr || length == nullptr)
-        ThrowMsg(SerializationException::InvalidStreamData,
-            "nullptr data or length. data=" << data << ", length=" << length);
-
-    MessageBuffer& buffer = dynamic_cast<MessageBuffer&>(stream);
-    buffer.Read(sizeof(size_t), length);
-    if (*length == 0) {
-        *data = nullptr;
-    } else {
-        *data = buffer.Ptr();
-    }
-
-    __checkValidity(*data, *length);
-    // for moving internal offset.
-    char buf[*length];
-    buffer.Read(*length, buf);
-    __removeAlignmentPadding(stream, *length);
-}
-
-// For char*
-void WAuthnCtypeSerializer::serialize(IStream& stream, const char* data) {
-    size_t length = (data) ? strlen(data) + 1 : 0;
-    serialize(stream, reinterpret_cast<const unsigned char*>(data), length);
-}
-void WAuthnCtypeSerializer::deserialize(IStream& stream, const char** data) {
-    if (data == nullptr)
-        ThrowMsg(SerializationException::InvalidStreamData, "nullptr data");
-    size_t length;
-    deserialize(stream, reinterpret_cast<const unsigned char**>(data), &length);
-    if (*data != nullptr && length != strlen(*data) + 1)
-        ThrowMsg(SerializationException::InvalidStreamData,
-                "Invalid length of cstring (not expected one): "
-                << " length=" << length <<", strlen(string)+1=" << strlen(*data) + 1);
-}
-
-// For wauthn_error_e
-void __checkValidity(const wauthn_error_e data) {
-    switch (data) {
-    case WAUTHN_ERROR_NONE:
-    case WAUTHN_ERROR_UNKNOWN:
-    case WAUTHN_ERROR_INVALID_PARAMETER:
-    case WAUTHN_ERROR_PERMISSION_DENIED:
-    case WAUTHN_ERROR_NOT_SUPPORTED:
-    case WAUTHN_ERROR_OUT_OF_MEMORY:
-    case WAUTHN_ERROR_CANCELED:
-    case WAUTHN_ERROR_TIMED_OUT:
-    case WAUTHN_ERROR_CONNECTION_REFUSED:
-    case WAUTHN_ERROR_NONE_AND_WAIT:
-    case WAUTHN_ERROR_NOT_ALLOWED:
-    case WAUTHN_ERROR_INVALID_STATE:
-    case WAUTHN_ERROR_ENCODING_FAILED:
-    case WAUTHN_ERROR_SOCKET:
-    case WAUTHN_ERROR_NO_SUCH_SERVICE:
-    case WAUTHN_ERROR_ACCESS_DENIED:
-        return;
-    }
-    ThrowMsg(SerializationException::InvalidStreamData,
-        "Invalid value for wauthn_error_e: value=" << data);
-}
-void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_error_e data) {
-    __checkValidity(data);
-    int tmp = static_cast<int>(data);
-    stream.Write(sizeof(tmp), &tmp);
-}
-void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_error_e* data) {
-    if (data == nullptr)
-        ThrowMsg(SerializationException::InvalidStreamData, "nullptr data");
-    int tmp = 0;
-    stream.Read(sizeof(tmp), &tmp);
-    *data = static_cast<wauthn_error_e>(tmp);
-    __checkValidity(*data);
+    return length;
 }
 
 // For wauthn_const_buffer_s
@@ -211,157 +157,153 @@ void __checkValidity(const wauthn_const_buffer_s* data) {
         ThrowMsg(SerializationException::InvalidStreamData,
             "Empty data with size=" << data->size);
 }
-void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_const_buffer_s* data) {
-    __checkValidity(data);
+void ConstBufferSerializer::Serialize(IStream &stream) const {
+    __checkValidity(m_ptr);
     // Serialize struct itself
-    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_const_buffer_s));
-    if (data == nullptr)
+    __serializeStructBody(stream, m_ptr, sizeof(wauthn_const_buffer_s));
+    if (m_ptr == nullptr)
         return;
     // Serialize the contents of struct's pointers
-    serialize(stream, data->data, data->size);
+    __serialize(stream, m_ptr->data, m_ptr->size);
 }
-void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_const_buffer_s** data) {
+void ConstBufferDeserializer::Deserialize(MessageBuffer &buffer) {
+    auto rawBufferPtr = std::make_unique<wauthn_const_buffer_s>();
     // Deserialize struct itself
-    deserializeStructBody(stream, reinterpret_cast<void**>(data), sizeof(wauthn_const_buffer_s));
-    __checkValidity(*data);
-    if (*data == nullptr)
+    size_t structLen = __deserializeStructBody(buffer, rawBufferPtr.get(),
+                                               sizeof(wauthn_const_buffer_s));
+    if (structLen == 0) // the serialized struct is nullptr
         return;
+    __checkValidity(rawBufferPtr.get());
     // Deserialize the contents of struct's pointers
-    deserialize(stream, &((*data)->data), &((*data)->size));
-    __checkAlignment("wauthn_const_buffer_s->data", (*data)->data);
+    size_t read = __deserializeWithNewArray(buffer, this->m_data);
+    // reset pointer
+    this->m_ptr = std::move(rawBufferPtr);
+    this->m_ptr->data = this->m_data.get();
+    this->m_ptr->size = read;
 }
 
 // For wauthn_authenticator_attestation_response_s
-void __checkAlignment(const wauthn_authenticator_attestation_response_s* data) {
-    if (data == nullptr)
-        return;
-    __checkAlignment("wauthn_authenticator_attestation_response_s->client_data_json", data->client_data_json);
-    __checkAlignment("wauthn_authenticator_attestation_response_s->attestation_object", data->attestation_object);
-    __checkAlignment("wauthn_authenticator_attestation_response_s->authenticator_data", data->authenticator_data);
-    __checkAlignment("wauthn_authenticator_attestation_response_s->subject_pubkey_info", data->subject_pubkey_info);
-}
-void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_authenticator_attestation_response_s* data) {
+void AuthenticatorAttestationResponseSerializer::Serialize(IStream &stream) const {
     // Serialize struct itself
-    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_authenticator_attestation_response_s));
-    if (data == nullptr)
+    __serializeStructBody(stream, m_ptr, sizeof(wauthn_authenticator_attestation_response_s));
+    if (m_ptr == nullptr)
         return;
     // Serialize the contents of struct's pointers
-    serialize(stream, data->client_data_json);
-    serialize(stream, data->attestation_object);
-    serialize(stream, data->authenticator_data);
-    serialize(stream, data->subject_pubkey_info);
+    ConstBufferSerializer(m_ptr->client_data_json).Serialize(stream);
+    ConstBufferSerializer(m_ptr->attestation_object).Serialize(stream);
+    ConstBufferSerializer(m_ptr->authenticator_data).Serialize(stream);
+    ConstBufferSerializer(m_ptr->subject_pubkey_info).Serialize(stream);
 }
-void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_authenticator_attestation_response_s** data) {
+void AuthenticatorAttestationResponseDeserializer::Deserialize(MessageBuffer &buffer) {
+    auto rawBufferPtr = std::make_unique<wauthn_authenticator_attestation_response_s>();
     // Deserialize struct itself
-    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_authenticator_attestation_response_s));
-    if (*data == nullptr)
+    size_t structLen =__deserializeStructBody(buffer,
+                                            rawBufferPtr.get(),
+                                            sizeof(wauthn_authenticator_attestation_response_s));
+    if (structLen == 0) // the serialized struct is nullptr
         return;
     // Deserialize the contents of struct's pointers
-    deserialize(stream, &((*data)->client_data_json));
-    deserialize(stream, &((*data)->attestation_object));
-    deserialize(stream, &((*data)->authenticator_data));
-    deserialize(stream, &((*data)->subject_pubkey_info));
-
-    __checkAlignment(*data);
+    this->m_clientDataJson.Deserialize(buffer);
+    this->m_attestationObject.Deserialize(buffer);
+    this->m_authenticatorData.Deserialize(buffer);
+    this->m_subjectPublicKey.Deserialize(buffer);
+    // reset pointer
+    this->m_ptr = std::move(rawBufferPtr);
+    this->m_ptr->client_data_json = this->m_clientDataJson.getRawPtr();
+    this->m_ptr->attestation_object = this->m_attestationObject.getRawPtr();
+    this->m_ptr->authenticator_data = this->m_authenticatorData.getRawPtr();
+    this->m_ptr->subject_pubkey_info = this->m_subjectPublicKey.getRawPtr();
 }
 
 // For wauthn_authenticator_assertion_response_s
-void __checkAlignment(const wauthn_authenticator_assertion_response_s* data) {
-    if (data == nullptr)
-        return;
-    __checkAlignment("wauthn_authenticator_assertion_response_s->client_data_json", data->client_data_json);
-    __checkAlignment("wauthn_authenticator_assertion_response_s->authenticator_data", data->authenticator_data);
-    __checkAlignment("wauthn_authenticator_assertion_response_s->signature", data->signature);
-    __checkAlignment("wauthn_authenticator_assertion_response_s->user_handle", data->user_handle);
-    __checkAlignment("wauthn_authenticator_assertion_response_s->attestation_object", data->attestation_object);
-}
-void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_authenticator_assertion_response_s* data) {
+void AuthenticatorAssertionResponseSerializer::Serialize(IStream &stream) const {
     // Serialize struct itself
-    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_authenticator_assertion_response_s));
-    if (data == nullptr)
+    __serializeStructBody(stream, m_ptr, sizeof(wauthn_authenticator_assertion_response_s));
+    if (m_ptr == nullptr)
         return;
     // Serialize the contents of struct's pointers
-    serialize(stream, data->client_data_json);
-    serialize(stream, data->authenticator_data);
-    serialize(stream, data->signature);
-    serialize(stream, data->user_handle);
-    serialize(stream, data->attestation_object);
-}
-void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_authenticator_assertion_response_s** data) {
+    ConstBufferSerializer(m_ptr->client_data_json).Serialize(stream);
+    ConstBufferSerializer(m_ptr->authenticator_data).Serialize(stream);
+    ConstBufferSerializer(m_ptr->signature).Serialize(stream);
+    ConstBufferSerializer(m_ptr->user_handle).Serialize(stream);
+    ConstBufferSerializer(m_ptr->attestation_object).Serialize(stream);
+}
+void AuthenticatorAssertionResponseDeserializer::Deserialize(MessageBuffer &buffer) {
+    auto rawBufferPtr = std::make_unique<wauthn_authenticator_assertion_response_s>();
     // Deserialize struct itself
-    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_authenticator_assertion_response_s));
-    if (*data == nullptr)
+    size_t structLen =__deserializeStructBody(buffer,
+                                            rawBufferPtr.get(),
+                                            sizeof(wauthn_authenticator_assertion_response_s));
+    if (structLen == 0) // the serialized struct is nullptr
         return;
     // Deserialize the contents of struct's pointers
-    deserialize(stream, &((*data)->client_data_json));
-    deserialize(stream, &((*data)->authenticator_data));
-    deserialize(stream, &((*data)->signature));
-    deserialize(stream, &((*data)->user_handle));
-    deserialize(stream, &((*data)->attestation_object));
-
-    __checkAlignment(*data);
-}
-
-// For wauthn_rp_entity_s
-void __checkAlignment(const wauthn_rp_entity_s* data) {
-    if (data == nullptr)
-        return;
-    __checkAlignment("wauthn_rp_entity_s->name", data->name);
-    __checkAlignment("wauthn_rp_entity_s->id", data->id);
-}
-void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_rp_entity_s* data) {
+    this->m_clientDataJson.Deserialize(buffer);
+    this->m_authenticatorData.Deserialize(buffer);
+    this->m_signature.Deserialize(buffer);
+    this->m_userHandle.Deserialize(buffer);
+    this->m_attestationObject.Deserialize(buffer);
+    // reset pointer
+    this->m_ptr = std::move(rawBufferPtr);
+    this->m_ptr->client_data_json = this->m_clientDataJson.getRawPtr();
+    this->m_ptr->authenticator_data = this->m_authenticatorData.getRawPtr();
+    this->m_ptr->signature = this->m_signature.getRawPtr();
+    this->m_ptr->user_handle = this->m_userHandle.getRawPtr();
+    this->m_ptr->attestation_object = this->m_attestationObject.getRawPtr();
+}
+
+void RpEntitySerializer::Serialize(IStream &stream) const {
     // Serialize struct itself
-    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_rp_entity_s));
-    if (data == nullptr)
+    __serializeStructBody(stream, m_ptr, sizeof(wauthn_rp_entity_s));
+    if (m_ptr == nullptr)
         return;
     // Serialize the contents of struct's pointers
-    serialize(stream, data->name);
-    serialize(stream, data->id);
+    __serialize(stream, m_ptr->name);
+    __serialize(stream, m_ptr->id);
 }
-void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_rp_entity_s** data) {
+void RpEntityDeserializer::Deserialize(MessageBuffer &buffer) {
+    auto rawBufferPtr = std::make_unique<wauthn_rp_entity_s>();
     // Deserialize struct itself
-    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_rp_entity_s));
-    if (*data == nullptr)
+    size_t structLen = __deserializeStructBody(buffer, rawBufferPtr.get(),
+                                               sizeof(wauthn_rp_entity_s));
+    if (structLen == 0) // the serialized struct is nullptr
         return;
     // Deserialize the contents of struct's pointers
-    deserialize(stream, &((*data)->name));
-    deserialize(stream, &((*data)->id));
-
-    __checkAlignment(*data);
+    __deserializeWithNewArray(buffer, this->m_name);
+    __deserializeWithNewArray(buffer, this->m_id);
+    // reset pointer
+    this->m_ptr = std::move(rawBufferPtr);
+    this->m_ptr->name = this->m_name.get();
+    this->m_ptr->id = this->m_id.get();
 }
 
-// For wauthn_user_entity_s
-void __checkAlignment(const wauthn_user_entity_s* data) {
-    if (data == nullptr)
-        return;
-    __checkAlignment("wauthn_user_entity_s->name", data->name);
-    __checkAlignment("wauthn_user_entity_s->id", data->id);
-    __checkAlignment("wauthn_user_entity_s->display_name", data->display_name);
-}
-void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_user_entity_s* data) {
+void UserEntitySerializer::Serialize(IStream &stream) const {
     // Serialize struct itself
-    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_user_entity_s));
-    if (data == nullptr)
+    __serializeStructBody(stream, m_ptr, sizeof(wauthn_user_entity_s));
+    if (m_ptr == nullptr)
         return;
     // Serialize the contents of struct's pointers
-    serialize(stream, data->name);
-    serialize(stream, data->id);
-    serialize(stream, data->display_name);
+    __serialize(stream, m_ptr->name);
+    ConstBufferSerializer(m_ptr->id).Serialize(stream);
+    __serialize(stream, m_ptr->display_name);
 }
-void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_user_entity_s** data) {
+void UserEntityDeserializer::Deserialize(MessageBuffer &buffer) {
+    auto rawBufferPtr = std::make_unique<wauthn_user_entity_s>();
     // Deserialize struct itself
-    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_user_entity_s));
-    if (*data == nullptr)
+    size_t structLen = __deserializeStructBody(buffer, rawBufferPtr.get(),
+                                               sizeof(wauthn_user_entity_s));
+    if (structLen == 0) // the serialized struct is nullptr
         return;
     // Deserialize the contents of struct's pointers
-    deserialize(stream, &((*data)->name));
-    deserialize(stream, &((*data)->id));
-    deserialize(stream, &((*data)->display_name));
-
-    __checkAlignment(*data);
+    __deserializeWithNewArray(buffer, this->m_name);
+    this->m_id.Deserialize(buffer);
+    __deserializeWithNewArray(buffer, this->m_displayName);
+    // reset pointer
+    this->m_ptr = std::move(rawBufferPtr);
+    this->m_ptr->name = this->m_name.get();
+    this->m_ptr->id = this->m_id.getRawPtr();
+    this->m_ptr->display_name = this->m_displayName.get();
 }
 
-// For wauthn_pubkey_cred_param_s
 void __checkValidity(const wauthn_pubkey_cred_type_e type) {
     if (type != WAUTHN_PUBKEY_CRED_TYPE_PUBLIC_KEY)
         ThrowMsg(SerializationException::InvalidStreamData,
@@ -391,20 +333,23 @@ void __checkValidity(const wauthn_pubkey_cred_param_s* data) {
     __checkValidity(data->type);
     __checkValidity(data->alg);
 }
-void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_pubkey_cred_param_s* data) {
-    __checkValidity(data);
+void PubkeyCredParamSerializer::Serialize(IStream &stream) const {
+    __checkValidity(m_ptr);
     // Serialize struct itself
-    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_pubkey_cred_param_s));
-    // No pointers in struct
+    __serializeStructBody(stream, m_ptr, sizeof(wauthn_pubkey_cred_param_s));
 }
-void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_pubkey_cred_param_s** data) {
+void PubkeyCredParamDeserializer::Deserialize(MessageBuffer &buffer) {
+    auto rawBufferPtr = std::make_unique<wauthn_pubkey_cred_param_s>();
     // Deserialize struct itself
-    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_pubkey_cred_param_s));
-    __checkValidity(*data);
-    // No pointers in struct
+    size_t structLen = __deserializeStructBody(buffer, rawBufferPtr.get(),
+                                               sizeof(wauthn_pubkey_cred_param_s));
+    if (structLen == 0) // the serialized struct is nullptr
+        return;
+    __checkValidity(rawBufferPtr.get());
+    // reset pointer
+    this->m_ptr = std::move(rawBufferPtr);
 }
 
-// For wauthn_pubkey_cred_params_s
 void __checkValidity(const wauthn_pubkey_cred_params_s* data) {
     if (data == nullptr)
         return;
@@ -413,180 +358,153 @@ void __checkValidity(const wauthn_pubkey_cred_params_s* data) {
         ThrowMsg(SerializationException::InvalidStreamData,
             "Inconsistent pointer & length: pointer=" << data->params << ", size=" << data->size);
 }
-void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_pubkey_cred_params_s* data) {
-    __checkValidity(data);
+void PubkeyCredParamsSerializer::Serialize(IStream &stream) const {
+    __checkValidity(m_ptr);
     // Serialize struct itself
-    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_pubkey_cred_params_s));
-    if (data == nullptr)
+    __serializeStructBody(stream, m_ptr, sizeof(wauthn_pubkey_cred_params_s));
+    if (m_ptr == nullptr)
         return;
-    // Serialize array
-    __serializeArray(stream, data->size, reinterpret_cast<const unsigned char *>(data->params),
-                        sizeof(wauthn_pubkey_cred_params_s));
+    // Serialize the contents of struct's pointers
+    __serializeBinaryArray(stream, m_ptr->size, m_ptr->params, sizeof(wauthn_pubkey_cred_param_s));
 }
-void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_pubkey_cred_params_s** data) {
+void PubkeyCredParamsDeserializer::Deserialize(MessageBuffer &buffer) {
+    auto rawBufferPtr = std::make_unique<wauthn_pubkey_cred_params_s>();
     // Deserialize struct itself
-    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_pubkey_cred_params_s));
-    if (*data == nullptr)
+    size_t structLen = __deserializeStructBody(buffer, rawBufferPtr.get(),
+                                               sizeof(wauthn_pubkey_cred_params_s));
+    if (structLen == 0) // the serialized struct is nullptr
         return;
-    if ((*data)->size == 0) {
-        (*data)->params = nullptr;
-    }
-    __checkValidity(*data);
-    // Deserialize array
-    __deserializeArray(stream, (*data)->size, reinterpret_cast<unsigned char **>(&((*data)->params)),
-                        sizeof(wauthn_pubkey_cred_params_s));
-    __checkAlignment("wauthn_pubkey_cred_params_s->params", (*data)->params);
+    __checkValidity(rawBufferPtr.get());
+    // Deserialize the contents of struct's pointers
+    __deserializeBinaryArray(buffer, rawBufferPtr->size, this->m_params,
+                             sizeof(wauthn_pubkey_cred_param_s));
+    // reset pointer
+    this->m_ptr = std::move(rawBufferPtr);
+    this->m_ptr->params = this->m_params.get();
 }
 
-// For wauthn_pubkey_cred_descriptor_s
 void __checkValidity(const wauthn_pubkey_cred_descriptor_s* data) {
     if (data == nullptr)
         return;
     __checkValidity(data->type);
 }
-void __serializePointerContents(IStream& stream, const wauthn_pubkey_cred_descriptor_s* data) {
-    WAuthnCtypeSerializer::serialize(stream, data->id);
-}
-void __deserializePointerContents(IStream& stream, wauthn_pubkey_cred_descriptor_s* data) {
-    WAuthnCtypeSerializer::deserialize(stream, &(data->id));
-}
-void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_pubkey_cred_descriptor_s* data) {
-    __checkValidity(data);
+void PubkeyCredDescriptorSerializer::Serialize(IStream &stream) const {
+    __checkValidity(m_ptr);
     // Serialize struct itself
-    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_pubkey_cred_descriptor_s));
-    if (data == nullptr)
+    __serializeStructBody(stream, m_ptr, sizeof(wauthn_pubkey_cred_descriptor_s));
+    if (m_ptr == nullptr)
         return;
     // Serialize the contents of struct's pointers
-    __serializePointerContents(stream, data);
+    ConstBufferSerializer(m_ptr->id).Serialize(stream);
 }
-void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_pubkey_cred_descriptor_s** data) {
+void PubkeyCredDescriptorDeserializer::Deserialize(MessageBuffer &buffer) {
+    auto rawBufferPtr = std::make_unique<wauthn_pubkey_cred_descriptor_s>();
     // Deserialize struct itself
-    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_pubkey_cred_descriptor_s));
-    if (*data == nullptr)
+    size_t structLen = __deserializeStructBody(buffer, rawBufferPtr.get(),
+                                               sizeof(wauthn_pubkey_cred_descriptor_s));
+    if (structLen == 0) // the serialized struct is nullptr
         return;
-    __checkValidity(*data);
+    __checkValidity(rawBufferPtr.get());
     // Deserialize the contents of struct's pointers
-    __deserializePointerContents(stream, *data);
-    __checkAlignment("wauthn_pubkey_cred_descriptor_s->id", (*data)->id);
+    this->m_id.Deserialize(buffer);
+    // reset pointer
+    this->m_ptr = std::move(rawBufferPtr);
+    this->m_ptr->id = this->m_id.getRawPtr();
 }
 
-// For wauthn_pubkey_cred_descriptors_s
 void __checkValidity(const wauthn_pubkey_cred_descriptors_s* data) {
     if (data == nullptr)
         return;
     __checkArraySize(data->size);
     if (data->descriptors == nullptr && data->size != 0)
         ThrowMsg(SerializationException::InvalidStreamData,
-            "Inconsistent pointer & length: pointer=" << data->descriptors << ", size=" << data->size);
+            "Inconsistent pointer & length: pointer=" << data->descriptors << ", size="
+            << data->size);
 }
-void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_pubkey_cred_descriptors_s* data) {
-    __checkValidity(data);
+void PubkeyCredDescriptorsSerializer::Serialize(IStream &stream) const {
+    __checkValidity(m_ptr);
     // Serialize struct itself
-    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_pubkey_cred_descriptors_s));
-    if (data == nullptr)
+    __serializeStructBody(stream, m_ptr, sizeof(wauthn_pubkey_cred_descriptors_s));
+    if (m_ptr == nullptr)
         return;
-    // Serialize array
-    __serializeArray(stream, data->size, reinterpret_cast<const unsigned char *>(data->descriptors),
-                        sizeof(wauthn_pubkey_cred_descriptor_s));
-    // Serialize the contents of pointers in struct array
-    for(size_t i=0; i < data->size; i++ )
-        __serializePointerContents(stream, data->descriptors + i);
+    // Serialize the contents of struct's pointers
+    __serializeArray<PubkeyCredDescriptorSerializer, wauthn_pubkey_cred_descriptor_s>(
+        stream, m_ptr->size, m_ptr->descriptors);
 }
-void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_pubkey_cred_descriptors_s** data) {
+void PubkeyCredDescriptorsDeserializer::Deserialize(MessageBuffer &buffer) {
+    auto rawBufferPtr = std::make_unique<wauthn_pubkey_cred_descriptors_s>();
     // Deserialize struct itself
-    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_pubkey_cred_descriptors_s));
-    if (*data == nullptr)
+    size_t structLen = __deserializeStructBody(buffer, rawBufferPtr.get(),
+                                               sizeof(wauthn_pubkey_cred_descriptors_s));
+    if (structLen == 0) // the serialized struct is nullptr
         return;
-    __checkValidity(*data);
-    if ((*data)->size == 0) {
-        (*data)->descriptors = nullptr;
-        return;
-    }
-    // Deserialize array
-    __deserializeArray(stream, (*data)->size, reinterpret_cast<unsigned char **>(&((*data)->descriptors)),
-                        sizeof(wauthn_pubkey_cred_descriptor_s));
-    // Deserialize the contents of pointers in struct array
-    for(size_t i=0; i < (*data)->size; i++ )
-        __deserializePointerContents(stream, (*data)->descriptors + i);
-    __checkAlignment("wauthn_pubkey_cred_descriptors_s->descriptors", (*data)->descriptors);
-}
-
-// For wauthn_authentication_ext_s
-void __checkAlignment(const wauthn_authentication_ext_s* data) {
-    __checkAlignment("wauthn_authentication_ext_s->extension_id", data->extension_id);
-    __checkAlignment("wauthn_authentication_ext_s->extension_value", data->extension_value);
-}
-void __serializePointerContents(IStream& stream, const wauthn_authentication_ext_s* data) {
-    WAuthnCtypeSerializer::serialize(stream, data->extension_id);
-    WAuthnCtypeSerializer::serialize(stream, data->extension_value);
+    __checkValidity(rawBufferPtr.get());
+    // Deserialize the contents of struct's pointers
+    __deserializeArray(buffer, rawBufferPtr->size, this->m_descriptors, this->m_deserializers);
+    // reset pointer
+    this->m_ptr = std::move(rawBufferPtr);
+    this->m_ptr->descriptors = this->m_descriptors.get();
 }
-void __deserializePointerContents(IStream& stream, wauthn_authentication_ext_s* data) {
-    WAuthnCtypeSerializer::deserialize(stream, &(data->extension_id));
-    WAuthnCtypeSerializer::deserialize(stream, &(data->extension_value));
 
-}
-void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_authentication_ext_s* data) {
+void AuthenticationExtSerializer::Serialize(IStream &stream) const {
     // Serialize struct itself
-    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_authentication_ext_s));
-    if (data == nullptr)
+    __serializeStructBody(stream, m_ptr, sizeof(wauthn_authentication_ext_s));
+    if (m_ptr == nullptr)
         return;
     // Serialize the contents of struct's pointers
-    __serializePointerContents(stream, data);
+    ConstBufferSerializer(m_ptr->extension_id).Serialize(stream);
+    ConstBufferSerializer(m_ptr->extension_value).Serialize(stream);
 }
-void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_authentication_ext_s** data) {
+void AuthenticationExtDeserializer::Deserialize(MessageBuffer &buffer) {
+    auto rawBufferPtr = std::make_unique<wauthn_authentication_ext_s>();
     // Deserialize struct itself
-    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_authentication_ext_s));
-    if (*data == nullptr)
+    size_t structLen = __deserializeStructBody(buffer, rawBufferPtr.get(),
+                                               sizeof(wauthn_authentication_ext_s));
+    if (structLen == 0) // the serialized struct is nullptr
         return;
     // Deserialize the contents of struct's pointers
-    __deserializePointerContents(stream, *data);
-
-    __checkAlignment(*data);
+    this->m_extensionId.Deserialize(buffer);
+    this->m_extensionValue.Deserialize(buffer);
+    // reset pointer
+    this->m_ptr = std::move(rawBufferPtr);
+    this->m_ptr->extension_id = this->m_extensionId.getRawPtr();
+    this->m_ptr->extension_value = this->m_extensionValue.getRawPtr();
 }
 
-// For wauthn_authentication_exts_s
 void __checkValidity(const wauthn_authentication_exts_s* data) {
     if (data == nullptr)
         return;
     __checkArraySize(data->size);
     if (data->extensions == nullptr && data->size != 0)
         ThrowMsg(SerializationException::InvalidStreamData,
-            "Inconsistent pointer & length: pointer=" << data->extensions << ", size=" << data->size);
+            "Inconsistent pointer & length: pointer=" << data->extensions << ", size="
+            << data->size);
 }
-void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_authentication_exts_s* data) {
-    __checkValidity(data);
+void AuthenticationExtsSerializer::Serialize(IStream &stream) const {
+    __checkValidity(m_ptr);
     // Serialize struct itself
-    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_authentication_exts_s));
-    if (data == nullptr)
+    __serializeStructBody(stream, m_ptr, sizeof(wauthn_authentication_exts_s));
+    if (m_ptr == nullptr)
         return;
-    // Serialize array
-    __serializeArray(stream, data->size, reinterpret_cast<const unsigned char *>(data->extensions),
-                        sizeof(wauthn_authentication_ext_s));
-    // Serialize the contents of pointers in struct array
-    for(size_t i=0; i < data->size; i++ )
-        __serializePointerContents(stream, data->extensions + i);
+    // Serialize the contents of struct's pointers
+    __serializeArray<AuthenticationExtSerializer, wauthn_authentication_ext_s>(stream, m_ptr->size,
+                                                                               m_ptr->extensions);
 }
-void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_authentication_exts_s** data) {
+void AuthenticationExtsDeserializer::Deserialize(MessageBuffer &buffer) {
+    auto rawBufferPtr = std::make_unique<wauthn_authentication_exts_s>();
     // Deserialize struct itself
-    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_authentication_exts_s));
-    if (*data == nullptr)
-        return;
-    __checkValidity(*data);
-    if ((*data)->size == 0) {
-        (*data)->extensions = nullptr;
+    size_t structLen = __deserializeStructBody(buffer, rawBufferPtr.get(),
+                                               sizeof(wauthn_authentication_exts_s));
+    if (structLen == 0) // the serialized struct is nullptr
         return;
-    }
-    // Deserialize array
-    __deserializeArray(stream, (*data)->size, reinterpret_cast<unsigned char **>(&((*data)->extensions)),
-                        sizeof(wauthn_authentication_ext_s));
-    // Deserialize the contents of pointers in struct array
-    for(size_t i=0; i < (*data)->size; i++ )
-        __deserializePointerContents(stream, (*data)->extensions + i);
-
-    __checkAlignment("wauthn_authentication_exts_s->extensions", (*data)->extensions);
+    __checkValidity(rawBufferPtr.get());
+    // Deserialize the contents of struct's pointers
+    __deserializeArray(buffer, rawBufferPtr->size, this->m_extensions, this->m_deserializers);
+    // reset pointer
+    this->m_ptr = std::move(rawBufferPtr);
+    this->m_ptr->extensions = this->m_extensions.get();
 }
 
-// For wauthn_authenticator_sel_cri_s
 void __checkValidity(const wauthn_authenticator_attachment_e attachment) {
     switch(attachment) {
         case WAUTHN_AUTHENTICATOR_ATTACHMENT_NONE:
@@ -619,7 +537,8 @@ void __checkValidity(const wauthn_user_verification_requirement_e user_verificat
             return;
         default:
             ThrowMsg(SerializationException::InvalidStreamData,
-                "Invalid wauthn_user_verification_requirement_e: user_verification=" << user_verification);
+                "Invalid wauthn_user_verification_requirement_e: user_verification="
+                << user_verification);
     }
 }
 void __checkValidity(const wauthn_authenticator_sel_cri_s* data) {
@@ -629,20 +548,23 @@ void __checkValidity(const wauthn_authenticator_sel_cri_s* data) {
     __checkValidity(data->resident_key);
     __checkValidity(data->user_verification);
 }
-void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_authenticator_sel_cri_s* data) {
-    __checkValidity(data);
+void AuthenticatorSelCriSerializer::Serialize(IStream &stream) const {
+    __checkValidity(m_ptr);
     // Serialize struct itself
-    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_authenticator_sel_cri_s));
-    // No pointers in struct
+    __serializeStructBody(stream, m_ptr, sizeof(wauthn_authenticator_sel_cri_s));
 }
-void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_authenticator_sel_cri_s** data) {
+void AuthenticatorSelCriDeserializer::Deserialize(MessageBuffer &buffer) {
+    auto rawBufferPtr = std::make_unique<wauthn_authenticator_sel_cri_s>();
     // Deserialize struct itself
-    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_authenticator_sel_cri_s));
-    __checkValidity(*data);
-    // No pointers in struct
+    size_t structLen = __deserializeStructBody(buffer, rawBufferPtr.get(),
+                                               sizeof(wauthn_authenticator_sel_cri_s));
+    if (structLen == 0) // the serialized struct is nullptr
+        return;
+    __checkValidity(rawBufferPtr.get());
+    // reset pointer
+    this->m_ptr = std::move(rawBufferPtr);
 }
 
-// For wauthn_pubkey_cred_hints_s
 void __checkValidity(const wauthn_pubkey_cred_hint_e *hint) {
     if (hint == nullptr)
         return;
@@ -665,75 +587,73 @@ void __checkValidity(const wauthn_pubkey_cred_hints_s* data) {
         ThrowMsg(SerializationException::InvalidStreamData,
             "Inconsistent pointer & length: pointer=" << data->hints << ", size=" << data->size);
 }
-void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_pubkey_cred_hints_s* data) {
-    __checkValidity(data);
+void PubkeyCredHintsSerializer::Serialize(IStream &stream) const {
+    __checkValidity(m_ptr);
     // Serialize struct itself
-    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_pubkey_cred_hints_s));
-    if (data == nullptr)
+    __serializeStructBody(stream, m_ptr, sizeof(wauthn_pubkey_cred_hints_s));
+    if (m_ptr == nullptr)
         return;
-    // Serialize array
-    __serializeArray(stream, data->size, reinterpret_cast<const unsigned char *>(data->hints),
-                        sizeof(wauthn_pubkey_cred_hint_e));
+    // Serialize the contents of struct's pointers
+    __serializeBinaryArray(stream, m_ptr->size, m_ptr->hints, sizeof(wauthn_pubkey_cred_hint_e));
 }
-void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_pubkey_cred_hints_s** data) {
+void PubkeyCredHintsDeserializer::Deserialize(MessageBuffer &buffer) {
+    auto rawBufferPtr = std::make_unique<wauthn_pubkey_cred_hints_s>();
     // Deserialize struct itself
-    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_pubkey_cred_hints_s));
-    if (*data == nullptr)
-        return;
-    if ((*data)->size == 0) {
-        (*data)->hints = nullptr;
+    size_t structLen = __deserializeStructBody(buffer, rawBufferPtr.get(),
+                                               sizeof(wauthn_pubkey_cred_hints_s));
+    if (structLen == 0) // the serialized struct is nullptr
         return;
-    }
-    __checkValidity(*data);
-    // Deserialize array
-    __deserializeArray(stream, (*data)->size, reinterpret_cast<unsigned char **>(&((*data)->hints)),
-                        sizeof(wauthn_pubkey_cred_hint_e));
-
-    __checkAlignment("wauthn_pubkey_cred_hints_s->hints", (*data)->hints);
-}
-
-// For wauthn_hybrid_linked_data_s
-void __checkAlignment(const wauthn_hybrid_linked_data_s* data) {
-    __checkAlignment("wauthn_hybrid_linked_data_s->contact_id", data->contact_id);
-    __checkAlignment("wauthn_hybrid_linked_data_s->link_id", data->link_id);
-    __checkAlignment("wauthn_hybrid_linked_data_s->link_secret", data->link_secret);
-    __checkAlignment("wauthn_hybrid_linked_data_s->authenticator_pubkey", data->authenticator_pubkey);
-    __checkAlignment("wauthn_hybrid_linked_data_s->authenticator_name", data->authenticator_name);
-    __checkAlignment("wauthn_hybrid_linked_data_s->signature", data->signature);
-    __checkAlignment("wauthn_hybrid_linked_data_s->tunnel_server_domain", data->tunnel_server_domain);
-    __checkAlignment("wauthn_hybrid_linked_data_s->identity_key", data->identity_key);
-}
-void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_hybrid_linked_data_s* data) {
+    __checkValidity(rawBufferPtr.get());
+    // Deserialize the contents of struct's pointers
+    __deserializeBinaryArray(buffer, rawBufferPtr->size, this->m_hints,
+                             sizeof(wauthn_pubkey_cred_hint_e));
+    // reset pointer
+    this->m_ptr = std::move(rawBufferPtr);
+    this->m_ptr->hints = this->m_hints.get();
+}
+
+void HybridLinkedDataSerializer::Serialize(IStream &stream) const {
     // Serialize struct itself
-    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_hybrid_linked_data_s));
-    if (data == nullptr)
+    __serializeStructBody(stream, m_ptr, sizeof(wauthn_hybrid_linked_data_s));
+    if (m_ptr == nullptr)
         return;
     // Serialize the contents of struct's pointers
-    serialize(stream, data->contact_id);
-    serialize(stream, data->link_id);
-    serialize(stream, data->link_secret);
-    serialize(stream, data->authenticator_pubkey);
-    serialize(stream, data->authenticator_name);
-    serialize(stream, data->signature);
-    serialize(stream, data->tunnel_server_domain);
-    serialize(stream, data->identity_key);
-}
-void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_hybrid_linked_data_s** data) {
+    ConstBufferSerializer(m_ptr->contact_id).Serialize(stream);
+    ConstBufferSerializer(m_ptr->link_id).Serialize(stream);
+    ConstBufferSerializer(m_ptr->link_secret).Serialize(stream);
+    ConstBufferSerializer(m_ptr->authenticator_pubkey).Serialize(stream);
+    ConstBufferSerializer(m_ptr->authenticator_name).Serialize(stream);
+    ConstBufferSerializer(m_ptr->signature).Serialize(stream);
+    ConstBufferSerializer(m_ptr->tunnel_server_domain).Serialize(stream);
+    ConstBufferSerializer(m_ptr->identity_key).Serialize(stream);
+}
+void HybridLinkedDataDeserializer::Deserialize(MessageBuffer &buffer) {
+    auto rawBufferPtr = std::make_unique<wauthn_hybrid_linked_data_s>();
     // Deserialize struct itself
-    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_hybrid_linked_data_s));
-    if (*data == nullptr)
+    size_t structLen = __deserializeStructBody(buffer, rawBufferPtr.get(),
+                                               sizeof(wauthn_hybrid_linked_data_s));
+    if (structLen == 0) // the serialized struct is nullptr
         return;
     // Deserialize the contents of struct's pointers
-    deserialize(stream, &((*data)->contact_id));
-    deserialize(stream, &((*data)->link_id));
-    deserialize(stream, &((*data)->link_secret));
-    deserialize(stream, &((*data)->authenticator_pubkey));
-    deserialize(stream, &((*data)->authenticator_name));
-    deserialize(stream, &((*data)->signature));
-    deserialize(stream, &((*data)->tunnel_server_domain));
-    deserialize(stream, &((*data)->identity_key));
-
-    __checkAlignment(*data);
+    this->m_contactId.Deserialize(buffer);
+    this->m_linkId.Deserialize(buffer);
+    this->m_linkSecret.Deserialize(buffer);
+    this->m_authenticatorPubkey.Deserialize(buffer);
+    this->m_authenticatorName.Deserialize(buffer);
+    this->m_signature.Deserialize(buffer);
+    this->m_tunnelServerDomain.Deserialize(buffer);
+    this->m_identityKey.Deserialize(buffer);
+
+    // reset pointer
+    this->m_ptr = std::move(rawBufferPtr);
+    this->m_ptr->contact_id = this->m_contactId.getRawPtr();
+    this->m_ptr->link_id = this->m_linkId.getRawPtr();
+    this->m_ptr->link_secret = this->m_linkSecret.getRawPtr();
+    this->m_ptr->authenticator_pubkey = this->m_authenticatorPubkey.getRawPtr();
+    this->m_ptr->authenticator_name = this->m_authenticatorName.getRawPtr();
+    this->m_ptr->signature = this->m_signature.getRawPtr();
+    this->m_ptr->tunnel_server_domain = this->m_tunnelServerDomain.getRawPtr();
+    this->m_ptr->identity_key = this->m_identityKey.getRawPtr();
 }
 
 // For wauthn_attestation_formats_s
@@ -743,59 +663,36 @@ void __checkValidity(const wauthn_attestation_formats_s* data) {
     __checkArraySize(data->size);
     if (data->attestation_formats == nullptr && data->size != 0)
         ThrowMsg(SerializationException::InvalidStreamData,
-            "Inconsistent pointer & length: pointer=" << data->attestation_formats << ", size=" << data->size);
-}
-void __serializePointerContents(IStream& stream, const wauthn_const_buffer_s* data) {
-    WAuthnCtypeSerializer::serialize(stream, data);
+            "Inconsistent pointer & length: pointer=" << data->attestation_formats << ", size="
+            << data->size);
 }
-void __deserializePointerContents(IStream& stream, wauthn_const_buffer_s* data) {
-    WAuthnCtypeSerializer::deserialize(stream, &data);
-}
-void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_attestation_formats_s* data) {
-    __checkValidity(data);
+void AttestationFormatsSerializer::Serialize(IStream &stream) const {
+    __checkValidity(m_ptr);
     // Serialize struct itself
-    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_attestation_formats_s));
-    if (data == nullptr)
+    __serializeStructBody(stream, m_ptr, sizeof(wauthn_attestation_formats_s));
+    if (m_ptr == nullptr)
         return;
-    // Serialize array
-    __serializeArray(stream, data->size, reinterpret_cast<const unsigned char *>(data->attestation_formats),
-                        sizeof(wauthn_const_buffer_s));
-    // Serialize the contents of pointers in struct array
-    for(size_t i=0; i < data->size; i++ )
-        __serializePointerContents(stream, data->attestation_formats + i);
+    // Serialize the contents of struct's pointers
+    __serializeArray<ConstBufferSerializer, wauthn_const_buffer_s>(stream, m_ptr->size,
+                                                                   m_ptr->attestation_formats);
 }
-void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_attestation_formats_s** data) {
+void AttestationFormatsDeserializer::Deserialize(MessageBuffer &buffer) {
+    auto rawBufferPtr = std::make_unique<wauthn_attestation_formats_s>();
     // Deserialize struct itself
-    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_attestation_formats_s));
-    if (*data == nullptr)
-        return;
-    if ((*data)->size == 0) {
-        (*data)->attestation_formats = nullptr;
+    size_t structLen = __deserializeStructBody(buffer, rawBufferPtr.get(),
+                                               sizeof(wauthn_attestation_formats_s));
+    if (structLen == 0) // the serialized struct is nullptr
         return;
-    }
-    __checkValidity(*data);
-    // Deserialize array
-    __deserializeArray(stream, (*data)->size, reinterpret_cast<unsigned char **>(&((*data)->attestation_formats)),
-                        sizeof(wauthn_const_buffer_s));
-    // Deserialize the contents of pointers in struct array
-    for(size_t i=0; i < (*data)->size; i++ )
-        __deserializePointerContents(stream, (*data)->attestation_formats + i);
-
-    __checkAlignment("wauthn_attestation_formats_s->attestation_formats", (*data)->attestation_formats);
+    __checkValidity(rawBufferPtr.get());
+    // Deserialize the contents of struct's pointers
+    __deserializeArray(buffer, rawBufferPtr->size, this->m_attestationFormats,
+                       this->m_deserializers);
+    // reset pointer
+    this->m_ptr = std::move(rawBufferPtr);
+    this->m_ptr->attestation_formats = this->m_attestationFormats.get();
 }
 
 // For wauthn_pubkey_cred_creation_options_s
-void __checkAlignment(const wauthn_pubkey_cred_creation_options_s* data) {
-    __checkAlignment("wauthn_pubkey_cred_creation_options_s->rp", data->rp);
-    __checkAlignment("wauthn_pubkey_cred_creation_options_s->user", data->user);
-    __checkAlignment("wauthn_pubkey_cred_creation_options_s->pubkey_cred_params", data->pubkey_cred_params);
-    __checkAlignment("wauthn_pubkey_cred_creation_options_s->exclude_credentials", data->exclude_credentials);
-    __checkAlignment("wauthn_pubkey_cred_creation_options_s->authenticator_selection", data->authenticator_selection);
-    __checkAlignment("wauthn_pubkey_cred_creation_options_s->hints", data->hints);
-    __checkAlignment("wauthn_pubkey_cred_creation_options_s->attestation_formats", data->attestation_formats);
-    __checkAlignment("wauthn_pubkey_cred_creation_options_s->extensions", data->extensions);
-    __checkAlignment("wauthn_pubkey_cred_creation_options_s->linked_device", data->linked_device);
-}
 void __checkValidity(wauthn_attestation_pref_e attestation) {
     switch(attestation) {
         case WAUTHN_ATTESTATION_PREF_NONE:
@@ -813,173 +710,188 @@ void __checkValidity(const wauthn_pubkey_cred_creation_options_s* data) {
         return;
     __checkValidity(data->attestation);
 }
-void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_pubkey_cred_creation_options_s* data) {
-    __checkValidity(data);
+void PubKeyCredCreationOptionsSerializer::Serialize(IStream &stream) const {
+    __checkValidity(m_ptr);
     // Serialize struct itself
-    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_pubkey_cred_creation_options_s));
-    if (data == nullptr)
+    __serializeStructBody(stream, m_ptr, sizeof(wauthn_pubkey_cred_creation_options_s));
+    if (m_ptr == nullptr)
         return;
     // Serialize the contents of struct's pointers
-    serialize(stream, data->rp);
-    serialize(stream, data->user);
-    serialize(stream, data->pubkey_cred_params);
-    serialize(stream, data->exclude_credentials);
-    serialize(stream, data->authenticator_selection);
-    serialize(stream, data->hints);
-    serialize(stream, data->attestation_formats);
-    serialize(stream, data->extensions);
-    serialize(stream, data->linked_device);
-}
-void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_pubkey_cred_creation_options_s** data) {
+    RpEntitySerializer(m_ptr->rp).Serialize(stream);
+    UserEntitySerializer(m_ptr->user).Serialize(stream);
+    PubkeyCredParamsSerializer(m_ptr->pubkey_cred_params).Serialize(stream);
+    PubkeyCredDescriptorsSerializer(m_ptr->exclude_credentials).Serialize(stream);
+    AuthenticatorSelCriSerializer(m_ptr->authenticator_selection).Serialize(stream);
+    PubkeyCredHintsSerializer(m_ptr->hints).Serialize(stream);
+    AttestationFormatsSerializer(m_ptr->attestation_formats).Serialize(stream);
+    AuthenticationExtsSerializer(m_ptr->extensions).Serialize(stream);
+    HybridLinkedDataSerializer(m_ptr->linked_device).Serialize(stream);
+}
+void PubKeyCredCreationOptionsDeserializer::Deserialize(MessageBuffer &buffer) {
+    auto rawBufferPtr = std::make_unique<wauthn_pubkey_cred_creation_options_s>();
     // Deserialize struct itself
-    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_pubkey_cred_creation_options_s));
-    if (*data == nullptr)
+    size_t structLen = __deserializeStructBody(buffer, rawBufferPtr.get(),
+                                               sizeof(wauthn_pubkey_cred_creation_options_s));
+    if (structLen == 0) // the serialized struct is nullptr
         return;
-    __checkValidity(*data);
+    __checkValidity(rawBufferPtr.get());
     // Deserialize the contents of struct's pointers
-    deserialize(stream, &((*data)->rp));
-    deserialize(stream, &((*data)->user));
-    deserialize(stream, &((*data)->pubkey_cred_params));
-    deserialize(stream, &((*data)->exclude_credentials));
-    deserialize(stream, &((*data)->authenticator_selection));
-    deserialize(stream, &((*data)->hints));
-    deserialize(stream, &((*data)->attestation_formats));
-    deserialize(stream, &((*data)->extensions));
-    deserialize(stream, &((*data)->linked_device));
-
-    __checkAlignment(*data);
+    this->m_rp.Deserialize(buffer);
+    this->m_user.Deserialize(buffer);
+    this->m_pubkeyCredParams.Deserialize(buffer);
+    this->m_excludeCredentials.Deserialize(buffer);
+    this->m_authenticatorSelection.Deserialize(buffer);
+    this->m_hints.Deserialize(buffer);
+    this->m_attestationFormats.Deserialize(buffer);
+    this->m_extensions.Deserialize(buffer);
+    this->m_linkedDevice.Deserialize(buffer);
+
+    // reset pointer
+    this->m_ptr = std::move(rawBufferPtr);
+    this->m_ptr->rp = this->m_rp.getRawPtr();
+    this->m_ptr->user = this->m_user.getRawPtr();
+    this->m_ptr->pubkey_cred_params = this->m_pubkeyCredParams.getRawPtr();
+    this->m_ptr->exclude_credentials = this->m_excludeCredentials.getRawPtr();
+    this->m_ptr->authenticator_selection = this->m_authenticatorSelection.getRawPtr();
+    this->m_ptr->hints = this->m_hints.getRawPtr();
+    this->m_ptr->attestation_formats = this->m_attestationFormats.getRawPtr();
+    this->m_ptr->extensions = this->m_extensions.getRawPtr();
+    this->m_ptr->linked_device = this->m_linkedDevice.getRawPtr();
 }
 
 // For wauthn_pubkey_cred_request_options_s
-void __checkAlignment(const wauthn_pubkey_cred_request_options_s* data) {
-    __checkAlignment("wauthn_pubkey_cred_request_options_s->rpId", data->rpId);
-    __checkAlignment("wauthn_pubkey_cred_request_options_s->allow_credentials", data->allow_credentials);
-    __checkAlignment("wauthn_pubkey_cred_request_options_s->hints", data->hints);
-    __checkAlignment("wauthn_pubkey_cred_request_options_s->attestation_formats", data->attestation_formats);
-    __checkAlignment("wauthn_pubkey_cred_request_options_s->extensions", data->extensions);
-    __checkAlignment("wauthn_pubkey_cred_request_options_s->linked_device", data->linked_device);
-}
 void __checkValidity(const wauthn_pubkey_cred_request_options_s* data) {
     if (data == nullptr)
         return;
     __checkValidity(data->user_verification);
     __checkValidity(data->attestation);
 }
-void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_pubkey_cred_request_options_s* data) {
-    __checkValidity(data);
+void PubKeyCredRequestOptionsSerializer::Serialize(IStream &stream) const {
+    __checkValidity(m_ptr);
     // Serialize struct itself
-    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_pubkey_cred_request_options_s));
-    if (data == nullptr)
+    __serializeStructBody(stream, m_ptr, sizeof(wauthn_pubkey_cred_request_options_s));
+    if (m_ptr == nullptr)
         return;
     // Serialize the contents of struct's pointers
-    serialize(stream, data->rpId);
-    serialize(stream, data->allow_credentials);
-    serialize(stream, data->hints);
-    serialize(stream, data->attestation_formats);
-    serialize(stream, data->extensions);
-    serialize(stream, data->linked_device);
-}
-void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_pubkey_cred_request_options_s** data) {
+    __serialize(stream, m_ptr->rpId);
+    PubkeyCredDescriptorsSerializer(m_ptr->allow_credentials).Serialize(stream);
+    PubkeyCredHintsSerializer(m_ptr->hints).Serialize(stream);
+    AttestationFormatsSerializer(m_ptr->attestation_formats).Serialize(stream);
+    AuthenticationExtsSerializer(m_ptr->extensions).Serialize(stream);
+    HybridLinkedDataSerializer(m_ptr->linked_device).Serialize(stream);
+}
+void PubKeyCredRequestOptionsDeserializer::Deserialize(MessageBuffer &buffer) {
+    auto rawBufferPtr = std::make_unique<wauthn_pubkey_cred_request_options_s>();
     // Deserialize struct itself
-    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_pubkey_cred_request_options_s));
-    if (*data == nullptr)
+    size_t structLen = __deserializeStructBody(buffer, rawBufferPtr.get(),
+                                               sizeof(wauthn_pubkey_cred_request_options_s));
+    if (structLen == 0) // the serialized struct is nullptr
         return;
-    __checkValidity(*data);
+    __checkValidity(rawBufferPtr.get());
     // Deserialize the contents of struct's pointers
-    deserialize(stream, &((*data)->rpId));
-    deserialize(stream, &((*data)->allow_credentials));
-    deserialize(stream, &((*data)->hints));
-    deserialize(stream, &((*data)->attestation_formats));
-    deserialize(stream, &((*data)->extensions));
-    deserialize(stream, &((*data)->linked_device));
-
-    __checkAlignment(*data);
+    __deserializeWithNewArray(buffer, this->m_rpId);
+    this->m_allowCredentials.Deserialize(buffer);
+    this->m_hints.Deserialize(buffer);
+    this->m_attestationFormats.Deserialize(buffer);
+    this->m_extensions.Deserialize(buffer);
+    this->m_linkedDevice.Deserialize(buffer);
+
+    // reset pointer
+    this->m_ptr = std::move(rawBufferPtr);
+    this->m_ptr->rpId = this->m_rpId.get();
+    this->m_ptr->allow_credentials = this->m_allowCredentials.getRawPtr();
+    this->m_ptr->hints = this->m_hints.getRawPtr();
+    this->m_ptr->attestation_formats = this->m_attestationFormats.getRawPtr();
+    this->m_ptr->extensions = this->m_extensions.getRawPtr();
+    this->m_ptr->linked_device = this->m_linkedDevice.getRawPtr();
 }
 
 // For wauthn_pubkey_credential_attestation_s
-void __checkAlignment(const wauthn_pubkey_credential_attestation_s* data) {
-    __checkAlignment("wauthn_pubkey_credential_attestation_s->id", data->id);
-    __checkAlignment("wauthn_pubkey_credential_attestation_s->rawId", data->rawId);
-    __checkAlignment("wauthn_pubkey_credential_attestation_s->response", data->response);
-    __checkAlignment("wauthn_pubkey_credential_attestation_s->extensions", data->extensions);
-    __checkAlignment("wauthn_pubkey_credential_attestation_s->linked_device", data->linked_device);
-}
 void __checkValidity(const wauthn_pubkey_credential_attestation_s* data) {
     if (data == nullptr)
         return;
     __checkValidity(data->type);
     __checkValidity(data->authenticator_attachment);
 }
-void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_pubkey_credential_attestation_s* data) {
-    __checkValidity(data);
+void PubkeyCredentialAttestationSerializer::Serialize(IStream &stream) const {
+    __checkValidity(m_ptr);
     // Serialize struct itself
-    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_pubkey_credential_attestation_s));
-    if (data == nullptr)
+    __serializeStructBody(stream, m_ptr, sizeof(wauthn_pubkey_credential_attestation_s));
+    if (m_ptr == nullptr)
         return;
     // Serialize the contents of struct's pointers
-    serialize(stream, data->id);
-    serialize(stream, data->rawId);
-    serialize(stream, data->response);
-    serialize(stream, data->extensions);
-    serialize(stream, data->linked_device);
-}
-void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_pubkey_credential_attestation_s** data) {
+    ConstBufferSerializer(m_ptr->id).Serialize(stream);
+    ConstBufferSerializer(m_ptr->rawId).Serialize(stream);
+    AuthenticatorAttestationResponseSerializer(m_ptr->response).Serialize(stream);
+    AuthenticationExtsSerializer(m_ptr->extensions).Serialize(stream);
+    HybridLinkedDataSerializer(m_ptr->linked_device).Serialize(stream);
+}
+void PubkeyCredentialAttestationDeserializer::Deserialize(MessageBuffer &buffer) {
+    auto rawBufferPtr = std::make_unique<wauthn_pubkey_credential_attestation_s>();
     // Deserialize struct itself
-    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_pubkey_credential_attestation_s));
-    if (*data == nullptr)
+    size_t structLen = __deserializeStructBody(buffer, rawBufferPtr.get(),
+                                               sizeof(wauthn_pubkey_credential_attestation_s));
+    if (structLen == 0) // the serialized struct is nullptr
         return;
-    __checkValidity(*data);
+    __checkValidity(rawBufferPtr.get());
     // Deserialize the contents of struct's pointers
-    deserialize(stream, &((*data)->id));
-    deserialize(stream, &((*data)->rawId));
-    deserialize(stream, &((*data)->response));
-    deserialize(stream, &((*data)->extensions));
-    deserialize(stream, &((*data)->linked_device));
+    this->m_id.Deserialize(buffer);
+    this->m_rawId.Deserialize(buffer);
+    this->m_response.Deserialize(buffer);
+    this->m_extensions.Deserialize(buffer);
+    this->m_linkedDevice.Deserialize(buffer);
 
-    __checkAlignment(*data);
+    // reset pointer
+    this->m_ptr = std::move(rawBufferPtr);
+    this->m_ptr->id = this->m_id.getRawPtr();
+    this->m_ptr->rawId = this->m_rawId.getRawPtr();
+    this->m_ptr->response = this->m_response.getRawPtr();
+    this->m_ptr->extensions = this->m_extensions.getRawPtr();
+    this->m_ptr->linked_device = this->m_linkedDevice.getRawPtr();
 }
 
 // For wauthn_pubkey_credential_assertion_s
-void __checkAlignment(const wauthn_pubkey_credential_assertion_s* data) {
-    __checkAlignment("wauthn_pubkey_credential_assertion_s->id", data->id);
-    __checkAlignment("wauthn_pubkey_credential_assertion_s->rawId", data->rawId);
-    __checkAlignment("wauthn_pubkey_credential_assertion_s->response", data->response);
-    __checkAlignment("wauthn_pubkey_credential_assertion_s->extensions", data->extensions);
-    __checkAlignment("wauthn_pubkey_credential_assertion_s->linked_device", data->linked_device);
-}
 void __checkValidity(const wauthn_pubkey_credential_assertion_s* data) {
     if (data == nullptr)
         return;
     __checkValidity(data->type);
     __checkValidity(data->authenticator_attachment);
 }
-void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_pubkey_credential_assertion_s* data) {
-    __checkValidity(data);
+void PubkeyCredentialAssertionSerializer::Serialize(IStream &stream) const {
+    __checkValidity(m_ptr);
     // Serialize struct itself
-    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_pubkey_credential_assertion_s));
-    if (data == nullptr)
+    __serializeStructBody(stream, m_ptr, sizeof(wauthn_pubkey_credential_assertion_s));
+    if (m_ptr == nullptr)
         return;
     // Serialize the contents of struct's pointers
-    serialize(stream, data->id);
-    serialize(stream, data->rawId);
-    serialize(stream, data->response);
-    serialize(stream, data->extensions);
-    serialize(stream, data->linked_device);
-}
-void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_pubkey_credential_assertion_s** data) {
+    ConstBufferSerializer(m_ptr->id).Serialize(stream);
+    ConstBufferSerializer(m_ptr->rawId).Serialize(stream);
+    AuthenticatorAssertionResponseSerializer(m_ptr->response).Serialize(stream);
+    AuthenticationExtsSerializer(m_ptr->extensions).Serialize(stream);
+    HybridLinkedDataSerializer(m_ptr->linked_device).Serialize(stream);
+}
+void PubkeyCredentialAssertionDeserializer::Deserialize(MessageBuffer &buffer) {
+    auto rawBufferPtr = std::make_unique<wauthn_pubkey_credential_assertion_s>();
     // Deserialize struct itself
-    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_pubkey_credential_assertion_s));
-    if (*data == nullptr)
+    size_t structLen = __deserializeStructBody(buffer, rawBufferPtr.get(),
+                                               sizeof(wauthn_pubkey_credential_assertion_s));
+    if (structLen == 0) // the serialized struct is nullptr
         return;
-    __checkValidity(*data);
+    __checkValidity(rawBufferPtr.get());
     // Deserialize the contents of struct's pointers
-    deserialize(stream, &((*data)->id));
-    deserialize(stream, &((*data)->rawId));
-    deserialize(stream, &((*data)->response));
-    deserialize(stream, &((*data)->extensions));
-    deserialize(stream, &((*data)->linked_device));
+    this->m_id.Deserialize(buffer);
+    this->m_rawId.Deserialize(buffer);
+    this->m_response.Deserialize(buffer);
+    this->m_extensions.Deserialize(buffer);
+    this->m_linkedDevice.Deserialize(buffer);
 
-    __checkAlignment(*data);
+    // reset pointer
+    this->m_ptr = std::move(rawBufferPtr);
+    this->m_ptr->id = this->m_id.getRawPtr();
+    this->m_ptr->rawId = this->m_rawId.getRawPtr();
+    this->m_ptr->response = this->m_response.getRawPtr();
+    this->m_ptr->extensions = this->m_extensions.getRawPtr();
+    this->m_ptr->linked_device = this->m_linkedDevice.getRawPtr();
 }
 
 // For wauthn_client_data_s
@@ -997,26 +909,29 @@ void __checkValidity(const wauthn_client_data_s* data) {
         return;
     __checkValidity(data->hash_alg);
 }
-void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_client_data_s* data) {
-    __checkValidity(data);
+void ClientDataSerializer::Serialize(IStream &stream) const {
+    __checkValidity(m_ptr);
     // Serialize struct itself
-    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_client_data_s));
-    if (data == nullptr)
+    __serializeStructBody(stream, m_ptr, sizeof(wauthn_client_data_s));
+    if (m_ptr == nullptr)
         return;
     // Serialize the contents of struct's pointers
-    serialize(stream, data->client_data_json);
+    ConstBufferSerializer(m_ptr->client_data_json).Serialize(stream);
 }
-void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_client_data_s** data) {
+void ClientDataDeserializer::Deserialize(MessageBuffer &buffer) {
+    auto rawBufferPtr = std::make_unique<wauthn_client_data_s>();
     // Deserialize struct itself
-    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_client_data_s));
-    if (*data == nullptr)
+    size_t structLen = __deserializeStructBody(buffer, rawBufferPtr.get(),
+                                               sizeof(wauthn_client_data_s));
+    if (structLen == 0) // the serialized struct is nullptr
         return;
-    __checkValidity(*data);
+    __checkValidity(rawBufferPtr.get());
     // Deserialize the contents of struct's pointers
-    deserialize(stream, &((*data)->client_data_json));
+    this->m_clientDataJson.Deserialize(buffer);
 
-    __checkAlignment("wauthn_client_data_s->client_data_json", (*data)->client_data_json);
+    // reset pointer
+    this->m_ptr = std::move(rawBufferPtr);
+    this->m_ptr->client_data_json = this->m_clientDataJson.getRawPtr();
 }
 
-
-} // namespace WebAuthn
+}    // namespace WA
index ab44d7e0027f0dcfd40259d3cdaec8bf4143909e..a297999789dc861fdc94a737552a0fda2085fc7a 100644 (file)
 #include <exception.h>
 #include <webauthn-types.h>
 
-namespace WA {
-
+#include "message-buffer.h"
 
-// Abstract data stream buffer
-class IStream
-{
-  public:
-    virtual void Read(size_t num, void * bytes) = 0;
-    virtual void Write(size_t num, const void * bytes) = 0;
-    virtual ~IStream(){}
-};
+namespace WA {
 
 // Serializable interface
 class ISerializable
@@ -52,6 +44,14 @@ class ISerializable
     virtual ~ISerializable(){}
 };
 
+// Deserializable interface
+class IDeserializable
+{
+  public:
+    virtual void Deserialize(MessageBuffer &) = 0;
+    virtual ~IDeserializable(){}
+};
+
 template <class Collection>
 class SerializeKeysAsVector
 {
@@ -61,87 +61,396 @@ class SerializeKeysAsVector
     const Collection &get() { return col_; }
 };
 
-
 const size_t MAX_BUFFER_SIZE = 128 * 1024 * 1024; // 128 MB
 const size_t MAX_ARRAY_COUNT = 1024;
 
-// Serialize & Deserialize struct types in webauthn-types.h
-struct WAuthnCtypeSerializer {
-private:
-    static void serializeStructBody(IStream& stream, const void *data, size_t struct_size);
-    static void deserializeStructBody(IStream& stream, void **data, size_t struct_size);
+//##########################################################################################
+// WARNING
+// - The stream of StructSerializer & StructDeserializer must be an instance of MessageBuffer.
+//###########################################################################################
+// For Struct Serializer/Deserializer Template
+template <typename StructType>
+class StructSerializer : public ISerializable {
+public:
+    StructSerializer(const StructType* data) : m_ptr(data) {};
+    virtual ~StructSerializer() = default;
+    const StructType* getRawPtr() { return m_ptr; };
+protected:
+    const StructType* m_ptr;
+};
+
+template <typename StructType>
+class StructDeserializer : public IDeserializable {
+public:
+    StructDeserializer(): m_ptr(nullptr) {}
+    StructDeserializer(StructDeserializer&&) = default;
+    virtual ~StructDeserializer() = default;
+    StructType* getRawPtr() { return m_ptr.get(); };
+protected:
+    std::unique_ptr<StructType> m_ptr;
+};
+
+
+// For wauthn_const_buffer_s
+class ConstBufferSerializer : public StructSerializer<wauthn_const_buffer_s> {
+public:
+    ConstBufferSerializer(const wauthn_const_buffer_s* data) : StructSerializer(data) {};
+    virtual void Serialize(IStream &stream) const override;
+};
+
+class ConstBufferDeserializer : public StructDeserializer<wauthn_const_buffer_s> {
+public:
+    virtual void Deserialize(MessageBuffer &buffer) override;
+protected:
+    std::unique_ptr<unsigned char[]> m_data;
+};
+
+// For wauthn_authenticator_attestation_response_s
+class AuthenticatorAttestationResponseSerializer
+        : public StructSerializer<wauthn_authenticator_attestation_response_s> {
+public:
+    AuthenticatorAttestationResponseSerializer(
+        const wauthn_authenticator_attestation_response_s* data)
+        : StructSerializer(data) {};
+    virtual void Serialize(IStream &stream) const override;
+};
+
+class AuthenticatorAttestationResponseDeserializer
+        : public StructDeserializer<wauthn_authenticator_attestation_response_s> {
+public:
+    virtual void Deserialize(MessageBuffer &buffer) override;
+protected:
+    ConstBufferDeserializer m_clientDataJson;
+    ConstBufferDeserializer m_attestationObject;
+    ConstBufferDeserializer m_authenticatorData;
+    ConstBufferDeserializer m_subjectPublicKey;
+};
+
+// For wauthn_authenticator_assertion_response_s
+class AuthenticatorAssertionResponseSerializer
+        : public StructSerializer<wauthn_authenticator_assertion_response_s> {
+public:
+    AuthenticatorAssertionResponseSerializer(
+        const wauthn_authenticator_assertion_response_s* data)
+        : StructSerializer(data) {};
+    virtual void Serialize(IStream &stream) const override;
+};
+
+class AuthenticatorAssertionResponseDeserializer
+        : public StructDeserializer<wauthn_authenticator_assertion_response_s> {
+public:
+    virtual void Deserialize(MessageBuffer &buffer) override;
+protected:
+    ConstBufferDeserializer m_clientDataJson;
+    ConstBufferDeserializer m_authenticatorData;
+    ConstBufferDeserializer m_signature;
+    ConstBufferDeserializer m_userHandle;
+    ConstBufferDeserializer m_attestationObject;
+};
+
+// For wauthn_rp_entity_s
+class RpEntitySerializer : public StructSerializer<wauthn_rp_entity_s> {
+public:
+    RpEntitySerializer(const wauthn_rp_entity_s* data)
+        : StructSerializer(data) {};
+    virtual void Serialize(IStream &stream) const override;
+};
+
+class RpEntityDeserializer : public StructDeserializer<wauthn_rp_entity_s> {
+public:
+    virtual void Deserialize(MessageBuffer &buffer) override;
+protected:
+    std::unique_ptr<char[]> m_name;
+    std::unique_ptr<char[]> m_id;
+};
+
+// For wauthn_user_entity_s
+class UserEntitySerializer : public StructSerializer<wauthn_user_entity_s> {
+public:
+    UserEntitySerializer(const wauthn_user_entity_s* data)
+        : StructSerializer(data) {};
+    virtual void Serialize(IStream &stream) const override;
+};
+
+class UserEntityDeserializer : public StructDeserializer<wauthn_user_entity_s> {
+public:
+    virtual void Deserialize(MessageBuffer &buffer) override;
+protected:
+    std::unique_ptr<char[]> m_name;
+    ConstBufferDeserializer m_id;
+    std::unique_ptr<char[]> m_displayName;
+};
 
+// For wauthn_pubkey_cred_param_s
+class PubkeyCredParamSerializer : public StructSerializer<wauthn_pubkey_cred_param_s> {
 public:
-    static void serialize(IStream& stream, const unsigned char* data, size_t length);
-    static void deserialize(IStream& stream, const unsigned char** data, size_t* length);
+    PubkeyCredParamSerializer(const wauthn_pubkey_cred_param_s* data)
+        : StructSerializer(data) {};
+    virtual void Serialize(IStream &stream) const override;
+};
 
-    static void serialize(IStream& stream, const char* data);
-    static void deserialize(IStream& stream, const char** data);
+class PubkeyCredParamDeserializer : public StructDeserializer<wauthn_pubkey_cred_param_s> {
+public:
+    virtual void Deserialize(MessageBuffer &buffer) override;
+protected:
+    std::unique_ptr<char[]> m_name;
+    ConstBufferDeserializer m_id;
+    std::unique_ptr<char[]> m_displayName;
+};
 
-    static void serialize(IStream& stream, const wauthn_error_e data);
-    static void deserialize(IStream& stream, wauthn_error_e* data);
+// For wauthn_pubkey_cred_params_s
+class PubkeyCredParamsSerializer : public StructSerializer<wauthn_pubkey_cred_params_s> {
+public:
+    PubkeyCredParamsSerializer(const wauthn_pubkey_cred_params_s* data)
+        : StructSerializer(data) {};
+    virtual void Serialize(IStream &stream) const override;
+};
 
-    static void serialize(IStream& stream, const wauthn_const_buffer_s* data);
-    static void deserialize(IStream& stream, wauthn_const_buffer_s** data);
+class PubkeyCredParamsDeserializer : public StructDeserializer<wauthn_pubkey_cred_params_s> {
+public:
+    virtual void Deserialize(MessageBuffer &buffer) override;
+protected:
+    std::unique_ptr<wauthn_pubkey_cred_param_s[]> m_params;
+};
 
-    static void serialize(IStream& stream, const wauthn_authenticator_attestation_response_s* data);
-    static void deserialize(IStream& stream, wauthn_authenticator_attestation_response_s** data);
+// For wauthn_pubkey_cred_descriptor_s
+class PubkeyCredDescriptorSerializer : public StructSerializer<wauthn_pubkey_cred_descriptor_s> {
+public:
+    PubkeyCredDescriptorSerializer(const wauthn_pubkey_cred_descriptor_s* data)
+        : StructSerializer(data) {};
+    virtual void Serialize(IStream &stream) const override;
+};
 
-    static void serialize(IStream& stream, const wauthn_authenticator_assertion_response_s* data);
-    static void deserialize(IStream& stream, wauthn_authenticator_assertion_response_s** data);
+class PubkeyCredDescriptorDeserializer :
+    public StructDeserializer<wauthn_pubkey_cred_descriptor_s> {
+public:
+    virtual void Deserialize(MessageBuffer &buffer) override;
+protected:
+    ConstBufferDeserializer m_id;
+};
 
-    static void serialize(IStream& stream, const wauthn_rp_entity_s* data);
-    static void deserialize(IStream& stream, wauthn_rp_entity_s** data);
+// For wauthn_pubkey_cred_descriptors_s
+class PubkeyCredDescriptorsSerializer : public StructSerializer<wauthn_pubkey_cred_descriptors_s> {
+public:
+    PubkeyCredDescriptorsSerializer(const wauthn_pubkey_cred_descriptors_s* data)
+        : StructSerializer(data) {};
+    virtual void Serialize(IStream &stream) const override;
+};
 
-    static void serialize(IStream& stream, const wauthn_user_entity_s* data);
-    static void deserialize(IStream& stream, wauthn_user_entity_s** data);
+class PubkeyCredDescriptorsDeserializer :
+    public StructDeserializer<wauthn_pubkey_cred_descriptors_s> {
+public:
+    virtual void Deserialize(MessageBuffer &buffer) override;
+protected:
+    std::unique_ptr<wauthn_pubkey_cred_descriptor_s[]> m_descriptors;
+    std::unique_ptr<PubkeyCredDescriptorDeserializer[]> m_deserializers;
+};
 
-    static void serialize(IStream& stream, const wauthn_pubkey_cred_param_s* data);
-    static void deserialize(IStream& stream, wauthn_pubkey_cred_param_s** data);
+// For wauthn_authentication_ext_s
+class AuthenticationExtSerializer : public StructSerializer<wauthn_authentication_ext_s> {
+public:
+    AuthenticationExtSerializer(const wauthn_authentication_ext_s* data)
+        : StructSerializer(data) {};
+    virtual void Serialize(IStream &stream) const override;
+};
 
-    static void serialize(IStream& stream, const wauthn_pubkey_cred_params_s* data);
-    static void deserialize(IStream& stream, wauthn_pubkey_cred_params_s** data);
+class AuthenticationExtDeserializer : public StructDeserializer<wauthn_authentication_ext_s> {
+public:
+    virtual void Deserialize(MessageBuffer &buffer) override;
+protected:
+    ConstBufferDeserializer m_extensionId;
+    ConstBufferDeserializer m_extensionValue;
+};
+
+// For wauthn_authentication_exts_s
+class AuthenticationExtsSerializer : public StructSerializer<wauthn_authentication_exts_s> {
+public:
+    AuthenticationExtsSerializer(const wauthn_authentication_exts_s* data)
+        : StructSerializer(data) {};
+    virtual void Serialize(IStream &stream) const override;
+};
+
+class AuthenticationExtsDeserializer : public StructDeserializer<wauthn_authentication_exts_s> {
+public:
+    virtual void Deserialize(MessageBuffer &buffer) override;
+protected:
+    std::unique_ptr<wauthn_authentication_ext_s[]> m_extensions;
+    std::unique_ptr<AuthenticationExtDeserializer[]> m_deserializers;
+};
+
+// For wauthn_authenticator_sel_cri_s
+class AuthenticatorSelCriSerializer : public StructSerializer<wauthn_authenticator_sel_cri_s> {
+public:
+    AuthenticatorSelCriSerializer(const wauthn_authenticator_sel_cri_s* data)
+        : StructSerializer(data) {};
+    virtual void Serialize(IStream &stream) const override;
+};
+
+class AuthenticatorSelCriDeserializer : public StructDeserializer<wauthn_authenticator_sel_cri_s> {
+public:
+    virtual void Deserialize(MessageBuffer &buffer) override;
+protected:
+    // nothing to be here.
+};
+
+// For wauthn_pubkey_cred_hints_s
+class PubkeyCredHintsSerializer : public StructSerializer<wauthn_pubkey_cred_hints_s> {
+public:
+    PubkeyCredHintsSerializer(const wauthn_pubkey_cred_hints_s* data)
+        : StructSerializer(data) {};
+    virtual void Serialize(IStream &stream) const override;
+};
+
+class PubkeyCredHintsDeserializer : public StructDeserializer<wauthn_pubkey_cred_hints_s> {
+public:
+    virtual void Deserialize(MessageBuffer &buffer) override;
+protected:
+    std::unique_ptr<wauthn_pubkey_cred_hint_e[]> m_hints;
+};
+
+// For wauthn_hybrid_linked_data_s
+class HybridLinkedDataSerializer : public StructSerializer<wauthn_hybrid_linked_data_s> {
+public:
+    HybridLinkedDataSerializer(const wauthn_hybrid_linked_data_s* data)
+        : StructSerializer(data) {};
+    virtual void Serialize(IStream &stream) const override;
+};
 
-    static void serialize(IStream& stream, const wauthn_pubkey_cred_descriptor_s* data);
-    static void deserialize(IStream& stream, wauthn_pubkey_cred_descriptor_s** data);
+class HybridLinkedDataDeserializer : public StructDeserializer<wauthn_hybrid_linked_data_s> {
+public:
+    virtual void Deserialize(MessageBuffer &buffer) override;
+protected:
+    ConstBufferDeserializer m_contactId;
+    ConstBufferDeserializer m_linkId;
+    ConstBufferDeserializer m_linkSecret;
+    ConstBufferDeserializer m_authenticatorPubkey;
+    ConstBufferDeserializer m_authenticatorName;
+    ConstBufferDeserializer m_signature;
+    ConstBufferDeserializer m_tunnelServerDomain;
+    ConstBufferDeserializer m_identityKey;
+};
 
-    static void serialize(IStream& stream, const wauthn_pubkey_cred_descriptors_s* data);
-    static void deserialize(IStream& stream, wauthn_pubkey_cred_descriptors_s** data);
+// For wauthn_attestation_formats_s
+class AttestationFormatsSerializer : public StructSerializer<wauthn_attestation_formats_s> {
+public:
+    AttestationFormatsSerializer(const wauthn_attestation_formats_s* data)
+        : StructSerializer(data) {};
+    virtual void Serialize(IStream &stream) const override;
+};
 
-    static void serialize(IStream& stream, const wauthn_authentication_ext_s* data);
-    static void deserialize(IStream& stream, wauthn_authentication_ext_s** data);
+class AttestationFormatsDeserializer : public StructDeserializer<wauthn_attestation_formats_s> {
+public:
+    virtual void Deserialize(MessageBuffer &buffer) override;
+protected:
+    std::unique_ptr<wauthn_const_buffer_s[]> m_attestationFormats;
+    std::unique_ptr<ConstBufferDeserializer[]> m_deserializers;
+};
 
-    static void serialize(IStream& stream, const wauthn_authentication_exts_s* data);
-    static void deserialize(IStream& stream, wauthn_authentication_exts_s** data);
+// For wauthn_pubkey_cred_creation_options_s
+class PubKeyCredCreationOptionsSerializer :
+    public StructSerializer<wauthn_pubkey_cred_creation_options_s> {
+public:
+    PubKeyCredCreationOptionsSerializer(const wauthn_pubkey_cred_creation_options_s* data)
+        : StructSerializer(data) {};
+    virtual void Serialize(IStream &stream) const override;
+};
 
-    static void serialize(IStream& stream, const wauthn_authenticator_sel_cri_s* data);
-    static void deserialize(IStream& stream, wauthn_authenticator_sel_cri_s** data);
+class PubKeyCredCreationOptionsDeserializer :
+    public StructDeserializer<wauthn_pubkey_cred_creation_options_s> {
+public:
+    virtual void Deserialize(MessageBuffer &buffer) override;
+protected:
+    RpEntityDeserializer m_rp;
+    UserEntityDeserializer m_user;
+    PubkeyCredParamsDeserializer m_pubkeyCredParams;
+    PubkeyCredDescriptorsDeserializer m_excludeCredentials;
+    AuthenticatorSelCriDeserializer m_authenticatorSelection;
+    PubkeyCredHintsDeserializer m_hints;
+    AttestationFormatsDeserializer m_attestationFormats;
+    AuthenticationExtsDeserializer m_extensions;
+    HybridLinkedDataDeserializer m_linkedDevice;
+};
 
-    static void serialize(IStream& stream, const wauthn_pubkey_cred_hints_s* data);
-    static void deserialize(IStream& stream, wauthn_pubkey_cred_hints_s** data);
+// For wauthn_pubkey_cred_request_options_s
+class PubKeyCredRequestOptionsSerializer :
+    public StructSerializer<wauthn_pubkey_cred_request_options_s> {
+public:
+    PubKeyCredRequestOptionsSerializer(const wauthn_pubkey_cred_request_options_s* data)
+        : StructSerializer(data) {};
+    virtual void Serialize(IStream &stream) const override;
+};
 
-    static void serialize(IStream& stream, const wauthn_hybrid_linked_data_s* data);
-    static void deserialize(IStream& stream, wauthn_hybrid_linked_data_s** data);
+class PubKeyCredRequestOptionsDeserializer :
+    public StructDeserializer<wauthn_pubkey_cred_request_options_s> {
+public:
+    virtual void Deserialize(MessageBuffer &buffer) override;
+protected:
+    std::unique_ptr<char[]> m_rpId;
+    PubkeyCredDescriptorsDeserializer m_allowCredentials;
+    PubkeyCredHintsDeserializer m_hints;
+    AttestationFormatsDeserializer m_attestationFormats;
+    AuthenticationExtsDeserializer m_extensions;
+    HybridLinkedDataDeserializer m_linkedDevice;
+};
 
-    static void serialize(IStream& stream, const wauthn_attestation_formats_s* data);
-    static void deserialize(IStream& stream, wauthn_attestation_formats_s** data);
+// For wauthn_pubkey_credential_attestation_s
+class PubkeyCredentialAttestationSerializer :
+    public StructSerializer<wauthn_pubkey_credential_attestation_s> {
+public:
+    PubkeyCredentialAttestationSerializer(const wauthn_pubkey_credential_attestation_s* data)
+        : StructSerializer(data) {};
+    virtual void Serialize(IStream &stream) const override;
+};
 
-    static void serialize(IStream& stream, const wauthn_pubkey_cred_creation_options_s* data);
-    static void deserialize(IStream& stream, wauthn_pubkey_cred_creation_options_s** data);
+class PubkeyCredentialAttestationDeserializer :
+    public StructDeserializer<wauthn_pubkey_credential_attestation_s> {
+public:
+    virtual void Deserialize(MessageBuffer &buffer) override;
+protected:
+    ConstBufferDeserializer m_id;
+    ConstBufferDeserializer m_rawId;
+    AuthenticatorAttestationResponseDeserializer m_response;
+    AuthenticationExtsDeserializer m_extensions;
+    HybridLinkedDataDeserializer m_linkedDevice;
+};
 
-    static void serialize(IStream& stream, const wauthn_pubkey_cred_request_options_s* data);
-    static void deserialize(IStream& stream, wauthn_pubkey_cred_request_options_s** data);
+// For wauthn_pubkey_credential_assertion_s
+class PubkeyCredentialAssertionSerializer :
+    public StructSerializer<wauthn_pubkey_credential_assertion_s> {
+public:
+    PubkeyCredentialAssertionSerializer(const wauthn_pubkey_credential_assertion_s* data)
+        : StructSerializer(data) {};
+    virtual void Serialize(IStream &stream) const override;
+};
 
-    static void serialize(IStream& stream, const wauthn_pubkey_credential_attestation_s* data);
-    static void deserialize(IStream& stream, wauthn_pubkey_credential_attestation_s** data);
+class PubkeyCredentialAssertionDeserializer :
+    public StructDeserializer<wauthn_pubkey_credential_assertion_s> {
+public:
+    virtual void Deserialize(MessageBuffer &buffer) override;
+protected:
+    ConstBufferDeserializer m_id;
+    ConstBufferDeserializer m_rawId;
+    AuthenticatorAssertionResponseDeserializer m_response;
+    AuthenticationExtsDeserializer m_extensions;
+    HybridLinkedDataDeserializer m_linkedDevice;
+};
 
-    static void serialize(IStream& stream, const wauthn_pubkey_credential_assertion_s* data);
-    static void deserialize(IStream& stream, wauthn_pubkey_credential_assertion_s** data);
+// For wauthn_client_data_s
+class ClientDataSerializer : public StructSerializer<wauthn_client_data_s> {
+public:
+    ClientDataSerializer(const wauthn_client_data_s* data)
+        : StructSerializer(data) {};
+    virtual void Serialize(IStream &stream) const override;
+};
 
-    static void serialize(IStream& stream, const wauthn_client_data_s* data);
-    static void deserialize(IStream& stream, wauthn_client_data_s** data);
+class ClientDataDeserializer : public StructDeserializer<wauthn_client_data_s> {
+public:
+    virtual void Deserialize(MessageBuffer &buffer) override;
+protected:
+    ConstBufferDeserializer m_clientDataJson;
 };
 
+
 struct Serialization {
     // serialization
     // normal functions
@@ -161,11 +470,10 @@ struct Serialization {
     {
         stream.Write(sizeof(value), &value);
     }
-    // The following function conflicts with Serialize function for WAuthn C Types.
-    // static void Serialize(IStream& stream, const char* const value)
-    // {
-    //     stream.Write(sizeof(*value), value);
-    // }
+    static void Serialize(IStream& stream, const char* const value)
+    {
+        stream.Write(sizeof(*value), value);
+    }
 
     // unsigned char
     static void Serialize(IStream& stream, const unsigned char value)
@@ -356,117 +664,10 @@ struct Serialization {
         Serialize(stream, second, tail...);
     }
 
-    // For WAuthn C Types
-
-    // For char*
-    static void Serialize(IStream& stream, const char* data)
-    {
-        WAuthnCtypeSerializer::serialize(stream, data);
-    }
-    // For wauthn_error_e
-    static void Serialize(IStream& stream, const wauthn_error_e data)
-    {
-        WAuthnCtypeSerializer::serialize(stream, data);
-    }
-    // For wauthn_const_buffer_s
-    static void Serialize(IStream& stream, const wauthn_const_buffer_s* data)
-    {
-        WAuthnCtypeSerializer::serialize(stream, data);
-    }
-    // For wauthn_authenticator_attestation_response_s
-    static void Serialize(IStream& stream, const wauthn_authenticator_attestation_response_s* data)
-    {
-        WAuthnCtypeSerializer::serialize(stream, data);
-    }
-    // For wauthn_authenticator_assertion_response_s
-    static void Serialize(IStream& stream, const wauthn_authenticator_assertion_response_s* data)
-    {
-        WAuthnCtypeSerializer::serialize(stream, data);
-    }
-    // For wauthn_rp_entity_s
-    static void Serialize(IStream& stream, const wauthn_rp_entity_s* data)
-    {
-        WAuthnCtypeSerializer::serialize(stream, data);
-    }
-    // For wauthn_user_entity_s
-    static void Serialize(IStream& stream, const wauthn_user_entity_s* data)
+    // For WAuthn C Types : wauthn_error_e
+    static void Serialize(IStream& stream, const wauthn_error_e value)
     {
-        WAuthnCtypeSerializer::serialize(stream, data);
-    }
-    // For wauthn_pubkey_cred_param_s
-    static void Serialize(IStream& stream, const wauthn_pubkey_cred_param_s* data)
-    {
-        WAuthnCtypeSerializer::serialize(stream, data);
-    }
-    // For wauthn_pubkey_cred_params_s
-    static void Serialize(IStream& stream, const wauthn_pubkey_cred_params_s* data)
-    {
-        WAuthnCtypeSerializer::serialize(stream, data);
-    }
-    // For wauthn_pubkey_cred_descriptor_s
-    static void Serialize(IStream& stream, const wauthn_pubkey_cred_descriptor_s* data)
-    {
-        WAuthnCtypeSerializer::serialize(stream, data);
-    }
-    // For wauthn_pubkey_cred_descriptors_s
-    static void Serialize(IStream& stream, const wauthn_pubkey_cred_descriptors_s* data)
-    {
-        WAuthnCtypeSerializer::serialize(stream, data);
-    }
-    // For wauthn_authentication_ext_s
-    static void Serialize(IStream& stream, const wauthn_authentication_ext_s* data)
-    {
-        WAuthnCtypeSerializer::serialize(stream, data);
-    }
-    // For wauthn_authentication_exts_s
-    static void Serialize(IStream& stream, const wauthn_authentication_exts_s* data)
-    {
-        WAuthnCtypeSerializer::serialize(stream, data);
-    }
-    // For wauthn_rp_entity_s
-    static void Serialize(IStream& stream, const wauthn_authenticator_sel_cri_s* data)
-    {
-        WAuthnCtypeSerializer::serialize(stream, data);
-    }
-    // For wauthn_pubkey_cred_hints_s
-    static void Serialize(IStream& stream, const wauthn_pubkey_cred_hints_s* data)
-    {
-        WAuthnCtypeSerializer::serialize(stream, data);
-    }
-    // For wauthn_hybrid_linked_data_s
-    static void Serialize(IStream& stream, const wauthn_hybrid_linked_data_s* data)
-    {
-        WAuthnCtypeSerializer::serialize(stream, data);
-    }
-    // For wauthn_attestation_formats_s
-    static void Serialize(IStream& stream, const wauthn_attestation_formats_s* data)
-    {
-        WAuthnCtypeSerializer::serialize(stream, data);
-    }
-    // For wauthn_pubkey_cred_creation_options_s
-    static void Serialize(IStream& stream, const wauthn_pubkey_cred_creation_options_s* data)
-    {
-        WAuthnCtypeSerializer::serialize(stream, data);
-    }
-    // For wauthn_pubkey_cred_request_options_s
-    static void Serialize(IStream& stream, const wauthn_pubkey_cred_request_options_s* data)
-    {
-        WAuthnCtypeSerializer::serialize(stream, data);
-    }
-    // For wauthn_pubkey_credential_attestation_s
-    static void Serialize(IStream& stream, const wauthn_pubkey_credential_attestation_s* data)
-    {
-        WAuthnCtypeSerializer::serialize(stream, data);
-    }
-    // For wauthn_pubkey_credential_assertion_s
-    static void Serialize(IStream& stream, const wauthn_pubkey_credential_assertion_s* data)
-    {
-        WAuthnCtypeSerializer::serialize(stream, data);
-    }
-    // For wauthn_client_data_s
-    static void Serialize(IStream& stream, const wauthn_client_data_s* data)
-    {
-        WAuthnCtypeSerializer::serialize(stream, data);
+        stream.Write(sizeof(value), &value);
     }
 
 }; // struct Serialization
@@ -475,132 +676,133 @@ struct Deserialization {
     // deserialization
     // normal functions
 
-    // ISerializable objects
-    // T instead of ISerializable is needed to call proper constructor
-    template <typename T>
-    static void Deserialize(IStream& stream, T& object)
+    // IDeserializable objects
+    static void Deserialize(MessageBuffer& buffer, IDeserializable& object)
     {
-        object = T(stream);
+        object.Deserialize(buffer);
     }
-    template <typename T>
-    static void Deserialize(IStream& stream, T*& object)
+    static void Deserialize(MessageBuffer& buffer, IDeserializable*& object)
     {
-        object = new T(stream);
+        object->Deserialize(buffer);
     }
 
     // char
-    static void Deserialize(IStream& stream, char& value)
+    static void Deserialize(MessageBuffer& buffer, char& value)
     {
-        stream.Read(sizeof(value), &value);
+        buffer.Read(sizeof(value), &value);
     }
-    static void Deserialize(IStream& stream, char*& value)
+    static void Deserialize(MessageBuffer& buffer, char*& value)
     {
         value = new char;
         std::unique_ptr<char> ptr(value);
-        stream.Read(sizeof(*value), value);
-        ptr.release();
+        buffer.Read(sizeof(*value), value);
+        ptr.reset();
     }
 
     // unsigned char
-    static void Deserialize(IStream& stream, unsigned char& value)
+    static void Deserialize(MessageBuffer& buffer, unsigned char& value)
     {
-        stream.Read(sizeof(value), &value);
+        buffer.Read(sizeof(value), &value);
     }
-    static void Deserialize(IStream& stream, unsigned char*& value)
+    static void Deserialize(MessageBuffer& buffer, unsigned char*& value)
     {
         value = new unsigned char;
         std::unique_ptr<unsigned char> ptr(value);
-        stream.Read(sizeof(*value), value);
-        ptr.release();
+        buffer.Read(sizeof(*value), value);
+        ptr.reset();
     }
 
     // unsigned int
-    static void Deserialize(IStream& stream, unsigned& value)
+    static void Deserialize(MessageBuffer& buffer, unsigned& value)
     {
-        stream.Read(sizeof(value), &value);
+        buffer.Read(sizeof(value), &value);
     }
-    static void Deserialize(IStream& stream, unsigned*& value)
+    static void Deserialize(MessageBuffer& buffer, unsigned*& value)
     {
         value = new unsigned;
         std::unique_ptr<unsigned> ptr(value);
-        stream.Read(sizeof(*value), value);
-        ptr.release();
+        buffer.Read(sizeof(*value), value);
+        ptr.reset();
     }
 
     // int
-    static void Deserialize(IStream& stream, int& value)
+    static void Deserialize(MessageBuffer& buffer, int& value)
     {
-        stream.Read(sizeof(value), &value);
+        buffer.Read(sizeof(value), &value);
     }
-    static void Deserialize(IStream& stream, int*& value)
+    static void Deserialize(MessageBuffer& buffer, int*& value)
     {
         value = new int;
         std::unique_ptr<int> ptr(value);
-        stream.Read(sizeof(*value), value);
-        ptr.release();
+        buffer.Read(sizeof(*value), value);
+        ptr.reset();
     }
 
     // bool
-    static void Deserialize(IStream& stream, bool& value)
+    static void Deserialize(MessageBuffer& buffer, bool& value)
     {
-        stream.Read(sizeof(value), &value);
+        buffer.Read(sizeof(value), &value);
     }
-    static void Deserialize(IStream& stream, bool*& value)
+    static void Deserialize(MessageBuffer& buffer, bool*& value)
     {
         value = new bool;
         std::unique_ptr<bool> ptr(value);
-        stream.Read(sizeof(*value), value);
-        ptr.release();
+        buffer.Read(sizeof(*value), value);
+        ptr.reset();
     }
 
     // unsigned long
-    static void Deserialize(IStream& stream, unsigned long& value)
+    static void Deserialize(MessageBuffer& buffer, unsigned long& value)
     {
-        stream.Read(sizeof(value), &value);
+        buffer.Read(sizeof(value), &value);
     }
-    static void Deserialize(IStream& stream, unsigned long*& value)
+    static void Deserialize(MessageBuffer& buffer, unsigned long*& value)
     {
         value = new unsigned long;
         std::unique_ptr<unsigned long> ptr(value);
-        stream.Read(sizeof(*value), value);
-        ptr.release();
+        buffer.Read(sizeof(*value), value);
+        ptr.reset();
     }
 
     // long
-    static void Deserialize(IStream& stream, long& value)
+    static void Deserialize(MessageBuffer& buffer, long& value)
     {
-        stream.Read(sizeof(value), &value);
+        buffer.Read(sizeof(value), &value);
     }
-    static void Deserialize(IStream& stream, long*& value)
+    static void Deserialize(MessageBuffer& buffer, long*& value)
     {
         value = new long;
         std::unique_ptr<long> ptr(value);
-        stream.Read(sizeof(*value), value);
-        ptr.release();
+        buffer.Read(sizeof(*value), value);
+        ptr.reset();
     }
 
     // std::string
-    static void Deserialize(IStream& stream, std::string& str)
+    static void Deserialize(MessageBuffer& buffer, std::string& str)
     {
         int length;
-        stream.Read(sizeof(length), &length);
-        if (length < 0)
-            ThrowMsg(SerializationException::InvalidStreamData, "Invalid length of std::string (less than 0)");
+        buffer.Read(sizeof(length), &length);
+        if (length < 0) {
+            ThrowMsg(SerializationException::InvalidStreamData,
+                     "Invalid length of std::string (less than 0)");
+        }
         char * buf = new char[length + 1];
         std::unique_ptr<char[]> ptr(buf);
-        stream.Read(length, buf);
+        buffer.Read(length, buf);
         buf[length] = 0;
         str = std::string(buf);
     }
-    static void Deserialize(IStream& stream, std::string*& str)
+    static void Deserialize(MessageBuffer& buffer, std::string*& str)
     {
         int length;
-        stream.Read(sizeof(length), &length);
-        if (length < 0)
-            ThrowMsg(SerializationException::InvalidStreamData, "Invalid length of std::string (less than 0)");
+        buffer.Read(sizeof(length), &length);
+        if (length < 0) {
+            ThrowMsg(SerializationException::InvalidStreamData,
+                     "Invalid length of std::string (less than 0)");
+        }
         char * buf = new char[length + 1];
         std::unique_ptr<char[]> ptr(buf);
-        stream.Read(length, buf);
+        buffer.Read(length, buf);
         buf[length] = 0;
         str = new std::string(buf);
     }
@@ -609,64 +811,68 @@ struct Deserialization {
 
     // std::list
     template <typename T>
-    static void Deserialize(IStream& stream, std::list<T>& list)
+    static void Deserialize(MessageBuffer& buffer, std::list<T>& list)
     {
         int length;
-        stream.Read(sizeof(length), &length);
-        if (length < 0)
-            ThrowMsg(SerializationException::InvalidStreamData, "Invalid length of std::list (less than 0)");
+        buffer.Read(sizeof(length), &length);
+        if (length < 0) {
+            ThrowMsg(SerializationException::InvalidStreamData,
+                     "Invalid length of std::list (less than 0)");
+        }
         for (int i = 0; i < length; ++i) {
             T obj;
-            Deserialize(stream, obj);
+            Deserialize(buffer, obj);
             list.push_back(std::move(obj));
         }
     }
     template <typename T>
-    static void Deserialize(IStream& stream, std::list<T>*& list)
+    static void Deserialize(MessageBuffer& buffer, std::list<T>*& list)
     {
         list = new std::list<T>;
         std::unique_ptr<std::list<T>> ptr(list);
-        Deserialize(stream, *list);
-        ptr.release();
+        Deserialize(buffer, *list);
+        ptr.reset();
     }
 
     // std::vector
     template <typename T>
-    static void Deserialize(IStream& stream, std::vector<T>& vec)
+    static void Deserialize(MessageBuffer& buffer, std::vector<T>& vec)
     {
         int length;
-        stream.Read(sizeof(length), &length);
-        if (length < 0)
-            ThrowMsg(SerializationException::InvalidStreamData, "Invalid length of std::vector (less than 0)");
+        buffer.Read(sizeof(length), &length);
+        if (length < 0) {
+            ThrowMsg(SerializationException::InvalidStreamData,
+                     "Invalid length of std::vector (less than 0)");
+        }
         for (int i = 0; i < length; ++i) {
             T obj;
-            Deserialize(stream, obj);
+            Deserialize(buffer, obj);
             vec.push_back(std::move(obj));
         }
     }
     template <typename T>
-    static void Deserialize(IStream& stream, std::vector<T>*& vec)
+    static void Deserialize(MessageBuffer& buffer, std::vector<T>*& vec)
     {
         vec = new std::vector<T>;
         std::unique_ptr<std::vector<T>> ptr(vec);
-        Deserialize(stream, *vec);
-        ptr.release();
+        Deserialize(buffer, *vec);
+        ptr.reset();
     }
 
     // std::pair
     template <typename A, typename B>
-    static void Deserialize(IStream& stream, std::pair<A, B>& p)
+    static void Deserialize(MessageBuffer& buffer, std::pair<A, B>& p)
     {
-        Deserialize(stream, p.first);
-        Deserialize(stream, p.second);
+        Deserialize(buffer, p.first);
+        Deserialize(buffer, p.second);
     }
     template <typename A, typename B>
-    static void Deserialize(IStream& stream, std::pair<A, B>*& p)
+    static void Deserialize(MessageBuffer& buffer, std::pair<A, B>*& p)
     {
         p = new std::pair<A, B>;
         std::unique_ptr<std::pair<A, B>> ptr(p);
-        Deserialize(stream, *p);
-        ptr.release();
+        Deserialize(buffer, *p);
+        ptr.reset();
     }
 
     // std::tuple
@@ -677,72 +883,59 @@ struct Deserialization {
 
     template <std::size_t I = 0, typename... Tp>
     static inline typename std::enable_if<I < sizeof...(Tp), void>::type
-    Deserialize(IStream& stream, std::tuple<Tp...>& t)
+    Deserialize(MessageBuffer& buffer, std::tuple<Tp...>& t)
     {
-        Deserialize(stream, std::get<I>(t));
-        Deserialize<I+1>(stream, t);
+        Deserialize(buffer, std::get<I>(t));
+        Deserialize<I+1>(buffer, t);
     }
 
     template <typename... Tp>
-    static void Deserialize(IStream& stream, std::tuple<Tp...>*& t)
+    static void Deserialize(MessageBuffer& buffer, std::tuple<Tp...>*& t)
     {
         t = new std::tuple<Tp...>;
         std::unique_ptr<std::tuple<Tp...>> ptr(t);
-        Deserialize(stream, *t);
-        ptr.release();
+        Deserialize(buffer, *t);
+        ptr.reset();
     }
 
     // std::map
     template <typename K, typename T>
-    static void Deserialize(IStream& stream, std::map<K, T>& map)
+    static void Deserialize(MessageBuffer& buffer, std::map<K, T>& map)
     {
         int length;
-        stream.Read(sizeof(length), &length);
-        if (length < 0)
-            ThrowMsg(SerializationException::InvalidStreamData, "Invalid size of std::map (less than 0)");
+        buffer.Read(sizeof(length), &length);
+        if (length < 0) {
+            ThrowMsg(SerializationException::InvalidStreamData,
+                     "Invalid size of std::map (less than 0)");
+        }
         for (int i = 0; i < length; ++i) {
             K key;
             T obj;
-            Deserialize(stream, key);
-            Deserialize(stream, obj);
+            Deserialize(buffer, key);
+            Deserialize(buffer, obj);
             map[key] = std::move(obj);
         }
     }
     template <typename K, typename T>
-    static void Deserialize(IStream& stream, std::map<K, T>*& map)
+    static void Deserialize(MessageBuffer& buffer, std::map<K, T>*& map)
     {
         map = new std::map<K, T>;
         std::unique_ptr<std::map<K, T>> ptr(map);
-        Deserialize(stream, *map);
-        ptr.release();
+        Deserialize(buffer, *map);
+        ptr.reset();
     }
 
     template<typename T1, typename T2, typename... Tail>
-    static void Deserialize(IStream& stream, T1 &&first, T2 &&second, Tail&&... tail)
-    {
-        Deserialization::Deserialize(stream, first);
-        Deserialization::Deserialize(stream, second, tail...);
-    }
-
-    // For WAuthn C Types
-
-    // For wauthn_error_e
-    static void Deserialize(IStream& stream, wauthn_error_e* data)
+    static void Deserialize(MessageBuffer& buffer, T1 &&first, T2 &&second, Tail&&... tail)
     {
-        WAuthnCtypeSerializer::deserialize(stream, data);
+        Deserialization::Deserialize(buffer, first);
+        Deserialization::Deserialize(buffer, second, tail...);
     }
 
-    //##########################################################################################
-    // WARNING
-    // 1. The stream must be an instance of MessageBuffer.
-    // 2. The returned data(more exactly *data) points to somewhere of m_buffer of MessageBuffer.
-    //    So the returned data is only valid while the stream is alive.
-    //###########################################################################################
-    // This converts all other C types.
-    template<typename T>
-    static void Deserialize(IStream& stream, T** data)
+    // For WAuthn C Types : For wauthn_error_e
+    static void Deserialize(MessageBuffer& buffer, wauthn_error_e& value)
     {
-        WAuthnCtypeSerializer::deserialize(stream, data);
+        buffer.Read(sizeof(value), &value);
     }
 
 }; // struct Deserialization
index 5c147e098aa4b561cbee0f7bef1ca94fd2e0c6a8..67b5d02b2981c9c5379d73e9bbb798fb59d8cd4b 100644 (file)
@@ -22,6 +22,7 @@
 #pragma once
 
 #include <tizen_error.h>
+#include <serialization.h>
 
 #include "request.h"
 
@@ -34,6 +35,8 @@ public:
     typedef wauthn_ga_callbacks_s Callbacks;
     typedef wauthn_pubkey_credential_assertion_s PubKeyCred;
 
+    typedef PubKeyCredRequestOptionsDeserializer Deserializer;
+
     std::string GetAPI() {return m_API;}
 
     static void ResponseCallback(const PubKeyCred *pubkey_cred,
@@ -45,7 +48,8 @@ public:
         if (userData != nullptr)
         {
             MessageBuffer buffer(userData->service->GetSocketManager()->newMessage());
-            Serialization::Serialize(buffer, result, pubkey_cred);
+            Serialization::Serialize(buffer, result,
+                                     PubkeyCredentialAssertionSerializer(pubkey_cred));
             userData->service->GetSocketManager()->Write(userData->connectionID, std::move(buffer));
             userData->service->UnsetBusy();
         }
index 672ef530536e3550b5d72de4d62b7a9098262ac3..0916646687df756bb7661a1f8cbe5aa76e98c9d8 100644 (file)
@@ -22,6 +22,7 @@
 #pragma once
 
 #include <tizen_error.h>
+#include <serialization.h>
 
 #include "request.h"
 
@@ -34,6 +35,8 @@ public:
     typedef wauthn_mc_callbacks_s Callbacks;
     typedef wauthn_pubkey_credential_attestation_s PubKeyCred;
 
+    typedef PubKeyCredCreationOptionsDeserializer Deserializer;
+
     std::string GetAPI() {return m_API;}
 
     static void ResponseCallback(const PubKeyCred *pubkey_cred,
@@ -45,7 +48,8 @@ public:
         if (userData != nullptr)
         {
             MessageBuffer buffer(userData->service->GetSocketManager()->newMessage());
-            Serialization::Serialize(buffer, result, pubkey_cred);
+            Serialization::Serialize(buffer, result,
+                                     PubkeyCredentialAttestationSerializer(pubkey_cred));
             userData->service->GetSocketManager()->Write(userData->connectionID, std::move(buffer));
             userData->service->UnsetBusy();
         }
index c1eea7df021a27f308d881d6fe15855db03e20a1..29962f8aa17da4aec624a6cb02de17a8d3ad24bb 100644 (file)
@@ -23,6 +23,8 @@
 
 #include <tizen_error.h>
 
+#include "service.h"
+
 namespace WA{
 
 class Request {
@@ -49,7 +51,7 @@ public:
         if (userData != nullptr)
         {
             MessageBuffer buffer(userData->service->GetSocketManager()->newMessage());
-            Serialization::Serialize(buffer, result, linked_data);
+            Serialization::Serialize(buffer, result, HybridLinkedDataSerializer(linked_data));
             userData->service->GetSocketManager()->Write(userData->connectionID, std::move(buffer));
         }
         else
index 3d6c4b1e421c9e33214671c3020d8ef189c3478c..c836d8ed6bd654630e1181acc6cfc361b9cd3cc2 100644 (file)
@@ -123,9 +123,9 @@ void GenericService::Worker(SocketManager::ConnectionID connectionID,
 template <typename T>
 void GenericService::Process(Event &&msg)
 {
-    wauthn_client_data_s *clientData = nullptr;
-    typename T::Options *options = nullptr;
-    Deserialization::Deserialize(msg.buffer, &clientData, &options);
+    ClientDataDeserializer clientDataDeserializer;
+    typename T::Deserializer optionsDeserializer;
+    Deserialization::Deserialize(msg.buffer, clientDataDeserializer, optionsDeserializer);
 
     MessageBuffer responseBuffer(m_serviceManager->newMessage());
     responseBuffer.ModeStreaming();
@@ -158,7 +158,14 @@ void GenericService::Process(Event &&msg)
     m_serviceManager->Write(msg.connectionID, std::move(responseBuffer));
     if (ret == WAUTHN_ERROR_NONE)
     {
-        std::thread worker(&GenericService::Worker<T>, this, msg.connectionID, clientData, options);
+        std::thread worker([this, msg = std::move(msg),
+                            clientDataDeserializer = std::move(clientDataDeserializer),
+                            optionsDeserializer = std::move(optionsDeserializer)]() mutable {
+            wauthn_client_data_s *clientData = clientDataDeserializer.getRawPtr();
+            typename T::Options *options = optionsDeserializer.getRawPtr();
+            GenericService::Worker<T>(msg.connectionID, clientData, options);
+        });
+
         worker.detach();
     }
 }
index b5d5403a082546b03fe65a8d367241416235dd4c..6c0555745bb9b217522f66e57ea49644b2b80267 100644 (file)
@@ -36,7 +36,7 @@ typedef struct __struct_user_data
 {
     GenericService *service;
     SocketManager::ConnectionID connectionID;
-}user_data_s;
+} user_data_s;
 
 struct Event {
     SocketManager::ConnectionID connectionID;
index 74970189ebda5fcbecc2d4850d06c1f70f4c9a93..8a03786053163a243114dbed4aa4bd46ace56e66 100644 (file)
@@ -65,6 +65,9 @@ public:
     typedef wauthn_mc_callbacks_s Callbacks;
     typedef wauthn_pubkey_credential_attestation_s PubKeyCred;
 
+    typedef PubKeyCredCreationOptionsSerializer OptionsSerializer;
+    typedef PubkeyCredentialAttestationDeserializer PubKeyCredDeserializer;
+
     explicit TestClientRequestMC() : TestClientRequest(WebAuthnCall::MAKE_CREDENTIAL) {}
 };
 
@@ -75,6 +78,9 @@ public:
     typedef wauthn_ga_callbacks_s Callbacks;
     typedef wauthn_pubkey_credential_assertion_s PubKeyCred;
 
+    typedef PubKeyCredRequestOptionsSerializer OptionsSerializer;
+    typedef PubkeyCredentialAssertionDeserializer PubKeyCredDeserializer;
+
     explicit TestClientRequestGA() : TestClientRequest(WebAuthnCall::GET_ASSERTION) {}
 };
 
index e526509aeb58718b7892477c9d1111e2ceec2f9d..ecd4283d90d7b056909caf48880ad2fedba3d5e1 100644 (file)
@@ -18,8 +18,6 @@
  * @version     1.0
  * @brief       Unit tests for serialization
  */
-
-
 #include <cstring>
 #include <gtest/gtest.h>
 #include <iostream>
@@ -44,39 +42,22 @@ protected:
 };
 
 template<typename T, typename U>
-void __serializeDeserializeWithWAuthnCtypeSerializer(MessageBuffer& buffer, T data, U deserialized)
-{
-    buffer.InitForStreaming();
-    WAuthnCtypeSerializer::serialize(buffer, data);
-    buffer.ModeOutput();
-
-    buffer.ModeStreaming();
-    WAuthnCtypeSerializer::deserialize(buffer, deserialized);
-}
-
-template<typename T, typename U>
-void __serializeDeserializeStruct(MessageBuffer& buffer, T data, U deserialized)
+void __serializeDeserialize(MessageBuffer& buffer, T& data, U& deserializable)
 {
     buffer.InitForStreaming();
     Serialization::Serialize(buffer, data);
     buffer.ModeOutput();
 
     buffer.ModeStreaming();
-    Deserialization::Deserialize(buffer, deserialized);
+    Deserialization::Deserialize(buffer, deserializable);
 }
 
-template<typename T, typename F>
-void __testSerialization(T data, F cmpFunction)
+template<typename T, typename U, typename F>
+void __testSerialization(T& data, U& deserializable, F cmpFunction)
 {
-    MessageBuffer buffer0;
-    T deserialized0;
-    __serializeDeserializeWithWAuthnCtypeSerializer(buffer0, data, &deserialized0);
-    EXPECT_EQ(cmpFunction(data, deserialized0), true);
-
-    MessageBuffer buffer1;
-    T deserialized1;
-    __serializeDeserializeStruct(buffer1, data, &deserialized1);
-    EXPECT_EQ(cmpFunction(data, deserialized1), true);
+    MessageBuffer buffer;
+    __serializeDeserialize(buffer, data, deserializable);
+    EXPECT_EQ(cmpFunction(data.getRawPtr(), deserializable.getRawPtr()), true);
 }
 
 void __fillBufferWithTestCommonData(MessageBuffer& buffer,
@@ -89,8 +70,7 @@ void __fillBufferWithTestCommonData(MessageBuffer& buffer,
     buffer.ModeStreaming();
 }
 
-template<typename T>
-void __testDeserializeForTooLongLength(T* deserialized)
+void __testDeserializeForTooLongLength(IDeserializable& deserialized)
 {
     // deserialize: for too large length
     unsigned char data[32] = {0x01, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, };
@@ -99,233 +79,84 @@ void __testDeserializeForTooLongLength(T* deserialized)
     __fillBufferWithTestCommonData(buffer, MAX_BUFFER_SIZE + 1, data, sizeof(data));
 
     try {
-        WAuthnCtypeSerializer::deserialize(buffer, &deserialized);
+        Deserialization::Deserialize(buffer, deserialized);
         EXPECT_TRUE(false);
     } catch(SerializationException::InvalidStreamData &) {
     }
 }
 
-template<typename T>
-void __testSerializeForInvalidMember(T data)
+void __testSerializeForInvalidMember(ISerializable& serializer)
 {
     MessageBuffer buffer;
     buffer.InitForStreaming();
     try {
-        WAuthnCtypeSerializer::serialize(buffer, data);
+        serializer.Serialize(buffer);
         EXPECT_TRUE(false);
     } catch(SerializationException::InvalidStreamData &) {
     }
 }
 
-template<typename T>
-void __testDeserializeInvalidMember(T data)
+template<typename T, typename U>
+void __testDeserializeForInvalidMember(T invalidData)
 {
     MessageBuffer buffer;
-    T *deserialized = nullptr;
+    U deserializer;
     __fillBufferWithTestCommonData(buffer, sizeof(T),
-                reinterpret_cast<unsigned char*>(&data), sizeof(T));
+                reinterpret_cast<unsigned char*>(&invalidData), sizeof(T));
 
     try {
-        WAuthnCtypeSerializer::deserialize(buffer, &deserialized);
+        deserializer.Deserialize(buffer);
         EXPECT_TRUE(false);
     } catch(SerializationException::InvalidStreamData &) {
     }
 }
 
-bool __compareWAuthnBuffers(const wauthn_const_buffer_s *expected, const wauthn_const_buffer_s *actual)
+bool __compareWAuthnBuffers(const wauthn_const_buffer_s *expected,
+                            const wauthn_const_buffer_s *actual)
 {
-    if (expected == nullptr || actual == nullptr) {
-        return (expected == actual);
-    } else {
-        if (expected->size != actual->size)
-            return false;
-        if (memcmp(expected->data, actual->data, expected->size) != 0)
-            return false;
+    if (actual == nullptr && expected == nullptr)
         return true;
-    }
+    if (actual == nullptr || expected == nullptr)
+        return false;
+    if (actual == expected) // The addresses should be different after deserialization.
+        return false;
+    if (expected->size != actual->size)
+        return false;
+    if (actual->size == 0)
+        return true;
+    assert(actual->data);
+    assert(expected->data);
+    if (memcmp(expected->data, actual->data, actual->size) != 0)
+        return false;
+    return true;
 }
-
 bool __compareCstring(const char *expected, const char *actual)
 {
-    if (expected == nullptr || actual == nullptr) {
-        return (expected == actual);
-    } else {
-        return (strcmp(expected, actual) == 0);
-    }
-}
-
-void __testUnsignedCharPtr(unsigned char *data, size_t data_size)
-{
-    MessageBuffer buffer;
-    const unsigned char *deserialized = nullptr;
-    size_t deserialized_len = 0;
-
-    buffer.InitForStreaming();
-    WAuthnCtypeSerializer::serialize(buffer, data, data_size);
-    buffer.ModeOutput();
-
-    buffer.ModeStreaming();
-    WAuthnCtypeSerializer::deserialize(buffer, &deserialized, &deserialized_len);
-
-    EXPECT_EQ(data_size, deserialized_len);
-    if (data_size != 0 && deserialized_len != 0) {
-        // If deserialized_len is zero, memcmp is guaranteed to return zero
-        EXPECT_EQ(memcmp(data, deserialized, deserialized_len), 0);
-    }
-    else {
-        EXPECT_EQ(data, nullptr);
-        EXPECT_EQ(deserialized, nullptr);
-    }
-}
-
-TEST_F(WAuthnSerializationTest, unsignedCharPtr_P)
-{
-    unsigned char data[13] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,};
-    unsigned char *nullData = nullptr;
-
-    __testUnsignedCharPtr(data, sizeof(data));
-    __testUnsignedCharPtr(nullData, 0);
-}
-TEST_F(WAuthnSerializationTest, unsignedCharPtr_N1)
-{
-    // serialize: for too large data size
-    unsigned char data[13] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,};
-    MessageBuffer buffer;
-    buffer.InitForStreaming();
-    try {
-        WAuthnCtypeSerializer::serialize(buffer, data, MAX_BUFFER_SIZE + 1);
-        EXPECT_TRUE(false);
-    } catch(SerializationException::InvalidStreamData &) {
-    }
-}
-TEST_F(WAuthnSerializationTest, unsignedCharPtr_N2)
-{
-    // serialize: for inconsistent pointer & length
-    MessageBuffer buffer;
-    buffer.InitForStreaming();
-    try {
-        WAuthnCtypeSerializer::serialize(buffer, nullptr, 4);
-        EXPECT_TRUE(false);
-    } catch(SerializationException::InvalidStreamData &) {
-    }
-}
-TEST_F(WAuthnSerializationTest, unsignedCharPtr_N3)
-{
-    // deserialize: for too large data size
-    unsigned char data[13] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,};
-    MessageBuffer buffer;
-    const unsigned char *deserialized = nullptr;
-    size_t deserialized_len = 0;
-
-        __fillBufferWithTestCommonData(buffer, MAX_BUFFER_SIZE + 1, data, sizeof(data));
-    try {
-        WAuthnCtypeSerializer::deserialize(buffer, &deserialized, &deserialized_len);
-        EXPECT_TRUE(false);
-    } catch(SerializationException::InvalidStreamData &) {
-    }
-}
-
-TEST_F(WAuthnSerializationTest, ConstCharPtr_P)
-{
-    const char *data = "This is a test data.";
-    const char *size0data ="";
-    const char *nullData = nullptr;
-
-    __testSerialization(data, __compareCstring);
-    __testSerialization(size0data, __compareCstring);
-    __testSerialization(nullData, __compareCstring);
-}
-TEST_F(WAuthnSerializationTest, CharPtr_N1)
-{// serialize: for too large length
-    char *data = new char[MAX_BUFFER_SIZE+1];
-    std::fill_n(data, MAX_BUFFER_SIZE+1, (char)0x31);
-    data[MAX_BUFFER_SIZE] = 0x00;
-    __testSerializeForInvalidMember(data);
-    delete[] data;
-}
-TEST_F(WAuthnSerializationTest, ConstCharPtr_N2)
-{// deserialize: for too large length
-    const char *deserialized = nullptr;
-    __testDeserializeForTooLongLength(deserialized);
-}
-TEST_F(WAuthnSerializationTest, CharPtr_N3)
-{// deserialize: for invalid C String length
-    // strlen(data) = 4, length in buffer stream = 8
-    unsigned char data[8] = {0x01, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00};
-    MessageBuffer buffer;
-    const char *deserialized = nullptr;
-    __fillBufferWithTestCommonData(buffer, sizeof(data), data, sizeof(data));
-    try {
-        WAuthnCtypeSerializer::deserialize(buffer, &deserialized);
-        EXPECT_TRUE(false);
-    } catch(SerializationException::InvalidStreamData &) {
-    }
-}
-
-
-bool __compareWAuthErrorE(wauthn_error_e expected, wauthn_error_e actual)
-{
-    return (expected == actual);
-}
-TEST_F(WAuthnSerializationTest, wauthn_error_e_P)
-{
-    for (const auto error : {WAUTHN_ERROR_NONE,
-                             WAUTHN_ERROR_UNKNOWN,
-                             WAUTHN_ERROR_INVALID_PARAMETER,
-                             WAUTHN_ERROR_PERMISSION_DENIED,
-                             WAUTHN_ERROR_NOT_SUPPORTED,
-                             WAUTHN_ERROR_OUT_OF_MEMORY,
-                             WAUTHN_ERROR_CANCELED,
-                             WAUTHN_ERROR_TIMED_OUT,
-                             WAUTHN_ERROR_CONNECTION_REFUSED,
-                             WAUTHN_ERROR_NONE_AND_WAIT,
-                             WAUTHN_ERROR_NOT_ALLOWED,
-                             WAUTHN_ERROR_INVALID_STATE,
-                             WAUTHN_ERROR_ENCODING_FAILED,
-                             WAUTHN_ERROR_SOCKET,
-                             WAUTHN_ERROR_NO_SUCH_SERVICE,
-                             WAUTHN_ERROR_ACCESS_DENIED})
-        __testSerialization(error, __compareWAuthErrorE);
-}
-TEST_F(WAuthnSerializationTest, wauthn_error_e_N1)
-{// serialize: invalid wauthn_error_e
-    wauthn_error_e data1 = static_cast<wauthn_error_e>(WAUTHN_ERROR_NONE + 1);
-    __testSerializeForInvalidMember(data1);
-    wauthn_error_e data2 = static_cast<wauthn_error_e>(TIZEN_ERROR_WAUTHN);
-    __testSerializeForInvalidMember(data2);
-    wauthn_error_e data3 = static_cast<wauthn_error_e>(WAUTHN_ERROR_ACCESS_DENIED + 1);
-    __testSerializeForInvalidMember(data3);
-}
-TEST_F(WAuthnSerializationTest, wauthn_error_e_N2)
-{// deserialize: invalid wauthn_error_e
-    MessageBuffer buffer;
-    wauthn_error_e deserialized;
-    __fillBufferWithTestCommonData(buffer, WAUTHN_ERROR_NONE + 1, nullptr, 0);
-    EXPECT_THROW(WAuthnCtypeSerializer::deserialize(buffer, &deserialized),
-                 SerializationException::InvalidStreamData);
-
-    MessageBuffer buffer1;
-    __fillBufferWithTestCommonData(buffer1, TIZEN_ERROR_WAUTHN, nullptr, 0);
-    EXPECT_THROW(WAuthnCtypeSerializer::deserialize(buffer1, &deserialized),
-                 SerializationException::InvalidStreamData);
-
-    MessageBuffer buffer2;
-    __fillBufferWithTestCommonData(buffer2, WAUTHN_ERROR_ACCESS_DENIED + 1, nullptr, 0);
-    EXPECT_THROW(WAuthnCtypeSerializer::deserialize(buffer2, &deserialized),
-                 SerializationException::InvalidStreamData);
+    if (actual == nullptr && expected == nullptr)
+        return true;
+    if (actual == nullptr || expected == nullptr)
+        return false;
+    if (actual == expected) // The addresses should be different after deserialization.
+        return false;
+    return (strcmp(expected, actual) == 0);
 }
-
-
 TEST_F(WAuthnSerializationTest, wauthn_const_buffer_s_P)
 {
     unsigned char TestCommonData[26] = {0x01, 0x02, 0x03, 0x04, };
     wauthn_const_buffer_s buffer = {TestCommonData, sizeof(TestCommonData)};
-    __testSerialization(&buffer, __compareWAuthnBuffers);
+
+    ConstBufferSerializer data1(&buffer);
+    ConstBufferDeserializer deserializer1;
+    __testSerialization(data1, deserializer1, __compareWAuthnBuffers);
 
     wauthn_const_buffer_s emptyBuffer = {nullptr, 0x00};
-    __testSerialization(&emptyBuffer, __compareWAuthnBuffers);
+    ConstBufferSerializer data2(&emptyBuffer);
+    ConstBufferDeserializer deserializer2;
+    __testSerialization(data2, deserializer2, __compareWAuthnBuffers);
 
-    __testSerialization(static_cast<wauthn_const_buffer_s *>(nullptr), __compareWAuthnBuffers);
+    ConstBufferSerializer data3(nullptr);
+    ConstBufferDeserializer deserializer3;
+    __testSerialization(data3, deserializer3, __compareWAuthnBuffers);
 }
 TEST_F(WAuthnSerializationTest, wauthn_const_buffer_s_N1)
 {// serialize: for too large length
@@ -334,7 +165,8 @@ TEST_F(WAuthnSerializationTest, wauthn_const_buffer_s_N1)
     MessageBuffer buffer;
     buffer.InitForStreaming();
     try {
-        WAuthnCtypeSerializer::serialize(buffer, &data);
+        ConstBufferSerializer serializer(&data);
+        serializer.Serialize(buffer);
         EXPECT_TRUE(false);
     } catch(SerializationException::InvalidStreamData &) {
     }
@@ -346,15 +178,16 @@ TEST_F(WAuthnSerializationTest, wauthn_const_buffer_s_N2)
     MessageBuffer buffer;
     buffer.InitForStreaming();
     try {
-        WAuthnCtypeSerializer::serialize(buffer, &data);
+        ConstBufferSerializer serializer(&data);
+        serializer.Serialize(buffer);
         EXPECT_TRUE(false);
     } catch(SerializationException::InvalidStreamData &) {
     }
 }
 TEST_F(WAuthnSerializationTest, wauthn_const_buffer_s_N3)
 {// deserialize: for too large length
-    wauthn_const_buffer_s *deserialized = nullptr;
-    __testDeserializeForTooLongLength(deserialized);
+    ConstBufferDeserializer deserializer;
+    __testDeserializeForTooLongLength(deserializer);
 }
 
 
@@ -362,8 +195,12 @@ bool __compareWAuthnAuthenticatorAttestationResponseS(
                     const wauthn_authenticator_attestation_response_s *expected,
                     const wauthn_authenticator_attestation_response_s *actual)
 {
+    if (actual == nullptr && expected == nullptr)
+        return true;
     if (actual == nullptr || expected == nullptr)
-        return (actual == expected);
+        return false;
+    if (actual == expected) // The addresses should be different after deserialization.
+        return false;
     if (__compareWAuthnBuffers(expected->client_data_json, actual->client_data_json) == false)
         return false;
     if (__compareWAuthnBuffers(expected->attestation_object, actual->attestation_object) == false)
@@ -380,26 +217,37 @@ bool __compareWAuthnAuthenticatorAttestationResponseS(
 }
 TEST_F(WAuthnSerializationTest, wauthn_authenticator_attestation_response_s_P)
 {
-    __testSerialization(&TestCommonData::authenticatorAttestationResponse,
-                    __compareWAuthnAuthenticatorAttestationResponseS);
-    __testSerialization(&TestCommonData::emptyAuthenticatorAttestationResponse,
-                    __compareWAuthnAuthenticatorAttestationResponseS);
-    __testSerialization(static_cast<wauthn_authenticator_attestation_response_s *>(nullptr),
-                    __compareWAuthnAuthenticatorAttestationResponseS);
+    AuthenticatorAttestationResponseSerializer data1(
+        &TestCommonData::authenticatorAttestationResponse);
+    AuthenticatorAttestationResponseDeserializer deserializer1;
+    __testSerialization(data1, deserializer1, __compareWAuthnAuthenticatorAttestationResponseS);
 
+    AuthenticatorAttestationResponseSerializer data2(
+        &TestCommonData::emptyAuthenticatorAttestationResponse);
+    AuthenticatorAttestationResponseDeserializer deserializer2;
+    __testSerialization(data2, deserializer2, __compareWAuthnAuthenticatorAttestationResponseS);
+
+    AuthenticatorAttestationResponseSerializer data3(nullptr);
+    AuthenticatorAttestationResponseDeserializer deserializer3;
+    __testSerialization(data3, deserializer3, __compareWAuthnAuthenticatorAttestationResponseS);
 }
 TEST_F(WAuthnSerializationTest, wauthn_bwauthn_authenticator_attestation_response_s_N1)
 {// deserialize: for too large length
-    wauthn_authenticator_attestation_response_s *deserialized = nullptr;
-    __testDeserializeForTooLongLength(deserialized);
+    AuthenticatorAttestationResponseDeserializer deserializer;
+    __testDeserializeForTooLongLength(deserializer);
 }
 
+
 bool __compareWAuthnAuthenticatorAssertionResponseS(
                     const wauthn_authenticator_assertion_response_s *expected,
                     const wauthn_authenticator_assertion_response_s *actual)
 {
+    if (actual == nullptr && expected == nullptr)
+        return true;
     if (actual == nullptr || expected == nullptr)
-        return (actual == expected);
+        return false;
+    if (actual == expected) // The addresses should be different after deserialization.
+        return false;
     if (__compareWAuthnBuffers(expected->client_data_json, actual->client_data_json) == false)
         return false;
     if (__compareWAuthnBuffers(expected->attestation_object, actual->attestation_object) == false)
@@ -414,24 +262,35 @@ bool __compareWAuthnAuthenticatorAssertionResponseS(
 }
 TEST_F(WAuthnSerializationTest, wauthn_authenticator_assertion_response_s_P)
 {
-    __testSerialization(&TestCommonData::authenticatorAssertionResponse,
-                    __compareWAuthnAuthenticatorAssertionResponseS);
-    __testSerialization(&TestCommonData::emptyAuthenticatorAssertionResponse,
-                    __compareWAuthnAuthenticatorAssertionResponseS);
-    __testSerialization(static_cast<wauthn_authenticator_assertion_response_s *>(nullptr),
-                    __compareWAuthnAuthenticatorAssertionResponseS);
+    AuthenticatorAssertionResponseSerializer data1(&TestCommonData::authenticatorAssertionResponse);
+    AuthenticatorAssertionResponseDeserializer deserializer1;
+    __testSerialization(data1, deserializer1, __compareWAuthnAuthenticatorAssertionResponseS);
+
+    AuthenticatorAssertionResponseSerializer data2(
+        &TestCommonData::emptyAuthenticatorAssertionResponse);
+    AuthenticatorAssertionResponseDeserializer deserializer2;
+    __testSerialization(data2, deserializer2, __compareWAuthnAuthenticatorAssertionResponseS);
+
+    AuthenticatorAssertionResponseSerializer data3(nullptr);
+    AuthenticatorAssertionResponseDeserializer deserializer3;
+    __testSerialization(data3, deserializer3, __compareWAuthnAuthenticatorAssertionResponseS);
 }
 TEST_F(WAuthnSerializationTest, wauthn_authenticator_assertion_response_s_N1)
 {// deserialize: for too large length
-    wauthn_authenticator_assertion_response_s *deserialized = nullptr;
-    __testDeserializeForTooLongLength(deserialized);
+    AuthenticatorAssertionResponseDeserializer deserializer;
+    __testDeserializeForTooLongLength(deserializer);
 }
 
+
 bool __compareWAuthnRpEntityS(const wauthn_rp_entity_s *expected,
             const wauthn_rp_entity_s *actual)
 {
+    if (actual == nullptr && expected == nullptr)
+        return true;
     if (actual == nullptr || expected == nullptr)
-        return (actual == expected);
+        return false;
+    if (actual == expected) // The addresses should be different after deserialization.
+        return false;
     if (__compareCstring(expected->name, actual->name) == false)
         return false;
     if (__compareCstring(expected->id, actual->id) == false)
@@ -440,21 +299,34 @@ bool __compareWAuthnRpEntityS(const wauthn_rp_entity_s *expected,
 }
 TEST_F(WAuthnSerializationTest, wauthn_rp_entity_s_P)
 {
-    __testSerialization(&TestCommonData::rpEntity, __compareWAuthnRpEntityS);
-    __testSerialization(&TestCommonData::emptyRpEntity, __compareWAuthnRpEntityS);
-    __testSerialization(static_cast<wauthn_rp_entity_s *>(nullptr), __compareWAuthnRpEntityS);
+    RpEntitySerializer data1(&TestCommonData::rpEntity);
+    RpEntityDeserializer deserializer1;
+    __testSerialization(data1, deserializer1, __compareWAuthnRpEntityS);
+
+    RpEntitySerializer data2(&TestCommonData::emptyRpEntity);
+    RpEntityDeserializer deserializer2;
+    __testSerialization(data2, deserializer2, __compareWAuthnRpEntityS);
+
+    RpEntitySerializer data3(nullptr);
+    RpEntityDeserializer deserializer3;
+    __testSerialization(data3, deserializer3, __compareWAuthnRpEntityS);
 }
 TEST_F(WAuthnSerializationTest, wauthn_rp_entity_s_N1)
 {// deserialize: for too large length
-    wauthn_rp_entity_s *deserialized = nullptr;
-    __testDeserializeForTooLongLength(deserialized);
+    RpEntityDeserializer deserializer;
+    __testDeserializeForTooLongLength(deserializer);
 }
 
+
 bool __compareWAuthnUserEntityS(const wauthn_user_entity_s *expected,
             const wauthn_user_entity_s *actual)
 {
+    if (actual == nullptr && expected == nullptr)
+        return true;
     if (actual == nullptr || expected == nullptr)
-        return (actual == expected);
+        return false;
+    if (actual == expected) // The addresses should be different after deserialization.
+        return false;
     if (__compareCstring(expected->name, actual->name) == false)
         return false;
     if (__compareWAuthnBuffers(expected->id, actual->id) == false)
@@ -465,22 +337,34 @@ bool __compareWAuthnUserEntityS(const wauthn_user_entity_s *expected,
 }
 TEST_F(WAuthnSerializationTest, wauthn_user_entity_s_P)
 {
-    __testSerialization(&TestCommonData::userEntity, __compareWAuthnUserEntityS);
-    __testSerialization(&TestCommonData::emptyUserEntity, __compareWAuthnUserEntityS);
-    __testSerialization(static_cast<wauthn_user_entity_s *>(nullptr), __compareWAuthnUserEntityS);
+    UserEntitySerializer data1(&TestCommonData::userEntity);
+    UserEntityDeserializer deserializer1;
+    __testSerialization(data1, deserializer1, __compareWAuthnUserEntityS);
+
+    UserEntitySerializer data2(&TestCommonData::emptyUserEntity);
+    UserEntityDeserializer deserializer2;
+    __testSerialization(data2, deserializer2, __compareWAuthnUserEntityS);
+
+    UserEntitySerializer data3(nullptr);
+    UserEntityDeserializer deserializer3;
+    __testSerialization(data3, deserializer3, __compareWAuthnUserEntityS);
 }
 TEST_F(WAuthnSerializationTest, wauthn_user_entity_s_N1)
 {// deserialize: for too large length
-    wauthn_user_entity_s *deserialized = nullptr;
-    __testDeserializeForTooLongLength(deserialized);
+    UserEntityDeserializer deserializer;
+    __testDeserializeForTooLongLength(deserializer);
 }
 
 
 bool __compareWAuthnPubkeyCredParamS(const wauthn_pubkey_cred_param_s *expected,
             const wauthn_pubkey_cred_param_s *actual)
 {
+    if (actual == nullptr && expected == nullptr)
+        return true;
     if (actual == nullptr || expected == nullptr)
-        return (actual == expected);
+        return false;
+    if (actual == expected) // The addresses should be different after deserialization.
+        return false;
     if (actual->type != expected->type)
         return false;
     if (actual->alg != expected->alg)
@@ -489,76 +373,112 @@ bool __compareWAuthnPubkeyCredParamS(const wauthn_pubkey_cred_param_s *expected,
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_param_s_P)
 {
-    wauthn_pubkey_cred_param_s data1 = {WAUTHN_PUBKEY_CRED_TYPE_PUBLIC_KEY,
+    wauthn_pubkey_cred_param_s param1 = {WAUTHN_PUBKEY_CRED_TYPE_PUBLIC_KEY,
                                         WAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256};
-    wauthn_pubkey_cred_param_s data2 = {WAUTHN_PUBKEY_CRED_TYPE_PUBLIC_KEY,
+    wauthn_pubkey_cred_param_s param2 = {WAUTHN_PUBKEY_CRED_TYPE_PUBLIC_KEY,
                                         WAUTHN_COSE_ALGORITHM_ECDSA_P521_WITH_SHA512};
 
-    __testSerialization(&data1, __compareWAuthnPubkeyCredParamS);
-    __testSerialization(&data2, __compareWAuthnPubkeyCredParamS);
-    __testSerialization(static_cast<wauthn_pubkey_cred_param_s *>(nullptr), __compareWAuthnPubkeyCredParamS);
+    PubkeyCredParamSerializer data1(&param1);
+    PubkeyCredParamDeserializer deserializer1;
+    __testSerialization(data1, deserializer1, __compareWAuthnPubkeyCredParamS);
+
+    PubkeyCredParamSerializer data2(&param2);
+    PubkeyCredParamDeserializer deserializer2;
+    __testSerialization(data2, deserializer2, __compareWAuthnPubkeyCredParamS);
+
+    PubkeyCredParamSerializer data3(nullptr);
+    PubkeyCredParamDeserializer deserializer3;
+    __testSerialization(data3, deserializer3, __compareWAuthnPubkeyCredParamS);
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_param_s_N1)
 {// serialize: invalid member
-    wauthn_pubkey_cred_param_s data1 = {static_cast<wauthn_pubkey_cred_type_e>(0x00FFFFFF),
+    wauthn_pubkey_cred_param_s param1 = {static_cast<wauthn_pubkey_cred_type_e>(0x00FFFFFF),
                                         WAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256};
-    __testSerializeForInvalidMember(&data1);
-    wauthn_pubkey_cred_param_s data2 = {WAUTHN_PUBKEY_CRED_TYPE_PUBLIC_KEY,
+    PubkeyCredParamSerializer data1(&param1);
+    __testSerializeForInvalidMember(data1);
+
+    wauthn_pubkey_cred_param_s param2 = {WAUTHN_PUBKEY_CRED_TYPE_PUBLIC_KEY,
                                         static_cast<wauthn_cose_algorithm_e>(0x00FFFFFF)};
-    __testSerializeForInvalidMember(&data2);
+    PubkeyCredParamSerializer data2(&param2);
+    __testSerializeForInvalidMember(data2);
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_param_s_N2)
-{// deserialize: for too large length
-    wauthn_pubkey_cred_param_s *deserialized = nullptr;
-    __testDeserializeForTooLongLength(deserialized);
-}
-TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_param_s_N3)
 {// deserialize: for invalid type
-    wauthn_pubkey_cred_param_s data = {static_cast<wauthn_pubkey_cred_type_e>(0x00FFFFFF),
+    wauthn_pubkey_cred_param_s param1 = {static_cast<wauthn_pubkey_cred_type_e>(0x00FFFFFF),
                                             WAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256};
-    __testDeserializeInvalidMember(data);
+    __testDeserializeForInvalidMember<wauthn_pubkey_cred_param_s,
+                                      PubkeyCredParamDeserializer>(param1);
+}
+TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_param_s_N3)
+{// deserialize: for too large length
+    PubkeyCredParamDeserializer deserializer;
+    __testDeserializeForTooLongLength(deserializer);
 }
 
+
 bool __compareWAuthnPubkeyCredParamsS(const wauthn_pubkey_cred_params_s *expected,
             const wauthn_pubkey_cred_params_s *actual)
 {
+    if (actual == nullptr && expected == nullptr)
+        return true;
     if (actual == nullptr || expected == nullptr)
-        return (actual == expected);
+        return false;
+    if (actual == expected) // The addresses should be different after deserialization.
+        return false;
     if (actual->size != expected->size)
         return false;
-    for (size_t i=0; i < expected->size; i++)
-        if(__compareWAuthnPubkeyCredParamS(expected->params + i, expected->params + i) == false)
+    for (size_t i=0; i < expected->size; i++) {
+        if(__compareWAuthnPubkeyCredParamS(expected->params + i, actual->params + i) == false)
             return false;
+    }
     return true;
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_params_s_P)
 {
-    __testSerialization(&TestCommonData::pubkeyCredParams2, __compareWAuthnPubkeyCredParamsS);
-    __testSerialization(&TestCommonData::pubkeyCredParams1, __compareWAuthnPubkeyCredParamsS);
-    __testSerialization(&TestCommonData::emptyPubkeyCredParams, __compareWAuthnPubkeyCredParamsS);
-    __testSerialization(static_cast<wauthn_pubkey_cred_params_s *>(nullptr), __compareWAuthnPubkeyCredParamsS);
+    PubkeyCredParamsSerializer data1(&TestCommonData::pubkeyCredParams1);
+    PubkeyCredParamsDeserializer deserializer1;
+    __testSerialization(data1, deserializer1, __compareWAuthnPubkeyCredParamsS);
+
+    PubkeyCredParamsSerializer data2(&TestCommonData::pubkeyCredParams2);
+    PubkeyCredParamsDeserializer deserializer2;
+    __testSerialization(data2, deserializer2, __compareWAuthnPubkeyCredParamsS);
+
+    PubkeyCredParamsSerializer data3(&TestCommonData::emptyPubkeyCredParams);
+    PubkeyCredParamsDeserializer deserializer3;
+    __testSerialization(data3, deserializer3, __compareWAuthnPubkeyCredParamsS);
+
+    PubkeyCredParamsSerializer data4(nullptr);
+    PubkeyCredParamsDeserializer deserializer4;
+    __testSerialization(data4, deserializer4, __compareWAuthnPubkeyCredParamsS);
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_params_s_N1)
 {// deserialize: for too large length
-    wauthn_pubkey_cred_params_s *deserialized = nullptr;
-    __testDeserializeForTooLongLength(deserialized);
+    PubkeyCredParamsDeserializer deserializer;
+    __testDeserializeForTooLongLength(deserializer);
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_params_s_N2)
 {// deserialize: for too large array count
-    wauthn_pubkey_cred_params_s data = {MAX_ARRAY_COUNT + 1, TestCommonData::pubkeyCredParam2};
-    __testDeserializeInvalidMember(data);
+    wauthn_pubkey_cred_params_s param = {MAX_ARRAY_COUNT + 1, TestCommonData::pubkeyCredParam2};
+    __testDeserializeForInvalidMember<wauthn_pubkey_cred_params_s,
+                                      PubkeyCredParamsDeserializer>(param);
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_params_s_N3)
 {// deserialize: for invalid array count
-    wauthn_pubkey_cred_params_s data = {3, nullptr};
-    __testDeserializeInvalidMember(data);
+    wauthn_pubkey_cred_params_s param = {3, nullptr};
+    __testDeserializeForInvalidMember<wauthn_pubkey_cred_params_s,
+                                      PubkeyCredParamsDeserializer>(param);
 }
 
+
 bool __compareWAuthnPubkeyCredDescriptorS(const wauthn_pubkey_cred_descriptor_s *expected,
             const wauthn_pubkey_cred_descriptor_s *actual)
 {
+    if (actual == nullptr && expected == nullptr)
+        return true;
     if (actual == nullptr || expected == nullptr)
-        return (actual == expected);
+        return false;
+    if (actual == expected) // The addresses should be different after deserialization.
+        return false;
     if (actual->type != expected->type)
         return false;
     if (__compareWAuthnBuffers(actual->id, expected->id) == false)
@@ -569,69 +489,103 @@ bool __compareWAuthnPubkeyCredDescriptorS(const wauthn_pubkey_cred_descriptor_s
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_descriptor_s_P)
 {
-    __testSerialization(&TestCommonData::pubkeyCredDescriptor, __compareWAuthnPubkeyCredDescriptorS);
-    __testSerialization(&TestCommonData::emptyPubkeyCredDescriptor, __compareWAuthnPubkeyCredDescriptorS);
-    __testSerialization(static_cast<wauthn_pubkey_cred_descriptor_s *>(nullptr), __compareWAuthnPubkeyCredDescriptorS);
+    PubkeyCredDescriptorSerializer data1(&TestCommonData::pubkeyCredDescriptor);
+    PubkeyCredDescriptorDeserializer deserializer1;
+    __testSerialization(data1, deserializer1, __compareWAuthnPubkeyCredDescriptorS);
+
+    PubkeyCredDescriptorSerializer data2(&TestCommonData::emptyPubkeyCredDescriptor);
+    PubkeyCredDescriptorDeserializer deserializer2;
+    __testSerialization(data2, deserializer2, __compareWAuthnPubkeyCredDescriptorS);
+
+    PubkeyCredDescriptorSerializer data3(nullptr);
+    PubkeyCredDescriptorDeserializer deserializer3;
+    __testSerialization(data3, deserializer3, __compareWAuthnPubkeyCredDescriptorS);
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_descriptor_s_N1)
 {// serialize: invalid member
     wauthn_pubkey_cred_descriptor_s data = TestCommonData::pubkeyCredDescriptor;
     data.type = static_cast<wauthn_pubkey_cred_type_e>(0x00FFFFFF);
-    __testSerializeForInvalidMember(&data);
+    __testDeserializeForInvalidMember<wauthn_pubkey_cred_descriptor_s,
+                                      PubkeyCredDescriptorDeserializer>(data);
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_descriptor_s_N2)
 {// deserialize: for too large length
-    wauthn_pubkey_cred_descriptor_s *deserialized = nullptr;
-    __testDeserializeForTooLongLength(deserialized);
+    PubkeyCredDescriptorDeserializer deserializer;
+    __testDeserializeForTooLongLength(deserializer);
+}
+TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_descriptor_s_N3)
+{// deserialize: for invalid type
+    wauthn_pubkey_cred_descriptor_s data = {static_cast<wauthn_pubkey_cred_type_e>(0x00FFFFFF),
+                                            &TestCommonData::clientDataJson, 3};
+    __testDeserializeForInvalidMember<wauthn_pubkey_cred_descriptor_s,
+                                      PubkeyCredDescriptorDeserializer>(data);
 }
 
+
 bool __compareWAuthnPubkeyCredDescriptorsS(const wauthn_pubkey_cred_descriptors_s *expected,
             const wauthn_pubkey_cred_descriptors_s *actual)
 {
+    if (actual == nullptr && expected == nullptr)
+        return true;
     if (actual == nullptr || expected == nullptr)
-        return (actual == expected);
+        return false;
+    if (actual == expected) // The addresses should be different after deserialization.
+        return false;
     if (actual->size != expected->size)
         return false;
     for (size_t i=0; i < expected->size; i++)
-        if(__compareWAuthnPubkeyCredDescriptorS(expected->descriptors + i, expected->descriptors + i) == false)
+        if (__compareWAuthnPubkeyCredDescriptorS(expected->descriptors + i,
+                                                 actual->descriptors + i) == false)
             return false;
     return true;
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_descriptors_s_P)
 {
-    __testSerialization(&TestCommonData::pubkeyCredDescriptors2, __compareWAuthnPubkeyCredDescriptorsS);
-    __testSerialization(&TestCommonData::pubkeyCredDescriptors1, __compareWAuthnPubkeyCredDescriptorsS);
-    __testSerialization(&TestCommonData::emptyPubkeyCredDescriptors, __compareWAuthnPubkeyCredDescriptorsS);
-    __testSerialization(static_cast<wauthn_pubkey_cred_descriptors_s *>(nullptr), __compareWAuthnPubkeyCredDescriptorsS);
+    PubkeyCredDescriptorsSerializer data1(&TestCommonData::pubkeyCredDescriptors1);
+    PubkeyCredDescriptorsDeserializer deserializer1;
+    __testSerialization(data1, deserializer1, __compareWAuthnPubkeyCredDescriptorsS);
+
+    PubkeyCredDescriptorsSerializer data2(&TestCommonData::pubkeyCredDescriptors2);
+    PubkeyCredDescriptorsDeserializer deserializer2;
+    __testSerialization(data2, deserializer2, __compareWAuthnPubkeyCredDescriptorsS);
+
+    PubkeyCredDescriptorsSerializer data3(&TestCommonData::emptyPubkeyCredDescriptors);
+    PubkeyCredDescriptorsDeserializer deserializer3;
+    __testSerialization(data3, deserializer3, __compareWAuthnPubkeyCredDescriptorsS);
+
+    PubkeyCredDescriptorsSerializer data4(nullptr);
+    PubkeyCredDescriptorsDeserializer deserializer4;
+    __testSerialization(data4, deserializer4, __compareWAuthnPubkeyCredDescriptorsS);
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_descriptors_s_N1)
 {// deserialize: for too large length
-    wauthn_pubkey_cred_descriptors_s *deserialized = nullptr;
-    __testDeserializeForTooLongLength(deserialized);
+    PubkeyCredDescriptorsDeserializer deserializer;
+    __testDeserializeForTooLongLength(deserializer);
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_descriptors_s_N2)
 {// deserialize: for too large array count
-    wauthn_pubkey_cred_descriptors_s data = {MAX_ARRAY_COUNT + 1, TestCommonData::pubkeyCredDescriptor2};
-    __testDeserializeInvalidMember(data);
+    wauthn_pubkey_cred_descriptors_s data = {MAX_ARRAY_COUNT + 1,
+                                             TestCommonData::pubkeyCredDescriptor2};
+    __testDeserializeForInvalidMember<wauthn_pubkey_cred_descriptors_s,
+                                      PubkeyCredDescriptorsDeserializer>(data);
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_descriptors_s_N3)
 {// deserialize: for inconsistent pointer & size
     wauthn_pubkey_cred_descriptors_s data = {3, nullptr};
-    __testDeserializeInvalidMember(data);
-}
-TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_descriptors_s_N4)
-{// deserialize: for invalid type
-    wauthn_pubkey_cred_descriptor_s data = {static_cast<wauthn_pubkey_cred_type_e>(0x00FFFFFF),
-                                            &TestCommonData::clientDataJson, 3};
-    __testDeserializeInvalidMember(data);
+    __testDeserializeForInvalidMember<wauthn_pubkey_cred_descriptors_s,
+                                      PubkeyCredDescriptorsDeserializer>(data);
 }
 
 
 bool __compareWAuthnAuthenticationExtS(const wauthn_authentication_ext_s *expected,
             const wauthn_authentication_ext_s *actual)
 {
+    if (actual == nullptr && expected == nullptr)
+        return true;
     if (actual == nullptr || expected == nullptr)
-        return (actual == expected);
+        return false;
+    if (actual == expected) // The addresses should be different after deserialization.
+        return false;
     if (__compareWAuthnBuffers(actual->extension_id, expected->extension_id) == false)
         return false;
     if (__compareWAuthnBuffers(actual->extension_value, expected->extension_value) == false)
@@ -640,56 +594,89 @@ bool __compareWAuthnAuthenticationExtS(const wauthn_authentication_ext_s *expect
 }
 TEST_F(WAuthnSerializationTest, wauthn_authentication_ext_s_P)
 {
-    __testSerialization(&TestCommonData::authenticationExt, __compareWAuthnAuthenticationExtS);
-    __testSerialization(&TestCommonData::emptyAuthenticationExt, __compareWAuthnAuthenticationExtS);
-    __testSerialization(static_cast<wauthn_authentication_ext_s *>(nullptr), __compareWAuthnAuthenticationExtS);
+    AuthenticationExtSerializer data1(&TestCommonData::authenticationExt);
+    AuthenticationExtDeserializer deserializer1;
+    __testSerialization(data1, deserializer1, __compareWAuthnAuthenticationExtS);
+
+    AuthenticationExtSerializer data2(&TestCommonData::emptyAuthenticationExt);
+    AuthenticationExtDeserializer deserializer2;
+    __testSerialization(data2, deserializer2, __compareWAuthnAuthenticationExtS);
+
+    AuthenticationExtSerializer data3(nullptr);
+    AuthenticationExtDeserializer deserializer3;
+    __testSerialization(data3, deserializer3, __compareWAuthnAuthenticationExtS);
 }
 TEST_F(WAuthnSerializationTest, wauthn_authentication_ext_s_N1)
 {// deserialize: for too large length
-    wauthn_authentication_ext_s *deserialized = nullptr;
-    __testDeserializeForTooLongLength(deserialized);
+    AuthenticationExtDeserializer deserializer;
+    __testDeserializeForTooLongLength(deserializer);
 }
 
+
 bool __compareWAuthnAuthenticationExtsS(const wauthn_authentication_exts_s *expected,
             const wauthn_authentication_exts_s *actual)
 {
+    if (actual == nullptr && expected == nullptr)
+        return true;
     if (actual == nullptr || expected == nullptr)
-        return (actual == expected);
+        return false;
+    if (actual == expected) // The addresses should be different after deserialization.
+        return false;
     if (actual->size != expected->size)
         return false;
     for (size_t i=0; i < expected->size; i++)
-        if(__compareWAuthnAuthenticationExtS(expected->extensions + i, expected->extensions + i) == false)
+        if(__compareWAuthnAuthenticationExtS(expected->extensions + i,
+                                             actual->extensions + i) == false)
             return false;
     return true;
 }
 TEST_F(WAuthnSerializationTest, wauthn_authentication_exts_s_P)
 {
-    __testSerialization(&TestCommonData::authenticationExts1, __compareWAuthnAuthenticationExtsS);
-    __testSerialization(&TestCommonData::authenticationExts2, __compareWAuthnAuthenticationExtsS);
-    __testSerialization(&TestCommonData::emptyAuthenticationExts, __compareWAuthnAuthenticationExtsS);
-    __testSerialization(static_cast<wauthn_authentication_exts_s *>(nullptr), __compareWAuthnAuthenticationExtsS);
+    AuthenticationExtsSerializer data1(&TestCommonData::authenticationExts1);
+    AuthenticationExtsDeserializer deserializer1;
+    __testSerialization(data1, deserializer1, __compareWAuthnAuthenticationExtsS);
+
+    AuthenticationExtsSerializer data2(&TestCommonData::authenticationExts2);
+    AuthenticationExtsDeserializer deserializer2;
+    __testSerialization(data2, deserializer2, __compareWAuthnAuthenticationExtsS);
+
+    AuthenticationExtsSerializer data3(&TestCommonData::emptyAuthenticationExts);
+    AuthenticationExtsDeserializer deserializer3;
+    __testSerialization(data3, deserializer3, __compareWAuthnAuthenticationExtsS);
+
+    AuthenticationExtsSerializer data4(nullptr);
+    AuthenticationExtsDeserializer deserializer4;
+    __testSerialization(data4, deserializer4, __compareWAuthnAuthenticationExtsS);
 }
 TEST_F(WAuthnSerializationTest, wauthn_authentication_exts_s_N1)
 {// deserialize: for too large length
-    wauthn_authentication_exts_s *deserialized = nullptr;
-    __testDeserializeForTooLongLength(deserialized);
+    AuthenticationExtsDeserializer deserializer;
+    __testDeserializeForTooLongLength(deserializer);
 }
 TEST_F(WAuthnSerializationTest, wauthn_authentication_exts_s_N2)
 {// deserialize: for too large array count
-    wauthn_authentication_exts_s data = {MAX_ARRAY_COUNT + 1, TestCommonData::authenticationExtArr2};
-    __testDeserializeInvalidMember(data);
+    wauthn_authentication_exts_s data = {MAX_ARRAY_COUNT + 1,
+                                         TestCommonData::authenticationExtArr2};
+    __testDeserializeForInvalidMember<wauthn_authentication_exts_s,
+                                      AuthenticationExtsDeserializer>(data);
 }
 TEST_F(WAuthnSerializationTest, wauthn_authentication_exts_s_N3)
 {// deserialize: for inconsistent pointer & size
     wauthn_authentication_exts_s data = {3, nullptr};
-    __testDeserializeInvalidMember(data);
+    __testDeserializeForInvalidMember<wauthn_authentication_exts_s,
+                                      AuthenticationExtsDeserializer>(data);
 }
 
+
 bool __compareWAuthnAuthenticatorSelCriS(const wauthn_authenticator_sel_cri_s *expected,
             const wauthn_authenticator_sel_cri_s *actual)
 {
+    if (actual == nullptr && expected == nullptr)
+        return true;
     if (actual == nullptr || expected == nullptr)
-        return (actual == expected);
+        return false;
+    if (actual == expected) // The addresses should be different after deserialization.
+        return false;
     if (actual->attachment != expected->attachment)
         return false;
     if (actual->resident_key != expected->resident_key)
@@ -702,57 +689,74 @@ bool __compareWAuthnAuthenticatorSelCriS(const wauthn_authenticator_sel_cri_s *e
 }
 TEST_F(WAuthnSerializationTest, wauthn_authenticator_sel_cri_s_P)
 {
-    __testSerialization(&TestCommonData::authenticatorSelCri, __compareWAuthnAuthenticatorSelCriS);
-    __testSerialization(static_cast<wauthn_authenticator_sel_cri_s *>(nullptr), __compareWAuthnAuthenticatorSelCriS);
+    AuthenticatorSelCriSerializer data1(&TestCommonData::authenticatorSelCri);
+    AuthenticatorSelCriDeserializer deserializer1;
+    __testSerialization(data1, deserializer1, __compareWAuthnAuthenticatorSelCriS);
+
+    AuthenticatorSelCriSerializer data2(nullptr);
+    AuthenticatorSelCriDeserializer deserializer2;
+    __testSerialization(data2, deserializer2, __compareWAuthnAuthenticatorSelCriS);
 }
 TEST_F(WAuthnSerializationTest, wauthn_authenticator_sel_cri_s_N1)
 {// serialize: invalid member
     wauthn_authenticator_sel_cri_s data1 = TestCommonData::authenticatorSelCri;
     data1.attachment = static_cast<wauthn_authenticator_attachment_e>(0x00FFFFFF);
-    __testSerializeForInvalidMember(&data1);
+    __testDeserializeForInvalidMember<wauthn_authenticator_sel_cri_s,
+                                      AuthenticatorSelCriDeserializer>(data1);
+
     wauthn_authenticator_sel_cri_s data2 = TestCommonData::authenticatorSelCri;
     data2.resident_key = static_cast<wauthn_resident_key_requirement_e>(0x00FFFFFF);
-    __testSerializeForInvalidMember(&data2);
+    __testDeserializeForInvalidMember<wauthn_authenticator_sel_cri_s,
+                                      AuthenticatorSelCriDeserializer>(data2);
+
     wauthn_authenticator_sel_cri_s data3 = TestCommonData::authenticatorSelCri;
     data3.user_verification = static_cast<wauthn_user_verification_requirement_e>(0x00FFFFFF);
-    __testSerializeForInvalidMember(&data3);
+    __testDeserializeForInvalidMember<wauthn_authenticator_sel_cri_s,
+                                      AuthenticatorSelCriDeserializer>(data3);
 }
 TEST_F(WAuthnSerializationTest, wauthn_authenticator_sel_cri_s_N2)
-{// deserialize: for too large length
-    wauthn_authenticator_sel_cri_s *deserialized = nullptr;
-    __testDeserializeForTooLongLength(deserialized);
-}
-TEST_F(WAuthnSerializationTest, wauthn_authenticator_sel_cri_s_N3)
 {// deserialize: for invalid attachment
     wauthn_authenticator_sel_cri_s data = {static_cast<wauthn_authenticator_attachment_e>(0x00FFFFFF),
                                 WAUTHN_RESIDENT_KEY_REQUIREMENT_DISCOURAGED,
                                 false,
                                 WAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED};
-    __testDeserializeInvalidMember(data);
+    __testDeserializeForInvalidMember<wauthn_authenticator_sel_cri_s,
+                                      AuthenticatorSelCriDeserializer>(data);
 }
-TEST_F(WAuthnSerializationTest, wauthn_authenticator_sel_cri_s_N4)
+TEST_F(WAuthnSerializationTest, wauthn_authenticator_sel_cri_s_N3)
 {// deserialize: for invalid resident_key
     wauthn_authenticator_sel_cri_s data = {WAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM,
                                 static_cast<wauthn_resident_key_requirement_e>(0x00FFFFFF),
                                 false,
                                 WAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED};
-    __testDeserializeInvalidMember(data);
+    __testDeserializeForInvalidMember<wauthn_authenticator_sel_cri_s,
+                                      AuthenticatorSelCriDeserializer>(data);
 }
-TEST_F(WAuthnSerializationTest, wauthn_authenticator_sel_cri_s_N5)
+TEST_F(WAuthnSerializationTest, wauthn_authenticator_sel_cri_s_N4)
 {// deserialize: for invalid user_verification
     wauthn_authenticator_sel_cri_s data = {WAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM,
                                 WAUTHN_RESIDENT_KEY_REQUIREMENT_DISCOURAGED,
                                 false,
                                 static_cast<wauthn_user_verification_requirement_e>(0x00FFFFFF)};
-    __testDeserializeInvalidMember(data);
+    __testDeserializeForInvalidMember<wauthn_authenticator_sel_cri_s,
+                                      AuthenticatorSelCriDeserializer>(data);
+}
+TEST_F(WAuthnSerializationTest, wauthn_authenticator_sel_cri_s_N5)
+{// deserialize: for too large length
+    AuthenticatorSelCriDeserializer deserializer;
+    __testDeserializeForTooLongLength(deserializer);
 }
 
 
 bool __compareWAuthnPubkeyCredHintE(const wauthn_pubkey_cred_hint_e *expected,
             const wauthn_pubkey_cred_hint_e *actual)
 {
+    if (actual == nullptr && expected == nullptr)
+        return true;
     if (actual == nullptr || expected == nullptr)
-        return (actual == expected);
+        return false;
+    if (actual == expected) // The addresses should be different after deserialization.
+        return false;
     if (*actual != *expected)
         return false;
     return true;
@@ -760,56 +764,79 @@ bool __compareWAuthnPubkeyCredHintE(const wauthn_pubkey_cred_hint_e *expected,
 bool __compareWAuthnPubkeyCredHintsE(const wauthn_pubkey_cred_hints_s *expected,
             const wauthn_pubkey_cred_hints_s *actual)
 {
+    if (actual == nullptr && expected == nullptr)
+        return true;
     if (actual == nullptr || expected == nullptr)
-        return (actual == expected);
+        return false;
+    if (actual == expected) // The addresses should be different after deserialization.
+        return false;
     if (actual->size != expected->size)
         return false;
     for (size_t i=0; i < expected->size; i++)
-        if(__compareWAuthnPubkeyCredHintE(expected->hints + i, expected->hints + i) == false)
+        if(__compareWAuthnPubkeyCredHintE(expected->hints + i, actual->hints + i) == false)
             return false;
     return true;
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_hints_s_P)
 {
-    __testSerialization(&TestCommonData::pubkeyCredHints1, __compareWAuthnPubkeyCredHintsE);
-    __testSerialization(&TestCommonData::pubkeyCredHints2, __compareWAuthnPubkeyCredHintsE);
-    __testSerialization(&TestCommonData::emptyPubkeyCredHints, __compareWAuthnPubkeyCredHintsE);
-    __testSerialization(static_cast<wauthn_pubkey_cred_hints_s *>(nullptr), __compareWAuthnPubkeyCredHintsE);
+    PubkeyCredHintsSerializer data1(&TestCommonData::pubkeyCredHints1);
+    PubkeyCredHintsDeserializer deserializer1;
+    __testSerialization(data1, deserializer1, __compareWAuthnPubkeyCredHintsE);
+
+    PubkeyCredHintsSerializer data2(&TestCommonData::pubkeyCredHints2);
+    PubkeyCredHintsDeserializer deserializer2;
+    __testSerialization(data2, deserializer2, __compareWAuthnPubkeyCredHintsE);
+
+    PubkeyCredHintsSerializer data3(&TestCommonData::emptyPubkeyCredHints);
+    PubkeyCredHintsDeserializer deserializer3;
+    __testSerialization(data3, deserializer3, __compareWAuthnPubkeyCredHintsE);
+
+    PubkeyCredHintsSerializer data4(nullptr);
+    PubkeyCredHintsDeserializer deserializer4;
+    __testSerialization(data4, deserializer4, __compareWAuthnPubkeyCredHintsE);
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_hints_s_N1)
 {// deserialize: for too large length
-    wauthn_pubkey_cred_hints_s *deserialized = nullptr;
-    __testDeserializeForTooLongLength(deserialized);
+    PubkeyCredHintsDeserializer deserializer;
+    __testDeserializeForTooLongLength(deserializer);
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_hints_s_N2)
 {// deserialize: for too large array count
     wauthn_pubkey_cred_hints_s data = {MAX_ARRAY_COUNT + 1, TestCommonData::pubkeyCredHint2};
-    __testDeserializeInvalidMember(data);
+    __testDeserializeForInvalidMember<wauthn_pubkey_cred_hints_s,
+                                      PubkeyCredHintsDeserializer>(data);
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_hints_s_N3)
 {// deserialize: for inconsistent pointer & size
     wauthn_pubkey_cred_hints_s data = {3, nullptr};
-    __testDeserializeInvalidMember(data);
+    __testDeserializeForInvalidMember<wauthn_pubkey_cred_hints_s,
+                                      PubkeyCredHintsDeserializer>(data);
 }
 
 bool __compareWAuthnHybridLinkedDataS(const wauthn_hybrid_linked_data_s *expected,
             const wauthn_hybrid_linked_data_s *actual)
 {
+    if (actual == nullptr && expected == nullptr)
+        return true;
     if (actual == nullptr || expected == nullptr)
-        return (actual == expected);
+        return false;
+    if (actual == expected) // The addresses should be different after deserialization.
+        return false;
     if (__compareWAuthnBuffers(actual->contact_id, expected->contact_id) == false)
         return false;
     if (__compareWAuthnBuffers(actual->link_id, expected->link_id) == false)
         return false;
     if (__compareWAuthnBuffers(actual->link_secret, expected->link_secret) == false)
         return false;
-    if (__compareWAuthnBuffers(actual->authenticator_pubkey, expected->authenticator_pubkey) == false)
+    if (__compareWAuthnBuffers(actual->authenticator_pubkey,
+                               expected->authenticator_pubkey) == false)
         return false;
     if (__compareWAuthnBuffers(actual->authenticator_name, expected->authenticator_name) == false)
         return false;
     if (__compareWAuthnBuffers(actual->signature, expected->signature) == false)
         return false;
-    if (__compareWAuthnBuffers(actual->tunnel_server_domain, expected->tunnel_server_domain) == false)
+    if (__compareWAuthnBuffers(actual->tunnel_server_domain,
+                               expected->tunnel_server_domain) == false)
         return false;
     if (__compareWAuthnBuffers(actual->identity_key, expected->identity_key) == false)
         return false;
@@ -817,21 +844,34 @@ bool __compareWAuthnHybridLinkedDataS(const wauthn_hybrid_linked_data_s *expecte
 }
 TEST_F(WAuthnSerializationTest, wauthn_hybrid_linked_data_s_P)
 {
-    __testSerialization(&TestCommonData::hybridLinkedData, __compareWAuthnHybridLinkedDataS);
-    __testSerialization(&TestCommonData::emptyHybridLinkedData, __compareWAuthnHybridLinkedDataS);
-    __testSerialization(static_cast<wauthn_hybrid_linked_data_s *>(nullptr), __compareWAuthnHybridLinkedDataS);
+    HybridLinkedDataSerializer data1(&TestCommonData::hybridLinkedData);
+    HybridLinkedDataDeserializer deserializer1;
+    __testSerialization(data1, deserializer1, __compareWAuthnHybridLinkedDataS);
+
+    HybridLinkedDataSerializer data2(&TestCommonData::emptyHybridLinkedData);
+    HybridLinkedDataDeserializer deserializer2;
+    __testSerialization(data2, deserializer2, __compareWAuthnHybridLinkedDataS);
+
+    HybridLinkedDataSerializer data3(nullptr);
+    HybridLinkedDataDeserializer deserializer3;
+    __testSerialization(data3, deserializer3, __compareWAuthnHybridLinkedDataS);
 }
 TEST_F(WAuthnSerializationTest, wauthn_hybrid_linked_data_s_N1)
 {// deserialize: for too large length
-    wauthn_hybrid_linked_data_s *deserialized = nullptr;
-    __testDeserializeForTooLongLength(deserialized);
+    HybridLinkedDataDeserializer deserializer;
+    __testDeserializeForTooLongLength(deserializer);
 }
 
+
 bool __compareWAuthnAttestationFormatsS(const wauthn_attestation_formats_s *expected,
             const wauthn_attestation_formats_s *actual)
 {
+    if (actual == nullptr && expected == nullptr)
+        return true;
     if (actual == nullptr || expected == nullptr)
-        return (actual == expected);
+        return false;
+    if (actual == expected) // The addresses should be different after deserialization.
+        return false;
     if (actual->size != expected->size)
         return false;
     for (size_t i=0; i < expected->size; i++)
@@ -842,49 +882,70 @@ bool __compareWAuthnAttestationFormatsS(const wauthn_attestation_formats_s *expe
 }
 TEST_F(WAuthnSerializationTest, wauthn_attestation_formats_s_P)
 {
-    __testSerialization(&TestCommonData::attestationFormats1, __compareWAuthnAttestationFormatsS);
-    __testSerialization(&TestCommonData::attestationFormats2, __compareWAuthnAttestationFormatsS);
-    __testSerialization(&TestCommonData::emptyAttestationFormats, __compareWAuthnAttestationFormatsS);
-    __testSerialization(static_cast<wauthn_attestation_formats_s *>(nullptr), __compareWAuthnAttestationFormatsS);
+    AttestationFormatsSerializer data1(&TestCommonData::attestationFormats1);
+    AttestationFormatsDeserializer deserializer1;
+    __testSerialization(data1, deserializer1, __compareWAuthnAttestationFormatsS);
+
+    AttestationFormatsSerializer data2(&TestCommonData::attestationFormats2);
+    AttestationFormatsDeserializer deserializer2;
+    __testSerialization(data2, deserializer2, __compareWAuthnAttestationFormatsS);
+
+    AttestationFormatsSerializer data3(&TestCommonData::emptyAttestationFormats);
+    AttestationFormatsDeserializer deserializer3;
+    __testSerialization(data3, deserializer3, __compareWAuthnAttestationFormatsS);
+
+    AttestationFormatsSerializer data4(nullptr);
+    AttestationFormatsDeserializer deserializer4;
+    __testSerialization(data4, deserializer4, __compareWAuthnAttestationFormatsS);
 }
 TEST_F(WAuthnSerializationTest, wauthn_attestation_formats_s_N1)
 {// deserialize: for too large length
-    wauthn_attestation_formats_s *deserialized = nullptr;
-    __testDeserializeForTooLongLength(deserialized);
+    AttestationFormatsDeserializer deserializer;
+    __testDeserializeForTooLongLength(deserializer);
 }
 TEST_F(WAuthnSerializationTest, wauthn_attestation_formats_s_N2)
 {// deserialize: for too large array count
     wauthn_attestation_formats_s data = {MAX_ARRAY_COUNT + 1, TestCommonData::attestationFormat2};
-    __testDeserializeInvalidMember(data);
+    __testDeserializeForInvalidMember<wauthn_attestation_formats_s,
+                                      AttestationFormatsDeserializer>(data);
 }
 TEST_F(WAuthnSerializationTest, wauthn_attestation_formats_s_N3)
 {// deserialize: for inconsistent pointer & size
     wauthn_attestation_formats_s data = {3, nullptr};
-    __testDeserializeInvalidMember(data);
+    __testDeserializeForInvalidMember<wauthn_attestation_formats_s,
+                                      AttestationFormatsDeserializer>(data);
 }
 
 bool __compareWAuthnPubkeyCredCreationOptionsS(const wauthn_pubkey_cred_creation_options_s *expected,
             const wauthn_pubkey_cred_creation_options_s *actual)
 {
+    if (actual == nullptr && expected == nullptr)
+        return true;
     if (actual == nullptr || expected == nullptr)
-        return (actual == expected);
+        return false;
+    if (actual == expected) // The addresses should be different after deserialization.
+        return false;
     if(__compareWAuthnRpEntityS(expected->rp, actual->rp) == false)
         return false;
     if(__compareWAuthnUserEntityS(expected->user, actual->user) == false)
         return false;
-    if(__compareWAuthnPubkeyCredParamsS(expected->pubkey_cred_params, actual->pubkey_cred_params) == false)
+    if(__compareWAuthnPubkeyCredParamsS(expected->pubkey_cred_params,
+                                        actual->pubkey_cred_params) == false)
         return false;
     if (expected->timeout != actual->timeout)
         return false;
-    if(__compareWAuthnPubkeyCredDescriptorsS(expected->exclude_credentials, actual->exclude_credentials) == false)
+    if(__compareWAuthnPubkeyCredDescriptorsS(expected->exclude_credentials,
+                                             actual->exclude_credentials) == false)
         return false;
-    if(__compareWAuthnAuthenticatorSelCriS(expected->authenticator_selection, actual->authenticator_selection) == false)
+    if(__compareWAuthnAuthenticatorSelCriS(expected->authenticator_selection,
+                                           actual->authenticator_selection) == false)
         return false;
     if(__compareWAuthnPubkeyCredHintsE(expected->hints, actual->hints) == false)
         return false;
     if (expected->attestation != actual->attestation)
         return false;
-    if(__compareWAuthnAttestationFormatsS(expected->attestation_formats, actual->attestation_formats) == false)
+    if(__compareWAuthnAttestationFormatsS(expected->attestation_formats,
+                                          actual->attestation_formats) == false)
         return false;
     if(__compareWAuthnAuthenticationExtsS(expected->extensions, actual->extensions) == false)
         return false;
@@ -894,42 +955,47 @@ bool __compareWAuthnPubkeyCredCreationOptionsS(const wauthn_pubkey_cred_creation
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_creation_options_s_P)
 {
-    __testSerialization(&TestCommonData::pubkeyCredCreationOptions,
-                __compareWAuthnPubkeyCredCreationOptionsS);
-    __testSerialization(&TestCommonData::emptyPubkeyCredCreationOptions,
-                __compareWAuthnPubkeyCredCreationOptionsS);
-    __testSerialization(static_cast<wauthn_pubkey_cred_creation_options_s *>(nullptr),
-                __compareWAuthnPubkeyCredCreationOptionsS);
+    PubKeyCredCreationOptionsSerializer data1(&TestCommonData::pubkeyCredCreationOptions);
+    PubKeyCredCreationOptionsDeserializer deserializer1;
+    __testSerialization(data1, deserializer1, __compareWAuthnPubkeyCredCreationOptionsS);
+
+    PubKeyCredCreationOptionsSerializer data2(&TestCommonData::emptyPubkeyCredCreationOptions);
+    PubKeyCredCreationOptionsDeserializer deserializer2;
+    __testSerialization(data2, deserializer2, __compareWAuthnPubkeyCredCreationOptionsS);
+
+    PubKeyCredCreationOptionsSerializer data3(nullptr);
+    PubKeyCredCreationOptionsDeserializer deserializer3;
+    __testSerialization(data3, deserializer3, __compareWAuthnPubkeyCredCreationOptionsS);
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_creation_options_s_N1)
-{// serialize: invalid member
-    wauthn_pubkey_cred_creation_options_s data = TestCommonData::pubkeyCredCreationOptions;
-    data.attestation = static_cast<wauthn_attestation_pref_e>(0x00FFFFFF);
-    __testSerializeForInvalidMember(&data);
-}
-TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_creation_options_s_N2)
 {// deserialize: for too large length
-    wauthn_pubkey_cred_creation_options_s *deserialized = nullptr;
-    __testDeserializeForTooLongLength(deserialized);
+    PubKeyCredCreationOptionsDeserializer deserializer;
+    __testDeserializeForTooLongLength(deserializer);
 }
-TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_creation_options_s_N3)
-{// deserialize: for invalid attestation
+TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_creation_options_s_N2)
+{// serialize: invalid member
     wauthn_pubkey_cred_creation_options_s data = TestCommonData::pubkeyCredCreationOptions;
     data.attestation = static_cast<wauthn_attestation_pref_e>(0x00FFFFFF);
-    __testDeserializeInvalidMember(data);
+    __testDeserializeForInvalidMember<wauthn_pubkey_cred_creation_options_s,
+                                      PubKeyCredCreationOptionsDeserializer>(data);
 }
 
 
 bool __compareWAuthnPubkeyCredRequestOptionsS(const wauthn_pubkey_cred_request_options_s *expected,
             const wauthn_pubkey_cred_request_options_s *actual)
 {
+    if (actual == nullptr && expected == nullptr)
+        return true;
     if (actual == nullptr || expected == nullptr)
-        return (actual == expected);
+        return false;
+    if (actual == expected) // The addresses should be different after deserialization.
+        return false;
     if (expected->timeout != actual->timeout)
         return false;
     if(__compareCstring(expected->rpId, actual->rpId) == false)
         return false;
-    if(__compareWAuthnPubkeyCredDescriptorsS(expected->allow_credentials, actual->allow_credentials) == false)
+    if(__compareWAuthnPubkeyCredDescriptorsS(expected->allow_credentials,
+                                             actual->allow_credentials) == false)
         return false;
     if (expected->user_verification != actual->user_verification)
         return false;
@@ -937,7 +1003,8 @@ bool __compareWAuthnPubkeyCredRequestOptionsS(const wauthn_pubkey_cred_request_o
         return false;
     if (expected->attestation != actual->attestation)
         return false;
-    if(__compareWAuthnAttestationFormatsS(expected->attestation_formats, actual->attestation_formats) == false)
+    if(__compareWAuthnAttestationFormatsS(expected->attestation_formats,
+                                          actual->attestation_formats) == false)
         return false;
     if(__compareWAuthnAuthenticationExtsS(expected->extensions, actual->extensions) == false)
         return false;
@@ -947,51 +1014,55 @@ bool __compareWAuthnPubkeyCredRequestOptionsS(const wauthn_pubkey_cred_request_o
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_request_options_s_P)
 {
-    __testSerialization(&TestCommonData::pubkeyCredRequestOptions,
-                __compareWAuthnPubkeyCredRequestOptionsS);
-    __testSerialization(&TestCommonData::emptyPubkeyCredRequestOptions,
-                __compareWAuthnPubkeyCredRequestOptionsS);
-    __testSerialization(static_cast<wauthn_pubkey_cred_request_options_s *>(nullptr),
-                __compareWAuthnPubkeyCredRequestOptionsS);
+    PubKeyCredRequestOptionsSerializer data1(&TestCommonData::pubkeyCredRequestOptions);
+    PubKeyCredRequestOptionsDeserializer deserializer1;
+    __testSerialization(data1, deserializer1, __compareWAuthnPubkeyCredRequestOptionsS);
+
+    PubKeyCredRequestOptionsSerializer data2(&TestCommonData::emptyPubkeyCredRequestOptions);
+    PubKeyCredRequestOptionsDeserializer deserializer2;
+    __testSerialization(data2, deserializer2, __compareWAuthnPubkeyCredRequestOptionsS);
+
+    PubKeyCredRequestOptionsSerializer data3(nullptr);
+    PubKeyCredRequestOptionsDeserializer deserializer3;
+    __testSerialization(data3, deserializer3, __compareWAuthnPubkeyCredRequestOptionsS);
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_request_options_s_N1)
 {// serialize: invalid member
-    wauthn_pubkey_cred_request_options_s data1 = TestCommonData::pubkeyCredRequestOptions;
-    data1.user_verification = static_cast<wauthn_user_verification_requirement_e>(0x00FFFFFF);
-    __testSerializeForInvalidMember(&data1);
-
-    wauthn_pubkey_cred_request_options_s data2 = TestCommonData::pubkeyCredRequestOptions;
-    data2.attestation = static_cast<wauthn_attestation_pref_e>(0x00FFFFFF);
-    __testSerializeForInvalidMember(&data2);
-}
-TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_request_options_s_N2)
-{// deserialize: for too large length
-    wauthn_pubkey_cred_request_options_s *deserialized = nullptr;
-    __testDeserializeForTooLongLength(deserialized);
-}
-TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_request_options_s_N3)
-{// deserialize: for invalid attestation
     wauthn_pubkey_cred_request_options_s data = TestCommonData::pubkeyCredRequestOptions;
     data.user_verification = static_cast<wauthn_user_verification_requirement_e>(0x00FFFFFF);
-    __testDeserializeInvalidMember(data);
+    __testDeserializeForInvalidMember<wauthn_pubkey_cred_request_options_s,
+                                      PubKeyCredRequestOptionsDeserializer>(data);
 }
-TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_request_options_s_N4)
-{// deserialize: for invalid attestation
+TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_request_options_s_N2)
+{// serialize: invalid member
     wauthn_pubkey_cred_request_options_s data = TestCommonData::pubkeyCredRequestOptions;
     data.attestation = static_cast<wauthn_attestation_pref_e>(0x00FFFFFF);
-    __testDeserializeInvalidMember(data);
+    __testDeserializeForInvalidMember<wauthn_pubkey_cred_request_options_s,
+                                      PubKeyCredRequestOptionsDeserializer>(data);
 }
+TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_request_options_s_N3)
+{// deserialize: for too large length
+    PubKeyCredRequestOptionsDeserializer deserializer;
+    __testDeserializeForTooLongLength(deserializer);
+}
+
 
-bool __compareWAuthnPubkeyCredentialAttestationS(const wauthn_pubkey_credential_attestation_s *expected,
-            const wauthn_pubkey_credential_attestation_s *actual)
+bool __compareWAuthnPubkeyCredentialAttestationS(
+    const wauthn_pubkey_credential_attestation_s *expected,
+    const wauthn_pubkey_credential_attestation_s *actual)
 {
+    if (actual == nullptr && expected == nullptr)
+        return true;
     if (actual == nullptr || expected == nullptr)
-        return (actual == expected);
+        return false;
+    if (actual == expected) // The addresses should be different after deserialization.
+        return false;
     if(__compareWAuthnBuffers(expected->id, actual->id) == false)
         return false;
     if (expected->type != actual->type)
         return false;
-    if(__compareWAuthnAuthenticatorAttestationResponseS(expected->response, actual->response) == false)
+    if(__compareWAuthnAuthenticatorAttestationResponseS(expected->response,
+                                                        actual->response) == false)
         return false;
     if(__compareWAuthnBuffers(expected->rawId, actual->rawId) == false)
         return false;
@@ -1005,51 +1076,55 @@ bool __compareWAuthnPubkeyCredentialAttestationS(const wauthn_pubkey_credential_
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_credential_attestation_s_P)
 {
-    __testSerialization(&TestCommonData::pubkeyCredentialAttestation,
-                __compareWAuthnPubkeyCredentialAttestationS);
-    __testSerialization(&TestCommonData::emptyPubkeyCredentialAttestation,
-                __compareWAuthnPubkeyCredentialAttestationS);
-    __testSerialization(static_cast<wauthn_pubkey_credential_attestation_s *>(nullptr),
-                __compareWAuthnPubkeyCredentialAttestationS);
-}
-TEST_F(WAuthnSerializationTest, wauthn_pubkey_credential_attestation_s_N1)
-{// serialize: invalid member
-    wauthn_pubkey_credential_attestation_s data1 = TestCommonData::pubkeyCredentialAttestation;
-    data1.type = static_cast<wauthn_pubkey_cred_type_e>(0x00FFFFFF);
-    __testSerializeForInvalidMember(&data1);
+    PubkeyCredentialAttestationSerializer data1(&TestCommonData::pubkeyCredentialAttestation);
+    PubkeyCredentialAttestationDeserializer deserializer1;
+    __testSerialization(data1, deserializer1, __compareWAuthnPubkeyCredentialAttestationS);
+
+    PubkeyCredentialAttestationSerializer data2(&TestCommonData::emptyPubkeyCredentialAttestation);
+    PubkeyCredentialAttestationDeserializer deserializer2;
+    __testSerialization(data2, deserializer2, __compareWAuthnPubkeyCredentialAttestationS);
 
-    wauthn_pubkey_credential_attestation_s data2 = TestCommonData::pubkeyCredentialAttestation;
-    data2.authenticator_attachment = static_cast<wauthn_authenticator_attachment_e>(0x00FFFFFF);
-    __testSerializeForInvalidMember(&data2);
+    PubkeyCredentialAttestationSerializer data3(nullptr);
+    PubkeyCredentialAttestationDeserializer deserializer3;
+    __testSerialization(data3, deserializer3, __compareWAuthnPubkeyCredentialAttestationS);
 }
-TEST_F(WAuthnSerializationTest, wauthn_pubkey_credential_attestation_s_N2)
+TEST_F(WAuthnSerializationTest, wauthn_pubkey_credential_attestation_s_N1)
 {// deserialize: for too large length
-    wauthn_pubkey_credential_attestation_s *deserialized = nullptr;
-    __testDeserializeForTooLongLength(deserialized);
+    PubkeyCredentialAttestationDeserializer deserializer;
+    __testDeserializeForTooLongLength(deserializer);
 }
-TEST_F(WAuthnSerializationTest, wauthn_pubkey_credential_attestation_s_N3)
+TEST_F(WAuthnSerializationTest, wauthn_pubkey_credential_attestation_s_N2)
 {// deserialize: for invalid type
     wauthn_pubkey_credential_attestation_s data = TestCommonData::pubkeyCredentialAttestation;
     data.type = static_cast<wauthn_pubkey_cred_type_e>(0x00FFFFFF);
-    __testDeserializeInvalidMember(data);
+    __testDeserializeForInvalidMember<wauthn_pubkey_credential_attestation_s,
+                                      PubkeyCredentialAttestationDeserializer>(data);
 }
-TEST_F(WAuthnSerializationTest, wauthn_pubkey_credential_attestation_s_N4)
+TEST_F(WAuthnSerializationTest, wauthn_pubkey_credential_attestation_s_N3)
 {// deserialize: for invalid authenticator_attachment
     wauthn_pubkey_credential_attestation_s data = TestCommonData::pubkeyCredentialAttestation;
     data.authenticator_attachment = static_cast<wauthn_authenticator_attachment_e>(0x00FFFFFF);
-    __testDeserializeInvalidMember(data);
+    __testDeserializeForInvalidMember<wauthn_pubkey_credential_attestation_s,
+                                      PubkeyCredentialAttestationDeserializer>(data);
 }
 
+
+
 bool __compareWAuthnPubkeyCredentialAssertionS(const wauthn_pubkey_credential_assertion_s *expected,
             const wauthn_pubkey_credential_assertion_s *actual)
 {
+    if (actual == nullptr && expected == nullptr)
+        return true;
     if (actual == nullptr || expected == nullptr)
-        return (actual == expected);
+        return false;
+    if (actual == expected) // The addresses should be different after deserialization.
+        return false;
     if(__compareWAuthnBuffers(expected->id, actual->id) == false)
         return false;
     if (expected->type != actual->type)
         return false;
-    if(__compareWAuthnAuthenticatorAssertionResponseS(expected->response, actual->response) == false)
+    if(__compareWAuthnAuthenticatorAssertionResponseS(expected->response,
+                                                      actual->response) == false)
         return false;
     if(__compareWAuthnBuffers(expected->rawId, actual->rawId) == false)
         return false;
@@ -1063,45 +1138,48 @@ bool __compareWAuthnPubkeyCredentialAssertionS(const wauthn_pubkey_credential_as
 }
 TEST_F(WAuthnSerializationTest, wauthn_pubkey_credential_assertion_s_P)
 {
-    __testSerialization(&TestCommonData::pubkeyCredentialAssertion,
-                __compareWAuthnPubkeyCredentialAssertionS);
-    __testSerialization(&TestCommonData::emptyPubkeyCredentialAssertion,
-                __compareWAuthnPubkeyCredentialAssertionS);
-    __testSerialization(static_cast<wauthn_pubkey_credential_assertion_s *>(nullptr),
-                __compareWAuthnPubkeyCredentialAssertionS);
-}
-TEST_F(WAuthnSerializationTest, wauthn_pubkey_credential_assertion_s_N1)
-{// serialize: invalid member
-    wauthn_pubkey_credential_assertion_s data1 = TestCommonData::pubkeyCredentialAssertion;
-    data1.type = static_cast<wauthn_pubkey_cred_type_e>(0x00FFFFFF);
-    __testSerializeForInvalidMember(&data1);
+    PubkeyCredentialAssertionSerializer data1(&TestCommonData::pubkeyCredentialAssertion);
+    PubkeyCredentialAssertionDeserializer deserializer1;
+    __testSerialization(data1, deserializer1, __compareWAuthnPubkeyCredentialAssertionS);
+
+    PubkeyCredentialAssertionSerializer data2(&TestCommonData::emptyPubkeyCredentialAssertion);
+    PubkeyCredentialAssertionDeserializer deserializer2;
+    __testSerialization(data2, deserializer2, __compareWAuthnPubkeyCredentialAssertionS);
 
-    wauthn_pubkey_credential_assertion_s data2 = TestCommonData::pubkeyCredentialAssertion;
-    data2.authenticator_attachment = static_cast<wauthn_authenticator_attachment_e>(0x00FFFFFF);
-    __testSerializeForInvalidMember(&data2);
+    PubkeyCredentialAssertionSerializer data3(nullptr);
+    PubkeyCredentialAssertionDeserializer deserializer3;
+    __testSerialization(data3, deserializer3, __compareWAuthnPubkeyCredentialAssertionS);
 }
-TEST_F(WAuthnSerializationTest, wauthn_pubkey_credential_assertion_s_N2)
+TEST_F(WAuthnSerializationTest, wauthn_pubkey_credential_assertion_s_N1)
 {// deserialize: for too large length
-    wauthn_pubkey_credential_assertion_s *deserialized = nullptr;
-    __testDeserializeForTooLongLength(deserialized);
+    PubkeyCredentialAssertionDeserializer deserializer;
+    __testDeserializeForTooLongLength(deserializer);
 }
-TEST_F(WAuthnSerializationTest, wauthn_pubkey_credential_assertion_s_N3)
+TEST_F(WAuthnSerializationTest, wauthn_pubkey_credential_assertion_s_N2)
 {// deserialize: for invalid type
     wauthn_pubkey_credential_assertion_s data = TestCommonData::pubkeyCredentialAssertion;
     data.type = static_cast<wauthn_pubkey_cred_type_e>(0x00FFFFFF);
-    __testDeserializeInvalidMember(data);
+    __testDeserializeForInvalidMember<wauthn_pubkey_credential_assertion_s,
+                                      PubkeyCredentialAssertionDeserializer>(data);
 }
-TEST_F(WAuthnSerializationTest, wauthn_pubkey_credential_assertion_s_N4)
+TEST_F(WAuthnSerializationTest, wauthn_pubkey_credential_assertion_s_N3)
 {// deserialize: for invalid authenticator_attachment
     wauthn_pubkey_credential_assertion_s data = TestCommonData::pubkeyCredentialAssertion;
     data.authenticator_attachment = static_cast<wauthn_authenticator_attachment_e>(0x00FFFFFF);
-    __testDeserializeInvalidMember(data);
+    __testDeserializeForInvalidMember<wauthn_pubkey_credential_assertion_s,
+                                      PubkeyCredentialAssertionDeserializer>(data);
 }
 
-bool __compareWAuthnClientDataS(const wauthn_client_data_s *expected, const wauthn_client_data_s *actual)
+
+bool __compareWAuthnClientDataS(const wauthn_client_data_s *expected,
+                                const wauthn_client_data_s *actual)
 {
+    if (actual == nullptr && expected == nullptr)
+        return true;
     if (actual == nullptr || expected == nullptr)
-        return (actual == expected);
+        return false;
+    if (actual == expected) // The addresses should be different after deserialization.
+        return false;
     if(__compareWAuthnBuffers(expected->client_data_json, actual->client_data_json) == false)
         return false;
     if (expected->hash_alg != actual->hash_alg)
@@ -1110,97 +1188,119 @@ bool __compareWAuthnClientDataS(const wauthn_client_data_s *expected, const waut
 }
 TEST_F(WAuthnSerializationTest, wauthn_client_data_s_P)
 {
-    __testSerialization(&TestCommonData::clientData, __compareWAuthnClientDataS);
-    __testSerialization(&TestCommonData::emptyClientData, __compareWAuthnClientDataS);
-    __testSerialization(static_cast<wauthn_client_data_s *>(nullptr), __compareWAuthnClientDataS);
+    ClientDataSerializer data1(&TestCommonData::clientData);
+    ClientDataDeserializer deserializer1;
+    __testSerialization(data1, deserializer1, __compareWAuthnClientDataS);
+
+    ClientDataSerializer data2(&TestCommonData::emptyClientData);
+    ClientDataDeserializer deserializer2;
+    __testSerialization(data2, deserializer2, __compareWAuthnClientDataS);
+
+    ClientDataSerializer data3(nullptr);
+    ClientDataDeserializer deserializer3;
+    __testSerialization(data3, deserializer3, __compareWAuthnClientDataS);
 }
 TEST_F(WAuthnSerializationTest, wauthn_client_data_s_N1)
 {// serialize: invalid member
     wauthn_client_data_s data = TestCommonData::clientData;
     data.hash_alg = static_cast<wauthn_hash_algorithm_e>(0x00FFFFFF);
-    __testSerializeForInvalidMember(&data);
+    __testDeserializeForInvalidMember<wauthn_client_data_s, ClientDataDeserializer>(data);
 }
 TEST_F(WAuthnSerializationTest, wauthn_client_data_s_N2)
 {// deserialize: for too large length
-    wauthn_client_data_s *deserialized = nullptr;
-    __testDeserializeForTooLongLength(deserialized);
-}
-TEST_F(WAuthnSerializationTest, wauthn_client_data_s_N3)
-{// deserialize: for invalid authenticator_attachment
-    wauthn_client_data_s data = TestCommonData::clientData;
-    data.hash_alg = static_cast<wauthn_hash_algorithm_e>(0x00FFFFFF);
-    __testDeserializeInvalidMember(data);
+    ClientDataDeserializer deserializer;
+    __testDeserializeForTooLongLength(deserializer);
 }
 
-template<typename T, typename U, typename FT, typename FU>
-void __testMultipleSerialization(T first, U second, FT cmp_first, FU cmp_second,
-                                 T deserialized_first, U deserialized_second)
+template<typename S1, typename S2, typename D1, typename D2>
+void __multipleSerialize(S1& serializer1, S2& serializer2,
+                                 D1& deserializer1, D2& deserializer2)
 {
     MessageBuffer buffer;
     buffer.InitForStreaming();
-    Serialization::Serialize(buffer, first, second);
+    Serialization::Serialize(buffer, serializer1, serializer2);
     buffer.ModeOutput();
 
     buffer.ModeStreaming();
-    Deserialization::Deserialize(buffer, &deserialized_first, &deserialized_second);
+    Deserialization::Deserialize(buffer, deserializer1, deserializer2);
+}
 
-    EXPECT_EQ(cmp_first(first, deserialized_first), true);
-    EXPECT_EQ(cmp_second(second, deserialized_second), true);
+template<typename S1, typename S2, typename D1, typename D2, typename CF1, typename CF2>
+void __testMultipleSerialization(S1& serializer1, S2& serializer2,
+                                 D1& deserializer1, D2& deserializer2,
+                                 CF1 cmp1, CF2 cmp2)
+{
+    __multipleSerialize(serializer1, serializer2, deserializer1, deserializer2);
+    EXPECT_EQ(cmp1(serializer1.getRawPtr(), deserializer1.getRawPtr()), true);
+    EXPECT_EQ(cmp2(serializer2.getRawPtr(), deserializer2.getRawPtr()), true);
 }
 
-template<typename T, typename U, typename FT, typename FU>
-void __testMultipleSerialization(T first, U second, FT cmp_first, FU cmp_second)
+bool __compareWAuthErrorE(wauthn_error_e expected, wauthn_error_e actual)
 {
-    T deserialized_first = nullptr;
-    U deserialized_second = nullptr;
-    __testMultipleSerialization(first, second, cmp_first, cmp_second,
-                                deserialized_first, deserialized_second);
+    return (expected == actual);
 }
 
-template<typename T, typename U, typename FT, typename FU>
-void __testMultipleSerializationWAuthErrorE(T first, U second, FT cmp_first, FU cmp_second)
+template<typename S1,typename D1,typename CF1>
+void __testMultipleSerializationWAuthErrorE(S1& serializer1, wauthn_error_e serializer2,
+                                 D1& deserializer1, wauthn_error_e& deserializer2,
+                                 CF1 cmp1)
 {
-    T deserialized_first = nullptr;
-    U deserialized_second = WAUTHN_ERROR_NONE;
-    __testMultipleSerialization(first, second, cmp_first, cmp_second,
-                                deserialized_first, deserialized_second);
+    __multipleSerialize(serializer1, serializer2, deserializer1, deserializer2);
+    EXPECT_EQ(cmp1(serializer1.getRawPtr(), deserializer1.getRawPtr()), true);
+    EXPECT_EQ(__compareWAuthErrorE(serializer2, deserializer2), true);
 }
 
-TEST_F(WAuthnSerializationTest, multiple_serialization_mcreq_P)
+TEST_F(WAuthnSerializationTest, multiple_serialization_mc_req_P)
 {
-    wauthn_client_data_s *client_data = &TestCommonData::clientData;
-    wauthn_pubkey_cred_creation_options_s *options = &TestCommonData::pubkeyCredCreationOptions;
+    ClientDataSerializer clientData(&TestCommonData::clientData);
+    PubKeyCredCreationOptionsSerializer options(&TestCommonData::pubkeyCredCreationOptions);
+
+    ClientDataDeserializer clientDataDeserializer;
+    PubKeyCredCreationOptionsDeserializer optionsDeserializer;
 
-    __testMultipleSerialization(client_data, options,
-            __compareWAuthnClientDataS, __compareWAuthnPubkeyCredCreationOptionsS);
+    __testMultipleSerialization(clientData, options,
+            clientDataDeserializer, optionsDeserializer,
+            __compareWAuthnClientDataS, __compareWAuthnPubkeyCredCreationOptionsS
+    );
 }
 
-TEST_F(WAuthnSerializationTest, multiple_serialization_gareq_P)
+TEST_F(WAuthnSerializationTest, multiple_serialization_ga_req_P)
 {
-    wauthn_client_data_s *client_data = &TestCommonData::clientData;
-    wauthn_pubkey_cred_request_options_s *options = &TestCommonData::pubkeyCredRequestOptions;
+    ClientDataSerializer clientData(&TestCommonData::clientData);
+    PubKeyCredRequestOptionsSerializer options(&TestCommonData::pubkeyCredRequestOptions);
 
-    __testMultipleSerialization(client_data, options,
+    ClientDataDeserializer clientDataDeserializer;
+    PubKeyCredRequestOptionsDeserializer optionsDeserializer;
+
+    __testMultipleSerialization(clientData, options,
+            clientDataDeserializer, optionsDeserializer,
             __compareWAuthnClientDataS, __compareWAuthnPubkeyCredRequestOptionsS);
 }
 
-TEST_F(WAuthnSerializationTest, multiple_serialization_mcres_P)
+TEST_F(WAuthnSerializationTest, multiple_serialization_mc_res_P)
 {
-    wauthn_pubkey_credential_attestation_s *pubkeyCred = &TestCommonData::pubkeyCredentialAttestation;
+    PubkeyCredentialAttestationSerializer pubkeyCred(&TestCommonData::pubkeyCredentialAttestation);
     wauthn_error_e result = WAUTHN_ERROR_PERMISSION_DENIED;
 
+    PubkeyCredentialAttestationDeserializer pubkeyCredDeserializer;
+    wauthn_error_e resultDeserializer = WAUTHN_ERROR_NONE;
+
     __testMultipleSerializationWAuthErrorE(pubkeyCred, result,
-            __compareWAuthnPubkeyCredentialAttestationS, __compareWAuthErrorE);
+            pubkeyCredDeserializer, resultDeserializer,
+            __compareWAuthnPubkeyCredentialAttestationS);
 }
 
-TEST_F(WAuthnSerializationTest, multiple_serialization_gares_P)
+TEST_F(WAuthnSerializationTest, multiple_serialization_ga_res_P)
 {
-    wauthn_pubkey_credential_assertion_s *pubkeyCred = &TestCommonData::pubkeyCredentialAssertion;
+    PubkeyCredentialAssertionSerializer pubkeyCred(&TestCommonData::pubkeyCredentialAssertion);
     wauthn_error_e result = WAUTHN_ERROR_CANCELED;
 
+    PubkeyCredentialAssertionDeserializer pubkeyCredDeserializer;
+    wauthn_error_e resultDeserializer = WAUTHN_ERROR_NONE;
+
     __testMultipleSerializationWAuthErrorE(pubkeyCred, result,
-            __compareWAuthnPubkeyCredentialAssertionS, __compareWAuthErrorE);
+            pubkeyCredDeserializer, resultDeserializer,
+            __compareWAuthnPubkeyCredentialAssertionS);
 }
 
-
 } // namespace WA