/**
 * \file
 * \brief cert client tests
 *
 * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries.
 *
 * \page License
 *
 * Subject to your compliance with these terms, you may use Microchip software
 * and any derivatives exclusively with Microchip products. It is your
 * responsibility to comply with third party license terms applicable to your
 * use of third party software (including open source software) that may
 * accompany Microchip software.
 *
 * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
 * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
 * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
 * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT,
 * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE
 * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF
 * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE
 * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL
 * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED
 * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR
 * THIS SOFTWARE.
 */


#include "atcacert/atcacert_client.h"
#include "atcacert/atcacert_pem.h"
#include "test/unity.h"
#include "test/unity_fixture.h"
#include <string.h>
#include "cryptoauthlib.h"
#include "basic/atca_basic.h"
#include "crypto/atca_crypto_sw_sha2.h"
#include "test_cert_def_0_device.h"
#include "test_cert_def_1_signer.h"
#include "test_cert_def_2_device_csr.h"

extern ATCAIfaceCfg *gCfg;

uint8_t g_signer_ca_public_key[64];
uint8_t g_signer_public_key[64];
uint8_t g_device_public_key[64];

uint8_t g_signer_cert_ref[512];
size_t g_signer_cert_ref_size = 0;

uint8_t g_device_cert_ref[512];
size_t g_device_cert_ref_size = 0;

static void build_and_save_cert(
    const atcacert_def_t*    cert_def,
    uint8_t*                 cert,
    size_t*                  cert_size,
    const uint8_t            ca_public_key[64],
    const uint8_t            public_key[64],
    const uint8_t            signer_id[2],
    const atcacert_tm_utc_t* issue_date,
    const uint8_t            config32[32],
    uint8_t                  ca_slot)
{
    int ret;
    atcacert_build_state_t build_state;
    uint8_t tbs_digest[32];
    uint8_t signature[64];
    size_t max_cert_size = *cert_size;
    atcacert_tm_utc_t expire_date = {
        .tm_year    = issue_date->tm_year + cert_def->expire_years,
        .tm_mon     = issue_date->tm_mon,
        .tm_mday    = issue_date->tm_mday,
        .tm_hour    = issue_date->tm_hour,
        .tm_min     = 0,
        .tm_sec     = 0
    };
    const atcacert_device_loc_t config32_dev_loc = {
        .zone   = DEVZONE_CONFIG,
        .offset = 0,
        .count  = 32
    };
    atcacert_device_loc_t device_locs[4];
    size_t device_locs_count = 0;
    size_t i;

    if (cert_def->expire_years == 0)
    {
        ret = atcacert_date_get_max_date(cert_def->expire_date_format, &expire_date);
        TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);
    }

    ret = atcacert_cert_build_start(&build_state, cert_def, cert, cert_size, ca_public_key);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);

    ret = atcacert_set_subj_public_key(build_state.cert_def, build_state.cert, *build_state.cert_size, public_key);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);
    ret = atcacert_set_issue_date(build_state.cert_def, build_state.cert, *build_state.cert_size, issue_date);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);
    ret = atcacert_set_expire_date(build_state.cert_def, build_state.cert, *build_state.cert_size, &expire_date);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);
    ret = atcacert_set_signer_id(build_state.cert_def, build_state.cert, *build_state.cert_size, signer_id);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);
    ret = atcacert_cert_build_process(&build_state, &config32_dev_loc, config32);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);

    ret = atcacert_cert_build_finish(&build_state);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);

    ret = atcacert_get_tbs_digest(build_state.cert_def, build_state.cert, *build_state.cert_size, tbs_digest);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);

    ret = atcab_sign(ca_slot, tbs_digest, signature);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);

    ret = atcacert_set_signature(cert_def, cert, cert_size, max_cert_size, signature);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);

    ret = atcacert_get_device_locs(cert_def, device_locs, &device_locs_count, sizeof(device_locs) / sizeof(device_locs[0]), 32);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);

    for (i = 0; i < device_locs_count; i++)
    {
        size_t end_block;
        size_t start_block;
        uint8_t data[96];
        uint8_t block;

        if (device_locs[i].zone == DEVZONE_CONFIG)
        {
            continue;
        }
        if (device_locs[i].zone == DEVZONE_DATA && device_locs[i].is_genkey)
        {
            continue;
        }

        TEST_ASSERT(sizeof(data) >= device_locs[i].count);

        ret = atcacert_get_device_data(cert_def, cert, *cert_size, &device_locs[i], data);
        TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);

        start_block = device_locs[i].offset / 32;
        end_block = (device_locs[i].offset + device_locs[i].count) / 32;
        for (block = (uint8_t)start_block; block < end_block; block++)
        {
            ret = atcab_write_zone(device_locs[i].zone, device_locs[i].slot, block, 0, &data[(block - start_block) * 32], 32);
            TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);
        }
    }
}

TEST_GROUP(atcacert_client);

TEST_SETUP(atcacert_client)
{
    int ret = 0;
    bool lockstate = 0;

    ret = atcab_init(gCfg);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);

    ret = atcab_is_locked(LOCK_ZONE_CONFIG, &lockstate);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);
    if (!lockstate)
    {
        TEST_IGNORE_MESSAGE("Config zone must be locked for this test.");
    }

    ret = atcab_is_locked(LOCK_ZONE_DATA, &lockstate);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);
    if (!lockstate)
    {
        TEST_IGNORE_MESSAGE("Data zone must be locked for this test.");
    }
}

TEST_TEAR_DOWN(atcacert_client)
{
    ATCA_STATUS status;

    status = atcab_wakeup();
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

    status = atcab_sleep();
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

    status = atcab_release();
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
}

TEST(atcacert_client, init)
{
    int ret = 0;

    static const uint8_t signer_ca_private_key_slot = 7;
    static const uint8_t signer_private_key_slot = 2;
    uint8_t signer_id[2] = { 0xC4, 0x8B };
    const atcacert_tm_utc_t signer_issue_date = {
        .tm_year    = 2014 - 1900,
        .tm_mon     = 8 - 1,
        .tm_mday    = 2,
        .tm_hour    = 20,
        .tm_min     = 0,
        .tm_sec     = 0
    };
    static const uint8_t device_private_key_slot = 0;
    const atcacert_tm_utc_t device_issue_date = {
        .tm_year    = 2015 - 1900,
        .tm_mon     = 9 - 1,
        .tm_mday    = 3,
        .tm_hour    = 21,
        .tm_min     = 0,
        .tm_sec     = 0
    };
    uint8_t config32[32];
    char disp_str[1500];
    size_t disp_size = sizeof(disp_str);


    ret = atcab_read_zone(ATCA_ZONE_CONFIG, 0, 0, 0, config32, 32);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);

    ret = atcab_genkey(signer_ca_private_key_slot, g_signer_ca_public_key);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);
    disp_size = sizeof(disp_str);
    ret = atcab_bin2hex(g_signer_ca_public_key, ATCA_PUB_KEY_SIZE, disp_str, &disp_size);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);
    printf("Signer CA Public Key:\r\n%s\r\n", disp_str);

    ret = atcab_genkey(signer_private_key_slot, g_signer_public_key);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);
    disp_size = sizeof(disp_str);
    ret = atcab_bin2hex(g_signer_public_key, ATCA_PUB_KEY_SIZE, disp_str, &disp_size);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);
    printf("Signer Public Key:\r\n%s\r\n", disp_str);

    ret = atcab_genkey(device_private_key_slot, g_device_public_key);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);
    disp_size = sizeof(disp_str);
    ret = atcab_bin2hex(g_device_public_key, ATCA_PUB_KEY_SIZE, disp_str, &disp_size);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);
    printf("Device Public Key:\r\n%s\r\n", disp_str);

    // Build signer cert
    g_signer_cert_ref_size = sizeof(g_signer_cert_ref);
    build_and_save_cert(
        &g_test_cert_def_1_signer,
        g_signer_cert_ref,
        &g_signer_cert_ref_size,
        g_signer_ca_public_key,
        g_signer_public_key,
        signer_id,
        &signer_issue_date,
        config32,
        signer_ca_private_key_slot);
    disp_size = sizeof(disp_str);
    ret = atcab_bin2hex(g_signer_cert_ref, g_signer_cert_ref_size, disp_str, &disp_size);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);
    printf("Signer Certificate:\r\n%s\r\n", disp_str);

    g_device_cert_ref_size = sizeof(g_device_cert_ref);
    build_and_save_cert(
        &g_test_cert_def_0_device,
        g_device_cert_ref,
        &g_device_cert_ref_size,
        g_signer_public_key,
        g_device_public_key,
        signer_id,
        &device_issue_date,
        config32,
        signer_private_key_slot);
    disp_size = sizeof(disp_str);
    ret = atcab_bin2hex(g_device_cert_ref, g_device_cert_ref_size, disp_str, &disp_size);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);
    printf("Device Certificate:\r\n%s\r\n", disp_str);
}

TEST(atcacert_client, atcacert_read_device_loc_gen_key)
{
    int ret;
    uint8_t public_key[ATCA_PUB_KEY_SIZE];
    uint8_t data[sizeof(public_key)];
    atcacert_device_loc_t device_loc = { DEVZONE_DATA, 0, TRUE, 0, 64 };

    ret = atcab_get_pubkey(device_loc.slot, public_key);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);

    ret = atcacert_read_device_loc(&device_loc, data);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);
    TEST_ASSERT_EQUAL_MEMORY(&public_key[device_loc.offset], data, device_loc.count);
}

TEST(atcacert_client, atcacert_read_device_loc_gen_key_partial)
{
    int ret;
    uint8_t public_key[ATCA_PUB_KEY_SIZE];
    uint8_t data[sizeof(public_key)];
    atcacert_device_loc_t device_loc = { DEVZONE_DATA, 0, TRUE, 5, 55 };

    ret = atcab_get_pubkey(device_loc.slot, public_key);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);

    ret = atcacert_read_device_loc(&device_loc, data);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);
    TEST_ASSERT_EQUAL_MEMORY(&public_key[device_loc.offset], data, device_loc.count);
}

TEST(atcacert_client, atcacert_read_device_loc_data_partial)
{
    int ret;
    uint8_t data_full[72];
    uint8_t data[sizeof(data_full)];
    atcacert_device_loc_t device_loc = { DEVZONE_DATA, 12, FALSE, 5, 55 };

    ret = atcab_read_bytes_zone(device_loc.zone, device_loc.slot, 0, data_full, 72);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);

    ret = atcacert_read_device_loc(&device_loc, data);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);
    TEST_ASSERT_EQUAL_MEMORY(&data_full[device_loc.offset], data, device_loc.count);
}

TEST(atcacert_client, atcacert_read_cert_signer)
{
    int ret = 0;
    uint8_t cert[512];
    size_t cert_size = sizeof(cert);

    ret = atcacert_read_cert(&g_test_cert_def_1_signer, g_signer_ca_public_key, cert, &cert_size);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);
    TEST_ASSERT_EQUAL(g_signer_cert_ref_size, cert_size);
    TEST_ASSERT_EQUAL_MEMORY(g_signer_cert_ref, cert, cert_size);
}

TEST(atcacert_client, atcacert_read_cert_device)
{
    int ret = 0;
    uint8_t cert[512];
    size_t cert_size = sizeof(cert);

    ret = atcacert_read_cert(&g_test_cert_def_0_device, g_signer_public_key, cert, &cert_size);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);
    TEST_ASSERT_EQUAL(g_device_cert_ref_size, cert_size);
    TEST_ASSERT_EQUAL_MEMORY(g_device_cert_ref, cert, cert_size);
}

TEST(atcacert_client, atcacert_read_cert_small_buf)
{
    int ret = 0;
    uint8_t cert[64];
    size_t cert_size = sizeof(cert);

    ret = atcacert_read_cert(&g_test_cert_def_1_signer, g_signer_ca_public_key, cert, &cert_size);
    TEST_ASSERT_EQUAL(ATCACERT_E_BUFFER_TOO_SMALL, ret);
}

TEST(atcacert_client, atcacert_read_cert_bad_params)
{
    int ret = 0;
    uint8_t cert[128];
    size_t cert_size = sizeof(cert);

    ret = atcacert_read_cert(NULL, g_signer_public_key, cert, &cert_size);
    TEST_ASSERT_EQUAL(ATCACERT_E_BAD_PARAMS, ret);

    ret = atcacert_read_cert(NULL, NULL, cert, &cert_size);
    TEST_ASSERT_EQUAL(ATCACERT_E_BAD_PARAMS, ret);

    ret = atcacert_read_cert(&g_test_cert_def_0_device, g_signer_public_key, NULL, &cert_size);
    TEST_ASSERT_EQUAL(ATCACERT_E_BAD_PARAMS, ret);

    ret = atcacert_read_cert(NULL, g_signer_public_key, NULL, &cert_size);
    TEST_ASSERT_EQUAL(ATCACERT_E_BAD_PARAMS, ret);

    ret = atcacert_read_cert(&g_test_cert_def_0_device, NULL, NULL, &cert_size);
    TEST_ASSERT_EQUAL(ATCACERT_E_BAD_PARAMS, ret);

    ret = atcacert_read_cert(NULL, NULL, NULL, &cert_size);
    TEST_ASSERT_EQUAL(ATCACERT_E_BAD_PARAMS, ret);

    ret = atcacert_read_cert(&g_test_cert_def_0_device, g_signer_public_key, cert, NULL);
    TEST_ASSERT_EQUAL(ATCACERT_E_BAD_PARAMS, ret);

    ret = atcacert_read_cert(NULL, g_signer_public_key, cert, NULL);
    TEST_ASSERT_EQUAL(ATCACERT_E_BAD_PARAMS, ret);

    ret = atcacert_read_cert(&g_test_cert_def_0_device, NULL, cert, NULL);
    TEST_ASSERT_EQUAL(ATCACERT_E_BAD_PARAMS, ret);

    ret = atcacert_read_cert(NULL, NULL, cert, NULL);
    TEST_ASSERT_EQUAL(ATCACERT_E_BAD_PARAMS, ret);

    ret = atcacert_read_cert(&g_test_cert_def_0_device, g_signer_public_key, NULL, NULL);
    TEST_ASSERT_EQUAL(ATCACERT_E_BAD_PARAMS, ret);

    ret = atcacert_read_cert(NULL, g_signer_public_key, NULL, NULL);
    TEST_ASSERT_EQUAL(ATCACERT_E_BAD_PARAMS, ret);

    ret = atcacert_read_cert(&g_test_cert_def_0_device, NULL, NULL, NULL);
    TEST_ASSERT_EQUAL(ATCACERT_E_BAD_PARAMS, ret);

    ret = atcacert_read_cert(NULL, NULL, NULL, NULL);
    TEST_ASSERT_EQUAL(ATCACERT_E_BAD_PARAMS, ret);
}

TEST(atcacert_client, atcacert_get_response)
{
    int ret = 0;
    uint8_t response[64];
    bool is_verified = false;
    const uint8_t challenge[32] = {
        0x0c, 0xa6, 0x34, 0xc8, 0x37, 0x2f, 0x87, 0x99, 0x99, 0x7e, 0x9e, 0xe9, 0xd5, 0xbc, 0x72, 0x71,
        0x84, 0xd1, 0x97, 0x0a, 0xea, 0xfe, 0xac, 0x60, 0x7e, 0xd1, 0x3e, 0x12, 0xb7, 0x32, 0x25, 0xf1
    };
    char disp_str[256];
    size_t disp_size = sizeof(disp_str);

    ret = atcacert_get_response(0, challenge, response);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);

    ret = atcab_verify_extern(challenge, response, g_device_public_key, &is_verified);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);
    TEST_ASSERT(is_verified);

    disp_size = sizeof(disp_str);
    ret = atcab_bin2hex(challenge, sizeof(challenge), disp_str, &disp_size);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);
    printf("Challenge:\r\n%s\r\n", disp_str);
    disp_size = sizeof(disp_str);
    ret = atcab_bin2hex(response, sizeof(response), disp_str, &disp_size);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);
    printf("Response:\r\n%s\r\n", disp_str);
    disp_size = sizeof(disp_str);
    ret = atcab_bin2hex(g_device_public_key, sizeof(g_device_public_key), disp_str, &disp_size);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, ret);
    printf("Public Key:\r\n%s\r\n", disp_str);
}

TEST(atcacert_client, atcacert_get_response_bad_params)
{
    int ret = 0;
    uint8_t response[64];
    const uint8_t challenge[32] = {
        0x0c, 0xa6, 0x34, 0xc8, 0x37, 0x2f, 0x87, 0x99, 0x99, 0x7e, 0x9e, 0xe9, 0xd5, 0xbc, 0x72, 0x71,
        0x84, 0xd1, 0x97, 0x0a, 0xea, 0xfe, 0xac, 0x60, 0x7e, 0xd1, 0x3e, 0x12, 0xb7, 0x32, 0x25, 0xf1
    };

    ret = atcacert_get_response(16, challenge, response);
    TEST_ASSERT_EQUAL(ATCACERT_E_BAD_PARAMS, ret);

    ret = atcacert_get_response(0, NULL, response);
    TEST_ASSERT_EQUAL(ATCACERT_E_BAD_PARAMS, ret);

    ret = atcacert_get_response(16, NULL, response);
    TEST_ASSERT_EQUAL(ATCACERT_E_BAD_PARAMS, ret);

    ret = atcacert_get_response(0, challenge, NULL);
    TEST_ASSERT_EQUAL(ATCACERT_E_BAD_PARAMS, ret);

    ret = atcacert_get_response(16, challenge, NULL);
    TEST_ASSERT_EQUAL(ATCACERT_E_BAD_PARAMS, ret);

    ret = atcacert_get_response(0, NULL, NULL);
    TEST_ASSERT_EQUAL(ATCACERT_E_BAD_PARAMS, ret);

    ret = atcacert_get_response(16, NULL, NULL);
    TEST_ASSERT_EQUAL(ATCACERT_E_BAD_PARAMS, ret);
}

TEST(atcacert_client, atcacert_generate_device_csr)
{
    uint8_t csr_der_buffer[512];
    uint8_t signature[64];
    uint8_t pub_key[64];
    size_t csr_der_buffer_length = 0;
    bool is_verified = false;
    uint8_t csr_digest[ATCA_BLOCK_SIZE];
    char disp_str[1024];
    size_t disp_size = sizeof(disp_str);
    const atcacert_cert_loc_t* pub_loc = NULL;
    int ret = 0;

    memset(csr_der_buffer, 0, sizeof(csr_der_buffer));

    // Generate the device CSR
    csr_der_buffer_length = sizeof(csr_der_buffer);
    ret = atcacert_create_csr(&g_csr_def_2_device, csr_der_buffer, &csr_der_buffer_length);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);

    ret = atcab_bin2hex(csr_der_buffer, csr_der_buffer_length, disp_str, &disp_size);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);
    printf("Device CSR:\r\n%s\r\n", disp_str);

    // Get the public key from CSR
    pub_loc =  &(g_csr_def_2_device.std_cert_elements[STDCERT_PUBLIC_KEY]);
    ret = atcacert_get_cert_element(&g_csr_def_2_device, pub_loc, csr_der_buffer, csr_der_buffer_length, pub_key, ATCA_PUB_KEY_SIZE);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);

    // Get the digest of the CSR
    ret = atcacert_get_tbs_digest(&g_csr_def_2_device, csr_der_buffer, csr_der_buffer_length, csr_digest);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);

    //Get the signature from the CSR
    ret = atcacert_get_signature(&g_csr_def_2_device, csr_der_buffer, csr_der_buffer_length, signature);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);

    ret = atcab_verify_extern(csr_digest, signature, pub_key, &is_verified);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);
    TEST_ASSERT(is_verified);

}

TEST(atcacert_client, atcacert_generate_device_csr_pem)
{
    uint8_t csr_der_buffer[512];
    char csr_pem_buffer[512];
    uint8_t signature[64];
    uint8_t pub_key[64];
    size_t csr_der_buffer_length = 0;
    size_t csr_pem_buffer_length = 0;
    bool is_verified = false;
    uint8_t csr_digest[ATCA_BLOCK_SIZE] = { 0 };
    const atcacert_cert_loc_t* pub_loc = NULL;
    int ret = 0;

    memset(csr_pem_buffer, 0, sizeof(csr_pem_buffer));
    memset(csr_der_buffer, 0, sizeof(csr_der_buffer));

    //Generate the CSR certificate in PEM
    csr_pem_buffer_length = sizeof(csr_pem_buffer);
    ret = atcacert_create_csr_pem(&g_csr_def_2_device, (char*)&csr_pem_buffer, &csr_pem_buffer_length);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);

    printf("Device CSR :\r\n%s", csr_pem_buffer);

    // Convert the CSR certificate to DER
    csr_der_buffer_length = sizeof(csr_der_buffer);
    ret = atcacert_decode_pem_csr(csr_pem_buffer, csr_pem_buffer_length, csr_der_buffer, &csr_der_buffer_length);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);

    // Get the public key from CSR
    pub_loc =  &(g_csr_def_2_device.std_cert_elements[STDCERT_PUBLIC_KEY]);
    ret = atcacert_get_cert_element(&g_csr_def_2_device, pub_loc, csr_der_buffer, csr_der_buffer_length, pub_key, ATCA_PUB_KEY_SIZE);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);

    // Get the digest of the CSR
    ret = atcacert_get_tbs_digest(&g_csr_def_2_device, csr_der_buffer, csr_der_buffer_length, csr_digest);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);

    //Get the signature from the CSR
    ret = atcacert_get_signature(&g_csr_def_2_device, csr_der_buffer, csr_der_buffer_length, signature);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);

    ret = atcab_verify_extern(csr_digest, signature, pub_key, &is_verified);
    TEST_ASSERT_EQUAL(ATCACERT_E_SUCCESS, ret);
    TEST_ASSERT(is_verified);
}
