/*************************************************************************
* Copyright (C) 2023 Intel Corporation
*
* Licensed under the Apache License,  Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 	http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law  or agreed  to  in  writing,  software
* distributed under  the License  is  distributed  on  an  "AS IS"  BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the  specific  language  governing  permissions  and
* limitations under the License.
*************************************************************************/

#ifdef IPPCP_FIPS_MODE
#include "ippcp.h"
#include "owndefs.h"
#include "dispatcher.h"

// FIPS selftests are not processed by dispatcher.
// Prevent several copies of the same functions.
#ifdef _IPP_DATA

#include <ippcp/fips_cert.h>
#include <fips_cert_internal/common.h>
#include <fips_cert_internal/bn_common.h>

/*
 * KAT
 * vectors are taken from FIPS 186 testing vectors set
*/
__ALIGN64 static const Ipp8u pPrivExp[] = { 0x9f,0x06,0xd2,0x01,0x39,0xfc,0x4f,0x7a,0x86,0x83,0xc2,0xc9,0x1c,0xe9,
                                            0xd3,0x0e,0x2b,0x87,0x5e,0x07,0x8e,0xa3,0xeb,0x3e,0xe3,0x13,0x5d,0x0b,
                                            0x40,0x9d,0x86,0xf4,0xdf,0xb4,0x72,0xd9,0xda,0x0a,0x24,0xdf,0x6b,0x90,
                                            0x7c,0x6c,0xd6,0xec,0x98,0xc6,0x5c,0x92,0x04,0x0c,0x24,0xe4,0xc3,0xe8,
                                            0xe3,0x20,0x31,0xba,0xc7,0x0f,0x32,0x9a,0x44,0xa2,0x41,0x9a,0xd2,0x1e,
                                            0xaf,0x91,0x2f,0x72,0x71,0x8c,0x0a,0xc9,0x93,0x10,0xcf,0x6a,0x02,0x95,
                                            0xb5,0x21,0x1f,0xa4,0x74,0xfe,0xe5,0x54,0xa0,0xed,0x65,0x93,0xba,0x33,
                                            0x2c,0xb6,0xc4,0x86,0x3e,0xfa,0xd3,0x98,0xc7,0x09,0xfa,0x50,0xa9,0xb3,
                                            0xc2,0x96,0xa7,0xb0,0xf5,0x4b,0x7e,0xbd,0xfe,0xea,0xa4,0x49,0x5f,0x3e,
                                            0xb6,0x54,0x7a,0xa3,0x2b,0x06,0xe9,0x03,0xc0,0xac,0xad,0xb2,0x5d,0xce,
                                            0x6d,0x12,0xd3,0x65,0x81,0x1a,0xd7,0x65,0x94,0x1e,0xbe,0x8a,0x74,0x2d,
                                            0xbb,0x78,0xc9,0x50,0x02,0x9d,0x5c,0x1e,0xfd,0x54,0x00,0x81,0xf7,0xc9,
                                            0x0d,0xc8,0x9d,0x1b,0x44,0x8a,0x53,0x95,0x4a,0x6c,0x06,0xc8,0x87,0x60,
                                            0x3c,0xb9,0xdd,0xe7,0x8c,0xdb,0x0d,0x17,0x67,0x79,0x9b,0xf3,0x43,0xa4,
                                            0xec,0x88,0x9b,0xfd,0xc9,0xc0,0xaf,0xff,0xa9,0x6b,0xe1,0x55,0x5f,0x7c,
                                            0x33,0x04,0x48,0x94,0xf7,0x7a,0xb9,0xd8,0x23,0x4a,0x4c,0x2d,0xa5,0xee,
                                            0x87,0x2a,0x30,0x15,0x47,0xab,0x74,0xe5,0x08,0x8f,0x48,0x28,0xd1,0x75,
                                            0x9b,0x37,0x75,0x88,0x08,0xde,0x7b,0x32,0x86,0x45,0xf9,0x32,0xd3,0xb4,
                                            0x6b,0x78,0xe5,0x49 };
__ALIGN64 static const Ipp8u pPubExp[]  = { 0x4f,0xc9,0x86 };
__ALIGN64 static const Ipp8u pModulus[] = { 0xef,0x05,0x18,0x6b,0x85,0xe9,0xc6,0x0f,0xfc,0xa3,0xde,0x11,0xeb,0x94,
                                            0x5c,0xaf,0x0a,0x45,0xad,0x50,0xa8,0xf1,0xd9,0x59,0x33,0x12,0x37,0xfd,
                                            0xe7,0x5f,0xe6,0x3e,0xac,0x43,0x6f,0xce,0xbe,0xb4,0x49,0xd5,0xf9,0xa7,
                                            0xe0,0x7e,0x5f,0xd7,0x66,0x64,0x94,0x5b,0x58,0x27,0xdd,0x0b,0xb4,0x12,
                                            0xc4,0x12,0xc0,0x0d,0xf4,0x05,0xf2,0xbe,0xa1,0x1c,0x12,0xf1,0x52,0xf3,
                                            0x3a,0xb5,0x90,0x87,0x28,0xf5,0xb4,0xb1,0xd1,0x31,0x33,0x94,0x3a,0x5a,
                                            0x63,0x3f,0x03,0x7f,0xca,0xda,0xf9,0xc7,0x01,0x66,0x89,0xea,0xff,0x2e,
                                            0xfd,0xd5,0x20,0xa6,0x89,0x1c,0xf8,0x36,0x8c,0xea,0xac,0x89,0x3a,0x35,
                                            0xbd,0x19,0xab,0xe2,0x37,0x19,0x17,0xd8,0xac,0x9c,0xe8,0x67,0xac,0x6b,
                                            0x6b,0x31,0x3d,0xcb,0xee,0x24,0xb7,0xf5,0x2f,0xe6,0x0a,0xdb,0x55,0x67,
                                            0xa3,0x3e,0x14,0x13,0x84,0xb2,0xff,0xeb,0x3e,0xff,0xd7,0x44,0xd9,0xe2,
                                            0x7b,0x15,0x13,0x11,0xc7,0xbe,0xc5,0x6b,0xb8,0x23,0x64,0x33,0x70,0x96,
                                            0xc9,0x09,0x6f,0xb2,0xb6,0x15,0xee,0x2f,0x2b,0xd4,0x26,0xcb,0xb9,0x2c,
                                            0x9c,0x74,0xe5,0x1d,0x58,0x90,0xd7,0xf9,0xb9,0x37,0x04,0x43,0x26,0xf8,
                                            0xe4,0x45,0xc4,0x7d,0xef,0x0f,0x6c,0x8b,0x17,0xc6,0x3b,0x57,0x81,0xd2,
                                            0x08,0xc3,0x52,0xa7,0xbc,0x59,0xca,0x59,0x93,0x77,0xbe,0x6a,0x12,0x8f,
                                            0x32,0xff,0x48,0x59,0xbb,0x0b,0x93,0x1a,0xfd,0xec,0x5f,0x10,0x13,0x2e,
                                            0x6c,0xd5,0x5d,0xf7,0x4c,0xf1,0xba,0x5d,0x1e,0x5e,0x76,0x9c,0x53,0xd8,
                                            0x58,0x2b,0x06,0xc5 };
__ALIGN64 static const Ipp8u pMsg[]     = { 0xdf,0xc2,0x26,0x04,0xb9,0x5d,0x15,0x32,0x80,0x59,0x74,0x5c,0x6c,0x98,
                                            0xeb,0x9d,0xfb,0x34,0x7c,0xf9,0xf1,0x70,0xaf,0xf1,0x9d,0xee,0xec,0x55,
                                            0x5f,0x22,0x28,0x5a,0x67,0x06,0xc4,0xec,0xbf,0x0f,0xb1,0x45,0x8c,0x60,
                                            0xd9,0xbf,0x91,0x3f,0xba,0xe6,0xf4,0xc5,0x54,0xd2,0x45,0xd9,0x46,0xb4,
                                            0xbc,0x5f,0x34,0xae,0xc2,0xac,0x6b,0xe8,0xb3,0x3d,0xc8,0xe0,0xe3,0xa9,
                                            0xd6,0x01,0xdf,0xd5,0x36,0x78,0xf5,0x67,0x44,0x43,0xf6,0x7d,0xf7,0x8a,
                                            0x3a,0x9e,0x09,0x33,0xe5,0xf1,0x58,0xb1,0x69,0xac,0x8d,0x1c,0x4c,0xd0,
                                            0xfb,0x87,0x2c,0x14,0xca,0x8e,0x00,0x1e,0x54,0x2e,0xa0,0xf9,0xcf,0xda,
                                            0x88,0xc4,0x2d,0xca,0xd8,0xa7,0x40,0x97,0xa0,0x0c,0x22,0x05,0x5b,0x0b,
                                            0xd4,0x1f };
__ALIGN64 static const Ipp8u pSig[]     = { 0x8b,0x46,0xf2,0xc8,0x89,0xd8,0x19,0xf8,0x60,0xaf,0x0a,0x6c,0x4c,0x88,
                                            0x9e,0x4d,0x14,0x36,0xc6,0xca,0x17,0x44,0x64,0xd2,0x2a,0xe1,0x1b,0x9c,
                                            0xcc,0x26,0x5d,0x74,0x3c,0x67,0xe5,0x69,0xac,0xcb,0xc5,0xa8,0x0d,0x4d,
                                            0xd5,0xf1,0xbf,0x40,0x39,0xe2,0x3d,0xe5,0x2a,0xec,0xe4,0x02,0x91,0xc7,
                                            0x5f,0x89,0x36,0xc5,0x8c,0x9a,0x2f,0x77,0xa7,0x80,0xbb,0xe7,0xad,0x31,
                                            0xeb,0x76,0x74,0x2f,0x7b,0x2b,0x8b,0x14,0xca,0x1a,0x71,0x96,0xaf,0x7e,
                                            0x67,0x3a,0x3c,0xfc,0x23,0x7d,0x50,0xf6,0x15,0xb7,0x5c,0xf4,0xa7,0xea,
                                            0x78,0xa9,0x48,0xbe,0xda,0xf9,0x24,0x24,0x94,0xb4,0x1e,0x1d,0xb5,0x1f,
                                            0x43,0x7f,0x15,0xfd,0x25,0x51,0xbb,0x5d,0x24,0xee,0xfb,0x1c,0x3e,0x60,
                                            0xf0,0x36,0x94,0xd0,0x03,0x3a,0x1e,0x0a,0x9b,0x9f,0x5e,0x4a,0xb9,0x7d,
                                            0x45,0x7d,0xff,0x9b,0x9d,0xa5,0x16,0xdc,0x22,0x6d,0x6d,0x65,0x29,0x50,
                                            0x03,0x08,0xed,0x74,0xa2,0xe6,0xd9,0xf3,0xc1,0x05,0x95,0x78,0x8a,0x52,
                                            0xa1,0xbc,0x06,0x64,0xae,0xdf,0x33,0xef,0xc8,0xba,0xdd,0x03,0x7e,0xb7,
                                            0xb8,0x80,0x77,0x2b,0xdb,0x04,0xa6,0x04,0x6e,0x9e,0xde,0xee,0x41,0x97,
                                            0xc2,0x55,0x07,0xfb,0x0f,0x11,0xab,0x1c,0x9f,0x63,0xf5,0x3c,0x88,0x20,
                                            0xea,0x84,0x05,0xcf,0xd7,0x72,0x16,0x92,0x47,0x5b,0x4d,0x72,0x35,0x5f,
                                            0xa9,0xa3,0x80,0x4f,0x29,0xe6,0xb6,0xa7,0xb0,0x59,0xc4,0x44,0x1d,0x54,
                                            0xb2,0x8e,0x4e,0xed,0x25,0x29,0xc6,0x10,0x3b,0x54,0x32,0xc7,0x13,0x32,
                                            0xce,0x74,0x2b,0xcc};
__ALIGN64 static const Ipp8u pSalt[]    = { 0xe1,0x25,0x6f,0xc1,0xee,0xef,0x81,0x77,0x3f,0xdd,0x54,0x65,0x7e,0x40,
                                            0x07,0xfd,0xe6,0xbc,0xb9,0xb1 };

static const unsigned int msgByteLen      = sizeof(pMsg);
static const unsigned int saltByteLen     = sizeof(pSalt);

static const unsigned int pubExpBitSize   = 24;
static const unsigned int privExpBitSize  = 2048;
static const unsigned int modulusBitSize  = 2048;
static const unsigned int primeBitsize    = 1024;

#define IPPCP_PUB_EXP_WORD_SIZE  (IPPCP_BITSIZE_2_WORDSIZE(pubExpBitSize))
#define IPPCP_PRIV_EXP_WORD_SIZE (IPPCP_BITSIZE_2_WORDSIZE(privExpBitSize))
#define IPPCP_MODULUS_WORD_SIZE  (IPPCP_BITSIZE_2_WORDSIZE(modulusBitSize))

IPPFUN(fips_test_status, fips_selftest_ippsRSASignVerify_PSS_rmf_get_size_keys, (int *pKeysBufferSize))
{
    /* return bad status if input pointer is NULL */
    IPP_BADARG_RET((NULL == pKeysBufferSize), IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR);

    IppStatus sts = ippStsNoErr;
    int total_size = 0;
    int tmp_size = 0;

    /* BIGNUMs sizes */
    sts = ippsBigNumGetSize(IPPCP_PRIV_EXP_WORD_SIZE, &tmp_size);
    if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }
    total_size += tmp_size; // D

    sts = ippsBigNumGetSize(IPPCP_PUB_EXP_WORD_SIZE, &tmp_size);
    if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }
    total_size += tmp_size; // E

    sts = ippsBigNumGetSize(IPPCP_MODULUS_WORD_SIZE, &tmp_size);
    if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }
    total_size += tmp_size; // N

    /* Public and private keys context size */
    sts = ippsRSA_GetSizePublicKey(modulusBitSize, pubExpBitSize, &tmp_size);
    if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }
    total_size += tmp_size; // pPubKey

    sts = ippsPrimeGetSize(primeBitsize,  &tmp_size);
    if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }
    total_size += tmp_size; // pPrimeG

    sts = ippsPRNGGetSize(&tmp_size);
    if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }
    total_size += tmp_size; // pRand

    sts = ippsRSA_GetSizePrivateKeyType1(modulusBitSize, privExpBitSize, &tmp_size);
    if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }

    int tmp_size_2 = 0;
    sts = ippsRSA_GetSizePrivateKeyType2(primeBitsize, privExpBitSize - primeBitsize, &tmp_size_2);
    if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }

    total_size += IPP_MAX(tmp_size, tmp_size_2); // pPrvKey

    *pKeysBufferSize = total_size;

    return IPPCP_ALGO_SELFTEST_OK;
}

IPPFUN(fips_test_status, fips_selftest_ippsRSASignVerify_PSS_rmf_get_size, (int *pBufferSize, Ipp8u *pKeysBuffer))
{
    /* return bad status if input pointers are NULL */
    IPP_BADARG_RET((NULL == pKeysBuffer) || (NULL == pBufferSize), IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR);

    IppStatus sts = ippStsNoErr;
    int total_size = 0;

    Ipp8u *pLocKeysBuffer = pKeysBuffer;

    /* Initialize BigNumber-s */
    int dByteSize;
    sts = ippsBigNumGetSize(IPPCP_PRIV_EXP_WORD_SIZE, &dByteSize);
    if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_BN_ALIGNMENT));
    IppsBigNumState* bnD = (IppsBigNumState *)pLocKeysBuffer;
    pLocKeysBuffer += dByteSize;

    int eByteSize;
    sts = ippsBigNumGetSize(IPPCP_PUB_EXP_WORD_SIZE, &eByteSize);
    if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_BN_ALIGNMENT));
    IppsBigNumState* bnE = (IppsBigNumState *)pLocKeysBuffer;
    pLocKeysBuffer += eByteSize;

    int nByteSize;
    sts = ippsBigNumGetSize(IPPCP_MODULUS_WORD_SIZE, &nByteSize);
    if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_BN_ALIGNMENT));
    IppsBigNumState* bnN = (IppsBigNumState *)pLocKeysBuffer;
    pLocKeysBuffer += nByteSize;

    sts = ippcp_init_set_bn(bnD, IPPCP_PRIV_EXP_WORD_SIZE, ippBigNumPOS, (const Ipp32u *)pPrivExp, IPPCP_PRIV_EXP_WORD_SIZE);
    if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }
    sts = ippcp_init_set_bn(bnE, IPPCP_PUB_EXP_WORD_SIZE,  ippBigNumPOS, (const Ipp32u *)pPubExp,  IPPCP_PUB_EXP_WORD_SIZE);
    if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }
    sts = ippcp_init_set_bn(bnN, IPPCP_MODULUS_WORD_SIZE,  ippBigNumPOS, (const Ipp32u *)pModulus, IPPCP_MODULUS_WORD_SIZE);
    if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }

    /* Initialize public and private keys - necessary to obtain signature size */
    // public key
    int pubKeySize;
    sts = ippsRSA_GetSizePublicKey(modulusBitSize, pubExpBitSize, &pubKeySize);
    if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_RSA_ALIGNMENT));
    IppsRSAPublicKeyState* pPubKey = (IppsRSAPublicKeyState*)pLocKeysBuffer;
    sts = ippsRSA_InitPublicKey(modulusBitSize, pubExpBitSize, pPubKey, pubKeySize);
    if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }
    pLocKeysBuffer+=pubKeySize;
    // private key
    int privKeySize;
    sts = ippsRSA_GetSizePrivateKeyType1(modulusBitSize, privExpBitSize, &privKeySize);
    if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_RSA_ALIGNMENT));
    IppsRSAPrivateKeyState* pPrvKey = (IppsRSAPrivateKeyState*)(pLocKeysBuffer);
    sts = ippsRSA_InitPrivateKeyType1(modulusBitSize, privExpBitSize, pPrvKey, privKeySize);
    if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }
    pLocKeysBuffer+=privKeySize;

    sts = ippsRSA_GetSizePrivateKeyType2(primeBitsize, privExpBitSize - primeBitsize, &privKeySize);
    if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }
    IppsRSAPrivateKeyState* pPrvKey2 = (IppsRSAPrivateKeyState*)(pLocKeysBuffer);
    sts = ippsRSA_InitPrivateKeyType2(primeBitsize, privExpBitSize - primeBitsize, pPrvKey2, privKeySize);
    if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }

    int buffSizePrivKey2 = 0;
    sts = ippsRSA_GetBufferSizePrivateKey(&buffSizePrivKey2, pPrvKey2);
    if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }

    /* set public and private keys */
    sts = ippsRSA_SetPublicKey(bnN, bnE, pPubKey);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    sts = ippsRSA_SetPrivateKeyType1(bnN, bnD, pPrvKey);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;

    /* RSA signature and verification buffers */
    int buffSizeSignVerify = 0;
    sts = ippsRSA_GetBufferSizePublicKey(&buffSizeSignVerify, pPubKey);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;

    // private
    int buffSizePrivKey1 = 0;
    sts = ippsRSA_GetBufferSizePrivateKey(&buffSizePrivKey1, pPrvKey);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;

    /* resize buffer */
    total_size = IPP_MAX(IPP_MAX(buffSizeSignVerify, buffSizePrivKey1), buffSizePrivKey2) + IPPCP_RSA_ALIGNMENT;
    *pBufferSize = total_size;

    return IPPCP_ALGO_SELFTEST_OK;
}

IPPFUN(fips_test_status, fips_selftest_ippsRSASign_PSS_rmf,(Ipp8u *pBuffer, Ipp8u *pKeysBuffer))
{
    IppStatus sts = ippStsNoErr;
    fips_test_status test_result = IPPCP_ALGO_SELFTEST_OK;

    /* Internal memory allocation feature */
    int internalMemMgm = 0;
#if IPPCP_SELFTEST_USE_MALLOC
    if(pBuffer == NULL || pKeysBuffer == NULL) {
        internalMemMgm = 1;

        int keysBuffSize = 0;
        sts = fips_selftest_ippsRSASignVerify_PSS_rmf_get_size_keys(&keysBuffSize);
        if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }
        pKeysBuffer = malloc((size_t)keysBuffSize);

        int dataBuffSize = 0;
        sts = fips_selftest_ippsRSASignVerify_PSS_rmf_get_size(&dataBuffSize, pKeysBuffer);
        if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }
        pBuffer = malloc((size_t)dataBuffSize);
    }
#else
    IPP_BADARG_RET((NULL == pBuffer) || (NULL == pKeysBuffer), IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR);
#endif

    /* buffer for the generated signature */
    Ipp8u pOutSig[256] = {0};
    Ipp8u* pLocKeysBuffer = pKeysBuffer;

    /* Initialize BigNumber-s */
    int dByteSize;
    sts = ippsBigNumGetSize(IPPCP_PRIV_EXP_WORD_SIZE, &dByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_BN_ALIGNMENT));
    IppsBigNumState* bnD = (IppsBigNumState *)pLocKeysBuffer;
    pLocKeysBuffer += dByteSize;

    int eByteSize;
    sts = ippsBigNumGetSize(IPPCP_PUB_EXP_WORD_SIZE, &eByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_BN_ALIGNMENT));
    IppsBigNumState* bnE = (IppsBigNumState *)pLocKeysBuffer;
    pLocKeysBuffer += eByteSize;

    int nByteSize;
    sts = ippsBigNumGetSize(IPPCP_MODULUS_WORD_SIZE, &nByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_BN_ALIGNMENT));
    IppsBigNumState* bnN = (IppsBigNumState *)pLocKeysBuffer;
    pLocKeysBuffer += nByteSize;

    sts = ippcp_init_set_bn(bnD, IPPCP_PRIV_EXP_WORD_SIZE, ippBigNumPOS, (const Ipp32u *)pPrivExp, IPPCP_PRIV_EXP_WORD_SIZE);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    sts = ippcp_init_set_bn(bnE, IPPCP_PUB_EXP_WORD_SIZE,  ippBigNumPOS, (const Ipp32u *)pPubExp,  IPPCP_PUB_EXP_WORD_SIZE);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    sts = ippcp_init_set_bn(bnN, IPPCP_MODULUS_WORD_SIZE,  ippBigNumPOS, (const Ipp32u *)pModulus, IPPCP_MODULUS_WORD_SIZE);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }

    /* Initialize key pair */
    // private key
    int privKeyByteSize = 0;
    sts = ippsRSA_GetSizePrivateKeyType1(modulusBitSize, privExpBitSize, &privKeyByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_RSA_ALIGNMENT));
    IppsRSAPrivateKeyState* pPrvKey = (IppsRSAPrivateKeyState*)pLocKeysBuffer;
    sts = ippsRSA_InitPrivateKeyType1(modulusBitSize, privExpBitSize, pPrvKey, privKeyByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer += (privKeyByteSize);

    // public key
    int pubKeyByteSize = 0;
    sts = ippsRSA_GetSizePublicKey(modulusBitSize, pubExpBitSize, &pubKeyByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_RSA_ALIGNMENT));
    IppsRSAPublicKeyState* pPubKey = (IppsRSAPublicKeyState*)pLocKeysBuffer;
    sts = ippsRSA_InitPublicKey(modulusBitSize, pubExpBitSize, pPubKey, pubKeyByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }

    /* set public and private keys */
    sts = ippsRSA_SetPublicKey(bnN, bnE, pPubKey);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    sts = ippsRSA_SetPrivateKeyType1(bnN, bnD, pPrvKey);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }

    /* RSA Signature Generation */
    Ipp8u* pLocSignBuffer = (IPP_ALIGNED_PTR(pBuffer, IPPCP_RSA_ALIGNMENT));

    sts = ippsRSASign_PSS_rmf(pMsg, msgByteLen, pSalt, saltByteLen, pOutSig, pPrvKey,
                              pPubKey, ippsHashMethod_SHA256(), pLocSignBuffer);

    int sigFlagErr = ippcp_is_mem_eq(pSig, sizeof(pSig), pOutSig, sizeof(pSig));
    if(1 != sigFlagErr || sts != ippStsNoErr) {
        test_result = IPPCP_ALGO_SELFTEST_KAT_ERR;
    }

    MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
    return test_result;
}

IPPFUN(fips_test_status, fips_selftest_ippsRSAVerify_PSS_rmf,(Ipp8u *pBuffer, Ipp8u *pKeysBuffer))
{
    IppStatus sts = ippStsNoErr;
    fips_test_status test_result = IPPCP_ALGO_SELFTEST_OK;

    /* Internal memory allocation feature */
    int internalMemMgm = 0;
#if IPPCP_SELFTEST_USE_MALLOC
    if(pBuffer == NULL || pKeysBuffer == NULL) {
        internalMemMgm = 1;

        int keysBuffSize = 0;
        sts = fips_selftest_ippsRSASignVerify_PSS_rmf_get_size_keys(&keysBuffSize);
        if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }
        pKeysBuffer = malloc((size_t)keysBuffSize);

        int dataBuffSize = 0;
        sts = fips_selftest_ippsRSASignVerify_PSS_rmf_get_size(&dataBuffSize, pKeysBuffer);
        if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }
        pBuffer = malloc((size_t)dataBuffSize);
    }
#else
    IPP_BADARG_RET((NULL == pBuffer) || (NULL == pKeysBuffer), IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR);
#endif

    Ipp8u* pLocKeysBuffer = pKeysBuffer;

    /* Initialize BigNumber-s */
    int eByteSize;
    sts = ippsBigNumGetSize(IPPCP_PUB_EXP_WORD_SIZE, &eByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_BN_ALIGNMENT));
    IppsBigNumState* bnE = (IppsBigNumState *)pLocKeysBuffer;
    pLocKeysBuffer += eByteSize;

    int nByteSize;
    sts = ippsBigNumGetSize(IPPCP_MODULUS_WORD_SIZE, &nByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_BN_ALIGNMENT));
    IppsBigNumState* bnN = (IppsBigNumState *)pLocKeysBuffer;
    pLocKeysBuffer += nByteSize;

    sts = ippcp_init_set_bn(bnE, IPPCP_PUB_EXP_WORD_SIZE,  ippBigNumPOS, (const Ipp32u *)pPubExp,  IPPCP_PUB_EXP_WORD_SIZE);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    sts = ippcp_init_set_bn(bnN, IPPCP_MODULUS_WORD_SIZE,  ippBigNumPOS, (const Ipp32u *)pModulus, IPPCP_MODULUS_WORD_SIZE);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }

    /* Initialize and set public key */
    int pubKeyByteSize = 0;
    sts = ippsRSA_GetSizePublicKey(modulusBitSize, pubExpBitSize, &pubKeyByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_RSA_ALIGNMENT));
    IppsRSAPublicKeyState* pPubKey = (IppsRSAPublicKeyState*)pLocKeysBuffer;
    sts = ippsRSA_InitPublicKey(modulusBitSize, pubExpBitSize, pPubKey, pubKeyByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    sts = ippsRSA_SetPublicKey(bnN, bnE, pPubKey);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }

    Ipp8u* pLocVerifBuffer = (IPP_ALIGNED_PTR(pBuffer, IPPCP_RSA_ALIGNMENT));

    /* RSA Signature Verification */
    int isValid;
    sts = ippsRSAVerify_PSS_rmf(pMsg,msgByteLen, pSig, &isValid, pPubKey,
                                ippsHashMethod_SHA256(), pLocVerifBuffer);

    if(!isValid || sts != ippStsNoErr)  {
        test_result = IPPCP_ALGO_SELFTEST_KAT_ERR;
    }

    MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
    return test_result;
}

IPPFUN(fips_test_status, fips_selftest_ippsRSA_GenerateKeys,(Ipp8u *pBuffer, Ipp8u *pKeysBuffer))
{
    IppStatus sts = ippStsNoErr;
    fips_test_status test_result = IPPCP_ALGO_SELFTEST_OK;

    /* Internal memory allocation feature */
    int internalMemMgm = 0;
#if IPPCP_SELFTEST_USE_MALLOC
    if(pBuffer == NULL || pKeysBuffer == NULL) {
        internalMemMgm = 1;

        int keysBuffSize = 0;
        sts = fips_selftest_ippsRSASignVerify_PSS_rmf_get_size_keys(&keysBuffSize);
        if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }
        pKeysBuffer = malloc((size_t)keysBuffSize);

        int dataBuffSize = 0;
        sts = fips_selftest_ippsRSASignVerify_PSS_rmf_get_size(&dataBuffSize, pKeysBuffer);
        if (sts != ippStsNoErr) { return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR; }
        pBuffer = malloc((size_t)dataBuffSize);
    }
#else
    IPP_BADARG_RET((NULL == pBuffer) || (NULL == pKeysBuffer), IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR);
#endif

    /* buffer for the generated signature */
    Ipp8u pOutSig[256] = {0};
    Ipp8u* pLocKeysBuffer = pKeysBuffer;

    /* Initialize BigNumber-s */
    int dByteSize;
    sts = ippsBigNumGetSize(IPPCP_PRIV_EXP_WORD_SIZE, &dByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_BN_ALIGNMENT));
    IppsBigNumState* bnD = (IppsBigNumState *)pLocKeysBuffer;
    pLocKeysBuffer += dByteSize;

    int eByteSize;
    sts = ippsBigNumGetSize(IPPCP_PUB_EXP_WORD_SIZE, &eByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_BN_ALIGNMENT));
    IppsBigNumState* bnE = (IppsBigNumState *)pLocKeysBuffer;
    pLocKeysBuffer += eByteSize;

    int nByteSize;
    sts = ippsBigNumGetSize(IPPCP_MODULUS_WORD_SIZE, &nByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_BN_ALIGNMENT));
    IppsBigNumState* bnN = (IppsBigNumState *)pLocKeysBuffer;
    pLocKeysBuffer += nByteSize;

    sts = ippcp_init_set_bn(bnD, IPPCP_PRIV_EXP_WORD_SIZE, ippBigNumPOS, (const Ipp32u *)pPrivExp, IPPCP_PRIV_EXP_WORD_SIZE);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    sts = ippcp_init_set_bn(bnE, IPPCP_PUB_EXP_WORD_SIZE,  ippBigNumPOS, (const Ipp32u *)pPubExp,  IPPCP_PUB_EXP_WORD_SIZE);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    sts = ippcp_init_set_bn(bnN, IPPCP_MODULUS_WORD_SIZE,  ippBigNumPOS, (const Ipp32u *)pModulus, IPPCP_MODULUS_WORD_SIZE);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }

    // prime generator
    int size;
    sts = ippsPrimeGetSize(primeBitsize, &size);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    IppsPrimeState* pPrimeG = (IppsPrimeState*)(IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_GFP_ALIGNMENT));
    sts = ippsPrimeInit(primeBitsize, pPrimeG);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer += size;

    int privKey2ByteSize = 0;
    sts = ippsRSA_GetSizePrivateKeyType2(primeBitsize, privExpBitSize - primeBitsize, &privKey2ByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_RSA_ALIGNMENT));
    IppsRSAPrivateKeyState* pPrvKey2 = (IppsRSAPrivateKeyState*)pLocKeysBuffer;
    sts = ippsRSA_InitPrivateKeyType2(primeBitsize, privExpBitSize - primeBitsize, pPrvKey2, privKey2ByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer += (privKey2ByteSize);

    // initialize RNG
    int pRandSize;
    const int seedBitsize = 160;
    sts = ippsPRNGGetSize(&pRandSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    IppsPRNGState* pRand = (IppsPRNGState*)pLocKeysBuffer;
    sts = ippsPRNGInit(seedBitsize, pRand);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer += (pRandSize);

    // generate keys
    Ipp8u* pLocGenerateKeysBuffer = (IPP_ALIGNED_PTR(pBuffer, IPPCP_RSA_ALIGNMENT));
    sts = ippStsInsufficientEntropy;
    for(int loop_count = 0; loop_count < 100 && ippStsInsufficientEntropy == sts; ++loop_count) {
        sts = ippsRSA_GenerateKeys(bnE, bnN, bnE, bnD, pPrvKey2, pLocGenerateKeysBuffer, 0, pPrimeG, ippsPRNGen, pRand);
    }

    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }

    // public key
    int pubKeyByteSize = 0;
    sts = ippsRSA_GetSizePublicKey(modulusBitSize, pubExpBitSize, &pubKeyByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_RSA_ALIGNMENT));
    IppsRSAPublicKeyState* pPubKey = (IppsRSAPublicKeyState*)pLocKeysBuffer;
    sts = ippsRSA_InitPublicKey(modulusBitSize, pubExpBitSize, pPubKey, pubKeyByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }

    /* set public and private keys */
    sts = ippsRSA_SetPublicKey(bnN, bnE, pPubKey);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }

    /* RSA Signature Generation */
    Ipp8u* pLocSignBuffer = (IPP_ALIGNED_PTR(pBuffer, IPPCP_RSA_ALIGNMENT));
    sts = ippsRSASign_PSS_rmf(pMsg, msgByteLen, pSalt, saltByteLen, pOutSig, pPrvKey2,
                              pPubKey, ippsHashMethod_SHA256(), pLocSignBuffer);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }

    /* RSA Signature Verification */
    int isValid;
    Ipp8u* pLocVerifBuffer = (IPP_ALIGNED_PTR(pBuffer, IPPCP_RSA_ALIGNMENT));
    sts = ippsRSAVerify_PSS_rmf(pMsg,msgByteLen, pOutSig, &isValid, pPubKey,
                                ippsHashMethod_SHA256(), pLocVerifBuffer);

    if(!isValid || sts != ippStsNoErr) {
        test_result = IPPCP_ALGO_SELFTEST_KAT_ERR;
    }
    MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
    return test_result;
}

#endif // _IPP_DATA
#endif // IPPCP_FIPS_MODE
