Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / lib / isc / pk11.c
blobfbd49813792d643b7a152d97820ad45fc0219474
1 /* $NetBSD: pk11.c,v 1.1.1.5 2015/07/08 15:38:05 christos Exp $ */
3 /*
4 * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
20 * Portions copyright (c) 2008 Nominet UK. All rights reserved.
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the above copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
31 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
32 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
33 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
34 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
35 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
40 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
45 * Use is subject to license terms.
49 * This product includes software developed by the OpenSSL Project for
50 * use in the OpenSSL Toolkit (http://www.openssl.org/).
52 * This project also referenced hw_pkcs11-0.9.7b.patch written by
53 * Afchine Madjlessi.
56 * ====================================================================
57 * Copyright (c) 2000-2001 The OpenSSL Project. All rights reserved.
59 * Redistribution and use in source and binary forms, with or without
60 * modification, are permitted provided that the following conditions
61 * are met:
63 * 1. Redistributions of source code must retain the above copyright
64 * notice, this list of conditions and the following disclaimer.
66 * 2. Redistributions in binary form must reproduce the above copyright
67 * notice, this list of conditions and the following disclaimer in
68 * the documentation and/or other materials provided with the
69 * distribution.
71 * 3. All advertising materials mentioning features or use of this
72 * software must display the following acknowledgment:
73 * "This product includes software developed by the OpenSSL Project
74 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
76 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
77 * endorse or promote products derived from this software without
78 * prior written permission. For written permission, please contact
79 * licensing@OpenSSL.org.
81 * 5. Products derived from this software may not be called "OpenSSL"
82 * nor may "OpenSSL" appear in their names without prior written
83 * permission of the OpenSSL Project.
85 * 6. Redistributions of any form whatsoever must retain the following
86 * acknowledgment:
87 * "This product includes software developed by the OpenSSL Project
88 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
90 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
91 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
92 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
93 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
94 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
95 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
96 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
97 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
98 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
99 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
100 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
101 * OF THE POSSIBILITY OF SUCH DAMAGE.
102 * ====================================================================
104 * This product includes cryptographic software written by Eric Young
105 * (eay@cryptsoft.com). This product includes software written by Tim
106 * Hudson (tjh@cryptsoft.com).
110 /* Id */
112 #include <config.h>
114 #include <stdio.h>
115 #include <stdlib.h>
116 #include <string.h>
118 #include <isc/log.h>
119 #include <isc/mem.h>
120 #include <isc/once.h>
121 #include <isc/platform.h>
122 #include <isc/stdio.h>
123 #include <isc/thread.h>
124 #include <isc/util.h>
126 #include <dst/result.h>
128 #include <pk11/pk11.h>
129 #include <pk11/internal.h>
130 #include <pk11/result.h>
132 #include <pkcs11/cryptoki.h>
133 #include <pkcs11/pkcs11.h>
135 /* was 32 octets, Petr Spacek suggested 1024, SoftHSMv2 uses 256... */
136 #ifndef PINLEN
137 #define PINLEN 256
138 #endif
140 #ifndef PK11_NO_LOGERR
141 #define PK11_NO_LOGERR 1
142 #endif
144 static isc_once_t once = ISC_ONCE_INIT;
145 static isc_mem_t *pk11_mctx = NULL;
146 static isc_int32_t allocsize = 0;
147 static isc_boolean_t initialized = ISC_FALSE;
149 typedef struct pk11_session pk11_session_t;
150 typedef struct pk11_token pk11_token_t;
151 typedef ISC_LIST(pk11_session_t) pk11_sessionlist_t;
153 struct pk11_session {
154 unsigned int magic;
155 CK_SESSION_HANDLE session;
156 ISC_LINK(pk11_session_t) link;
157 pk11_token_t *token;
160 struct pk11_token {
161 unsigned int magic;
162 unsigned int operations;
163 ISC_LINK(pk11_token_t) link;
164 CK_SLOT_ID slotid;
165 pk11_sessionlist_t sessions;
166 isc_boolean_t logged;
167 char name[32];
168 char manuf[32];
169 char model[16];
170 char serial[16];
171 char pin[PINLEN + 1];
173 static ISC_LIST(pk11_token_t) tokens;
175 static pk11_token_t *rand_token;
176 static pk11_token_t *best_rsa_token;
177 static pk11_token_t *best_dsa_token;
178 static pk11_token_t *best_dh_token;
179 static pk11_token_t *digest_token;
180 static pk11_token_t *best_ec_token;
181 static pk11_token_t *best_gost_token;
182 static pk11_token_t *aes_token;
184 static isc_result_t free_all_sessions(void);
185 static isc_result_t free_session_list(pk11_sessionlist_t *slist);
186 static isc_result_t setup_session(pk11_session_t *sp,
187 pk11_token_t *token,
188 isc_boolean_t rw);
189 static void choose_slots(void);
190 static isc_result_t token_login(pk11_session_t *sp);
191 static char *percent_decode(char *x, size_t *len);
192 static isc_boolean_t pk11strcmp(const char *x, size_t lenx,
193 const char *y, size_t leny);
194 static CK_ATTRIBUTE *push_attribute(pk11_object_t *obj,
195 isc_mem_t *mctx,
196 size_t len);
198 static isc_mutex_t alloclock;
199 static isc_mutex_t sessionlock;
201 static pk11_sessionlist_t actives;
203 static CK_C_INITIALIZE_ARGS pk11_init_args = {
204 NULL_PTR, /* CreateMutex */
205 NULL_PTR, /* DestroyMutex */
206 NULL_PTR, /* LockMutex */
207 NULL_PTR, /* UnlockMutex */
208 CKF_OS_LOCKING_OK, /* flags */
209 NULL_PTR, /* pReserved */
212 #ifndef PK11_LIB_LOCATION
213 #define PK11_LIB_LOCATION "unknown_provider"
214 #endif
216 #ifndef WIN32
217 static const char *lib_name = PK11_LIB_LOCATION;
218 #else
219 static const char *lib_name = PK11_LIB_LOCATION ".dll";
220 #endif
222 void
223 pk11_set_lib_name(const char *name) {
224 lib_name = name;
227 const char *
228 pk11_get_lib_name(void) {
229 return (lib_name);
232 static void
233 initialize(void) {
234 char *pk11_provider;
236 RUNTIME_CHECK(isc_mutex_init(&alloclock) == ISC_R_SUCCESS);
237 RUNTIME_CHECK(isc_mutex_init(&sessionlock) == ISC_R_SUCCESS);
239 pk11_provider = getenv("PKCS11_PROVIDER");
240 if (pk11_provider != NULL)
241 lib_name = pk11_provider;
244 void *
245 pk11_mem_get(size_t size) {
246 void *ptr;
248 LOCK(&alloclock);
249 if (pk11_mctx != NULL)
250 ptr = isc_mem_get(pk11_mctx, size);
251 else {
252 ptr = malloc(size);
253 if (ptr != NULL)
254 allocsize += (int)size;
256 UNLOCK(&alloclock);
258 if (ptr != NULL)
259 memset(ptr, 0, size);
260 return (ptr);
263 void
264 pk11_mem_put(void *ptr, size_t size) {
265 if (ptr != NULL)
266 memset(ptr, 0, size);
267 LOCK(&alloclock);
268 if (pk11_mctx != NULL)
269 isc_mem_put(pk11_mctx, ptr, size);
270 else {
271 if (ptr != NULL)
272 allocsize -= (int)size;
273 free(ptr);
275 UNLOCK(&alloclock);
278 isc_result_t
279 pk11_initialize(isc_mem_t *mctx, const char *engine) {
280 isc_result_t result;
281 CK_RV rv;
283 RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
285 LOCK(&alloclock);
286 if ((mctx != NULL) && (pk11_mctx == NULL) && (allocsize == 0))
287 isc_mem_attach(mctx, &pk11_mctx);
288 if (initialized) {
289 UNLOCK(&alloclock);
290 return (ISC_R_SUCCESS);
291 } else {
292 LOCK(&sessionlock);
293 initialized = ISC_TRUE;
294 UNLOCK(&alloclock);
297 ISC_LIST_INIT(tokens);
298 ISC_LIST_INIT(actives);
300 if (engine != NULL)
301 lib_name = engine;
303 /* Initialize the CRYPTOKI library */
304 rv = pkcs_C_Initialize((CK_VOID_PTR) &pk11_init_args);
306 if (rv == 0xfe) {
307 result = PK11_R_NOPROVIDER;
308 goto unlock;
310 if (rv != CKR_OK) {
311 result = PK11_R_INITFAILED;
312 goto unlock;
315 choose_slots();
316 #ifdef PKCS11CRYPTO
317 if (rand_token == NULL) {
318 result = PK11_R_NORANDOMSERVICE;
319 goto unlock;
321 if (digest_token == NULL) {
322 result = PK11_R_NODIGESTSERVICE;
323 goto unlock;
325 #if defined(ISC_PLATFORM_USESIT) && defined(AES_SIT)
326 if (aes_token == NULL) {
327 result = PK11_R_NOAESSERVICE;
328 goto unlock;
330 #endif
331 #endif /* PKCS11CRYPTO */
332 result = ISC_R_SUCCESS;
333 unlock:
334 UNLOCK(&sessionlock);
335 return (result);
338 isc_result_t
339 pk11_finalize(void) {
340 pk11_token_t *token, *next;
341 isc_result_t ret;
343 ret = free_all_sessions();
344 (void) pkcs_C_Finalize(NULL_PTR);
345 token = ISC_LIST_HEAD(tokens);
346 while (token != NULL) {
347 next = ISC_LIST_NEXT(token, link);
348 ISC_LIST_UNLINK(tokens, token, link);
349 if (token == rand_token)
350 rand_token = NULL;
351 if (token == best_rsa_token)
352 best_rsa_token = NULL;
353 if (token == best_dsa_token)
354 best_dsa_token = NULL;
355 if (token == best_dh_token)
356 best_dh_token = NULL;
357 if (token == digest_token)
358 digest_token = NULL;
359 if (token == best_ec_token)
360 best_ec_token = NULL;
361 if (token == best_gost_token)
362 best_gost_token = NULL;
363 if (token == aes_token)
364 aes_token = NULL;
365 pk11_mem_put(token, sizeof(*token));
366 token = next;
368 if (pk11_mctx != NULL)
369 isc_mem_detach(&pk11_mctx);
370 initialized = ISC_FALSE;
371 return (ret);
374 isc_result_t
375 pk11_rand_bytes(unsigned char *buf, int num) {
376 isc_result_t ret;
377 CK_RV rv;
378 pk11_context_t ctx;
380 ret = pk11_get_session(&ctx, OP_RAND, ISC_FALSE, ISC_FALSE,
381 ISC_FALSE, NULL, 0);
382 if ((ret != ISC_R_SUCCESS) &&
383 (ret != PK11_R_NODIGESTSERVICE) &&
384 (ret != PK11_R_NOAESSERVICE))
385 return (ret);
386 RUNTIME_CHECK(ctx.session != CK_INVALID_HANDLE);
387 rv = pkcs_C_GenerateRandom(ctx.session,
388 (CK_BYTE_PTR) buf, (CK_ULONG) num);
389 pk11_return_session(&ctx);
390 if (rv == CKR_OK)
391 return (ISC_R_SUCCESS);
392 else
393 return (DST_R_CRYPTOFAILURE);
396 #define SEEDSIZE 1024
398 static CK_BYTE seed[SEEDSIZE];
400 void
401 pk11_rand_seed_fromfile(const char *randomfile) {
402 pk11_context_t ctx;
403 FILE *stream = NULL;
404 size_t cc = 0;
405 isc_result_t ret;
407 ret = pk11_get_session(&ctx, OP_RAND, ISC_FALSE, ISC_FALSE,
408 ISC_FALSE, NULL, 0);
409 if ((ret != ISC_R_SUCCESS) &&
410 (ret != PK11_R_NODIGESTSERVICE) &&
411 (ret != PK11_R_NOAESSERVICE))
412 return;
413 RUNTIME_CHECK(ctx.session != CK_INVALID_HANDLE);
414 ret = isc_stdio_open(randomfile, "r", &stream);
415 if (ret != ISC_R_SUCCESS)
416 goto cleanup;
417 ret = isc_stdio_read(seed, 1, SEEDSIZE, stream, &cc);
418 if (ret!= ISC_R_SUCCESS)
419 goto cleanup;
420 ret = isc_stdio_close(stream);
421 stream = NULL;
422 if (ret!= ISC_R_SUCCESS)
423 goto cleanup;
424 (void) pkcs_C_SeedRandom(ctx.session, seed, (CK_ULONG) cc);
426 cleanup:
427 if (stream != NULL)
428 (void) isc_stdio_close(stream);
429 pk11_return_session(&ctx);
432 isc_result_t
433 pk11_get_session(pk11_context_t *ctx, pk11_optype_t optype,
434 isc_boolean_t need_services, isc_boolean_t rw,
435 isc_boolean_t logon, const char *pin, CK_SLOT_ID slot)
437 pk11_token_t *token = NULL;
438 pk11_sessionlist_t *freelist;
439 pk11_session_t *sp;
440 isc_result_t ret;
441 #ifdef PKCS11CRYPTO
442 isc_result_t service_ret = ISC_R_SUCCESS;
443 #else
444 UNUSED(need_services);
445 #endif
447 memset(ctx, 0, sizeof(pk11_context_t));
448 ctx->handle = NULL;
449 ctx->session = CK_INVALID_HANDLE;
451 ret = pk11_initialize(NULL, NULL);
452 #ifdef PKCS11CRYPTO
453 if (ret == PK11_R_NORANDOMSERVICE ||
454 ret == PK11_R_NODIGESTSERVICE ||
455 ret == PK11_R_NOAESSERVICE) {
456 if (need_services)
457 return (ret);
458 service_ret = ret;
460 else
461 #endif /* PKCS11CRYPTO */
462 if (ret != ISC_R_SUCCESS)
463 return (ret);
465 LOCK(&sessionlock);
466 /* wait for initialization to finish */
467 UNLOCK(&sessionlock);
469 switch(optype) {
470 #ifdef PKCS11CRYPTO
471 case OP_RAND:
472 token = rand_token;
473 break;
474 case OP_DIGEST:
475 token = digest_token;
476 break;
477 case OP_AES:
478 token = aes_token;
479 break;
480 case OP_ANY:
481 for (token = ISC_LIST_HEAD(tokens);
482 token != NULL;
483 token = ISC_LIST_NEXT(token, link))
484 if (token->slotid == slot)
485 break;
486 break;
487 #endif
488 default:
489 for (token = ISC_LIST_HEAD(tokens);
490 token != NULL;
491 token = ISC_LIST_NEXT(token, link))
492 if (token->slotid == slot)
493 break;
494 #ifdef PKCS11CRYPTO
495 if ((token == NULL) ||
496 ((token->operations & (1 << optype)) == 0))
497 return (ISC_R_NOTFOUND);
498 #endif
499 break;
501 if (token == NULL)
502 return (ISC_R_NOTFOUND);
504 /* Override the token's PIN */
505 if (logon && pin != NULL && *pin != '\0') {
506 if (strlen(pin) > PINLEN)
507 return ISC_R_RANGE;
508 memset(token->pin, 0, PINLEN + 1);
509 strncpy(token->pin, pin, PINLEN);
512 freelist = &token->sessions;
514 LOCK(&sessionlock);
515 sp = ISC_LIST_HEAD(*freelist);
516 if (sp != NULL) {
517 ISC_LIST_UNLINK(*freelist, sp, link);
518 ISC_LIST_APPEND(actives, sp, link);
519 UNLOCK(&sessionlock);
520 if (logon)
521 ret = token_login(sp);
522 ctx->handle = sp;
523 ctx->session = sp->session;
524 return (ret);
526 UNLOCK(&sessionlock);
528 sp = pk11_mem_get(sizeof(*sp));
529 if (sp == NULL)
530 return (ISC_R_NOMEMORY);
531 sp->magic = SES_MAGIC;
532 sp->token = token;
533 sp->session = CK_INVALID_HANDLE;
534 ISC_LINK_INIT(sp, link);
535 ret = setup_session(sp, token, rw);
536 if ((ret == ISC_R_SUCCESS) && logon)
537 ret = token_login(sp);
538 LOCK(&sessionlock);
539 ISC_LIST_APPEND(actives, sp, link);
540 UNLOCK(&sessionlock);
541 ctx->handle = sp;
542 ctx->session = sp->session;
543 #ifdef PKCS11CRYPTO
544 if (ret == ISC_R_SUCCESS)
545 ret = service_ret;
546 #endif
547 return (ret);
550 void
551 pk11_return_session(pk11_context_t *ctx) {
552 pk11_session_t *sp = (pk11_session_t *) ctx->handle;
554 if (sp == NULL)
555 return;
556 ctx->handle = NULL;
557 ctx->session = CK_INVALID_HANDLE;
559 LOCK(&sessionlock);
560 ISC_LIST_UNLINK(actives, sp, link);
561 UNLOCK(&sessionlock);
562 if (sp->session == CK_INVALID_HANDLE) {
563 pk11_mem_put(sp, sizeof(*sp));
564 return;
567 LOCK(&sessionlock);
568 ISC_LIST_APPEND(sp->token->sessions, sp, link);
569 UNLOCK(&sessionlock);
572 static isc_result_t
573 free_all_sessions(void) {
574 pk11_token_t *token;
575 isc_result_t ret = ISC_R_SUCCESS;
576 isc_result_t oret;
578 for (token = ISC_LIST_HEAD(tokens);
579 token != NULL;
580 token = ISC_LIST_NEXT(token, link)) {
581 oret = free_session_list(&token->sessions);
582 if (oret != ISC_R_SUCCESS)
583 ret = oret;
585 if (!ISC_LIST_EMPTY(actives)) {
586 ret = ISC_R_ADDRINUSE;
587 oret = free_session_list(&actives);
588 if (oret != ISC_R_SUCCESS)
589 ret = oret;
591 return (ret);
594 static isc_result_t
595 free_session_list(pk11_sessionlist_t *slist) {
596 pk11_session_t *sp;
597 CK_RV rv;
598 isc_result_t ret;
600 ret = ISC_R_SUCCESS;
601 LOCK(&sessionlock);
602 while (!ISC_LIST_EMPTY(*slist)) {
603 sp = ISC_LIST_HEAD(*slist);
604 UNLOCK(&sessionlock);
605 if (sp->session != CK_INVALID_HANDLE) {
606 rv = pkcs_C_CloseSession(sp->session);
607 if (rv != CKR_OK)
608 ret = DST_R_CRYPTOFAILURE;
610 LOCK(&sessionlock);
611 ISC_LIST_UNLINK(*slist, sp, link);
612 pk11_mem_put(sp, sizeof(*sp));
614 UNLOCK(&sessionlock);
616 return (ret);
619 static isc_result_t
620 setup_session(pk11_session_t *sp, pk11_token_t *token,
621 isc_boolean_t rw)
623 CK_RV rv;
624 CK_FLAGS flags = CKF_SERIAL_SESSION;
626 if (rw)
627 flags += CKF_RW_SESSION;
629 rv = pkcs_C_OpenSession(token->slotid, flags, NULL_PTR,
630 NULL_PTR, &sp->session);
631 if (rv != CKR_OK)
632 return (DST_R_CRYPTOFAILURE);
633 return (ISC_R_SUCCESS);
636 static isc_result_t
637 token_login(pk11_session_t *sp) {
638 CK_RV rv;
639 pk11_token_t *token = sp->token;
640 isc_result_t ret = ISC_R_SUCCESS;
642 LOCK(&sessionlock);
643 if (!token->logged) {
644 rv = pkcs_C_Login(sp->session, CKU_USER,
645 (CK_UTF8CHAR_PTR) token->pin,
646 (CK_ULONG) strlen(token->pin));
647 if (rv != CKR_OK) {
648 ret = ISC_R_NOPERM;
649 #if PK11_NO_LOGERR
650 pk11_error_fatalcheck(__FILE__, __LINE__,
651 "pkcs_C_Login", rv);
652 #endif
653 } else
654 token->logged = ISC_TRUE;
656 UNLOCK(&sessionlock);
657 return (ret);
660 static void
661 choose_slots(void) {
662 CK_MECHANISM_INFO mechInfo;
663 CK_TOKEN_INFO tokenInfo;
664 CK_RV rv;
665 CK_SLOT_ID slot;
666 CK_SLOT_ID_PTR slotList;
667 CK_ULONG slotCount;
668 pk11_token_t *token;
669 unsigned int i;
671 slotCount = 0;
672 PK11_FATALCHECK(pkcs_C_GetSlotList, (CK_FALSE, NULL_PTR, &slotCount));
673 /* it's not an error if we didn't find any providers */
674 if (slotCount == 0)
675 return;
676 slotList = pk11_mem_get(sizeof(CK_SLOT_ID_PTR) * slotCount);
677 RUNTIME_CHECK(slotList != NULL);
678 PK11_FATALCHECK(pkcs_C_GetSlotList, (CK_FALSE, slotList, &slotCount));
680 for (i = 0; i < slotCount; i++) {
681 slot = slotList[i];
683 rv = pkcs_C_GetTokenInfo(slot, &tokenInfo);
684 if (rv != CKR_OK)
685 continue;
686 token = pk11_mem_get(sizeof(*token));
687 RUNTIME_CHECK(token != NULL);
688 token->magic = TOK_MAGIC;
689 token->slotid = slot;
690 ISC_LINK_INIT(token, link);
691 ISC_LIST_INIT(token->sessions);
692 memmove(token->name, tokenInfo.label, 32);
693 memmove(token->manuf, tokenInfo.manufacturerID, 32);
694 memmove(token->model, tokenInfo.model, 16);
695 memmove(token->serial, tokenInfo.serialNumber, 16);
696 ISC_LIST_APPEND(tokens, token, link);
697 if ((tokenInfo.flags & CKF_RNG) == 0)
698 goto try_rsa;
699 token->operations |= 1 << OP_RAND;
700 if (rand_token == NULL)
701 rand_token = token;
703 try_rsa:
704 rv = pkcs_C_GetMechanismInfo(slot, CKM_RSA_PKCS_KEY_PAIR_GEN,
705 &mechInfo);
706 if ((rv != CKR_OK) ||
707 ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0))
708 goto try_dsa;
709 rv = pkcs_C_GetMechanismInfo(slot, CKM_MD5_RSA_PKCS,
710 &mechInfo);
711 if ((rv != CKR_OK) ||
712 ((mechInfo.flags & CKF_SIGN) == 0) ||
713 ((mechInfo.flags & CKF_VERIFY) == 0))
714 goto try_dsa;
715 rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA1_RSA_PKCS,
716 &mechInfo);
717 if ((rv != CKR_OK) ||
718 ((mechInfo.flags & CKF_SIGN) == 0) ||
719 ((mechInfo.flags & CKF_VERIFY) == 0))
720 goto try_dsa;
721 rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA256_RSA_PKCS,
722 &mechInfo);
723 if ((rv != CKR_OK) ||
724 ((mechInfo.flags & CKF_SIGN) == 0) ||
725 ((mechInfo.flags & CKF_VERIFY) == 0))
726 goto try_dsa;
727 rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA512_RSA_PKCS,
728 &mechInfo);
729 if ((rv != CKR_OK) ||
730 ((mechInfo.flags & CKF_SIGN) == 0) ||
731 ((mechInfo.flags & CKF_VERIFY) == 0))
732 goto try_dsa;
733 token->operations |= 1 << OP_RSA;
734 if (best_rsa_token == NULL)
735 best_rsa_token = token;
737 try_dsa:
738 rv = pkcs_C_GetMechanismInfo(slot, CKM_DSA_PARAMETER_GEN,
739 &mechInfo);
740 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_GENERATE) == 0))
741 goto try_dh;
742 rv = pkcs_C_GetMechanismInfo(slot, CKM_DSA_KEY_PAIR_GEN,
743 &mechInfo);
744 if ((rv != CKR_OK) ||
745 ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0))
746 goto try_dh;
747 rv = pkcs_C_GetMechanismInfo(slot, CKM_DSA_SHA1, &mechInfo);
748 if ((rv != CKR_OK) ||
749 ((mechInfo.flags & CKF_SIGN) == 0) ||
750 ((mechInfo.flags & CKF_VERIFY) == 0))
751 goto try_dh;
752 token->operations |= 1 << OP_DSA;
753 if (best_dsa_token == NULL)
754 best_dsa_token = token;
756 try_dh:
757 #ifdef notdef
758 rv = pkcs_C_GetMechanismInfo(slot, CKM_DH_PKCS_PARAMETER_GEN,
759 &mechInfo);
760 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_GENERATE) == 0))
761 goto try_digest;
762 #endif
763 rv = pkcs_C_GetMechanismInfo(slot, CKM_DH_PKCS_KEY_PAIR_GEN,
764 &mechInfo);
765 if ((rv != CKR_OK) ||
766 ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0))
767 goto try_digest;
768 rv = pkcs_C_GetMechanismInfo(slot, CKM_DH_PKCS_DERIVE,
769 &mechInfo);
770 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DERIVE) == 0))
771 goto try_digest;
772 token->operations |= 1 << OP_DH;
773 if (best_dh_token == NULL)
774 best_dh_token = token;
776 try_digest:
777 rv = pkcs_C_GetMechanismInfo(slot, CKM_MD5, &mechInfo);
778 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0))
779 continue;
780 rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA_1, &mechInfo);
781 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0))
782 continue;
783 rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA224, &mechInfo);
784 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0))
785 continue;
786 rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA256, &mechInfo);
787 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0))
788 continue;
789 rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA384, &mechInfo);
790 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0))
791 continue;
792 rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA512, &mechInfo);
793 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0))
794 continue;
795 #ifdef PKCS11CRYPTOWITHHMAC
796 rv = pkcs_C_GetMechanismInfo(slot, CKM_MD5_HMAC, &mechInfo);
797 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0))
798 continue;
799 #endif
800 rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA_1_HMAC, &mechInfo);
801 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0))
802 continue;
803 rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA224_HMAC, &mechInfo);
804 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0))
805 continue;
806 rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA256_HMAC, &mechInfo);
807 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0))
808 continue;
809 rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA384_HMAC, &mechInfo);
810 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0))
811 continue;
812 rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA512_HMAC, &mechInfo);
813 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0))
814 continue;
815 token->operations |= 1 << OP_DIGEST;
816 if (digest_token == NULL)
817 digest_token = token;
819 /* ECDSA requires digest */
820 rv = pkcs_C_GetMechanismInfo(slot, CKM_EC_KEY_PAIR_GEN,
821 &mechInfo);
822 if ((rv != CKR_OK) ||
823 ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0))
824 goto try_gost;
825 rv = pkcs_C_GetMechanismInfo(slot, CKM_ECDSA, &mechInfo);
826 if ((rv != CKR_OK) ||
827 ((mechInfo.flags & CKF_SIGN) == 0) ||
828 ((mechInfo.flags & CKF_VERIFY) == 0))
829 goto try_gost;
830 token->operations |= 1 << OP_EC;
831 if (best_ec_token == NULL)
832 best_ec_token = token;
834 try_gost:
835 /* does GOST require digest too? */
836 rv = pkcs_C_GetMechanismInfo(slot, CKM_GOSTR3411, &mechInfo);
837 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0))
838 goto try_aes;
839 rv = pkcs_C_GetMechanismInfo(slot, CKM_GOSTR3410_KEY_PAIR_GEN,
840 &mechInfo);
841 if ((rv != CKR_OK) ||
842 ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0))
843 goto try_aes;
844 rv = pkcs_C_GetMechanismInfo(slot,
845 CKM_GOSTR3410_WITH_GOSTR3411,
846 &mechInfo);
847 if ((rv != CKR_OK) ||
848 ((mechInfo.flags & CKF_SIGN) == 0) ||
849 ((mechInfo.flags & CKF_VERIFY) == 0))
850 goto try_aes;
851 token->operations |= 1 << OP_GOST;
852 if (best_gost_token == NULL)
853 best_gost_token = token;
855 try_aes:
856 rv = pkcs_C_GetMechanismInfo(slot, CKM_AES_ECB, &mechInfo);
857 if ((rv != CKR_OK) || ((mechInfo.flags & CKF_ENCRYPT) == 0))
858 continue;
859 token->operations |= 1 << OP_AES;
860 if (aes_token == NULL)
861 aes_token = token;
864 if (slotList != NULL)
865 pk11_mem_put(slotList, sizeof(CK_SLOT_ID_PTR) * slotCount);
868 CK_SLOT_ID
869 pk11_get_best_token(pk11_optype_t optype) {
870 pk11_token_t *token = NULL;
872 switch (optype) {
873 case OP_RAND:
874 token = rand_token;
875 break;
876 case OP_RSA:
877 token = best_rsa_token;
878 break;
879 case OP_DSA:
880 token = best_dsa_token;
881 break;
882 case OP_DH:
883 token = best_dh_token;
884 break;
885 case OP_DIGEST:
886 token = digest_token;
887 break;
888 case OP_EC:
889 token = best_ec_token;
890 break;
891 case OP_GOST:
892 token = best_gost_token;
893 break;
894 case OP_AES:
895 token = aes_token;
896 break;
897 default:
898 break;
900 if (token == NULL)
901 return (0);
902 return (token->slotid);
905 unsigned int
906 pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt) {
907 unsigned int bitcnt, i;
908 CK_BYTE top;
910 if (bytecnt == 0)
911 return (0);
912 bitcnt = bytecnt * 8;
913 for (i = 0; i < bytecnt; i++) {
914 top = data[i];
915 if (top == 0) {
916 bitcnt -= 8;
917 continue;
919 if (top & 0x80)
920 return (bitcnt);
921 if (top & 0x40)
922 return (bitcnt - 1);
923 if (top & 0x20)
924 return (bitcnt - 2);
925 if (top & 0x10)
926 return (bitcnt - 3);
927 if (top & 0x08)
928 return (bitcnt - 4);
929 if (top & 0x04)
930 return (bitcnt - 5);
931 if (top & 0x02)
932 return (bitcnt - 6);
933 if (top & 0x01)
934 return (bitcnt - 7);
935 break;
937 INSIST(0);
940 CK_ATTRIBUTE *
941 pk11_attribute_first(const pk11_object_t *obj) {
942 return (obj->repr);
945 CK_ATTRIBUTE *
946 pk11_attribute_next(const pk11_object_t *obj, CK_ATTRIBUTE *attr) {
947 CK_ATTRIBUTE *next;
949 next = attr + 1;
950 if ((next - obj->repr) >= obj->attrcnt)
951 return (NULL);
952 return (next);
955 CK_ATTRIBUTE *
956 pk11_attribute_bytype(const pk11_object_t *obj, CK_ATTRIBUTE_TYPE type) {
957 CK_ATTRIBUTE *attr;
959 for(attr = pk11_attribute_first(obj);
960 attr != NULL;
961 attr = pk11_attribute_next(obj, attr))
962 if (attr->type == type)
963 return (attr);
964 return (NULL);
967 static char *
968 percent_decode(char *x, size_t *len) {
969 char *p, *c;
970 unsigned char v;
972 INSIST(len != NULL);
974 for (p = c = x; p[0] != '\0'; p++, c++) {
975 switch (p[0]) {
976 case '%':
977 v = 0;
978 switch (p[1]) {
979 case '0':
980 case '1':
981 case '2':
982 case '3':
983 case '4':
984 case '5':
985 case '6':
986 case '7':
987 case '8':
988 case '9':
989 v = (p[1] - '0') << 4;
990 break;
991 case 'A':
992 case 'B':
993 case 'C':
994 case 'D':
995 case 'E':
996 case 'F':
997 v = (p[1] - 'A' + 10) << 4;
998 break;
999 case 'a':
1000 case 'b':
1001 case 'c':
1002 case 'd':
1003 case 'e':
1004 case 'f':
1005 v = (p[1] - 'a' + 10) << 4;
1006 break;
1007 default:
1008 return (NULL);
1010 switch (p[2]) {
1011 case '0':
1012 case '1':
1013 case '2':
1014 case '3':
1015 case '4':
1016 case '5':
1017 case '6':
1018 case '7':
1019 case '8':
1020 case '9':
1021 v |= (p[2] - '0') & 0x0f;
1022 break;
1023 case 'A':
1024 case 'B':
1025 case 'C':
1026 case 'D':
1027 case 'E':
1028 case 'F':
1029 v = (p[2] - 'A' + 10) & 0x0f;
1030 break;
1031 case 'a':
1032 case 'b':
1033 case 'c':
1034 case 'd':
1035 case 'e':
1036 case 'f':
1037 v = (p[2] - 'a' + 10) & 0x0f;
1038 break;
1039 default:
1040 return (NULL);
1042 p += 2;
1043 *c = (char) v;
1044 (*len)++;
1045 break;
1046 default:
1047 *c = *p;
1048 (*len)++;
1051 return (x);
1054 static isc_boolean_t
1055 pk11strcmp(const char *x, size_t lenx, const char *y, size_t leny) {
1056 char buf[32];
1058 INSIST((leny == 32) || (leny == 16));
1060 memset(buf, ' ', 32);
1061 if (lenx > leny)
1062 lenx = leny;
1063 memmove(buf, x, lenx);
1064 return (ISC_TF(memcmp(buf, y, leny) == 0));
1067 static CK_ATTRIBUTE *
1068 push_attribute(pk11_object_t *obj, isc_mem_t *mctx, size_t len) {
1069 CK_ATTRIBUTE *old = obj->repr;
1070 CK_ATTRIBUTE *attr;
1071 CK_BYTE cnt = obj->attrcnt;
1073 obj->repr = isc_mem_get(mctx, (cnt + 1) * sizeof(*attr));
1074 if (obj->repr == NULL) {
1075 obj->repr = old;
1076 return (NULL);
1078 memset(obj->repr, 0, (cnt + 1) * sizeof(*attr));
1079 memmove(obj->repr, old, cnt * sizeof(*attr));
1080 attr = obj->repr + cnt;
1081 attr->ulValueLen = (CK_ULONG) len;
1082 attr->pValue = isc_mem_get(mctx, len);
1083 if (attr->pValue == NULL) {
1084 memset(obj->repr, 0, (cnt + 1) * sizeof(*attr));
1085 isc_mem_put(mctx, obj->repr, (cnt + 1) * sizeof(*attr));
1086 obj->repr = old;
1087 return (NULL);
1089 memset(attr->pValue, 0, len);
1090 if (old != NULL) {
1091 memset(old, 0, cnt * sizeof(*attr));
1092 isc_mem_put(mctx, old, cnt * sizeof(*attr));
1094 obj->attrcnt++;
1095 return (attr);
1098 #define DST_RET(a) { ret = a; goto err; }
1100 isc_result_t
1101 pk11_parse_uri(pk11_object_t *obj, const char *label,
1102 isc_mem_t *mctx, pk11_optype_t optype)
1104 CK_ATTRIBUTE *attr;
1105 pk11_token_t *token = NULL;
1106 char *uri, *p, *a, *na, *v;
1107 size_t len, l;
1108 FILE *stream = NULL;
1109 char pin[PINLEN + 1];
1110 isc_boolean_t gotpin = ISC_FALSE;
1111 isc_result_t ret;
1113 /* get values to work on */
1114 len = strlen(label) + 1;
1115 uri = isc_mem_get(mctx, len);
1116 if (uri == NULL)
1117 return (ISC_R_NOMEMORY);
1118 memmove(uri, label, len);
1120 /* get the URI scheme */
1121 p = strchr(uri, ':');
1122 if (p == NULL)
1123 DST_RET(PK11_R_NOPROVIDER);
1124 *p++ = '\0';
1125 if (strcmp(uri, "pkcs11") != 0)
1126 DST_RET(PK11_R_NOPROVIDER);
1128 /* get attributes */
1129 for (na = p; na != NULL;) {
1130 a = na;
1131 p = strchr(a, ';');
1132 if (p == NULL) {
1133 /* last attribute */
1134 na = NULL;
1135 } else {
1136 *p++ = '\0';
1137 na = p;
1139 p = strchr(a, '=');
1140 if (p != NULL) {
1141 *p++ = '\0';
1142 v = p;
1143 } else
1144 v = a;
1145 l = 0;
1146 v = percent_decode(v, &l);
1147 if (v == NULL)
1148 DST_RET(PK11_R_NOPROVIDER);
1149 if ((a == v) || (strcmp(a, "object") == 0)) {
1150 /* object: CKA_LABEL */
1151 attr = pk11_attribute_bytype(obj, CKA_LABEL);
1152 if (attr != NULL)
1153 DST_RET(PK11_R_NOPROVIDER);
1154 attr = push_attribute(obj, mctx, l);
1155 if (attr == NULL)
1156 DST_RET(ISC_R_NOMEMORY);
1157 attr->type = CKA_LABEL;
1158 memmove(attr->pValue, v, l);
1159 } else if (strcmp(a, "token") == 0) {
1160 /* token: CK_TOKEN_INFO label */
1161 if (token == NULL)
1162 for (token = ISC_LIST_HEAD(tokens);
1163 token != NULL;
1164 token = ISC_LIST_NEXT(token, link))
1165 if (pk11strcmp(v, l, token->name, 32))
1166 break;
1167 } else if (strcmp(a, "manufacturer") == 0) {
1168 /* manufacturer: CK_TOKEN_INFO manufacturerID */
1169 if (token == NULL)
1170 for (token = ISC_LIST_HEAD(tokens);
1171 token != NULL;
1172 token = ISC_LIST_NEXT(token, link))
1173 if (pk11strcmp(v, l, token->manuf, 32))
1174 break;
1175 } else if (strcmp(a, "serial") == 0) {
1176 /* serial: CK_TOKEN_INFO serialNumber */
1177 if (token == NULL)
1178 for (token = ISC_LIST_HEAD(tokens);
1179 token != NULL;
1180 token = ISC_LIST_NEXT(token, link))
1181 if (pk11strcmp(v, l, token->serial, 16))
1182 break;
1183 } else if (strcmp(a, "model") == 0) {
1184 /* model: CK_TOKEN_INFO model */
1185 if (token == NULL)
1186 for (token = ISC_LIST_HEAD(tokens);
1187 token != NULL;
1188 token = ISC_LIST_NEXT(token, link))
1189 if (pk11strcmp(v, l, token->model, 16))
1190 break;
1191 } else if (strcmp(a, "library-manufacturer") == 0) {
1192 /* ignored */
1193 } else if (strcmp(a, "library-description") == 0) {
1194 /* ignored */
1195 } else if (strcmp(a, "library-version") == 0) {
1196 /* ignored */
1197 } else if (strcmp(a, "object-type") == 0) {
1198 /* object-type: CKA_CLASS */
1199 /* only private makes sense */
1200 if (strcmp(v, "private") != 0)
1201 DST_RET(PK11_R_NOPROVIDER);
1202 } else if (strcmp(a, "id") == 0) {
1203 /* id: CKA_ID */
1204 attr = pk11_attribute_bytype(obj, CKA_ID);
1205 if (attr != NULL)
1206 DST_RET(PK11_R_NOPROVIDER);
1207 attr = push_attribute(obj, mctx, l);
1208 if (attr == NULL)
1209 DST_RET(ISC_R_NOMEMORY);
1210 attr->type = CKA_ID;
1211 memmove(attr->pValue, v, l);
1212 } else if (strcmp(a, "pin-source") == 0) {
1213 /* pin-source: PIN */
1214 ret = isc_stdio_open(v, "r", &stream);
1215 if (ret != ISC_R_SUCCESS)
1216 goto err;
1217 memset(pin, 0, PINLEN + 1);
1218 ret = isc_stdio_read(pin, 1, PINLEN + 1, stream, &l);
1219 if ((ret != ISC_R_SUCCESS) && (ret != ISC_R_EOF))
1220 goto err;
1221 if (l > PINLEN)
1222 DST_RET(ISC_R_RANGE);
1223 ret = isc_stdio_close(stream);
1224 stream = NULL;
1225 if (ret != ISC_R_SUCCESS)
1226 goto err;
1227 gotpin = ISC_TRUE;
1228 } else
1229 DST_RET(PK11_R_NOPROVIDER);
1232 if ((pk11_attribute_bytype(obj, CKA_LABEL) == NULL) &&
1233 (pk11_attribute_bytype(obj, CKA_ID) == NULL))
1234 DST_RET(ISC_R_NOTFOUND);
1236 if (token == NULL) {
1237 if (optype == OP_RSA)
1238 token = best_rsa_token;
1239 else if (optype == OP_DSA)
1240 token = best_dsa_token;
1241 else if (optype == OP_DH)
1242 token = best_dh_token;
1243 else if (optype == OP_EC)
1244 token = best_ec_token;
1246 if (token == NULL)
1247 DST_RET(ISC_R_NOTFOUND);
1248 obj->slot = token->slotid;
1249 if (gotpin) {
1250 memmove(token->pin, pin, PINLEN + 1);
1251 obj->reqlogon = ISC_TRUE;
1254 ret = ISC_R_SUCCESS;
1256 err:
1257 if (stream != NULL)
1258 (void) isc_stdio_close(stream);
1259 isc_mem_put(mctx, uri, len);
1260 return (ret);
1263 void
1264 pk11_error_fatalcheck(const char *file, int line,
1265 const char *funcname, CK_RV rv)
1267 isc_error_fatal(file, line, "%s: Error = 0x%.8lX\n", funcname, rv);
1270 void
1271 pk11_dump_tokens(void)
1273 pk11_token_t *token;
1274 isc_boolean_t first;
1276 printf("DEFAULTS\n");
1277 printf("\trand_token=%p\n", rand_token);
1278 printf("\tbest_rsa_token=%p\n", best_rsa_token);
1279 printf("\tbest_dsa_token=%p\n", best_dsa_token);
1280 printf("\tbest_dh_token=%p\n", best_dh_token);
1281 printf("\tdigest_token=%p\n", digest_token);
1282 printf("\tbest_ec_token=%p\n", best_ec_token);
1283 printf("\tbest_gost_token=%p\n", best_gost_token);
1284 printf("\taes_token=%p\n", aes_token);
1286 for (token = ISC_LIST_HEAD(tokens);
1287 token != NULL;
1288 token = ISC_LIST_NEXT(token, link)) {
1289 printf("\nTOKEN\n");
1290 printf("\taddress=%p\n", token);
1291 printf("\tslotID=%lu\n", token->slotid);
1292 printf("\tlabel=%.32s\n", token->name);
1293 printf("\tmanufacturerID=%.32s\n", token->manuf);
1294 printf("\tmodel=%.16s\n", token->model);
1295 printf("\tserialNumber=%.16s\n", token->serial);
1296 printf("\tsupported operations=0x%x (", token->operations);
1297 first = ISC_TRUE;
1298 if (token->operations & (1 << OP_RAND)) {
1299 if (!first)
1300 printf(",");
1301 first = ISC_FALSE;
1302 printf("RAND");
1304 if (token->operations & (1 << OP_RSA)) {
1305 if (!first)
1306 printf(",");
1307 first = ISC_FALSE;
1308 printf("RSA");
1310 if (token->operations & (1 << OP_DSA)) {
1311 if (!first)
1312 printf(",");
1313 first = ISC_FALSE;
1314 printf("DSA");
1316 if (token->operations & (1 << OP_DH)) {
1317 if (!first)
1318 printf(",");
1319 first = ISC_FALSE;
1320 printf("DH");
1322 if (token->operations & (1 << OP_DIGEST)) {
1323 if (!first)
1324 printf(",");
1325 first = ISC_FALSE;
1326 printf("DIGEST");
1328 if (token->operations & (1 << OP_EC)) {
1329 if (!first)
1330 printf(",");
1331 first = ISC_FALSE;
1332 printf("EC");
1334 printf(")\n");