/* Copyright (c) (2017,2019) Apple Inc. All rights reserved.
 *
 * corecrypto is licensed under Apple Inc.’s Internal Use License Agreement (which
 * is contained in the License.txt file distributed with corecrypto) and only to 
 * people who accept that license. IMPORTANT:  Any license rights granted to you by 
 * Apple Inc. (if any) are limited to internal use within your organization only on 
 * devices and computers you own or control, for the sole purpose of verifying the 
 * security characteristics and correct functioning of the Apple Software.  You may 
 * not, directly or indirectly, redistribute the Apple Software or any portions thereof.
 */
#include <corecrypto/cc_debug.h>
#include <corecrypto/ccrsa.h>
#include <corecrypto/ccsha2.h>

#include "fipspost.h"
#include "fipspost_priv.h"
#include "fipspost_post_rsa_sig.h"

// Test RSA Signature Creation and Verification
int fipspost_post_rsa_sig(uint32_t fips_mode)
{
    /* Sign / Verify */
    size_t nbits=2048;
    cc_size n = ccn_nof(nbits);
    ccrsa_full_ctx_decl(ccn_sizeof(nbits), full_key);
    ccrsa_ctx_n(full_key)=n;

    // Import the key
    if (0 != ccrsa_import_priv(full_key, fipspost_post_rsa_test_key_nbytes, fipspost_post_rsa_test_key))
    {
        failf("import");
        return CCPOST_GENERIC_FAILURE;
    }

    ccrsa_pub_ctx_t pub_key = ccrsa_ctx_public(full_key);

    const unsigned char msg[] = "\x70\x99\x2c\x9d\x95\xa4\x90\x8d\x2a\x94\xb3\xab\x9f\xa1\xcd\x64\x3f\x12\x0e\x32\x6f\x9d\x78\x08\xaf\x50\xca\xc4\x2c\x4b\x0b\x4e\xeb\x7f\x0d\x4d\xf3\x03\xa5\x68\xfb\xfb\x82\xb0\xf5\x83\x00\xd2\x53\x57\x64\x57\x21\xbb\x71\x86\x1c\xaf\x81\xb2\x7a\x56\x08\x2c\x80\xa1\x46\x49\x9f\xb4\xea\xb5\xbd\xe4\x49\x3f\x5d\x00\xf1\xa4\x37\xbb\xc3\x60\xdf\xcd\x80\x56\xfe\x6b\xe1\x0e\x60\x8a\xdb\x30\xb6\xc2\xf7\x65\x24\x28\xb8\xd3\x2d\x36\x29\x45\x98\x2a\x46\x58\x5d\x21\x02\xef\x79\x95\xa8\xba\x6e\x8a\xd8\xfd\x16\xbd\x7a\xe8\xf5\x3c\x3d\x7f\xcf\xba\x29\x0b\x57\xce\x7f\x8f\x09\xc8\x28\xd6\xf2\xd3\xce\x56\xf1\x31\xbd\x94\x61\xe5\x66\x7e\x5b\x73\xed\xac\x77\xf5\x04\xda\xc4\xf2\x02\xa9\x57\x0e\xb4\x51\x5b\x2b\xf5\x16\x40\x7d\xb8\x31\x51\x8d\xb8\xa2\x08\x3e\xc7\x01\xe8\xfd\x38\x7c\x43\x0b\xb1\xa7\x2d\xec\xa5\xb4\x9d\x42\x9c\xf9\xde\xb0\x9c\xc4\x51\x8d\xc5\xf5\x7c\x08\x9a\xa2\xd3\x42\x0e\x56\x7e\x73\x21\x02\xc2\xc9\x2b\x88\xa0\x7c\x69\xd7\x09\x17\x14\x0a\xb3\x82\x3c\x63\xf3\x12\xd3\xf1\x1f\xa8\x7b\xa2\x9d\xa3\xc7\x22\x4b\x4f\xb4\xbc";

    unsigned char *expected_signature;
    expected_signature = POST_FIPS_RESULT_STR("\x5e\xb1\xe4\xb3\x4e\xda\x48\x52\x70\x59\x57\xe4\x22\xe1\xaf\x21\xf0\x2d\x77\xe3\x73\xc9\xda\xdb\x69\x83\x31\x0d\x12\xe9\xbf\x40\x4c\x19\x37\xa0\xe7\x9d\x18\x5e\xfb\x08\x48\x58\x14\x4d\x0e\x7e\xcf\x6f\x7a\x53\x57\x71\xcd\x26\xd8\xee\xb2\xba\x6f\x71\xbc\xf0\x16\x80\xe1\x04\xa5\xf0\x4a\x74\x0b\xa4\xee\x5c\x9e\x3f\xef\x75\x1f\xcb\x87\x7c\xc2\x3d\xaa\x22\x48\xeb\xf1\x5f\xfb\x27\x88\x59\x00\x27\xb9\x5b\x31\x07\x0a\x79\x50\x8d\xe8\x68\x9d\xa6\x33\x67\x17\xc7\x94\xff\xb6\xcb\x82\x6d\xf0\x72\x0a\xb2\x05\x78\x9f\xdd\x84\xfe\xdd\xb9\xb9\x2c\xeb\x49\xcf\x24\xf6\x06\x57\x9c\x6e\xe7\x57\xde\x02\xd4\x2e\xc8\xfe\x48\xd0\xa7\xfb\xff\x18\xcc\x5a\x4e\x7e\xec\x17\x88\x9a\xcf\x94\x39\xb6\xdc\xe7\x48\xa5\x4c\xba\x24\xb8\xb5\xcd\x04\xbc\xb8\xb4\x36\xe1\x9c\x42\x33\x78\xb0\xcc\x98\xd4\x9b\xc8\xb3\x53\x8e\xf1\xa3\x1b\x43\xe4\x81\x5c\x82\x13\x01\xdc\xc3\x13\x51\x09\xd4\x1f\xa8\xb4\x2e\x26\x6c\x8e\x35\x62\x64\x2f\x10\x35\xef\x5f\x65\x40\x61\xfc\x4e\x52\x05\xe7\x38\xba\x92\x9e\x5f\xf0\xe3\x76\x1f\x36\xba\x42\x2d\xdb\x7b\xb6\xb1\x5c\x0b");

    // Use SHA256
    const struct ccdigest_info* di = ccsha256_di();
    unsigned char msg_digest[di->output_size];
    ccdigest(di, sizeof(msg)-1, msg, msg_digest); // size-1 to strip null byte

    uint8_t sig[(nbits+7)/8];
    size_t siglen=sizeof(sig);

    // Sign the digest
    if (0 != ccrsa_sign_pkcs1v15(full_key, di->oid, di->output_size, msg_digest,  &siglen, sig))
    {
        failf("ccrsa_sign_pkcs1v15");
        ccrsa_full_ctx_clear(ccn_sizeof(nbits), full_key);
        return CCPOST_GENERIC_FAILURE;
    }

    // Verify computed signature == expected signature
    if (0 != cc_cmp_safe(siglen, sig, expected_signature))
    {
        failf("sig != expected_signature");
        ccrsa_full_ctx_clear(ccn_sizeof(nbits), full_key);
        return CCPOST_KAT_FAILURE;
    }

    // Verify Signature
    bool ok;
    if (0 != ccrsa_verify_pkcs1v15(pub_key, ccoid_sha256, CCSHA256_OUTPUT_SIZE, msg_digest, siglen, sig, &ok))
    {
        failf("ccrsa_verify_pkcs1v15");
        ccrsa_full_ctx_clear(ccn_sizeof(nbits), full_key);
        return CCPOST_GENERIC_FAILURE;
    }

    ccrsa_full_ctx_clear(ccn_sizeof(nbits), full_key);
    if (!ok)
    {
        failf("ccrsa_verify_pkcs1v15");
        return CCPOST_KAT_FAILURE;
    }

    return 0;
}
