1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * SPDX-License-Identifier: MPL-2.0
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0.  If a copy of the MPL was not distributed with this
8  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 /*
15  * Portions copyright (c) 2008 Nominet UK.  All rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  * 1. Redistributions of source code must retain the above copyright
21  *    notice, this list of conditions and the following disclaimer.
22  * 2. Redistributions in binary form must reproduce the above copyright
23  *    notice, this list of conditions and the following disclaimer in the
24  *    documentation and/or other materials provided with the distribution.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 /* create [-m module] [-s $slot] [-p pin] [-t] [-n count] */
39 
40 /*! \file */
41 
42 #include <inttypes.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <time.h>
47 #include <unistd.h>
48 
49 #include <isc/commandline.h>
50 #include <isc/print.h>
51 #include <isc/result.h>
52 #include <isc/types.h>
53 #include <isc/util.h>
54 
55 #include <pk11/pk11.h>
56 #include <pk11/result.h>
57 
58 #ifndef HAVE_CLOCK_GETTIME
59 
60 #include <sys/time.h>
61 
62 #ifndef CLOCK_REALTIME
63 #define CLOCK_REALTIME 0
64 #endif /* ifndef CLOCK_REALTIME */
65 
66 static int
67 clock_gettime(int32_t id, struct timespec *tp);
68 
69 static int
clock_gettime(int32_t id,struct timespec * tp)70 clock_gettime(int32_t id, struct timespec *tp) {
71 	struct timeval tv;
72 	int result;
73 
74 	UNUSED(id);
75 
76 	result = gettimeofday(&tv, NULL);
77 	if (result == 0) {
78 		tp->tv_sec = tv.tv_sec;
79 		tp->tv_nsec = (long)tv.tv_usec * 1000;
80 	}
81 	return (result);
82 }
83 #endif /* ifndef HAVE_CLOCK_GETTIME */
84 
85 CK_BYTE buf[1024];
86 char label[16];
87 
88 static CK_BBOOL truevalue = TRUE;
89 static CK_BBOOL falsevalue = FALSE;
90 
91 int
main(int argc,char * argv[])92 main(int argc, char *argv[]) {
93 	isc_result_t result;
94 	CK_RV rv;
95 	CK_SLOT_ID slot = 0;
96 	CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
97 	CK_OBJECT_HANDLE *hKey;
98 	CK_OBJECT_CLASS kClass = CKO_DATA;
99 	CK_ULONG len = sizeof(buf);
100 	CK_ATTRIBUTE kTemplate[] = {
101 		{ CKA_CLASS, &kClass, (CK_ULONG)sizeof(kClass) },
102 		{ CKA_TOKEN, &falsevalue, (CK_ULONG)sizeof(falsevalue) },
103 		{ CKA_PRIVATE, &falsevalue, (CK_ULONG)sizeof(falsevalue) },
104 		{ CKA_LABEL, (CK_BYTE_PTR)label, (CK_ULONG)sizeof(label) },
105 		{ CKA_VALUE, buf, (CK_ULONG)sizeof(buf) }
106 	};
107 	pk11_context_t pctx;
108 	char *lib_name = NULL;
109 	char *pin = NULL;
110 	int error = 0;
111 	int c, errflg = 0;
112 	int ontoken = 0;
113 	unsigned int count = 1000;
114 	unsigned int i;
115 	struct timespec starttime;
116 	struct timespec endtime;
117 
118 	while ((c = isc_commandline_parse(argc, argv, ":m:s:p:tn:")) != -1) {
119 		switch (c) {
120 		case 'm':
121 			lib_name = isc_commandline_argument;
122 			break;
123 		case 's':
124 			slot = atoi(isc_commandline_argument);
125 			break;
126 		case 't':
127 			ontoken = 1;
128 			break;
129 		case 'p':
130 			pin = isc_commandline_argument;
131 			break;
132 		case 'n':
133 			count = atoi(isc_commandline_argument);
134 			break;
135 		case ':':
136 			fprintf(stderr, "Option -%c requires an operand\n",
137 				isc_commandline_option);
138 			errflg++;
139 			break;
140 		case '?':
141 		default:
142 			fprintf(stderr, "Unrecognised option: -%c\n",
143 				isc_commandline_option);
144 			errflg++;
145 		}
146 	}
147 
148 	if (errflg) {
149 		fprintf(stderr, "Usage:\n");
150 		fprintf(stderr, "\tcreate [-m module] [-s slot] [-t] [-n "
151 				"count]\n");
152 		exit(1);
153 	}
154 
155 	pk11_result_register();
156 
157 	/* Allocate handles */
158 	hKey = (CK_SESSION_HANDLE *)malloc(count * sizeof(CK_SESSION_HANDLE));
159 	if (hKey == NULL) {
160 		perror("malloc");
161 		exit(1);
162 	}
163 	for (i = 0; i < count; i++)
164 		hKey[i] = CK_INVALID_HANDLE;
165 
166 	/* Initialize the CRYPTOKI library */
167 	if (lib_name != NULL) {
168 		pk11_set_lib_name(lib_name);
169 	}
170 
171 	if (pin == NULL) {
172 		pin = getpass("Enter Pin: ");
173 	}
174 
175 	result = pk11_get_session(&pctx, OP_ANY, true, true, true,
176 				  (const char *)pin, slot);
177 	if ((result != ISC_R_SUCCESS) && (result != PK11_R_NORANDOMSERVICE) &&
178 	    (result != PK11_R_NODIGESTSERVICE) &&
179 	    (result != PK11_R_NOAESSERVICE))
180 	{
181 		fprintf(stderr, "Error initializing PKCS#11: %s\n",
182 			isc_result_totext(result));
183 		exit(1);
184 	}
185 
186 	if (pin != NULL) {
187 		memset(pin, 0, strlen((char *)pin));
188 	}
189 
190 	hSession = pctx.session;
191 
192 	/* Randomize the buffer */
193 	rv = pkcs_C_GenerateRandom(hSession, buf, len);
194 	if (rv != CKR_OK) {
195 		fprintf(stderr, "C_GenerateRandom: Error = 0x%.8lX\n", rv);
196 		goto exit_objects;
197 	}
198 
199 	if (ontoken) {
200 		kTemplate[1].pValue = &truevalue;
201 	}
202 
203 	if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) {
204 		perror("clock_gettime(start)");
205 		goto exit_objects;
206 	}
207 
208 	for (i = 0; i < count; i++) {
209 		(void)snprintf(label, sizeof(label), "obj%u", i);
210 		kTemplate[3].ulValueLen = strlen(label);
211 		rv = pkcs_C_CreateObject(hSession, kTemplate, 5, &hKey[i]);
212 		if (rv != CKR_OK) {
213 			fprintf(stderr, "C_CreateObject[%u]: Error = 0x%.8lX\n",
214 				i, rv);
215 			error = 1;
216 			if (i == 0) {
217 				goto exit_objects;
218 			}
219 			break;
220 		}
221 	}
222 
223 	if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) {
224 		perror("clock_gettime(end)");
225 		goto exit_objects;
226 	}
227 
228 	endtime.tv_sec -= starttime.tv_sec;
229 	endtime.tv_nsec -= starttime.tv_nsec;
230 	while (endtime.tv_nsec < 0) {
231 		endtime.tv_sec -= 1;
232 		endtime.tv_nsec += 1000000000;
233 	}
234 	printf("%u created objects in %ld.%09lds\n", i, endtime.tv_sec,
235 	       endtime.tv_nsec);
236 	if (i > 0) {
237 		printf("%g created objects/s\n",
238 		       1024 * i /
239 			       ((double)endtime.tv_sec +
240 				(double)endtime.tv_nsec / 1000000000.));
241 	}
242 
243 exit_objects:
244 	for (i = 0; i < count; i++) {
245 		/* Destroy objects */
246 		if (hKey[i] == CK_INVALID_HANDLE) {
247 			continue;
248 		}
249 		rv = pkcs_C_DestroyObject(hSession, hKey[i]);
250 		if ((rv != CKR_OK) && !errflg) {
251 			fprintf(stderr,
252 				"C_DestroyObject[%u]: Error = 0x%.8lX\n", i,
253 				rv);
254 			errflg = 1;
255 		}
256 	}
257 
258 	free(hKey);
259 	pk11_return_session(&pctx);
260 	(void)pk11_finalize();
261 
262 	exit(error);
263 }
264