/*--------------------------------------------------------------------------*/
/* Copyright 2021 NXP                                                       */
/*                                                                          */
/* NXP Confidential. This software is owned or controlled by NXP and may    */
/* only be used strictly in accordance with the applicable license terms.   */
/* By expressly accepting such terms or by downloading, installing,         */
/* activating and/or otherwise using the software, you are agreeing that    */
/* you have read, and that you agree to comply with and are bound by, such  */
/* license terms. If you do not agree to be bound by the applicable license */
/* terms, then you may not retain, install, activate or otherwise use the   */
/* software.                                                                */
/*--------------------------------------------------------------------------*/

/**
 * @file  mcuxClRsa_verify_NoVerify_example.c
 * @brief Example of using function mcuxClRsa_verify to perform the RSA signature verification primitive RSAVP1
 *      (public exponentiation and NO padding verification) according to PKCS #1 v2.2.
 *
 * @example mcuxClRsa_verify_NoVerify_example.c
 * @brief Example of using function mcuxClRsa_verify to perform the RSA signature verification primitive RSAVP1
 *      (public exponentiation and NO padding verification) according to PKCS #1 v2.2.
 */

#include <mcuxClSession.h>          // Interface to the entire mcuxClSession component
#include <mcuxCsslFlowProtection.h> // Code flow protection
#include <mcuxClPkc.h>              // Interface to the entire mcuxClPkc component
#include <mcuxClRsa.h>              // Interface to the entire mcuxClRsa component
#include <toolchain.h>             // Memory segment definitions
#include <stdbool.h>               // bool type for the example's return code
#include <mcuxClCss.h> // Interface to the entire mcuxClCss component

/**********************************************************/
/* Example test vectors                                   */
/**********************************************************/

#define RSA_KEY_BIT_LENGTH (2048u)                    ///< The example uses a 2048-bit key
#define RSA_KEY_BYTE_LENGTH (RSA_KEY_BIT_LENGTH / 8u) ///< Converting the key-bitlength to bytelength


/**
 * @brief Example value for public RSA modulus N.
 */
static const uint8_t modulus[RSA_KEY_BYTE_LENGTH] __attribute__ ((aligned (4))) = {
  0xbau,0xd4u,0x7au,0x84u,0xc1u,0x78u,0x2eu,0x4du,0xbdu,0xd9u,0x13u,0xf2u,0xa2u,0x61u,0xfcu,0x8bu,
  0x65u,0x83u,0x84u,0x12u,0xc6u,0xe4u,0x5au,0x20u,0x68u,0xedu,0x6du,0x7fu,0x16u,0xe9u,0xcdu,0xf4u,
  0x46u,0x2bu,0x39u,0x11u,0x95u,0x63u,0xcau,0xfbu,0x74u,0xb9u,0xcbu,0xf2u,0x5cu,0xfdu,0x54u,0x4bu,
  0xdau,0xe2u,0x3bu,0xffu,0x0eu,0xbeu,0x7fu,0x64u,0x41u,0x04u,0x2bu,0x7eu,0x10u,0x9bu,0x9au,0x8au,
  0xfau,0xa0u,0x56u,0x82u,0x1eu,0xf8u,0xefu,0xaau,0xb2u,0x19u,0xd2u,0x1du,0x67u,0x63u,0x48u,0x47u,
  0x85u,0x62u,0x2du,0x91u,0x8du,0x39u,0x5au,0x2au,0x31u,0xf2u,0xecu,0xe8u,0x38u,0x5au,0x81u,0x31u,
  0xe5u,0xffu,0x14u,0x33u,0x14u,0xa8u,0x2eu,0x21u,0xafu,0xd7u,0x13u,0xbau,0xe8u,0x17u,0xccu,0x0eu,
  0xe3u,0x51u,0x4du,0x48u,0x39u,0x00u,0x7cu,0xcbu,0x55u,0xd6u,0x84u,0x09u,0xc9u,0x7au,0x18u,0xabu,
  0x62u,0xfau,0x6fu,0x9fu,0x89u,0xb3u,0xf9u,0x4au,0x27u,0x77u,0xc4u,0x7du,0x61u,0x36u,0x77u,0x5au,
  0x56u,0xa9u,0xa0u,0x12u,0x7fu,0x68u,0x24u,0x70u,0xbeu,0xf8u,0x31u,0xfbu,0xecu,0x4bu,0xcdu,0x7bu,
  0x50u,0x95u,0xa7u,0x82u,0x3fu,0xd7u,0x07u,0x45u,0xd3u,0x7du,0x1bu,0xf7u,0x2bu,0x63u,0xc4u,0xb1u,
  0xb4u,0xa3u,0xd0u,0x58u,0x1eu,0x74u,0xbfu,0x9au,0xdeu,0x93u,0xccu,0x46u,0x14u,0x86u,0x17u,0x55u,
  0x39u,0x31u,0xa7u,0x9du,0x92u,0xe9u,0xe4u,0x88u,0xefu,0x47u,0x22u,0x3eu,0xe6u,0xf6u,0xc0u,0x61u,
  0x88u,0x4bu,0x13u,0xc9u,0x06u,0x5bu,0x59u,0x11u,0x39u,0xdeu,0x13u,0xc1u,0xeau,0x29u,0x27u,0x49u,
  0x1eu,0xd0u,0x0fu,0xb7u,0x93u,0xcdu,0x68u,0xf4u,0x63u,0xf5u,0xf6u,0x4bu,0xaau,0x53u,0x91u,0x6bu,
  0x46u,0xc8u,0x18u,0xabu,0x99u,0x70u,0x65u,0x57u,0xa1u,0xc2u,0xd5u,0x0du,0x23u,0x25u,0x77u,0xd1u
 };

/**
 * @brief Example value for public RSA exponent e.
 */
static const uint8_t exponent[3] __attribute__ ((aligned (4))) = {
  0x01u, 0x00u, 0x01u
};

/**
 * @brief Example value for RSA signature s.
 */
static const uint8_t signature[RSA_KEY_BYTE_LENGTH] __attribute__ ((aligned (4))) = {
  0x7eu,0x65u,0xb9u,0x98u,0xa0u,0x5fu,0x62u,0x6bu,0x02u,0x8cu,0x75u,0xdcu,0x3fu,0xbfu,0x98u,0x96u,
  0x3du,0xceu,0x66u,0xd0u,0xf4u,0xc3u,0xaeu,0x42u,0x37u,0xcfu,0xf3u,0x04u,0xd8u,0x4du,0x88u,0x36u,
  0xcbu,0x6bu,0xadu,0x9au,0xc8u,0x6fu,0x9du,0x1bu,0x8au,0x28u,0xddu,0x70u,0x40u,0x47u,0x88u,0xb8u,
  0x69u,0xd2u,0x42u,0x9fu,0x1eu,0xc0u,0x66u,0x3eu,0x51u,0xb7u,0x53u,0xf7u,0x45u,0x1cu,0x6bu,0x46u,
  0x45u,0xd9u,0x91u,0x26u,0xe4u,0x57u,0xc1u,0xdau,0xc4u,0x95u,0x51u,0xd8u,0x6au,0x8au,0x97u,0x4au,
  0x31u,0x31u,0xe9u,0xb3u,0x71u,0xd5u,0xc2u,0x14u,0xccu,0x9fu,0xf2u,0x40u,0xc2u,0x99u,0xbdu,0x0eu,
  0x62u,0xdbu,0xc7u,0xa9u,0xa2u,0xdau,0xd9u,0xfau,0x54u,0x04u,0xadu,0xb0u,0x06u,0x32u,0xd3u,0x63u,
  0x32u,0xd5u,0xbeu,0x61u,0x06u,0xe9u,0xe6u,0xecu,0x81u,0xcau,0xc4u,0x5cu,0xd3u,0x39u,0xccu,0x87u,
  0xabu,0xbeu,0x7fu,0x89u,0x43u,0x08u,0x00u,0xe1u,0x6eu,0x03u,0x2au,0x66u,0x21u,0x0bu,0x25u,0xe9u,
  0x26u,0xedu,0xa2u,0x43u,0xd9u,0xf0u,0x99u,0x55u,0x49u,0x6du,0xdbu,0xc7u,0x7eu,0xf7u,0x4fu,0x17u,
  0xfeu,0xe4u,0x1cu,0x44u,0x35u,0xe7u,0x8bu,0x46u,0x96u,0x5bu,0x71u,0x3du,0x72u,0xceu,0x8au,0x31u,
  0xafu,0x64u,0x15u,0x38u,0xadu,0xd3u,0x87u,0xfeu,0xdfu,0xd8u,0x8bu,0xb2u,0x2au,0x42u,0xebu,0x3bu,
  0xdau,0x40u,0xf7u,0x2eu,0xcau,0xd9u,0x41u,0xdbu,0xffu,0xddu,0x47u,0xb3u,0xe7u,0x77u,0x37u,0xdau,
  0x74u,0x15u,0x53u,0xa4u,0x5bu,0x63u,0x0du,0x07u,0x0bu,0xccu,0x52u,0x05u,0x80u,0x4bu,0xf8u,0x0eu,
  0xe2u,0xd5u,0x16u,0x12u,0x87u,0x5du,0xbcu,0x47u,0x96u,0x96u,0x00u,0x52u,0xf1u,0x68u,0x7eu,0x00u,
  0x74u,0x00u,0x7eu,0x6au,0x33u,0xabu,0x8bu,0x20u,0x85u,0xc0u,0x33u,0xf9u,0x89u,0x2bu,0x6fu,0x74u
};

/**
 * @brief Reference output when calling mcuxClRsa_verify on signature s using the RSA public key pair (N,e)
 *        and choosing mode mcuxClRsa_Mode_Verify_NoVerify.
 */
static const uint8_t reference_result[RSA_KEY_BYTE_LENGTH] __attribute__ ((aligned (4))) = {
  0x70u,0x99u,0x2cu,0x9du,0x95u,0xa4u,0x90u,0x8du,0x2au,0x94u,0xb3u,0xabu,0x9fu,0xa1u,0xcdu,0x64u,
  0x3fu,0x12u,0x0eu,0x32u,0x6fu,0x9du,0x78u,0x08u,0xafu,0x50u,0xcau,0xc4u,0x2cu,0x4bu,0x0bu,0x4eu,
  0xebu,0x7fu,0x0du,0x4du,0xf3u,0x03u,0xa5u,0x68u,0xfbu,0xfbu,0x82u,0xb0u,0xf5u,0x83u,0x00u,0xd2u,
  0x53u,0x57u,0x64u,0x57u,0x21u,0xbbu,0x71u,0x86u,0x1cu,0xafu,0x81u,0xb2u,0x7au,0x56u,0x08u,0x2cu,
  0x80u,0xa1u,0x46u,0x49u,0x9fu,0xb4u,0xeau,0xb5u,0xbdu,0xe4u,0x49u,0x3fu,0x5du,0x00u,0xf1u,0xa4u,
  0x37u,0xbbu,0xc3u,0x60u,0xdfu,0xcdu,0x80u,0x56u,0xfeu,0x6bu,0xe1u,0x0eu,0x60u,0x8au,0xdbu,0x30u,
  0xb6u,0xc2u,0xf7u,0x65u,0x24u,0x28u,0xb8u,0xd3u,0x2du,0x36u,0x29u,0x45u,0x98u,0x2au,0x46u,0x58u,
  0x5du,0x21u,0x02u,0xefu,0x79u,0x95u,0xa8u,0xbau,0x6eu,0x8au,0xd8u,0xfdu,0x16u,0xbdu,0x7au,0xe8u,
  0xf5u,0x3cu,0x3du,0x7fu,0xcfu,0xbau,0x29u,0x0bu,0x57u,0xceu,0x7fu,0x8fu,0x09u,0xc8u,0x28u,0xd6u,
  0xf2u,0xd3u,0xceu,0x56u,0xf1u,0x31u,0xbdu,0x94u,0x61u,0xe5u,0x66u,0x7eu,0x5bu,0x73u,0xedu,0xacu,
  0x77u,0xf5u,0x04u,0xdau,0xc4u,0xf2u,0x02u,0xa9u,0x57u,0x0eu,0xb4u,0x51u,0x5bu,0x2bu,0xf5u,0x16u,
  0x40u,0x7du,0xb8u,0x31u,0x51u,0x8du,0xb8u,0xa2u,0x08u,0x3eu,0xc7u,0x01u,0xe8u,0xfdu,0x38u,0x7cu,
  0x43u,0x0bu,0xb1u,0xa7u,0x2du,0xecu,0xa5u,0xb4u,0x9du,0x42u,0x9cu,0xf9u,0xdeu,0xb0u,0x9cu,0xc4u,
  0x51u,0x8du,0xc5u,0xf5u,0x7cu,0x08u,0x9au,0xa2u,0xd3u,0x42u,0x0eu,0x56u,0x7eu,0x73u,0x21u,0x02u,
  0xc2u,0xc9u,0x2bu,0x88u,0xa0u,0x7cu,0x69u,0xd7u,0x09u,0x17u,0x14u,0x0au,0xb3u,0x82u,0x3cu,0x63u,
  0xf3u,0x12u,0xd3u,0xf1u,0x1fu,0xa8u,0x7bu,0xa2u,0x9du,0xa3u,0xc7u,0x22u,0x4bu,0x4fu,0xb4u,0xbcu
};


/** Performs a session set-up; a call to function mcuxClRsa_verify using mode mcuxClRsa_Mode_Verify_NoVerify; a session clean-up
 * @retval true  The example code completed successfully
 * @retval false The example code failed */
bool mcuxClRsa_verify_NoVerify_example(void)
{
    /**************************************************************************/
    /* Preparation                                                            */
    /**************************************************************************/

    /* Enable Css */
    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_Enable_Async()); // Enable the CSSv2.
    // mcuxClCss_Enable_Async is a flow-protected function: Check the protection token and the return value
    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_Enable_Async) != token) || (MCUXCLCSS_STATUS_OK_WAIT != result))
        return false;
    MCUX_CSSL_FP_FUNCTION_CALL_END();

    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_WaitForOperation(MCUXCLCSS_ERROR_FLAGS_CLEAR)); // Wait for the mcuxClCss_Enable_Async operation to complete.
    // mcuxClCss_WaitForOperation is a flow-protected function: Check the protection token and the return value
    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_WaitForOperation) != token) || (MCUXCLCSS_STATUS_OK != result))
        return false;
    MCUX_CSSL_FP_FUNCTION_CALL_END();

    /* Create session handle to be used by verify function */
    uint32_t cpuWaBuffer[MCUXCLRSA_VERIFY_OPTIONNOVERIFY_WACPU_SIZE/sizeof(uint32_t)];

    mcuxClSession_Descriptor_t sessionDesc;
    mcuxClSession_Handle_t session = &sessionDesc;

    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(si_status, si_token, mcuxClSession_init(
                /* mcuxClSession_Handle_t session:      */ session,
                /* uint32_t * const cpuWaBuffer:       */ cpuWaBuffer,
                /* uint32_t cpuWaSize:                 */ MCUXCLRSA_VERIFY_OPTIONNOVERIFY_WACPU_SIZE/sizeof(uint32_t),
                /* uint32_t * const pkcWaBuffer:       */ (uint32_t *) MCUXCLPKC_RAM_START_ADDRESS,
                /* uint32_t pkcWaSize:                 */ MCUXCLRSA_VERIFY_OPTIONNOVERIFY_2048_WAPKC_SIZE/sizeof(uint32_t)
                ));


    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClSession_init) != si_token) || (MCUXCLSESSION_STATUS_OK != si_status))
            return false;

    MCUX_CSSL_FP_FUNCTION_CALL_END();

    /* Create key struct of type MCUXCLRSA_KEY_PUBLIC */
    const mcuxClRsa_KeyEntry_t Mod1 = {
                       .pKeyEntryData = (uint8_t *)modulus,
                       .keyEntryLength = RSA_KEY_BYTE_LENGTH };

    const mcuxClRsa_KeyEntry_t Exp1 = {
                       .pKeyEntryData = (uint8_t *)exponent,
                       .keyEntryLength = 3U };

    const mcuxClRsa_Key public_key = {
                                     .keytype = MCUXCLRSA_KEY_PUBLIC,
                                     .pMod1 = (mcuxClRsa_KeyEntry_t *)&Mod1,
                                     .pMod2 = NULL,
                                     .pQInv = NULL,
                                     .pExp1 = (mcuxClRsa_KeyEntry_t *)&Exp1,
                                     .pExp2 = NULL,
                                     .pExp3 = NULL };

    /* Prepare buffer to store the result */
    uint8_t encodedMessag[RSA_KEY_BYTE_LENGTH];

    /**************************************************************************/
    /* RSA verification call                                                  */
    /**************************************************************************/

    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(verify_result, verify_token, mcuxClRsa_verify(
                /* mcuxClSession_Handle_t           pSession: */           session,
                /* const mcuxClRsa_Key * const      pKey: */               &public_key,
                /* const uint8_t * const           pMessageOrDigest: */   NULL,
                /* const uint32_t                  messageLength: */      0u,
                /* uint8_t * const                 pSignature: */         (uint8_t *)signature,
                /* const mcuxClRsa_SignVerifyMode   pVerifyMode: */        (mcuxClRsa_SignVerifyMode_t *)&mcuxClRsa_Mode_Verify_NoVerify,
                /* const uint32_t                  saltLength: */         0u,
                /* uint32_t                        options: */            0u,
                /* uint8_t * const                 pOutput: */            encodedMessag));

    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClRsa_verify) != verify_token) || (MCUXCLRSA_STATUS_VERIFYPRIMITIVE_OK != verify_result))
        return false;

    MCUX_CSSL_FP_FUNCTION_CALL_END();


    /**************************************************************************/
    /* Verification of the result                                             */
    /**************************************************************************/
    for (size_t i = 0U; i < sizeof(encodedMessag); i++)
    {
        if (reference_result[i] != encodedMessag[i])
        {
            return false;
        }
    }

    /**************************************************************************/
    /* Session clean-up                                                       */
    /**************************************************************************/

    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(cleanup_result, cleanup_token, mcuxClSession_cleanup(
                /* mcuxClSession_Handle_t           pSession: */           session));

    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClSession_cleanup) != cleanup_token) || (MCUXCLSESSION_STATUS_OK != cleanup_result))
        return false;

    MCUX_CSSL_FP_FUNCTION_CALL_END();

    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(destroy_result, destroy_token, mcuxClSession_destroy(
                /* mcuxClSession_Handle_t           pSession: */           session));

    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClSession_destroy) != destroy_token) || (MCUXCLSESSION_STATUS_OK != destroy_result))
        return false;

    MCUX_CSSL_FP_FUNCTION_CALL_END();

    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_Disable()); // Disable the CSSv2.
    // mcuxClCss_Disable is a flow-protected function: Check the protection token and the return value
    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_Disable) != token) || (MCUXCLCSS_STATUS_OK != result))
        return false;
    MCUX_CSSL_FP_FUNCTION_CALL_END();

    return true;
}
