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