/**
 *  Copyright Notice:
 *  Copyright 2021-2022 DMTF. All rights reserved.
 *  License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md
 **/

#include "spdm_unit_test.h"
#include "internal/libspdm_responder_lib.h"

#if LIBSPDM_ENABLE_CAPABILITY_CSR_CAP

#define LIBSPDM_MAX_CSR_SIZE 0x1000

/*refer to https://github.com/Mbed-TLS/mbedtls/blob/3048c8c90654eb116a6b17c0d2d27c3ccbe6782c/programs/x509/cert_req.c#L119-L129*/
#define LIBSPDM_MAX_REQ_INFO_BUFFER_SIZE 4096

uint8_t m_csr_opaque_data[8] = "libspdm";

/*ECC 256 req_info(include right req_info attribute)*/
uint8_t req_info_sequence[] = {0x30, 0x81, 0xBF,};
uint8_t req_info_version[] = {0x02, 0x01, 0x00,};
uint8_t req_info_subject[] = {
    0x30, 0x45, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31,
    0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0C, 0x0A, 0x53, 0x6F, 0x6D, 0x65, 0x2D, 0x53,
    0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x18, 0x49,
    0x6E, 0x74, 0x65, 0x72, 0x6E, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20,
    0x50, 0x74, 0x79, 0x20, 0x4C, 0x74, 0x64,
};
uint8_t req_info_right_attributes[] = {
    /*[0]: attributes*/
    0xA0, 0x18, 0x30, 0x16,
    /*OID*/
    0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x07,
    /*attributes*/
    0x31, 0x09, 0x0C, 0x07, 0x74, 0x65, 0x73, 0x74, 0x31, 0x32, 0x33
};

/*the unique attribute from right_req_info*/
uint8_t right_req_info_string[] = {0x74, 0x65, 0x73, 0x74, 0x31, 0x32, 0x33};
/*the default subject without req_info*/
uint8_t default_subject1[] = {
    0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4E, 0x4C,
};

uint8_t default_subject2[] = {
    0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x08, 0x50, 0x6F, 0x6C, 0x61, 0x72, 0x53, 0x53, 0x4C,
};
uint8_t default_subject3[] = {
    0x0C, 0x11, 0x50, 0x6F, 0x6C, 0x61, 0x72, 0x53, 0x53, 0x4C, 0x20, 0x53, 0x65, 0x72, 0x76,
    0x65, 0x72, 0x20, 0x31
};

static uint8_t right_req_info[LIBSPDM_MAX_REQ_INFO_BUFFER_SIZE];
static uint8_t wrong_req_info[LIBSPDM_MAX_REQ_INFO_BUFFER_SIZE];
static uint16_t req_info_len;

/*gen right_req_info and wrong_req_info*/
void libspdm_gen_req_info()
{
    uint8_t *req_info_p;
    void *req_info_pkinfo;
    size_t req_info_pkinfo_len;

    libspdm_zero_mem(right_req_info, sizeof(right_req_info));
    libspdm_zero_mem(wrong_req_info, sizeof(wrong_req_info));

    req_info_p = right_req_info;
    req_info_len = sizeof(right_req_info);

    libspdm_read_responder_public_key(m_libspdm_use_asym_algo,
                                      &req_info_pkinfo, &req_info_pkinfo_len);

    /*concat right_req_info*/
    libspdm_copy_mem(req_info_p, req_info_len, req_info_sequence, sizeof(req_info_sequence));
    req_info_p += sizeof(req_info_sequence);
    req_info_len -= sizeof(req_info_sequence);

    libspdm_copy_mem(req_info_p, req_info_len, req_info_version, sizeof(req_info_version));
    req_info_p += sizeof(req_info_version);
    req_info_len -= sizeof(req_info_version);

    libspdm_copy_mem(req_info_p, req_info_len, req_info_subject, sizeof(req_info_subject));
    req_info_p += sizeof(req_info_subject);
    req_info_len -= sizeof(req_info_subject);

    libspdm_copy_mem(req_info_p, req_info_len, req_info_pkinfo, req_info_pkinfo_len);
    req_info_p += req_info_pkinfo_len;
    req_info_len = (uint16_t)(req_info_len - req_info_pkinfo_len);

    libspdm_copy_mem(req_info_p, req_info_len,
                     req_info_right_attributes, sizeof(req_info_right_attributes));
    req_info_p += sizeof(req_info_right_attributes);
    req_info_len -= sizeof(req_info_right_attributes);

    req_info_len = sizeof(right_req_info) - req_info_len;

    /*concat wrong_req_info*/
    libspdm_copy_mem(wrong_req_info, sizeof(wrong_req_info), right_req_info, req_info_len);
    /*make the wrong_req_info is wrong*/
    *wrong_req_info = '1';

    free(req_info_pkinfo);
}

/*find destination buffer from source buffer*/
bool libspdm_find_buffer(uint8_t *src, size_t src_len, uint8_t *dst, size_t dst_len)
{
    size_t index;

    if ((src == NULL) || (dst == NULL)) {
        return false;
    }

    if (src_len < dst_len) {
        return false;
    }

    for (index = 0; index < src_len - dst_len; index++) {
        if ((*(src + index) == *dst) &&
            libspdm_consttime_is_mem_equal(src + index, dst, dst_len)) {
            return true;
        }
    }

    return false;
}

/*get the cached csr*/
bool libspdm_test_read_cached_csr(uint8_t **csr_pointer, size_t *csr_len)
{
    bool res;
    char *file;

    file = "test_csr/cached.csr";

    res = libspdm_read_input_file(file, (void **)csr_pointer, csr_len);
    return res;
}

/*
 * If device need reset to set csr, the function simulates the CSR state before device reset.
 * The returned status indicates whether the setting was successful or unsuccessful.
 **/
bool libspdm_set_csr_before_reset()
{
    char *file_name = "test_csr/cached.csr";
    char *new_name = "test_csr/cached.staging";

    if (rename(file_name, new_name) != 0) {
        return false;
    }

    return true;
}

/*
 * If device need reset to set csr, the function simulates the CSR state after device reset.
 * The returned status indicates whether the setting was successful or unsuccessful.
 **/
bool libspdm_set_csr_after_reset()
{
    char *file_name = "test_csr/cached.csr";
    char *new_name = "test_csr/cached.staging";

    if (rename(new_name, file_name) != 0) {
        return false;
    }

    return true;
}

/*ensure that cached.csr exists in test_csr at the beginning*/
void libspdm_clear_cached_csr()
{
    char *new_name = "test_csr/cached.csr";
    char *file_name = "test_csr/cached.staging";

    rename(file_name, new_name);
}

/*clean the cached last SPDM csr request*/
void libspdm_test_clear_cached_last_request()
{
    uint8_t index;

    char file[] = "cached_last_csr_x_request";

    for (index = 1; index <= SPDM_MAX_CSR_TRACKING_TAG; index++) {
        file[16] = (char)(index + '0');
        libspdm_write_output_file(file, NULL, 0);
    }
}

/*check the csr is consistent with the is_device_cert_model*/
bool libspdm_check_csr_basic_constraints(uint8_t *csr, uint16_t csr_len, bool is_device_cert_model)
{
    bool result;
    uint8_t *ptr;
    uint16_t length;
    size_t obj_len;
    uint8_t *end;

    /*basic_constraints: CA: false */
    #define BASIC_CONSTRAINTS_STRING_FALSE {0x30, 0x00}
    uint8_t basic_constraints_false[] = BASIC_CONSTRAINTS_STRING_FALSE;

    /*basic_constraints: CA: true */
    #define BASIC_CONSTRAINTS_STRING_TRUE {0x30, 0x03, 0x01, 0x01, 0xFF}
    uint8_t basic_constraints_true[] = BASIC_CONSTRAINTS_STRING_TRUE;

    length = csr_len;
    ptr = (uint8_t*)csr;
    obj_len = 0;
    end = ptr + length;

    result = libspdm_asn1_get_tag(&ptr, end, &obj_len,
                                  LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
    if (!result) {
        return false;
    }

    result = libspdm_asn1_get_tag(&ptr, end, &obj_len,
                                  LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
    if (!result) {
        return false;
    }

    end = ptr + obj_len;

    /*version*/
    result = libspdm_asn1_get_tag(&ptr, end, &obj_len, LIBSPDM_CRYPTO_ASN1_INTEGER);
    if (!result) {
        return false;
    }
    ptr += obj_len;

    /*subject*/
    result = libspdm_asn1_get_tag(&ptr, end, &obj_len,
                                  LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
    if (!result) {
        return false;
    }
    ptr += obj_len;

    /*PKinfo*/
    result = libspdm_asn1_get_tag(&ptr, end, &obj_len,
                                  LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
    if (!result) {
        return false;
    }
    ptr += obj_len;

    /*attribute*/
    result = libspdm_asn1_get_tag(&ptr, end, &obj_len,
                                  LIBSPDM_CRYPTO_ASN1_CONTEXT_SPECIFIC |
                                  LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
    if (!result) {
        return false;
    }

    result = libspdm_asn1_get_tag(&ptr, end, &obj_len,
                                  LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
    if (!result) {
        return false;
    }
    result = libspdm_asn1_get_tag(&ptr, end, &obj_len, LIBSPDM_CRYPTO_ASN1_OID);
    if (!result) {
        return false;
    }
    ptr += obj_len;

    result = libspdm_asn1_get_tag(&ptr, end, &obj_len,
                                  LIBSPDM_CRYPTO_ASN1_SET | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
    if (!result) {
        return false;
    }
    result = libspdm_asn1_get_tag(&ptr, end, &obj_len,
                                  LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
    if (!result) {
        return false;
    }
    result = libspdm_asn1_get_tag(&ptr, end, &obj_len,
                                  LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED);
    if (!result) {
        return false;
    }
    /*basic constriants oid*/
    result = libspdm_asn1_get_tag(&ptr, end, &obj_len, LIBSPDM_CRYPTO_ASN1_OID);
    if (!result) {
        return false;
    }
    ptr += obj_len;

    /*basic constriants*/
    result = libspdm_asn1_get_tag(&ptr, end, &obj_len, LIBSPDM_CRYPTO_ASN1_OCTET_STRING);
    if (!result) {
        return false;
    }

    if (is_device_cert_model) {
        result = libspdm_consttime_is_mem_equal(
            ptr, basic_constraints_false, sizeof(basic_constraints_false));
    } else {
        result = libspdm_consttime_is_mem_equal(
            ptr, basic_constraints_true, sizeof(basic_constraints_true));
    }

    return result;
}

/**
 * Test 1: receives a valid GET_CSR request message from Requester
 * Expected Behavior: produces a valid CSR response message with device_cert mode
 **/
void libspdm_test_responder_csr_case1(void **state)
{
    libspdm_return_t status;
    libspdm_test_context_t *spdm_test_context;
    libspdm_context_t *spdm_context;
    size_t response_size;
    uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE];
    spdm_csr_response_t *spdm_response;
    spdm_get_csr_request_t *m_libspdm_get_csr_request;
    uint8_t wrong_csr[LIBSPDM_MAX_CSR_SIZE];
    bool result;
    bool is_device_cert_model;

    libspdm_zero_mem(wrong_csr, LIBSPDM_MAX_CSR_SIZE);

    spdm_test_context = *state;
    spdm_context = spdm_test_context->spdm_context;
    spdm_test_context->case_id = 0x1;
    spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
                                            SPDM_VERSION_NUMBER_SHIFT_BIT;

    spdm_context->connection_info.connection_state =
        LIBSPDM_CONNECTION_STATE_NEGOTIATED;
    spdm_context->local_context.capability.flags |=
        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CSR_CAP;
    spdm_context->connection_info.algorithm.base_hash_algo =
        m_libspdm_use_hash_algo;
    spdm_context->connection_info.algorithm.base_asym_algo =
        m_libspdm_use_asym_algo;

    is_device_cert_model = true;
    spdm_context->local_context.capability.flags &=
        ~SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ALIAS_CERT_CAP;

    m_libspdm_get_csr_request = malloc(sizeof(spdm_get_csr_request_t));

    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_12;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 0;
    m_libspdm_get_csr_request->header.param2 = 0;

    m_libspdm_get_csr_request->opaque_data_length = 0;
    m_libspdm_get_csr_request->requester_info_length = 0;

    size_t m_libspdm_get_csr_request_size = sizeof(spdm_get_csr_request_t);

    /*init req_info*/
    libspdm_gen_req_info();

    response_size = sizeof(response);
    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);

    spdm_response = (void *)response;
    assert_int_equal(response_size, sizeof(spdm_csr_response_t) + spdm_response->csr_length);
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_CSR);

    /*check returned CSR not zero */
    assert_memory_not_equal(spdm_response + 1, wrong_csr, spdm_response->csr_length);

    /*check the resulting CSR shall be for a Device Certificate*/
    result = libspdm_check_csr_basic_constraints((uint8_t *)(spdm_response + 1),
                                                 spdm_response->csr_length, is_device_cert_model);
    assert_true(result);

    /*check that returned CSR contains default subject*/
    assert_true(libspdm_find_buffer((uint8_t *)(spdm_response + 1), spdm_response->csr_length,
                                    default_subject1, sizeof(default_subject1)));
    assert_true(libspdm_find_buffer((uint8_t *)(spdm_response + 1), spdm_response->csr_length,
                                    default_subject2, sizeof(default_subject2)));
    assert_true(libspdm_find_buffer((uint8_t *)(spdm_response + 1), spdm_response->csr_length,
                                    default_subject3, sizeof(default_subject3)));
    free(m_libspdm_get_csr_request);
}

/**
 * Test 2: Wrong GET_CSR message size (larger than expected)
 * Expected Behavior: generate an ERROR_RESPONSE with code SPDM_ERROR_CODE_INVALID_REQUEST
 **/
void libspdm_test_responder_csr_case2(void **state)
{
    libspdm_return_t status;
    libspdm_test_context_t *spdm_test_context;
    libspdm_context_t *spdm_context;
    size_t response_size;
    uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE];
    spdm_csr_response_t *spdm_response;
    spdm_get_csr_request_t *m_libspdm_get_csr_request;

    spdm_test_context = *state;
    spdm_context = spdm_test_context->spdm_context;
    spdm_test_context->case_id = 0x2;
    spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
                                            SPDM_VERSION_NUMBER_SHIFT_BIT;

    spdm_context->connection_info.connection_state =
        LIBSPDM_CONNECTION_STATE_NEGOTIATED;
    spdm_context->local_context.capability.flags |=
        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CSR_CAP;
    spdm_context->connection_info.algorithm.base_hash_algo =
        m_libspdm_use_hash_algo;
    spdm_context->connection_info.algorithm.base_asym_algo =
        m_libspdm_use_asym_algo;


    m_libspdm_get_csr_request = malloc(sizeof(spdm_get_csr_request_t));

    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_12;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 0;
    m_libspdm_get_csr_request->header.param2 = 0;

    m_libspdm_get_csr_request->opaque_data_length = 0;
    m_libspdm_get_csr_request->requester_info_length = 0;

    /* Bad request size*/
    size_t m_libspdm_get_csr_request_size = sizeof(spdm_get_csr_request_t) - 1;

    response_size = sizeof(response);
    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);

    assert_int_equal(response_size, sizeof(spdm_error_response_t));
    spdm_response = (void *)response;
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_ERROR);
    assert_int_equal(spdm_response->header.param1,
                     SPDM_ERROR_CODE_INVALID_REQUEST);
    assert_int_equal(spdm_response->header.param2, 0);

    free(m_libspdm_get_csr_request);
}

/**
 * Test 3: receives a valid GET_CSR request message from Requester with non-null right req_info
 * Expected Behavior: produces a valid CSR response message
 **/
void libspdm_test_responder_csr_case3(void **state)
{
    libspdm_return_t status;
    libspdm_test_context_t *spdm_test_context;
    libspdm_context_t *spdm_context;
    size_t response_size;
    uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE];
    spdm_csr_response_t *spdm_response;
    spdm_get_csr_request_t *m_libspdm_get_csr_request;
    uint8_t wrong_csr[LIBSPDM_MAX_CSR_SIZE];
    libspdm_zero_mem(wrong_csr, LIBSPDM_MAX_CSR_SIZE);
    uint8_t *csr;

    spdm_test_context = *state;
    spdm_context = spdm_test_context->spdm_context;
    spdm_test_context->case_id = 0x3;
    spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
                                            SPDM_VERSION_NUMBER_SHIFT_BIT;

    spdm_context->connection_info.connection_state =
        LIBSPDM_CONNECTION_STATE_NEGOTIATED;
    spdm_context->local_context.capability.flags |=
        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CSR_CAP;
    spdm_context->connection_info.algorithm.base_hash_algo =
        m_libspdm_use_hash_algo;
    spdm_context->connection_info.algorithm.base_asym_algo =
        m_libspdm_use_asym_algo;

    m_libspdm_get_csr_request = malloc(sizeof(spdm_get_csr_request_t) +
                                       req_info_len);

    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_12;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 0;
    m_libspdm_get_csr_request->header.param2 = 0;

    m_libspdm_get_csr_request->opaque_data_length = 0;
    m_libspdm_get_csr_request->requester_info_length = req_info_len;

    libspdm_copy_mem(m_libspdm_get_csr_request + 1, req_info_len,
                     right_req_info, req_info_len);

    size_t m_libspdm_get_csr_request_size = sizeof(spdm_get_csr_request_t) +
                                            req_info_len;

    response_size = sizeof(response);
    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);

    spdm_response = (void *)response;
    assert_int_equal(response_size, sizeof(spdm_csr_response_t) + spdm_response->csr_length);
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_CSR);

    /*check returned CSR not zero */
    assert_memory_not_equal(spdm_response + 1, wrong_csr, spdm_response->csr_length);

    csr = (uint8_t *)(spdm_response + 1);
    /*check that returned CSR contains req_info attribute*/
    assert_true(libspdm_find_buffer(csr, spdm_response->csr_length,
                                    right_req_info_string, sizeof(right_req_info_string)));

    /*check that returned CSR contains req_info subject*/
    assert_true(libspdm_find_buffer(csr, spdm_response->csr_length,
                                    req_info_subject, sizeof(req_info_subject)));

    free(m_libspdm_get_csr_request);
}

/**
 * Test 4: receives a valid GET_CSR request message from Requester with non-null opaque_data
 * Expected Behavior: produces a valid CSR response message
 **/
void libspdm_test_responder_csr_case4(void **state)
{
    libspdm_return_t status;
    libspdm_test_context_t *spdm_test_context;
    libspdm_context_t *spdm_context;
    size_t response_size;
    uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE];
    spdm_csr_response_t *spdm_response;
    spdm_get_csr_request_t *m_libspdm_get_csr_request;
    uint8_t wrong_csr[LIBSPDM_MAX_CSR_SIZE];
    libspdm_zero_mem(wrong_csr, LIBSPDM_MAX_CSR_SIZE);

    spdm_test_context = *state;
    spdm_context = spdm_test_context->spdm_context;
    spdm_test_context->case_id = 0x4;
    spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
                                            SPDM_VERSION_NUMBER_SHIFT_BIT;

    spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_NEGOTIATED;
    spdm_context->local_context.capability.flags |= SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CSR_CAP;
    spdm_context->connection_info.algorithm.base_hash_algo = m_libspdm_use_hash_algo;
    spdm_context->connection_info.algorithm.base_asym_algo = m_libspdm_use_asym_algo;
    spdm_context->connection_info.algorithm.other_params_support =
        SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_0;

    m_libspdm_get_csr_request = malloc(sizeof(spdm_get_csr_request_t) +
                                       sizeof(m_csr_opaque_data));

    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_12;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 0;
    m_libspdm_get_csr_request->header.param2 = 0;

    m_libspdm_get_csr_request->opaque_data_length = sizeof(m_csr_opaque_data);
    m_libspdm_get_csr_request->requester_info_length = 0;

    libspdm_copy_mem(m_libspdm_get_csr_request + 1, sizeof(m_csr_opaque_data),
                     m_csr_opaque_data, sizeof(m_csr_opaque_data));

    size_t m_libspdm_get_csr_request_size = sizeof(spdm_get_csr_request_t) +
                                            sizeof(m_csr_opaque_data);

    response_size = sizeof(response);
    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);

    spdm_response = (void *)response;
    assert_int_equal(response_size, sizeof(spdm_csr_response_t) + spdm_response->csr_length);
    assert_int_equal(spdm_response->header.request_response_code, SPDM_CSR);

    /*check returned CSR not zero */
    assert_memory_not_equal(spdm_response + 1, wrong_csr, spdm_response->csr_length);

    free(m_libspdm_get_csr_request);
}

/**
 * Test 5: receives a valid GET_CSR request message from Requester with non-null wrong req_info
 * Expected Behavior: generate an ERROR_RESPONSE with code SPDM_ERROR_CODE_INVALID_REQUEST
 **/
void libspdm_test_responder_csr_case5(void **state)
{
    libspdm_return_t status;
    libspdm_test_context_t *spdm_test_context;
    libspdm_context_t *spdm_context;
    size_t response_size;
    uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE];
    spdm_csr_response_t *spdm_response;
    spdm_get_csr_request_t *m_libspdm_get_csr_request;
    uint8_t wrong_csr[LIBSPDM_MAX_CSR_SIZE];
    libspdm_zero_mem(wrong_csr, LIBSPDM_MAX_CSR_SIZE);

    spdm_test_context = *state;
    spdm_context = spdm_test_context->spdm_context;
    spdm_test_context->case_id = 0x5;
    spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
                                            SPDM_VERSION_NUMBER_SHIFT_BIT;

    spdm_context->connection_info.connection_state =
        LIBSPDM_CONNECTION_STATE_NEGOTIATED;
    spdm_context->local_context.capability.flags |=
        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CSR_CAP;
    spdm_context->connection_info.algorithm.base_hash_algo =
        m_libspdm_use_hash_algo;
    spdm_context->connection_info.algorithm.base_asym_algo =
        m_libspdm_use_asym_algo;

    m_libspdm_get_csr_request = malloc(sizeof(spdm_get_csr_request_t) +
                                       req_info_len);

    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_12;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 0;
    m_libspdm_get_csr_request->header.param2 = 0;

    m_libspdm_get_csr_request->opaque_data_length = 0;
    m_libspdm_get_csr_request->requester_info_length = req_info_len;

    libspdm_copy_mem(m_libspdm_get_csr_request + 1, req_info_len,
                     wrong_req_info, req_info_len);

    size_t m_libspdm_get_csr_request_size = sizeof(spdm_get_csr_request_t) +
                                            req_info_len;

    response_size = sizeof(response);
    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);

    assert_int_equal(response_size, sizeof(spdm_error_response_t));
    spdm_response = (void *)response;
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_ERROR);
    assert_int_equal(spdm_response->header.param1,
                     SPDM_ERROR_CODE_INVALID_REQUEST);
    assert_int_equal(spdm_response->header.param2, 0);

    free(m_libspdm_get_csr_request);
}

/**
 * Test 6: receives a valid GET_CSR request message from Requester with need_reset
 * Expected Behavior: the first get_csr: responder return need reset;
 *                    the second get_csr after device reset: get the cached valid csr;
 **/
void libspdm_test_responder_csr_case6(void **state)
{
    libspdm_return_t status;
    libspdm_test_context_t *spdm_test_context;
    libspdm_context_t *spdm_context;
    size_t response_size;
    uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE];
    spdm_csr_response_t *spdm_response;
    spdm_get_csr_request_t *m_libspdm_get_csr_request;
    uint8_t cached_csr[LIBSPDM_MAX_CSR_SIZE];
    libspdm_zero_mem(cached_csr, LIBSPDM_MAX_CSR_SIZE);

    uint8_t *csr_pointer;
    size_t csr_len;

    if (!libspdm_test_read_cached_csr(&csr_pointer, &csr_len)) {
        assert_false(true);
    }

    libspdm_copy_mem(cached_csr, LIBSPDM_MAX_CSR_SIZE, csr_pointer, csr_len);
    free(csr_pointer);

    spdm_test_context = *state;
    spdm_context = spdm_test_context->spdm_context;
    spdm_test_context->case_id = 0x6;
    spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
                                            SPDM_VERSION_NUMBER_SHIFT_BIT;

    spdm_context->connection_info.connection_state =
        LIBSPDM_CONNECTION_STATE_NEGOTIATED;
    spdm_context->local_context.capability.flags |=
        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CSR_CAP;

    /*set responder need reset*/
    spdm_context->local_context.capability.flags |=
        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_INSTALL_RESET_CAP;

    spdm_context->connection_info.algorithm.base_hash_algo =
        m_libspdm_use_hash_algo;
    spdm_context->connection_info.algorithm.base_asym_algo =
        m_libspdm_use_asym_algo;

    /*set csr before reset*/
    assert_true(libspdm_set_csr_before_reset());

    m_libspdm_get_csr_request = malloc(sizeof(spdm_get_csr_request_t) +
                                       req_info_len);

    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_12;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 0;
    m_libspdm_get_csr_request->header.param2 = 0;

    m_libspdm_get_csr_request->opaque_data_length = 0;
    m_libspdm_get_csr_request->requester_info_length = req_info_len;

    libspdm_copy_mem(m_libspdm_get_csr_request + 1, req_info_len,
                     right_req_info, req_info_len);

    size_t m_libspdm_get_csr_request_size = sizeof(spdm_get_csr_request_t) +
                                            req_info_len;

    response_size = sizeof(response);

    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);
    /*first get_csr: the responder need reset*/
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
    assert_int_equal(response_size, sizeof(spdm_error_response_t));
    spdm_response = (void *)response;
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_ERROR);
    assert_int_equal(spdm_response->header.param1,
                     SPDM_ERROR_CODE_RESET_REQUIRED);
    assert_int_equal(spdm_response->header.param2, 0);

    /*set csr after reset*/
    assert_true(libspdm_set_csr_after_reset());

    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_12;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 0;
    m_libspdm_get_csr_request->header.param2 = 0;

    m_libspdm_get_csr_request->opaque_data_length = 0;
    m_libspdm_get_csr_request->requester_info_length = req_info_len;
    libspdm_copy_mem(m_libspdm_get_csr_request + 1, req_info_len,
                     right_req_info, req_info_len);

    response_size = sizeof(response);
    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);
    /*second get_csr after device reset: get the responder cached csr*/
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);

    spdm_response = (void *)response;
    assert_int_equal(response_size, sizeof(spdm_csr_response_t) + spdm_response->csr_length);
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_CSR);

    /*check returned CSR is equal the cached CSR */
    assert_memory_equal(spdm_response + 1, cached_csr, spdm_response->csr_length);

    /*clear cached req_info*/
    libspdm_test_clear_cached_last_request();
    free(m_libspdm_get_csr_request);
}

/**
 * Test 7: receives a valid GET_CSR request message from Requester with non-null right req_info and opaque_data
 * Expected Behavior: produces a valid CSR response message
 **/
void libspdm_test_responder_csr_case7(void **state)
{
    libspdm_return_t status;
    libspdm_test_context_t *spdm_test_context;
    libspdm_context_t *spdm_context;
    size_t response_size;
    uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE];
    spdm_csr_response_t *spdm_response;
    spdm_get_csr_request_t *libspdm_get_csr_request;
    uint8_t wrong_csr[LIBSPDM_MAX_CSR_SIZE];
    libspdm_zero_mem(wrong_csr, LIBSPDM_MAX_CSR_SIZE);
    uint8_t *csr;

    spdm_test_context = *state;
    spdm_context = spdm_test_context->spdm_context;
    spdm_test_context->case_id = 0x7;
    spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
                                            SPDM_VERSION_NUMBER_SHIFT_BIT;

    spdm_context->connection_info.connection_state =
        LIBSPDM_CONNECTION_STATE_NEGOTIATED;
    spdm_context->local_context.capability.flags = 0;
    spdm_context->local_context.capability.flags |=
        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CSR_CAP;
    spdm_context->connection_info.algorithm.base_hash_algo =
        m_libspdm_use_hash_algo;
    spdm_context->connection_info.algorithm.base_asym_algo =
        m_libspdm_use_asym_algo;

    libspdm_get_csr_request = malloc(sizeof(spdm_get_csr_request_t) +
                                     sizeof(m_csr_opaque_data) +
                                     req_info_len);

    libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_12;
    libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    libspdm_get_csr_request->header.param1 = 0;
    libspdm_get_csr_request->header.param2 = 0;
    libspdm_get_csr_request->opaque_data_length = sizeof(m_csr_opaque_data);
    libspdm_get_csr_request->requester_info_length = req_info_len;

    libspdm_copy_mem(libspdm_get_csr_request + 1, req_info_len,
                     right_req_info, req_info_len);

    libspdm_copy_mem((uint8_t *)(libspdm_get_csr_request + 1) + req_info_len,
                     sizeof(m_csr_opaque_data),
                     m_csr_opaque_data, sizeof(m_csr_opaque_data));

    size_t libspdm_get_csr_request_size = sizeof(spdm_get_csr_request_t) +
                                          sizeof(m_csr_opaque_data) +
                                          req_info_len;

    response_size = sizeof(response);
    status = libspdm_get_response_csr(spdm_context,
                                      libspdm_get_csr_request_size,
                                      libspdm_get_csr_request,
                                      &response_size, response);
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);

    spdm_response = (void *)response;
    assert_int_equal(response_size, sizeof(spdm_csr_response_t) + spdm_response->csr_length);
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_CSR);

    /*check returned CSR not zero */
    assert_memory_not_equal(spdm_response + 1, wrong_csr, spdm_response->csr_length);

    csr = (uint8_t *)(spdm_response + 1);
    assert_true(libspdm_find_buffer(csr, spdm_response->csr_length,
                                    right_req_info_string, sizeof(right_req_info_string)));
    /*check that returned CSR contains req_info subject*/
    assert_true(libspdm_find_buffer(csr, spdm_response->csr_length,
                                    req_info_subject, sizeof(req_info_subject)));

    free(libspdm_get_csr_request);
}

/**
 * Test 8: receives a invalid GET_CSR request message from Requester With chaotic req_info and opaque_data
 * Expected Behavior: generate an ERROR_RESPONSE with code SPDM_ERROR_CODE_INVALID_REQUEST
 **/
void libspdm_test_responder_csr_case8(void **state)
{
    libspdm_return_t status;
    libspdm_test_context_t *spdm_test_context;
    libspdm_context_t *spdm_context;
    size_t response_size;
    uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE];
    spdm_csr_response_t *spdm_response;
    spdm_get_csr_request_t *libspdm_get_csr_request;
    uint8_t wrong_csr[LIBSPDM_MAX_CSR_SIZE];
    libspdm_zero_mem(wrong_csr, LIBSPDM_MAX_CSR_SIZE);

    spdm_test_context = *state;
    spdm_context = spdm_test_context->spdm_context;
    spdm_test_context->case_id = 0x8;
    spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
                                            SPDM_VERSION_NUMBER_SHIFT_BIT;

    spdm_context->connection_info.connection_state =
        LIBSPDM_CONNECTION_STATE_NEGOTIATED;
    spdm_context->local_context.capability.flags = 0;
    spdm_context->local_context.capability.flags |=
        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CSR_CAP;
    spdm_context->connection_info.algorithm.base_hash_algo =
        m_libspdm_use_hash_algo;
    spdm_context->connection_info.algorithm.base_asym_algo =
        m_libspdm_use_asym_algo;

    libspdm_get_csr_request = malloc(LIBSPDM_RECEIVER_BUFFER_SIZE);
    libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_12;
    libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    libspdm_get_csr_request->header.param1 = 0;
    libspdm_get_csr_request->header.param2 = 0;

    /* Swap right_req_info and m_csr_opaque_data */
    libspdm_get_csr_request->opaque_data_length = req_info_len;
    libspdm_get_csr_request->requester_info_length = sizeof(m_csr_opaque_data);
    libspdm_copy_mem(libspdm_get_csr_request + 1, sizeof(m_csr_opaque_data),
                     m_csr_opaque_data, sizeof(m_csr_opaque_data));
    libspdm_copy_mem((uint8_t *)(libspdm_get_csr_request + 1) + req_info_len,
                     req_info_len,
                     right_req_info, req_info_len);

    size_t libspdm_get_csr_request_size = sizeof(spdm_get_csr_request_t) +
                                          sizeof(m_csr_opaque_data) +
                                          req_info_len;

    response_size = sizeof(response);
    status = libspdm_get_response_csr(spdm_context,
                                      libspdm_get_csr_request_size,
                                      libspdm_get_csr_request,
                                      &response_size, response);
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
    assert_int_equal(response_size, sizeof(spdm_error_response_t));
    spdm_response = (void *)response;
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_ERROR);
    assert_int_equal(spdm_response->header.param1,
                     SPDM_ERROR_CODE_INVALID_REQUEST);
    assert_int_equal(spdm_response->header.param2, 0);
    free(libspdm_get_csr_request);
}

/**
 * Test 9: receives a valid GET_CSR request message from Requester with non-null opaque_data
 * the OpaqueDataFmt1 bit is selected in OtherParamsSelection of ALGORITHMS ,
 * Expected Behavior: produces a valid CSR response message
 **/
void libspdm_test_responder_csr_case9(void **state)
{
    libspdm_return_t status;
    libspdm_test_context_t *spdm_test_context;
    libspdm_context_t *spdm_context;
    size_t response_size;
    uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE];
    spdm_csr_response_t *spdm_response;
    spdm_get_csr_request_t *m_libspdm_get_csr_request;
    uint8_t wrong_csr[LIBSPDM_MAX_CSR_SIZE];
    libspdm_zero_mem(wrong_csr, LIBSPDM_MAX_CSR_SIZE);
    spdm_general_opaque_data_table_header_t
    *spdm_general_opaque_data_table_header;
    opaque_element_table_header_t
    *opaque_element_table_header;
    uint8_t *ptr;
    size_t opaque_data_size;
    uint8_t element_num;
    uint8_t element_index;
    size_t current_element_len;
    uint16_t opaque_element_data_len;

    spdm_test_context = *state;
    spdm_context = spdm_test_context->spdm_context;
    spdm_test_context->case_id = 0x9;
    spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
                                            SPDM_VERSION_NUMBER_SHIFT_BIT;

    spdm_context->connection_info.connection_state =
        LIBSPDM_CONNECTION_STATE_NEGOTIATED;
    spdm_context->local_context.capability.flags |=
        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CSR_CAP;
    spdm_context->connection_info.algorithm.base_hash_algo =
        m_libspdm_use_hash_algo;
    spdm_context->connection_info.algorithm.base_asym_algo =
        m_libspdm_use_asym_algo;
    spdm_context->connection_info.algorithm.other_params_support =
        SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1;

    m_libspdm_get_csr_request = malloc(sizeof(spdm_get_csr_request_t) + SPDM_MAX_OPAQUE_DATA_SIZE);

    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_12;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 0;
    m_libspdm_get_csr_request->header.param2 = 0;

    spdm_general_opaque_data_table_header = (void *)(m_libspdm_get_csr_request + 1);
    spdm_general_opaque_data_table_header->total_elements = 1;
    opaque_element_table_header = (void *)(spdm_general_opaque_data_table_header + 1);

    element_num = spdm_general_opaque_data_table_header->total_elements;
    opaque_data_size = sizeof(spdm_general_opaque_data_table_header_t);

    for (element_index = 0; element_index < element_num; element_index++) {
        opaque_element_table_header->id = SPDM_REGISTRY_ID_MAX;
        opaque_element_table_header->vendor_len = 0;
        opaque_element_data_len = 8;

        ptr = (void *)(opaque_element_table_header + 1);
        ptr += opaque_element_table_header->vendor_len;

        libspdm_copy_mem((uint16_t *)ptr,
                         sizeof(opaque_element_data_len),
                         &opaque_element_data_len,
                         sizeof(opaque_element_data_len));

        libspdm_copy_mem(ptr + sizeof(opaque_element_data_len),
                         SPDM_MAX_OPAQUE_DATA_SIZE -
                         sizeof(opaque_element_table_header_t), "libspdm",
                         strlen("libspdm"));

        current_element_len = sizeof(opaque_element_table_header_t) +
                              opaque_element_table_header->vendor_len +
                              sizeof(opaque_element_data_len) +
                              opaque_element_data_len;

        current_element_len = (current_element_len + 3) & ~3;

        /*move to next element*/
        opaque_element_table_header =
            (opaque_element_table_header_t *)
            ((uint8_t *)opaque_element_table_header +
             current_element_len);

        opaque_data_size += current_element_len;
    }

    m_libspdm_get_csr_request->opaque_data_length = (uint16_t)opaque_data_size;
    m_libspdm_get_csr_request->requester_info_length = 0;

    size_t m_libspdm_get_csr_request_size = sizeof(spdm_get_csr_request_t) + opaque_data_size;

    response_size = sizeof(response);
    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);

    spdm_response = (void *)response;
    assert_int_equal(response_size, sizeof(spdm_csr_response_t) + spdm_response->csr_length);
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_CSR);

    /*check returned CSR not zero */
    assert_memory_not_equal(spdm_response + 1, wrong_csr, spdm_response->csr_length);

    free(m_libspdm_get_csr_request);
}

/**
 * Test 10: receives a invalid GET_CSR request message from Requester with non-null alignPadding in opaque_data is not zero
 * the OpaqueDataFmt1 bit is selected in OtherParamsSelection of ALGORITHMS
 * Expected Behavior: generate an ERROR_RESPONSE with code SPDM_ERROR_CODE_INVALID_REQUEST
 **/
void libspdm_test_responder_csr_case10(void **state)
{
    libspdm_return_t status;
    libspdm_test_context_t *spdm_test_context;
    libspdm_context_t *spdm_context;
    size_t response_size;
    uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE];
    spdm_csr_response_t *spdm_response;
    spdm_get_csr_request_t *m_libspdm_get_csr_request;
    uint8_t wrong_csr[LIBSPDM_MAX_CSR_SIZE];
    libspdm_zero_mem(wrong_csr, LIBSPDM_MAX_CSR_SIZE);
    spdm_general_opaque_data_table_header_t
    *spdm_general_opaque_data_table_header;
    opaque_element_table_header_t
    *opaque_element_table_header;
    uint8_t *ptr;
    size_t opaque_data_size;
    uint8_t element_num;
    uint8_t element_index;
    size_t current_element_len;
    uint16_t opaque_element_data_len;

    spdm_test_context = *state;
    spdm_context = spdm_test_context->spdm_context;
    spdm_test_context->case_id = 0xA;
    spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
                                            SPDM_VERSION_NUMBER_SHIFT_BIT;

    spdm_context->connection_info.connection_state =
        LIBSPDM_CONNECTION_STATE_NEGOTIATED;
    spdm_context->local_context.capability.flags |=
        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CSR_CAP;
    spdm_context->connection_info.algorithm.base_hash_algo =
        m_libspdm_use_hash_algo;
    spdm_context->connection_info.algorithm.base_asym_algo =
        m_libspdm_use_asym_algo;
    spdm_context->connection_info.algorithm.other_params_support =
        SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1;

    m_libspdm_get_csr_request = malloc(sizeof(spdm_get_csr_request_t) + SPDM_MAX_OPAQUE_DATA_SIZE);

    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_12;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 0;
    m_libspdm_get_csr_request->header.param2 = 0;

    spdm_general_opaque_data_table_header = (void *)(m_libspdm_get_csr_request + 1);
    spdm_general_opaque_data_table_header->total_elements = 1;
    opaque_element_table_header = (void *)(spdm_general_opaque_data_table_header + 1);

    element_num = spdm_general_opaque_data_table_header->total_elements;
    opaque_data_size = sizeof(spdm_general_opaque_data_table_header_t);

    for (element_index = 0; element_index < element_num; element_index++) {
        opaque_element_table_header->id = SPDM_REGISTRY_ID_MAX;
        opaque_element_table_header->vendor_len = 0;
        opaque_element_data_len = (uint16_t)strlen("libspdm");

        ptr = (void *)(opaque_element_table_header + 1);
        ptr += opaque_element_table_header->vendor_len;

        libspdm_copy_mem((uint16_t *)ptr,
                         sizeof(opaque_element_data_len),
                         &opaque_element_data_len,
                         sizeof(opaque_element_data_len));

        libspdm_copy_mem(ptr + sizeof(opaque_element_data_len),
                         SPDM_MAX_OPAQUE_DATA_SIZE -
                         sizeof(opaque_element_table_header_t), "libspdm",
                         strlen("libspdm"));

        current_element_len = sizeof(opaque_element_table_header_t) +
                              opaque_element_table_header->vendor_len +
                              sizeof(opaque_element_data_len) +
                              opaque_element_data_len;

        *(uint8_t *)((size_t)(opaque_element_table_header) + current_element_len) = 0xFF;

        current_element_len += 1;
        current_element_len = (current_element_len + 3) & ~3;

        /*move to next element*/
        opaque_element_table_header =
            (opaque_element_table_header_t *)
            ((uint8_t *)opaque_element_table_header +
             current_element_len);

        opaque_data_size += current_element_len;
    }

    m_libspdm_get_csr_request->opaque_data_length = (uint16_t)opaque_data_size;
    m_libspdm_get_csr_request->requester_info_length = 0;

    size_t m_libspdm_get_csr_request_size = sizeof(spdm_get_csr_request_t) + opaque_data_size;

    response_size = sizeof(response);
    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);

    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
    assert_int_equal(response_size, sizeof(spdm_error_response_t));
    spdm_response = (void *)response;
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_ERROR);
    assert_int_equal(spdm_response->header.param1,
                     SPDM_ERROR_CODE_INVALID_REQUEST);
    assert_int_equal(spdm_response->header.param2, 0);

    free(m_libspdm_get_csr_request);
}

/**
 * Test 11: receives a valid GET_CSR request message from Requester
 * Expected Behavior: produces a valid CSR response message with alias_cert mode
 **/
void libspdm_test_responder_csr_case11(void **state)
{
    libspdm_return_t status;
    libspdm_test_context_t *spdm_test_context;
    libspdm_context_t *spdm_context;
    size_t response_size;
    uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE];
    spdm_csr_response_t *spdm_response;
    spdm_get_csr_request_t *m_libspdm_get_csr_request;
    uint8_t wrong_csr[LIBSPDM_MAX_CSR_SIZE];
    bool result;
    bool is_device_cert_model;

    libspdm_zero_mem(wrong_csr, LIBSPDM_MAX_CSR_SIZE);

    spdm_test_context = *state;
    spdm_context = spdm_test_context->spdm_context;
    spdm_test_context->case_id = 0xB;
    spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
                                            SPDM_VERSION_NUMBER_SHIFT_BIT;

    spdm_context->connection_info.connection_state =
        LIBSPDM_CONNECTION_STATE_NEGOTIATED;
    spdm_context->local_context.capability.flags |=
        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CSR_CAP;
    spdm_context->connection_info.algorithm.base_hash_algo =
        m_libspdm_use_hash_algo;
    spdm_context->connection_info.algorithm.base_asym_algo =
        m_libspdm_use_asym_algo;

    /*set alias cert mode*/
    spdm_context->local_context.capability.flags |=
        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ALIAS_CERT_CAP;
    is_device_cert_model = false;

    m_libspdm_get_csr_request = malloc(sizeof(spdm_get_csr_request_t));

    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_12;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 0;
    m_libspdm_get_csr_request->header.param2 = 0;

    m_libspdm_get_csr_request->opaque_data_length = 0;
    m_libspdm_get_csr_request->requester_info_length = 0;

    size_t m_libspdm_get_csr_request_size = sizeof(spdm_get_csr_request_t);

    response_size = sizeof(response);
    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);

    spdm_response = (void *)response;
    assert_int_equal(response_size, sizeof(spdm_csr_response_t) + spdm_response->csr_length);
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_CSR);

    /*check returned CSR not zero */
    assert_memory_not_equal(spdm_response + 1, wrong_csr, spdm_response->csr_length);

    /*check the resulting CSR shall be for a Device Certificate CA.*/
    result = libspdm_check_csr_basic_constraints((uint8_t *)(spdm_response + 1),
                                                 spdm_response->csr_length, is_device_cert_model);
    assert_true(result);

    free(m_libspdm_get_csr_request);
}

/**
 * Test 12: receives a valid GET_CSR request message from Requester with need_reset
 * Expected Behavior: the first get_csr: responder return need reset;
 *                    the second get_csr without device reset: responder return need reset;
 **/
void libspdm_test_responder_csr_case12(void **state)
{
    libspdm_return_t status;
    libspdm_test_context_t *spdm_test_context;
    libspdm_context_t *spdm_context;
    size_t response_size;
    uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE];
    spdm_csr_response_t *spdm_response;
    spdm_get_csr_request_t *m_libspdm_get_csr_request;
    uint8_t cached_csr[LIBSPDM_MAX_CSR_SIZE];
    libspdm_zero_mem(cached_csr, LIBSPDM_MAX_CSR_SIZE);

    uint8_t *csr_pointer;
    size_t csr_len;

    if (!libspdm_test_read_cached_csr(&csr_pointer, &csr_len)) {
        assert_false(true);
    }

    libspdm_copy_mem(cached_csr, LIBSPDM_MAX_CSR_SIZE, csr_pointer, csr_len);
    free(csr_pointer);

    spdm_test_context = *state;
    spdm_context = spdm_test_context->spdm_context;
    spdm_test_context->case_id = 0xC;
    spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
                                            SPDM_VERSION_NUMBER_SHIFT_BIT;

    spdm_context->connection_info.connection_state =
        LIBSPDM_CONNECTION_STATE_NEGOTIATED;
    spdm_context->local_context.capability.flags |=
        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CSR_CAP;

    /*set responder need reset*/
    spdm_context->local_context.capability.flags |=
        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_INSTALL_RESET_CAP;

    spdm_context->connection_info.algorithm.base_hash_algo =
        m_libspdm_use_hash_algo;
    spdm_context->connection_info.algorithm.base_asym_algo =
        m_libspdm_use_asym_algo;

    /*set csr before reset*/
    assert_true(libspdm_set_csr_before_reset());

    m_libspdm_get_csr_request = malloc(sizeof(spdm_get_csr_request_t) +
                                       req_info_len);

    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_12;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 0;
    m_libspdm_get_csr_request->header.param2 = 0;

    m_libspdm_get_csr_request->opaque_data_length = 0;
    m_libspdm_get_csr_request->requester_info_length = req_info_len;

    libspdm_copy_mem(m_libspdm_get_csr_request + 1, req_info_len,
                     right_req_info, req_info_len);

    size_t m_libspdm_get_csr_request_size = sizeof(spdm_get_csr_request_t) +
                                            req_info_len;

    response_size = sizeof(response);

    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);
    /*first get_csr: the responder need reset*/
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
    assert_int_equal(response_size, sizeof(spdm_error_response_t));
    spdm_response = (void *)response;
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_ERROR);
    assert_int_equal(spdm_response->header.param1,
                     SPDM_ERROR_CODE_RESET_REQUIRED);
    assert_int_equal(spdm_response->header.param2, 0);

    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_12;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 0;
    m_libspdm_get_csr_request->header.param2 = 0;

    m_libspdm_get_csr_request->opaque_data_length = 0;
    m_libspdm_get_csr_request->requester_info_length = req_info_len;
    libspdm_copy_mem(m_libspdm_get_csr_request + 1, req_info_len,
                     right_req_info, req_info_len);

    response_size = sizeof(response);

    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);
    /*second get_csr without device reset: get the responder cached csr*/
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
    assert_int_equal(response_size, sizeof(spdm_error_response_t));
    spdm_response = (void *)response;
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_ERROR);
    assert_int_equal(spdm_response->header.param1,
                     SPDM_ERROR_CODE_RESET_REQUIRED);
    assert_int_equal(spdm_response->header.param2, 0);

    /*clear cached req_info*/
    libspdm_test_clear_cached_last_request();
    free(m_libspdm_get_csr_request);

    /*set csr to the origin state*/
    assert_true(libspdm_set_csr_after_reset());
}

/**
 * Test 13: receives a valid GET_CSR request message from Requester with need_reset for SPDM 1.3
 * Expected Behavior: the first get_csr with csr_tracking_tag 0: responder return need reset and available csr_tracking_tag;
 *                    After reset, the second get_csr with returned available csr_tracking_tag: after device reset: get the cached valid csr;
 **/
void libspdm_test_responder_csr_case13(void **state)
{
    libspdm_return_t status;
    libspdm_test_context_t *spdm_test_context;
    libspdm_context_t *spdm_context;
    size_t response_size;
    uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE];
    spdm_csr_response_t *spdm_response;
    spdm_get_csr_request_t *m_libspdm_get_csr_request;
    uint8_t cached_csr[LIBSPDM_MAX_CSR_SIZE];
    libspdm_zero_mem(cached_csr, LIBSPDM_MAX_CSR_SIZE);

    uint8_t *csr_pointer;
    size_t csr_len;
    uint8_t csr_tracking_tag;

    csr_tracking_tag = 0;

    if (!libspdm_test_read_cached_csr(&csr_pointer, &csr_len)) {
        assert_false(true);
    }

    libspdm_copy_mem(cached_csr, LIBSPDM_MAX_CSR_SIZE, csr_pointer, csr_len);
    free(csr_pointer);

    spdm_test_context = *state;
    spdm_context = spdm_test_context->spdm_context;
    spdm_test_context->case_id = 0xD;
    spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_13 <<
                                            SPDM_VERSION_NUMBER_SHIFT_BIT;

    spdm_context->connection_info.connection_state =
        LIBSPDM_CONNECTION_STATE_NEGOTIATED;
    spdm_context->local_context.capability.flags |=
        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CSR_CAP;

    spdm_context->connection_info.multi_key_conn_rsp = true;
    /*set responder need reset*/
    spdm_context->local_context.capability.flags |=
        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_INSTALL_RESET_CAP;

    spdm_context->connection_info.algorithm.base_hash_algo =
        m_libspdm_use_hash_algo;
    spdm_context->connection_info.algorithm.base_asym_algo =
        m_libspdm_use_asym_algo;

    /*set csr before reset*/
    assert_true(libspdm_set_csr_before_reset());

    m_libspdm_get_csr_request = malloc(sizeof(spdm_get_csr_request_t) +
                                       req_info_len);

    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_13;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 1;
    m_libspdm_get_csr_request->header.param2 =
        SPDM_CERTIFICATE_INFO_CERT_MODEL_DEVICE_CERT |
        (csr_tracking_tag << SPDM_GET_CSR_REQUEST_ATTRIBUTES_CSR_TRACKING_TAG_OFFSET);

    m_libspdm_get_csr_request->opaque_data_length = 0;
    m_libspdm_get_csr_request->requester_info_length = req_info_len;

    libspdm_copy_mem(m_libspdm_get_csr_request + 1, req_info_len,
                     right_req_info, req_info_len);

    size_t m_libspdm_get_csr_request_size = sizeof(spdm_get_csr_request_t) +
                                            req_info_len;

    response_size = sizeof(response);
    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);

    /*set csr after reset*/
    assert_true(libspdm_set_csr_after_reset());
#if LIBSPDM_ENABLE_CAPABILITY_CSR_CAP_EX
    /*first get_csr: the responder need reset*/
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
    assert_int_equal(response_size, sizeof(spdm_error_response_t));
    spdm_response = (void *)response;
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_ERROR);
    assert_int_equal(spdm_response->header.param1,
                     SPDM_ERROR_CODE_RESET_REQUIRED);
    assert_int_equal(spdm_response->header.param2, 1);

    csr_tracking_tag = spdm_response->header.param2;
    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_13;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 1;
    m_libspdm_get_csr_request->header.param2 =
        SPDM_CERTIFICATE_INFO_CERT_MODEL_DEVICE_CERT |
        (csr_tracking_tag << SPDM_GET_CSR_REQUEST_ATTRIBUTES_CSR_TRACKING_TAG_OFFSET);

    m_libspdm_get_csr_request->opaque_data_length = 0;
    m_libspdm_get_csr_request->requester_info_length = req_info_len;
    libspdm_copy_mem(m_libspdm_get_csr_request + 1, req_info_len,
                     right_req_info, req_info_len);

    response_size = sizeof(response);
    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);
    /*second get_csr after device reset: get the responder cached csr*/
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);

    spdm_response = (void *)response;
    assert_int_equal(response_size, sizeof(spdm_csr_response_t) + spdm_response->csr_length);
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_CSR);

    /*check returned CSR is equal the cached CSR */
    assert_memory_equal(spdm_response + 1, cached_csr, spdm_response->csr_length);
#else
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
    assert_int_equal(response_size, sizeof(spdm_error_response_t));
    spdm_response = (void *)response;
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_ERROR);
    assert_int_equal(spdm_response->header.param1,
                     SPDM_ERROR_CODE_UNEXPECTED_REQUEST);
    assert_int_equal(spdm_response->header.param2, 0);
#endif /*LIBSPDM_ENABLE_CAPABILITY_CSR_CAP_EX*/
    /*clear cached req_info*/
    libspdm_test_clear_cached_last_request();
    free(m_libspdm_get_csr_request);
}

/**
 * Test 14: receives a valid GET_CSR request message from Requester with need_reset for SPDM 1.3
 * Expected Behavior: the first get_csr with csr_tracking_tag 0: responder return need reset and available csr_tracking_tag;
 *                    Afer reset, then send get_csr with csr_tracking_tag 0 six times: responder return need reset and available csr_tracking_tag;
 *                    Then send get_csr with csr_tracking_tag 0: responder return busy error;
 **/
void libspdm_test_responder_csr_case14(void **state)
{
    libspdm_return_t status;
    libspdm_test_context_t *spdm_test_context;
    libspdm_context_t *spdm_context;
    size_t response_size;
    uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE];
    spdm_csr_response_t *spdm_response;
    spdm_get_csr_request_t *m_libspdm_get_csr_request;
    uint8_t cached_csr[LIBSPDM_MAX_CSR_SIZE];
#if LIBSPDM_ENABLE_CAPABILITY_CSR_CAP_EX
    uint8_t index;
#endif /*LIBSPDM_ENABLE_CAPABILITY_CSR_CAP_EX*/
    libspdm_zero_mem(cached_csr, LIBSPDM_MAX_CSR_SIZE);

    uint8_t *csr_pointer;
    size_t csr_len;
    uint8_t csr_tracking_tag;

    csr_tracking_tag = 0;

    if (!libspdm_test_read_cached_csr(&csr_pointer, &csr_len)) {
        assert_false(true);
    }

    libspdm_copy_mem(cached_csr, LIBSPDM_MAX_CSR_SIZE, csr_pointer, csr_len);
    free(csr_pointer);

    spdm_test_context = *state;
    spdm_context = spdm_test_context->spdm_context;
    spdm_test_context->case_id = 0xE;
    spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_13 <<
                                            SPDM_VERSION_NUMBER_SHIFT_BIT;

    spdm_context->connection_info.connection_state =
        LIBSPDM_CONNECTION_STATE_NEGOTIATED;
    spdm_context->local_context.capability.flags |=
        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CSR_CAP;

    spdm_context->connection_info.multi_key_conn_rsp = true;
    /*set responder need reset*/
    spdm_context->local_context.capability.flags |=
        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_INSTALL_RESET_CAP;

    spdm_context->connection_info.algorithm.base_hash_algo =
        m_libspdm_use_hash_algo;
    spdm_context->connection_info.algorithm.base_asym_algo =
        m_libspdm_use_asym_algo;

    /*set csr before reset*/
    assert_true(libspdm_set_csr_before_reset());

    m_libspdm_get_csr_request = malloc(sizeof(spdm_get_csr_request_t) +
                                       req_info_len);

    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_13;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 1;
    m_libspdm_get_csr_request->header.param2 =
        SPDM_CERTIFICATE_INFO_CERT_MODEL_DEVICE_CERT |
        (csr_tracking_tag << SPDM_GET_CSR_REQUEST_ATTRIBUTES_CSR_TRACKING_TAG_OFFSET);

    m_libspdm_get_csr_request->opaque_data_length = 0;
    m_libspdm_get_csr_request->requester_info_length = req_info_len;

    libspdm_copy_mem(m_libspdm_get_csr_request + 1, req_info_len,
                     right_req_info, req_info_len);

    size_t m_libspdm_get_csr_request_size = sizeof(spdm_get_csr_request_t) +
                                            req_info_len;

    response_size = sizeof(response);
    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);

    /*set csr after reset*/
    assert_true(libspdm_set_csr_after_reset());
#if LIBSPDM_ENABLE_CAPABILITY_CSR_CAP_EX
    /*first get_csr: the responder need reset*/
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
    assert_int_equal(response_size, sizeof(spdm_error_response_t));
    spdm_response = (void *)response;
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_ERROR);
    assert_int_equal(spdm_response->header.param1,
                     SPDM_ERROR_CODE_RESET_REQUIRED);
    assert_int_equal(spdm_response->header.param2, 1);

    for (index = 1; index < SPDM_MAX_CSR_TRACKING_TAG; index++) {
        csr_tracking_tag = 0;
        m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_13;
        m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
        m_libspdm_get_csr_request->header.param1 = 1;
        m_libspdm_get_csr_request->header.param2 =
            SPDM_CERTIFICATE_INFO_CERT_MODEL_DEVICE_CERT |
            (csr_tracking_tag << SPDM_GET_CSR_REQUEST_ATTRIBUTES_CSR_TRACKING_TAG_OFFSET);

        m_libspdm_get_csr_request->opaque_data_length = 0;
        m_libspdm_get_csr_request->requester_info_length = req_info_len;
        libspdm_copy_mem(m_libspdm_get_csr_request + 1, req_info_len,
                         right_req_info, req_info_len);

        response_size = sizeof(response);
        status = libspdm_get_response_csr(spdm_context,
                                          m_libspdm_get_csr_request_size,
                                          m_libspdm_get_csr_request,
                                          &response_size, response);
        /*second get_csr after device reset: get the responder cached csr*/
        assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
        assert_int_equal(response_size, sizeof(spdm_error_response_t));
        spdm_response = (void *)response;
        assert_int_equal(spdm_response->header.request_response_code,
                         SPDM_ERROR);
        assert_int_equal(spdm_response->header.param1,
                         SPDM_ERROR_CODE_RESET_REQUIRED);
        assert_int_equal(spdm_response->header.param2, index + 1);
    }

    csr_tracking_tag = 0;
    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_13;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 1;
    m_libspdm_get_csr_request->header.param2 =
        SPDM_CERTIFICATE_INFO_CERT_MODEL_DEVICE_CERT |
        (csr_tracking_tag << SPDM_GET_CSR_REQUEST_ATTRIBUTES_CSR_TRACKING_TAG_OFFSET);

    m_libspdm_get_csr_request->opaque_data_length = 0;
    m_libspdm_get_csr_request->requester_info_length = req_info_len;
    libspdm_copy_mem(m_libspdm_get_csr_request + 1, req_info_len,
                     right_req_info, req_info_len);

    response_size = sizeof(response);
    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);
    /*second get_csr after device reset: get the responder cached csr*/
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
    assert_int_equal(response_size, sizeof(spdm_error_response_t));
    spdm_response = (void *)response;
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_ERROR);
    assert_int_equal(spdm_response->header.param1,
                     SPDM_ERROR_CODE_BUSY);
    assert_int_equal(spdm_response->header.param2, 0);
#else
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
    assert_int_equal(response_size, sizeof(spdm_error_response_t));
    spdm_response = (void *)response;
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_ERROR);
    assert_int_equal(spdm_response->header.param1,
                     SPDM_ERROR_CODE_UNEXPECTED_REQUEST);
    assert_int_equal(spdm_response->header.param2, 0);
#endif /*LIBSPDM_ENABLE_CAPABILITY_CSR_CAP_EX*/
    /*clear cached req_info*/
    libspdm_test_clear_cached_last_request();
    free(m_libspdm_get_csr_request);
}

/**
 * Test 15: receives a valid GET_CSR request message from Requester with need_reset for SPDM 1.3
 * Expected Behavior: the first get_csr with csr_tracking_tag 0: responder return need reset and available csr_tracking_tag;
 *                    Without reset, then send get_csr with unmatched csr_tracking_tag：responder return unexpected error;
 *                    Without reset, then send get_csr with matched csr_tracking_tag：responder return busy error;
 *                    Without reset, then send get_csr with non-0 csr_tracking_tag, and overwrite is set：responder return invalid error;
 *                    After reset, then send get_csr with unmatched csr_tracking_tag：responder return unexpected error;
 *                    After reset, then send get_csr with csr_tracking_tag 0, and overwrite is set：responder return need reset and available csr_tracking_tag;
 **/
void libspdm_test_responder_csr_case15(void **state)
{
    libspdm_return_t status;
    libspdm_test_context_t *spdm_test_context;
    libspdm_context_t *spdm_context;
    size_t response_size;
    uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE];
    spdm_csr_response_t *spdm_response;
    spdm_get_csr_request_t *m_libspdm_get_csr_request;
    uint8_t cached_csr[LIBSPDM_MAX_CSR_SIZE];
    libspdm_zero_mem(cached_csr, LIBSPDM_MAX_CSR_SIZE);

    uint8_t *csr_pointer;
    size_t csr_len;
    uint8_t csr_tracking_tag;

    csr_tracking_tag = 0;

    if (!libspdm_test_read_cached_csr(&csr_pointer, &csr_len)) {
        assert_false(true);
    }

    libspdm_copy_mem(cached_csr, LIBSPDM_MAX_CSR_SIZE, csr_pointer, csr_len);
    free(csr_pointer);

    spdm_test_context = *state;
    spdm_context = spdm_test_context->spdm_context;
    spdm_test_context->case_id = 0xF;
    spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_13 <<
                                            SPDM_VERSION_NUMBER_SHIFT_BIT;

    spdm_context->connection_info.connection_state =
        LIBSPDM_CONNECTION_STATE_NEGOTIATED;
    spdm_context->local_context.capability.flags |=
        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CSR_CAP;

    spdm_context->connection_info.multi_key_conn_rsp = true;
    /*set responder need reset*/
    spdm_context->local_context.capability.flags |=
        SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_INSTALL_RESET_CAP;

    spdm_context->connection_info.algorithm.base_hash_algo =
        m_libspdm_use_hash_algo;
    spdm_context->connection_info.algorithm.base_asym_algo =
        m_libspdm_use_asym_algo;

    /*set csr before reset*/
    assert_true(libspdm_set_csr_before_reset());

    m_libspdm_get_csr_request = malloc(sizeof(spdm_get_csr_request_t) +
                                       req_info_len);

    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_13;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 1;
    m_libspdm_get_csr_request->header.param2 =
        SPDM_CERTIFICATE_INFO_CERT_MODEL_DEVICE_CERT |
        (csr_tracking_tag << SPDM_GET_CSR_REQUEST_ATTRIBUTES_CSR_TRACKING_TAG_OFFSET);

    m_libspdm_get_csr_request->opaque_data_length = 0;
    m_libspdm_get_csr_request->requester_info_length = req_info_len;

    libspdm_copy_mem(m_libspdm_get_csr_request + 1, req_info_len,
                     right_req_info, req_info_len);

    size_t m_libspdm_get_csr_request_size = sizeof(spdm_get_csr_request_t) +
                                            req_info_len;

    response_size = sizeof(response);
    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);
#if LIBSPDM_ENABLE_CAPABILITY_CSR_CAP_EX
    /*first get_csr: the responder need reset*/
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
    assert_int_equal(response_size, sizeof(spdm_error_response_t));
    spdm_response = (void *)response;
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_ERROR);
    assert_int_equal(spdm_response->header.param1,
                     SPDM_ERROR_CODE_RESET_REQUIRED);
    assert_int_equal(spdm_response->header.param2, 1);

    /*unmatched csr_tracking_tag*/
    csr_tracking_tag = 3;
    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_13;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 1;
    m_libspdm_get_csr_request->header.param2 =
        SPDM_CERTIFICATE_INFO_CERT_MODEL_DEVICE_CERT |
        (csr_tracking_tag << SPDM_GET_CSR_REQUEST_ATTRIBUTES_CSR_TRACKING_TAG_OFFSET);

    m_libspdm_get_csr_request->opaque_data_length = 0;
    m_libspdm_get_csr_request->requester_info_length = req_info_len;
    libspdm_copy_mem(m_libspdm_get_csr_request + 1, req_info_len,
                     right_req_info, req_info_len);

    response_size = sizeof(response);
    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);
    /*second get_csr after device reset: get the responder cached csr*/
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
    assert_int_equal(response_size, sizeof(spdm_error_response_t));
    spdm_response = (void *)response;
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_ERROR);
    assert_int_equal(spdm_response->header.param1,
                     SPDM_ERROR_CODE_INVALID_REQUEST);
    assert_int_equal(spdm_response->header.param2, 0);

    /*matched csr_tracking_tag without overwrite*/
    csr_tracking_tag = 1;
    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_13;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 1;
    m_libspdm_get_csr_request->header.param2 =
        SPDM_CERTIFICATE_INFO_CERT_MODEL_DEVICE_CERT |
        (csr_tracking_tag << SPDM_GET_CSR_REQUEST_ATTRIBUTES_CSR_TRACKING_TAG_OFFSET);

    m_libspdm_get_csr_request->opaque_data_length = 0;
    m_libspdm_get_csr_request->requester_info_length = req_info_len;
    libspdm_copy_mem(m_libspdm_get_csr_request + 1, req_info_len,
                     right_req_info, req_info_len);

    response_size = sizeof(response);
    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);
    /*second get_csr after device reset: get the responder cached csr*/
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
    assert_int_equal(response_size, sizeof(spdm_error_response_t));
    spdm_response = (void *)response;
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_ERROR);
    assert_int_equal(spdm_response->header.param1,
                     SPDM_ERROR_CODE_BUSY);
    assert_int_equal(spdm_response->header.param2, 0);


    /*matched csr_tracking_tag with overwrite*/
    csr_tracking_tag = 1;
    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_13;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 1;
    m_libspdm_get_csr_request->header.param2 =
        (csr_tracking_tag << SPDM_GET_CSR_REQUEST_ATTRIBUTES_CSR_TRACKING_TAG_OFFSET) |
        SPDM_GET_CSR_REQUEST_ATTRIBUTES_OVERWRITE;

    m_libspdm_get_csr_request->opaque_data_length = 0;
    m_libspdm_get_csr_request->requester_info_length = req_info_len;
    libspdm_copy_mem(m_libspdm_get_csr_request + 1, req_info_len,
                     right_req_info, req_info_len);

    response_size = sizeof(response);
    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);
    /*second get_csr after device reset: get the responder cached csr*/
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
    assert_int_equal(response_size, sizeof(spdm_error_response_t));
    spdm_response = (void *)response;
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_ERROR);
    assert_int_equal(spdm_response->header.param1,
                     SPDM_ERROR_CODE_INVALID_REQUEST);
    assert_int_equal(spdm_response->header.param2, 0);

    /*set csr after reset*/
    assert_true(libspdm_set_csr_after_reset());

    /*unmatched csr_tracking_tag*/
    csr_tracking_tag = 3;
    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_13;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 1;
    m_libspdm_get_csr_request->header.param2 =
        SPDM_CERTIFICATE_INFO_CERT_MODEL_DEVICE_CERT |
        (csr_tracking_tag << SPDM_GET_CSR_REQUEST_ATTRIBUTES_CSR_TRACKING_TAG_OFFSET);

    m_libspdm_get_csr_request->opaque_data_length = 0;
    m_libspdm_get_csr_request->requester_info_length = req_info_len;
    libspdm_copy_mem(m_libspdm_get_csr_request + 1, req_info_len,
                     right_req_info, req_info_len);

    response_size = sizeof(response);
    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
    assert_int_equal(response_size, sizeof(spdm_error_response_t));
    spdm_response = (void *)response;
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_ERROR);
    assert_int_equal(spdm_response->header.param1,
                     SPDM_ERROR_CODE_INVALID_REQUEST);
    assert_int_equal(spdm_response->header.param2, 0);

    /*csr_tracking_tag 0 and overwrite*/
    csr_tracking_tag = 0;
    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_13;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 1;
    m_libspdm_get_csr_request->header.param2 =
        SPDM_CERTIFICATE_INFO_CERT_MODEL_DEVICE_CERT |
        (csr_tracking_tag << SPDM_GET_CSR_REQUEST_ATTRIBUTES_CSR_TRACKING_TAG_OFFSET) |
        SPDM_GET_CSR_REQUEST_ATTRIBUTES_OVERWRITE;

    m_libspdm_get_csr_request->opaque_data_length = 0;
    m_libspdm_get_csr_request->requester_info_length = req_info_len;
    libspdm_copy_mem(m_libspdm_get_csr_request + 1, req_info_len,
                     right_req_info, req_info_len);

    response_size = sizeof(response);
    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
    assert_int_equal(response_size, sizeof(spdm_error_response_t));
    spdm_response = (void *)response;
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_ERROR);
    assert_int_equal(spdm_response->header.param1,
                     SPDM_ERROR_CODE_RESET_REQUIRED);
    assert_int_equal(spdm_response->header.param2, 1);

#else
    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
    assert_int_equal(response_size, sizeof(spdm_error_response_t));
    spdm_response = (void *)response;
    assert_int_equal(spdm_response->header.request_response_code,
                     SPDM_ERROR);
    assert_int_equal(spdm_response->header.param1,
                     SPDM_ERROR_CODE_UNEXPECTED_REQUEST);
    assert_int_equal(spdm_response->header.param2, 0);
    /*set csr after reset*/
    assert_true(libspdm_set_csr_after_reset());
#endif /*LIBSPDM_ENABLE_CAPABILITY_CSR_CAP_EX*/
    /*clear cached req_info*/
    libspdm_test_clear_cached_last_request();
    free(m_libspdm_get_csr_request);
}

/**
 * Test 16: Illegal combination of MULTI_KEY_CONN_RSP = true and CSRCertModel = 0.
 * Expected Behavior: produces SPDM_ERROR_CODE_INVALID_REQUEST message.
 **/
void libspdm_test_responder_csr_case16(void **state)
{
#if LIBSPDM_ENABLE_CAPABILITY_CSR_CAP_EX
    libspdm_return_t status;
    libspdm_test_context_t *spdm_test_context;
    libspdm_context_t *spdm_context;
    size_t response_size;
    uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE];
    spdm_csr_response_t *spdm_response;
    spdm_get_csr_request_t *m_libspdm_get_csr_request;
    uint8_t cached_csr[LIBSPDM_MAX_CSR_SIZE];
    libspdm_zero_mem(cached_csr, LIBSPDM_MAX_CSR_SIZE);

    uint8_t *csr_pointer;
    size_t csr_len;
    uint8_t csr_tracking_tag;

    csr_tracking_tag = 0;

    if (!libspdm_test_read_cached_csr(&csr_pointer, &csr_len)) {
        assert_false(true);
    }

    libspdm_copy_mem(cached_csr, LIBSPDM_MAX_CSR_SIZE, csr_pointer, csr_len);
    free(csr_pointer);

    spdm_test_context = *state;
    spdm_context = spdm_test_context->spdm_context;
    spdm_test_context->case_id = 0x10;
    spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_13 <<
                                            SPDM_VERSION_NUMBER_SHIFT_BIT;

    spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_NEGOTIATED;
    spdm_context->local_context.capability.flags = SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CSR_CAP;

    spdm_context->connection_info.multi_key_conn_rsp = true;
    spdm_context->connection_info.algorithm.base_hash_algo = m_libspdm_use_hash_algo;
    spdm_context->connection_info.algorithm.base_asym_algo = m_libspdm_use_asym_algo;

    m_libspdm_get_csr_request = malloc(sizeof(spdm_get_csr_request_t) + req_info_len);

    m_libspdm_get_csr_request->header.spdm_version = SPDM_MESSAGE_VERSION_13;
    m_libspdm_get_csr_request->header.request_response_code = SPDM_GET_CSR;
    m_libspdm_get_csr_request->header.param1 = 1;
    m_libspdm_get_csr_request->header.param2 =
        SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE |
        (csr_tracking_tag << SPDM_GET_CSR_REQUEST_ATTRIBUTES_CSR_TRACKING_TAG_OFFSET);

    m_libspdm_get_csr_request->opaque_data_length = 0;
    m_libspdm_get_csr_request->requester_info_length = req_info_len;

    libspdm_copy_mem(m_libspdm_get_csr_request + 1, req_info_len, right_req_info, req_info_len);

    size_t m_libspdm_get_csr_request_size = sizeof(spdm_get_csr_request_t) + req_info_len;

    response_size = sizeof(response);
    status = libspdm_get_response_csr(spdm_context,
                                      m_libspdm_get_csr_request_size,
                                      m_libspdm_get_csr_request,
                                      &response_size, response);

    assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
    assert_int_equal(response_size, sizeof(spdm_error_response_t));
    spdm_response = (void *)response;
    assert_int_equal(spdm_response->header.request_response_code, SPDM_ERROR);
    assert_int_equal(spdm_response->header.param1, SPDM_ERROR_CODE_INVALID_REQUEST);
    assert_int_equal(spdm_response->header.param2, 0);

    /*clear cached req_info*/
    libspdm_test_clear_cached_last_request();
    free(m_libspdm_get_csr_request);
#endif /* LIBSPDM_ENABLE_CAPABILITY_CSR_CAP_EX */
}

int libspdm_responder_csr_test_main(void)
{
    const struct CMUnitTest spdm_responder_csr_tests[] = {
        /* Success Case for csr response with device_cert mode */
        cmocka_unit_test(libspdm_test_responder_csr_case1),
        /* Bad request size*/
        cmocka_unit_test(libspdm_test_responder_csr_case2),
        /* Success Case for csr response with non-null right req_info */
        cmocka_unit_test(libspdm_test_responder_csr_case3),
        /* Success Case for csr response with non-null opaque_data */
        cmocka_unit_test(libspdm_test_responder_csr_case4),
        /* Failed Case for csr response with non-null wrong req_info */
        cmocka_unit_test(libspdm_test_responder_csr_case5),
        /* Responder need reset to gen csr, the second send after device reset*/
        cmocka_unit_test(libspdm_test_responder_csr_case6),
        /* Success Case for csr response with non-null right req_info and opaque_data */
        cmocka_unit_test(libspdm_test_responder_csr_case7),
        /* Failed Case for csr response  With chaotic req_info and opaque_data */
        cmocka_unit_test(libspdm_test_responder_csr_case8),
        /* the OpaqueDataFmt1 bit is selected in OtherParamsSelection of ALGORITHMS*/
        cmocka_unit_test(libspdm_test_responder_csr_case9),
        /* Failed Case  OpaqueDataFmt1, When AlignPadding is not zero*/
        cmocka_unit_test(libspdm_test_responder_csr_case10),
        /* Success Case for csr response with alias_cert mode */
        cmocka_unit_test(libspdm_test_responder_csr_case11),
        /* Responder need reset to gen csr, the second send without device reset*/
        cmocka_unit_test(libspdm_test_responder_csr_case12),
        /* Success Case: Responder need reset to gen csr for SPDM1.3, the second send with matched csr_tracking_tag after device reset*/
        cmocka_unit_test(libspdm_test_responder_csr_case13),
        /* Failed Case: Responder need reset to gen csr for SPDM1.3, test for busy error*/
        cmocka_unit_test(libspdm_test_responder_csr_case14),
        /* Failed Case: Responder need reset to gen csr for SPDM1.3, test for unmatched csr_tracking_tag and overwrite*/
        cmocka_unit_test(libspdm_test_responder_csr_case15),
        cmocka_unit_test(libspdm_test_responder_csr_case16),
    };

    libspdm_test_context_t test_context = {
        LIBSPDM_TEST_CONTEXT_VERSION,
        false,
    };

    libspdm_setup_test_context(&test_context);

    /*ensure that cached.csr exists in test_csr at the beginning*/
    libspdm_clear_cached_csr();

    return cmocka_run_group_tests(spdm_responder_csr_tests,
                                  libspdm_unit_test_group_setup,
                                  libspdm_unit_test_group_teardown);
}

#endif /*LIBSPDM_ENABLE_CAPABILITY_CSR_CAP*/
