Implements message serialization
authorDongsun Lee <ds73.lee@samsung.com>
Wed, 3 Jan 2024 09:18:26 +0000 (18:18 +0900)
committer이동선/Security&Privacy팀(SR)/삼성전자 <ds73.lee@samsung.com>
Wed, 17 Jan 2024 06:17:17 +0000 (15:17 +0900)
srcs/common/message-buffer.h
srcs/common/serialization.cpp
srcs/common/serialization.h
tests/CMakeLists.txt
tests/serialization-test.cpp [new file with mode: 0644]

index c37474aedd994afb57799c908e93795f78e03fa4..e96bfa353562003cfbe6dd0a224b098f8384c374 100644 (file)
@@ -105,7 +105,8 @@ public:
     }
 
     ~MessageBuffer() {
-        free(m_buffer);
+        if(m_buffer)
+            free(m_buffer);
     }
 
     /**
@@ -142,7 +143,8 @@ public:
      * Switch to Default mode.
      */
     void Clear() {
-        free(m_buffer);
+        if(m_buffer)
+            free(m_buffer);
         m_buffer = nullptr;
     }
 
index 6027aa08850e84b65451107b4bf326b3621226e0..ac2be2d2b601e2c65669c572347fea40a6b9bbdf 100644 (file)
  *  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        serialization.cpp
- * @version     1.0
- * @brief       This file is the implementation file of data serialization
  */
 
-#include <stddef.h>
+#include <cstring>
+#include <iostream>
+
 #include <serialization.h>
+#include <message-buffer.h>
+
+
+namespace WA {
+
+// For array item
+void __serializeArrayItem(IStream& stream, const void *data, size_t struct_size) {
+    MessageBuffer& buffer = dynamic_cast<MessageBuffer&>(stream);
+    buffer.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 struct body itself
+void WAuthnCtypeSerializer::serializeStructBody(IStream& stream, const void *data, size_t struct_size) {
+    size_t lengh = (data == nullptr) ? 0 : struct_size; 
+    serialize(stream, reinterpret_cast<const unsigned char*>(data), lengh);
+}
+void WAuthnCtypeSerializer::deserializeStructBody(IStream& stream, void **data, size_t struct_size) {
+    size_t length = 0;
+    deserialize(stream, reinterpret_cast<unsigned char**>(data), &length);
+    if (length != 0 && length != struct_size)
+        ThrowMsg(SerializationException::InvalidStreamData, "Invalid length: length=" << length 
+                                                            << ", struct_size=" << struct_size);
+}
+
+// For unsigned char*
+void WAuthnCtypeSerializer::serialize(IStream& stream, const unsigned char* data, size_t length) {
+    stream.Write(sizeof(size_t), &length);
+    if (length > MAX_BUFFER_SIZE)
+        ThrowMsg(SerializationException::InvalidStreamData, "Too large length of data to write: length=" << length);
+    if (length != 0)
+        stream.Write(length, data);
+}
+void WAuthnCtypeSerializer::deserialize(IStream& stream, unsigned char** data, size_t* length) {
+    MessageBuffer& buffer = dynamic_cast<MessageBuffer&>(stream);
+    buffer.Read(sizeof(size_t), length);
+    if (*length > MAX_BUFFER_SIZE)
+        ThrowMsg(SerializationException::InvalidStreamData, "Too large length of data to read: length=" << *length);
+    if (*length == 0) {
+        *data = nullptr;
+    } else {
+        *data = buffer.Ptr();
+        char buf[*length];
+        buffer.Read(*length, buf); // for moving internal offset.
+    }
+}
+
+// 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, char** data) {
+    size_t length;
+    deserialize(stream, reinterpret_cast<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 WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_error_e data) {
+    // Serialization::Serialize(stream, static_cast<int>(data));
+    stream.Write(sizeof(data), &data);
+}
+void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_error_e* data) {
+    int tmp = 0;
+    stream.Read(sizeof(tmp), &tmp);
+    *data = static_cast<wauthn_error_e>(tmp);
+}
+
+// For wauthn_buffer_s
+void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_buffer_s* data) {
+    // Seriallize struct itself
+    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_buffer_s));
+    if (data == nullptr)
+        return;
+    // Seriallize the contents of struct's pointers
+    serialize(stream, data->data, data->size);
+}
+void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_buffer_s** data) {
+    // Deseriallize struct itself
+    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_buffer_s));
+    if (*data == nullptr)
+        return;
+    // Deseriallize the contents of struct's pointers
+    deserialize(stream, &((*data)->data), &((*data)->size));
+}
+
+// For wauthn_authenticator_attestation_response_s
+void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_authenticator_attestation_response_s* data) {
+    // Seriallize struct itself
+    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_authenticator_attestation_response_s));
+    if (data == nullptr)
+        return;
+    // Seriallize 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);
+}
+void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_authenticator_attestation_response_s** data) {
+    // Deseriallize struct itself
+    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_authenticator_attestation_response_s));
+    if (*data == nullptr)
+        return;
+    // Deseriallize 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));
+}
+
+// For wauthn_authenticator_assertion_response_s
+void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_authenticator_assertion_response_s* data) {
+    // Seriallize struct itself
+    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_authenticator_assertion_response_s));
+    if (data == nullptr)
+        return;
+    // Seriallize 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) {
+    // Deseriallize struct itself
+    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_authenticator_assertion_response_s));
+    if (*data == nullptr)
+        return;
+    // Deseriallize 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));
+}
+
+// For wauthn_rp_entity_s
+void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_rp_entity_s* data) {
+    // Seriallize struct itself
+    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_rp_entity_s));
+    if (data == nullptr)
+        return;
+    // Seriallize the contents of struct's pointers
+    serialize(stream, data->name);
+    serialize(stream, data->id);
+}
+void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_rp_entity_s** data) {
+    // Deseriallize struct itself
+    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_rp_entity_s));
+    if (*data == nullptr)
+        return;
+    // Deseriallize the contents of struct's pointers
+    deserialize(stream, &((*data)->name));
+    deserialize(stream, &((*data)->id));
+}
+
+// For wauthn_user_entity_s
+void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_user_entity_s* data) {
+    // Seriallize struct itself
+    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_user_entity_s));
+    if (data == nullptr)
+        return;
+    // Seriallize the contents of struct's pointers
+    serialize(stream, data->name);
+    serialize(stream, data->id);
+    serialize(stream, data->display_name);
+}
+void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_user_entity_s** data) {
+    // Deseriallize struct itself
+    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_user_entity_s));
+    if (*data == nullptr)
+        return;
+    // Deseriallize the contents of struct's pointers
+    deserialize(stream, &((*data)->name));
+    deserialize(stream, &((*data)->id));
+    deserialize(stream, &((*data)->display_name));
+}
+
+// For wauthn_pubkey_cred_param_s
+void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_pubkey_cred_param_s* data) {
+    // Seriallize struct itself
+    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_pubkey_cred_param_s));
+    // No pointers in struct
+}
+void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_pubkey_cred_param_s** data) {
+    // Deseriallize struct itself
+    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_pubkey_cred_param_s));
+    // No pointers in struct
+}
+
+// For wauthn_pubkey_cred_params_s
+void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_pubkey_cred_params_s* data) {
+    // Seriallize struct itself
+    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_pubkey_cred_params_s));
+    if (data == nullptr)
+        return;
+    // Serialize array
+    for(size_t i=0; i < data->size; i++ )
+        __serializeArrayItem(stream, reinterpret_cast<const void *>(data->params + i), sizeof(wauthn_pubkey_cred_params_s));
+}
+void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_pubkey_cred_params_s** data) {
+    // Deseriallize struct itself
+    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_pubkey_cred_params_s));
+    if (*data == nullptr)
+        return;
+    if ((*data)->size == 0) {
+        (*data)->params = nullptr;
+    }
+    // Deseriallize array
+    wauthn_pubkey_cred_param_s* tmp;
+    for(size_t i=0; i < (*data)->size; i++ ) {
+        __deserializeArrayItem(stream, reinterpret_cast<void **>(&tmp), sizeof(wauthn_pubkey_cred_params_s));
+        if (i == 0) // set pointer to the first parameter
+            (*data)->params = tmp;
+    }
+}
+
+// For wauthn_pubkey_cred_descriptor_s
+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) {
+    // Seriallize struct itself
+    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_pubkey_cred_descriptor_s));
+    if (data == nullptr)
+        return;
+    // Seriallize the contents of struct's pointers
+    __serializePointerContents(stream, data);
+}
+void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_pubkey_cred_descriptor_s** data) {
+    // Deseriallize struct itself
+    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_pubkey_cred_descriptor_s));
+    if (*data == nullptr)
+        return;
+    // Deseriallize the contents of struct's pointers
+    __deserializePointerContents(stream, *data);
+}
+
+// For wauthn_pubkey_cred_descriptors_s
+void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_pubkey_cred_descriptors_s* data) {
+    // Seriallize struct itself
+    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_pubkey_cred_descriptors_s));
+    if (data == nullptr)
+        return;
+    // Serialize array
+    for(size_t i=0; i < data->size; i++ )
+        __serializeArrayItem(stream, reinterpret_cast<const void *>(data->descriptors + i), sizeof(wauthn_pubkey_cred_descriptor_s));
+    // Seriallize the contents of pointers in struct array
+    for(size_t i=0; i < data->size; i++ )
+        __serializePointerContents(stream, data->descriptors + i);
+}
+void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_pubkey_cred_descriptors_s** data) {
+    // Deseriallize struct itself
+    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_pubkey_cred_descriptors_s));
+    if (*data == nullptr)
+        return;
+    if ((*data)->size == 0) {
+        (*data)->descriptors = nullptr;
+        return;
+    }
+    // Deseriallize array
+    wauthn_pubkey_cred_descriptor_s* tmp;
+    for(size_t i=0; i < (*data)->size; i++ ) {
+        __deserializeArrayItem(stream, reinterpret_cast<void **>(&tmp), sizeof(wauthn_pubkey_cred_descriptor_s));
+        if (i == 0) // set pointer to the first parameter
+            (*data)->descriptors = tmp;
+    }
+    // Deseriallize the contents of pointers in struct array
+    for(size_t i=0; i < (*data)->size; i++ )
+        __deserializePointerContents(stream, (*data)->descriptors + i);
+}
+
+// For wauthn_authentication_ext_s
+void __serializePointerContents(IStream& stream, const wauthn_authentication_ext_s* data) {
+    WAuthnCtypeSerializer::serialize(stream, data->extension_id);
+    WAuthnCtypeSerializer::serialize(stream, data->extension_value);
+}
+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) {
+    // Seriallize struct itself
+    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_authentication_ext_s));
+    if (data == nullptr)
+        return;
+    // Seriallize the contents of struct's pointers
+    __serializePointerContents(stream, data);
+}
+void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_authentication_ext_s** data) {
+    // Deseriallize struct itself
+    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_authentication_ext_s));
+    if (*data == nullptr)
+        return;
+    // Deseriallize the contents of struct's pointers
+    __deserializePointerContents(stream, *data);
+}
+
+// For wauthn_authentication_exts_s
+void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_authentication_exts_s* data) {
+    // Seriallize struct itself
+    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_authentication_exts_s));
+    if (data == nullptr)
+        return;
+    // Serialize array
+    for(size_t i=0; i < data->size; i++ )
+        __serializeArrayItem(stream, reinterpret_cast<const void *>(data->extensions + i), sizeof(wauthn_authentication_ext_s));
+    // Seriallize the contents of pointers in struct array
+    for(size_t i=0; i < data->size; i++ )
+        __serializePointerContents(stream, data->extensions + i);
+}
+void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_authentication_exts_s** data) {
+    // Deseriallize struct itself
+    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_authentication_exts_s));
+    if (*data == nullptr)
+        return;
+    if ((*data)->size == 0) {
+        (*data)->extensions = nullptr;
+        return;
+    }
+    // Deseriallize array
+    wauthn_authentication_ext_s* tmp;
+    for(size_t i=0; i < (*data)->size; i++ ) {
+        __deserializeArrayItem(stream, reinterpret_cast<void **>(&tmp), sizeof(wauthn_authentication_ext_s));
+        if (i == 0) // set pointer to the first parameter
+            (*data)->extensions = tmp;
+    }
+    // Deseriallize the contents of pointers in struct array
+    for(size_t i=0; i < (*data)->size; i++ )
+        __deserializePointerContents(stream, (*data)->extensions + i);
+}
+
+// For wauthn_authenticator_sel_cri_s
+void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_authenticator_sel_cri_s* data) {
+    // Seriallize struct itself
+    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_authenticator_sel_cri_s));
+    // No pointers in struct
+}
+void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_authenticator_sel_cri_s** data) {
+    // Deseriallize struct itself
+    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_authenticator_sel_cri_s));
+    // No pointers in struct
+}
+
+// For wauthn_pubkey_cred_hints_s
+void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_pubkey_cred_hints_s* data) {
+    // Seriallize struct itself
+    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_pubkey_cred_hints_s));
+    if (data == nullptr)
+        return;
+    // Serialize array
+    for(size_t i=0; i < data->size; i++ )
+        __serializeArrayItem(stream, reinterpret_cast<const void *>(data->hints + i), sizeof(wauthn_pubkey_cred_hint_e));
+}
+void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_pubkey_cred_hints_s** data) {
+    // Deseriallize struct itself
+    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_pubkey_cred_hints_s));
+    if (*data == nullptr)
+        return;
+    // Deseriallize array
+    wauthn_pubkey_cred_hint_e* tmp;
+    for(size_t i=0; i < (*data)->size; i++ ) {
+        __deserializeArrayItem(stream, reinterpret_cast<void **>(&tmp), sizeof(wauthn_pubkey_cred_hint_e));
+        if (i == 0) // set pointer to the first parameter
+            (*data)->hints = tmp;
+    }
+}
+
+// For wauthn_hybrid_linked_data_s
+void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_hybrid_linked_data_s* data) {
+    // Seriallize struct itself
+    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_hybrid_linked_data_s));
+    if (data == nullptr)
+        return;
+    // Seriallize 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->auth_pubkey);
+    serialize(stream, data->tunnel_server_domain);
+}
+void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_hybrid_linked_data_s** data) {
+    // Deseriallize struct itself
+    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_hybrid_linked_data_s));
+    if (*data == nullptr)
+        return;
+    // Deseriallize 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)->auth_pubkey));
+    deserialize(stream, &((*data)->tunnel_server_domain));
+}
+
+// For wauthn_attestation_formats_s
+void __serializePointerContents(IStream& stream, const wauthn_buffer_s* data) {
+    WAuthnCtypeSerializer::serialize(stream, data);
+}
+void __deserializePointerContents(IStream& stream, wauthn_buffer_s* data) {
+    WAuthnCtypeSerializer::deserialize(stream, &data);
+}
+void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_attestation_formats_s* data) {
+    // Seriallize struct itself
+    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_attestation_formats_s));
+    if (data == nullptr)
+        return;
+    // Serialize array
+    for(size_t i=0; i < data->size; i++ )
+        __serializeArrayItem(stream, reinterpret_cast<const void *>(data->attestation_formats + i), sizeof(wauthn_buffer_s));
+    // Seriallize the contents of pointers in struct array
+    for(size_t i=0; i < data->size; i++ )
+        __serializePointerContents(stream, data->attestation_formats + i);
+}
+void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_attestation_formats_s** data) {
+    // Deseriallize 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;
+        return;
+    }
+    // Deseriallize array
+    wauthn_buffer_s* tmp;
+    for(size_t i=0; i < (*data)->size; i++ ) {
+        __deserializeArrayItem(stream, reinterpret_cast<void **>(&tmp), sizeof(wauthn_buffer_s));
+        if (i == 0) // set pointer to the first parameter
+            (*data)->attestation_formats = tmp;
+    }
+    // Deseriallize the contents of pointers in struct array
+    for(size_t i=0; i < (*data)->size; i++ )
+        __deserializePointerContents(stream, (*data)->attestation_formats + i);
+}
+
+// For wauthn_pubkey_cred_creation_options_s
+void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_pubkey_cred_creation_options_s* data) {
+    // Seriallize struct itself
+    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_pubkey_cred_creation_options_s));
+    if (data == nullptr)
+        return;
+    // Seriallize the contents of struct's pointers
+    serialize(stream, data->rp);
+    serialize(stream, data->user);
+    serialize(stream, data->challenge);
+    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) {
+    // Deseriallize struct itself
+    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_pubkey_cred_creation_options_s));
+    if (*data == nullptr)
+        return;
+    // Deseriallize the contents of struct's pointers
+    deserialize(stream, &((*data)->rp));
+    deserialize(stream, &((*data)->user));
+    deserialize(stream, &((*data)->challenge));
+    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));
+}
+
+// For wauthn_pubkey_cred_request_options_s
+void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_pubkey_cred_request_options_s* data) {
+    // Seriallize struct itself
+    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_pubkey_cred_request_options_s));
+    if (data == nullptr)
+        return;
+    // Seriallize the contents of struct's pointers
+    serialize(stream, data->challenge);
+    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) {
+    // Deseriallize struct itself
+    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_pubkey_cred_request_options_s));
+    if (*data == nullptr)
+        return;
+    // Deseriallize the contents of struct's pointers
+    deserialize(stream, &((*data)->challenge));
+    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));
+}
+
+// For wauthn_pubkey_credential_attestaion_s
+void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_pubkey_credential_attestaion_s* data) {
+    // Seriallize struct itself
+    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_pubkey_credential_attestaion_s));
+    if (data == nullptr)
+        return;
+    // Seriallize 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->json_data);
+    serialize(stream, data->linked_device);
+}
+void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_pubkey_credential_attestaion_s** data) {
+    // Deseriallize struct itself
+    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_pubkey_credential_attestaion_s));
+    if (*data == nullptr)
+        return;
+    // Deseriallize 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)->json_data));
+    deserialize(stream, &((*data)->linked_device));
+}
+
+// For wauthn_pubkey_credential_assertion_s
+void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_pubkey_credential_assertion_s* data) {
+    // Seriallize struct itself
+    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_pubkey_credential_assertion_s));
+    if (data == nullptr)
+        return;
+    // Seriallize 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->json_data);
+    serialize(stream, data->linked_device);
+}
+void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_pubkey_credential_assertion_s** data) {
+    // Deseriallize struct itself
+    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_pubkey_credential_assertion_s));
+    if (*data == nullptr)
+        return;
+    // Deseriallize 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)->json_data));
+    deserialize(stream, &((*data)->linked_device));
+}
+
+// For wauthn_client_data_s
+void WAuthnCtypeSerializer::serialize(IStream& stream, const wauthn_client_data_s* data) {
+    // Seriallize struct itself
+    serializeStructBody(stream, reinterpret_cast<const void *>(data), sizeof(wauthn_client_data_s));
+    if (data == nullptr)
+        return;
+    // Seriallize the contents of struct's pointers
+    serialize(stream, data->client_data_json);
+}
+void WAuthnCtypeSerializer::deserialize(IStream& stream, wauthn_client_data_s** data) {
+    // Deseriallize struct itself
+    deserializeStructBody(stream, reinterpret_cast<void **>(data), sizeof(wauthn_client_data_s));
+    if (*data == nullptr)
+        return;
+    // Deseriallize the contents of struct's pointers
+    deserialize(stream, &((*data)->client_data_json));
+}
+
 
-//
-// Note:
-//
-// The file here is left blank to enable precompilation
-// of templates in corresponding header file.
-// Do not remove this file.
-//
+} // namespace WebAuthn
index 3ca0af35490afa04a8bd7271fd631de16e7bc85e..184dc25674e37906db9b4fd21f400d7918ff106b 100644 (file)
@@ -27,6 +27,7 @@
 #include <tuple>
 
 #include <exception.h>
+#include <webauthn-types.h>
 
 namespace WA {
 
@@ -64,6 +65,86 @@ class SerializeKeysAsVector
     const Collection &get() { return col_; }
 };
 
+
+const size_t MAX_BUFFER_SIZE = 128 * 1024 * 1024; // 128 MB
+
+// Serialize & Deserialze struct types in wetauthn-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);
+
+public:
+    static void serialize(IStream& stream, const unsigned char* data, size_t length);
+    static void deserialize(IStream& stream, unsigned char** data, size_t* length);
+
+    static void serialize(IStream& stream, const char* data);
+    static void deserialize(IStream& stream, char** data);
+
+    static void serialize(IStream& stream, const wauthn_error_e data);
+    static void deserialize(IStream& stream, wauthn_error_e* data);
+
+    static void serialize(IStream& stream, const wauthn_buffer_s* data);
+    static void deserialize(IStream& stream, wauthn_buffer_s** data);
+
+    static void serialize(IStream& stream, const wauthn_authenticator_attestation_response_s* data);
+    static void deserialize(IStream& stream, wauthn_authenticator_attestation_response_s** data);
+
+    static void serialize(IStream& stream, const wauthn_authenticator_assertion_response_s* data);
+    static void deserialize(IStream& stream, wauthn_authenticator_assertion_response_s** data);
+
+    static void serialize(IStream& stream, const wauthn_rp_entity_s* data);
+    static void deserialize(IStream& stream, wauthn_rp_entity_s** data);
+
+    static void serialize(IStream& stream, const wauthn_user_entity_s* data);
+    static void deserialize(IStream& stream, wauthn_user_entity_s** data);
+
+    static void serialize(IStream& stream, const wauthn_pubkey_cred_param_s* data);
+    static void deserialize(IStream& stream, wauthn_pubkey_cred_param_s** data);
+
+    static void serialize(IStream& stream, const wauthn_pubkey_cred_params_s* data);
+    static void deserialize(IStream& stream, wauthn_pubkey_cred_params_s** data);
+
+    static void serialize(IStream& stream, const wauthn_pubkey_cred_descriptor_s* data);
+    static void deserialize(IStream& stream, wauthn_pubkey_cred_descriptor_s** data);
+
+    static void serialize(IStream& stream, const wauthn_pubkey_cred_descriptors_s* data);
+    static void deserialize(IStream& stream, wauthn_pubkey_cred_descriptors_s** data);
+
+    static void serialize(IStream& stream, const wauthn_authentication_ext_s* data);
+    static void deserialize(IStream& stream, wauthn_authentication_ext_s** data);
+
+    static void serialize(IStream& stream, const wauthn_authentication_exts_s* data);
+    static void deserialize(IStream& stream, wauthn_authentication_exts_s** data);
+
+    static void serialize(IStream& stream, const wauthn_authenticator_sel_cri_s* data);
+    static void deserialize(IStream& stream, wauthn_authenticator_sel_cri_s** data);
+
+    static void serialize(IStream& stream, const wauthn_pubkey_cred_hints_s* data);
+    static void deserialize(IStream& stream, wauthn_pubkey_cred_hints_s** data);
+
+    static void serialize(IStream& stream, const wauthn_hybrid_linked_data_s* data);
+    static void deserialize(IStream& stream, wauthn_hybrid_linked_data_s** data);
+
+    static void serialize(IStream& stream, const wauthn_attestation_formats_s* data);
+    static void deserialize(IStream& stream, wauthn_attestation_formats_s** data);
+
+    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);
+
+    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);
+
+    static void serialize(IStream& stream, const wauthn_pubkey_credential_attestaion_s* data);
+    static void deserialize(IStream& stream, wauthn_pubkey_credential_attestaion_s** data);
+
+    static void serialize(IStream& stream, const wauthn_pubkey_credential_assertion_s* data);
+    static void deserialize(IStream& stream, wauthn_pubkey_credential_assertion_s** data);
+
+    static void serialize(IStream& stream, const wauthn_client_data_s* data);
+    static void deserialize(IStream& stream, wauthn_client_data_s** data);
+};
+
 struct Serialization {
     // serialization
     // normal functions
@@ -83,10 +164,11 @@ struct Serialization {
     {
         stream.Write(sizeof(value), &value);
     }
-    static void Serialize(IStream& stream, const char* const value)
-    {
-        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);
+    // }
 
     // unsigned char
     static void Serialize(IStream& stream, const unsigned char value)
@@ -276,6 +358,120 @@ struct Serialization {
         Serialize(stream, first);
         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_buffer_s
+    static void Serialize(IStream& stream, const wauthn_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)
+    {
+        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_attestaion_s
+    static void Serialize(IStream& stream, const wauthn_pubkey_credential_attestaion_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);
+    }
+
 }; // struct Serialization
 
 struct Deserialization {
@@ -525,10 +721,34 @@ struct Deserialization {
     }
 
     template<typename T1, typename T2, typename... Tail>
-    static void Deserialize(IStream& stream, T1 &first, T2 &second, Tail&... 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)
+    {
+        WAuthnCtypeSerializer::deserialize(stream, data);
+    }
+
+    //##########################################################################################
+    // 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 convers all other C types.
+    template<typename T>
+    static void Deserialize(IStream& stream, T** data)
+    {
+        WAuthnCtypeSerializer::deserialize(stream, data);
+    }
+
 }; // struct Deserialization
+
+
 } // namespace WebAuthn
index f8bab2d8e5241b1129e3eee9997d7a3dd7cfc68f..97c7c61a60b2c47e20b27aa67141f28722e18fde 100644 (file)
@@ -10,6 +10,7 @@ SET(UNIT_TESTS_SOURCES
     ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/webauthn-client-test.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/ble_test.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/serialization-test.cpp
 )
 
 SET_SOURCE_FILES_PROPERTIES(
diff --git a/tests/serialization-test.cpp b/tests/serialization-test.cpp
new file mode 100644 (file)
index 0000000..50c0478
--- /dev/null
@@ -0,0 +1,889 @@
+/*
+ *  Copyright (c) 2023 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        webauthn-client-test.cpp
+ * @version     1.0
+ * @brief       unit tests for webauthn client api
+ */
+
+
+#include <string>
+#include <cstring>
+#include <iostream>
+#include <gtest/gtest.h>
+#include <unistd.h>
+#include <webauthn-types.h>
+#include <message-buffer.h>
+#include <serialization.h>
+
+
+namespace WA {
+
+
+namespace CommonTestData {
+    unsigned char clientDataJsonRaw[06] = {0x01, 0x02, 0x03, 0x04, };
+    unsigned char attestationObjectRaw[16] = {0x11, 0x12, 0x13, 0x14, };
+    unsigned char authenticatorDataRaw[26] = {0x21, 0x22, 0x23, 0x24, };
+    unsigned char subjectPubkeyInfoRaw[36] = {0x31, 0x32, 0x33, 0x34, };
+    wauthn_buffer_s clientDataJson = {clientDataJsonRaw, sizeof(clientDataJsonRaw)};
+    wauthn_buffer_s attestationObject = {attestationObjectRaw, sizeof(attestationObjectRaw)};
+    unsigned int transports = 3;
+    wauthn_buffer_s authenticatorData = {authenticatorDataRaw, sizeof(authenticatorDataRaw)};
+    wauthn_buffer_s subjectPubkeyInfo = {subjectPubkeyInfoRaw, sizeof(subjectPubkeyInfoRaw)};
+    wauthn_cose_algorithm_e pubkey_alg = WAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256;
+    wauthn_authenticator_attestation_response_s authenticatorAttestationResponse
+            = {&clientDataJson, &attestationObject, transports, &authenticatorData, &subjectPubkeyInfo, pubkey_alg};
+    wauthn_authenticator_attestation_response_s emptyAuthenticatorAttestationResponse
+            = {nullptr, nullptr, 0x00, nullptr, nullptr, pubkey_alg};
+
+    unsigned char signatureRaw[26] = {0x21, 0x22, 0x23, 0x24, };
+    unsigned char userHnadleRaw[36] = {0x31, 0x32, 0x33, 0x34, };
+    wauthn_buffer_s signature = {signatureRaw, sizeof(signatureRaw)};
+    wauthn_buffer_s userHnadle = {userHnadleRaw, sizeof(userHnadleRaw)};
+    wauthn_authenticator_assertion_response_s authenticatorAssertionResponse
+            = {&clientDataJson, &authenticatorData, &signature, &userHnadle, &attestationObject};
+    wauthn_authenticator_assertion_response_s emptyAuthenticatorAssertionResponse
+            = {nullptr, nullptr, nullptr, nullptr, nullptr};
+
+    const char *name = "test name";
+    const char *id = "test id";
+    wauthn_rp_entity_s rpEntity = {const_cast<char*>(name), const_cast<char*>(id)};
+    wauthn_rp_entity_s emptyRpEntiy = {nullptr, nullptr};
+
+    unsigned char idRaw[06] = {0x01, 0x02, 0x03, 0x04, };
+    wauthn_buffer_s bufferId = {idRaw, sizeof(idRaw)};
+    const char *displayName = "test displayName";
+    wauthn_user_entity_s userEntity = {const_cast<char*>(name), &bufferId, const_cast<char*>(displayName)};
+    wauthn_user_entity_s emptyUserEntity = {nullptr, nullptr, nullptr};
+
+    wauthn_pubkey_cred_type_e pubkeyCredType = pct_public_key;
+    wauthn_pubkey_cred_param_s credParam0 = {pubkeyCredType, WAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256};
+    wauthn_pubkey_cred_param_s credParam1 = {pubkeyCredType, WAUTHN_COSE_ALGORITHM_ECDSA_P521_WITH_SHA512};
+    wauthn_pubkey_cred_param_s pubkeyCredParam2[2] = {credParam0, credParam1};
+    wauthn_pubkey_cred_params_s pubkeyCredParams2 = {sizeof(pubkeyCredParam2)/sizeof(pubkeyCredParam2[0]), pubkeyCredParam2};
+    wauthn_pubkey_cred_param_s pubkeyCredParam1[1] = {credParam0};
+    wauthn_pubkey_cred_params_s pubkeyCredParams1 = {sizeof(pubkeyCredParam1)/sizeof(pubkeyCredParam1[0]), pubkeyCredParam1};
+    wauthn_pubkey_cred_params_s emptyPubkeyCredParams = {0, nullptr};
+
+    wauthn_pubkey_cred_descriptor_s pubkeyCredDescriptor = {pubkeyCredType, &bufferId, 3};
+    wauthn_pubkey_cred_descriptor_s emptyPubkeyCredDescriptor = {pubkeyCredType, nullptr, 0};
+
+    unsigned char idRaw0[06] = {0x01, 0x02, 0x03, 0x04, };
+    unsigned char idRaw1[16] = {0x11, 0x12, 0x13, 0x14, };
+    wauthn_buffer_s bufferId0 = {idRaw0, sizeof(idRaw0)};
+    wauthn_buffer_s bufferId1 = {idRaw1, sizeof(idRaw1)};
+    wauthn_pubkey_cred_descriptor_s credDescriptor0 = {pubkeyCredType, &bufferId0, 3};
+    wauthn_pubkey_cred_descriptor_s credDescriptor1 = {pubkeyCredType, &bufferId1, 13};
+    wauthn_pubkey_cred_descriptor_s pubkeyCredDescriptor2[2] = {credDescriptor0, credDescriptor1};
+    wauthn_pubkey_cred_descriptors_s pubkeyCredDescriptors2 = {sizeof(pubkeyCredDescriptor2)/sizeof(pubkeyCredDescriptor2[0]),
+                                                                pubkeyCredDescriptor2};
+    wauthn_pubkey_cred_descriptor_s pubkeyCredDescriptor1[1] = {credDescriptor0};
+    wauthn_pubkey_cred_descriptors_s pubkeyCredDescriptors1 = {sizeof(pubkeyCredDescriptor1)/sizeof(pubkeyCredDescriptor1[0]),
+                                                                pubkeyCredDescriptor1};
+    wauthn_pubkey_cred_descriptors_s emptyPubkeyCredDescriptors = {0, nullptr};
+
+    unsigned char extensionIdRaw[06] = {0x01, 0x02, 0x03, 0x04, };
+    unsigned char extensionValueRaw[16] = {0x11, 0x12, 0x13, 0x14, };
+    wauthn_buffer_s extensionId = {extensionIdRaw, sizeof(extensionIdRaw)};
+    wauthn_buffer_s extensionValue = {extensionValueRaw, sizeof(extensionValueRaw)};
+    wauthn_authentication_ext_s authenticationExt = {&extensionId, &extensionValue};
+    wauthn_authentication_ext_s emptyAuthenticationExt = {nullptr, nullptr};
+
+    unsigned char extensionIdRaw1[06] = {0x01, 0x02, 0x03, 0x04, };
+    unsigned char extensionValueRaw1[16] = {0x11, 0x12, 0x13, 0x14, };
+    wauthn_buffer_s extensionId1 = {extensionIdRaw1, sizeof(extensionIdRaw1)};
+    wauthn_buffer_s extensionValue1 = {extensionValueRaw1, sizeof(extensionValueRaw1)};
+    wauthn_authentication_ext_s authenticationExt1 = {&extensionId1, &extensionValue1};
+    wauthn_authentication_ext_s authenticationExtArr1[1] = {authenticationExt};
+    wauthn_authentication_ext_s authenticationExtArr2[2] = {authenticationExt, authenticationExt1};
+    wauthn_authentication_exts_s authenticationExts1 = {sizeof(authenticationExtArr1)/sizeof(authenticationExtArr1[0]),
+                                                                authenticationExtArr1};
+    wauthn_authentication_exts_s authenticationExts2 = {sizeof(authenticationExtArr2)/sizeof(authenticationExtArr2[0]),
+                                                                authenticationExtArr2};
+    wauthn_authentication_exts_s emptyAuthenticationExts = {0, nullptr};
+
+    wauthn_authenticator_attachment_e attachment = aa_platform;
+    wauthn_resident_key_requirement_e resident_key = rkr_preferred;
+    bool require_resident_key = false;
+    wauthn_user_verification_requirement_e user_verification = uvr_discouraged;
+    wauthn_authenticator_sel_cri_s authenticatorSelCri = {attachment, resident_key,
+                                require_resident_key, user_verification};
+
+    wauthn_pubkey_cred_hint_e hint0 = pch_security_key;
+    wauthn_pubkey_cred_hint_e hint1 = pch_client_device;
+    wauthn_pubkey_cred_hint_e hintAarr1[1] = {hint0};
+    wauthn_pubkey_cred_hint_e hintAarr2[2] = {hint0, hint1};
+    wauthn_pubkey_cred_hints_s pubkeyCredHints1 = {sizeof(hintAarr1)/sizeof(hintAarr1[0]), hintAarr1};
+    wauthn_pubkey_cred_hints_s pubkeyCredHints2 = {sizeof(hintAarr2)/sizeof(hintAarr2[0]), hintAarr2};
+    wauthn_pubkey_cred_hints_s emptyPubkeyCredHints = {0, nullptr};
+
+    unsigned char contactIdRaw[06] = {0x01, 0x02, 0x03, 0x04, };
+    unsigned char linkIdRaw[16] = {0x11, 0x12, 0x13, 0x14, };
+    unsigned char linkSecretRaw[26] = {0x11, 0x12, 0x13, 0x14, };
+    unsigned char authenticatorPubkeyRaw[16] = {0x11, 0x12, 0x13, 0x14, };
+    unsigned char authenticatorNameRaw[26] = {0x11, 0x12, 0x13, 0x14, };
+    unsigned char authPubkeyRaw[36] = {0x11, 0x12, 0x13, 0x14, };
+    unsigned char tunnelServerDomainRaw[36] = {0x11, 0x12, 0x13, 0x14, };
+    wauthn_buffer_s contactId = {contactIdRaw, sizeof(contactIdRaw)};
+    wauthn_buffer_s linkId = {linkIdRaw, sizeof(linkIdRaw)};
+    wauthn_buffer_s linkSecret = {linkSecretRaw, sizeof(linkSecretRaw)};
+    wauthn_buffer_s authenticatorPubkey = {authenticatorPubkeyRaw, sizeof(authenticatorPubkeyRaw)};
+    wauthn_buffer_s authenticatorName = {authenticatorNameRaw, sizeof(authenticatorNameRaw)};
+    wauthn_buffer_s authPubkey = {authPubkeyRaw, sizeof(authPubkeyRaw)};
+    wauthn_buffer_s tunnelServerDomain = {tunnelServerDomainRaw, sizeof(tunnelServerDomainRaw)};
+    wauthn_hybrid_linked_data_s hybirdLinkedData = {&contactId, &linkId, &linkSecret, &authenticatorPubkey,
+                                &authenticatorName, &signature, &authPubkey, &tunnelServerDomain};
+    wauthn_hybrid_linked_data_s emptyHybirdLinkedData = {nullptr, nullptr, nullptr, nullptr,
+                                            nullptr, nullptr, nullptr, nullptr};
+
+    unsigned char bufferRaw0[06] = {0x01, 0x02, 0x03, 0x04, };
+    unsigned char bufferRaw1[16] = {0x11, 0x12, 0x13, 0x14, };
+    wauthn_buffer_s buffer0 = {bufferRaw0, sizeof(bufferRaw0)};
+    wauthn_buffer_s buffer1 = {bufferRaw1, sizeof(bufferRaw1)};
+    wauthn_buffer_s bufferArr1[1] = {buffer0};
+    wauthn_buffer_s bufferArr2[2] = {buffer0, buffer1};
+    wauthn_attestation_formats_s attestationFormats1 = {sizeof(bufferArr1)/sizeof(bufferArr1[0]), bufferArr1};
+    wauthn_attestation_formats_s attestationFormats2 = {sizeof(bufferArr2)/sizeof(bufferArr2[0]), bufferArr2};
+    wauthn_attestation_formats_s emptyAttestationFormats = {0, nullptr};
+
+    unsigned char challengeRaw[06] = {0x01, 0x02, 0x03, 0x04, };
+    unsigned long timeout = 1000;
+    wauthn_buffer_s challenge = {challengeRaw, sizeof(challengeRaw)};
+    wauthn_attestation_pref_e attestation = ap_direct;
+    wauthn_pubkey_cred_creation_options_s pubkeyCredCreationOptions = {&rpEntity, &userEntity, &challenge,
+            &pubkeyCredParams2, timeout, &pubkeyCredDescriptors2, &authenticatorSelCri, &pubkeyCredHints2,
+            attestation, &attestationFormats1, &authenticationExts2, &hybirdLinkedData};
+    wauthn_pubkey_cred_creation_options_s emptyPubkeyCredCreationOptions = {nullptr, nullptr, nullptr,
+            nullptr, 0, nullptr, nullptr, nullptr, ap_none, nullptr, nullptr, nullptr};
+
+    const char *rpId = "test RP ID";
+    wauthn_pubkey_cred_request_options_s pubkeyCredRequestOptions = {&challenge, timeout, const_cast<char *>(rpId),
+            &pubkeyCredDescriptors2, user_verification, &pubkeyCredHints2, attestation, &attestationFormats1,
+            &authenticationExts2, &hybirdLinkedData};
+    wauthn_pubkey_cred_request_options_s emptyPubkeyCredRequestOptions = {nullptr, 0, nullptr,
+            nullptr, uvr_none, nullptr, ap_none, nullptr, nullptr, nullptr};
+
+    bool is_conditional_mediation_available = false;
+    wauthn_pubkey_credential_attestaion_s pubkeyCredentialAttestation = {&bufferId, pubkeyCredType, &bufferId0,
+            &authenticatorAttestationResponse, attachment, &authenticationExts2, is_conditional_mediation_available,
+            &buffer1, &hybirdLinkedData};
+    wauthn_pubkey_credential_attestaion_s emptyPubkeyCredentialAttestation = {nullptr, pubkeyCredType, nullptr,
+            nullptr, attachment, nullptr, is_conditional_mediation_available, nullptr, nullptr};
+
+    wauthn_pubkey_credential_assertion_s pubkeyCredentialAssertion = {&bufferId, pubkeyCredType, &bufferId0,
+            &authenticatorAssertionResponse, attachment, &authenticationExts2, is_conditional_mediation_available,
+            &buffer1, &hybirdLinkedData};
+    wauthn_pubkey_credential_assertion_s emptyPubkeyCredentialAssertion = {nullptr, pubkeyCredType, nullptr,
+            nullptr, attachment, nullptr, is_conditional_mediation_available, nullptr, nullptr};
+
+    wauthn_hash_algorithm_e hashAlg = WAUTHN_HASH_ALGORITHM_SHA_256;
+    wauthn_client_data_s clientData = {&bufferId, hashAlg};
+    wauthn_client_data_s emptyClientData = {nullptr, hashAlg};
+}
+
+class WAuthnSerializationTest : public ::testing::Test {
+protected:
+    void SetUp() override {        
+        int ret = WAUTHN_ERROR_NONE;
+        // Do initialization if needed.
+        if (ret != WAUTHN_ERROR_NONE) {
+            std::cout << "[webauthn_initialize] failed." << std::endl;
+            return;
+        }
+    }
+
+    void TearDown() override {
+        int ret = WAUTHN_ERROR_NONE;
+        // Do deinitialization if needed.
+        if (ret != WAUTHN_ERROR_NONE) {
+            std::cout << "[webauthn_deinitialize] failed." << std::endl;
+            return;
+        }
+    }
+};
+
+template<typename T, typename U>
+void __serializeDeserializeWtihWAuthnCtypeSerializer(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)
+{
+    buffer.InitForStreaming();
+    Serialization::Serialize(buffer, data);
+    buffer.ModeOutput();
+
+    buffer.ModeStreaming();
+    Deserialization::Deserialize(buffer, deserialized);
+}
+
+template<typename T, typename F>
+void __testSerialization(T data, F cmpfunction)
+{
+    MessageBuffer buffer0;
+    T deserialized0;
+    __serializeDeserializeWtihWAuthnCtypeSerializer(buffer0, data, &deserialized0);
+    EXPECT_EQ(cmpfunction(data, deserialized0), true);
+
+    MessageBuffer buffer1;
+    T deserialized1;
+    __serializeDeserializeStruct(buffer1, data, &deserialized1);
+    EXPECT_EQ(cmpfunction(data, deserialized1), true);
+}
+
+bool __compareWAuthnBuffers(const wauthn_buffer_s *expected, const wauthn_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;
+        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;
+    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);
+    EXPECT_EQ(memcmp(data, deserialized, deserialized_len), 0);
+    if (deserialized == nullptr || deserialized_len == 0) {
+        EXPECT_EQ(deserialized, nullptr);
+        EXPECT_EQ(deserialized_len, 0);
+    }
+    if (data == nullptr) {
+        EXPECT_EQ(deserialized, nullptr);
+    }
+}
+TEST_F(WAuthnSerializationTest, unsignedCharPtr)
+{
+    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, CharPtr)
+{
+    char *data = const_cast<char *>("This is a test data.");
+    char *size0data = const_cast<char *>("");
+    char *nulldata = nullptr;
+
+    __testSerialization(data, __compareCstring);
+    __testSerialization(size0data, __compareCstring);
+    __testSerialization(nulldata, __compareCstring);
+}
+
+
+bool __compareWAuthErrorE(wauthn_error_e expected, wauthn_error_e actual)
+{
+    return (expected == actual);
+}
+TEST_F(WAuthnSerializationTest, wauthn_error_e)
+{
+    __testSerialization(WAUTHN_ERROR_NONE, __compareWAuthErrorE);
+    __testSerialization(WAUTHN_ERROR_NOT_ALLOWED, __compareWAuthErrorE);
+    __testSerialization(WAUTHN_ERROR_ENCODING_FAILED, __compareWAuthErrorE);
+    __testSerialization(WAUTHN_ERROR_CANCELLED, __compareWAuthErrorE);
+}
+
+TEST_F(WAuthnSerializationTest, wauthn_buffer_s)
+{
+    unsigned char testdata[26] = {0x01, 0x02, 0x03, 0x04, };
+    wauthn_buffer_s buffer = {testdata, sizeof(testdata)};
+    __testSerialization(&buffer, __compareWAuthnBuffers);
+
+    wauthn_buffer_s emptyBuffer = {nullptr, 0x00};
+    __testSerialization(&emptyBuffer, __compareWAuthnBuffers);
+
+    __testSerialization(static_cast<wauthn_buffer_s *>(nullptr), __compareWAuthnBuffers);
+}
+
+bool __compareWAuthnAuthenticatorAttestationResponseS(
+                    const wauthn_authenticator_attestation_response_s *expected,
+                    const wauthn_authenticator_attestation_response_s *actual)
+{
+    if (actual == nullptr || expected == nullptr)
+        return (actual == expected);
+    if (__compareWAuthnBuffers(expected->client_data_json, actual->client_data_json) == false)
+        return false;
+    if (__compareWAuthnBuffers(expected->attestation_object, actual->attestation_object) == false)
+        return false;
+    if (expected->transports != actual->transports)
+        return false;
+    if (__compareWAuthnBuffers(expected->authenticator_data, actual->authenticator_data) == false)
+        return false;
+    if (__compareWAuthnBuffers(expected->subject_pubkey_info, actual->subject_pubkey_info) == false)
+        return false;
+    if (expected->pubkey_alg != actual->pubkey_alg)
+        return false;
+    return true;
+}
+TEST_F(WAuthnSerializationTest, wauthn_authenticator_attestation_response_s)
+{
+    __testSerialization(&CommonTestData::authenticatorAttestationResponse, 
+                    __compareWAuthnAuthenticatorAttestationResponseS);
+    __testSerialization(&CommonTestData::emptyAuthenticatorAttestationResponse, 
+                    __compareWAuthnAuthenticatorAttestationResponseS);
+    __testSerialization(static_cast<wauthn_authenticator_attestation_response_s *>(nullptr), 
+                    __compareWAuthnAuthenticatorAttestationResponseS);
+
+}
+
+bool __compareWAuthnAuthenticatorAssertionResponseS(
+                    const wauthn_authenticator_assertion_response_s *expected,
+                    const wauthn_authenticator_assertion_response_s *actual)
+{
+    if (actual == nullptr || expected == nullptr)
+        return (actual == expected);
+    if (__compareWAuthnBuffers(expected->client_data_json, actual->client_data_json) == false)
+        return false;
+    if (__compareWAuthnBuffers(expected->attestation_object, actual->attestation_object) == false)
+        return false;
+    if (__compareWAuthnBuffers(expected->signature, actual->signature) == false)
+        return false;
+    if (__compareWAuthnBuffers(expected->user_handle, actual->user_handle) == false)
+        return false;
+    if (__compareWAuthnBuffers(expected->attestation_object, actual->attestation_object) == false)
+        return false;
+    return true;
+}
+TEST_F(WAuthnSerializationTest, wauthn_authenticator_assertion_response_s)
+{
+    __testSerialization(&CommonTestData::authenticatorAssertionResponse, 
+                    __compareWAuthnAuthenticatorAssertionResponseS);
+    __testSerialization(&CommonTestData::emptyAuthenticatorAssertionResponse, 
+                    __compareWAuthnAuthenticatorAssertionResponseS);
+    __testSerialization(static_cast<wauthn_authenticator_assertion_response_s *>(nullptr), 
+                    __compareWAuthnAuthenticatorAssertionResponseS);
+}
+
+bool __compareWAuthnRpEntityS(const wauthn_rp_entity_s *expected,
+            const wauthn_rp_entity_s *actual)
+{
+    if (actual == nullptr || expected == nullptr)
+        return (actual == expected);
+    if (__compareCstring(expected->name, actual->name) == false)
+        return false;
+    if (__compareCstring(expected->id, actual->id) == false)
+        return false;
+    return true;
+}
+TEST_F(WAuthnSerializationTest, wauthn_rp_entity_s)
+{
+    __testSerialization(&CommonTestData::rpEntity, __compareWAuthnRpEntityS);
+    __testSerialization(&CommonTestData::emptyRpEntiy, __compareWAuthnRpEntityS);
+    __testSerialization(static_cast<wauthn_rp_entity_s *>(nullptr), __compareWAuthnRpEntityS);
+}
+
+bool __compareWAuthnUserEntityS(const wauthn_user_entity_s *expected,
+            const wauthn_user_entity_s *actual)
+{
+    if (actual == nullptr || expected == nullptr)
+        return (actual == expected);
+    if (__compareCstring(expected->name, actual->name) == false)
+        return false;
+    if (__compareWAuthnBuffers(expected->id, actual->id) == false)
+        return false;
+    if (__compareCstring(expected->display_name, actual->display_name) == false)
+        return false;
+    return true;
+}
+TEST_F(WAuthnSerializationTest, wauthn_user_entity_s)
+{
+    __testSerialization(&CommonTestData::userEntity, __compareWAuthnUserEntityS);
+    __testSerialization(&CommonTestData::emptyUserEntity, __compareWAuthnUserEntityS);
+    __testSerialization(static_cast<wauthn_user_entity_s *>(nullptr), __compareWAuthnUserEntityS);
+}
+
+
+bool __compareWAuthnPubkeyCredParamS(const wauthn_pubkey_cred_param_s *expected,
+            const wauthn_pubkey_cred_param_s *actual)
+{
+    if (actual == nullptr || expected == nullptr)
+        return (actual == expected);
+    if (actual->type != expected->type)
+        return false;
+    if (actual->alg != expected->alg)
+        return false;
+    return true;
+}
+TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_param_s)
+{
+    wauthn_pubkey_cred_param_s data1 = {pct_public_key, WAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256};
+    wauthn_pubkey_cred_param_s data2 = {pct_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);
+}
+
+bool __compareWAuthnPubkeyCredParamsS(const wauthn_pubkey_cred_params_s *expected,
+            const wauthn_pubkey_cred_params_s *actual)
+{
+    if (actual == nullptr || expected == nullptr)
+        return (actual == expected);
+    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)
+            return false;
+    return true;
+}
+TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_params_s)
+{
+    __testSerialization(&CommonTestData::pubkeyCredParams2, __compareWAuthnPubkeyCredParamsS);
+    __testSerialization(&CommonTestData::pubkeyCredParams1, __compareWAuthnPubkeyCredParamsS);
+    __testSerialization(&CommonTestData::emptyPubkeyCredParams, __compareWAuthnPubkeyCredParamsS);
+    __testSerialization(static_cast<wauthn_pubkey_cred_params_s *>(nullptr), __compareWAuthnPubkeyCredParamsS);
+}
+
+
+bool __compareWAuthnPubkeyCredDescriptorS(const wauthn_pubkey_cred_descriptor_s *expected,
+            const wauthn_pubkey_cred_descriptor_s *actual)
+{
+    if (actual == nullptr || expected == nullptr)
+        return (actual == expected);
+    if (actual->type != expected->type)
+        return false;
+    if (__compareWAuthnBuffers(actual->id, expected->id) == false)
+        return false;
+    if (actual->transports != expected->transports)
+        return false;
+    return true;
+}
+TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_descriptor_s)
+{
+    __testSerialization(&CommonTestData::pubkeyCredDescriptor, __compareWAuthnPubkeyCredDescriptorS);
+    __testSerialization(&CommonTestData::emptyPubkeyCredDescriptor, __compareWAuthnPubkeyCredDescriptorS);
+    __testSerialization(static_cast<wauthn_pubkey_cred_descriptor_s *>(nullptr), __compareWAuthnPubkeyCredDescriptorS);
+}
+
+bool __compareWAuthnPubkeyCredDescriptorsS(const wauthn_pubkey_cred_descriptors_s *expected,
+            const wauthn_pubkey_cred_descriptors_s *actual)
+{
+    if (actual == nullptr || expected == nullptr)
+        return (actual == expected);
+    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)
+            return false;
+    return true;
+}
+TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_descriptors_s)
+{
+    __testSerialization(&CommonTestData::pubkeyCredDescriptors2, __compareWAuthnPubkeyCredDescriptorsS);
+    __testSerialization(&CommonTestData::pubkeyCredDescriptors1, __compareWAuthnPubkeyCredDescriptorsS);
+    __testSerialization(&CommonTestData::emptyPubkeyCredDescriptors, __compareWAuthnPubkeyCredDescriptorsS);
+    __testSerialization(static_cast<wauthn_pubkey_cred_descriptors_s *>(nullptr), __compareWAuthnPubkeyCredDescriptorsS);
+}
+
+
+bool __compareWAuthnAuthenticationExtS(const wauthn_authentication_ext_s *expected,
+            const wauthn_authentication_ext_s *actual)
+{
+    if (actual == nullptr || expected == nullptr)
+        return (actual == expected);
+    if (__compareWAuthnBuffers(actual->extension_id, expected->extension_id) == false)
+        return false;
+    if (__compareWAuthnBuffers(actual->extension_value, expected->extension_value) == false)
+        return false;
+    return true;
+}
+TEST_F(WAuthnSerializationTest, wauthn_authentication_ext_s)
+{
+    __testSerialization(&CommonTestData::authenticationExt, __compareWAuthnAuthenticationExtS);
+    __testSerialization(&CommonTestData::emptyAuthenticationExt, __compareWAuthnAuthenticationExtS);
+    __testSerialization(static_cast<wauthn_authentication_ext_s *>(nullptr), __compareWAuthnAuthenticationExtS);
+}
+
+bool __compareWAuthnAuthenticationExtsS(const wauthn_authentication_exts_s *expected,
+            const wauthn_authentication_exts_s *actual)
+{
+    if (actual == nullptr || expected == nullptr)
+        return (actual == expected);
+    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)
+            return false;
+    return true;
+}
+TEST_F(WAuthnSerializationTest, wauthn_authentication_exts_s)
+{
+    __testSerialization(&CommonTestData::authenticationExts1, __compareWAuthnAuthenticationExtsS);
+    __testSerialization(&CommonTestData::authenticationExts2, __compareWAuthnAuthenticationExtsS);
+    __testSerialization(&CommonTestData::emptyAuthenticationExts, __compareWAuthnAuthenticationExtsS);
+    __testSerialization(static_cast<wauthn_authentication_exts_s *>(nullptr), __compareWAuthnAuthenticationExtsS);
+}
+
+bool __compareWAuthnAuthenticatorSelCriS(const wauthn_authenticator_sel_cri_s *expected,
+            const wauthn_authenticator_sel_cri_s *actual)
+{
+    if (actual == nullptr || expected == nullptr)
+        return (actual == expected);
+    if (actual->attachment != expected->attachment)
+        return false;
+    if (actual->resident_key != expected->resident_key)
+        return false;
+    if (actual->require_resident_key != expected->require_resident_key)
+        return false;
+    if (actual->user_verification != expected->user_verification)
+        return false;
+    return true;
+}
+TEST_F(WAuthnSerializationTest, wauthn_authenticator_sel_cri_s)
+{
+    __testSerialization(&CommonTestData::authenticatorSelCri, __compareWAuthnAuthenticatorSelCriS);
+    __testSerialization(static_cast<wauthn_authenticator_sel_cri_s *>(nullptr), __compareWAuthnAuthenticatorSelCriS);
+}
+
+
+bool __compareWAuthnPubkeyCredHintE(const wauthn_pubkey_cred_hint_e *expected,
+            const wauthn_pubkey_cred_hint_e *actual)
+{
+    if (actual == nullptr || expected == nullptr)
+        return (actual == expected);
+    if (*actual != *expected)
+        return false;
+    return true;
+}
+bool __compareWAuthnPubkeyCredHintsE(const wauthn_pubkey_cred_hints_s *expected,
+            const wauthn_pubkey_cred_hints_s *actual)
+{
+    if (actual == nullptr || expected == nullptr)
+        return (actual == expected);
+    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)
+            return false;
+    return true;
+}
+TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_hints_s)
+{
+    __testSerialization(&CommonTestData::pubkeyCredHints1, __compareWAuthnPubkeyCredHintsE);
+    __testSerialization(&CommonTestData::pubkeyCredHints2, __compareWAuthnPubkeyCredHintsE);
+    __testSerialization(&CommonTestData::emptyPubkeyCredHints, __compareWAuthnPubkeyCredHintsE);
+    __testSerialization(static_cast<wauthn_pubkey_cred_hints_s *>(nullptr), __compareWAuthnPubkeyCredHintsE);
+}
+
+bool __compareWAuthnHybridLinkedDataS(const wauthn_hybrid_linked_data_s *expected,
+            const wauthn_hybrid_linked_data_s *actual)
+{
+    if (actual == nullptr || expected == nullptr)
+        return (actual == expected);
+    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)
+        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->auth_pubkey, expected->auth_pubkey) == false)
+        return false;
+    if (__compareWAuthnBuffers(actual->tunnel_server_domain, expected->tunnel_server_domain) == false)
+        return false;
+    return true;
+}
+TEST_F(WAuthnSerializationTest, wauthn_hybrid_linked_data_s)
+{
+    __testSerialization(&CommonTestData::hybirdLinkedData, __compareWAuthnHybridLinkedDataS);
+    __testSerialization(&CommonTestData::emptyHybirdLinkedData, __compareWAuthnHybridLinkedDataS);
+    __testSerialization(static_cast<wauthn_hybrid_linked_data_s *>(nullptr), __compareWAuthnHybridLinkedDataS);
+}
+
+bool __compareWAuthnAttestationFormatsS(const wauthn_attestation_formats_s *expected,
+            const wauthn_attestation_formats_s *actual)
+{
+    if (actual == nullptr || expected == nullptr)
+        return (actual == expected);
+    if (actual->size != expected->size)
+        return false;
+    for (size_t i=0; i < expected->size; i++)
+        if(__compareWAuthnBuffers(expected->attestation_formats + i,
+                                    actual->attestation_formats + i) == false)
+            return false;
+    return true;
+}
+TEST_F(WAuthnSerializationTest, wauthn_attestation_formats_s)
+{
+    __testSerialization(&CommonTestData::attestationFormats1, __compareWAuthnAttestationFormatsS);
+    __testSerialization(&CommonTestData::attestationFormats2, __compareWAuthnAttestationFormatsS);
+    __testSerialization(&CommonTestData::emptyAttestationFormats, __compareWAuthnAttestationFormatsS);
+    __testSerialization(static_cast<wauthn_attestation_formats_s *>(nullptr), __compareWAuthnAttestationFormatsS);
+}
+
+bool __compareWAuthnPubkeyCredCreationOptionsS(const wauthn_pubkey_cred_creation_options_s *expected,
+            const wauthn_pubkey_cred_creation_options_s *actual)
+{
+    if (actual == nullptr || expected == nullptr)
+        return (actual == expected);
+    if(__compareWAuthnRpEntityS(expected->rp, actual->rp) == false)
+        return false;
+    if(__compareWAuthnUserEntityS(expected->user, actual->user) == false)
+        return false;
+    if(__compareWAuthnBuffers(expected->challenge, actual->challenge) == false)
+        return 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)
+        return 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)
+        return false;
+    if(__compareWAuthnAuthenticationExtsS(expected->extensions, actual->extensions) == false)
+        return false;
+    if(__compareWAuthnHybridLinkedDataS(expected->linked_device, actual->linked_device) == false)
+        return false;
+    return true;
+}
+TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_creation_options_s)
+{
+    __testSerialization(&CommonTestData::pubkeyCredCreationOptions,
+                __compareWAuthnPubkeyCredCreationOptionsS);
+    __testSerialization(&CommonTestData::emptyPubkeyCredCreationOptions,
+                __compareWAuthnPubkeyCredCreationOptionsS);
+    __testSerialization(static_cast<wauthn_pubkey_cred_creation_options_s *>(nullptr),
+                __compareWAuthnPubkeyCredCreationOptionsS);
+}
+
+
+bool __compareWAuthnPubkeyCredRequestOptionsS(const wauthn_pubkey_cred_request_options_s *expected,
+            const wauthn_pubkey_cred_request_options_s *actual)
+{
+    if (actual == nullptr || expected == nullptr)
+        return (actual == expected);
+    if(__compareWAuthnBuffers(expected->challenge, actual->challenge) == false)
+        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)
+        return false;
+    if (expected->user_verification != actual->user_verification)
+        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)
+        return false;
+    if(__compareWAuthnAuthenticationExtsS(expected->extensions, actual->extensions) == false)
+        return false;
+    if(__compareWAuthnHybridLinkedDataS(expected->linked_device, actual->linked_device) == false)
+        return false;
+    return true;
+}
+TEST_F(WAuthnSerializationTest, wauthn_pubkey_cred_request_options_s)
+{
+    __testSerialization(&CommonTestData::pubkeyCredRequestOptions,
+                __compareWAuthnPubkeyCredRequestOptionsS);
+    __testSerialization(&CommonTestData::emptyPubkeyCredRequestOptions,
+                __compareWAuthnPubkeyCredRequestOptionsS);
+    __testSerialization(static_cast<wauthn_pubkey_cred_request_options_s *>(nullptr),
+                __compareWAuthnPubkeyCredRequestOptionsS);
+}
+
+
+bool __compareWAuthnPubkeyCredentialAttestionS(const wauthn_pubkey_credential_attestaion_s *expected,
+            const wauthn_pubkey_credential_attestaion_s *actual)
+{
+    if (actual == nullptr || expected == nullptr)
+        return (actual == expected);
+    if(__compareWAuthnBuffers(expected->id, actual->id) == false)
+        return false;
+    if (expected->type != actual->type)
+        return false;
+    if(__compareWAuthnAuthenticatorAttestationResponseS(expected->response, actual->response) == false)
+        return false;
+    if(__compareWAuthnBuffers(expected->rawId, actual->rawId) == false)
+        return false;
+    if (expected->authenticator_attachment != actual->authenticator_attachment)
+        return false;
+    if(__compareWAuthnAuthenticationExtsS(expected->extensions, actual->extensions) == false)
+        return false;
+    if (expected->is_conditional_mediation_available != actual->is_conditional_mediation_available)
+        return false;
+    if(__compareWAuthnBuffers(expected->json_data, actual->json_data) == false)
+        return false;
+    if(__compareWAuthnHybridLinkedDataS(expected->linked_device, actual->linked_device) == false)
+        return false;
+    return true;
+}
+TEST_F(WAuthnSerializationTest, wauthn_pubkey_credential_attestaion_s)
+{
+    __testSerialization(&CommonTestData::pubkeyCredentialAttestation,
+                __compareWAuthnPubkeyCredentialAttestionS);
+    __testSerialization(&CommonTestData::emptyPubkeyCredentialAttestation,
+                __compareWAuthnPubkeyCredentialAttestionS);
+    __testSerialization(static_cast<wauthn_pubkey_credential_attestaion_s *>(nullptr),
+                __compareWAuthnPubkeyCredentialAttestionS);
+}
+
+
+bool __compareWAuthnPubkeyCredentialAssertionS(const wauthn_pubkey_credential_assertion_s *expected,
+            const wauthn_pubkey_credential_assertion_s *actual)
+{
+    if (actual == nullptr || expected == nullptr)
+        return (actual == expected);
+    if(__compareWAuthnBuffers(expected->id, actual->id) == false)
+        return false;
+    if (expected->type != actual->type)
+        return false;
+    if(__compareWAuthnAuthenticatorAssertionResponseS(expected->response, actual->response) == false)
+        return false;
+    if(__compareWAuthnBuffers(expected->rawId, actual->rawId) == false)
+        return false;
+    if (expected->authenticator_attachment != actual->authenticator_attachment)
+        return false;
+    if(__compareWAuthnAuthenticationExtsS(expected->extensions, actual->extensions) == false)
+        return false;
+    if (expected->is_conditional_mediation_available != actual->is_conditional_mediation_available)
+        return false;
+    if(__compareWAuthnBuffers(expected->json_data, actual->json_data) == false)
+        return false;
+    if(__compareWAuthnHybridLinkedDataS(expected->linked_device, actual->linked_device) == false)
+        return false;
+    return true;
+}
+TEST_F(WAuthnSerializationTest, wauthn_pubkey_credential_assertion_s)
+{
+    __testSerialization(&CommonTestData::pubkeyCredentialAssertion,
+                __compareWAuthnPubkeyCredentialAssertionS);
+    __testSerialization(&CommonTestData::emptyPubkeyCredentialAssertion,
+                __compareWAuthnPubkeyCredentialAssertionS);
+    __testSerialization(static_cast<wauthn_pubkey_credential_assertion_s *>(nullptr),
+                __compareWAuthnPubkeyCredentialAssertionS);
+}
+
+
+bool __compareWAuthnClientDataS(const wauthn_client_data_s *expected, const wauthn_client_data_s *actual)
+{
+    if (actual == nullptr || expected == nullptr)
+        return (actual == expected);
+    if(__compareWAuthnBuffers(expected->client_data_json, actual->client_data_json) == false)
+        return false;
+    if (expected->hash_alg != actual->hash_alg)
+        return false;
+    return true;
+}
+TEST_F(WAuthnSerializationTest, wauthn_client_data_s)
+{
+    __testSerialization(&CommonTestData::clientData, __compareWAuthnClientDataS);
+    __testSerialization(&CommonTestData::emptyClientData, __compareWAuthnClientDataS);
+    __testSerialization(static_cast<wauthn_client_data_s *>(nullptr), __compareWAuthnClientDataS);
+}
+
+template<typename T, typename U, typename FT, typename FU>
+void __testMultipleSerialization(T first, U second, FT cmpfirst, FU cmpsecond)
+{
+    T deserialized_first;
+    U deserialized_second;
+
+    MessageBuffer buffer;
+    buffer.InitForStreaming();
+    Serialization::Serialize(buffer, first, second);
+    buffer.ModeOutput();
+
+    buffer.ModeStreaming();
+    Deserialization::Deserialize(buffer, &deserialized_first, &deserialized_second);
+
+    EXPECT_EQ(cmpfirst(first, deserialized_first), true);
+    EXPECT_EQ(cmpsecond(second, deserialized_second), true);
+}
+
+TEST_F(WAuthnSerializationTest, multiple_serialization_mcreq)
+{
+    wauthn_client_data_s *client_data = &CommonTestData::clientData;
+    wauthn_pubkey_cred_creation_options_s *options = &CommonTestData::pubkeyCredCreationOptions;
+
+    __testMultipleSerialization(client_data, options, 
+            __compareWAuthnClientDataS, __compareWAuthnPubkeyCredCreationOptionsS);
+}
+
+TEST_F(WAuthnSerializationTest, multiple_serialization_gareq)
+{
+    wauthn_client_data_s *client_data = &CommonTestData::clientData;
+    wauthn_pubkey_cred_request_options_s *options = &CommonTestData::pubkeyCredRequestOptions;
+
+    __testMultipleSerialization(client_data, options, 
+            __compareWAuthnClientDataS, __compareWAuthnPubkeyCredRequestOptionsS);
+}
+
+TEST_F(WAuthnSerializationTest, multiple_serialization_mcres)
+{
+    wauthn_pubkey_credential_attestaion_s *pubkeyCred = &CommonTestData::pubkeyCredentialAttestation;
+    wauthn_error_e result = WAUTHN_ERROR_PERMISSION_DENIED;
+
+    __testMultipleSerialization(pubkeyCred, result, 
+            __compareWAuthnPubkeyCredentialAttestionS, __compareWAuthErrorE);
+}
+
+TEST_F(WAuthnSerializationTest, multiple_serialization_gares)
+{
+    wauthn_pubkey_credential_assertion_s *pubkeyCred = &CommonTestData::pubkeyCredentialAssertion;
+    wauthn_error_e result = WAUTHN_ERROR_CANCELLED;
+
+    __testMultipleSerialization(pubkeyCred, result, 
+            __compareWAuthnPubkeyCredentialAssertionS, __compareWAuthErrorE);
+}
+
+
+} // namespace WA
\ No newline at end of file