1 /*
2  * COPYRIGHT (c) International Business Machines Corp. 2017
3  *
4  * This program is provided under the terms of the Common Public License,
5  * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this
6  * software constitutes recipient's acceptance of CPL-1.0 terms which can be
7  * found in the file LICENSE file or at
8  * https://opensource.org/licenses/cpl1.0.php
9  */
10 
11 /*
12  * Testcase for
13  * C_GetOperationState / C_SetOperationState
14  */
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <memory.h>
20 #include <time.h>
21 
22 #include "pkcs11types.h"
23 #include "regress.h"
24 #include "common.c"
25 
26 
alloc_random_buf(CK_SESSION_HANDLE sess,CK_LONG nbytes)27 CK_BYTE_PTR alloc_random_buf(CK_SESSION_HANDLE sess, CK_LONG nbytes)
28 {
29     CK_RV rc;
30     CK_BYTE_PTR ptr = malloc(nbytes);
31     if (ptr == NULL) {
32         testcase_error("malloc(%lu) failed", nbytes);
33         return NULL;
34     }
35 
36     rc = funcs->C_GenerateRandom(sess, ptr, nbytes);
37     if (rc != CKR_OK) {
38         testcase_error("C_GenerateRandom() rc=%s", p11_get_ckr(rc));
39         free(ptr);
40         return NULL;
41     }
42 
43     return ptr;
44 }
45 
sess_opstate_funcs(int loops)46 int sess_opstate_funcs(int loops)
47 {
48     CK_SESSION_HANDLE s1, s2;
49     CK_SLOT_ID slot_id = SLOT_ID;
50     CK_ULONG flags;
51     CK_RV rc;
52     unsigned int i;
53     int counter, rbytes;
54     CK_BYTE *rdata = NULL;
55     CK_MECHANISM mech1 = { CKM_SHA256, 0, 0 };
56     CK_MECHANISM mech2 = { CKM_SHA_1, 0, 0 };
57     CK_ULONG r1hlen, r2hlen, hlen;
58     CK_BYTE r1hash[32], r2hash[32], hash[32];
59     CK_ULONG opstatelen;
60     CK_BYTE *opstate = NULL;
61 
62     // open 2 sessions
63     flags = CKF_SERIAL_SESSION | CKF_RW_SESSION;
64     rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &s1);
65     if (rc != CKR_OK) {
66         testcase_error("C_OpenSession() rc=%s", p11_get_ckr(rc));
67         goto out;
68     }
69 
70     rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &s2);
71     if (rc != CKR_OK) {
72         testcase_error("C_OpenSession() rc=%s", p11_get_ckr(rc));
73         goto out;
74     }
75 
76     // init digest for both sessions
77     rc = funcs->C_DigestInit(s1, &mech1);
78     if (rc != CKR_OK) {
79         testcase_error("C_DigestInit rc=%s", p11_get_ckr(rc));
80         goto out;
81     }
82 
83     rc = funcs->C_DigestInit(s2, &mech1);
84     if (rc != CKR_OK) {
85         testcase_error("C_DigestInit rc=%s", p11_get_ckr(rc));
86         goto out;
87     }
88 
89     // now loop over some digest updates
90     for (counter = 0; counter < loops; counter++) {
91         // create some random data
92         rbytes = random() % sizeof(rdata);
93         rdata = alloc_random_buf(s1, rbytes);
94         if (!rdata)
95             goto out;
96 
97         // digest update on session 1
98         rc = funcs->C_DigestUpdate(s1, rdata, rbytes);
99         if (rc != CKR_OK) {
100             testcase_error("C_DigestUpdate rc=%s", p11_get_ckr(rc));
101             goto out;
102         }
103 
104         // restore op state on session 2
105         if (opstate != NULL) {
106             rc = funcs->C_SetOperationState(s2, opstate, opstatelen, 0, 0);
107             if (rc != CKR_OK) {
108                 testcase_error("C_SetOperationState rc=%s", p11_get_ckr(rc));
109                 goto out;
110             }
111             free(opstate);
112             opstate = NULL;
113         }
114 
115         // digest update on session 2
116         rc = funcs->C_DigestUpdate(s2, rdata, rbytes);
117         if (rc != CKR_OK) {
118             testcase_error("C_DigestUpdate rc=%s", p11_get_ckr(rc));
119             goto out;
120         }
121 
122         // fetch op state on session 2
123         opstatelen = 0;
124         rc = funcs->C_GetOperationState(s2, NULL, &opstatelen);
125         if (rc != CKR_OK) {
126             testcase_error("C_GetOperationState rc=%s", p11_get_ckr(rc));
127             goto out;
128         }
129 
130         opstate = malloc(opstatelen);
131         if (opstate == NULL) {
132             testcase_error("malloc(%lu) failed", opstatelen);
133             goto out;
134         }
135 
136         rc = funcs->C_GetOperationState(s2, opstate, &opstatelen);
137         if (rc != CKR_OK) {
138             testcase_error("C_GetOperationState rc=%s", p11_get_ckr(rc));
139             goto out;
140         }
141 
142         free(rdata);
143         rdata = NULL;
144 
145         // now do something different on session 2, but first
146         // we have to wipe out the started digest operation
147         hlen = sizeof(hash);
148         rc = funcs->C_DigestFinal(s2, hash, &hlen);
149         if (rc != CKR_OK) {
150             testcase_error("C_DigestFinal rc=%s", p11_get_ckr(rc));
151             goto out;
152         }
153 
154         // so now let's do a digest init/update/finish
155         // to randomize the memory a little
156         rc = funcs->C_DigestInit(s2, &mech2);
157         if (rc != CKR_OK) {
158             testcase_error("C_DigestInit rc=%s", p11_get_ckr(rc));
159             goto out;
160         }
161 
162         for (i = 0; i < (unsigned int)loops; i++) {
163             rbytes = random() % sizeof(rdata);
164             rdata = alloc_random_buf(s1, rbytes);
165             if (!rdata)
166                 goto out;
167 
168             rc = funcs->C_DigestUpdate(s2, rdata, rbytes);
169             if (rc != CKR_OK) {
170                 testcase_error("C_DigestUpdate rc=%s", p11_get_ckr(rc));
171                 goto out;
172             }
173             free(rdata);
174             rdata = NULL;
175         }
176         hlen = sizeof(hash);
177 
178         rc = funcs->C_DigestFinal(s2, hash, &hlen);
179         if (rc != CKR_OK) {
180             testcase_error("C_DigestFinal rc=%s", p11_get_ckr(rc));
181             goto out;
182         }
183     }
184 
185     // restore op state on session 2
186     rc = funcs->C_SetOperationState(s2, opstate, opstatelen, 0, 0);
187     if (rc != CKR_OK) {
188         testcase_error("C_SetOperationState rc=%s", p11_get_ckr(rc));
189         goto out;
190     }
191 
192     // digest finish
193     r1hlen = sizeof(r1hash);
194     rc = funcs->C_DigestFinal(s1, r1hash, &r1hlen);
195     if (rc != CKR_OK) {
196         testcase_error("C_DigestFinal rc=%s", p11_get_ckr(rc));
197         goto out;
198     }
199 
200     r2hlen = sizeof(r2hash);
201     rc = funcs->C_DigestFinal(s2, r2hash, &r2hlen);
202     if (rc != CKR_OK) {
203         testcase_error("C_DigestFinal rc=%s", p11_get_ckr(rc));
204         goto out;
205     }
206 
207     // check both hashes
208     if (r1hlen != r2hlen) {
209         testcase_fail("hash length differ");
210         goto out;
211     }
212     if (memcmp(r1hash, r2hash, r1hlen) != 0) {
213         testcase_fail("hash values differs");
214         goto out;
215     }
216 
217     testcase_pass("Get/SetOperationState digest test");
218 
219 out:
220     if (opstate)
221         free(opstate);
222     if (rdata)
223         free(rdata);
224     funcs->C_CloseAllSessions(slot_id);
225 
226     return rc;
227 }
228 
main(int argc,char ** argv)229 int main(int argc, char **argv)
230 {
231     CK_C_INITIALIZE_ARGS cinit_args;
232     int rc, i, j, loops = 0;
233     CK_RV rv;
234 
235     SLOT_ID = 0;
236     no_init = FALSE;
237 
238     srandom(time(0));
239 
240     for (i = 0; i < argc; i++) {
241         if (strncmp(argv[i], "loops=", 6) == 0) {
242             sscanf(argv[i] + 6, "%i", &loops);
243             for (j = i; j < argc; j++)
244                 argv[j] = argv[j + 1];
245             argc--;
246         }
247     }
248 
249     if (loops < 1)
250         loops = 100;
251 
252     rc = do_ParseArgs(argc, argv);
253     if (rc != 1)
254         return rc;
255 
256     printf("Using slot #%lu...\n\n", SLOT_ID);
257     printf("With option: no_init: %d\n", no_init);
258     printf("Running %d loops...\n", loops);
259 
260     rc = do_GetFunctionList();
261     if (!rc) {
262         PRINT_ERR("ERROR do_GetFunctionList() Failed , rc = 0x%0x\n", rc);
263         return rc;
264     }
265 
266     memset(&cinit_args, 0x0, sizeof(cinit_args));
267     cinit_args.flags = CKF_OS_LOCKING_OK;
268 
269     funcs->C_Initialize(&cinit_args);
270 
271     {
272         CK_SESSION_HANDLE hsess = 0;
273 
274         rc = funcs->C_GetFunctionStatus(hsess);
275         if (rc != CKR_FUNCTION_NOT_PARALLEL)
276             return rc;
277 
278         rc = funcs->C_CancelFunction(hsess);
279         if (rc != CKR_FUNCTION_NOT_PARALLEL)
280             return rc;
281     }
282 
283     rv = sess_opstate_funcs(loops);
284 
285     /* make sure we return non-zero if rv is non-zero */
286     return ((rv == 0) || (rv % 256) ? (int)rv : -1);
287 }
288