#include "test_common.h"

CK_RV test_crypto();
CK_RV test_keypair_import(CK_SESSION_HANDLE sess);

int main(int argc, char *argv[])
{
    CK_RV rc = CKR_OK;

    rc = test_main(argc, argv);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "test_main failed: 0x%lx(%s)\n",
                rc, get_ckr_name(rc));
        return rc;
    }
    rc = test_crypto();
    if (rc != CKR_OK)
    {
        fprintf(stderr, "test_crypto failed: 0x%lx(%s)\n",
                rc, get_ckr_name(rc));
        return rc;
    }
    return CKR_OK;
}

CK_RV test_crypto()
{
    CK_RV             rc, ret;
    CK_SESSION_HANDLE hSession;

    rc = funcs->C_OpenSession(SlotId,
                              CKF_RW_SESSION | CKF_SERIAL_SESSION,
                              NULL_PTR, NULL_PTR, &hSession);
    if (rc != CKR_OK)
    {
        fprintf(stderr,
                "ERROR call to C_OpenSession failed, rc = 0x%lx(%s)\n",
                rc, get_ckr_name(rc));
        goto out;
    }
    fprintf(stderr, "C_OpenSession success\n");

    // log in as normal user
    rc = funcs->C_Login(hSession, CKU_USER, user_pin, (CK_ULONG)strlen((char *)user_pin));
    if (rc != CKR_OK)
    {
        fprintf(stderr,
                "ERROR call to C_Login failed, rc = 0x%lx(%s)\n",
                rc, get_ckr_name(rc));
        goto out_close;
    }
    fprintf(stderr, "C_Login success\n");
    fprintf(stderr,
        "\n==================== keypair import test ==================\n");
    rc = test_keypair_import(hSession);
    if (rc != CKR_OK)
    {
        fprintf(stderr,
            "ERROR keypair import failed, rc = 0x%lx(%s)\n",
            rc, get_ckr_name(rc));
    }
    else
    {
            fprintf(stderr, "keypair import test SUCCESS.\n");
    }
 out_close:
    if ((ret = funcs->C_CloseSession(hSession)) != CKR_OK)
    {
        rc = ret;
        fprintf(stderr,
                "Error: C_CloseSession failed with 0x%lx(%s)\n", rc, get_ckr_name(rc));
    }
    else
    {
        fprintf(stderr, "C_CloseSession success\n");
    }

 out:
    return rc;
}

CK_RV test_keypair_import(CK_SESSION_HANDLE sess)
{
    CK_RV                  rc = CKR_OK;
    CK_OBJECT_HANDLE       pub_key            = CK_INVALID_HANDLE;
    CK_OBJECT_HANDLE       priv_key           = CK_INVALID_HANDLE;

    static CK_BBOOL        ltrue       = CK_TRUE;
//    static CK_BBOOL        lfalse      = CK_FALSE;
    static CK_OBJECT_CLASS oclass_pub  = CKO_PUBLIC_KEY;
    static CK_OBJECT_CLASS oclass_priv = CKO_PRIVATE_KEY;
    static CK_KEY_TYPE     key_type    = CKK_GOSTR3410;

    static CK_BYTE         gostR3410params[] = {
        0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x24, 0x00
    };
    static CK_BYTE         gostR3411params[] = {
        0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01
    };
	static CK_BYTE         gost28147params[] = {
		0x06, 0x09, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x02, 0x05, 0x01, 0x01
	};

    static CK_BYTE         priv_key_value[] = {
		0xD0, 0xCA, 0x4D, 0xFE, 0xA0, 0x38, 0x11, 0xAB, 
		0xEC, 0x1E, 0xED, 0x1F, 0xB6, 0x39, 0x7B, 0xBA, 
		0xCC, 0x13, 0x11, 0x5D, 0xE1, 0xD4, 0x4C, 0xC2, 
		0x7A, 0x9D, 0x8A, 0xCA, 0xB8, 0x13, 0x83, 0xB4
    };
	static CK_BYTE         pub_key_value[] = {
		0xD8, 0x2D, 0xCF, 0xD9, 0x26, 0x35, 0x27, 0xE0, 
		0x25, 0x05, 0xAE, 0x5B, 0xB3, 0xC7, 0x53, 0xF5, 
		0x7B, 0x82, 0x3C, 0x6E, 0x08, 0x1D, 0x47, 0xCE, 
		0x8E, 0x3D, 0x0F, 0x83, 0x41, 0x99, 0xB7, 0x2F, 
		0xF0, 0x17, 0x7C, 0x0C, 0x0B, 0x3C, 0x31, 0x56, 
		0xDE, 0x04, 0x13, 0xA3, 0x8A, 0x69, 0xF6, 0xA2, 
		0xEF, 0x31, 0xB8, 0xC9, 0x00, 0xF7, 0x55, 0x61, 
		0x01, 0x47, 0xFF, 0xAB, 0x8F, 0xA1, 0x2F, 0xBD
	};

    static CK_UTF8CHAR     *label         = (CK_UTF8CHAR *)"Yet Another Keypair";
	CK_ULONG label_len = (CK_ULONG)strlen((char *)label) + 1;
    CK_ATTRIBUTE           pub_template[] = {
		{ CKA_CLASS,			&oclass_pub,		sizeof(oclass_pub)		},
		{ CKA_KEY_TYPE,			&key_type,			sizeof(key_type)		},
        { CKA_TOKEN,			&ltrue,				sizeof(ltrue)           },
        { CKA_GOSTR3410PARAMS,	gostR3410params,	sizeof(gostR3410params) },
        { CKA_GOSTR3411PARAMS,	gostR3411params,	sizeof(gostR3411params) },
		{ CKA_GOST28147_PARAMS, gost28147params,	sizeof(gost28147params)	},
        { CKA_VERIFY,			&ltrue,				sizeof(CK_BBOOL)        },
        { CKA_ENCRYPT,			&ltrue,				sizeof(CK_BBOOL)        },
		{ CKA_LABEL,			NULL,				0	},	// 8
        { CKA_VALUE,			pub_key_value,		sizeof(pub_key_value)	},
    };
	CK_ATTRIBUTE           priv_template[] = {
		{ CKA_CLASS,			&oclass_priv,		sizeof(oclass_priv)		},
		{ CKA_KEY_TYPE,			&key_type,			sizeof(key_type)		},
        { CKA_TOKEN,			&ltrue,				sizeof(ltrue)			},
        { CKA_PRIVATE,			&ltrue,				sizeof(ltrue)			},
        { CKA_GOSTR3410PARAMS,	gostR3410params,	sizeof(gostR3410params) },
        { CKA_GOSTR3411PARAMS,	gostR3411params,	sizeof(gostR3411params) },
		{ CKA_GOST28147_PARAMS, gost28147params,	sizeof(gost28147params)	},
        { CKA_SIGN,				&ltrue,				sizeof(CK_BBOOL)		},
		{ CKA_DERIVE,           &ltrue,				sizeof(CK_BBOOL)		},
        { CKA_DECRYPT,			&ltrue,				sizeof(CK_BBOOL)		},
		{ CKA_LABEL,			NULL,				0			},	// 10
        { CKA_VALUE,			priv_key_value,		sizeof(priv_key_value)	},
    };

	pub_template[8].pValue = label;
	pub_template[8].ulValueLen = label_len;
	priv_template[10].pValue = label;
	priv_template[10].ulValueLen = label_len;

    rc = funcs->C_CreateObject(sess, 
        priv_template, sizeof(priv_template) / sizeof(CK_ATTRIBUTE),
        &priv_key);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "Create private key failed: 0x%lx(%s)\n",
                rc, get_ckr_name(rc));
        return rc;
    }
    fprintf(stderr, "C_CreateObject private key OK\n");

    rc = funcs->C_CreateObject(sess, 
        pub_template, sizeof(pub_template) / sizeof(CK_ATTRIBUTE),
        &pub_key);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "Create public key failed: 0x%lx(%s)\n",
                rc, get_ckr_name(rc));
        return rc;
    }
    fprintf(stderr, "C_CreateObject public key OK\n");

    rc = funcs->C_DestroyObject(sess, priv_key);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_DestroyObject failed: 0x%lx(%s)\n",
                rc, get_ckr_name(rc));
        return rc;
    }
    rc = funcs->C_DestroyObject(sess, pub_key);
    if (rc != CKR_OK)
    {
        fprintf(stderr, "C_DestroyObject failed: 0x%lx(%s)\n",
                rc, get_ckr_name(rc));
        return rc;
    }

    return rc;
}



