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