1 /* $NetBSD: pk11.c,v 1.1.1.5 2015/07/08 15:38:05 christos Exp $ */
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
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
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
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
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
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).
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... */
140 #ifndef PK11_NO_LOGERR
141 #define PK11_NO_LOGERR 1
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
{
155 CK_SESSION_HANDLE session
;
156 ISC_LINK(pk11_session_t
) link
;
162 unsigned int operations
;
163 ISC_LINK(pk11_token_t
) link
;
165 pk11_sessionlist_t sessions
;
166 isc_boolean_t logged
;
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
,
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
,
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"
217 static const char *lib_name
= PK11_LIB_LOCATION
;
219 static const char *lib_name
= PK11_LIB_LOCATION
".dll";
223 pk11_set_lib_name(const char *name
) {
228 pk11_get_lib_name(void) {
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
;
245 pk11_mem_get(size_t size
) {
249 if (pk11_mctx
!= NULL
)
250 ptr
= isc_mem_get(pk11_mctx
, size
);
254 allocsize
+= (int)size
;
259 memset(ptr
, 0, size
);
264 pk11_mem_put(void *ptr
, size_t size
) {
266 memset(ptr
, 0, size
);
268 if (pk11_mctx
!= NULL
)
269 isc_mem_put(pk11_mctx
, ptr
, size
);
272 allocsize
-= (int)size
;
279 pk11_initialize(isc_mem_t
*mctx
, const char *engine
) {
283 RUNTIME_CHECK(isc_once_do(&once
, initialize
) == ISC_R_SUCCESS
);
286 if ((mctx
!= NULL
) && (pk11_mctx
== NULL
) && (allocsize
== 0))
287 isc_mem_attach(mctx
, &pk11_mctx
);
290 return (ISC_R_SUCCESS
);
293 initialized
= ISC_TRUE
;
297 ISC_LIST_INIT(tokens
);
298 ISC_LIST_INIT(actives
);
303 /* Initialize the CRYPTOKI library */
304 rv
= pkcs_C_Initialize((CK_VOID_PTR
) &pk11_init_args
);
307 result
= PK11_R_NOPROVIDER
;
311 result
= PK11_R_INITFAILED
;
317 if (rand_token
== NULL
) {
318 result
= PK11_R_NORANDOMSERVICE
;
321 if (digest_token
== NULL
) {
322 result
= PK11_R_NODIGESTSERVICE
;
325 #if defined(ISC_PLATFORM_USESIT) && defined(AES_SIT)
326 if (aes_token
== NULL
) {
327 result
= PK11_R_NOAESSERVICE
;
331 #endif /* PKCS11CRYPTO */
332 result
= ISC_R_SUCCESS
;
334 UNLOCK(&sessionlock
);
339 pk11_finalize(void) {
340 pk11_token_t
*token
, *next
;
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
)
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
)
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
)
365 pk11_mem_put(token
, sizeof(*token
));
368 if (pk11_mctx
!= NULL
)
369 isc_mem_detach(&pk11_mctx
);
370 initialized
= ISC_FALSE
;
375 pk11_rand_bytes(unsigned char *buf
, int num
) {
380 ret
= pk11_get_session(&ctx
, OP_RAND
, ISC_FALSE
, ISC_FALSE
,
382 if ((ret
!= ISC_R_SUCCESS
) &&
383 (ret
!= PK11_R_NODIGESTSERVICE
) &&
384 (ret
!= PK11_R_NOAESSERVICE
))
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
);
391 return (ISC_R_SUCCESS
);
393 return (DST_R_CRYPTOFAILURE
);
396 #define SEEDSIZE 1024
398 static CK_BYTE seed
[SEEDSIZE
];
401 pk11_rand_seed_fromfile(const char *randomfile
) {
407 ret
= pk11_get_session(&ctx
, OP_RAND
, ISC_FALSE
, ISC_FALSE
,
409 if ((ret
!= ISC_R_SUCCESS
) &&
410 (ret
!= PK11_R_NODIGESTSERVICE
) &&
411 (ret
!= PK11_R_NOAESSERVICE
))
413 RUNTIME_CHECK(ctx
.session
!= CK_INVALID_HANDLE
);
414 ret
= isc_stdio_open(randomfile
, "r", &stream
);
415 if (ret
!= ISC_R_SUCCESS
)
417 ret
= isc_stdio_read(seed
, 1, SEEDSIZE
, stream
, &cc
);
418 if (ret
!= ISC_R_SUCCESS
)
420 ret
= isc_stdio_close(stream
);
422 if (ret
!= ISC_R_SUCCESS
)
424 (void) pkcs_C_SeedRandom(ctx
.session
, seed
, (CK_ULONG
) cc
);
428 (void) isc_stdio_close(stream
);
429 pk11_return_session(&ctx
);
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
;
442 isc_result_t service_ret
= ISC_R_SUCCESS
;
444 UNUSED(need_services
);
447 memset(ctx
, 0, sizeof(pk11_context_t
));
449 ctx
->session
= CK_INVALID_HANDLE
;
451 ret
= pk11_initialize(NULL
, NULL
);
453 if (ret
== PK11_R_NORANDOMSERVICE
||
454 ret
== PK11_R_NODIGESTSERVICE
||
455 ret
== PK11_R_NOAESSERVICE
) {
461 #endif /* PKCS11CRYPTO */
462 if (ret
!= ISC_R_SUCCESS
)
466 /* wait for initialization to finish */
467 UNLOCK(&sessionlock
);
475 token
= digest_token
;
481 for (token
= ISC_LIST_HEAD(tokens
);
483 token
= ISC_LIST_NEXT(token
, link
))
484 if (token
->slotid
== slot
)
489 for (token
= ISC_LIST_HEAD(tokens
);
491 token
= ISC_LIST_NEXT(token
, link
))
492 if (token
->slotid
== slot
)
495 if ((token
== NULL
) ||
496 ((token
->operations
& (1 << optype
)) == 0))
497 return (ISC_R_NOTFOUND
);
502 return (ISC_R_NOTFOUND
);
504 /* Override the token's PIN */
505 if (logon
&& pin
!= NULL
&& *pin
!= '\0') {
506 if (strlen(pin
) > PINLEN
)
508 memset(token
->pin
, 0, PINLEN
+ 1);
509 strncpy(token
->pin
, pin
, PINLEN
);
512 freelist
= &token
->sessions
;
515 sp
= ISC_LIST_HEAD(*freelist
);
517 ISC_LIST_UNLINK(*freelist
, sp
, link
);
518 ISC_LIST_APPEND(actives
, sp
, link
);
519 UNLOCK(&sessionlock
);
521 ret
= token_login(sp
);
523 ctx
->session
= sp
->session
;
526 UNLOCK(&sessionlock
);
528 sp
= pk11_mem_get(sizeof(*sp
));
530 return (ISC_R_NOMEMORY
);
531 sp
->magic
= SES_MAGIC
;
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
);
539 ISC_LIST_APPEND(actives
, sp
, link
);
540 UNLOCK(&sessionlock
);
542 ctx
->session
= sp
->session
;
544 if (ret
== ISC_R_SUCCESS
)
551 pk11_return_session(pk11_context_t
*ctx
) {
552 pk11_session_t
*sp
= (pk11_session_t
*) ctx
->handle
;
557 ctx
->session
= CK_INVALID_HANDLE
;
560 ISC_LIST_UNLINK(actives
, sp
, link
);
561 UNLOCK(&sessionlock
);
562 if (sp
->session
== CK_INVALID_HANDLE
) {
563 pk11_mem_put(sp
, sizeof(*sp
));
568 ISC_LIST_APPEND(sp
->token
->sessions
, sp
, link
);
569 UNLOCK(&sessionlock
);
573 free_all_sessions(void) {
575 isc_result_t ret
= ISC_R_SUCCESS
;
578 for (token
= ISC_LIST_HEAD(tokens
);
580 token
= ISC_LIST_NEXT(token
, link
)) {
581 oret
= free_session_list(&token
->sessions
);
582 if (oret
!= ISC_R_SUCCESS
)
585 if (!ISC_LIST_EMPTY(actives
)) {
586 ret
= ISC_R_ADDRINUSE
;
587 oret
= free_session_list(&actives
);
588 if (oret
!= ISC_R_SUCCESS
)
595 free_session_list(pk11_sessionlist_t
*slist
) {
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
);
608 ret
= DST_R_CRYPTOFAILURE
;
611 ISC_LIST_UNLINK(*slist
, sp
, link
);
612 pk11_mem_put(sp
, sizeof(*sp
));
614 UNLOCK(&sessionlock
);
620 setup_session(pk11_session_t
*sp
, pk11_token_t
*token
,
624 CK_FLAGS flags
= CKF_SERIAL_SESSION
;
627 flags
+= CKF_RW_SESSION
;
629 rv
= pkcs_C_OpenSession(token
->slotid
, flags
, NULL_PTR
,
630 NULL_PTR
, &sp
->session
);
632 return (DST_R_CRYPTOFAILURE
);
633 return (ISC_R_SUCCESS
);
637 token_login(pk11_session_t
*sp
) {
639 pk11_token_t
*token
= sp
->token
;
640 isc_result_t ret
= ISC_R_SUCCESS
;
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
));
650 pk11_error_fatalcheck(__FILE__
, __LINE__
,
654 token
->logged
= ISC_TRUE
;
656 UNLOCK(&sessionlock
);
662 CK_MECHANISM_INFO mechInfo
;
663 CK_TOKEN_INFO tokenInfo
;
666 CK_SLOT_ID_PTR slotList
;
672 PK11_FATALCHECK(pkcs_C_GetSlotList
, (CK_FALSE
, NULL_PTR
, &slotCount
));
673 /* it's not an error if we didn't find any providers */
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
++) {
683 rv
= pkcs_C_GetTokenInfo(slot
, &tokenInfo
);
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)
699 token
->operations
|= 1 << OP_RAND
;
700 if (rand_token
== NULL
)
704 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_RSA_PKCS_KEY_PAIR_GEN
,
706 if ((rv
!= CKR_OK
) ||
707 ((mechInfo
.flags
& CKF_GENERATE_KEY_PAIR
) == 0))
709 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_MD5_RSA_PKCS
,
711 if ((rv
!= CKR_OK
) ||
712 ((mechInfo
.flags
& CKF_SIGN
) == 0) ||
713 ((mechInfo
.flags
& CKF_VERIFY
) == 0))
715 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_SHA1_RSA_PKCS
,
717 if ((rv
!= CKR_OK
) ||
718 ((mechInfo
.flags
& CKF_SIGN
) == 0) ||
719 ((mechInfo
.flags
& CKF_VERIFY
) == 0))
721 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_SHA256_RSA_PKCS
,
723 if ((rv
!= CKR_OK
) ||
724 ((mechInfo
.flags
& CKF_SIGN
) == 0) ||
725 ((mechInfo
.flags
& CKF_VERIFY
) == 0))
727 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_SHA512_RSA_PKCS
,
729 if ((rv
!= CKR_OK
) ||
730 ((mechInfo
.flags
& CKF_SIGN
) == 0) ||
731 ((mechInfo
.flags
& CKF_VERIFY
) == 0))
733 token
->operations
|= 1 << OP_RSA
;
734 if (best_rsa_token
== NULL
)
735 best_rsa_token
= token
;
738 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_DSA_PARAMETER_GEN
,
740 if ((rv
!= CKR_OK
) || ((mechInfo
.flags
& CKF_GENERATE
) == 0))
742 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_DSA_KEY_PAIR_GEN
,
744 if ((rv
!= CKR_OK
) ||
745 ((mechInfo
.flags
& CKF_GENERATE_KEY_PAIR
) == 0))
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))
752 token
->operations
|= 1 << OP_DSA
;
753 if (best_dsa_token
== NULL
)
754 best_dsa_token
= token
;
758 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_DH_PKCS_PARAMETER_GEN
,
760 if ((rv
!= CKR_OK
) || ((mechInfo
.flags
& CKF_GENERATE
) == 0))
763 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_DH_PKCS_KEY_PAIR_GEN
,
765 if ((rv
!= CKR_OK
) ||
766 ((mechInfo
.flags
& CKF_GENERATE_KEY_PAIR
) == 0))
768 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_DH_PKCS_DERIVE
,
770 if ((rv
!= CKR_OK
) || ((mechInfo
.flags
& CKF_DERIVE
) == 0))
772 token
->operations
|= 1 << OP_DH
;
773 if (best_dh_token
== NULL
)
774 best_dh_token
= token
;
777 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_MD5
, &mechInfo
);
778 if ((rv
!= CKR_OK
) || ((mechInfo
.flags
& CKF_DIGEST
) == 0))
780 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_SHA_1
, &mechInfo
);
781 if ((rv
!= CKR_OK
) || ((mechInfo
.flags
& CKF_DIGEST
) == 0))
783 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_SHA224
, &mechInfo
);
784 if ((rv
!= CKR_OK
) || ((mechInfo
.flags
& CKF_DIGEST
) == 0))
786 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_SHA256
, &mechInfo
);
787 if ((rv
!= CKR_OK
) || ((mechInfo
.flags
& CKF_DIGEST
) == 0))
789 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_SHA384
, &mechInfo
);
790 if ((rv
!= CKR_OK
) || ((mechInfo
.flags
& CKF_DIGEST
) == 0))
792 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_SHA512
, &mechInfo
);
793 if ((rv
!= CKR_OK
) || ((mechInfo
.flags
& CKF_DIGEST
) == 0))
795 #ifdef PKCS11CRYPTOWITHHMAC
796 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_MD5_HMAC
, &mechInfo
);
797 if ((rv
!= CKR_OK
) || ((mechInfo
.flags
& CKF_SIGN
) == 0))
800 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_SHA_1_HMAC
, &mechInfo
);
801 if ((rv
!= CKR_OK
) || ((mechInfo
.flags
& CKF_SIGN
) == 0))
803 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_SHA224_HMAC
, &mechInfo
);
804 if ((rv
!= CKR_OK
) || ((mechInfo
.flags
& CKF_SIGN
) == 0))
806 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_SHA256_HMAC
, &mechInfo
);
807 if ((rv
!= CKR_OK
) || ((mechInfo
.flags
& CKF_SIGN
) == 0))
809 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_SHA384_HMAC
, &mechInfo
);
810 if ((rv
!= CKR_OK
) || ((mechInfo
.flags
& CKF_SIGN
) == 0))
812 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_SHA512_HMAC
, &mechInfo
);
813 if ((rv
!= CKR_OK
) || ((mechInfo
.flags
& CKF_SIGN
) == 0))
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
,
822 if ((rv
!= CKR_OK
) ||
823 ((mechInfo
.flags
& CKF_GENERATE_KEY_PAIR
) == 0))
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))
830 token
->operations
|= 1 << OP_EC
;
831 if (best_ec_token
== NULL
)
832 best_ec_token
= token
;
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))
839 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_GOSTR3410_KEY_PAIR_GEN
,
841 if ((rv
!= CKR_OK
) ||
842 ((mechInfo
.flags
& CKF_GENERATE_KEY_PAIR
) == 0))
844 rv
= pkcs_C_GetMechanismInfo(slot
,
845 CKM_GOSTR3410_WITH_GOSTR3411
,
847 if ((rv
!= CKR_OK
) ||
848 ((mechInfo
.flags
& CKF_SIGN
) == 0) ||
849 ((mechInfo
.flags
& CKF_VERIFY
) == 0))
851 token
->operations
|= 1 << OP_GOST
;
852 if (best_gost_token
== NULL
)
853 best_gost_token
= token
;
856 rv
= pkcs_C_GetMechanismInfo(slot
, CKM_AES_ECB
, &mechInfo
);
857 if ((rv
!= CKR_OK
) || ((mechInfo
.flags
& CKF_ENCRYPT
) == 0))
859 token
->operations
|= 1 << OP_AES
;
860 if (aes_token
== NULL
)
864 if (slotList
!= NULL
)
865 pk11_mem_put(slotList
, sizeof(CK_SLOT_ID_PTR
) * slotCount
);
869 pk11_get_best_token(pk11_optype_t optype
) {
870 pk11_token_t
*token
= NULL
;
877 token
= best_rsa_token
;
880 token
= best_dsa_token
;
883 token
= best_dh_token
;
886 token
= digest_token
;
889 token
= best_ec_token
;
892 token
= best_gost_token
;
902 return (token
->slotid
);
906 pk11_numbits(CK_BYTE_PTR data
, unsigned int bytecnt
) {
907 unsigned int bitcnt
, i
;
912 bitcnt
= bytecnt
* 8;
913 for (i
= 0; i
< bytecnt
; i
++) {
941 pk11_attribute_first(const pk11_object_t
*obj
) {
946 pk11_attribute_next(const pk11_object_t
*obj
, CK_ATTRIBUTE
*attr
) {
950 if ((next
- obj
->repr
) >= obj
->attrcnt
)
956 pk11_attribute_bytype(const pk11_object_t
*obj
, CK_ATTRIBUTE_TYPE type
) {
959 for(attr
= pk11_attribute_first(obj
);
961 attr
= pk11_attribute_next(obj
, attr
))
962 if (attr
->type
== type
)
968 percent_decode(char *x
, size_t *len
) {
974 for (p
= c
= x
; p
[0] != '\0'; p
++, c
++) {
989 v
= (p
[1] - '0') << 4;
997 v
= (p
[1] - 'A' + 10) << 4;
1005 v
= (p
[1] - 'a' + 10) << 4;
1021 v
|= (p
[2] - '0') & 0x0f;
1029 v
= (p
[2] - 'A' + 10) & 0x0f;
1037 v
= (p
[2] - 'a' + 10) & 0x0f;
1054 static isc_boolean_t
1055 pk11strcmp(const char *x
, size_t lenx
, const char *y
, size_t leny
) {
1058 INSIST((leny
== 32) || (leny
== 16));
1060 memset(buf
, ' ', 32);
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
;
1071 CK_BYTE cnt
= obj
->attrcnt
;
1073 obj
->repr
= isc_mem_get(mctx
, (cnt
+ 1) * sizeof(*attr
));
1074 if (obj
->repr
== 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
));
1089 memset(attr
->pValue
, 0, len
);
1091 memset(old
, 0, cnt
* sizeof(*attr
));
1092 isc_mem_put(mctx
, old
, cnt
* sizeof(*attr
));
1098 #define DST_RET(a) { ret = a; goto err; }
1101 pk11_parse_uri(pk11_object_t
*obj
, const char *label
,
1102 isc_mem_t
*mctx
, pk11_optype_t optype
)
1105 pk11_token_t
*token
= NULL
;
1106 char *uri
, *p
, *a
, *na
, *v
;
1108 FILE *stream
= NULL
;
1109 char pin
[PINLEN
+ 1];
1110 isc_boolean_t gotpin
= ISC_FALSE
;
1113 /* get values to work on */
1114 len
= strlen(label
) + 1;
1115 uri
= isc_mem_get(mctx
, len
);
1117 return (ISC_R_NOMEMORY
);
1118 memmove(uri
, label
, len
);
1120 /* get the URI scheme */
1121 p
= strchr(uri
, ':');
1123 DST_RET(PK11_R_NOPROVIDER
);
1125 if (strcmp(uri
, "pkcs11") != 0)
1126 DST_RET(PK11_R_NOPROVIDER
);
1128 /* get attributes */
1129 for (na
= p
; na
!= NULL
;) {
1133 /* last attribute */
1146 v
= percent_decode(v
, &l
);
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
);
1153 DST_RET(PK11_R_NOPROVIDER
);
1154 attr
= push_attribute(obj
, mctx
, l
);
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 */
1162 for (token
= ISC_LIST_HEAD(tokens
);
1164 token
= ISC_LIST_NEXT(token
, link
))
1165 if (pk11strcmp(v
, l
, token
->name
, 32))
1167 } else if (strcmp(a
, "manufacturer") == 0) {
1168 /* manufacturer: CK_TOKEN_INFO manufacturerID */
1170 for (token
= ISC_LIST_HEAD(tokens
);
1172 token
= ISC_LIST_NEXT(token
, link
))
1173 if (pk11strcmp(v
, l
, token
->manuf
, 32))
1175 } else if (strcmp(a
, "serial") == 0) {
1176 /* serial: CK_TOKEN_INFO serialNumber */
1178 for (token
= ISC_LIST_HEAD(tokens
);
1180 token
= ISC_LIST_NEXT(token
, link
))
1181 if (pk11strcmp(v
, l
, token
->serial
, 16))
1183 } else if (strcmp(a
, "model") == 0) {
1184 /* model: CK_TOKEN_INFO model */
1186 for (token
= ISC_LIST_HEAD(tokens
);
1188 token
= ISC_LIST_NEXT(token
, link
))
1189 if (pk11strcmp(v
, l
, token
->model
, 16))
1191 } else if (strcmp(a
, "library-manufacturer") == 0) {
1193 } else if (strcmp(a
, "library-description") == 0) {
1195 } else if (strcmp(a
, "library-version") == 0) {
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) {
1204 attr
= pk11_attribute_bytype(obj
, CKA_ID
);
1206 DST_RET(PK11_R_NOPROVIDER
);
1207 attr
= push_attribute(obj
, mctx
, l
);
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
)
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
))
1222 DST_RET(ISC_R_RANGE
);
1223 ret
= isc_stdio_close(stream
);
1225 if (ret
!= ISC_R_SUCCESS
)
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
;
1247 DST_RET(ISC_R_NOTFOUND
);
1248 obj
->slot
= token
->slotid
;
1250 memmove(token
->pin
, pin
, PINLEN
+ 1);
1251 obj
->reqlogon
= ISC_TRUE
;
1254 ret
= ISC_R_SUCCESS
;
1258 (void) isc_stdio_close(stream
);
1259 isc_mem_put(mctx
, uri
, len
);
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
);
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
);
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
);
1298 if (token
->operations
& (1 << OP_RAND
)) {
1304 if (token
->operations
& (1 << OP_RSA
)) {
1310 if (token
->operations
& (1 << OP_DSA
)) {
1316 if (token
->operations
& (1 << OP_DH
)) {
1322 if (token
->operations
& (1 << OP_DIGEST
)) {
1328 if (token
->operations
& (1 << OP_EC
)) {