/*
* COPYRIGHT (c) International Business Machines Corp. 2017
*
* This program is provided under the terms of the Common Public License,
* version 1.0 (CPL-1.0). Any use, reproduction or distribution for this
* software constitutes recipient's acceptance of CPL-1.0 terms which can be
* found in the file LICENSE file or at
* https://opensource.org/licenses/cpl1.0.php
*/
/*
* Testcase for
* C_GetOperationState / C_SetOperationState
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <time.h>
#include "pkcs11types.h"
#include "regress.h"
#include "common.c"
CK_BYTE_PTR alloc_random_buf(CK_SESSION_HANDLE sess, CK_LONG nbytes)
{
CK_RV rc;
CK_BYTE_PTR ptr = malloc(nbytes);
if (ptr == NULL) {
testcase_error("malloc(%lu) failed", nbytes);
return NULL;
}
rc = funcs->C_GenerateRandom(sess, ptr, nbytes);
if (rc != CKR_OK) {
testcase_error("C_GenerateRandom() rc=%s", p11_get_ckr(rc));
free(ptr);
return NULL;
}
return ptr;
}
int sess_opstate_funcs(int loops)
{
CK_SESSION_HANDLE s1, s2;
CK_SLOT_ID slot_id = SLOT_ID;
CK_ULONG flags;
CK_RV rc;
unsigned int i;
int counter, rbytes;
CK_BYTE *rdata = NULL;
CK_MECHANISM mech1 = { CKM_SHA256, 0, 0 };
CK_MECHANISM mech2 = { CKM_SHA_1, 0, 0 };
CK_ULONG r1hlen, r2hlen, hlen;
CK_BYTE r1hash[32], r2hash[32], hash[32];
CK_ULONG opstatelen;
CK_BYTE *opstate = NULL;
// open 2 sessions
flags = CKF_SERIAL_SESSION | CKF_RW_SESSION;
rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &s1);
if (rc != CKR_OK) {
testcase_error("C_OpenSession() rc=%s", p11_get_ckr(rc));
goto out;
}
rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &s2);
if (rc != CKR_OK) {
testcase_error("C_OpenSession() rc=%s", p11_get_ckr(rc));
goto out;
}
// init digest for both sessions
rc = funcs->C_DigestInit(s1, &mech1);
if (rc != CKR_OK) {
testcase_error("C_DigestInit rc=%s", p11_get_ckr(rc));
goto out;
}
rc = funcs->C_DigestInit(s2, &mech1);
if (rc != CKR_OK) {
testcase_error("C_DigestInit rc=%s", p11_get_ckr(rc));
goto out;
}
// now loop over some digest updates
for (counter = 0; counter < loops; counter++) {
// create some random data
rbytes = random() % sizeof(rdata);
rdata = alloc_random_buf(s1, rbytes);
if (!rdata)
goto out;
// digest update on session 1
rc = funcs->C_DigestUpdate(s1, rdata, rbytes);
if (rc != CKR_OK) {
testcase_error("C_DigestUpdate rc=%s", p11_get_ckr(rc));
goto out;
}
// restore op state on session 2
if (opstate != NULL) {
rc = funcs->C_SetOperationState(s2, opstate, opstatelen, 0, 0);
if (rc != CKR_OK) {
testcase_error("C_SetOperationState rc=%s", p11_get_ckr(rc));
goto out;
}
free(opstate);
opstate = NULL;
}
// digest update on session 2
rc = funcs->C_DigestUpdate(s2, rdata, rbytes);
if (rc != CKR_OK) {
testcase_error("C_DigestUpdate rc=%s", p11_get_ckr(rc));
goto out;
}
// fetch op state on session 2
opstatelen = 0;
rc = funcs->C_GetOperationState(s2, NULL, &opstatelen);
if (rc != CKR_OK) {
testcase_error("C_GetOperationState rc=%s", p11_get_ckr(rc));
goto out;
}
opstate = malloc(opstatelen);
if (opstate == NULL) {
testcase_error("malloc(%lu) failed", opstatelen);
goto out;
}
rc = funcs->C_GetOperationState(s2, opstate, &opstatelen);
if (rc != CKR_OK) {
testcase_error("C_GetOperationState rc=%s", p11_get_ckr(rc));
goto out;
}
free(rdata);
rdata = NULL;
// now do something different on session 2, but first
// we have to wipe out the started digest operation
hlen = sizeof(hash);
rc = funcs->C_DigestFinal(s2, hash, &hlen);
if (rc != CKR_OK) {
testcase_error("C_DigestFinal rc=%s", p11_get_ckr(rc));
goto out;
}
// so now let's do a digest init/update/finish
// to randomize the memory a little
rc = funcs->C_DigestInit(s2, &mech2);
if (rc != CKR_OK) {
testcase_error("C_DigestInit rc=%s", p11_get_ckr(rc));
goto out;
}
for (i = 0; i < (unsigned int)loops; i++) {
rbytes = random() % sizeof(rdata);
rdata = alloc_random_buf(s1, rbytes);
if (!rdata)
goto out;
rc = funcs->C_DigestUpdate(s2, rdata, rbytes);
if (rc != CKR_OK) {
testcase_error("C_DigestUpdate rc=%s", p11_get_ckr(rc));
goto out;
}
free(rdata);
rdata = NULL;
}
hlen = sizeof(hash);
rc = funcs->C_DigestFinal(s2, hash, &hlen);
if (rc != CKR_OK) {
testcase_error("C_DigestFinal rc=%s", p11_get_ckr(rc));
goto out;
}
}
// restore op state on session 2
rc = funcs->C_SetOperationState(s2, opstate, opstatelen, 0, 0);
if (rc != CKR_OK) {
testcase_error("C_SetOperationState rc=%s", p11_get_ckr(rc));
goto out;
}
// digest finish
r1hlen = sizeof(r1hash);
rc = funcs->C_DigestFinal(s1, r1hash, &r1hlen);
if (rc != CKR_OK) {
testcase_error("C_DigestFinal rc=%s", p11_get_ckr(rc));
goto out;
}
r2hlen = sizeof(r2hash);
rc = funcs->C_DigestFinal(s2, r2hash, &r2hlen);
if (rc != CKR_OK) {
testcase_error("C_DigestFinal rc=%s", p11_get_ckr(rc));
goto out;
}
// check both hashes
if (r1hlen != r2hlen) {
testcase_fail("hash length differ");
goto out;
}
if (memcmp(r1hash, r2hash, r1hlen) != 0) {
testcase_fail("hash values differs");
goto out;
}
testcase_pass("Get/SetOperationState digest test");
out:
if (opstate)
free(opstate);
if (rdata)
free(rdata);
funcs->C_CloseAllSessions(slot_id);
return rc;
}
int main(int argc, char **argv)
{
CK_C_INITIALIZE_ARGS cinit_args;
int rc, i, j, loops = 0;
CK_RV rv;
SLOT_ID = 0;
no_init = FALSE;
srandom(time(0));
for (i = 0; i < argc; i++) {
if (strncmp(argv[i], "loops=", 6) == 0) {
sscanf(argv[i] + 6, "%i", &loops);
for (j = i; j < argc; j++)
argv[j] = argv[j + 1];
argc--;
}
}
if (loops < 1)
loops = 100;
rc = do_ParseArgs(argc, argv);
if (rc != 1)
return rc;
printf("Using slot #%lu...\n\n", SLOT_ID);
printf("With option: no_init: %d\n", no_init);
printf("Running %d loops...\n", loops);
rc = do_GetFunctionList();
if (!rc) {
PRINT_ERR("ERROR do_GetFunctionList() Failed , rc = 0x%0x\n", rc);
return rc;
}
memset(&cinit_args, 0x0, sizeof(cinit_args));
cinit_args.flags = CKF_OS_LOCKING_OK;
funcs->C_Initialize(&cinit_args);
{
CK_SESSION_HANDLE hsess = 0;
rc = funcs->C_GetFunctionStatus(hsess);
if (rc != CKR_FUNCTION_NOT_PARALLEL)
return rc;
rc = funcs->C_CancelFunction(hsess);
if (rc != CKR_FUNCTION_NOT_PARALLEL)
return rc;
}
rv = sess_opstate_funcs(loops);
/* make sure we return non-zero if rv is non-zero */
return ((rv == 0) || (rv % 256) ? (int)rv : -1);
}