xref: /onnv-gate/usr/src/common/openssl/crypto/engine/hw_pk11.c (revision 7616:c4c6b4767487)
10Sstevel@tonic-gate /*
26847Svk199839  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
50Sstevel@tonic-gate 
60Sstevel@tonic-gate /* crypto/engine/hw_pk11.c */
7*7616SVladimir.Kotal@Sun.COM /*
8*7616SVladimir.Kotal@Sun.COM  * This product includes software developed by the OpenSSL Project for
90Sstevel@tonic-gate  * use in the OpenSSL Toolkit (http://www.openssl.org/).
100Sstevel@tonic-gate  *
11*7616SVladimir.Kotal@Sun.COM  * This project also referenced hw_pkcs11-0.9.7b.patch written by
120Sstevel@tonic-gate  * Afchine Madjlessi.
130Sstevel@tonic-gate  */
14*7616SVladimir.Kotal@Sun.COM /*
15*7616SVladimir.Kotal@Sun.COM  * ====================================================================
160Sstevel@tonic-gate  * Copyright (c) 2000-2001 The OpenSSL Project.  All rights reserved.
170Sstevel@tonic-gate  *
180Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
190Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
200Sstevel@tonic-gate  * are met:
210Sstevel@tonic-gate  *
220Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
23*7616SVladimir.Kotal@Sun.COM  *    notice, this list of conditions and the following disclaimer.
240Sstevel@tonic-gate  *
250Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
260Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in
270Sstevel@tonic-gate  *    the documentation and/or other materials provided with the
280Sstevel@tonic-gate  *    distribution.
290Sstevel@tonic-gate  *
300Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this
310Sstevel@tonic-gate  *    software must display the following acknowledgment:
320Sstevel@tonic-gate  *    "This product includes software developed by the OpenSSL Project
330Sstevel@tonic-gate  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
340Sstevel@tonic-gate  *
350Sstevel@tonic-gate  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
360Sstevel@tonic-gate  *    endorse or promote products derived from this software without
370Sstevel@tonic-gate  *    prior written permission. For written permission, please contact
380Sstevel@tonic-gate  *    licensing@OpenSSL.org.
390Sstevel@tonic-gate  *
400Sstevel@tonic-gate  * 5. Products derived from this software may not be called "OpenSSL"
410Sstevel@tonic-gate  *    nor may "OpenSSL" appear in their names without prior written
420Sstevel@tonic-gate  *    permission of the OpenSSL Project.
430Sstevel@tonic-gate  *
440Sstevel@tonic-gate  * 6. Redistributions of any form whatsoever must retain the following
450Sstevel@tonic-gate  *    acknowledgment:
460Sstevel@tonic-gate  *    "This product includes software developed by the OpenSSL Project
470Sstevel@tonic-gate  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
480Sstevel@tonic-gate  *
490Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
500Sstevel@tonic-gate  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
510Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
520Sstevel@tonic-gate  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
530Sstevel@tonic-gate  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
540Sstevel@tonic-gate  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
550Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
560Sstevel@tonic-gate  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
570Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
580Sstevel@tonic-gate  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
590Sstevel@tonic-gate  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
600Sstevel@tonic-gate  * OF THE POSSIBILITY OF SUCH DAMAGE.
610Sstevel@tonic-gate  * ====================================================================
620Sstevel@tonic-gate  *
630Sstevel@tonic-gate  * This product includes cryptographic software written by Eric Young
640Sstevel@tonic-gate  * (eay@cryptsoft.com).  This product includes software written by Tim
650Sstevel@tonic-gate  * Hudson (tjh@cryptsoft.com).
660Sstevel@tonic-gate  *
670Sstevel@tonic-gate  */
680Sstevel@tonic-gate 
690Sstevel@tonic-gate #include <stdio.h>
700Sstevel@tonic-gate #include <stdlib.h>
710Sstevel@tonic-gate #include <string.h>
720Sstevel@tonic-gate #include <sys/types.h>
730Sstevel@tonic-gate #include <unistd.h>
740Sstevel@tonic-gate 
750Sstevel@tonic-gate #include <openssl/e_os2.h>
766847Svk199839 #include <openssl/crypto.h>
770Sstevel@tonic-gate #include <openssl/engine.h>
780Sstevel@tonic-gate #include <openssl/dso.h>
790Sstevel@tonic-gate #include <openssl/err.h>
800Sstevel@tonic-gate #include <openssl/bn.h>
812139Sjp161948 #include <openssl/md5.h>
820Sstevel@tonic-gate #include <openssl/pem.h>
836847Svk199839 #ifndef OPENSSL_NO_RSA
840Sstevel@tonic-gate #include <openssl/rsa.h>
856847Svk199839 #endif
866847Svk199839 #ifndef OPENSSL_NO_DSA
876847Svk199839 #include <openssl/dsa.h>
886847Svk199839 #endif
896847Svk199839 #ifndef OPENSSL_NO_DH
906847Svk199839 #include <openssl/dh.h>
916847Svk199839 #endif
920Sstevel@tonic-gate #include <openssl/rand.h>
930Sstevel@tonic-gate #include <openssl/objects.h>
940Sstevel@tonic-gate #include <openssl/x509.h>
957211Sjp161948 #include <openssl/aes.h>
960Sstevel@tonic-gate #include <cryptlib.h>
977211Sjp161948 #include <dlfcn.h>
987526SVladimir.Kotal@Sun.COM #include <pthread.h>
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate #ifndef OPENSSL_NO_HW
1010Sstevel@tonic-gate #ifndef OPENSSL_NO_HW_PK11
1020Sstevel@tonic-gate 
1037211Sjp161948 /* label for debug messages printed on stderr */
1047211Sjp161948 #define	PK11_DBG	"PKCS#11 ENGINE DEBUG"
1057211Sjp161948 /* prints a lot of debug messages on stderr about slot selection process */
1067211Sjp161948 #undef	DEBUG_SLOT_SELECTION
1077211Sjp161948 /*
1087211Sjp161948  * Solaris specific code. See comment at check_hw_mechanisms() for more
1097211Sjp161948  * information.
1107211Sjp161948  */
1117211Sjp161948 #define	SOLARIS_HW_SLOT_SELECTION
1127211Sjp161948 
1137211Sjp161948 /*
1147211Sjp161948  * AES counter mode is not supported in the OpenSSL EVP API yet and neither
1157211Sjp161948  * there are official OIDs for mechanisms based on this mode. With our changes,
1167211Sjp161948  * an application can define its own EVP calls for AES counter mode and then
1177211Sjp161948  * it can make use of hardware acceleration through this engine. However, it's
1187211Sjp161948  * better if we keep AES CTR support code under ifdef's.
1197211Sjp161948  */
1207211Sjp161948 #define	SOLARIS_AES_CTR
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate #include "security/cryptoki.h"
1230Sstevel@tonic-gate #include "security/pkcs11.h"
1240Sstevel@tonic-gate #include "hw_pk11_err.c"
1250Sstevel@tonic-gate 
1267211Sjp161948 #ifdef	SOLARIS_AES_CTR
1277211Sjp161948 /*
1287211Sjp161948  * NIDs for AES counter mode that will be defined during the engine
1297211Sjp161948  * initialization.
1307211Sjp161948  */
1317211Sjp161948 int NID_aes_128_ctr = NID_undef;
1327211Sjp161948 int NID_aes_192_ctr = NID_undef;
1337211Sjp161948 int NID_aes_256_ctr = NID_undef;
1347211Sjp161948 #endif	/* SOLARIS_AES_CTR */
1357211Sjp161948 
1367211Sjp161948 #ifdef	SOLARIS_HW_SLOT_SELECTION
1377211Sjp161948 /*
1387211Sjp161948  * Tables for symmetric ciphers and digest mechs found in the pkcs11_kernel
1397211Sjp161948  * library. See comment at check_hw_mechanisms() for more information.
1407211Sjp161948  */
1417211Sjp161948 int *hw_cnids;
1427211Sjp161948 int *hw_dnids;
1437211Sjp161948 #endif	/* SOLARIS_HW_SLOT_SELECTION */
1447211Sjp161948 
1457526SVladimir.Kotal@Sun.COM /* PKCS#11 session caches and their locks for all operation types */
1467526SVladimir.Kotal@Sun.COM static PK11_CACHE session_cache[OP_MAX];
1477526SVladimir.Kotal@Sun.COM 
1487211Sjp161948 /*
1497526SVladimir.Kotal@Sun.COM  * As stated in v2.20, 11.7 Object Management Function, in section for
1507526SVladimir.Kotal@Sun.COM  * C_FindObjectsInit(), at most one search operation may be active at a given
1517526SVladimir.Kotal@Sun.COM  * time in a given session. Therefore, C_Find{,Init,Final}Objects() should be
1527526SVladimir.Kotal@Sun.COM  * grouped together to form one atomic search operation. This is already
1537526SVladimir.Kotal@Sun.COM  * ensured by the property of unique PKCS#11 session handle used for each
1547526SVladimir.Kotal@Sun.COM  * PK11_SESSION object.
1557526SVladimir.Kotal@Sun.COM  *
1567526SVladimir.Kotal@Sun.COM  * This is however not the biggest concern - maintaining consistency of the
1577526SVladimir.Kotal@Sun.COM  * underlying object store is more important. The same section of the spec also
1587526SVladimir.Kotal@Sun.COM  * says that one thread can be in the middle of a search operation while another
1597526SVladimir.Kotal@Sun.COM  * thread destroys the object matching the search template which would result in
1607526SVladimir.Kotal@Sun.COM  * invalid handle returned from the search operation.
1617526SVladimir.Kotal@Sun.COM  *
1627526SVladimir.Kotal@Sun.COM  * Hence, the following locks are used for both protection of the object stores.
1637526SVladimir.Kotal@Sun.COM  * They are also used for active list protection.
1647211Sjp161948  */
1657526SVladimir.Kotal@Sun.COM pthread_mutex_t *find_lock[OP_MAX] = { NULL };
1667526SVladimir.Kotal@Sun.COM 
1677526SVladimir.Kotal@Sun.COM /*
1687526SVladimir.Kotal@Sun.COM  * lists of asymmetric key handles which are active (referenced by at least one
1697526SVladimir.Kotal@Sun.COM  * PK11_SESSION structure, either held by a thread or present in free_session
1707526SVladimir.Kotal@Sun.COM  * list) for given algorithm type
1717526SVladimir.Kotal@Sun.COM  */
1727526SVladimir.Kotal@Sun.COM PK11_active *active_list[OP_MAX] = { NULL };
1737526SVladimir.Kotal@Sun.COM 
1747526SVladimir.Kotal@Sun.COM /*
1757526SVladimir.Kotal@Sun.COM  * Create all secret key objects in a global session so that they are available
1760Sstevel@tonic-gate  * to use for other sessions. These other sessions may be opened or closed
1777526SVladimir.Kotal@Sun.COM  * without losing the secret key objects.
1787526SVladimir.Kotal@Sun.COM  */
1790Sstevel@tonic-gate static CK_SESSION_HANDLE	global_session = CK_INVALID_HANDLE;
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate /* ENGINE level stuff */
1820Sstevel@tonic-gate static int pk11_init(ENGINE *e);
1830Sstevel@tonic-gate static int pk11_library_init(ENGINE *e);
1840Sstevel@tonic-gate static int pk11_finish(ENGINE *e);
1850Sstevel@tonic-gate static int pk11_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)());
1860Sstevel@tonic-gate static int pk11_destroy(ENGINE *e);
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate /* RAND stuff */
1890Sstevel@tonic-gate static void pk11_rand_seed(const void *buf, int num);
1900Sstevel@tonic-gate static void pk11_rand_add(const void *buf, int num, double add_entropy);
1910Sstevel@tonic-gate static void pk11_rand_cleanup(void);
1920Sstevel@tonic-gate static int pk11_rand_bytes(unsigned char *buf, int num);
1930Sstevel@tonic-gate static int pk11_rand_status(void);
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate /* These functions are also used in other files */
1967211Sjp161948 PK11_SESSION *pk11_get_session(PK11_OPTYPE optype);
1977211Sjp161948 void pk11_return_session(PK11_SESSION *sp, PK11_OPTYPE optype);
1986847Svk199839 
1997526SVladimir.Kotal@Sun.COM /* active list manipulation functions used in this file */
2007526SVladimir.Kotal@Sun.COM extern int pk11_active_delete(CK_OBJECT_HANDLE h, PK11_OPTYPE type);
2017526SVladimir.Kotal@Sun.COM extern void pk11_free_active_list(PK11_OPTYPE type);
2026847Svk199839 
2036847Svk199839 #ifndef OPENSSL_NO_RSA
2040Sstevel@tonic-gate int pk11_destroy_rsa_key_objects(PK11_SESSION *session);
2056847Svk199839 int pk11_destroy_rsa_object_pub(PK11_SESSION *sp, CK_BBOOL uselock);
2066847Svk199839 int pk11_destroy_rsa_object_priv(PK11_SESSION *sp, CK_BBOOL uselock);
2076847Svk199839 #endif
2086847Svk199839 #ifndef OPENSSL_NO_DSA
2090Sstevel@tonic-gate int pk11_destroy_dsa_key_objects(PK11_SESSION *session);
2106847Svk199839 int pk11_destroy_dsa_object_pub(PK11_SESSION *sp, CK_BBOOL uselock);
2116847Svk199839 int pk11_destroy_dsa_object_priv(PK11_SESSION *sp, CK_BBOOL uselock);
2126847Svk199839 #endif
2136847Svk199839 #ifndef OPENSSL_NO_DH
2140Sstevel@tonic-gate int pk11_destroy_dh_key_objects(PK11_SESSION *session);
2156847Svk199839 int pk11_destroy_dh_object(PK11_SESSION *session, CK_BBOOL uselock);
2166847Svk199839 #endif
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate /* Local helper functions */
2197211Sjp161948 static int pk11_free_all_sessions(void);
2207526SVladimir.Kotal@Sun.COM static int pk11_free_session_list(PK11_OPTYPE optype);
2217211Sjp161948 static int pk11_setup_session(PK11_SESSION *sp, PK11_OPTYPE optype);
2220Sstevel@tonic-gate static int pk11_destroy_cipher_key_objects(PK11_SESSION *session);
2236847Svk199839 static int pk11_destroy_object(CK_SESSION_HANDLE session,
2240Sstevel@tonic-gate 	CK_OBJECT_HANDLE oh);
2250Sstevel@tonic-gate static const char *get_PK11_LIBNAME(void);
2260Sstevel@tonic-gate static void free_PK11_LIBNAME(void);
2270Sstevel@tonic-gate static long set_PK11_LIBNAME(const char *name);
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate /* Symmetric cipher and digest support functions */
2300Sstevel@tonic-gate static int cipher_nid_to_pk11(int nid);
2317211Sjp161948 #ifdef	SOLARIS_AES_CTR
2327211Sjp161948 static int pk11_add_NID(char *sn, char *ln);
2337211Sjp161948 static int pk11_add_aes_ctr_NIDs(void);
2347211Sjp161948 #endif	/* SOLARIS_AES_CTR */
2350Sstevel@tonic-gate static int pk11_usable_ciphers(const int **nids);
2360Sstevel@tonic-gate static int pk11_usable_digests(const int **nids);
2370Sstevel@tonic-gate static int pk11_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
2380Sstevel@tonic-gate 	const unsigned char *iv, int enc);
2390Sstevel@tonic-gate static int pk11_cipher_final(PK11_SESSION *sp);
2400Sstevel@tonic-gate static int pk11_cipher_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
2410Sstevel@tonic-gate 	const unsigned char *in, unsigned int inl);
2420Sstevel@tonic-gate static int pk11_cipher_cleanup(EVP_CIPHER_CTX *ctx);
2430Sstevel@tonic-gate static int pk11_engine_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
2440Sstevel@tonic-gate 	const int **nids, int nid);
2450Sstevel@tonic-gate static int pk11_engine_digests(ENGINE *e, const EVP_MD **digest,
2460Sstevel@tonic-gate 	const int **nids, int nid);
247*7616SVladimir.Kotal@Sun.COM static CK_OBJECT_HANDLE pk11_get_cipher_key(EVP_CIPHER_CTX *ctx,
2480Sstevel@tonic-gate 	const unsigned char *key, CK_KEY_TYPE key_type, PK11_SESSION *sp);
2497211Sjp161948 static int check_new_cipher_key(PK11_SESSION *sp, const unsigned char *key,
2507211Sjp161948 	int key_len);
2510Sstevel@tonic-gate static int md_nid_to_pk11(int nid);
2520Sstevel@tonic-gate static int pk11_digest_init(EVP_MD_CTX *ctx);
253*7616SVladimir.Kotal@Sun.COM static int pk11_digest_update(EVP_MD_CTX *ctx, const void *data,
2542139Sjp161948 	size_t count);
255*7616SVladimir.Kotal@Sun.COM static int pk11_digest_final(EVP_MD_CTX *ctx, unsigned char *md);
256*7616SVladimir.Kotal@Sun.COM static int pk11_digest_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from);
2570Sstevel@tonic-gate static int pk11_digest_cleanup(EVP_MD_CTX *ctx);
2580Sstevel@tonic-gate 
2597211Sjp161948 static int pk11_choose_slots(int *any_slot_found);
2607211Sjp161948 static void pk11_find_symmetric_ciphers(CK_FUNCTION_LIST_PTR pflist,
2617211Sjp161948     CK_SLOT_ID current_slot, int *current_slot_n_cipher,
2627211Sjp161948     int *local_cipher_nids);
2637211Sjp161948 static void pk11_find_digests(CK_FUNCTION_LIST_PTR pflist,
2647211Sjp161948     CK_SLOT_ID current_slot, int *current_slot_n_digest,
2657211Sjp161948     int *local_digest_nids);
2667211Sjp161948 static void pk11_get_symmetric_cipher(CK_FUNCTION_LIST_PTR, int slot_id,
2677211Sjp161948     CK_MECHANISM_TYPE mech, int *current_slot_n_cipher, int *local_cipher_nids,
2687211Sjp161948     int id);
2697211Sjp161948 static void pk11_get_digest(CK_FUNCTION_LIST_PTR pflist, int slot_id,
2707211Sjp161948     CK_MECHANISM_TYPE mech, int *current_slot_n_digest, int *local_digest_nids,
2717211Sjp161948     int id);
2727211Sjp161948 
2737526SVladimir.Kotal@Sun.COM static int pk11_init_all_locks(void);
2747526SVladimir.Kotal@Sun.COM static void pk11_free_all_locks(void);
2757526SVladimir.Kotal@Sun.COM 
2767211Sjp161948 #ifdef	SOLARIS_HW_SLOT_SELECTION
2777211Sjp161948 static int check_hw_mechanisms(void);
2787211Sjp161948 static int nid_in_table(int nid, int *nid_table);
2797211Sjp161948 #endif	/* SOLARIS_HW_SLOT_SELECTION */
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate /* Index for the supported ciphers */
2827211Sjp161948 enum pk11_cipher_id {
2837211Sjp161948 	PK11_DES_CBC,
2847211Sjp161948 	PK11_DES3_CBC,
2857211Sjp161948 	PK11_DES_ECB,
2867211Sjp161948 	PK11_DES3_ECB,
2877211Sjp161948 	PK11_RC4,
2887211Sjp161948 	PK11_AES_128_CBC,
2897211Sjp161948 	PK11_AES_192_CBC,
2907211Sjp161948 	PK11_AES_256_CBC,
2917211Sjp161948 	PK11_AES_128_ECB,
2927211Sjp161948 	PK11_AES_192_ECB,
2937211Sjp161948 	PK11_AES_256_ECB,
2947211Sjp161948 	PK11_BLOWFISH_CBC,
2957211Sjp161948 #ifdef	SOLARIS_AES_CTR
2967211Sjp161948 	PK11_AES_128_CTR,
2977211Sjp161948 	PK11_AES_192_CTR,
2987211Sjp161948 	PK11_AES_256_CTR,
2997211Sjp161948 #endif	/* SOLARIS_AES_CTR */
3007211Sjp161948 	PK11_CIPHER_MAX
3017211Sjp161948 };
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate /* Index for the supported digests */
3047211Sjp161948 enum pk11_digest_id {
3057211Sjp161948 	PK11_MD5,
3067211Sjp161948 	PK11_SHA1,
3077211Sjp161948 	PK11_SHA224,
3087211Sjp161948 	PK11_SHA256,
3097211Sjp161948 	PK11_SHA384,
3107211Sjp161948 	PK11_SHA512,
3117211Sjp161948 	PK11_DIGEST_MAX
3127211Sjp161948 };
3130Sstevel@tonic-gate 
3147526SVladimir.Kotal@Sun.COM #define	TRY_OBJ_DESTROY(sess_hdl, obj_hdl, retval, uselock, alg_type)	\
3156847Svk199839 	{								\
3166847Svk199839 	if (uselock)							\
3177526SVladimir.Kotal@Sun.COM 		LOCK_OBJSTORE(alg_type);				\
3187526SVladimir.Kotal@Sun.COM 	if (pk11_active_delete(obj_hdl, alg_type) == 1)			\
3196847Svk199839 		{							\
3206847Svk199839 		retval = pk11_destroy_object(sess_hdl, obj_hdl);	\
3216847Svk199839 		}							\
3226847Svk199839 	if (uselock)							\
3237526SVladimir.Kotal@Sun.COM 		UNLOCK_OBJSTORE(alg_type);				\
3246847Svk199839 	}
3256847Svk199839 
3260Sstevel@tonic-gate static int cipher_nids[PK11_CIPHER_MAX];
3270Sstevel@tonic-gate static int digest_nids[PK11_DIGEST_MAX];
3280Sstevel@tonic-gate static int cipher_count		= 0;
3290Sstevel@tonic-gate static int digest_count		= 0;
3300Sstevel@tonic-gate static CK_BBOOL pk11_have_rsa	= CK_FALSE;
3310Sstevel@tonic-gate static CK_BBOOL pk11_have_dsa	= CK_FALSE;
3320Sstevel@tonic-gate static CK_BBOOL pk11_have_dh	= CK_FALSE;
3330Sstevel@tonic-gate static CK_BBOOL pk11_have_random = CK_FALSE;
3340Sstevel@tonic-gate 
335*7616SVladimir.Kotal@Sun.COM typedef struct PK11_CIPHER_st
3360Sstevel@tonic-gate 	{
3377211Sjp161948 	enum pk11_cipher_id	id;
3384320Sjp161948 	int			nid;
3397211Sjp161948 	int			iv_len;
3404320Sjp161948 	int			key_len;
3414320Sjp161948 	CK_KEY_TYPE		key_type;
3424320Sjp161948 	CK_MECHANISM_TYPE	mech_type;
3430Sstevel@tonic-gate 	} PK11_CIPHER;
3440Sstevel@tonic-gate 
345*7616SVladimir.Kotal@Sun.COM static PK11_CIPHER ciphers[] =
3460Sstevel@tonic-gate 	{
347*7616SVladimir.Kotal@Sun.COM 	{ PK11_DES_CBC,		NID_des_cbc,		8,	8,
348*7616SVladimir.Kotal@Sun.COM 		CKK_DES,	CKM_DES_CBC, },
349*7616SVladimir.Kotal@Sun.COM 	{ PK11_DES3_CBC,	NID_des_ede3_cbc,	8,	24,
350*7616SVladimir.Kotal@Sun.COM 		CKK_DES3,	CKM_DES3_CBC, },
351*7616SVladimir.Kotal@Sun.COM 	{ PK11_DES_ECB,		NID_des_ecb,		0,	8,
352*7616SVladimir.Kotal@Sun.COM 		CKK_DES,	CKM_DES_ECB, },
353*7616SVladimir.Kotal@Sun.COM 	{ PK11_DES3_ECB,	NID_des_ede3_ecb,	0,	24,
354*7616SVladimir.Kotal@Sun.COM 		CKK_DES3,	CKM_DES3_ECB, },
355*7616SVladimir.Kotal@Sun.COM 	{ PK11_RC4,		NID_rc4,		0,	16,
356*7616SVladimir.Kotal@Sun.COM 		CKK_RC4,	CKM_RC4, },
357*7616SVladimir.Kotal@Sun.COM 	{ PK11_AES_128_CBC,	NID_aes_128_cbc,	16,	16,
358*7616SVladimir.Kotal@Sun.COM 		CKK_AES,	CKM_AES_CBC, },
359*7616SVladimir.Kotal@Sun.COM 	{ PK11_AES_192_CBC,	NID_aes_192_cbc,	16,	24,
360*7616SVladimir.Kotal@Sun.COM 		CKK_AES,	CKM_AES_CBC, },
361*7616SVladimir.Kotal@Sun.COM 	{ PK11_AES_256_CBC,	NID_aes_256_cbc,	16,	32,
362*7616SVladimir.Kotal@Sun.COM 		CKK_AES,	CKM_AES_CBC, },
363*7616SVladimir.Kotal@Sun.COM 	{ PK11_AES_128_ECB,	NID_aes_128_ecb,	0,	16,
364*7616SVladimir.Kotal@Sun.COM 		CKK_AES,	CKM_AES_ECB, },
365*7616SVladimir.Kotal@Sun.COM 	{ PK11_AES_192_ECB,	NID_aes_192_ecb,	0,	24,
366*7616SVladimir.Kotal@Sun.COM 		CKK_AES,	CKM_AES_ECB, },
367*7616SVladimir.Kotal@Sun.COM 	{ PK11_AES_256_ECB,	NID_aes_256_ecb,	0,	32,
368*7616SVladimir.Kotal@Sun.COM 		CKK_AES,	CKM_AES_ECB, },
369*7616SVladimir.Kotal@Sun.COM 	{ PK11_BLOWFISH_CBC,	NID_bf_cbc,		8,	16,
370*7616SVladimir.Kotal@Sun.COM 		CKK_BLOWFISH,	CKM_BLOWFISH_CBC, },
3717211Sjp161948 #ifdef	SOLARIS_AES_CTR
3727211Sjp161948 	/* we don't know the correct NIDs until the engine is initialized */
373*7616SVladimir.Kotal@Sun.COM 	{ PK11_AES_128_CTR,	NID_undef,		16,	16,
374*7616SVladimir.Kotal@Sun.COM 		CKK_AES,	CKM_AES_CTR, },
375*7616SVladimir.Kotal@Sun.COM 	{ PK11_AES_192_CTR,	NID_undef,		16,	24,
376*7616SVladimir.Kotal@Sun.COM 		CKK_AES,	CKM_AES_CTR, },
377*7616SVladimir.Kotal@Sun.COM 	{ PK11_AES_256_CTR,	NID_undef,		16,	32,
378*7616SVladimir.Kotal@Sun.COM 		CKK_AES,	CKM_AES_CTR, },
3797211Sjp161948 #endif	/* SOLARIS_AES_CTR */
3800Sstevel@tonic-gate 	};
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate typedef struct PK11_DIGEST_st
3830Sstevel@tonic-gate 	{
3847211Sjp161948 	enum pk11_digest_id	id;
3854320Sjp161948 	int			nid;
3864320Sjp161948 	CK_MECHANISM_TYPE	mech_type;
3870Sstevel@tonic-gate 	} PK11_DIGEST;
3880Sstevel@tonic-gate 
389*7616SVladimir.Kotal@Sun.COM static PK11_DIGEST digests[] =
3900Sstevel@tonic-gate 	{
3914320Sjp161948 	{PK11_MD5,	NID_md5,	CKM_MD5, },
3924320Sjp161948 	{PK11_SHA1,	NID_sha1,	CKM_SHA_1, },
3937211Sjp161948 	{PK11_SHA224,	NID_sha224,	CKM_SHA224, },
3947211Sjp161948 	{PK11_SHA256,	NID_sha256,	CKM_SHA256, },
3957211Sjp161948 	{PK11_SHA384,	NID_sha384,	CKM_SHA384, },
3967211Sjp161948 	{PK11_SHA512,	NID_sha512,	CKM_SHA512, },
3974320Sjp161948 	{0,		NID_undef,	0xFFFF, },
3980Sstevel@tonic-gate 	};
3990Sstevel@tonic-gate 
400*7616SVladimir.Kotal@Sun.COM /*
401*7616SVladimir.Kotal@Sun.COM  * Structure to be used for the cipher_data/md_data in
402*7616SVladimir.Kotal@Sun.COM  * EVP_CIPHER_CTX/EVP_MD_CTX structures in order to use the same pk11
403*7616SVladimir.Kotal@Sun.COM  * session in multiple cipher_update calls
4040Sstevel@tonic-gate  */
4050Sstevel@tonic-gate typedef struct PK11_CIPHER_STATE_st
4060Sstevel@tonic-gate 	{
4070Sstevel@tonic-gate 	PK11_SESSION	*sp;
4080Sstevel@tonic-gate 	} PK11_CIPHER_STATE;
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 
4117211Sjp161948 /*
4127211Sjp161948  * libcrypto EVP stuff - this is how we get wired to EVP so the engine gets
4137211Sjp161948  * called when libcrypto requests a cipher NID.
4147211Sjp161948  *
4150Sstevel@tonic-gate  * Note how the PK11_CIPHER_STATE is used here.
4160Sstevel@tonic-gate  */
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate /* DES CBC EVP */
419*7616SVladimir.Kotal@Sun.COM static const EVP_CIPHER pk11_des_cbc =
4200Sstevel@tonic-gate 	{
4210Sstevel@tonic-gate 	NID_des_cbc,
4220Sstevel@tonic-gate 	8, 8, 8,
4230Sstevel@tonic-gate 	EVP_CIPH_CBC_MODE,
4240Sstevel@tonic-gate 	pk11_cipher_init,
4250Sstevel@tonic-gate 	pk11_cipher_do_cipher,
4260Sstevel@tonic-gate 	pk11_cipher_cleanup,
427*7616SVladimir.Kotal@Sun.COM 	sizeof (PK11_CIPHER_STATE),
4280Sstevel@tonic-gate 	EVP_CIPHER_set_asn1_iv,
4290Sstevel@tonic-gate 	EVP_CIPHER_get_asn1_iv,
4300Sstevel@tonic-gate 	NULL
4310Sstevel@tonic-gate 	};
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate /* 3DES CBC EVP */
434*7616SVladimir.Kotal@Sun.COM static const EVP_CIPHER pk11_3des_cbc =
4350Sstevel@tonic-gate 	{
4360Sstevel@tonic-gate 	NID_des_ede3_cbc,
4370Sstevel@tonic-gate 	8, 24, 8,
4380Sstevel@tonic-gate 	EVP_CIPH_CBC_MODE,
4390Sstevel@tonic-gate 	pk11_cipher_init,
4400Sstevel@tonic-gate 	pk11_cipher_do_cipher,
4410Sstevel@tonic-gate 	pk11_cipher_cleanup,
442*7616SVladimir.Kotal@Sun.COM 	sizeof (PK11_CIPHER_STATE),
4430Sstevel@tonic-gate 	EVP_CIPHER_set_asn1_iv,
4440Sstevel@tonic-gate 	EVP_CIPHER_get_asn1_iv,
4450Sstevel@tonic-gate 	NULL
4460Sstevel@tonic-gate 	};
4470Sstevel@tonic-gate 
4487211Sjp161948 /*
4497211Sjp161948  * ECB modes don't use an Initial Vector so that's why set_asn1_parameters and
4507211Sjp161948  * get_asn1_parameters fields are set to NULL.
4517211Sjp161948  */
452*7616SVladimir.Kotal@Sun.COM static const EVP_CIPHER pk11_des_ecb =
4537211Sjp161948 	{
4547211Sjp161948 	NID_des_ecb,
4557211Sjp161948 	8, 8, 8,
4567211Sjp161948 	EVP_CIPH_ECB_MODE,
4577211Sjp161948 	pk11_cipher_init,
4587211Sjp161948 	pk11_cipher_do_cipher,
4597211Sjp161948 	pk11_cipher_cleanup,
460*7616SVladimir.Kotal@Sun.COM 	sizeof (PK11_CIPHER_STATE),
4617211Sjp161948 	NULL,
4627211Sjp161948 	NULL,
4637211Sjp161948 	NULL
4647211Sjp161948 	};
4657211Sjp161948 
466*7616SVladimir.Kotal@Sun.COM static const EVP_CIPHER pk11_3des_ecb =
4677211Sjp161948 	{
4687211Sjp161948 	NID_des_ede3_ecb,
4697211Sjp161948 	8, 24, 8,
4707211Sjp161948 	EVP_CIPH_ECB_MODE,
4717211Sjp161948 	pk11_cipher_init,
4727211Sjp161948 	pk11_cipher_do_cipher,
4737211Sjp161948 	pk11_cipher_cleanup,
474*7616SVladimir.Kotal@Sun.COM 	sizeof (PK11_CIPHER_STATE),
4757211Sjp161948 	NULL,
4767211Sjp161948 	NULL,
4777211Sjp161948 	NULL
4787211Sjp161948 	};
4797211Sjp161948 
4807211Sjp161948 
481*7616SVladimir.Kotal@Sun.COM static const EVP_CIPHER pk11_aes_128_cbc =
4820Sstevel@tonic-gate 	{
4830Sstevel@tonic-gate 	NID_aes_128_cbc,
4840Sstevel@tonic-gate 	16, 16, 16,
4850Sstevel@tonic-gate 	EVP_CIPH_CBC_MODE,
4860Sstevel@tonic-gate 	pk11_cipher_init,
4870Sstevel@tonic-gate 	pk11_cipher_do_cipher,
4880Sstevel@tonic-gate 	pk11_cipher_cleanup,
489*7616SVladimir.Kotal@Sun.COM 	sizeof (PK11_CIPHER_STATE),
4900Sstevel@tonic-gate 	EVP_CIPHER_set_asn1_iv,
4910Sstevel@tonic-gate 	EVP_CIPHER_get_asn1_iv,
4920Sstevel@tonic-gate 	NULL
4930Sstevel@tonic-gate 	};
4940Sstevel@tonic-gate 
495*7616SVladimir.Kotal@Sun.COM static const EVP_CIPHER pk11_aes_192_cbc =
4967211Sjp161948 	{
4977211Sjp161948 	NID_aes_192_cbc,
4987211Sjp161948 	16, 24, 16,
4997211Sjp161948 	EVP_CIPH_CBC_MODE,
5007211Sjp161948 	pk11_cipher_init,
5017211Sjp161948 	pk11_cipher_do_cipher,
5027211Sjp161948 	pk11_cipher_cleanup,
503*7616SVladimir.Kotal@Sun.COM 	sizeof (PK11_CIPHER_STATE),
5047211Sjp161948 	EVP_CIPHER_set_asn1_iv,
5057211Sjp161948 	EVP_CIPHER_get_asn1_iv,
5067211Sjp161948 	NULL
5077211Sjp161948 	};
5087211Sjp161948 
509*7616SVladimir.Kotal@Sun.COM static const EVP_CIPHER pk11_aes_256_cbc =
5107211Sjp161948 	{
5117211Sjp161948 	NID_aes_256_cbc,
5127211Sjp161948 	16, 32, 16,
5137211Sjp161948 	EVP_CIPH_CBC_MODE,
5147211Sjp161948 	pk11_cipher_init,
5157211Sjp161948 	pk11_cipher_do_cipher,
5167211Sjp161948 	pk11_cipher_cleanup,
517*7616SVladimir.Kotal@Sun.COM 	sizeof (PK11_CIPHER_STATE),
5187211Sjp161948 	EVP_CIPHER_set_asn1_iv,
5197211Sjp161948 	EVP_CIPHER_get_asn1_iv,
5207211Sjp161948 	NULL
5217211Sjp161948 	};
5227211Sjp161948 
5237211Sjp161948 /*
5247211Sjp161948  * ECB modes don't use IV so that's why set_asn1_parameters and
5257211Sjp161948  * get_asn1_parameters are set to NULL.
5267211Sjp161948  */
527*7616SVladimir.Kotal@Sun.COM static const EVP_CIPHER pk11_aes_128_ecb =
5287211Sjp161948 	{
5297211Sjp161948 	NID_aes_128_ecb,
5307211Sjp161948 	16, 16, 0,
5317211Sjp161948 	EVP_CIPH_ECB_MODE,
5327211Sjp161948 	pk11_cipher_init,
5337211Sjp161948 	pk11_cipher_do_cipher,
5347211Sjp161948 	pk11_cipher_cleanup,
535*7616SVladimir.Kotal@Sun.COM 	sizeof (PK11_CIPHER_STATE),
5367211Sjp161948 	NULL,
5377211Sjp161948 	NULL,
5387211Sjp161948 	NULL
5397211Sjp161948 	};
5407211Sjp161948 
541*7616SVladimir.Kotal@Sun.COM static const EVP_CIPHER pk11_aes_192_ecb =
5427211Sjp161948 	{
5437211Sjp161948 	NID_aes_192_ecb,
5447211Sjp161948 	16, 24, 0,
5457211Sjp161948 	EVP_CIPH_ECB_MODE,
5467211Sjp161948 	pk11_cipher_init,
5477211Sjp161948 	pk11_cipher_do_cipher,
5487211Sjp161948 	pk11_cipher_cleanup,
549*7616SVladimir.Kotal@Sun.COM 	sizeof (PK11_CIPHER_STATE),
5507211Sjp161948 	NULL,
5517211Sjp161948 	NULL,
5527211Sjp161948 	NULL
5537211Sjp161948 	};
5547211Sjp161948 
555*7616SVladimir.Kotal@Sun.COM static const EVP_CIPHER pk11_aes_256_ecb =
5567211Sjp161948 	{
5577211Sjp161948 	NID_aes_256_ecb,
5587211Sjp161948 	16, 32, 0,
5597211Sjp161948 	EVP_CIPH_ECB_MODE,
5607211Sjp161948 	pk11_cipher_init,
5617211Sjp161948 	pk11_cipher_do_cipher,
5627211Sjp161948 	pk11_cipher_cleanup,
563*7616SVladimir.Kotal@Sun.COM 	sizeof (PK11_CIPHER_STATE),
5647211Sjp161948 	NULL,
5657211Sjp161948 	NULL,
5667211Sjp161948 	NULL
5677211Sjp161948 	};
5687211Sjp161948 
5697211Sjp161948 #ifdef	SOLARIS_AES_CTR
5707211Sjp161948 /*
5717211Sjp161948  * NID_undef's will be changed to the AES counter mode NIDs as soon they are
5727211Sjp161948  * created in pk11_library_init(). Note that the need to change these structures
5737211Sjp161948  * is the reason why we don't define them with the const keyword.
5747211Sjp161948  */
575*7616SVladimir.Kotal@Sun.COM static EVP_CIPHER pk11_aes_128_ctr =
5767211Sjp161948 	{
5777211Sjp161948 	NID_undef,
5787211Sjp161948 	16, 16, 16,
5797211Sjp161948 	EVP_CIPH_CBC_MODE,
5807211Sjp161948 	pk11_cipher_init,
5817211Sjp161948 	pk11_cipher_do_cipher,
5827211Sjp161948 	pk11_cipher_cleanup,
583*7616SVladimir.Kotal@Sun.COM 	sizeof (PK11_CIPHER_STATE),
5847211Sjp161948 	EVP_CIPHER_set_asn1_iv,
5857211Sjp161948 	EVP_CIPHER_get_asn1_iv,
5867211Sjp161948 	NULL
5877211Sjp161948 	};
5887211Sjp161948 
589*7616SVladimir.Kotal@Sun.COM static EVP_CIPHER pk11_aes_192_ctr =
5907211Sjp161948 	{
5917211Sjp161948 	NID_undef,
5927211Sjp161948 	16, 24, 16,
5937211Sjp161948 	EVP_CIPH_CBC_MODE,
5947211Sjp161948 	pk11_cipher_init,
5957211Sjp161948 	pk11_cipher_do_cipher,
5967211Sjp161948 	pk11_cipher_cleanup,
597*7616SVladimir.Kotal@Sun.COM 	sizeof (PK11_CIPHER_STATE),
5987211Sjp161948 	EVP_CIPHER_set_asn1_iv,
5997211Sjp161948 	EVP_CIPHER_get_asn1_iv,
6007211Sjp161948 	NULL
6017211Sjp161948 	};
6027211Sjp161948 
603*7616SVladimir.Kotal@Sun.COM static EVP_CIPHER pk11_aes_256_ctr =
6047211Sjp161948 	{
6057211Sjp161948 	NID_undef,
6067211Sjp161948 	16, 32, 16,
6077211Sjp161948 	EVP_CIPH_CBC_MODE,
6087211Sjp161948 	pk11_cipher_init,
6097211Sjp161948 	pk11_cipher_do_cipher,
6107211Sjp161948 	pk11_cipher_cleanup,
611*7616SVladimir.Kotal@Sun.COM 	sizeof (PK11_CIPHER_STATE),
6127211Sjp161948 	EVP_CIPHER_set_asn1_iv,
6137211Sjp161948 	EVP_CIPHER_get_asn1_iv,
6147211Sjp161948 	NULL
6157211Sjp161948 	};
6167211Sjp161948 #endif	/* SOLARIS_AES_CTR */
6177211Sjp161948 
618*7616SVladimir.Kotal@Sun.COM static const EVP_CIPHER pk11_bf_cbc =
6197211Sjp161948 	{
6207211Sjp161948 	NID_bf_cbc,
6217211Sjp161948 	8, 16, 8,
6227211Sjp161948 	EVP_CIPH_VARIABLE_LENGTH,
6237211Sjp161948 	pk11_cipher_init,
6247211Sjp161948 	pk11_cipher_do_cipher,
6257211Sjp161948 	pk11_cipher_cleanup,
626*7616SVladimir.Kotal@Sun.COM 	sizeof (PK11_CIPHER_STATE),
6277211Sjp161948 	EVP_CIPHER_set_asn1_iv,
6287211Sjp161948 	EVP_CIPHER_get_asn1_iv,
6297211Sjp161948 	NULL
6307211Sjp161948 	};
6317211Sjp161948 
6320Sstevel@tonic-gate static const EVP_CIPHER pk11_rc4 =
6330Sstevel@tonic-gate 	{
6340Sstevel@tonic-gate 	NID_rc4,
6357211Sjp161948 	1, 16, 0,
6360Sstevel@tonic-gate 	EVP_CIPH_VARIABLE_LENGTH,
6370Sstevel@tonic-gate 	pk11_cipher_init,
6380Sstevel@tonic-gate 	pk11_cipher_do_cipher,
6390Sstevel@tonic-gate 	pk11_cipher_cleanup,
640*7616SVladimir.Kotal@Sun.COM 	sizeof (PK11_CIPHER_STATE),
6410Sstevel@tonic-gate 	NULL,
6420Sstevel@tonic-gate 	NULL,
6430Sstevel@tonic-gate 	NULL
6440Sstevel@tonic-gate 	};
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate static const EVP_MD pk11_md5 =
6470Sstevel@tonic-gate 	{
6480Sstevel@tonic-gate 	NID_md5,
6490Sstevel@tonic-gate 	NID_md5WithRSAEncryption,
6500Sstevel@tonic-gate 	MD5_DIGEST_LENGTH,
6510Sstevel@tonic-gate 	0,
6520Sstevel@tonic-gate 	pk11_digest_init,
6530Sstevel@tonic-gate 	pk11_digest_update,
6540Sstevel@tonic-gate 	pk11_digest_final,
6550Sstevel@tonic-gate 	pk11_digest_copy,
6560Sstevel@tonic-gate 	pk11_digest_cleanup,
6570Sstevel@tonic-gate 	EVP_PKEY_RSA_method,
6580Sstevel@tonic-gate 	MD5_CBLOCK,
659*7616SVladimir.Kotal@Sun.COM 	sizeof (PK11_CIPHER_STATE),
6600Sstevel@tonic-gate 	};
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate static const EVP_MD pk11_sha1 =
6630Sstevel@tonic-gate 	{
6640Sstevel@tonic-gate 	NID_sha1,
6650Sstevel@tonic-gate 	NID_sha1WithRSAEncryption,
6660Sstevel@tonic-gate 	SHA_DIGEST_LENGTH,
6670Sstevel@tonic-gate 	0,
6680Sstevel@tonic-gate 	pk11_digest_init,
6690Sstevel@tonic-gate 	pk11_digest_update,
6700Sstevel@tonic-gate 	pk11_digest_final,
6710Sstevel@tonic-gate 	pk11_digest_copy,
6720Sstevel@tonic-gate 	pk11_digest_cleanup,
6730Sstevel@tonic-gate 	EVP_PKEY_RSA_method,
6740Sstevel@tonic-gate 	SHA_CBLOCK,
675*7616SVladimir.Kotal@Sun.COM 	sizeof (PK11_CIPHER_STATE),
6760Sstevel@tonic-gate 	};
6770Sstevel@tonic-gate 
6787211Sjp161948 static const EVP_MD pk11_sha224 =
6797211Sjp161948 	{
6807211Sjp161948 	NID_sha224,
6817211Sjp161948 	NID_sha224WithRSAEncryption,
6827211Sjp161948 	SHA224_DIGEST_LENGTH,
6837211Sjp161948 	0,
6847211Sjp161948 	pk11_digest_init,
6857211Sjp161948 	pk11_digest_update,
6867211Sjp161948 	pk11_digest_final,
6877211Sjp161948 	pk11_digest_copy,
6887211Sjp161948 	pk11_digest_cleanup,
6897211Sjp161948 	EVP_PKEY_RSA_method,
6907211Sjp161948 	/* SHA-224 uses the same cblock size as SHA-256 */
6917211Sjp161948 	SHA256_CBLOCK,
692*7616SVladimir.Kotal@Sun.COM 	sizeof (PK11_CIPHER_STATE),
6937211Sjp161948 	};
6947211Sjp161948 
6957211Sjp161948 static const EVP_MD pk11_sha256 =
6967211Sjp161948 	{
6977211Sjp161948 	NID_sha256,
6987211Sjp161948 	NID_sha256WithRSAEncryption,
6997211Sjp161948 	SHA256_DIGEST_LENGTH,
7007211Sjp161948 	0,
7017211Sjp161948 	pk11_digest_init,
7027211Sjp161948 	pk11_digest_update,
7037211Sjp161948 	pk11_digest_final,
7047211Sjp161948 	pk11_digest_copy,
7057211Sjp161948 	pk11_digest_cleanup,
7067211Sjp161948 	EVP_PKEY_RSA_method,
7077211Sjp161948 	SHA256_CBLOCK,
708*7616SVladimir.Kotal@Sun.COM 	sizeof (PK11_CIPHER_STATE),
7097211Sjp161948 	};
7107211Sjp161948 
7117211Sjp161948 static const EVP_MD pk11_sha384 =
7127211Sjp161948 	{
7137211Sjp161948 	NID_sha384,
7147211Sjp161948 	NID_sha384WithRSAEncryption,
7157211Sjp161948 	SHA384_DIGEST_LENGTH,
7167211Sjp161948 	0,
7177211Sjp161948 	pk11_digest_init,
7187211Sjp161948 	pk11_digest_update,
7197211Sjp161948 	pk11_digest_final,
7207211Sjp161948 	pk11_digest_copy,
7217211Sjp161948 	pk11_digest_cleanup,
7227211Sjp161948 	EVP_PKEY_RSA_method,
7237211Sjp161948 	/* SHA-384 uses the same cblock size as SHA-512 */
7247211Sjp161948 	SHA512_CBLOCK,
725*7616SVladimir.Kotal@Sun.COM 	sizeof (PK11_CIPHER_STATE),
7267211Sjp161948 	};
7277211Sjp161948 
7287211Sjp161948 static const EVP_MD pk11_sha512 =
7297211Sjp161948 	{
7307211Sjp161948 	NID_sha512,
7317211Sjp161948 	NID_sha512WithRSAEncryption,
7327211Sjp161948 	SHA512_DIGEST_LENGTH,
7337211Sjp161948 	0,
7347211Sjp161948 	pk11_digest_init,
7357211Sjp161948 	pk11_digest_update,
7367211Sjp161948 	pk11_digest_final,
7377211Sjp161948 	pk11_digest_copy,
7387211Sjp161948 	pk11_digest_cleanup,
7397211Sjp161948 	EVP_PKEY_RSA_method,
7407211Sjp161948 	SHA512_CBLOCK,
741*7616SVladimir.Kotal@Sun.COM 	sizeof (PK11_CIPHER_STATE),
7427211Sjp161948 	};
7437211Sjp161948 
744*7616SVladimir.Kotal@Sun.COM /*
745*7616SVladimir.Kotal@Sun.COM  * Initialization function. Sets up various PKCS#11 library components.
746*7616SVladimir.Kotal@Sun.COM  * The definitions for control commands specific to this engine
7470Sstevel@tonic-gate  */
748*7616SVladimir.Kotal@Sun.COM #define	PK11_CMD_SO_PATH		ENGINE_CMD_BASE
7490Sstevel@tonic-gate static const ENGINE_CMD_DEFN pk11_cmd_defns[] =
7500Sstevel@tonic-gate 	{
7510Sstevel@tonic-gate 		{
7520Sstevel@tonic-gate 		PK11_CMD_SO_PATH,
7530Sstevel@tonic-gate 		"SO_PATH",
7540Sstevel@tonic-gate 		"Specifies the path to the 'pkcs#11' shared library",
7550Sstevel@tonic-gate 		ENGINE_CMD_FLAG_STRING
7560Sstevel@tonic-gate 		},
7570Sstevel@tonic-gate 		{0, NULL, NULL, 0}
7580Sstevel@tonic-gate 	};
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate static RAND_METHOD pk11_random =
7620Sstevel@tonic-gate 	{
7630Sstevel@tonic-gate 	pk11_rand_seed,
7640Sstevel@tonic-gate 	pk11_rand_bytes,
7650Sstevel@tonic-gate 	pk11_rand_cleanup,
7660Sstevel@tonic-gate 	pk11_rand_add,
7670Sstevel@tonic-gate 	pk11_rand_bytes,
7680Sstevel@tonic-gate 	pk11_rand_status
7690Sstevel@tonic-gate 	};
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 
772*7616SVladimir.Kotal@Sun.COM /* Constants used when creating the ENGINE */
7730Sstevel@tonic-gate static const char *engine_pk11_id = "pkcs11";
7740Sstevel@tonic-gate static const char *engine_pk11_name = "PKCS #11 engine support";
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate CK_FUNCTION_LIST_PTR pFuncList = NULL;
7770Sstevel@tonic-gate static const char PK11_GET_FUNCTION_LIST[] = "C_GetFunctionList";
7780Sstevel@tonic-gate 
779*7616SVladimir.Kotal@Sun.COM /*
780*7616SVladimir.Kotal@Sun.COM  * These are the static string constants for the DSO file name and the function
7817211Sjp161948  * symbol names to bind to.
7820Sstevel@tonic-gate  */
7830Sstevel@tonic-gate #if defined(__sparcv9) || defined(__x86_64) || defined(__amd64)
7840Sstevel@tonic-gate static const char def_PK11_LIBNAME[] = "/usr/lib/64/libpkcs11.so.1";
7850Sstevel@tonic-gate #else
7860Sstevel@tonic-gate static const char def_PK11_LIBNAME[] = "/usr/lib/libpkcs11.so.1";
7870Sstevel@tonic-gate #endif
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate static CK_BBOOL true = TRUE;
7900Sstevel@tonic-gate static CK_BBOOL false = FALSE;
7917211Sjp161948 static CK_SLOT_ID pubkey_SLOTID = 0;
7927211Sjp161948 static CK_SLOT_ID rand_SLOTID = 0;
7930Sstevel@tonic-gate static CK_SLOT_ID SLOTID = 0;
7947526SVladimir.Kotal@Sun.COM static CK_BBOOL pk11_library_initialized = FALSE;
7957526SVladimir.Kotal@Sun.COM static CK_BBOOL pk11_atfork_initialized = FALSE;
7967211Sjp161948 static int pk11_pid = 0;
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate static DSO *pk11_dso = NULL;
7990Sstevel@tonic-gate 
8007526SVladimir.Kotal@Sun.COM /* allocate and initialize all locks used by the engine itself */
8017526SVladimir.Kotal@Sun.COM static int pk11_init_all_locks(void)
8027526SVladimir.Kotal@Sun.COM 	{
8037526SVladimir.Kotal@Sun.COM 	int type;
8047526SVladimir.Kotal@Sun.COM 
8057526SVladimir.Kotal@Sun.COM #ifndef OPENSSL_NO_RSA
8067526SVladimir.Kotal@Sun.COM 	find_lock[OP_RSA] = OPENSSL_malloc(sizeof (pthread_mutex_t));
8077526SVladimir.Kotal@Sun.COM 	if (find_lock[OP_RSA] == NULL)
8087526SVladimir.Kotal@Sun.COM 		goto malloc_err;
8097526SVladimir.Kotal@Sun.COM 	(void) pthread_mutex_init(find_lock[OP_RSA], NULL);
8107526SVladimir.Kotal@Sun.COM #endif /* OPENSSL_NO_RSA */
8117526SVladimir.Kotal@Sun.COM 
8127526SVladimir.Kotal@Sun.COM #ifndef OPENSSL_NO_DSA
8137526SVladimir.Kotal@Sun.COM 	find_lock[OP_DSA] = OPENSSL_malloc(sizeof (pthread_mutex_t));
8147526SVladimir.Kotal@Sun.COM 	if (find_lock[OP_DSA] == NULL)
8157526SVladimir.Kotal@Sun.COM 		goto malloc_err;
8167526SVladimir.Kotal@Sun.COM 	(void) pthread_mutex_init(find_lock[OP_DSA], NULL);
8177526SVladimir.Kotal@Sun.COM #endif /* OPENSSL_NO_DSA */
8187526SVladimir.Kotal@Sun.COM 
8197526SVladimir.Kotal@Sun.COM #ifndef OPENSSL_NO_DH
8207526SVladimir.Kotal@Sun.COM 	find_lock[OP_DH] = OPENSSL_malloc(sizeof (pthread_mutex_t));
8217526SVladimir.Kotal@Sun.COM 	if (find_lock[OP_DH] == NULL)
8227526SVladimir.Kotal@Sun.COM 		goto malloc_err;
8237526SVladimir.Kotal@Sun.COM 	(void) pthread_mutex_init(find_lock[OP_DH], NULL);
8247526SVladimir.Kotal@Sun.COM #endif /* OPENSSL_NO_DH */
8257526SVladimir.Kotal@Sun.COM 
8267526SVladimir.Kotal@Sun.COM 	for (type = 0; type < OP_MAX; type++)
8277526SVladimir.Kotal@Sun.COM 		{
8287526SVladimir.Kotal@Sun.COM 		session_cache[type].lock =
8297526SVladimir.Kotal@Sun.COM 		    OPENSSL_malloc(sizeof (pthread_mutex_t));
8307526SVladimir.Kotal@Sun.COM 		if (session_cache[type].lock == NULL)
8317526SVladimir.Kotal@Sun.COM 			goto malloc_err;
8327526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_init(session_cache[type].lock, NULL);
8337526SVladimir.Kotal@Sun.COM 		}
8347526SVladimir.Kotal@Sun.COM 
8357526SVladimir.Kotal@Sun.COM 	return (1);
8367526SVladimir.Kotal@Sun.COM 
8377526SVladimir.Kotal@Sun.COM malloc_err:
8387526SVladimir.Kotal@Sun.COM 	pk11_free_all_locks();
8397526SVladimir.Kotal@Sun.COM 	PK11err(PK11_F_INIT_ALL_LOCKS, PK11_R_MALLOC_FAILURE);
8407526SVladimir.Kotal@Sun.COM 	return (0);
8417526SVladimir.Kotal@Sun.COM 	}
8427526SVladimir.Kotal@Sun.COM 
8437526SVladimir.Kotal@Sun.COM static void pk11_free_all_locks(void)
8447526SVladimir.Kotal@Sun.COM 	{
8457526SVladimir.Kotal@Sun.COM 	int type;
8467526SVladimir.Kotal@Sun.COM 
8477526SVladimir.Kotal@Sun.COM #ifndef OPENSSL_NO_RSA
8487526SVladimir.Kotal@Sun.COM 	if (find_lock[OP_RSA] != NULL)
8497526SVladimir.Kotal@Sun.COM 		{
8507526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_destroy(find_lock[OP_RSA]);
8517526SVladimir.Kotal@Sun.COM 		OPENSSL_free(find_lock[OP_RSA]);
8527526SVladimir.Kotal@Sun.COM 		find_lock[OP_RSA] = NULL;
8537526SVladimir.Kotal@Sun.COM 		}
8547526SVladimir.Kotal@Sun.COM #endif /* OPENSSL_NO_RSA */
8557526SVladimir.Kotal@Sun.COM #ifndef OPENSSL_NO_DSA
8567526SVladimir.Kotal@Sun.COM 	if (find_lock[OP_DSA] != NULL)
8577526SVladimir.Kotal@Sun.COM 		{
8587526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_destroy(find_lock[OP_DSA]);
8597526SVladimir.Kotal@Sun.COM 		OPENSSL_free(find_lock[OP_DSA]);
8607526SVladimir.Kotal@Sun.COM 		find_lock[OP_DSA] = NULL;
8617526SVladimir.Kotal@Sun.COM 		}
8627526SVladimir.Kotal@Sun.COM #endif /* OPENSSL_NO_DSA */
8637526SVladimir.Kotal@Sun.COM #ifndef OPENSSL_NO_DH
8647526SVladimir.Kotal@Sun.COM 	if (find_lock[OP_DH] != NULL)
8657526SVladimir.Kotal@Sun.COM 		{
8667526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_destroy(find_lock[OP_DH]);
8677526SVladimir.Kotal@Sun.COM 		OPENSSL_free(find_lock[OP_DH]);
8687526SVladimir.Kotal@Sun.COM 		find_lock[OP_DH] = NULL;
8697526SVladimir.Kotal@Sun.COM 		}
8707526SVladimir.Kotal@Sun.COM #endif /* OPENSSL_NO_DH */
8717526SVladimir.Kotal@Sun.COM 
8727526SVladimir.Kotal@Sun.COM 	for (type = 0; type < OP_MAX; type++)
8737526SVladimir.Kotal@Sun.COM 		{
8747526SVladimir.Kotal@Sun.COM 		if (session_cache[type].lock != NULL)
8757526SVladimir.Kotal@Sun.COM 			{
8767526SVladimir.Kotal@Sun.COM 			(void) pthread_mutex_destroy(session_cache[type].lock);
8777526SVladimir.Kotal@Sun.COM 			OPENSSL_free(session_cache[type].lock);
8787526SVladimir.Kotal@Sun.COM 			session_cache[type].lock = NULL;
8797526SVladimir.Kotal@Sun.COM 			}
8807526SVladimir.Kotal@Sun.COM 		}
8817526SVladimir.Kotal@Sun.COM 	}
8827526SVladimir.Kotal@Sun.COM 
8830Sstevel@tonic-gate /*
8840Sstevel@tonic-gate  * This internal function is used by ENGINE_pk11() and "dynamic" ENGINE support.
8850Sstevel@tonic-gate  */
8860Sstevel@tonic-gate static int bind_pk11(ENGINE *e)
8870Sstevel@tonic-gate 	{
8886847Svk199839 #ifndef OPENSSL_NO_RSA
8890Sstevel@tonic-gate 	const RSA_METHOD *rsa = NULL;
8900Sstevel@tonic-gate 	RSA_METHOD *pk11_rsa = PK11_RSA();
8917211Sjp161948 #endif	/* OPENSSL_NO_RSA */
8920Sstevel@tonic-gate 	if (!pk11_library_initialized)
8937526SVladimir.Kotal@Sun.COM 		(void) pk11_library_init(e);
8940Sstevel@tonic-gate 
895*7616SVladimir.Kotal@Sun.COM 	if (!ENGINE_set_id(e, engine_pk11_id) ||
896*7616SVladimir.Kotal@Sun.COM 	    !ENGINE_set_name(e, engine_pk11_name) ||
897*7616SVladimir.Kotal@Sun.COM 	    !ENGINE_set_ciphers(e, pk11_engine_ciphers) ||
898*7616SVladimir.Kotal@Sun.COM 	    !ENGINE_set_digests(e, pk11_engine_digests))
899*7616SVladimir.Kotal@Sun.COM 		return (0);
9000Sstevel@tonic-gate #ifndef OPENSSL_NO_RSA
901*7616SVladimir.Kotal@Sun.COM 	if (pk11_have_rsa == CK_TRUE)
9020Sstevel@tonic-gate 		{
903*7616SVladimir.Kotal@Sun.COM 		if (!ENGINE_set_RSA(e, PK11_RSA()) ||
904*7616SVladimir.Kotal@Sun.COM 		    !ENGINE_set_load_privkey_function(e, pk11_load_privkey) ||
905*7616SVladimir.Kotal@Sun.COM 		    !ENGINE_set_load_pubkey_function(e, pk11_load_pubkey))
906*7616SVladimir.Kotal@Sun.COM 			return (0);
9077211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
9087211Sjp161948 		fprintf(stderr, "%s: registered RSA\n", PK11_DBG);
9097211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
9100Sstevel@tonic-gate 		}
9117211Sjp161948 #endif	/* OPENSSL_NO_RSA */
9120Sstevel@tonic-gate #ifndef OPENSSL_NO_DSA
913*7616SVladimir.Kotal@Sun.COM 	if (pk11_have_dsa == CK_TRUE)
914*7616SVladimir.Kotal@Sun.COM 		{
915*7616SVladimir.Kotal@Sun.COM 		if (!ENGINE_set_DSA(e, PK11_DSA()))
916*7616SVladimir.Kotal@Sun.COM 			return (0);
9177211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
9187211Sjp161948 		fprintf(stderr, "%s: registered DSA\n", PK11_DBG);
9197211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
920*7616SVladimir.Kotal@Sun.COM 		}
9217211Sjp161948 #endif	/* OPENSSL_NO_DSA */
9220Sstevel@tonic-gate #ifndef OPENSSL_NO_DH
923*7616SVladimir.Kotal@Sun.COM 	if (pk11_have_dh == CK_TRUE)
9240Sstevel@tonic-gate 		{
925*7616SVladimir.Kotal@Sun.COM 		if (!ENGINE_set_DH(e, PK11_DH()))
926*7616SVladimir.Kotal@Sun.COM 			return (0);
9277211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
9287211Sjp161948 		fprintf(stderr, "%s: registered DH\n", PK11_DBG);
9297211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
930*7616SVladimir.Kotal@Sun.COM 		}
9317211Sjp161948 #endif	/* OPENSSL_NO_DH */
932*7616SVladimir.Kotal@Sun.COM 	if (pk11_have_random)
9330Sstevel@tonic-gate 		{
934*7616SVladimir.Kotal@Sun.COM 		if (!ENGINE_set_RAND(e, &pk11_random))
935*7616SVladimir.Kotal@Sun.COM 			return (0);
9367211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
9377211Sjp161948 		fprintf(stderr, "%s: registered random\n", PK11_DBG);
9387211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
9390Sstevel@tonic-gate 		}
940*7616SVladimir.Kotal@Sun.COM 	if (!ENGINE_set_init_function(e, pk11_init) ||
941*7616SVladimir.Kotal@Sun.COM 	    !ENGINE_set_destroy_function(e, pk11_destroy) ||
942*7616SVladimir.Kotal@Sun.COM 	    !ENGINE_set_finish_function(e, pk11_finish) ||
943*7616SVladimir.Kotal@Sun.COM 	    !ENGINE_set_ctrl_function(e, pk11_ctrl) ||
944*7616SVladimir.Kotal@Sun.COM 	    !ENGINE_set_cmd_defns(e, pk11_cmd_defns))
945*7616SVladimir.Kotal@Sun.COM 		return (0);
946*7616SVladimir.Kotal@Sun.COM 
947*7616SVladimir.Kotal@Sun.COM /*
948*7616SVladimir.Kotal@Sun.COM  * Apache calls OpenSSL function RSA_blinding_on() once during startup
9490Sstevel@tonic-gate  * which in turn calls bn_mod_exp. Since we do not implement bn_mod_exp
950*7616SVladimir.Kotal@Sun.COM  * here, we wire it back to the OpenSSL software implementation.
951*7616SVladimir.Kotal@Sun.COM  * Since it is used only once, performance is not a concern.
952*7616SVladimir.Kotal@Sun.COM  */
9530Sstevel@tonic-gate #ifndef OPENSSL_NO_RSA
954*7616SVladimir.Kotal@Sun.COM 	rsa = RSA_PKCS1_SSLeay();
955*7616SVladimir.Kotal@Sun.COM 	pk11_rsa->rsa_mod_exp = rsa->rsa_mod_exp;
956*7616SVladimir.Kotal@Sun.COM 	pk11_rsa->bn_mod_exp = rsa->bn_mod_exp;
9577211Sjp161948 #endif	/* OPENSSL_NO_RSA */
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 	/* Ensure the pk11 error handling is set up */
9600Sstevel@tonic-gate 	ERR_load_pk11_strings();
961*7616SVladimir.Kotal@Sun.COM 
962*7616SVladimir.Kotal@Sun.COM 	return (1);
9630Sstevel@tonic-gate 	}
9640Sstevel@tonic-gate 
965*7616SVladimir.Kotal@Sun.COM /* Dynamic engine support is disabled at a higher level for Solaris */
9667211Sjp161948 #ifdef	ENGINE_DYNAMIC_SUPPORT
9670Sstevel@tonic-gate static int bind_helper(ENGINE *e, const char *id)
9680Sstevel@tonic-gate 	{
9690Sstevel@tonic-gate 	if (id && (strcmp(id, engine_pk11_id) != 0))
970*7616SVladimir.Kotal@Sun.COM 		return (0);
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 	if (!bind_pk11(e))
973*7616SVladimir.Kotal@Sun.COM 		return (0);
974*7616SVladimir.Kotal@Sun.COM 
975*7616SVladimir.Kotal@Sun.COM 	return (1);
976*7616SVladimir.Kotal@Sun.COM 	}
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate IMPLEMENT_DYNAMIC_CHECK_FN()
9790Sstevel@tonic-gate IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate #else
9820Sstevel@tonic-gate static ENGINE *engine_pk11(void)
9830Sstevel@tonic-gate 	{
9840Sstevel@tonic-gate 	ENGINE *ret = ENGINE_new();
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate 	if (!ret)
987*7616SVladimir.Kotal@Sun.COM 		return (NULL);
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate 	if (!bind_pk11(ret))
9900Sstevel@tonic-gate 		{
9910Sstevel@tonic-gate 		ENGINE_free(ret);
992*7616SVladimir.Kotal@Sun.COM 		return (NULL);
9930Sstevel@tonic-gate 		}
9940Sstevel@tonic-gate 
995*7616SVladimir.Kotal@Sun.COM 	return (ret);
9960Sstevel@tonic-gate 	}
9970Sstevel@tonic-gate 
998*7616SVladimir.Kotal@Sun.COM void
999*7616SVladimir.Kotal@Sun.COM ENGINE_load_pk11(void)
10000Sstevel@tonic-gate 	{
10010Sstevel@tonic-gate 	ENGINE *e_pk11 = NULL;
10020Sstevel@tonic-gate 
1003*7616SVladimir.Kotal@Sun.COM 	/*
1004*7616SVladimir.Kotal@Sun.COM 	 * Do not use dynamic PKCS#11 library on Solaris due to
1005*7616SVladimir.Kotal@Sun.COM 	 * security reasons. We will link it in statically.
10060Sstevel@tonic-gate 	 */
1007*7616SVladimir.Kotal@Sun.COM 	/* Attempt to load PKCS#11 library */
10080Sstevel@tonic-gate 	if (!pk11_dso)
10090Sstevel@tonic-gate 		pk11_dso = DSO_load(NULL, get_PK11_LIBNAME(), NULL, 0);
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 	if (pk11_dso == NULL)
10120Sstevel@tonic-gate 		{
10130Sstevel@tonic-gate 		PK11err(PK11_F_LOAD, PK11_R_DSO_FAILURE);
10140Sstevel@tonic-gate 		return;
10150Sstevel@tonic-gate 		}
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate 	e_pk11 = engine_pk11();
1018*7616SVladimir.Kotal@Sun.COM 	if (!e_pk11)
10190Sstevel@tonic-gate 		{
10200Sstevel@tonic-gate 		DSO_free(pk11_dso);
10210Sstevel@tonic-gate 		pk11_dso = NULL;
10220Sstevel@tonic-gate 		return;
10230Sstevel@tonic-gate 		}
10240Sstevel@tonic-gate 
1025*7616SVladimir.Kotal@Sun.COM 	/*
1026*7616SVladimir.Kotal@Sun.COM 	 * At this point, the pk11 shared library is either dynamically
1027*7616SVladimir.Kotal@Sun.COM 	 * loaded or statically linked in. So, initialize the pk11
1028*7616SVladimir.Kotal@Sun.COM 	 * library before calling ENGINE_set_default since the latter
10290Sstevel@tonic-gate 	 * needs cipher and digest algorithm information
10300Sstevel@tonic-gate 	 */
10310Sstevel@tonic-gate 	if (!pk11_library_init(e_pk11))
10320Sstevel@tonic-gate 		{
10330Sstevel@tonic-gate 		DSO_free(pk11_dso);
10340Sstevel@tonic-gate 		pk11_dso = NULL;
10350Sstevel@tonic-gate 		ENGINE_free(e_pk11);
10360Sstevel@tonic-gate 		return;
10370Sstevel@tonic-gate 		}
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate 	ENGINE_add(e_pk11);
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 	ENGINE_free(e_pk11);
10420Sstevel@tonic-gate 	ERR_clear_error();
10430Sstevel@tonic-gate 	}
10447211Sjp161948 #endif	/* ENGINE_DYNAMIC_SUPPORT */
10450Sstevel@tonic-gate 
1046*7616SVladimir.Kotal@Sun.COM /*
1047*7616SVladimir.Kotal@Sun.COM  * These are the static string constants for the DSO file name and
1048*7616SVladimir.Kotal@Sun.COM  * the function symbol names to bind to.
10490Sstevel@tonic-gate  */
10500Sstevel@tonic-gate static const char *PK11_LIBNAME = NULL;
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate static const char *get_PK11_LIBNAME(void)
10530Sstevel@tonic-gate 	{
10540Sstevel@tonic-gate 	if (PK11_LIBNAME)
1055*7616SVladimir.Kotal@Sun.COM 		return (PK11_LIBNAME);
1056*7616SVladimir.Kotal@Sun.COM 
1057*7616SVladimir.Kotal@Sun.COM 	return (def_PK11_LIBNAME);
10580Sstevel@tonic-gate 	}
10590Sstevel@tonic-gate 
10600Sstevel@tonic-gate static void free_PK11_LIBNAME(void)
10610Sstevel@tonic-gate 	{
10620Sstevel@tonic-gate 	if (PK11_LIBNAME)
10630Sstevel@tonic-gate 		OPENSSL_free((void*)PK11_LIBNAME);
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 	PK11_LIBNAME = NULL;
10660Sstevel@tonic-gate 	}
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate static long set_PK11_LIBNAME(const char *name)
10690Sstevel@tonic-gate 	{
10700Sstevel@tonic-gate 	free_PK11_LIBNAME();
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 	return ((PK11_LIBNAME = BUF_strdup(name)) != NULL ? 1 : 0);
10730Sstevel@tonic-gate 	}
10740Sstevel@tonic-gate 
10757526SVladimir.Kotal@Sun.COM /* acquire all engine specific mutexes before fork */
10767526SVladimir.Kotal@Sun.COM static void pk11_fork_prepare(void)
10777526SVladimir.Kotal@Sun.COM 	{
10787526SVladimir.Kotal@Sun.COM 	int i;
10797526SVladimir.Kotal@Sun.COM 
10807560SVladimir.Kotal@Sun.COM 	if (!pk11_library_initialized)
10817560SVladimir.Kotal@Sun.COM 		return;
10827560SVladimir.Kotal@Sun.COM 
10837526SVladimir.Kotal@Sun.COM 	LOCK_OBJSTORE(OP_RSA);
10847526SVladimir.Kotal@Sun.COM 	LOCK_OBJSTORE(OP_DSA);
10857526SVladimir.Kotal@Sun.COM 	LOCK_OBJSTORE(OP_DH);
10867526SVladimir.Kotal@Sun.COM 	for (i = 0; i < OP_MAX; i++)
10877526SVladimir.Kotal@Sun.COM 		{
10887526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_lock(session_cache[i].lock);
10897526SVladimir.Kotal@Sun.COM 		}
10907526SVladimir.Kotal@Sun.COM 	}
10917526SVladimir.Kotal@Sun.COM 
10927526SVladimir.Kotal@Sun.COM /* release all engine specific mutexes */
10937526SVladimir.Kotal@Sun.COM static void pk11_fork_parent(void)
10947526SVladimir.Kotal@Sun.COM 	{
10957526SVladimir.Kotal@Sun.COM 	int i;
10967526SVladimir.Kotal@Sun.COM 
10977560SVladimir.Kotal@Sun.COM 	if (!pk11_library_initialized)
10987560SVladimir.Kotal@Sun.COM 		return;
10997560SVladimir.Kotal@Sun.COM 
11007526SVladimir.Kotal@Sun.COM 	for (i = OP_MAX - 1; i >= 0; i--)
11017526SVladimir.Kotal@Sun.COM 		{
11027526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_unlock(session_cache[i].lock);
11037526SVladimir.Kotal@Sun.COM 		}
11047526SVladimir.Kotal@Sun.COM 	UNLOCK_OBJSTORE(OP_DH);
11057526SVladimir.Kotal@Sun.COM 	UNLOCK_OBJSTORE(OP_DSA);
11067526SVladimir.Kotal@Sun.COM 	UNLOCK_OBJSTORE(OP_RSA);
11077526SVladimir.Kotal@Sun.COM 	}
11087526SVladimir.Kotal@Sun.COM 
11097526SVladimir.Kotal@Sun.COM /*
11107526SVladimir.Kotal@Sun.COM  * same situation as in parent - we need to unlock all locks to make them
11117526SVladimir.Kotal@Sun.COM  * accessible to all threads.
11127526SVladimir.Kotal@Sun.COM  */
11137526SVladimir.Kotal@Sun.COM static void pk11_fork_child(void)
11147526SVladimir.Kotal@Sun.COM 	{
11157526SVladimir.Kotal@Sun.COM 	int i;
11167526SVladimir.Kotal@Sun.COM 
11177560SVladimir.Kotal@Sun.COM 	if (!pk11_library_initialized)
11187560SVladimir.Kotal@Sun.COM 		return;
11197560SVladimir.Kotal@Sun.COM 
11207526SVladimir.Kotal@Sun.COM 	for (i = OP_MAX - 1; i >= 0; i--)
11217526SVladimir.Kotal@Sun.COM 		{
11227526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_unlock(session_cache[i].lock);
11237526SVladimir.Kotal@Sun.COM 		}
11247526SVladimir.Kotal@Sun.COM 	UNLOCK_OBJSTORE(OP_DH);
11257526SVladimir.Kotal@Sun.COM 	UNLOCK_OBJSTORE(OP_DSA);
11267526SVladimir.Kotal@Sun.COM 	UNLOCK_OBJSTORE(OP_RSA);
11277526SVladimir.Kotal@Sun.COM 	}
11287526SVladimir.Kotal@Sun.COM 
11290Sstevel@tonic-gate /* Initialization function for the pk11 engine */
11300Sstevel@tonic-gate static int pk11_init(ENGINE *e)
11310Sstevel@tonic-gate {
1132*7616SVladimir.Kotal@Sun.COM 	return (pk11_library_init(e));
11330Sstevel@tonic-gate }
11340Sstevel@tonic-gate 
1135*7616SVladimir.Kotal@Sun.COM /*
1136*7616SVladimir.Kotal@Sun.COM  * Initialization function. Sets up various PKCS#11 library components.
11370Sstevel@tonic-gate  * It selects a slot based on predefined critiera. In the process, it also
11380Sstevel@tonic-gate  * count how many ciphers and digests to support. Since the cipher and
11390Sstevel@tonic-gate  * digest information is needed when setting default engine, this function
11400Sstevel@tonic-gate  * needs to be called before calling ENGINE_set_default.
11410Sstevel@tonic-gate  */
11427534SVladimir.Kotal@Sun.COM /* ARGSUSED */
11430Sstevel@tonic-gate static int pk11_library_init(ENGINE *e)
11440Sstevel@tonic-gate 	{
11450Sstevel@tonic-gate 	CK_C_GetFunctionList p;
11460Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
11470Sstevel@tonic-gate 	CK_INFO info;
11480Sstevel@tonic-gate 	CK_ULONG ul_state_len;
11497211Sjp161948 	int any_slot_found;
11507526SVladimir.Kotal@Sun.COM 	int i;
11517211Sjp161948 
11527211Sjp161948 	/*
11537211Sjp161948 	 * pk11_library_initialized is set to 0 in pk11_finish() which is called
11547211Sjp161948 	 * from ENGINE_finish(). However, if there is still at least one
11557211Sjp161948 	 * existing functional reference to the engine (see engine(3) for more
11567211Sjp161948 	 * information), pk11_finish() is skipped. For example, this can happen
11577211Sjp161948 	 * if an application forgets to clear one cipher context. In case of a
11587211Sjp161948 	 * fork() when the application is finishing the engine so that it can be
11597211Sjp161948 	 * reinitialized in the child, forgotten functional reference causes
11607211Sjp161948 	 * pk11_library_initialized to stay 1. In that case we need the PID
11617211Sjp161948 	 * check so that we properly initialize the engine again.
11627211Sjp161948 	 */
11630Sstevel@tonic-gate 	if (pk11_library_initialized)
11647211Sjp161948 		{
11657211Sjp161948 		if (pk11_pid == getpid())
11667526SVladimir.Kotal@Sun.COM 			{
1167*7616SVladimir.Kotal@Sun.COM 			return (1);
11687526SVladimir.Kotal@Sun.COM 			}
11697211Sjp161948 		else
11707526SVladimir.Kotal@Sun.COM 			{
11717211Sjp161948 			global_session = CK_INVALID_HANDLE;
11727526SVladimir.Kotal@Sun.COM 			/*
11737526SVladimir.Kotal@Sun.COM 			 * free the locks first to prevent memory leak in case
11747526SVladimir.Kotal@Sun.COM 			 * the application calls fork() without finishing the
11757526SVladimir.Kotal@Sun.COM 			 * engine first.
11767526SVladimir.Kotal@Sun.COM 			 */
11777526SVladimir.Kotal@Sun.COM 			pk11_free_all_locks();
11787526SVladimir.Kotal@Sun.COM 			}
11797211Sjp161948 		}
1180*7616SVladimir.Kotal@Sun.COM 
11810Sstevel@tonic-gate 	if (pk11_dso == NULL)
11820Sstevel@tonic-gate 		{
11830Sstevel@tonic-gate 		PK11err(PK11_F_LIBRARY_INIT, PK11_R_DSO_FAILURE);
11840Sstevel@tonic-gate 		goto err;
11850Sstevel@tonic-gate 		}
11860Sstevel@tonic-gate 
11877211Sjp161948 #ifdef	SOLARIS_AES_CTR
11887211Sjp161948 	/*
11897211Sjp161948 	 * We must do this before we start working with slots since we need all
11907211Sjp161948 	 * NIDs there.
11917211Sjp161948 	 */
11927211Sjp161948 	if (pk11_add_aes_ctr_NIDs() == 0)
11937211Sjp161948 		goto err;
11947211Sjp161948 #endif	/* SOLARIS_AES_CTR */
11957211Sjp161948 
11967211Sjp161948 #ifdef	SOLARIS_HW_SLOT_SELECTION
11977211Sjp161948 	if (check_hw_mechanisms() == 0)
11987211Sjp161948 		goto err;
11997211Sjp161948 #endif	/* SOLARIS_HW_SLOT_SELECTION */
12007211Sjp161948 
1201*7616SVladimir.Kotal@Sun.COM 	/* get the C_GetFunctionList function from the loaded library */
1202*7616SVladimir.Kotal@Sun.COM 	p = (CK_C_GetFunctionList)DSO_bind_func(pk11_dso,
12030Sstevel@tonic-gate 		PK11_GET_FUNCTION_LIST);
1204*7616SVladimir.Kotal@Sun.COM 	if (!p)
12050Sstevel@tonic-gate 		{
12060Sstevel@tonic-gate 		PK11err(PK11_F_LIBRARY_INIT, PK11_R_DSO_FAILURE);
12070Sstevel@tonic-gate 		goto err;
12080Sstevel@tonic-gate 		}
1209*7616SVladimir.Kotal@Sun.COM 
1210*7616SVladimir.Kotal@Sun.COM 	/* get the full function list from the loaded library */
12110Sstevel@tonic-gate 	rv = p(&pFuncList);
12120Sstevel@tonic-gate 	if (rv != CKR_OK)
12130Sstevel@tonic-gate 		{
12147211Sjp161948 		PK11err_add_data(PK11_F_LIBRARY_INIT, PK11_R_DSO_FAILURE, rv);
12150Sstevel@tonic-gate 		goto err;
12160Sstevel@tonic-gate 		}
1217*7616SVladimir.Kotal@Sun.COM 
12180Sstevel@tonic-gate 	rv = pFuncList->C_Initialize(NULL_PTR);
12190Sstevel@tonic-gate 	if ((rv != CKR_OK) && (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED))
12200Sstevel@tonic-gate 		{
12217211Sjp161948 		PK11err_add_data(PK11_F_LIBRARY_INIT, PK11_R_INITIALIZE, rv);
12220Sstevel@tonic-gate 		goto err;
12230Sstevel@tonic-gate 		}
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate 	rv = pFuncList->C_GetInfo(&info);
1226*7616SVladimir.Kotal@Sun.COM 	if (rv != CKR_OK)
12270Sstevel@tonic-gate 		{
12287211Sjp161948 		PK11err_add_data(PK11_F_LIBRARY_INIT, PK11_R_GETINFO, rv);
12290Sstevel@tonic-gate 		goto err;
12300Sstevel@tonic-gate 		}
12310Sstevel@tonic-gate 
12327211Sjp161948 	if (pk11_choose_slots(&any_slot_found) == 0)
12330Sstevel@tonic-gate 		goto err;
12340Sstevel@tonic-gate 
12357211Sjp161948 	/*
12367211Sjp161948 	 * The library we use, set in def_PK11_LIBNAME, may not offer any
12377211Sjp161948 	 * slot(s). In that case, we must not proceed but we must not return an
12387211Sjp161948 	 * error. The reason is that applications that try to set up the PKCS#11
12397211Sjp161948 	 * engine don't exit on error during the engine initialization just
12407211Sjp161948 	 * because no slot was present.
12417211Sjp161948 	 */
12427211Sjp161948 	if (any_slot_found == 0)
1243*7616SVladimir.Kotal@Sun.COM 		return (1);
12447211Sjp161948 
12450Sstevel@tonic-gate 	if (global_session == CK_INVALID_HANDLE)
12460Sstevel@tonic-gate 		{
12470Sstevel@tonic-gate 		/* Open the global_session for the new process */
12480Sstevel@tonic-gate 		rv = pFuncList->C_OpenSession(SLOTID, CKF_SERIAL_SESSION,
12490Sstevel@tonic-gate 			NULL_PTR, NULL_PTR, &global_session);
12500Sstevel@tonic-gate 		if (rv != CKR_OK)
12510Sstevel@tonic-gate 			{
12527211Sjp161948 			PK11err_add_data(PK11_F_LIBRARY_INIT,
12537211Sjp161948 			    PK11_R_OPENSESSION, rv);
12540Sstevel@tonic-gate 			goto err;
12550Sstevel@tonic-gate 			}
12560Sstevel@tonic-gate 		}
12570Sstevel@tonic-gate 
1258*7616SVladimir.Kotal@Sun.COM 	/*
1259*7616SVladimir.Kotal@Sun.COM 	 * Disable digest if C_GetOperationState is not supported since
1260*7616SVladimir.Kotal@Sun.COM 	 * this function is required by OpenSSL digest copy function
1261*7616SVladimir.Kotal@Sun.COM 	 */
12620Sstevel@tonic-gate 	if (pFuncList->C_GetOperationState(global_session, NULL, &ul_state_len)
12637211Sjp161948 			== CKR_FUNCTION_NOT_SUPPORTED) {
12647211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
12657211Sjp161948 		fprintf(stderr, "%s: C_GetOperationState() not supported, "
12667211Sjp161948 		    "setting digest_count to 0\n", PK11_DBG);
12677211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
12680Sstevel@tonic-gate 		digest_count = 0;
12697211Sjp161948 	}
12700Sstevel@tonic-gate 
12717526SVladimir.Kotal@Sun.COM 	pk11_library_initialized = TRUE;
12727211Sjp161948 	pk11_pid = getpid();
12737526SVladimir.Kotal@Sun.COM 	/*
12747526SVladimir.Kotal@Sun.COM 	 * if initialization of the locks fails pk11_init_all_locks()
12757526SVladimir.Kotal@Sun.COM 	 * will do the cleanup.
12767526SVladimir.Kotal@Sun.COM 	 */
12777526SVladimir.Kotal@Sun.COM 	if (!pk11_init_all_locks())
12787526SVladimir.Kotal@Sun.COM 		goto err;
12797526SVladimir.Kotal@Sun.COM 	for (i = 0; i < OP_MAX; i++)
12807526SVladimir.Kotal@Sun.COM 		session_cache[i].head = NULL;
12817526SVladimir.Kotal@Sun.COM 	/*
12827526SVladimir.Kotal@Sun.COM 	 * initialize active lists. We only use active lists
12837526SVladimir.Kotal@Sun.COM 	 * for asymmetric ciphers.
12847526SVladimir.Kotal@Sun.COM 	 */
12857526SVladimir.Kotal@Sun.COM 	for (i = 0; i < OP_MAX; i++)
12867526SVladimir.Kotal@Sun.COM 		active_list[i] = NULL;
12877526SVladimir.Kotal@Sun.COM 
12887526SVladimir.Kotal@Sun.COM 	if (!pk11_atfork_initialized)
12897526SVladimir.Kotal@Sun.COM 		{
12907526SVladimir.Kotal@Sun.COM 		if (pthread_atfork(pk11_fork_prepare, pk11_fork_parent,
12917526SVladimir.Kotal@Sun.COM 		    pk11_fork_child) != 0)
12927526SVladimir.Kotal@Sun.COM 			{
12937526SVladimir.Kotal@Sun.COM 			PK11err(PK11_F_LIBRARY_INIT, PK11_R_ATFORK_FAILED);
12947526SVladimir.Kotal@Sun.COM 			goto err;
12957526SVladimir.Kotal@Sun.COM 			}
12967526SVladimir.Kotal@Sun.COM 		pk11_atfork_initialized = TRUE;
12977526SVladimir.Kotal@Sun.COM 		}
12987526SVladimir.Kotal@Sun.COM 
1299*7616SVladimir.Kotal@Sun.COM 	return (1);
13000Sstevel@tonic-gate 
13010Sstevel@tonic-gate err:
1302*7616SVladimir.Kotal@Sun.COM 	return (0);
13030Sstevel@tonic-gate 	}
13040Sstevel@tonic-gate 
1305*7616SVladimir.Kotal@Sun.COM /* Destructor (complements the "ENGINE_pk11()" constructor) */
13067534SVladimir.Kotal@Sun.COM /* ARGSUSED */
13070Sstevel@tonic-gate static int pk11_destroy(ENGINE *e)
13080Sstevel@tonic-gate 	{
13090Sstevel@tonic-gate 	free_PK11_LIBNAME();
13100Sstevel@tonic-gate 	ERR_unload_pk11_strings();
1311*7616SVladimir.Kotal@Sun.COM 	return (1);
13120Sstevel@tonic-gate 	}
13130Sstevel@tonic-gate 
1314*7616SVladimir.Kotal@Sun.COM /*
1315*7616SVladimir.Kotal@Sun.COM  * Termination function to clean up the session, the token, and the pk11
1316*7616SVladimir.Kotal@Sun.COM  * library.
13170Sstevel@tonic-gate  */
13187534SVladimir.Kotal@Sun.COM /* ARGSUSED */
13190Sstevel@tonic-gate static int pk11_finish(ENGINE *e)
13200Sstevel@tonic-gate 	{
13217526SVladimir.Kotal@Sun.COM 	int i;
13227526SVladimir.Kotal@Sun.COM 
13230Sstevel@tonic-gate 	if (pk11_dso == NULL)
13240Sstevel@tonic-gate 		{
13250Sstevel@tonic-gate 		PK11err(PK11_F_FINISH, PK11_R_NOT_LOADED);
13260Sstevel@tonic-gate 		goto err;
13270Sstevel@tonic-gate 		}
13280Sstevel@tonic-gate 
13296847Svk199839 	OPENSSL_assert(pFuncList != NULL);
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate 	if (pk11_free_all_sessions() == 0)
13320Sstevel@tonic-gate 		goto err;
13330Sstevel@tonic-gate 
13347526SVladimir.Kotal@Sun.COM 	/* free all active lists */
13357526SVladimir.Kotal@Sun.COM 	for (i = 0; i < OP_MAX; i++)
13367526SVladimir.Kotal@Sun.COM 		pk11_free_active_list(i);
13377526SVladimir.Kotal@Sun.COM 
13380Sstevel@tonic-gate 	pFuncList->C_CloseSession(global_session);
13397211Sjp161948 	global_session = CK_INVALID_HANDLE;
13407211Sjp161948 
13417211Sjp161948 	/*
13427211Sjp161948 	 * Since we are part of a library (libcrypto.so), calling this function
13437211Sjp161948 	 * may have side-effects.
13447211Sjp161948 	 */
13457211Sjp161948 #if 0
13460Sstevel@tonic-gate 	pFuncList->C_Finalize(NULL);
13477211Sjp161948 #endif
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 	if (!DSO_free(pk11_dso))
13500Sstevel@tonic-gate 		{
13510Sstevel@tonic-gate 		PK11err(PK11_F_FINISH, PK11_R_DSO_FAILURE);
13520Sstevel@tonic-gate 		goto err;
13530Sstevel@tonic-gate 		}
13540Sstevel@tonic-gate 	pk11_dso = NULL;
13550Sstevel@tonic-gate 	pFuncList = NULL;
13567526SVladimir.Kotal@Sun.COM 	pk11_library_initialized = FALSE;
13577211Sjp161948 	pk11_pid = 0;
13587560SVladimir.Kotal@Sun.COM 	/*
13597560SVladimir.Kotal@Sun.COM 	 * There is no way how to unregister atfork handlers (other than
13607560SVladimir.Kotal@Sun.COM 	 * unloading the library) so we just free the locks. For this reason
13617560SVladimir.Kotal@Sun.COM 	 * the atfork handlers check if the engine is initialized and bail out
13627560SVladimir.Kotal@Sun.COM 	 * immediately if not. This is necessary in case a process finishes
13637560SVladimir.Kotal@Sun.COM 	 * the engine before calling fork().
13647560SVladimir.Kotal@Sun.COM 	 */
13657526SVladimir.Kotal@Sun.COM 	pk11_free_all_locks();
13660Sstevel@tonic-gate 
1367*7616SVladimir.Kotal@Sun.COM 	return (1);
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate err:
1370*7616SVladimir.Kotal@Sun.COM 	return (0);
13710Sstevel@tonic-gate 	}
13720Sstevel@tonic-gate 
13730Sstevel@tonic-gate /* Standard engine interface function to set the dynamic library path */
13747534SVladimir.Kotal@Sun.COM /* ARGSUSED */
13750Sstevel@tonic-gate static int pk11_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)())
13760Sstevel@tonic-gate 	{
13770Sstevel@tonic-gate 	int initialized = ((pk11_dso == NULL) ? 0 : 1);
13780Sstevel@tonic-gate 
1379*7616SVladimir.Kotal@Sun.COM 	switch (cmd)
13800Sstevel@tonic-gate 		{
13810Sstevel@tonic-gate 	case PK11_CMD_SO_PATH:
13820Sstevel@tonic-gate 		if (p == NULL)
13830Sstevel@tonic-gate 			{
13840Sstevel@tonic-gate 			PK11err(PK11_F_CTRL, ERR_R_PASSED_NULL_PARAMETER);
1385*7616SVladimir.Kotal@Sun.COM 			return (0);
13860Sstevel@tonic-gate 			}
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate 		if (initialized)
13890Sstevel@tonic-gate 			{
13900Sstevel@tonic-gate 			PK11err(PK11_F_CTRL, PK11_R_ALREADY_LOADED);
1391*7616SVladimir.Kotal@Sun.COM 			return (0);
13920Sstevel@tonic-gate 			}
13930Sstevel@tonic-gate 
1394*7616SVladimir.Kotal@Sun.COM 		return (set_PK11_LIBNAME((const char *)p));
13950Sstevel@tonic-gate 	default:
13960Sstevel@tonic-gate 		break;
13970Sstevel@tonic-gate 		}
13980Sstevel@tonic-gate 
1399*7616SVladimir.Kotal@Sun.COM 	PK11err(PK11_F_CTRL, PK11_R_CTRL_COMMAND_NOT_IMPLEMENTED);
1400*7616SVladimir.Kotal@Sun.COM 
1401*7616SVladimir.Kotal@Sun.COM 	return (0);
14020Sstevel@tonic-gate 	}
14030Sstevel@tonic-gate 
14040Sstevel@tonic-gate 
1405*7616SVladimir.Kotal@Sun.COM /* Required function by the engine random interface. It does nothing here */
14060Sstevel@tonic-gate static void pk11_rand_cleanup(void)
14070Sstevel@tonic-gate 	{
14080Sstevel@tonic-gate 	return;
14090Sstevel@tonic-gate 	}
14100Sstevel@tonic-gate 
14117534SVladimir.Kotal@Sun.COM /* ARGSUSED */
14120Sstevel@tonic-gate static void pk11_rand_add(const void *buf, int num, double add)
14130Sstevel@tonic-gate 	{
14140Sstevel@tonic-gate 	PK11_SESSION *sp;
14150Sstevel@tonic-gate 
14167211Sjp161948 	if ((sp = pk11_get_session(OP_RAND)) == NULL)
14170Sstevel@tonic-gate 		return;
14180Sstevel@tonic-gate 
1419*7616SVladimir.Kotal@Sun.COM 	/*
1420*7616SVladimir.Kotal@Sun.COM 	 * Ignore any errors (e.g. CKR_RANDOM_SEED_NOT_SUPPORTED) since
14210Sstevel@tonic-gate 	 * the calling functions do not care anyway
14220Sstevel@tonic-gate 	 */
14230Sstevel@tonic-gate 	pFuncList->C_SeedRandom(sp->session, (unsigned char *) buf, num);
14247211Sjp161948 	pk11_return_session(sp, OP_RAND);
14250Sstevel@tonic-gate 
14260Sstevel@tonic-gate 	return;
14270Sstevel@tonic-gate 	}
14280Sstevel@tonic-gate 
14290Sstevel@tonic-gate static void pk11_rand_seed(const void *buf, int num)
14300Sstevel@tonic-gate 	{
14310Sstevel@tonic-gate 	pk11_rand_add(buf, num, 0);
14320Sstevel@tonic-gate 	}
14330Sstevel@tonic-gate 
14340Sstevel@tonic-gate static int pk11_rand_bytes(unsigned char *buf, int num)
14350Sstevel@tonic-gate 	{
14360Sstevel@tonic-gate 	CK_RV rv;
14370Sstevel@tonic-gate 	PK11_SESSION *sp;
1438*7616SVladimir.Kotal@Sun.COM 
14397211Sjp161948 	if ((sp = pk11_get_session(OP_RAND)) == NULL)
1440*7616SVladimir.Kotal@Sun.COM 		return (0);
1441*7616SVladimir.Kotal@Sun.COM 
14420Sstevel@tonic-gate 	rv = pFuncList->C_GenerateRandom(sp->session, buf, num);
14430Sstevel@tonic-gate 	if (rv != CKR_OK)
14440Sstevel@tonic-gate 		{
14457211Sjp161948 		PK11err_add_data(PK11_F_RAND_BYTES, PK11_R_GENERATERANDOM, rv);
14467211Sjp161948 		pk11_return_session(sp, OP_RAND);
1447*7616SVladimir.Kotal@Sun.COM 		return (0);
14480Sstevel@tonic-gate 		}
14490Sstevel@tonic-gate 
14507211Sjp161948 	pk11_return_session(sp, OP_RAND);
1451*7616SVladimir.Kotal@Sun.COM 	return (1);
14520Sstevel@tonic-gate 	}
14530Sstevel@tonic-gate 
1454*7616SVladimir.Kotal@Sun.COM /* Required function by the engine random interface. It does nothing here */
14550Sstevel@tonic-gate static int pk11_rand_status(void)
14560Sstevel@tonic-gate 	{
1457*7616SVladimir.Kotal@Sun.COM 	return (1);
14580Sstevel@tonic-gate 	}
14590Sstevel@tonic-gate 
1460*7616SVladimir.Kotal@Sun.COM /* Free all BIGNUM structures from PK11_SESSION. */
14617526SVladimir.Kotal@Sun.COM static void pk11_free_nums(PK11_SESSION *sp, PK11_OPTYPE optype)
14626847Svk199839 	{
14637526SVladimir.Kotal@Sun.COM 	switch (optype)
14647526SVladimir.Kotal@Sun.COM 		{
14656847Svk199839 #ifndef	OPENSSL_NO_RSA
14667526SVladimir.Kotal@Sun.COM 		case OP_RSA:
14677526SVladimir.Kotal@Sun.COM 			if (sp->opdata_rsa_n_num != NULL)
14687526SVladimir.Kotal@Sun.COM 				{
14697526SVladimir.Kotal@Sun.COM 				BN_free(sp->opdata_rsa_n_num);
14707526SVladimir.Kotal@Sun.COM 				sp->opdata_rsa_n_num = NULL;
14717526SVladimir.Kotal@Sun.COM 				}
14727526SVladimir.Kotal@Sun.COM 			if (sp->opdata_rsa_e_num != NULL)
14737526SVladimir.Kotal@Sun.COM 				{
14747526SVladimir.Kotal@Sun.COM 				BN_free(sp->opdata_rsa_e_num);
14757526SVladimir.Kotal@Sun.COM 				sp->opdata_rsa_e_num = NULL;
14767526SVladimir.Kotal@Sun.COM 				}
14777526SVladimir.Kotal@Sun.COM 			if (sp->opdata_rsa_d_num != NULL)
14787526SVladimir.Kotal@Sun.COM 				{
14797526SVladimir.Kotal@Sun.COM 				BN_free(sp->opdata_rsa_d_num);
14807526SVladimir.Kotal@Sun.COM 				sp->opdata_rsa_d_num = NULL;
14817526SVladimir.Kotal@Sun.COM 				}
14827526SVladimir.Kotal@Sun.COM 			break;
14836847Svk199839 #endif
14846847Svk199839 #ifndef	OPENSSL_NO_DSA
14857526SVladimir.Kotal@Sun.COM 		case OP_DSA:
14867526SVladimir.Kotal@Sun.COM 			if (sp->opdata_dsa_pub_num != NULL)
14877526SVladimir.Kotal@Sun.COM 				{
14887526SVladimir.Kotal@Sun.COM 				BN_free(sp->opdata_dsa_pub_num);
14897526SVladimir.Kotal@Sun.COM 				sp->opdata_dsa_pub_num = NULL;
14907526SVladimir.Kotal@Sun.COM 				}
14917526SVladimir.Kotal@Sun.COM 			if (sp->opdata_dsa_priv_num != NULL)
14927526SVladimir.Kotal@Sun.COM 				{
14937526SVladimir.Kotal@Sun.COM 				BN_free(sp->opdata_dsa_priv_num);
14947526SVladimir.Kotal@Sun.COM 				sp->opdata_dsa_priv_num = NULL;
14957526SVladimir.Kotal@Sun.COM 				}
14967526SVladimir.Kotal@Sun.COM 			break;
14976847Svk199839 #endif
14986847Svk199839 #ifndef	OPENSSL_NO_DH
14997526SVladimir.Kotal@Sun.COM 		case OP_DH:
15007526SVladimir.Kotal@Sun.COM 			if (sp->opdata_dh_priv_num != NULL)
15017526SVladimir.Kotal@Sun.COM 				{
15027526SVladimir.Kotal@Sun.COM 				BN_free(sp->opdata_dh_priv_num);
15037526SVladimir.Kotal@Sun.COM 				sp->opdata_dh_priv_num = NULL;
15047526SVladimir.Kotal@Sun.COM 				}
15057526SVladimir.Kotal@Sun.COM 			break;
15066847Svk199839 #endif
15077526SVladimir.Kotal@Sun.COM 		default:
15087526SVladimir.Kotal@Sun.COM 			break;
15097526SVladimir.Kotal@Sun.COM 		}
15106847Svk199839 	}
15110Sstevel@tonic-gate 
15126847Svk199839 /*
15136847Svk199839  * Get new PK11_SESSION structure ready for use. Every process must have
15146847Svk199839  * its own freelist of PK11_SESSION structures so handle fork() here
15156847Svk199839  * by destroying the old and creating new freelist.
15166847Svk199839  * The returned PK11_SESSION structure is disconnected from the freelist.
15176847Svk199839  */
1518*7616SVladimir.Kotal@Sun.COM PK11_SESSION *
1519*7616SVladimir.Kotal@Sun.COM pk11_get_session(PK11_OPTYPE optype)
15200Sstevel@tonic-gate 	{
15217526SVladimir.Kotal@Sun.COM 	PK11_SESSION *sp = NULL, *sp1, *freelist;
15227526SVladimir.Kotal@Sun.COM 	pthread_mutex_t *freelist_lock;
15230Sstevel@tonic-gate 	CK_RV rv;
15240Sstevel@tonic-gate 
15257211Sjp161948 	switch (optype)
15267211Sjp161948 		{
15277526SVladimir.Kotal@Sun.COM 		case OP_RSA:
15287526SVladimir.Kotal@Sun.COM 		case OP_DSA:
15297526SVladimir.Kotal@Sun.COM 		case OP_DH:
15307211Sjp161948 		case OP_RAND:
15317211Sjp161948 		case OP_DIGEST:
15327211Sjp161948 		case OP_CIPHER:
15337526SVladimir.Kotal@Sun.COM 			freelist_lock = session_cache[optype].lock;
15347211Sjp161948 			break;
15357211Sjp161948 		default:
1536*7616SVladimir.Kotal@Sun.COM 			PK11err(PK11_F_GET_SESSION,
15377211Sjp161948 				PK11_R_INVALID_OPERATION_TYPE);
15387526SVladimir.Kotal@Sun.COM 			return (NULL);
15397211Sjp161948 		}
15407526SVladimir.Kotal@Sun.COM 	(void) pthread_mutex_lock(freelist_lock);
15417526SVladimir.Kotal@Sun.COM 	freelist = session_cache[optype].head;
15427211Sjp161948 	sp = freelist;
15437211Sjp161948 
15446847Svk199839 	/*
15456847Svk199839 	 * If the free list is empty, allocate new unitialized (filled
15466847Svk199839 	 * with zeroes) PK11_SESSION structure otherwise return first
15476847Svk199839 	 * structure from the freelist.
15486847Svk199839 	 */
15497211Sjp161948 	if (sp == NULL)
15500Sstevel@tonic-gate 		{
1551*7616SVladimir.Kotal@Sun.COM 		if ((sp = OPENSSL_malloc(sizeof (PK11_SESSION))) == NULL)
15520Sstevel@tonic-gate 			{
1553*7616SVladimir.Kotal@Sun.COM 			PK11err(PK11_F_GET_SESSION,
15540Sstevel@tonic-gate 				PK11_R_MALLOC_FAILURE);
15550Sstevel@tonic-gate 			goto err;
15560Sstevel@tonic-gate 			}
1557*7616SVladimir.Kotal@Sun.COM 		(void) memset(sp, 0, sizeof (PK11_SESSION));
15580Sstevel@tonic-gate 		}
15590Sstevel@tonic-gate 	else
15600Sstevel@tonic-gate 		{
15617211Sjp161948 		freelist = sp->next;
15620Sstevel@tonic-gate 		}
15630Sstevel@tonic-gate 
15640Sstevel@tonic-gate 	if (sp->pid != 0 && sp->pid != getpid())
15650Sstevel@tonic-gate 		{
15666847Svk199839 		/*
15676847Svk199839 		 * We are a new process and thus need to free any inherited
15680Sstevel@tonic-gate 		 * PK11_SESSION objects.
15690Sstevel@tonic-gate 		 */
15707211Sjp161948 		while ((sp1 = freelist) != NULL)
15710Sstevel@tonic-gate 			{
15727211Sjp161948 			freelist = sp1->next;
15736847Svk199839 			/*
15747211Sjp161948 			 * NOTE: we do not want to call pk11_free_all_sessions()
15757211Sjp161948 			 * here because it would close underlying PKCS#11
15767211Sjp161948 			 * sessions and destroy all objects.
15776847Svk199839 			 */
15787526SVladimir.Kotal@Sun.COM 			pk11_free_nums(sp1, optype);
15790Sstevel@tonic-gate 			OPENSSL_free(sp1);
15800Sstevel@tonic-gate 			}
15810Sstevel@tonic-gate 
15827526SVladimir.Kotal@Sun.COM 		/* we have to free the active list as well. */
15837526SVladimir.Kotal@Sun.COM 		pk11_free_active_list(optype);
15847526SVladimir.Kotal@Sun.COM 
15850Sstevel@tonic-gate 		/* Initialize the process */
15860Sstevel@tonic-gate 		rv = pFuncList->C_Initialize(NULL_PTR);
15870Sstevel@tonic-gate 		if ((rv != CKR_OK) && (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED))
15880Sstevel@tonic-gate 			{
15897211Sjp161948 			PK11err_add_data(PK11_F_GET_SESSION, PK11_R_INITIALIZE,
15907211Sjp161948 			    rv);
15910Sstevel@tonic-gate 			OPENSSL_free(sp);
15920Sstevel@tonic-gate 			sp = NULL;
15930Sstevel@tonic-gate 			goto err;
15940Sstevel@tonic-gate 			}
15950Sstevel@tonic-gate 
15966847Svk199839 		/*
15977211Sjp161948 		 * Choose slot here since the slot table is different on this
15987211Sjp161948 		 * process. If we are here then we must have found at least one
15997211Sjp161948 		 * usable slot before so we don't need to check any_slot_found.
16007211Sjp161948 		 * See pk11_library_init()'s usage of this function for more
16017211Sjp161948 		 * information.
16020Sstevel@tonic-gate 		 */
16037211Sjp161948 #ifdef	SOLARIS_HW_SLOT_SELECTION
16047211Sjp161948 		if (check_hw_mechanisms() == 0)
16057211Sjp161948 			goto err;
16067211Sjp161948 #endif	/* SOLARIS_HW_SLOT_SELECTION */
16077211Sjp161948 		if (pk11_choose_slots(NULL) == 0)
16080Sstevel@tonic-gate 			goto err;
16090Sstevel@tonic-gate 
16100Sstevel@tonic-gate 		/* Open the global_session for the new process */
16110Sstevel@tonic-gate 		rv = pFuncList->C_OpenSession(SLOTID, CKF_SERIAL_SESSION,
16120Sstevel@tonic-gate 			NULL_PTR, NULL_PTR, &global_session);
16130Sstevel@tonic-gate 		if (rv != CKR_OK)
16140Sstevel@tonic-gate 			{
16157211Sjp161948 			PK11err_add_data(PK11_F_GET_SESSION, PK11_R_OPENSESSION,
16167211Sjp161948 			    rv);
16170Sstevel@tonic-gate 			OPENSSL_free(sp);
16180Sstevel@tonic-gate 			sp = NULL;
16190Sstevel@tonic-gate 			goto err;
16200Sstevel@tonic-gate 			}
16210Sstevel@tonic-gate 
1622*7616SVladimir.Kotal@Sun.COM 		/* It is an inherited session and needs re-initialization. */
16237211Sjp161948 		if (pk11_setup_session(sp, optype) == 0)
16240Sstevel@tonic-gate 			{
16250Sstevel@tonic-gate 			OPENSSL_free(sp);
16260Sstevel@tonic-gate 			sp = NULL;
16270Sstevel@tonic-gate 			}
16280Sstevel@tonic-gate 		}
1629*7616SVladimir.Kotal@Sun.COM 	if (sp->pid == 0)
16300Sstevel@tonic-gate 		{
16317211Sjp161948 		/* It is a new session and needs initialization. */
16327211Sjp161948 		if (pk11_setup_session(sp, optype) == 0)
16330Sstevel@tonic-gate 			{
16340Sstevel@tonic-gate 			OPENSSL_free(sp);
16350Sstevel@tonic-gate 			sp = NULL;
16360Sstevel@tonic-gate 			}
16370Sstevel@tonic-gate 		}
16380Sstevel@tonic-gate 
16397526SVladimir.Kotal@Sun.COM 	/* set new head for the list of PK11_SESSION objects */
16407526SVladimir.Kotal@Sun.COM 	session_cache[optype].head = freelist;
16417211Sjp161948 
16420Sstevel@tonic-gate err:
16436847Svk199839 	if (sp != NULL)
16440Sstevel@tonic-gate 		sp->next = NULL;
16450Sstevel@tonic-gate 
16467526SVladimir.Kotal@Sun.COM 	(void) pthread_mutex_unlock(freelist_lock);
16470Sstevel@tonic-gate 
1648*7616SVladimir.Kotal@Sun.COM 	return (sp);
16490Sstevel@tonic-gate 	}
16500Sstevel@tonic-gate 
16510Sstevel@tonic-gate 
1652*7616SVladimir.Kotal@Sun.COM void
1653*7616SVladimir.Kotal@Sun.COM pk11_return_session(PK11_SESSION *sp, PK11_OPTYPE optype)
16540Sstevel@tonic-gate 	{
16557526SVladimir.Kotal@Sun.COM 	pthread_mutex_t *freelist_lock;
16567526SVladimir.Kotal@Sun.COM 	PK11_SESSION *freelist;
16577526SVladimir.Kotal@Sun.COM 
16580Sstevel@tonic-gate 	if (sp == NULL || sp->pid != getpid())
16590Sstevel@tonic-gate 		return;
1660*7616SVladimir.Kotal@Sun.COM 
16617211Sjp161948 	switch (optype)
16627211Sjp161948 		{
16637526SVladimir.Kotal@Sun.COM 		case OP_RSA:
16647526SVladimir.Kotal@Sun.COM 		case OP_DSA:
16657526SVladimir.Kotal@Sun.COM 		case OP_DH:
16667211Sjp161948 		case OP_RAND:
16677211Sjp161948 		case OP_DIGEST:
16687211Sjp161948 		case OP_CIPHER:
16697526SVladimir.Kotal@Sun.COM 			freelist_lock = session_cache[optype].lock;
16707211Sjp161948 			break;
16717526SVladimir.Kotal@Sun.COM 		default:
16727526SVladimir.Kotal@Sun.COM 			PK11err(PK11_F_RETURN_SESSION,
16737526SVladimir.Kotal@Sun.COM 				PK11_R_INVALID_OPERATION_TYPE);
16747526SVladimir.Kotal@Sun.COM 			return;
16757211Sjp161948 		}
16760Sstevel@tonic-gate 
16777526SVladimir.Kotal@Sun.COM 	(void) pthread_mutex_lock(freelist_lock);
16787526SVladimir.Kotal@Sun.COM 	freelist = session_cache[optype].head;
16797526SVladimir.Kotal@Sun.COM 	sp->next = freelist;
16807526SVladimir.Kotal@Sun.COM 	session_cache[optype].head = sp;
16817526SVladimir.Kotal@Sun.COM 	(void) pthread_mutex_unlock(freelist_lock);
16820Sstevel@tonic-gate 	}
16830Sstevel@tonic-gate 
16840Sstevel@tonic-gate 
1685*7616SVladimir.Kotal@Sun.COM /* Destroy all objects. This function is called when the engine is finished */
16860Sstevel@tonic-gate static int pk11_free_all_sessions()
16870Sstevel@tonic-gate 	{
16887211Sjp161948 	int ret = 1;
16897526SVladimir.Kotal@Sun.COM 	int type;
16900Sstevel@tonic-gate 
16916847Svk199839 #ifndef OPENSSL_NO_RSA
16926847Svk199839 	(void) pk11_destroy_rsa_key_objects(NULL);
16937211Sjp161948 #endif	/* OPENSSL_NO_RSA */
16946847Svk199839 #ifndef OPENSSL_NO_DSA
16956847Svk199839 	(void) pk11_destroy_dsa_key_objects(NULL);
16967211Sjp161948 #endif	/* OPENSSL_NO_DSA */
16976847Svk199839 #ifndef OPENSSL_NO_DH
16986847Svk199839 	(void) pk11_destroy_dh_key_objects(NULL);
16997211Sjp161948 #endif	/* OPENSSL_NO_DH */
17006847Svk199839 	(void) pk11_destroy_cipher_key_objects(NULL);
17017211Sjp161948 
17027211Sjp161948 	/*
17037211Sjp161948 	 * We try to release as much as we can but any error means that we will
17047211Sjp161948 	 * return 0 on exit.
17057211Sjp161948 	 */
17067526SVladimir.Kotal@Sun.COM 	for (type = 0; type < OP_MAX; type++)
17077526SVladimir.Kotal@Sun.COM 		{
17087526SVladimir.Kotal@Sun.COM 		if (pk11_free_session_list(type) == 0)
17097526SVladimir.Kotal@Sun.COM 			ret = 0;
17107526SVladimir.Kotal@Sun.COM 		}
17117211Sjp161948 
1712*7616SVladimir.Kotal@Sun.COM 	return (ret);
17137211Sjp161948 	}
1714*7616SVladimir.Kotal@Sun.COM 
17157211Sjp161948 /*
17167526SVladimir.Kotal@Sun.COM  * Destroy session structures from the linked list specified. Free as many
17177526SVladimir.Kotal@Sun.COM  * sessions as possible but any failure in C_CloseSession() means that we
17187526SVladimir.Kotal@Sun.COM  * return an error on return.
17197211Sjp161948  */
17207526SVladimir.Kotal@Sun.COM static int pk11_free_session_list(PK11_OPTYPE optype)
17217211Sjp161948 	{
17227211Sjp161948 	CK_RV rv;
17237211Sjp161948 	PK11_SESSION *sp = NULL;
17247526SVladimir.Kotal@Sun.COM 	PK11_SESSION *freelist = NULL;
17257211Sjp161948 	pid_t mypid = getpid();
17267526SVladimir.Kotal@Sun.COM 	pthread_mutex_t *freelist_lock;
17277211Sjp161948 	int ret = 1;
17287211Sjp161948 
17297526SVladimir.Kotal@Sun.COM 	switch (optype)
17307526SVladimir.Kotal@Sun.COM 		{
17317526SVladimir.Kotal@Sun.COM 		case OP_RSA:
17327526SVladimir.Kotal@Sun.COM 		case OP_DSA:
17337526SVladimir.Kotal@Sun.COM 		case OP_DH:
17347526SVladimir.Kotal@Sun.COM 		case OP_RAND:
17357526SVladimir.Kotal@Sun.COM 		case OP_DIGEST:
17367526SVladimir.Kotal@Sun.COM 		case OP_CIPHER:
17377526SVladimir.Kotal@Sun.COM 			freelist_lock = session_cache[optype].lock;
17387526SVladimir.Kotal@Sun.COM 			break;
17397526SVladimir.Kotal@Sun.COM 		default:
17407526SVladimir.Kotal@Sun.COM 			PK11err(PK11_F_FREE_ALL_SESSIONS,
17417526SVladimir.Kotal@Sun.COM 				PK11_R_INVALID_OPERATION_TYPE);
17427526SVladimir.Kotal@Sun.COM 			return (0);
17437526SVladimir.Kotal@Sun.COM 		}
17447526SVladimir.Kotal@Sun.COM 
17457526SVladimir.Kotal@Sun.COM 	(void) pthread_mutex_lock(freelist_lock);
17467526SVladimir.Kotal@Sun.COM 	freelist = session_cache[optype].head;
17477526SVladimir.Kotal@Sun.COM 	while ((sp = freelist) != NULL)
17480Sstevel@tonic-gate 		{
17490Sstevel@tonic-gate 		if (sp->session != CK_INVALID_HANDLE && sp->pid == mypid)
17500Sstevel@tonic-gate 			{
17510Sstevel@tonic-gate 			rv = pFuncList->C_CloseSession(sp->session);
17520Sstevel@tonic-gate 			if (rv != CKR_OK)
17530Sstevel@tonic-gate 				{
1754*7616SVladimir.Kotal@Sun.COM 				PK11err_add_data(PK11_F_FREE_ALL_SESSIONS,
17557211Sjp161948 					PK11_R_CLOSESESSION, rv);
17567211Sjp161948 				ret = 0;
17570Sstevel@tonic-gate 				}
17580Sstevel@tonic-gate 			}
17597526SVladimir.Kotal@Sun.COM 		freelist = sp->next;
17607526SVladimir.Kotal@Sun.COM 		pk11_free_nums(sp, optype);
17610Sstevel@tonic-gate 		OPENSSL_free(sp);
17620Sstevel@tonic-gate 		}
17637211Sjp161948 
17647526SVladimir.Kotal@Sun.COM 	(void) pthread_mutex_unlock(freelist_lock);
1765*7616SVladimir.Kotal@Sun.COM 	return (ret);
17660Sstevel@tonic-gate 	}
17670Sstevel@tonic-gate 
17680Sstevel@tonic-gate 
17697211Sjp161948 static int pk11_setup_session(PK11_SESSION *sp, PK11_OPTYPE optype)
17700Sstevel@tonic-gate 	{
17710Sstevel@tonic-gate 	CK_RV rv;
17727211Sjp161948 	CK_SLOT_ID myslot;
17737211Sjp161948 
17747211Sjp161948 	switch (optype)
17757211Sjp161948 		{
17767526SVladimir.Kotal@Sun.COM 		case OP_RSA:
17777526SVladimir.Kotal@Sun.COM 		case OP_DSA:
17787526SVladimir.Kotal@Sun.COM 		case OP_DH:
17797211Sjp161948 			myslot = pubkey_SLOTID;
17807211Sjp161948 			break;
17817211Sjp161948 		case OP_RAND:
17827211Sjp161948 			myslot = rand_SLOTID;
17837211Sjp161948 			break;
17847211Sjp161948 		case OP_DIGEST:
17857211Sjp161948 		case OP_CIPHER:
17867211Sjp161948 			myslot = SLOTID;
17877211Sjp161948 			break;
17887211Sjp161948 		default:
17897211Sjp161948 			PK11err(PK11_F_SETUP_SESSION,
17907211Sjp161948 			    PK11_R_INVALID_OPERATION_TYPE);
1791*7616SVladimir.Kotal@Sun.COM 			return (0);
17927211Sjp161948 		}
17937211Sjp161948 
17940Sstevel@tonic-gate 	sp->session = CK_INVALID_HANDLE;
17957211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
17967211Sjp161948 	fprintf(stderr, "%s: myslot=%d optype=%d\n", PK11_DBG, myslot, optype);
17977211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
17987211Sjp161948 	rv = pFuncList->C_OpenSession(myslot, CKF_SERIAL_SESSION,
17990Sstevel@tonic-gate 		NULL_PTR, NULL_PTR, &sp->session);
18000Sstevel@tonic-gate 	if (rv == CKR_CRYPTOKI_NOT_INITIALIZED)
18010Sstevel@tonic-gate 		{
18020Sstevel@tonic-gate 		/*
18030Sstevel@tonic-gate 		 * We are probably a child process so force the
18040Sstevel@tonic-gate 		 * reinitialize of the session
18050Sstevel@tonic-gate 		 */
18067526SVladimir.Kotal@Sun.COM 		pk11_library_initialized = FALSE;
18070Sstevel@tonic-gate 		(void) pk11_library_init(NULL);
18087211Sjp161948 		rv = pFuncList->C_OpenSession(myslot, CKF_SERIAL_SESSION,
18090Sstevel@tonic-gate 			NULL_PTR, NULL_PTR, &sp->session);
18100Sstevel@tonic-gate 		}
18110Sstevel@tonic-gate 	if (rv != CKR_OK)
18120Sstevel@tonic-gate 		{
18137211Sjp161948 		PK11err_add_data(PK11_F_SETUP_SESSION, PK11_R_OPENSESSION, rv);
1814*7616SVladimir.Kotal@Sun.COM 		return (0);
18150Sstevel@tonic-gate 		}
18160Sstevel@tonic-gate 
18177526SVladimir.Kotal@Sun.COM 	sp->pid = getpid();
18187526SVladimir.Kotal@Sun.COM 
18197526SVladimir.Kotal@Sun.COM 	switch (optype)
18200Sstevel@tonic-gate 		{
18216847Svk199839 #ifndef OPENSSL_NO_RSA
18227526SVladimir.Kotal@Sun.COM 		case OP_RSA:
18237526SVladimir.Kotal@Sun.COM 			sp->opdata_rsa_pub_key = CK_INVALID_HANDLE;
18247526SVladimir.Kotal@Sun.COM 			sp->opdata_rsa_priv_key = CK_INVALID_HANDLE;
18257526SVladimir.Kotal@Sun.COM 			sp->opdata_rsa_pub = NULL;
18267526SVladimir.Kotal@Sun.COM 			sp->opdata_rsa_n_num = NULL;
18277526SVladimir.Kotal@Sun.COM 			sp->opdata_rsa_e_num = NULL;
18287526SVladimir.Kotal@Sun.COM 			sp->opdata_rsa_priv = NULL;
18297526SVladimir.Kotal@Sun.COM 			sp->opdata_rsa_d_num = NULL;
18307526SVladimir.Kotal@Sun.COM 			break;
18317211Sjp161948 #endif	/* OPENSSL_NO_RSA */
18326847Svk199839 #ifndef OPENSSL_NO_DSA
18337526SVladimir.Kotal@Sun.COM 		case OP_DSA:
18347526SVladimir.Kotal@Sun.COM 			sp->opdata_dsa_pub_key = CK_INVALID_HANDLE;
18357526SVladimir.Kotal@Sun.COM 			sp->opdata_dsa_priv_key = CK_INVALID_HANDLE;
18367526SVladimir.Kotal@Sun.COM 			sp->opdata_dsa_pub = NULL;
18377526SVladimir.Kotal@Sun.COM 			sp->opdata_dsa_pub_num = NULL;
18387526SVladimir.Kotal@Sun.COM 			sp->opdata_dsa_priv = NULL;
18397526SVladimir.Kotal@Sun.COM 			sp->opdata_dsa_priv_num = NULL;
18407526SVladimir.Kotal@Sun.COM 			break;
18417211Sjp161948 #endif	/* OPENSSL_NO_DSA */
18426847Svk199839 #ifndef OPENSSL_NO_DH
18437526SVladimir.Kotal@Sun.COM 		case OP_DH:
18447526SVladimir.Kotal@Sun.COM 			sp->opdata_dh_key = CK_INVALID_HANDLE;
18457526SVladimir.Kotal@Sun.COM 			sp->opdata_dh = NULL;
18467526SVladimir.Kotal@Sun.COM 			sp->opdata_dh_priv_num = NULL;
18477526SVladimir.Kotal@Sun.COM 			break;
18487211Sjp161948 #endif	/* OPENSSL_NO_DH */
18497526SVladimir.Kotal@Sun.COM 		case OP_CIPHER:
18507526SVladimir.Kotal@Sun.COM 			sp->opdata_cipher_key = CK_INVALID_HANDLE;
18517526SVladimir.Kotal@Sun.COM 			sp->opdata_encrypt = -1;
18527526SVladimir.Kotal@Sun.COM 			break;
18537526SVladimir.Kotal@Sun.COM 		}
18540Sstevel@tonic-gate 
1855*7616SVladimir.Kotal@Sun.COM 	return (1);
18560Sstevel@tonic-gate 	}
18570Sstevel@tonic-gate 
18586847Svk199839 #ifndef OPENSSL_NO_RSA
18596847Svk199839 /* Destroy RSA public key from single session. */
1860*7616SVladimir.Kotal@Sun.COM int
1861*7616SVladimir.Kotal@Sun.COM pk11_destroy_rsa_object_pub(PK11_SESSION *sp, CK_BBOOL uselock)
18626847Svk199839 	{
18636847Svk199839 	int ret = 0;
18646847Svk199839 
18657526SVladimir.Kotal@Sun.COM 	if (sp->opdata_rsa_pub_key != CK_INVALID_HANDLE)
18666847Svk199839 		{
18677526SVladimir.Kotal@Sun.COM 		TRY_OBJ_DESTROY(sp->session, sp->opdata_rsa_pub_key,
18687526SVladimir.Kotal@Sun.COM 		    ret, uselock, OP_RSA);
18697526SVladimir.Kotal@Sun.COM 		sp->opdata_rsa_pub_key = CK_INVALID_HANDLE;
18707526SVladimir.Kotal@Sun.COM 		sp->opdata_rsa_pub = NULL;
18717526SVladimir.Kotal@Sun.COM 		if (sp->opdata_rsa_n_num != NULL)
18727526SVladimir.Kotal@Sun.COM 			{
18737526SVladimir.Kotal@Sun.COM 			BN_free(sp->opdata_rsa_n_num);
18747526SVladimir.Kotal@Sun.COM 			sp->opdata_rsa_n_num = NULL;
18757526SVladimir.Kotal@Sun.COM 			}
18767526SVladimir.Kotal@Sun.COM 		if (sp->opdata_rsa_e_num != NULL)
18777526SVladimir.Kotal@Sun.COM 			{
18787526SVladimir.Kotal@Sun.COM 			BN_free(sp->opdata_rsa_e_num);
18797526SVladimir.Kotal@Sun.COM 			sp->opdata_rsa_e_num = NULL;
18807526SVladimir.Kotal@Sun.COM 			}
18816847Svk199839 		}
18826847Svk199839 
18836847Svk199839 	return (ret);
18846847Svk199839 	}
18856847Svk199839 
18866847Svk199839 /* Destroy RSA private key from single session. */
1887*7616SVladimir.Kotal@Sun.COM int
1888*7616SVladimir.Kotal@Sun.COM pk11_destroy_rsa_object_priv(PK11_SESSION *sp, CK_BBOOL uselock)
18890Sstevel@tonic-gate 	{
18900Sstevel@tonic-gate 	int ret = 0;
18916847Svk199839 
18927526SVladimir.Kotal@Sun.COM 	if (sp->opdata_rsa_priv_key != CK_INVALID_HANDLE)
18936847Svk199839 		{
18947526SVladimir.Kotal@Sun.COM 		TRY_OBJ_DESTROY(sp->session, sp->opdata_rsa_priv_key,
18957526SVladimir.Kotal@Sun.COM 		    ret, uselock, OP_RSA);
18967526SVladimir.Kotal@Sun.COM 		sp->opdata_rsa_priv_key = CK_INVALID_HANDLE;
18977526SVladimir.Kotal@Sun.COM 		sp->opdata_rsa_priv = NULL;
18987526SVladimir.Kotal@Sun.COM 		if (sp->opdata_rsa_d_num != NULL)
18997526SVladimir.Kotal@Sun.COM 			{
19007526SVladimir.Kotal@Sun.COM 			BN_free(sp->opdata_rsa_d_num);
19017526SVladimir.Kotal@Sun.COM 			sp->opdata_rsa_d_num = NULL;
19027526SVladimir.Kotal@Sun.COM 			}
19036847Svk199839 		}
19046847Svk199839 
19056847Svk199839 	return (ret);
19066847Svk199839 	}
19076847Svk199839 
19086847Svk199839 /*
19097211Sjp161948  * Destroy RSA key object wrapper. If session is NULL, try to destroy all
19107211Sjp161948  * objects in the free list.
19116847Svk199839  */
1912*7616SVladimir.Kotal@Sun.COM int
1913*7616SVladimir.Kotal@Sun.COM pk11_destroy_rsa_key_objects(PK11_SESSION *session)
19146847Svk199839 	{
19156847Svk199839 	int ret = 1;
19160Sstevel@tonic-gate 	PK11_SESSION *sp = NULL;
19170Sstevel@tonic-gate 	PK11_SESSION *local_free_session;
19186847Svk199839 	CK_BBOOL uselock = TRUE;
19190Sstevel@tonic-gate 
19206847Svk199839 	if (session != NULL)
19210Sstevel@tonic-gate 		local_free_session = session;
19220Sstevel@tonic-gate 	else
19236847Svk199839 		{
19247526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_lock(session_cache[OP_RSA].lock);
19257526SVladimir.Kotal@Sun.COM 		local_free_session = session_cache[OP_RSA].head;
19266847Svk199839 		uselock = FALSE;
19276847Svk199839 		}
19280Sstevel@tonic-gate 
19296847Svk199839 	/*
19306847Svk199839 	 * go through the list of sessions and delete key objects
19316847Svk199839 	 */
19320Sstevel@tonic-gate 	while ((sp = local_free_session) != NULL)
19330Sstevel@tonic-gate 		{
19340Sstevel@tonic-gate 		local_free_session = sp->next;
19350Sstevel@tonic-gate 
19366847Svk199839 		/*
19376847Svk199839 		 * Do not terminate list traversal if one of the
19386847Svk199839 		 * destroy operations fails.
19396847Svk199839 		 */
19406847Svk199839 		if (pk11_destroy_rsa_object_pub(sp, uselock) == 0)
19410Sstevel@tonic-gate 			{
19426847Svk199839 			ret = 0;
19436847Svk199839 			continue;
19440Sstevel@tonic-gate 			}
19456847Svk199839 		if (pk11_destroy_rsa_object_priv(sp, uselock) == 0)
19466847Svk199839 			{
19476847Svk199839 			ret = 0;
19486847Svk199839 			continue;
19496847Svk199839 			}
19506847Svk199839 		}
19510Sstevel@tonic-gate 
19526847Svk199839 	if (session == NULL)
19537526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_unlock(session_cache[OP_RSA].lock);
19540Sstevel@tonic-gate 
1955*7616SVladimir.Kotal@Sun.COM 	return (ret);
19560Sstevel@tonic-gate 	}
19577211Sjp161948 #endif	/* OPENSSL_NO_RSA */
19580Sstevel@tonic-gate 
19596847Svk199839 #ifndef OPENSSL_NO_DSA
19606847Svk199839 /* Destroy DSA public key from single session. */
1961*7616SVladimir.Kotal@Sun.COM int
1962*7616SVladimir.Kotal@Sun.COM pk11_destroy_dsa_object_pub(PK11_SESSION *sp, CK_BBOOL uselock)
19630Sstevel@tonic-gate 	{
19640Sstevel@tonic-gate 	int ret = 0;
19656847Svk199839 
19667526SVladimir.Kotal@Sun.COM 	if (sp->opdata_dsa_pub_key != CK_INVALID_HANDLE)
19676847Svk199839 		{
19687526SVladimir.Kotal@Sun.COM 		TRY_OBJ_DESTROY(sp->session, sp->opdata_dsa_pub_key,
19697526SVladimir.Kotal@Sun.COM 		    ret, uselock, OP_DSA);
19707526SVladimir.Kotal@Sun.COM 		sp->opdata_dsa_pub_key = CK_INVALID_HANDLE;
19717526SVladimir.Kotal@Sun.COM 		sp->opdata_dsa_pub = NULL;
19727526SVladimir.Kotal@Sun.COM 		if (sp->opdata_dsa_pub_num != NULL)
19737526SVladimir.Kotal@Sun.COM 			{
19747526SVladimir.Kotal@Sun.COM 			BN_free(sp->opdata_dsa_pub_num);
19757526SVladimir.Kotal@Sun.COM 			sp->opdata_dsa_pub_num = NULL;
19767526SVladimir.Kotal@Sun.COM 			}
19776847Svk199839 		}
19786847Svk199839 
19796847Svk199839 	return (ret);
19806847Svk199839 	}
19816847Svk199839 
19826847Svk199839 /* Destroy DSA private key from single session. */
1983*7616SVladimir.Kotal@Sun.COM int
1984*7616SVladimir.Kotal@Sun.COM pk11_destroy_dsa_object_priv(PK11_SESSION *sp, CK_BBOOL uselock)
19856847Svk199839 	{
19866847Svk199839 	int ret = 0;
19876847Svk199839 
19887526SVladimir.Kotal@Sun.COM 	if (sp->opdata_dsa_priv_key != CK_INVALID_HANDLE)
19896847Svk199839 		{
19907526SVladimir.Kotal@Sun.COM 		TRY_OBJ_DESTROY(sp->session, sp->opdata_dsa_priv_key,
19917526SVladimir.Kotal@Sun.COM 		    ret, uselock, OP_DSA);
19927526SVladimir.Kotal@Sun.COM 		sp->opdata_dsa_priv_key = CK_INVALID_HANDLE;
19937526SVladimir.Kotal@Sun.COM 		sp->opdata_dsa_priv = NULL;
19947526SVladimir.Kotal@Sun.COM 		if (sp->opdata_dsa_priv_num != NULL)
19957526SVladimir.Kotal@Sun.COM 			{
19967526SVladimir.Kotal@Sun.COM 			BN_free(sp->opdata_dsa_priv_num);
19977526SVladimir.Kotal@Sun.COM 			sp->opdata_dsa_priv_num = NULL;
19987526SVladimir.Kotal@Sun.COM 			}
19996847Svk199839 		}
20006847Svk199839 
20016847Svk199839 	return (ret);
20026847Svk199839 	}
20036847Svk199839 
20046847Svk199839 /*
20057211Sjp161948  * Destroy DSA key object wrapper. If session is NULL, try to destroy all
20067211Sjp161948  * objects in the free list.
20076847Svk199839  */
2008*7616SVladimir.Kotal@Sun.COM int
2009*7616SVladimir.Kotal@Sun.COM pk11_destroy_dsa_key_objects(PK11_SESSION *session)
20106847Svk199839 	{
20116847Svk199839 	int ret = 1;
20120Sstevel@tonic-gate 	PK11_SESSION *sp = NULL;
20130Sstevel@tonic-gate 	PK11_SESSION *local_free_session;
20146847Svk199839 	CK_BBOOL uselock = TRUE;
20150Sstevel@tonic-gate 
20166847Svk199839 	if (session != NULL)
20170Sstevel@tonic-gate 		local_free_session = session;
20180Sstevel@tonic-gate 	else
20196847Svk199839 		{
20207526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_lock(session_cache[OP_DSA].lock);
20217526SVladimir.Kotal@Sun.COM 		local_free_session = session_cache[OP_DSA].head;
20226847Svk199839 		uselock = FALSE;
20236847Svk199839 		}
20246847Svk199839 
20256847Svk199839 	/*
20266847Svk199839 	 * go through the list of sessions and delete key objects
20276847Svk199839 	 */
20280Sstevel@tonic-gate 	while ((sp = local_free_session) != NULL)
20290Sstevel@tonic-gate 		{
20300Sstevel@tonic-gate 		local_free_session = sp->next;
20310Sstevel@tonic-gate 
20326847Svk199839 		/*
20336847Svk199839 		 * Do not terminate list traversal if one of the
20346847Svk199839 		 * destroy operations fails.
20356847Svk199839 		 */
20366847Svk199839 		if (pk11_destroy_dsa_object_pub(sp, uselock) == 0)
20370Sstevel@tonic-gate 			{
20386847Svk199839 			ret = 0;
20396847Svk199839 			continue;
20400Sstevel@tonic-gate 			}
20416847Svk199839 		if (pk11_destroy_dsa_object_priv(sp, uselock) == 0)
20426847Svk199839 			{
20436847Svk199839 			ret = 0;
20446847Svk199839 			continue;
20456847Svk199839 			}
20460Sstevel@tonic-gate 		}
20476847Svk199839 
20486847Svk199839 	if (session == NULL)
20497526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_unlock(session_cache[OP_DSA].lock);
20500Sstevel@tonic-gate 
2051*7616SVladimir.Kotal@Sun.COM 	return (ret);
20520Sstevel@tonic-gate 	}
20537211Sjp161948 #endif	/* OPENSSL_NO_DSA */
20546847Svk199839 
20556847Svk199839 #ifndef OPENSSL_NO_DH
20566847Svk199839 /* Destroy DH key from single session. */
2057*7616SVladimir.Kotal@Sun.COM int
2058*7616SVladimir.Kotal@Sun.COM pk11_destroy_dh_object(PK11_SESSION *sp, CK_BBOOL uselock)
20596847Svk199839 	{
20606847Svk199839 	int ret = 0;
20616847Svk199839 
20627526SVladimir.Kotal@Sun.COM 	if (sp->opdata_dh_key != CK_INVALID_HANDLE)
20636847Svk199839 		{
20647526SVladimir.Kotal@Sun.COM 		TRY_OBJ_DESTROY(sp->session, sp->opdata_dh_key,
20657526SVladimir.Kotal@Sun.COM 		    ret, uselock, OP_DH);
20667526SVladimir.Kotal@Sun.COM 		sp->opdata_dh_key = CK_INVALID_HANDLE;
20677526SVladimir.Kotal@Sun.COM 		sp->opdata_dh = NULL;
20687526SVladimir.Kotal@Sun.COM 		if (sp->opdata_dh_priv_num != NULL)
20697526SVladimir.Kotal@Sun.COM 			{
20707526SVladimir.Kotal@Sun.COM 			BN_free(sp->opdata_dh_priv_num);
20717526SVladimir.Kotal@Sun.COM 			sp->opdata_dh_priv_num = NULL;
20727526SVladimir.Kotal@Sun.COM 			}
20736847Svk199839 		}
20746847Svk199839 
20756847Svk199839 	return (ret);
20766847Svk199839 	}
20776847Svk199839 
20786847Svk199839 /*
20796847Svk199839  * Destroy DH key object wrapper.
20806847Svk199839  *
20816847Svk199839  * arg0: pointer to PKCS#11 engine session structure
20826847Svk199839  *       if session is NULL, try to destroy all objects in the free list
20836847Svk199839  */
2084*7616SVladimir.Kotal@Sun.COM int
2085*7616SVladimir.Kotal@Sun.COM pk11_destroy_dh_key_objects(PK11_SESSION *session)
20866847Svk199839 	{
20876847Svk199839 	int ret = 1;
20886847Svk199839 	PK11_SESSION *sp = NULL;
20896847Svk199839 	PK11_SESSION *local_free_session;
20906847Svk199839 	CK_BBOOL uselock = TRUE;
20916847Svk199839 
20926847Svk199839 	if (session != NULL)
20936847Svk199839 		local_free_session = session;
20946847Svk199839 	else
20956847Svk199839 		{
20967526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_lock(session_cache[OP_DH].lock);
20977526SVladimir.Kotal@Sun.COM 		local_free_session = session_cache[OP_DH].head;
20986847Svk199839 		uselock = FALSE;
20996847Svk199839 		}
21006847Svk199839 
21016847Svk199839 	while ((sp = local_free_session) != NULL)
21026847Svk199839 		{
21036847Svk199839 		local_free_session = sp->next;
21046847Svk199839 
21056847Svk199839 		/*
21066847Svk199839 		 * Do not terminate list traversal if one of the
21076847Svk199839 		 * destroy operations fails.
21086847Svk199839 		 */
21096847Svk199839 		if (pk11_destroy_dh_object(sp, uselock) == 0)
21106847Svk199839 			{
21116847Svk199839 			ret = 0;
21126847Svk199839 			continue;
21136847Svk199839 			}
21146847Svk199839 		}
21156847Svk199839 err:
21166847Svk199839 	if (session == NULL)
21177526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_unlock(session_cache[OP_DH].lock);
21186847Svk199839 
2119*7616SVladimir.Kotal@Sun.COM 	return (ret);
21206847Svk199839 	}
21217211Sjp161948 #endif	/* OPENSSL_NO_DH */
21220Sstevel@tonic-gate 
21230Sstevel@tonic-gate static int pk11_destroy_object(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE oh)
21240Sstevel@tonic-gate 	{
21250Sstevel@tonic-gate 	CK_RV rv;
21260Sstevel@tonic-gate 	rv = pFuncList->C_DestroyObject(session, oh);
21270Sstevel@tonic-gate 	if (rv != CKR_OK)
21280Sstevel@tonic-gate 		{
21297211Sjp161948 		PK11err_add_data(PK11_F_DESTROY_OBJECT, PK11_R_DESTROYOBJECT,
21307211Sjp161948 		    rv);
2131*7616SVladimir.Kotal@Sun.COM 		return (0);
21320Sstevel@tonic-gate 		}
21330Sstevel@tonic-gate 
2134*7616SVladimir.Kotal@Sun.COM 	return (1);
21350Sstevel@tonic-gate 	}
21360Sstevel@tonic-gate 
21370Sstevel@tonic-gate 
2138*7616SVladimir.Kotal@Sun.COM /* Symmetric ciphers and digests support functions */
21390Sstevel@tonic-gate 
21400Sstevel@tonic-gate static int
21410Sstevel@tonic-gate cipher_nid_to_pk11(int nid)
21420Sstevel@tonic-gate 	{
21430Sstevel@tonic-gate 	int i;
21440Sstevel@tonic-gate 
21450Sstevel@tonic-gate 	for (i = 0; i < PK11_CIPHER_MAX; i++)
21460Sstevel@tonic-gate 		if (ciphers[i].nid == nid)
21470Sstevel@tonic-gate 			return (ciphers[i].id);
21480Sstevel@tonic-gate 	return (-1);
21490Sstevel@tonic-gate 	}
21500Sstevel@tonic-gate 
21510Sstevel@tonic-gate static int
21520Sstevel@tonic-gate pk11_usable_ciphers(const int **nids)
21530Sstevel@tonic-gate 	{
21540Sstevel@tonic-gate 	if (cipher_count > 0)
21550Sstevel@tonic-gate 		*nids = cipher_nids;
21560Sstevel@tonic-gate 	else
21570Sstevel@tonic-gate 		*nids = NULL;
21580Sstevel@tonic-gate 	return (cipher_count);
21590Sstevel@tonic-gate 	}
21600Sstevel@tonic-gate 
21610Sstevel@tonic-gate static int
21620Sstevel@tonic-gate pk11_usable_digests(const int **nids)
21630Sstevel@tonic-gate 	{
21640Sstevel@tonic-gate 	if (digest_count > 0)
21650Sstevel@tonic-gate 		*nids = digest_nids;
21660Sstevel@tonic-gate 	else
21670Sstevel@tonic-gate 		*nids = NULL;
21680Sstevel@tonic-gate 	return (digest_count);
21690Sstevel@tonic-gate 	}
21700Sstevel@tonic-gate 
21717211Sjp161948 /*
21727211Sjp161948  * Init context for encryption or decryption using a symmetric key.
21737211Sjp161948  */
21747211Sjp161948 static int pk11_init_symmetric(EVP_CIPHER_CTX *ctx, PK11_CIPHER *pcipher,
21757211Sjp161948 	PK11_SESSION *sp, CK_MECHANISM_PTR pmech)
21767211Sjp161948 	{
21777211Sjp161948 	CK_RV rv;
21787211Sjp161948 #ifdef	SOLARIS_AES_CTR
21797211Sjp161948 	CK_AES_CTR_PARAMS ctr_params;
21807211Sjp161948 #endif	/* SOLARIS_AES_CTR */
2181*7616SVladimir.Kotal@Sun.COM 
21827211Sjp161948 	/*
21837211Sjp161948 	 * We expect pmech->mechanism to be already set and
21847211Sjp161948 	 * pParameter/ulParameterLen initialized to NULL/0 before
21857211Sjp161948 	 * pk11_init_symetric() is called.
21867211Sjp161948 	 */
21877211Sjp161948 	OPENSSL_assert(pmech->mechanism != NULL);
21887211Sjp161948 	OPENSSL_assert(pmech->pParameter == NULL);
21897211Sjp161948 	OPENSSL_assert(pmech->ulParameterLen == 0);
21907211Sjp161948 
21917211Sjp161948 #ifdef	SOLARIS_AES_CTR
21927211Sjp161948 	if (ctx->cipher->nid == NID_aes_128_ctr ||
21937211Sjp161948 	    ctx->cipher->nid == NID_aes_192_ctr ||
21947211Sjp161948 	    ctx->cipher->nid == NID_aes_256_ctr)
21957211Sjp161948 		{
21967211Sjp161948 		pmech->pParameter = (void *)(&ctr_params);
2197*7616SVladimir.Kotal@Sun.COM 		pmech->ulParameterLen = sizeof (ctr_params);
21987211Sjp161948 		/*
21997211Sjp161948 		 * For now, we are limited to the fixed length of the counter,
22007211Sjp161948 		 * it covers the whole counter block. That's what RFC 4344
22017211Sjp161948 		 * needs. For more information on internal structure of the
22027211Sjp161948 		 * counter block, see RFC 3686. If needed in the future, we can
22037211Sjp161948 		 * add code so that the counter length can be set via
22047211Sjp161948 		 * ENGINE_ctrl() function.
22057211Sjp161948 		 */
22067211Sjp161948 		ctr_params.ulCounterBits = AES_BLOCK_SIZE * 8;
22077211Sjp161948 		OPENSSL_assert(pcipher->iv_len == AES_BLOCK_SIZE);
22087534SVladimir.Kotal@Sun.COM 		(void) memcpy(ctr_params.cb, ctx->iv, AES_BLOCK_SIZE);
22097211Sjp161948 		}
22107211Sjp161948 	else
22117211Sjp161948 #endif	/* SOLARIS_AES_CTR */
22127211Sjp161948 		{
22137211Sjp161948 		if (pcipher->iv_len > 0)
22147211Sjp161948 			{
22157211Sjp161948 			pmech->pParameter = (void *)ctx->iv;
22167211Sjp161948 			pmech->ulParameterLen = pcipher->iv_len;
22177211Sjp161948 			}
22187211Sjp161948 		}
22197211Sjp161948 
22207211Sjp161948 	/* if we get here, the encryption needs to be reinitialized */
22217211Sjp161948 	if (ctx->encrypt)
22227526SVladimir.Kotal@Sun.COM 		rv = pFuncList->C_EncryptInit(sp->session, pmech,
22237526SVladimir.Kotal@Sun.COM 			sp->opdata_cipher_key);
22247211Sjp161948 	else
22257526SVladimir.Kotal@Sun.COM 		rv = pFuncList->C_DecryptInit(sp->session, pmech,
22267526SVladimir.Kotal@Sun.COM 			sp->opdata_cipher_key);
22277211Sjp161948 
22287211Sjp161948 	if (rv != CKR_OK)
22297211Sjp161948 		{
22307211Sjp161948 		PK11err_add_data(PK11_F_CIPHER_INIT, ctx->encrypt ?
22317211Sjp161948 		    PK11_R_ENCRYPTINIT : PK11_R_DECRYPTINIT, rv);
22327211Sjp161948 		pk11_return_session(sp, OP_CIPHER);
22337211Sjp161948 		return (0);
22347211Sjp161948 		}
22357211Sjp161948 
22367211Sjp161948 	return (1);
22377211Sjp161948 	}
22387211Sjp161948 
22397534SVladimir.Kotal@Sun.COM /* ARGSUSED */
22400Sstevel@tonic-gate static int
22410Sstevel@tonic-gate pk11_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
22420Sstevel@tonic-gate     const unsigned char *iv, int enc)
22430Sstevel@tonic-gate 	{
22444320Sjp161948 	CK_MECHANISM mech;
22450Sstevel@tonic-gate 	int index;
22460Sstevel@tonic-gate 	PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->cipher_data;
22470Sstevel@tonic-gate 	PK11_SESSION *sp;
22487211Sjp161948 	PK11_CIPHER *p_ciph_table_row;
2249*7616SVladimir.Kotal@Sun.COM 
22500Sstevel@tonic-gate 	state->sp = NULL;
22510Sstevel@tonic-gate 
22520Sstevel@tonic-gate 	index = cipher_nid_to_pk11(ctx->cipher->nid);
22530Sstevel@tonic-gate 	if (index < 0 || index >= PK11_CIPHER_MAX)
2254*7616SVladimir.Kotal@Sun.COM 		return (0);
22550Sstevel@tonic-gate 
22567211Sjp161948 	p_ciph_table_row = &ciphers[index];
22577211Sjp161948 	/*
22587211Sjp161948 	 * iv_len in the ctx->cipher structure is the maximum IV length for the
22597211Sjp161948 	 * current cipher and it must be less or equal to the IV length in our
22607211Sjp161948 	 * ciphers table. The key length must match precisely. Every application
22617211Sjp161948 	 * can define its own EVP functions so this code serves as a sanity
22627211Sjp161948 	 * check.
22637211Sjp161948 	 *
22647211Sjp161948 	 * Note that the reason why the IV length in ctx->cipher might be
22657211Sjp161948 	 * greater than the actual length is that OpenSSL uses BLOCK_CIPHER_defs
22667211Sjp161948 	 * macro to define functions that return EVP structures for all DES
22677211Sjp161948 	 * modes. So, even ECB modes get 8 byte IV.
22687211Sjp161948 	 */
22697211Sjp161948 	if (ctx->cipher->iv_len < p_ciph_table_row->iv_len ||
22707211Sjp161948 	    ctx->key_len != p_ciph_table_row->key_len)
22717211Sjp161948 		{
22727211Sjp161948 		PK11err(PK11_F_CIPHER_INIT, PK11_R_KEY_OR_IV_LEN_PROBLEM);
2273*7616SVladimir.Kotal@Sun.COM 		return (0);
22747211Sjp161948 		}
22757211Sjp161948 
22767211Sjp161948 	if ((sp = pk11_get_session(OP_CIPHER)) == NULL)
2277*7616SVladimir.Kotal@Sun.COM 		return (0);
22780Sstevel@tonic-gate 
22794320Sjp161948 	/* if applicable, the mechanism parameter is used for IV */
22807211Sjp161948 	mech.mechanism = p_ciph_table_row->mech_type;
22814320Sjp161948 	mech.pParameter = NULL;
22824320Sjp161948 	mech.ulParameterLen = 0;
22834320Sjp161948 
2284*7616SVladimir.Kotal@Sun.COM 	/* The key object is destroyed here if it is not the current key. */
22857211Sjp161948 	(void) check_new_cipher_key(sp, key, p_ciph_table_row->key_len);
2286*7616SVladimir.Kotal@Sun.COM 
2287*7616SVladimir.Kotal@Sun.COM 	/*
2288*7616SVladimir.Kotal@Sun.COM 	 * If the key is the same and the encryption is also the same, then
2289*7616SVladimir.Kotal@Sun.COM 	 * just reuse it. However, we must not forget to reinitialize the
22906847Svk199839 	 * context that was finalized in pk11_cipher_cleanup().
22910Sstevel@tonic-gate 	 */
22927526SVladimir.Kotal@Sun.COM 	if (sp->opdata_cipher_key != CK_INVALID_HANDLE &&
22937526SVladimir.Kotal@Sun.COM 	    sp->opdata_encrypt == ctx->encrypt)
22940Sstevel@tonic-gate 		{
22950Sstevel@tonic-gate 		state->sp = sp;
22967211Sjp161948 		if (pk11_init_symmetric(ctx, p_ciph_table_row, sp, &mech) == 0)
22976847Svk199839 			return (0);
22986847Svk199839 
22996847Svk199839 		return (1);
23000Sstevel@tonic-gate 		}
23010Sstevel@tonic-gate 
2302*7616SVladimir.Kotal@Sun.COM 	/*
2303*7616SVladimir.Kotal@Sun.COM 	 * Check if the key has been invalidated. If so, a new key object
23040Sstevel@tonic-gate 	 * needs to be created.
23050Sstevel@tonic-gate 	 */
23067526SVladimir.Kotal@Sun.COM 	if (sp->opdata_cipher_key == CK_INVALID_HANDLE)
23070Sstevel@tonic-gate 		{
23087526SVladimir.Kotal@Sun.COM 		sp->opdata_cipher_key = pk11_get_cipher_key(
23097211Sjp161948 			ctx, key, p_ciph_table_row->key_type, sp);
23100Sstevel@tonic-gate 		}
23110Sstevel@tonic-gate 
23127526SVladimir.Kotal@Sun.COM 	if (sp->opdata_encrypt != ctx->encrypt && sp->opdata_encrypt != -1)
23130Sstevel@tonic-gate 		{
2314*7616SVladimir.Kotal@Sun.COM 		/*
2315*7616SVladimir.Kotal@Sun.COM 		 * The previous encryption/decryption is different. Need to
2316*7616SVladimir.Kotal@Sun.COM 		 * terminate the previous * active encryption/decryption here.
23170Sstevel@tonic-gate 		 */
23180Sstevel@tonic-gate 		if (!pk11_cipher_final(sp))
23190Sstevel@tonic-gate 			{
23207211Sjp161948 			pk11_return_session(sp, OP_CIPHER);
2321*7616SVladimir.Kotal@Sun.COM 			return (0);
23220Sstevel@tonic-gate 			}
23230Sstevel@tonic-gate 		}
23240Sstevel@tonic-gate 
23257526SVladimir.Kotal@Sun.COM 	if (sp->opdata_cipher_key == CK_INVALID_HANDLE)
23260Sstevel@tonic-gate 		{
23277211Sjp161948 		pk11_return_session(sp, OP_CIPHER);
2328*7616SVladimir.Kotal@Sun.COM 		return (0);
23290Sstevel@tonic-gate 		}
23300Sstevel@tonic-gate 
23316847Svk199839 	/* now initialize the context with a new key */
23327211Sjp161948 	if (pk11_init_symmetric(ctx, p_ciph_table_row, sp, &mech) == 0)
23336847Svk199839 		return (0);
23340Sstevel@tonic-gate 
23357526SVladimir.Kotal@Sun.COM 	sp->opdata_encrypt = ctx->encrypt;
23360Sstevel@tonic-gate 	state->sp = sp;
23370Sstevel@tonic-gate 
2338*7616SVladimir.Kotal@Sun.COM 	return (1);
23390Sstevel@tonic-gate 	}
23400Sstevel@tonic-gate 
2341*7616SVladimir.Kotal@Sun.COM /*
2342*7616SVladimir.Kotal@Sun.COM  * When reusing the same key in an encryption/decryption session for a
23430Sstevel@tonic-gate  * decryption/encryption session, we need to close the active session
23440Sstevel@tonic-gate  * and recreate a new one. Note that the key is in the global session so
23450Sstevel@tonic-gate  * that it needs not be recreated.
23460Sstevel@tonic-gate  *
23470Sstevel@tonic-gate  * It is more appropriate to use C_En/DecryptFinish here. At the time of this
23480Sstevel@tonic-gate  * development, these two functions in the PKCS#11 libraries used return
23490Sstevel@tonic-gate  * unexpected errors when passing in 0 length output. It may be a good
23500Sstevel@tonic-gate  * idea to try them again if performance is a problem here and fix
23510Sstevel@tonic-gate  * C_En/DecryptFinial if there are bugs there causing the problem.
23520Sstevel@tonic-gate  */
23530Sstevel@tonic-gate static int
23540Sstevel@tonic-gate pk11_cipher_final(PK11_SESSION *sp)
23550Sstevel@tonic-gate 	{
23560Sstevel@tonic-gate 	CK_RV rv;
23570Sstevel@tonic-gate 
23587526SVladimir.Kotal@Sun.COM 	rv = pFuncList->C_CloseSession(sp->session);
23590Sstevel@tonic-gate 	if (rv != CKR_OK)
23600Sstevel@tonic-gate 		{
23617211Sjp161948 		PK11err_add_data(PK11_F_CIPHER_FINAL, PK11_R_CLOSESESSION, rv);
2362*7616SVladimir.Kotal@Sun.COM 		return (0);
23630Sstevel@tonic-gate 		}
23640Sstevel@tonic-gate 
23650Sstevel@tonic-gate 	rv = pFuncList->C_OpenSession(SLOTID, CKF_SERIAL_SESSION,
23667526SVladimir.Kotal@Sun.COM 		NULL_PTR, NULL_PTR, &sp->session);
23670Sstevel@tonic-gate 	if (rv != CKR_OK)
23680Sstevel@tonic-gate 		{
23697211Sjp161948 		PK11err_add_data(PK11_F_CIPHER_FINAL, PK11_R_OPENSESSION, rv);
2370*7616SVladimir.Kotal@Sun.COM 		return (0);
23710Sstevel@tonic-gate 		}
23720Sstevel@tonic-gate 
2373*7616SVladimir.Kotal@Sun.COM 	return (1);
23740Sstevel@tonic-gate 	}
23750Sstevel@tonic-gate 
2376*7616SVladimir.Kotal@Sun.COM /*
2377*7616SVladimir.Kotal@Sun.COM  * An engine interface function. The calling function allocates sufficient
2378*7616SVladimir.Kotal@Sun.COM  * memory for the output buffer "out" to hold the results.
2379*7616SVladimir.Kotal@Sun.COM  */
23800Sstevel@tonic-gate static int
23810Sstevel@tonic-gate pk11_cipher_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
23820Sstevel@tonic-gate 	const unsigned char *in, unsigned int inl)
23830Sstevel@tonic-gate 	{
23840Sstevel@tonic-gate 	PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->cipher_data;
23850Sstevel@tonic-gate 	PK11_SESSION *sp;
23860Sstevel@tonic-gate 	CK_RV rv;
23870Sstevel@tonic-gate 	unsigned long outl = inl;
23880Sstevel@tonic-gate 
23890Sstevel@tonic-gate 	if (state == NULL || state->sp == NULL)
2390*7616SVladimir.Kotal@Sun.COM 		return (0);
23910Sstevel@tonic-gate 
23920Sstevel@tonic-gate 	sp = (PK11_SESSION *) state->sp;
23930Sstevel@tonic-gate 
23940Sstevel@tonic-gate 	if (!inl)
2395*7616SVladimir.Kotal@Sun.COM 		return (1);
23960Sstevel@tonic-gate 
23970Sstevel@tonic-gate 	/* RC4 is the only stream cipher we support */
23980Sstevel@tonic-gate 	if (ctx->cipher->nid != NID_rc4 && (inl % ctx->cipher->block_size) != 0)
2399*7616SVladimir.Kotal@Sun.COM 		return (0);
24000Sstevel@tonic-gate 
24010Sstevel@tonic-gate 	if (ctx->encrypt)
24020Sstevel@tonic-gate 		{
24037526SVladimir.Kotal@Sun.COM 		rv = pFuncList->C_EncryptUpdate(sp->session,
24040Sstevel@tonic-gate 			(unsigned char *)in, inl, out, &outl);
24050Sstevel@tonic-gate 
24060Sstevel@tonic-gate 		if (rv != CKR_OK)
24070Sstevel@tonic-gate 			{
2408*7616SVladimir.Kotal@Sun.COM 			PK11err_add_data(PK11_F_CIPHER_DO_CIPHER,
24097211Sjp161948 			    PK11_R_ENCRYPTUPDATE, rv);
2410*7616SVladimir.Kotal@Sun.COM 			return (0);
24110Sstevel@tonic-gate 			}
24120Sstevel@tonic-gate 		}
24130Sstevel@tonic-gate 	else
24140Sstevel@tonic-gate 		{
24157526SVladimir.Kotal@Sun.COM 		rv = pFuncList->C_DecryptUpdate(sp->session,
24160Sstevel@tonic-gate 			(unsigned char *)in, inl, out, &outl);
24170Sstevel@tonic-gate 
24180Sstevel@tonic-gate 		if (rv != CKR_OK)
24190Sstevel@tonic-gate 			{
24207211Sjp161948 			PK11err_add_data(PK11_F_CIPHER_DO_CIPHER,
24217211Sjp161948 			    PK11_R_DECRYPTUPDATE, rv);
2422*7616SVladimir.Kotal@Sun.COM 			return (0);
24230Sstevel@tonic-gate 			}
24240Sstevel@tonic-gate 		}
24250Sstevel@tonic-gate 
2426*7616SVladimir.Kotal@Sun.COM 	/*
2427*7616SVladimir.Kotal@Sun.COM 	 * For DES_CBC, DES3_CBC, AES_CBC, and RC4, the output size is always
2428*7616SVladimir.Kotal@Sun.COM 	 * the same size of input.
2429*7616SVladimir.Kotal@Sun.COM 	 * The application has guaranteed to call the block ciphers with
24300Sstevel@tonic-gate 	 * correctly aligned buffers.
24310Sstevel@tonic-gate 	 */
24320Sstevel@tonic-gate 	if (inl != outl)
2433*7616SVladimir.Kotal@Sun.COM 		return (0);
2434*7616SVladimir.Kotal@Sun.COM 
2435*7616SVladimir.Kotal@Sun.COM 	return (1);
24360Sstevel@tonic-gate 	}
24370Sstevel@tonic-gate 
24386847Svk199839 /*
24397211Sjp161948  * Return the session to the pool. Calling C_EncryptFinal() and C_DecryptFinal()
24407211Sjp161948  * here is the right thing because in EVP_DecryptFinal_ex(), engine's
24417211Sjp161948  * do_cipher() is not even called, and in EVP_EncryptFinal_ex() it is called but
24427211Sjp161948  * the engine can't find out that it's the finalizing call. We wouldn't
24437211Sjp161948  * necessarily have to finalize the context here since reinitializing it with
24447211Sjp161948  * C_(Encrypt|Decrypt)Init() should be fine but for the sake of correctness,
24457211Sjp161948  * let's do it. Some implementations might leak memory if the previously used
24467211Sjp161948  * context is initialized without finalizing it first.
24470Sstevel@tonic-gate  */
24480Sstevel@tonic-gate static int
24490Sstevel@tonic-gate pk11_cipher_cleanup(EVP_CIPHER_CTX *ctx)
24500Sstevel@tonic-gate 	{
24516847Svk199839 	CK_RV rv;
24527211Sjp161948 	CK_ULONG len = EVP_MAX_BLOCK_LENGTH;
24536847Svk199839 	CK_BYTE buf[EVP_MAX_BLOCK_LENGTH];
24540Sstevel@tonic-gate 	PK11_CIPHER_STATE *state = ctx->cipher_data;
24550Sstevel@tonic-gate 
24560Sstevel@tonic-gate 	if (state != NULL && state->sp != NULL)
24570Sstevel@tonic-gate 		{
24586847Svk199839 		/*
24596847Svk199839 		 * We are not interested in the data here, we just need to get
24606847Svk199839 		 * rid of the context.
24616847Svk199839 		 */
24626847Svk199839 		if (ctx->encrypt)
24636847Svk199839 			rv = pFuncList->C_EncryptFinal(
24647526SVladimir.Kotal@Sun.COM 			    state->sp->session, buf, &len);
24656847Svk199839 		else
24666847Svk199839 			rv = pFuncList->C_DecryptFinal(
24677526SVladimir.Kotal@Sun.COM 			    state->sp->session, buf, &len);
24686847Svk199839 
24696847Svk199839 		if (rv != CKR_OK)
24706847Svk199839 			{
24717211Sjp161948 			PK11err_add_data(PK11_F_CIPHER_CLEANUP, ctx->encrypt ?
24727211Sjp161948 			    PK11_R_ENCRYPTFINAL : PK11_R_DECRYPTFINAL, rv);
24737211Sjp161948 			pk11_return_session(state->sp, OP_CIPHER);
24746847Svk199839 			return (0);
24756847Svk199839 			}
24766847Svk199839 
24777211Sjp161948 		pk11_return_session(state->sp, OP_CIPHER);
24780Sstevel@tonic-gate 		state->sp = NULL;
24790Sstevel@tonic-gate 		}
24800Sstevel@tonic-gate 
24816847Svk199839 	return (1);
24826847Svk199839 	}
24836847Svk199839 
2484*7616SVladimir.Kotal@Sun.COM /*
2485*7616SVladimir.Kotal@Sun.COM  * Registered by the ENGINE when used to find out how to deal with
24860Sstevel@tonic-gate  * a particular NID in the ENGINE. This says what we'll do at the
24870Sstevel@tonic-gate  * top level - note, that list is restricted by what we answer with
24880Sstevel@tonic-gate  */
24897534SVladimir.Kotal@Sun.COM /* ARGSUSED */
24900Sstevel@tonic-gate static int
24910Sstevel@tonic-gate pk11_engine_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
24920Sstevel@tonic-gate 	const int **nids, int nid)
24930Sstevel@tonic-gate 	{
24940Sstevel@tonic-gate 	if (!cipher)
24950Sstevel@tonic-gate 		return (pk11_usable_ciphers(nids));
24960Sstevel@tonic-gate 
24970Sstevel@tonic-gate 	switch (nid)
24980Sstevel@tonic-gate 		{
24990Sstevel@tonic-gate 		case NID_des_ede3_cbc:
25000Sstevel@tonic-gate 			*cipher = &pk11_3des_cbc;
25010Sstevel@tonic-gate 			break;
25020Sstevel@tonic-gate 		case NID_des_cbc:
25030Sstevel@tonic-gate 			*cipher = &pk11_des_cbc;
25040Sstevel@tonic-gate 			break;
25057211Sjp161948 		case NID_des_ede3_ecb:
25067211Sjp161948 			*cipher = &pk11_3des_ecb;
25077211Sjp161948 			break;
25087211Sjp161948 		case NID_des_ecb:
25097211Sjp161948 			*cipher = &pk11_des_ecb;
25107211Sjp161948 			break;
25110Sstevel@tonic-gate 		case NID_aes_128_cbc:
25127211Sjp161948 			*cipher = &pk11_aes_128_cbc;
25137211Sjp161948 			break;
25147211Sjp161948 		case NID_aes_192_cbc:
25157211Sjp161948 			*cipher = &pk11_aes_192_cbc;
25167211Sjp161948 			break;
25177211Sjp161948 		case NID_aes_256_cbc:
25187211Sjp161948 			*cipher = &pk11_aes_256_cbc;
25197211Sjp161948 			break;
25207211Sjp161948 		case NID_aes_128_ecb:
25217211Sjp161948 			*cipher = &pk11_aes_128_ecb;
25227211Sjp161948 			break;
25237211Sjp161948 		case NID_aes_192_ecb:
25247211Sjp161948 			*cipher = &pk11_aes_192_ecb;
25257211Sjp161948 			break;
25267211Sjp161948 		case NID_aes_256_ecb:
25277211Sjp161948 			*cipher = &pk11_aes_256_ecb;
25287211Sjp161948 			break;
25297211Sjp161948 		case NID_bf_cbc:
25307211Sjp161948 			*cipher = &pk11_bf_cbc;
25310Sstevel@tonic-gate 			break;
25320Sstevel@tonic-gate 		case NID_rc4:
25330Sstevel@tonic-gate 			*cipher = &pk11_rc4;
25340Sstevel@tonic-gate 			break;
25350Sstevel@tonic-gate 		default:
25367211Sjp161948 #ifdef	SOLARIS_AES_CTR
25377211Sjp161948 			/*
25387211Sjp161948 			 * These can't be in separated cases because the NIDs
25397211Sjp161948 			 * here are not constants.
25407211Sjp161948 			 */
25417211Sjp161948 			if (nid == NID_aes_128_ctr)
25427211Sjp161948 				*cipher = &pk11_aes_128_ctr;
25437211Sjp161948 			else if (nid == NID_aes_192_ctr)
25447211Sjp161948 				*cipher = &pk11_aes_192_ctr;
25457211Sjp161948 			else if (nid == NID_aes_256_ctr)
25467211Sjp161948 				*cipher = &pk11_aes_256_ctr;
25477211Sjp161948 			else
25487211Sjp161948 #endif	/* SOLARIS_AES_CTR */
25490Sstevel@tonic-gate 			*cipher = NULL;
25500Sstevel@tonic-gate 			break;
25510Sstevel@tonic-gate 		}
25520Sstevel@tonic-gate 	return (*cipher != NULL);
25530Sstevel@tonic-gate 	}
25540Sstevel@tonic-gate 
25557534SVladimir.Kotal@Sun.COM /* ARGSUSED */
25560Sstevel@tonic-gate static int
25570Sstevel@tonic-gate pk11_engine_digests(ENGINE *e, const EVP_MD **digest,
25580Sstevel@tonic-gate 	const int **nids, int nid)
25590Sstevel@tonic-gate 	{
25600Sstevel@tonic-gate 	if (!digest)
25610Sstevel@tonic-gate 		return (pk11_usable_digests(nids));
25620Sstevel@tonic-gate 
25630Sstevel@tonic-gate 	switch (nid)
25640Sstevel@tonic-gate 		{
25650Sstevel@tonic-gate 		case NID_md5:
2566*7616SVladimir.Kotal@Sun.COM 			*digest = &pk11_md5;
25670Sstevel@tonic-gate 			break;
25680Sstevel@tonic-gate 		case NID_sha1:
2569*7616SVladimir.Kotal@Sun.COM 			*digest = &pk11_sha1;
25700Sstevel@tonic-gate 			break;
25717211Sjp161948 		case NID_sha224:
2572*7616SVladimir.Kotal@Sun.COM 			*digest = &pk11_sha224;
25737211Sjp161948 			break;
25747211Sjp161948 		case NID_sha256:
2575*7616SVladimir.Kotal@Sun.COM 			*digest = &pk11_sha256;
25767211Sjp161948 			break;
25777211Sjp161948 		case NID_sha384:
2578*7616SVladimir.Kotal@Sun.COM 			*digest = &pk11_sha384;
25797211Sjp161948 			break;
25807211Sjp161948 		case NID_sha512:
2581*7616SVladimir.Kotal@Sun.COM 			*digest = &pk11_sha512;
25827211Sjp161948 			break;
25830Sstevel@tonic-gate 		default:
25840Sstevel@tonic-gate 			*digest = NULL;
25850Sstevel@tonic-gate 			break;
25860Sstevel@tonic-gate 		}
25870Sstevel@tonic-gate 	return (*digest != NULL);
25880Sstevel@tonic-gate 	}
25890Sstevel@tonic-gate 
25900Sstevel@tonic-gate 
2591*7616SVladimir.Kotal@Sun.COM /* Create a secret key object in a PKCS#11 session */
2592*7616SVladimir.Kotal@Sun.COM static CK_OBJECT_HANDLE pk11_get_cipher_key(EVP_CIPHER_CTX *ctx,
25930Sstevel@tonic-gate 	const unsigned char *key, CK_KEY_TYPE key_type, PK11_SESSION *sp)
25940Sstevel@tonic-gate 	{
25950Sstevel@tonic-gate 	CK_RV rv;
25960Sstevel@tonic-gate 	CK_OBJECT_HANDLE h_key = CK_INVALID_HANDLE;
25970Sstevel@tonic-gate 	CK_OBJECT_CLASS obj_key = CKO_SECRET_KEY;
25980Sstevel@tonic-gate 	CK_ULONG ul_key_attr_count = 6;
25990Sstevel@tonic-gate 
26000Sstevel@tonic-gate 	CK_ATTRIBUTE  a_key_template[] =
26010Sstevel@tonic-gate 		{
2602*7616SVladimir.Kotal@Sun.COM 		{CKA_CLASS, (void*) NULL, sizeof (CK_OBJECT_CLASS)},
2603*7616SVladimir.Kotal@Sun.COM 		{CKA_KEY_TYPE, (void*) NULL, sizeof (CK_KEY_TYPE)},
2604*7616SVladimir.Kotal@Sun.COM 		{CKA_TOKEN, &false, sizeof (false)},
2605*7616SVladimir.Kotal@Sun.COM 		{CKA_ENCRYPT, &true, sizeof (true)},
2606*7616SVladimir.Kotal@Sun.COM 		{CKA_DECRYPT, &true, sizeof (true)},
26070Sstevel@tonic-gate 		{CKA_VALUE, (void*) NULL, 0},
26080Sstevel@tonic-gate 		};
26090Sstevel@tonic-gate 
2610*7616SVladimir.Kotal@Sun.COM 	/*
2611*7616SVladimir.Kotal@Sun.COM 	 * Create secret key object in global_session. All other sessions
26120Sstevel@tonic-gate 	 * can use the key handles. Here is why:
26130Sstevel@tonic-gate 	 * OpenSSL will call EncryptInit and EncryptUpdate using a secret key.
26140Sstevel@tonic-gate 	 * It may then call DecryptInit and DecryptUpdate using the same key.
26150Sstevel@tonic-gate 	 * To use the same key object, we need to call EncryptFinal with
2616*7616SVladimir.Kotal@Sun.COM 	 * a 0 length message. Currently, this does not work for 3DES
26170Sstevel@tonic-gate 	 * mechanism. To get around this problem, we close the session and
26180Sstevel@tonic-gate 	 * then create a new session to use the same key object. When a session
2619*7616SVladimir.Kotal@Sun.COM 	 * is closed, all the object handles will be invalid. Thus, create key
26200Sstevel@tonic-gate 	 * objects in a global session, an individual session may be closed to
26210Sstevel@tonic-gate 	 * terminate the active operation.
26220Sstevel@tonic-gate 	 */
26230Sstevel@tonic-gate 	CK_SESSION_HANDLE session = global_session;
26240Sstevel@tonic-gate 	a_key_template[0].pValue = &obj_key;
26250Sstevel@tonic-gate 	a_key_template[1].pValue = &key_type;
26260Sstevel@tonic-gate 	a_key_template[5].pValue = (void *) key;
26270Sstevel@tonic-gate 	a_key_template[5].ulValueLen = (unsigned long) ctx->key_len;
26280Sstevel@tonic-gate 
2629*7616SVladimir.Kotal@Sun.COM 	rv = pFuncList->C_CreateObject(session,
26304602Sjp161948 		a_key_template, ul_key_attr_count, &h_key);
26310Sstevel@tonic-gate 	if (rv != CKR_OK)
26320Sstevel@tonic-gate 		{
26337211Sjp161948 		PK11err_add_data(PK11_F_GET_CIPHER_KEY, PK11_R_CREATEOBJECT,
26347211Sjp161948 		    rv);
26350Sstevel@tonic-gate 		goto err;
26360Sstevel@tonic-gate 		}
26370Sstevel@tonic-gate 
2638*7616SVladimir.Kotal@Sun.COM 	/*
2639*7616SVladimir.Kotal@Sun.COM 	 * Save the key information used in this session.
26400Sstevel@tonic-gate 	 * The max can be saved is PK11_KEY_LEN_MAX.
26410Sstevel@tonic-gate 	 */
26427526SVladimir.Kotal@Sun.COM 	sp->opdata_key_len = ctx->key_len > PK11_KEY_LEN_MAX ?
26430Sstevel@tonic-gate 		PK11_KEY_LEN_MAX : ctx->key_len;
26447534SVladimir.Kotal@Sun.COM 	(void) memcpy(sp->opdata_key, key, sp->opdata_key_len);
26450Sstevel@tonic-gate err:
26460Sstevel@tonic-gate 
2647*7616SVladimir.Kotal@Sun.COM 	return (h_key);
26480Sstevel@tonic-gate 	}
26490Sstevel@tonic-gate 
26500Sstevel@tonic-gate static int
26510Sstevel@tonic-gate md_nid_to_pk11(int nid)
26520Sstevel@tonic-gate 	{
26530Sstevel@tonic-gate 	int i;
26540Sstevel@tonic-gate 
26550Sstevel@tonic-gate 	for (i = 0; i < PK11_DIGEST_MAX; i++)
26560Sstevel@tonic-gate 		if (digests[i].nid == nid)
26570Sstevel@tonic-gate 			return (digests[i].id);
26580Sstevel@tonic-gate 	return (-1);
26590Sstevel@tonic-gate 	}
26600Sstevel@tonic-gate 
2661*7616SVladimir.Kotal@Sun.COM static int
26620Sstevel@tonic-gate pk11_digest_init(EVP_MD_CTX *ctx)
2663*7616SVladimir.Kotal@Sun.COM 	{
26640Sstevel@tonic-gate 	CK_RV rv;
26654320Sjp161948 	CK_MECHANISM mech;
26660Sstevel@tonic-gate 	int index;
26670Sstevel@tonic-gate 	PK11_SESSION *sp;
26680Sstevel@tonic-gate 	PK11_DIGEST *pdp;
26690Sstevel@tonic-gate 	PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->md_data;
2670*7616SVladimir.Kotal@Sun.COM 
26710Sstevel@tonic-gate 	state->sp = NULL;
26720Sstevel@tonic-gate 
26730Sstevel@tonic-gate 	index = md_nid_to_pk11(ctx->digest->type);
26740Sstevel@tonic-gate 	if (index < 0 || index >= PK11_DIGEST_MAX)
2675*7616SVladimir.Kotal@Sun.COM 		return (0);
26760Sstevel@tonic-gate 
26770Sstevel@tonic-gate 	pdp = &digests[index];
26787211Sjp161948 	if ((sp = pk11_get_session(OP_DIGEST)) == NULL)
2679*7616SVladimir.Kotal@Sun.COM 		return (0);
26800Sstevel@tonic-gate 
26814320Sjp161948 	/* at present, no parameter is needed for supported digests */
26824320Sjp161948 	mech.mechanism = pdp->mech_type;
26834320Sjp161948 	mech.pParameter = NULL;
26844320Sjp161948 	mech.ulParameterLen = 0;
26854320Sjp161948 
26864320Sjp161948 	rv = pFuncList->C_DigestInit(sp->session, &mech);
26870Sstevel@tonic-gate 
26880Sstevel@tonic-gate 	if (rv != CKR_OK)
26890Sstevel@tonic-gate 		{
26907211Sjp161948 		PK11err_add_data(PK11_F_DIGEST_INIT, PK11_R_DIGESTINIT, rv);
26917211Sjp161948 		pk11_return_session(sp, OP_DIGEST);
2692*7616SVladimir.Kotal@Sun.COM 		return (0);
26930Sstevel@tonic-gate 		}
26940Sstevel@tonic-gate 
26950Sstevel@tonic-gate 	state->sp = sp;
26960Sstevel@tonic-gate 
2697*7616SVladimir.Kotal@Sun.COM 	return (1);
26980Sstevel@tonic-gate 	}
26990Sstevel@tonic-gate 
2700*7616SVladimir.Kotal@Sun.COM static int
2701*7616SVladimir.Kotal@Sun.COM pk11_digest_update(EVP_MD_CTX *ctx, const void *data, size_t count)
2702*7616SVladimir.Kotal@Sun.COM 	{
27030Sstevel@tonic-gate 	CK_RV rv;
27040Sstevel@tonic-gate 	PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->md_data;
2705*7616SVladimir.Kotal@Sun.COM 
27060Sstevel@tonic-gate 	/* 0 length message will cause a failure in C_DigestFinal */
27070Sstevel@tonic-gate 	if (count == 0)
2708*7616SVladimir.Kotal@Sun.COM 		return (1);
27090Sstevel@tonic-gate 
27100Sstevel@tonic-gate 	if (state == NULL || state->sp == NULL)
2711*7616SVladimir.Kotal@Sun.COM 		return (0);
27120Sstevel@tonic-gate 
27130Sstevel@tonic-gate 	rv = pFuncList->C_DigestUpdate(state->sp->session, (CK_BYTE *) data,
27140Sstevel@tonic-gate 		count);
27150Sstevel@tonic-gate 
27160Sstevel@tonic-gate 	if (rv != CKR_OK)
27170Sstevel@tonic-gate 		{
27187211Sjp161948 		PK11err_add_data(PK11_F_DIGEST_UPDATE, PK11_R_DIGESTUPDATE, rv);
27197211Sjp161948 		pk11_return_session(state->sp, OP_DIGEST);
27200Sstevel@tonic-gate 		state->sp = NULL;
2721*7616SVladimir.Kotal@Sun.COM 		return (0);
27220Sstevel@tonic-gate 		}
27230Sstevel@tonic-gate 
2724*7616SVladimir.Kotal@Sun.COM 	return (1);
27250Sstevel@tonic-gate 	}
27260Sstevel@tonic-gate 
2727*7616SVladimir.Kotal@Sun.COM static int
2728*7616SVladimir.Kotal@Sun.COM pk11_digest_final(EVP_MD_CTX *ctx, unsigned char *md)
2729*7616SVladimir.Kotal@Sun.COM 	{
27300Sstevel@tonic-gate 	CK_RV rv;
27310Sstevel@tonic-gate 	unsigned long len;
27320Sstevel@tonic-gate 	PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->md_data;
27330Sstevel@tonic-gate 	len = ctx->digest->md_size;
2734*7616SVladimir.Kotal@Sun.COM 
27350Sstevel@tonic-gate 	if (state == NULL || state->sp == NULL)
2736*7616SVladimir.Kotal@Sun.COM 		return (0);
27370Sstevel@tonic-gate 
27380Sstevel@tonic-gate 	rv = pFuncList->C_DigestFinal(state->sp->session, md, &len);
27390Sstevel@tonic-gate 
27400Sstevel@tonic-gate 	if (rv != CKR_OK)
27410Sstevel@tonic-gate 		{
27427211Sjp161948 		PK11err_add_data(PK11_F_DIGEST_FINAL, PK11_R_DIGESTFINAL, rv);
27437211Sjp161948 		pk11_return_session(state->sp, OP_DIGEST);
27440Sstevel@tonic-gate 		state->sp = NULL;
2745*7616SVladimir.Kotal@Sun.COM 		return (0);
27460Sstevel@tonic-gate 		}
27470Sstevel@tonic-gate 
27480Sstevel@tonic-gate 	if (ctx->digest->md_size != len)
2749*7616SVladimir.Kotal@Sun.COM 		return (0);
2750*7616SVladimir.Kotal@Sun.COM 
2751*7616SVladimir.Kotal@Sun.COM 	/*
2752*7616SVladimir.Kotal@Sun.COM 	 * Final is called and digest is returned, so return the session
27530Sstevel@tonic-gate 	 * to the pool
27540Sstevel@tonic-gate 	 */
27557211Sjp161948 	pk11_return_session(state->sp, OP_DIGEST);
27560Sstevel@tonic-gate 	state->sp = NULL;
27570Sstevel@tonic-gate 
2758*7616SVladimir.Kotal@Sun.COM 	return (1);
27590Sstevel@tonic-gate 	}
27600Sstevel@tonic-gate 
2761*7616SVladimir.Kotal@Sun.COM static int
2762*7616SVladimir.Kotal@Sun.COM pk11_digest_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
2763*7616SVladimir.Kotal@Sun.COM 	{
27640Sstevel@tonic-gate 	CK_RV rv;
27650Sstevel@tonic-gate 	int ret = 0;
27660Sstevel@tonic-gate 	PK11_CIPHER_STATE *state, *state_to;
27670Sstevel@tonic-gate 	CK_BYTE_PTR pstate = NULL;
27680Sstevel@tonic-gate 	CK_ULONG ul_state_len;
2769*7616SVladimir.Kotal@Sun.COM 
27700Sstevel@tonic-gate 	/* The copy-from state */
27710Sstevel@tonic-gate 	state = (PK11_CIPHER_STATE *) from->md_data;
27720Sstevel@tonic-gate 	if (state == NULL || state->sp == NULL)
27730Sstevel@tonic-gate 		goto err;
27740Sstevel@tonic-gate 
27750Sstevel@tonic-gate 	/* Initialize the copy-to state */
27760Sstevel@tonic-gate 	if (!pk11_digest_init(to))
27770Sstevel@tonic-gate 		goto err;
27780Sstevel@tonic-gate 	state_to = (PK11_CIPHER_STATE *) to->md_data;
27790Sstevel@tonic-gate 
27800Sstevel@tonic-gate 	/* Get the size of the operation state of the copy-from session */
2781*7616SVladimir.Kotal@Sun.COM 	rv = pFuncList->C_GetOperationState(state->sp->session, NULL,
27820Sstevel@tonic-gate 		&ul_state_len);
27830Sstevel@tonic-gate 
27840Sstevel@tonic-gate 	if (rv != CKR_OK)
27850Sstevel@tonic-gate 		{
27867211Sjp161948 		PK11err_add_data(PK11_F_DIGEST_COPY, PK11_R_GET_OPERATION_STATE,
27877211Sjp161948 		    rv);
27880Sstevel@tonic-gate 		goto err;
27890Sstevel@tonic-gate 		}
27900Sstevel@tonic-gate 	if (ul_state_len == 0)
27910Sstevel@tonic-gate 		{
27920Sstevel@tonic-gate 		goto err;
27930Sstevel@tonic-gate 		}
27940Sstevel@tonic-gate 
27950Sstevel@tonic-gate 	pstate = OPENSSL_malloc(ul_state_len);
27960Sstevel@tonic-gate 	if (pstate == NULL)
27970Sstevel@tonic-gate 		{
27986847Svk199839 		PK11err(PK11_F_DIGEST_COPY, PK11_R_MALLOC_FAILURE);
27990Sstevel@tonic-gate 		goto err;
28000Sstevel@tonic-gate 		}
28010Sstevel@tonic-gate 
28020Sstevel@tonic-gate 	/* Get the operation state of the copy-from session */
2803*7616SVladimir.Kotal@Sun.COM 	rv = pFuncList->C_GetOperationState(state->sp->session, pstate,
28040Sstevel@tonic-gate 		&ul_state_len);
28050Sstevel@tonic-gate 
28060Sstevel@tonic-gate 	if (rv != CKR_OK)
28070Sstevel@tonic-gate 		{
28087211Sjp161948 		PK11err_add_data(PK11_F_DIGEST_COPY, PK11_R_GET_OPERATION_STATE,
28097211Sjp161948 		    rv);
28100Sstevel@tonic-gate 		goto err;
28110Sstevel@tonic-gate 		}
28120Sstevel@tonic-gate 
28130Sstevel@tonic-gate 	/* Set the operation state of the copy-to session */
2814*7616SVladimir.Kotal@Sun.COM 	rv = pFuncList->C_SetOperationState(state_to->sp->session, pstate,
28150Sstevel@tonic-gate 		ul_state_len, 0, 0);
28160Sstevel@tonic-gate 
28170Sstevel@tonic-gate 	if (rv != CKR_OK)
28180Sstevel@tonic-gate 		{
2819*7616SVladimir.Kotal@Sun.COM 		PK11err_add_data(PK11_F_DIGEST_COPY,
2820*7616SVladimir.Kotal@Sun.COM 		    PK11_R_SET_OPERATION_STATE, rv);
28210Sstevel@tonic-gate 		goto err;
28220Sstevel@tonic-gate 		}
28230Sstevel@tonic-gate 
28240Sstevel@tonic-gate 	ret = 1;
28250Sstevel@tonic-gate err:
28260Sstevel@tonic-gate 	if (pstate != NULL)
28270Sstevel@tonic-gate 		OPENSSL_free(pstate);
28280Sstevel@tonic-gate 
2829*7616SVladimir.Kotal@Sun.COM 	return (ret);
28300Sstevel@tonic-gate 	}
28310Sstevel@tonic-gate 
28320Sstevel@tonic-gate /* Return any pending session state to the pool */
28330Sstevel@tonic-gate static int
28340Sstevel@tonic-gate pk11_digest_cleanup(EVP_MD_CTX *ctx)
28350Sstevel@tonic-gate 	{
28360Sstevel@tonic-gate 	PK11_CIPHER_STATE *state = ctx->md_data;
28374602Sjp161948 	unsigned char buf[EVP_MAX_MD_SIZE];
28380Sstevel@tonic-gate 
28390Sstevel@tonic-gate 	if (state != NULL && state->sp != NULL)
28400Sstevel@tonic-gate 		{
28414602Sjp161948 		/*
28424602Sjp161948 		 * If state->sp is not NULL then pk11_digest_final() has not
28434602Sjp161948 		 * been called yet. We must call it now to free any memory
28444602Sjp161948 		 * that might have been allocated in the token when
28454602Sjp161948 		 * pk11_digest_init() was called.
28464602Sjp161948 		 */
28477526SVladimir.Kotal@Sun.COM 		(void) pk11_digest_final(ctx, buf);
28487211Sjp161948 		pk11_return_session(state->sp, OP_DIGEST);
28490Sstevel@tonic-gate 		state->sp = NULL;
28500Sstevel@tonic-gate 		}
28510Sstevel@tonic-gate 
2852*7616SVladimir.Kotal@Sun.COM 	return (1);
28530Sstevel@tonic-gate 	}
28540Sstevel@tonic-gate 
28556847Svk199839 /*
28567211Sjp161948  * Check if the new key is the same as the key object in the session. If the key
28577211Sjp161948  * is the same, no need to create a new key object. Otherwise, the old key
28587211Sjp161948  * object needs to be destroyed and a new one will be created. Return 1 for
28597211Sjp161948  * cache hit, 0 for cache miss. Note that we must check the key length first
28607211Sjp161948  * otherwise we could end up reusing a different, longer key with the same
28617211Sjp161948  * prefix.
28620Sstevel@tonic-gate  */
28637211Sjp161948 static int check_new_cipher_key(PK11_SESSION *sp, const unsigned char *key,
28647211Sjp161948 	int key_len)
28650Sstevel@tonic-gate 	{
28667526SVladimir.Kotal@Sun.COM 	if (sp->opdata_key_len != key_len ||
28677526SVladimir.Kotal@Sun.COM 	    memcmp(sp->opdata_key, key, key_len) != 0)
28686847Svk199839 		{
28697211Sjp161948 		(void) pk11_destroy_cipher_key_objects(sp);
28706847Svk199839 		return (0);
28716847Svk199839 		}
28726847Svk199839 	return (1);
28730Sstevel@tonic-gate 	}
28740Sstevel@tonic-gate 
2875*7616SVladimir.Kotal@Sun.COM /* Destroy one or more secret key objects. */
28760Sstevel@tonic-gate static int pk11_destroy_cipher_key_objects(PK11_SESSION *session)
28770Sstevel@tonic-gate 	{
28780Sstevel@tonic-gate 	int ret = 0;
28790Sstevel@tonic-gate 	PK11_SESSION *sp = NULL;
28800Sstevel@tonic-gate 	PK11_SESSION *local_free_session;
28810Sstevel@tonic-gate 
28827526SVladimir.Kotal@Sun.COM 	if (session != NULL)
28830Sstevel@tonic-gate 		local_free_session = session;
28840Sstevel@tonic-gate 	else
28857526SVladimir.Kotal@Sun.COM 		{
28867526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_lock(session_cache[OP_CIPHER].lock);
28877526SVladimir.Kotal@Sun.COM 		local_free_session = session_cache[OP_CIPHER].head;
28887526SVladimir.Kotal@Sun.COM 		}
28897526SVladimir.Kotal@Sun.COM 
28900Sstevel@tonic-gate 	while ((sp = local_free_session) != NULL)
28910Sstevel@tonic-gate 		{
28920Sstevel@tonic-gate 		local_free_session = sp->next;
28930Sstevel@tonic-gate 
28947526SVladimir.Kotal@Sun.COM 		if (sp->opdata_cipher_key != CK_INVALID_HANDLE)
28950Sstevel@tonic-gate 			{
2896*7616SVladimir.Kotal@Sun.COM 			/*
2897*7616SVladimir.Kotal@Sun.COM 			 * The secret key object is created in the
28980Sstevel@tonic-gate 			 * global_session. See pk11_get_cipher_key
28990Sstevel@tonic-gate 			 */
2900*7616SVladimir.Kotal@Sun.COM 			if (pk11_destroy_object(global_session,
29017526SVladimir.Kotal@Sun.COM 				sp->opdata_cipher_key) == 0)
29020Sstevel@tonic-gate 				goto err;
29037526SVladimir.Kotal@Sun.COM 			sp->opdata_cipher_key = CK_INVALID_HANDLE;
29040Sstevel@tonic-gate 			}
29050Sstevel@tonic-gate 		}
29060Sstevel@tonic-gate 	ret = 1;
29070Sstevel@tonic-gate err:
29087526SVladimir.Kotal@Sun.COM 
29097526SVladimir.Kotal@Sun.COM 	if (session == NULL)
29107526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_unlock(session_cache[OP_CIPHER].lock);
29110Sstevel@tonic-gate 
2912*7616SVladimir.Kotal@Sun.COM 	return (ret);
29130Sstevel@tonic-gate 	}
29140Sstevel@tonic-gate 
29150Sstevel@tonic-gate 
29160Sstevel@tonic-gate /*
29177211Sjp161948  * Public key mechanisms optionally supported
29180Sstevel@tonic-gate  *
29190Sstevel@tonic-gate  * CKM_RSA_X_509
29200Sstevel@tonic-gate  * CKM_RSA_PKCS
29210Sstevel@tonic-gate  * CKM_DSA
29220Sstevel@tonic-gate  *
29237211Sjp161948  * The first slot that supports at least one of those mechanisms is chosen as a
29247211Sjp161948  * public key slot.
29250Sstevel@tonic-gate  *
29260Sstevel@tonic-gate  * Symmetric ciphers optionally supported
29270Sstevel@tonic-gate  *
29280Sstevel@tonic-gate  * CKM_DES3_CBC
29290Sstevel@tonic-gate  * CKM_DES_CBC
29300Sstevel@tonic-gate  * CKM_AES_CBC
29317211Sjp161948  * CKM_DES3_ECB
29327211Sjp161948  * CKM_DES_ECB
29337211Sjp161948  * CKM_AES_ECB
29347211Sjp161948  * CKM_AES_CTR
29350Sstevel@tonic-gate  * CKM_RC4
29367211Sjp161948  * CKM_BLOWFISH_CBC
29370Sstevel@tonic-gate  *
29380Sstevel@tonic-gate  * Digests optionally supported
29390Sstevel@tonic-gate  *
29400Sstevel@tonic-gate  * CKM_MD5
29410Sstevel@tonic-gate  * CKM_SHA_1
29427211Sjp161948  * CKM_SHA224
29437211Sjp161948  * CKM_SHA256
29447211Sjp161948  * CKM_SHA384
29457211Sjp161948  * CKM_SHA512
29467211Sjp161948  *
29477211Sjp161948  * The output of this function is a set of global variables indicating which
29487211Sjp161948  * mechanisms from RSA, DSA, DH and RAND are present, and also two arrays of
29497211Sjp161948  * mechanisms, one for symmetric ciphers and one for digests. Also, 3 global
29507211Sjp161948  * variables carry information about which slot was chosen for (a) public key
29517211Sjp161948  * mechanisms, (b) random operations, and (c) symmetric ciphers and digests.
29520Sstevel@tonic-gate  */
2953*7616SVladimir.Kotal@Sun.COM static int
29547211Sjp161948 pk11_choose_slots(int *any_slot_found)
29550Sstevel@tonic-gate 	{
29560Sstevel@tonic-gate 	CK_SLOT_ID_PTR pSlotList = NULL_PTR;
29570Sstevel@tonic-gate 	CK_ULONG ulSlotCount = 0;
29580Sstevel@tonic-gate 	CK_MECHANISM_INFO mech_info;
29590Sstevel@tonic-gate 	CK_TOKEN_INFO token_info;
29600Sstevel@tonic-gate 	int i;
29610Sstevel@tonic-gate 	CK_RV rv;
29620Sstevel@tonic-gate 	CK_SLOT_ID best_slot_sofar;
29630Sstevel@tonic-gate 	CK_BBOOL found_candidate_slot = CK_FALSE;
29640Sstevel@tonic-gate 	int slot_n_cipher = 0;
29650Sstevel@tonic-gate 	int slot_n_digest = 0;
29660Sstevel@tonic-gate 	CK_SLOT_ID current_slot = 0;
29670Sstevel@tonic-gate 	int current_slot_n_cipher = 0;
29680Sstevel@tonic-gate 	int current_slot_n_digest = 0;
29690Sstevel@tonic-gate 
29700Sstevel@tonic-gate 	int local_cipher_nids[PK11_CIPHER_MAX];
29710Sstevel@tonic-gate 	int local_digest_nids[PK11_DIGEST_MAX];
29727211Sjp161948 
29737211Sjp161948 	/* let's initialize the output parameter */
29747211Sjp161948 	if (any_slot_found != NULL)
29757211Sjp161948 		*any_slot_found = 0;
29767211Sjp161948 
29777211Sjp161948 	/* Get slot list for memory allocation */
29780Sstevel@tonic-gate 	rv = pFuncList->C_GetSlotList(0, NULL_PTR, &ulSlotCount);
29790Sstevel@tonic-gate 
29800Sstevel@tonic-gate 	if (rv != CKR_OK)
29810Sstevel@tonic-gate 		{
29827211Sjp161948 		PK11err_add_data(PK11_F_CHOOSE_SLOT, PK11_R_GETSLOTLIST, rv);
2983*7616SVladimir.Kotal@Sun.COM 		return (0);
29840Sstevel@tonic-gate 		}
29850Sstevel@tonic-gate 
29867211Sjp161948 	/* it's not an error if we didn't find any providers */
2987*7616SVladimir.Kotal@Sun.COM 	if (ulSlotCount == 0)
29880Sstevel@tonic-gate 		{
29897211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
29907211Sjp161948 		fprintf(stderr, "%s: no crypto providers found\n", PK11_DBG);
29917211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
2992*7616SVladimir.Kotal@Sun.COM 		return (1);
29930Sstevel@tonic-gate 		}
29940Sstevel@tonic-gate 
29950Sstevel@tonic-gate 	pSlotList = OPENSSL_malloc(ulSlotCount * sizeof (CK_SLOT_ID));
29960Sstevel@tonic-gate 
2997*7616SVladimir.Kotal@Sun.COM 	if (pSlotList == NULL)
29980Sstevel@tonic-gate 		{
29996847Svk199839 		PK11err(PK11_F_CHOOSE_SLOT, PK11_R_MALLOC_FAILURE);
3000*7616SVladimir.Kotal@Sun.COM 		return (0);
30010Sstevel@tonic-gate 		}
30020Sstevel@tonic-gate 
30030Sstevel@tonic-gate 	/* Get the slot list for processing */
30040Sstevel@tonic-gate 	rv = pFuncList->C_GetSlotList(0, pSlotList, &ulSlotCount);
3005*7616SVladimir.Kotal@Sun.COM 	if (rv != CKR_OK)
30060Sstevel@tonic-gate 		{
30077211Sjp161948 		PK11err_add_data(PK11_F_CHOOSE_SLOT, PK11_R_GETSLOTLIST, rv);
30080Sstevel@tonic-gate 		OPENSSL_free(pSlotList);
3009*7616SVladimir.Kotal@Sun.COM 		return (0);
30100Sstevel@tonic-gate 		}
30110Sstevel@tonic-gate 
30127211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
30137211Sjp161948 	fprintf(stderr, "%s: provider: %s\n", PK11_DBG, def_PK11_LIBNAME);
30147211Sjp161948 	fprintf(stderr, "%s: number of slots: %d\n", PK11_DBG, ulSlotCount);
30157211Sjp161948 
30167211Sjp161948 	fprintf(stderr, "%s: == checking rand slots ==\n", PK11_DBG);
30177211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
3018*7616SVladimir.Kotal@Sun.COM 	for (i = 0; i < ulSlotCount; i++)
30197211Sjp161948 		{
30207211Sjp161948 		current_slot = pSlotList[i];
30217211Sjp161948 
30227211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
30237211Sjp161948 	fprintf(stderr, "%s: checking slot: %d\n", PK11_DBG, i);
30247211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
30257211Sjp161948 		/* Check if slot has random support. */
30267211Sjp161948 		rv = pFuncList->C_GetTokenInfo(current_slot, &token_info);
30277211Sjp161948 		if (rv != CKR_OK)
30287211Sjp161948 			continue;
30297211Sjp161948 
30307211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
30317211Sjp161948 	fprintf(stderr, "%s: token label: %.32s\n", PK11_DBG, token_info.label);
30327211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
30337211Sjp161948 
30347211Sjp161948 		if (token_info.flags & CKF_RNG)
30357211Sjp161948 			{
30367211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
30377211Sjp161948 	fprintf(stderr, "%s: this token has CKF_RNG flag\n", PK11_DBG);
30387211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
30397211Sjp161948 			pk11_have_random = CK_TRUE;
30407211Sjp161948 			break;
30417211Sjp161948 			}
30427211Sjp161948 		}
30437211Sjp161948 
30447211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
30457211Sjp161948 	fprintf(stderr, "%s: == checking pubkey slots ==\n", PK11_DBG);
30467211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
3047*7616SVladimir.Kotal@Sun.COM 	for (i = 0; i < ulSlotCount; i++)
30480Sstevel@tonic-gate 		{
30490Sstevel@tonic-gate 		CK_BBOOL slot_has_rsa = CK_FALSE;
30500Sstevel@tonic-gate 		CK_BBOOL slot_has_dsa = CK_FALSE;
30510Sstevel@tonic-gate 		CK_BBOOL slot_has_dh = CK_FALSE;
30520Sstevel@tonic-gate 		current_slot = pSlotList[i];
30537211Sjp161948 
30547211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
30557211Sjp161948 	fprintf(stderr, "%s: checking slot: %d\n", PK11_DBG, i);
30567211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
30570Sstevel@tonic-gate 		rv = pFuncList->C_GetTokenInfo(current_slot, &token_info);
30580Sstevel@tonic-gate 		if (rv != CKR_OK)
30590Sstevel@tonic-gate 			continue;
30600Sstevel@tonic-gate 
30617211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
30627211Sjp161948 	fprintf(stderr, "%s: token label: %.32s\n", PK11_DBG, token_info.label);
30637211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
30647211Sjp161948 
30656847Svk199839 #ifndef OPENSSL_NO_RSA
30660Sstevel@tonic-gate 		/*
30670Sstevel@tonic-gate 		 * Check if this slot is capable of signing and
30680Sstevel@tonic-gate 		 * verifying with CKM_RSA_PKCS.
30690Sstevel@tonic-gate 		 */
3070*7616SVladimir.Kotal@Sun.COM 		rv = pFuncList->C_GetMechanismInfo(current_slot, CKM_RSA_PKCS,
30710Sstevel@tonic-gate 			&mech_info);
30720Sstevel@tonic-gate 
30730Sstevel@tonic-gate 		if (rv == CKR_OK && ((mech_info.flags & CKF_SIGN) &&
30740Sstevel@tonic-gate 				(mech_info.flags & CKF_VERIFY)))
30750Sstevel@tonic-gate 			{
30760Sstevel@tonic-gate 			/*
30770Sstevel@tonic-gate 			 * Check if this slot is capable of encryption,
30780Sstevel@tonic-gate 			 * decryption, sign, and verify with CKM_RSA_X_509.
30790Sstevel@tonic-gate 			 */
30800Sstevel@tonic-gate 			rv = pFuncList->C_GetMechanismInfo(current_slot,
3081*7616SVladimir.Kotal@Sun.COM 			    CKM_RSA_X_509, &mech_info);
30820Sstevel@tonic-gate 
30830Sstevel@tonic-gate 			if (rv == CKR_OK && ((mech_info.flags & CKF_SIGN) &&
30840Sstevel@tonic-gate 			    (mech_info.flags & CKF_VERIFY) &&
30850Sstevel@tonic-gate 			    (mech_info.flags & CKF_ENCRYPT) &&
30860Sstevel@tonic-gate 			    (mech_info.flags & CKF_VERIFY_RECOVER) &&
30870Sstevel@tonic-gate 			    (mech_info.flags & CKF_DECRYPT)))
30887211Sjp161948 				{
30890Sstevel@tonic-gate 				slot_has_rsa = CK_TRUE;
30907211Sjp161948 				}
30910Sstevel@tonic-gate 			}
30927211Sjp161948 #endif	/* OPENSSL_NO_RSA */
30937211Sjp161948 
30946847Svk199839 #ifndef OPENSSL_NO_DSA
30950Sstevel@tonic-gate 		/*
30960Sstevel@tonic-gate 		 * Check if this slot is capable of signing and
30970Sstevel@tonic-gate 		 * verifying with CKM_DSA.
30980Sstevel@tonic-gate 		 */
3099*7616SVladimir.Kotal@Sun.COM 		rv = pFuncList->C_GetMechanismInfo(current_slot, CKM_DSA,
31000Sstevel@tonic-gate 			&mech_info);
31010Sstevel@tonic-gate 		if (rv == CKR_OK && ((mech_info.flags & CKF_SIGN) &&
31020Sstevel@tonic-gate 		    (mech_info.flags & CKF_VERIFY)))
31037211Sjp161948 			{
31040Sstevel@tonic-gate 			slot_has_dsa = CK_TRUE;
31057211Sjp161948 			}
31067526SVladimir.Kotal@Sun.COM 
31077211Sjp161948 #endif	/* OPENSSL_NO_DSA */
31087211Sjp161948 
31096847Svk199839 #ifndef OPENSSL_NO_DH
31100Sstevel@tonic-gate 		/*
31110Sstevel@tonic-gate 		 * Check if this slot is capable of DH key generataion and
31120Sstevel@tonic-gate 		 * derivation.
31130Sstevel@tonic-gate 		 */
31140Sstevel@tonic-gate 		rv = pFuncList->C_GetMechanismInfo(current_slot,
3115*7616SVladimir.Kotal@Sun.COM 		    CKM_DH_PKCS_KEY_PAIR_GEN, &mech_info);
31160Sstevel@tonic-gate 
31170Sstevel@tonic-gate 		if (rv == CKR_OK && (mech_info.flags & CKF_GENERATE_KEY_PAIR))
3118*7616SVladimir.Kotal@Sun.COM 			{
31190Sstevel@tonic-gate 			rv = pFuncList->C_GetMechanismInfo(current_slot,
31200Sstevel@tonic-gate 				CKM_DH_PKCS_DERIVE, &mech_info);
31210Sstevel@tonic-gate 			if (rv == CKR_OK && (mech_info.flags & CKF_DERIVE))
31227211Sjp161948 				{
31230Sstevel@tonic-gate 				slot_has_dh = CK_TRUE;
31247211Sjp161948 				}
31250Sstevel@tonic-gate 			}
31267211Sjp161948 #endif	/* OPENSSL_NO_DH */
31277211Sjp161948 
31280Sstevel@tonic-gate 		if (!found_candidate_slot &&
31290Sstevel@tonic-gate 		    (slot_has_rsa || slot_has_dsa || slot_has_dh))
31300Sstevel@tonic-gate 			{
31317211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
31320Sstevel@tonic-gate 			fprintf(stderr,
3133*7616SVladimir.Kotal@Sun.COM 			    "%s: potential slot: %d\n", PK11_DBG, current_slot);
31347211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
31350Sstevel@tonic-gate 			best_slot_sofar = current_slot;
31360Sstevel@tonic-gate 			pk11_have_rsa = slot_has_rsa;
31370Sstevel@tonic-gate 			pk11_have_dsa = slot_has_dsa;
31380Sstevel@tonic-gate 			pk11_have_dh = slot_has_dh;
31390Sstevel@tonic-gate 			found_candidate_slot = CK_TRUE;
31407211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
31417211Sjp161948 			fprintf(stderr,
3142*7616SVladimir.Kotal@Sun.COM 			    "%s: setting found_candidate_slot to CK_TRUE\n",
31437211Sjp161948 			    PK11_DBG);
31440Sstevel@tonic-gate 			fprintf(stderr,
3145*7616SVladimir.Kotal@Sun.COM 			    "%s: best so far slot: %d\n", PK11_DBG,
3146*7616SVladimir.Kotal@Sun.COM 			    best_slot_sofar);
31477211Sjp161948 			}
31487211Sjp161948 		else
31497211Sjp161948 			{
31507211Sjp161948 			fprintf(stderr,
3151*7616SVladimir.Kotal@Sun.COM 			    "%s: no rsa/dsa/dh\n", PK11_DBG);
31520Sstevel@tonic-gate 			}
31537211Sjp161948 #else
31547211Sjp161948 			} /* if */
31557211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
31567211Sjp161948 		} /* for */
31577211Sjp161948 
31587211Sjp161948 	if (found_candidate_slot)
31597211Sjp161948 		{
31607211Sjp161948 		pubkey_SLOTID = best_slot_sofar;
31617211Sjp161948 		}
31627211Sjp161948 
31637211Sjp161948 	found_candidate_slot = CK_FALSE;
31647211Sjp161948 	best_slot_sofar = 0;
31657211Sjp161948 
31667211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
31677211Sjp161948 	fprintf(stderr, "%s: == checking cipher/digest ==\n", PK11_DBG);
31687211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
3169*7616SVladimir.Kotal@Sun.COM 	for (i = 0; i < ulSlotCount; i++)
31707211Sjp161948 		{
31717211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
31727211Sjp161948 	fprintf(stderr, "%s: checking slot: %d\n", PK11_DBG, i);
31737211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
31747211Sjp161948 
31757211Sjp161948 		current_slot = pSlotList[i];
31767211Sjp161948 		current_slot_n_cipher = 0;
31777211Sjp161948 		current_slot_n_digest = 0;
3178*7616SVladimir.Kotal@Sun.COM 		(void) memset(local_cipher_nids, 0, sizeof (local_cipher_nids));
3179*7616SVladimir.Kotal@Sun.COM 		(void) memset(local_digest_nids, 0, sizeof (local_digest_nids));
31807211Sjp161948 
31817211Sjp161948 		pk11_find_symmetric_ciphers(pFuncList, current_slot,
31827211Sjp161948 		    &current_slot_n_cipher, local_cipher_nids);
31837211Sjp161948 
31847211Sjp161948 		pk11_find_digests(pFuncList, current_slot,
31857211Sjp161948 		    &current_slot_n_digest, local_digest_nids);
31867211Sjp161948 
31877211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
31887211Sjp161948 		fprintf(stderr, "%s: current_slot_n_cipher %d\n", PK11_DBG,
31897211Sjp161948 			current_slot_n_cipher);
31907211Sjp161948 		fprintf(stderr, "%s: current_slot_n_digest %d\n", PK11_DBG,
31917211Sjp161948 			current_slot_n_digest);
31927211Sjp161948 		fprintf(stderr, "%s: best so far cipher/digest slot: %d\n",
31937211Sjp161948 			PK11_DBG, best_slot_sofar);
31947211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
31950Sstevel@tonic-gate 
31960Sstevel@tonic-gate 		/*
3197*7616SVladimir.Kotal@Sun.COM 		 * If the current slot supports more ciphers/digests than
31987250Sjp161948 		 * the previous best one we change the current best to this one,
31990Sstevel@tonic-gate 		 * otherwise leave it where it is.
32000Sstevel@tonic-gate 		 */
32017250Sjp161948 		if ((current_slot_n_cipher + current_slot_n_digest) >
32027250Sjp161948 		    (slot_n_cipher + slot_n_digest))
32030Sstevel@tonic-gate 			{
32047211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
32057211Sjp161948 			fprintf(stderr,
32067211Sjp161948 				"%s: changing best so far slot to %d\n",
32077211Sjp161948 				PK11_DBG, current_slot);
32087211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
32097211Sjp161948 			best_slot_sofar = SLOTID = current_slot;
32107250Sjp161948 			cipher_count = slot_n_cipher = current_slot_n_cipher;
32117250Sjp161948 			digest_count = slot_n_digest = current_slot_n_digest;
32127534SVladimir.Kotal@Sun.COM 			(void) memcpy(cipher_nids, local_cipher_nids,
32137526SVladimir.Kotal@Sun.COM 			    sizeof (local_cipher_nids));
32147534SVladimir.Kotal@Sun.COM 			(void) memcpy(digest_nids, local_digest_nids,
32157526SVladimir.Kotal@Sun.COM 			    sizeof (local_digest_nids));
32160Sstevel@tonic-gate 			}
32170Sstevel@tonic-gate 		}
32180Sstevel@tonic-gate 
32197211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
32207211Sjp161948 	fprintf(stderr,
32217526SVladimir.Kotal@Sun.COM 	    "%s: chosen pubkey slot: %d\n", PK11_DBG, pubkey_SLOTID);
32220Sstevel@tonic-gate 	fprintf(stderr,
32237526SVladimir.Kotal@Sun.COM 	    "%s: chosen rand slot: %d\n", PK11_DBG, rand_SLOTID);
32240Sstevel@tonic-gate 	fprintf(stderr,
32257526SVladimir.Kotal@Sun.COM 	    "%s: chosen cipher/digest slot: %d\n", PK11_DBG, SLOTID);
32267211Sjp161948 	fprintf(stderr,
32277526SVladimir.Kotal@Sun.COM 	    "%s: pk11_have_rsa %d\n", PK11_DBG, pk11_have_rsa);
32280Sstevel@tonic-gate 	fprintf(stderr,
32297526SVladimir.Kotal@Sun.COM 	    "%s: pk11_have_dsa %d\n", PK11_DBG, pk11_have_dsa);
32307211Sjp161948 	fprintf(stderr,
32317526SVladimir.Kotal@Sun.COM 	    "%s: pk11_have_dh %d\n", PK11_DBG, pk11_have_dh);
32320Sstevel@tonic-gate 	fprintf(stderr,
32337526SVladimir.Kotal@Sun.COM 	    "%s: pk11_have_random %d\n", PK11_DBG, pk11_have_random);
32340Sstevel@tonic-gate 	fprintf(stderr,
32357526SVladimir.Kotal@Sun.COM 	    "%s: cipher_count %d\n", PK11_DBG, cipher_count);
32367211Sjp161948 	fprintf(stderr,
32377526SVladimir.Kotal@Sun.COM 	    "%s: digest_count %d\n", PK11_DBG, digest_count);
32387211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
3239*7616SVladimir.Kotal@Sun.COM 
32406847Svk199839 	if (pSlotList != NULL)
32416847Svk199839 		OPENSSL_free(pSlotList);
32420Sstevel@tonic-gate 
32437211Sjp161948 #ifdef	SOLARIS_HW_SLOT_SELECTION
32447211Sjp161948 	OPENSSL_free(hw_cnids);
32457211Sjp161948 	OPENSSL_free(hw_dnids);
32467211Sjp161948 #endif	/* SOLARIS_HW_SLOT_SELECTION */
32477211Sjp161948 
32487211Sjp161948 	if (any_slot_found != NULL)
32497211Sjp161948 		*any_slot_found = 1;
3250*7616SVladimir.Kotal@Sun.COM 	return (1);
32510Sstevel@tonic-gate 	}
32520Sstevel@tonic-gate 
32537211Sjp161948 static void pk11_get_symmetric_cipher(CK_FUNCTION_LIST_PTR pflist,
32547211Sjp161948     int slot_id, CK_MECHANISM_TYPE mech, int *current_slot_n_cipher,
32557211Sjp161948     int *local_cipher_nids, int id)
32567211Sjp161948 	{
32577211Sjp161948 	CK_MECHANISM_INFO mech_info;
32587211Sjp161948 	CK_RV rv;
32597211Sjp161948 
32607211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
32617211Sjp161948 	fprintf(stderr, "%s: checking mech: %x", PK11_DBG, mech);
32627211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
32637211Sjp161948 	rv = pflist->C_GetMechanismInfo(slot_id, mech, &mech_info);
32647211Sjp161948 
3265*7616SVladimir.Kotal@Sun.COM 	if (rv != CKR_OK)
32667211Sjp161948 		{
32677211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
32687211Sjp161948 		fprintf(stderr, " not found\n");
32697211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
32707211Sjp161948 		return;
32717211Sjp161948 		}
32727211Sjp161948 
32737211Sjp161948 	if ((mech_info.flags & CKF_ENCRYPT) &&
32747211Sjp161948 	    (mech_info.flags & CKF_DECRYPT))
32757211Sjp161948 		{
32767211Sjp161948 #ifdef	SOLARIS_HW_SLOT_SELECTION
32777211Sjp161948 		if (nid_in_table(ciphers[id].nid, hw_cnids))
32787211Sjp161948 #endif	/* SOLARIS_HW_SLOT_SELECTION */
32797211Sjp161948 			{
32807211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
32817211Sjp161948 		fprintf(stderr, " usable\n");
32827211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
32837211Sjp161948 			local_cipher_nids[(*current_slot_n_cipher)++] =
32847211Sjp161948 			    ciphers[id].nid;
32857211Sjp161948 			}
32867211Sjp161948 #ifdef	SOLARIS_HW_SLOT_SELECTION
32877211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
32887211Sjp161948 		else
32897211Sjp161948 			{
32907211Sjp161948 		fprintf(stderr, " rejected, software implementation only\n");
32917211Sjp161948 			}
32927211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
32937211Sjp161948 #endif	/* SOLARIS_HW_SLOT_SELECTION */
32947211Sjp161948 		}
32957211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
32967211Sjp161948 	else
32977211Sjp161948 		{
32987211Sjp161948 		fprintf(stderr, " unusable\n");
32997211Sjp161948 		}
33007211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
33017211Sjp161948 
33027211Sjp161948 	return;
33037211Sjp161948 	}
33047211Sjp161948 
33057211Sjp161948 static void pk11_get_digest(CK_FUNCTION_LIST_PTR pflist, int slot_id,
33067211Sjp161948     CK_MECHANISM_TYPE mech, int *current_slot_n_digest, int *local_digest_nids,
33077211Sjp161948     int id)
33080Sstevel@tonic-gate 	{
33090Sstevel@tonic-gate 	CK_MECHANISM_INFO mech_info;
33100Sstevel@tonic-gate 	CK_RV rv;
33110Sstevel@tonic-gate 
33127211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
33137211Sjp161948 	fprintf(stderr, "%s: checking mech: %x", PK11_DBG, mech);
33147211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
33157211Sjp161948 	rv = pflist->C_GetMechanismInfo(slot_id, mech, &mech_info);
33160Sstevel@tonic-gate 
3317*7616SVladimir.Kotal@Sun.COM 	if (rv != CKR_OK)
33180Sstevel@tonic-gate 		{
33197211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
33207211Sjp161948 		fprintf(stderr, " not found\n");
33217211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
33227211Sjp161948 		return;
33230Sstevel@tonic-gate 		}
33240Sstevel@tonic-gate 
33250Sstevel@tonic-gate 	if (mech_info.flags & CKF_DIGEST)
33260Sstevel@tonic-gate 		{
33277211Sjp161948 #ifdef	SOLARIS_HW_SLOT_SELECTION
3328*7616SVladimir.Kotal@Sun.COM 		if (nid_in_table(digests[id].nid, hw_dnids))
33297211Sjp161948 #endif	/* SOLARIS_HW_SLOT_SELECTION */
33307211Sjp161948 			{
33317211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
33327211Sjp161948 		fprintf(stderr, " usable\n");
33337211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
33347211Sjp161948 			local_digest_nids[(*current_slot_n_digest)++] =
33357211Sjp161948 			    digests[id].nid;
33367211Sjp161948 			}
33377211Sjp161948 #ifdef	SOLARIS_HW_SLOT_SELECTION
33387211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
33397211Sjp161948 		else
33407211Sjp161948 			{
33417211Sjp161948 		fprintf(stderr, " rejected, software implementation only\n");
33427211Sjp161948 			}
33437211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
33447211Sjp161948 #endif	/* SOLARIS_HW_SLOT_SELECTION */
33457211Sjp161948 		}
33467211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
33477211Sjp161948 	else
33487211Sjp161948 		{
33497211Sjp161948 		fprintf(stderr, " unusable\n");
33500Sstevel@tonic-gate 		}
33517211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
33527211Sjp161948 
33537211Sjp161948 	return;
33547211Sjp161948 	}
33557211Sjp161948 
33567211Sjp161948 #ifdef	SOLARIS_AES_CTR
33577211Sjp161948 /* create a new NID when we have no OID for that mechanism */
33587211Sjp161948 static int pk11_add_NID(char *sn, char *ln)
33597211Sjp161948 	{
33607211Sjp161948 	ASN1_OBJECT *o;
33617211Sjp161948 	int nid;
33627211Sjp161948 
33637211Sjp161948 	if ((o = ASN1_OBJECT_create(OBJ_new_nid(1), (unsigned char *)"",
33647211Sjp161948 	    1, sn, ln)) == NULL)
33657211Sjp161948 		{
3366*7616SVladimir.Kotal@Sun.COM 		return (0);
33677211Sjp161948 		}
33687211Sjp161948 
33697211Sjp161948 	/* will return NID_undef on error */
33707211Sjp161948 	nid = OBJ_add_object(o);
33717211Sjp161948 	ASN1_OBJECT_free(o);
33727211Sjp161948 
33737211Sjp161948 	return (nid);
33747211Sjp161948 	}
33757211Sjp161948 
33767211Sjp161948 /*
33777211Sjp161948  * Create new NIDs for AES counter mode. OpenSSL doesn't support them now so we
33787211Sjp161948  * have to help ourselves here.
33797211Sjp161948  */
33807211Sjp161948 static int pk11_add_aes_ctr_NIDs(void)
33817211Sjp161948 	{
33827211Sjp161948 	/* are we already set? */
33837211Sjp161948 	if (NID_aes_256_ctr != NID_undef)
3384*7616SVladimir.Kotal@Sun.COM 		return (1);
33857211Sjp161948 
33867211Sjp161948 	/*
33877211Sjp161948 	 * There are no official names for AES counter modes yet so we just
33887211Sjp161948 	 * follow the format of those that exist.
33897211Sjp161948 	 */
33907211Sjp161948 	if ((NID_aes_128_ctr = pk11_add_NID("AES-128-CTR", "aes-128-ctr")) ==
33917211Sjp161948 	    NID_undef)
33927211Sjp161948 		goto err;
33937211Sjp161948 	ciphers[PK11_AES_128_CTR].nid = pk11_aes_128_ctr.nid = NID_aes_128_ctr;
33947211Sjp161948 	if ((NID_aes_192_ctr = pk11_add_NID("AES-192-CTR", "aes-192-ctr")) ==
33957211Sjp161948 	    NID_undef)
33967211Sjp161948 		goto err;
33977211Sjp161948 	ciphers[PK11_AES_192_CTR].nid = pk11_aes_192_ctr.nid = NID_aes_192_ctr;
33987211Sjp161948 	if ((NID_aes_256_ctr = pk11_add_NID("AES-256-CTR", "aes-256-ctr")) ==
33997211Sjp161948 	    NID_undef)
34007211Sjp161948 		goto err;
34017211Sjp161948 	ciphers[PK11_AES_256_CTR].nid = pk11_aes_256_ctr.nid = NID_aes_256_ctr;
3402*7616SVladimir.Kotal@Sun.COM 	return (1);
34037211Sjp161948 
34047211Sjp161948 err:
34057211Sjp161948 	PK11err(PK11_F_ADD_AES_CTR_NIDS, PK11_R_ADD_NID_FAILED);
3406*7616SVladimir.Kotal@Sun.COM 	return (0);
34070Sstevel@tonic-gate 	}
34087211Sjp161948 #endif	/* SOLARIS_AES_CTR */
34097211Sjp161948 
34107211Sjp161948 /* Find what symmetric ciphers this slot supports. */
34117211Sjp161948 static void pk11_find_symmetric_ciphers(CK_FUNCTION_LIST_PTR pflist,
34127211Sjp161948     CK_SLOT_ID current_slot, int *current_slot_n_cipher, int *local_cipher_nids)
34137211Sjp161948 	{
34147211Sjp161948 	int i;
34157211Sjp161948 
34167211Sjp161948 	for (i = 0; i < PK11_CIPHER_MAX; ++i)
34177211Sjp161948 		{
34187211Sjp161948 		pk11_get_symmetric_cipher(pflist, current_slot,
34197211Sjp161948 		    ciphers[i].mech_type, current_slot_n_cipher,
34207211Sjp161948 		    local_cipher_nids, ciphers[i].id);
34217211Sjp161948 		}
34227211Sjp161948 	}
34237211Sjp161948 
34247211Sjp161948 /* Find what digest algorithms this slot supports. */
34257211Sjp161948 static void pk11_find_digests(CK_FUNCTION_LIST_PTR pflist,
34267211Sjp161948     CK_SLOT_ID current_slot, int *current_slot_n_digest, int *local_digest_nids)
34277211Sjp161948 	{
34287211Sjp161948 	int i;
34297211Sjp161948 
34307211Sjp161948 	for (i = 0; i < PK11_DIGEST_MAX; ++i)
34317211Sjp161948 		{
34327211Sjp161948 		pk11_get_digest(pflist, current_slot, digests[i].mech_type,
34337211Sjp161948 		    current_slot_n_digest, local_digest_nids, digests[i].id);
34347211Sjp161948 		}
34357211Sjp161948 	}
34367211Sjp161948 
34377211Sjp161948 #ifdef	SOLARIS_HW_SLOT_SELECTION
34387211Sjp161948 /*
34397211Sjp161948  * It would be great if we could use pkcs11_kernel directly since this library
34407211Sjp161948  * offers hardware slots only. That's the easiest way to achieve the situation
34417211Sjp161948  * where we use the hardware accelerators when present and OpenSSL native code
34427211Sjp161948  * otherwise. That presumes the fact that OpenSSL native code is faster than the
34437211Sjp161948  * code in the soft token. It's a logical assumption - Crypto Framework has some
34447211Sjp161948  * inherent overhead so going there for the software implementation of a
34457211Sjp161948  * mechanism should be logically slower in contrast to the OpenSSL native code,
34467211Sjp161948  * presuming that both implementations are of similar speed. For example, the
34477211Sjp161948  * soft token for AES is roughly three times slower than OpenSSL for 64 byte
34487211Sjp161948  * blocks and still 20% slower for 8KB blocks. So, if we want to ship products
34497211Sjp161948  * that use the PKCS#11 engine by default, we must somehow avoid that regression
34507211Sjp161948  * on machines without hardware acceleration. That's why switching to the
34517211Sjp161948  * pkcs11_kernel library seems like a very good idea.
34527211Sjp161948  *
34537211Sjp161948  * The problem is that OpenSSL built with SunStudio is roughly 2x slower for
34547211Sjp161948  * asymmetric operations (RSA/DSA/DH) than the soft token built with the same
34557211Sjp161948  * compiler. That means that if we switched to pkcs11_kernel from the libpkcs11
34567211Sjp161948  * library, we would have had a performance regression on machines without
34577211Sjp161948  * hardware acceleration for asymmetric operations for all applications that use
34587211Sjp161948  * the PKCS#11 engine. There is one such application - Apache web server since
34597211Sjp161948  * it's shipped configured to use the PKCS#11 engine by default. Having said
34607211Sjp161948  * that, we can't switch to the pkcs11_kernel library now and have to come with
34617211Sjp161948  * a solution that, on non-accelerated machines, uses the OpenSSL native code
34627211Sjp161948  * for all symmetric ciphers and digests while it uses the soft token for
34637211Sjp161948  * asymmetric operations.
34647211Sjp161948  *
34657211Sjp161948  * This is the idea: dlopen() pkcs11_kernel directly and find out what
34667211Sjp161948  * mechanisms are there. We don't care about duplications (more slots can
34677211Sjp161948  * support the same mechanism), we just want to know what mechanisms can be
34687211Sjp161948  * possibly supported in hardware on that particular machine. As said before,
34697211Sjp161948  * pkcs11_kernel will show you hardware providers only.
34707211Sjp161948  *
34717211Sjp161948  * Then, we rely on the fact that since we use libpkcs11 library we will find
34727211Sjp161948  * the metaslot. When we go through the metaslot's mechanisms for symmetric
34737211Sjp161948  * ciphers and digests, we check that any found mechanism is in the table
34747211Sjp161948  * created using the pkcs11_kernel library. So, as a result we have two arrays
34757211Sjp161948  * of mechanisms that were advertised as supported in hardware which was the
34767211Sjp161948  * goal of that whole excercise. Thus, we can use libpkcs11 but avoid soft token
34777211Sjp161948  * code for symmetric ciphers and digests. See pk11_choose_slots() for more
34787211Sjp161948  * information.
34797211Sjp161948  *
34807211Sjp161948  * This is Solaris specific code, if SOLARIS_HW_SLOT_SELECTION is not defined
34817211Sjp161948  * the code won't be used.
34827211Sjp161948  */
34837211Sjp161948 #if defined(__sparcv9) || defined(__x86_64) || defined(__amd64)
34847211Sjp161948 static const char pkcs11_kernel[] = "/usr/lib/security/64/pkcs11_kernel.so.1";
34857211Sjp161948 #else
34867211Sjp161948 static const char pkcs11_kernel[] = "/usr/lib/security/pkcs11_kernel.so.1";
34877211Sjp161948 #endif
34887211Sjp161948 
34897211Sjp161948 /*
34907211Sjp161948  * Check hardware capabilities of the machines. The output are two lists,
34917211Sjp161948  * hw_cnids and hw_dnids, that contain hardware mechanisms found in all hardware
34927211Sjp161948  * providers together. They are not sorted and may contain duplicate mechanisms.
34937211Sjp161948  */
34947211Sjp161948 static int check_hw_mechanisms(void)
34957211Sjp161948 	{
34967211Sjp161948 	int i;
34977211Sjp161948 	CK_RV rv;
34987211Sjp161948 	void *handle;
34997211Sjp161948 	CK_C_GetFunctionList p;
35007211Sjp161948 	CK_TOKEN_INFO token_info;
35017211Sjp161948 	CK_ULONG ulSlotCount = 0;
35027211Sjp161948 	int n_cipher = 0, n_digest = 0;
35037211Sjp161948 	CK_FUNCTION_LIST_PTR pflist = NULL;
35047211Sjp161948 	CK_SLOT_ID_PTR pSlotList = NULL_PTR;
35057211Sjp161948 	int *tmp_hw_cnids, *tmp_hw_dnids;
35067211Sjp161948 	int hw_ctable_size, hw_dtable_size;
35077211Sjp161948 
35087211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
35097211Sjp161948 	fprintf(stderr, "%s: SOLARIS_HW_SLOT_SELECTION code running\n",
35107211Sjp161948 	    PK11_DBG);
35110Sstevel@tonic-gate #endif
35127211Sjp161948 	if ((handle = dlopen(pkcs11_kernel, RTLD_LAZY)) == NULL)
35137211Sjp161948 		{
35147211Sjp161948 		PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_DSO_FAILURE);
35157211Sjp161948 		goto err;
35167211Sjp161948 		}
35177211Sjp161948 
3518*7616SVladimir.Kotal@Sun.COM 	if ((p = (CK_C_GetFunctionList)dlsym(handle,
35197211Sjp161948 	    PK11_GET_FUNCTION_LIST)) == NULL)
35207211Sjp161948 		{
35217211Sjp161948 		PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_DSO_FAILURE);
35227211Sjp161948 		goto err;
35237211Sjp161948 		}
3524*7616SVladimir.Kotal@Sun.COM 
3525*7616SVladimir.Kotal@Sun.COM 	/* get the full function list from the loaded library */
35267211Sjp161948 	if (p(&pflist) != CKR_OK)
35277211Sjp161948 		{
35287211Sjp161948 		PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_DSO_FAILURE);
35297211Sjp161948 		goto err;
35307211Sjp161948 		}
3531*7616SVladimir.Kotal@Sun.COM 
35327211Sjp161948 	rv = pflist->C_Initialize(NULL_PTR);
35337211Sjp161948 	if ((rv != CKR_OK) && (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED))
35347211Sjp161948 		{
35357211Sjp161948 		PK11err_add_data(PK11_F_CHECK_HW_MECHANISMS,
35367211Sjp161948 		    PK11_R_INITIALIZE, rv);
35377211Sjp161948 		goto err;
35387211Sjp161948 		}
35397211Sjp161948 
35407211Sjp161948 	if (pflist->C_GetSlotList(0, NULL_PTR, &ulSlotCount) != CKR_OK)
35417211Sjp161948 		{
35427211Sjp161948 		PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_GETSLOTLIST);
35437211Sjp161948 		goto err;
35447211Sjp161948 		}
35457211Sjp161948 
35467211Sjp161948 	/* no slots, set the hw mechanism tables as empty */
35477211Sjp161948 	if (ulSlotCount == 0)
35487211Sjp161948 		{
35497211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
35507211Sjp161948 	fprintf(stderr, "%s: no hardware mechanisms found\n", PK11_DBG);
35510Sstevel@tonic-gate #endif
35527211Sjp161948 		hw_cnids = OPENSSL_malloc(sizeof (int));
35537211Sjp161948 		hw_dnids = OPENSSL_malloc(sizeof (int));
35547211Sjp161948 		if (hw_cnids == NULL || hw_dnids == NULL)
35557211Sjp161948 			{
35567211Sjp161948 			PK11err(PK11_F_CHECK_HW_MECHANISMS,
35577211Sjp161948 			    PK11_R_MALLOC_FAILURE);
35587211Sjp161948 			return (0);
35597211Sjp161948 			}
35607211Sjp161948 		/* this means empty tables */
35617211Sjp161948 		hw_cnids[0] = NID_undef;
35627211Sjp161948 		hw_dnids[0] = NID_undef;
35637211Sjp161948 		return (1);
35647211Sjp161948 		}
35657211Sjp161948 
35667211Sjp161948 	pSlotList = OPENSSL_malloc(ulSlotCount * sizeof (CK_SLOT_ID));
3567*7616SVladimir.Kotal@Sun.COM 	if (pSlotList == NULL)
35687211Sjp161948 		{
35697211Sjp161948 		PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_MALLOC_FAILURE);
35707211Sjp161948 		goto err;
35717211Sjp161948 		}
35727211Sjp161948 
35737211Sjp161948 	/* Get the slot list for processing */
35747211Sjp161948 	if (pflist->C_GetSlotList(0, pSlotList, &ulSlotCount) != CKR_OK)
35757211Sjp161948 		{
35767211Sjp161948 		PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_GETSLOTLIST);
35777211Sjp161948 		goto err;
35787211Sjp161948 		}
35797211Sjp161948 
35807211Sjp161948 	/*
35817211Sjp161948 	 * We don't care about duplicit mechanisms in multiple slots and also
35827211Sjp161948 	 * reserve one slot for the terminal NID_undef which we use to stop the
35837211Sjp161948 	 * search.
35847211Sjp161948 	 */
35857211Sjp161948 	hw_ctable_size = ulSlotCount * PK11_CIPHER_MAX + 1;
35867211Sjp161948 	hw_dtable_size = ulSlotCount * PK11_DIGEST_MAX + 1;
35877211Sjp161948 	tmp_hw_cnids = OPENSSL_malloc(hw_ctable_size * sizeof (int));
35887211Sjp161948 	tmp_hw_dnids = OPENSSL_malloc(hw_dtable_size * sizeof (int));
35897211Sjp161948 	if (tmp_hw_cnids == NULL || tmp_hw_dnids == NULL)
35907211Sjp161948 		{
35917211Sjp161948 		PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_MALLOC_FAILURE);
35927211Sjp161948 		goto err;
35937211Sjp161948 		}
35947211Sjp161948 
35957211Sjp161948 	/*
35967211Sjp161948 	 * Do not use memset since we should not rely on the fact that NID_undef
35977211Sjp161948 	 * is zero now.
35987211Sjp161948 	 */
35997211Sjp161948 	for (i = 0; i < hw_ctable_size; ++i)
36007211Sjp161948 		tmp_hw_cnids[i] = NID_undef;
36017211Sjp161948 	for (i = 0; i < hw_dtable_size; ++i)
36027211Sjp161948 		tmp_hw_dnids[i] = NID_undef;
36037211Sjp161948 
36047211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
36057211Sjp161948 	fprintf(stderr, "%s: provider: %s\n", PK11_DBG, pkcs11_kernel);
36067211Sjp161948 	fprintf(stderr, "%s: found %d hardware slots\n", PK11_DBG, ulSlotCount);
36077211Sjp161948 	fprintf(stderr, "%s: now looking for mechs supported in hw\n",
3608*7616SVladimir.Kotal@Sun.COM 	    PK11_DBG);
36097211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
36107211Sjp161948 
3611*7616SVladimir.Kotal@Sun.COM 	for (i = 0; i < ulSlotCount; i++)
36127211Sjp161948 		{
36137211Sjp161948 		if (pflist->C_GetTokenInfo(pSlotList[i], &token_info) != CKR_OK)
36147211Sjp161948 			continue;
36157211Sjp161948 
36167211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
36177211Sjp161948 	fprintf(stderr, "%s: token label: %.32s\n", PK11_DBG, token_info.label);
36187211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
36197211Sjp161948 
36207211Sjp161948 		/*
36217211Sjp161948 		 * We are filling the hw mech tables here. Global tables are
36227211Sjp161948 		 * still NULL so all mechanisms are put into tmp tables.
36237211Sjp161948 		 */
36247211Sjp161948 		pk11_find_symmetric_ciphers(pflist, pSlotList[i],
36257211Sjp161948 		    &n_cipher, tmp_hw_cnids);
36267211Sjp161948 		pk11_find_digests(pflist, pSlotList[i],
36277211Sjp161948 		    &n_digest, tmp_hw_dnids);
36287211Sjp161948 		}
36297211Sjp161948 
36307211Sjp161948 	/*
36317211Sjp161948 	 * Since we are part of a library (libcrypto.so), calling this function
36327211Sjp161948 	 * may have side-effects. Also, C_Finalize() is triggered by
36337211Sjp161948 	 * dlclose(3C).
36347211Sjp161948 	 */
36357211Sjp161948 #if 0
36367211Sjp161948 	pflist->C_Finalize(NULL);
36377211Sjp161948 #endif
36387211Sjp161948 	OPENSSL_free(pSlotList);
36397534SVladimir.Kotal@Sun.COM 	(void) dlclose(handle);
36407211Sjp161948 	hw_cnids = tmp_hw_cnids;
36417211Sjp161948 	hw_dnids = tmp_hw_dnids;
36427211Sjp161948 
36437211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
36447211Sjp161948 	fprintf(stderr, "%s: hw mechs check complete\n", PK11_DBG);
36457211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
36467211Sjp161948 	return (1);
36477211Sjp161948 
36487211Sjp161948 err:
36497211Sjp161948 	if (pSlotList != NULL)
36507211Sjp161948 		OPENSSL_free(pSlotList);
36517211Sjp161948 	if (tmp_hw_cnids != NULL)
36527211Sjp161948 		OPENSSL_free(tmp_hw_cnids);
36537211Sjp161948 	if (tmp_hw_dnids != NULL)
36547211Sjp161948 		OPENSSL_free(tmp_hw_dnids);
36557211Sjp161948 
36567211Sjp161948 	return (0);
36577211Sjp161948 	}
36587211Sjp161948 
36597211Sjp161948 /*
36607211Sjp161948  * Check presence of a NID in the table of NIDs. The table may be NULL (i.e.,
36617211Sjp161948  * non-existent).
36627211Sjp161948  */
36637211Sjp161948 static int nid_in_table(int nid, int *nid_table)
36647211Sjp161948 	{
36657211Sjp161948 	int i = 0;
36667211Sjp161948 
36677211Sjp161948 	/*
36687211Sjp161948 	 * a special case. NULL means that we are initializing a new
36697211Sjp161948 	 * table.
36707211Sjp161948 	 */
36717211Sjp161948 	if (nid_table == NULL)
36727211Sjp161948 		return (1);
36737211Sjp161948 
36747211Sjp161948 	/*
36757211Sjp161948 	 * the table is never full, there is always at least one
36767211Sjp161948 	 * NID_undef.
36777211Sjp161948 	 */
36787211Sjp161948 	while (nid_table[i] != NID_undef)
36797211Sjp161948 		{
36807211Sjp161948 		if (nid_table[i++] == nid)
36817211Sjp161948 			{
36827211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
36837211Sjp161948 	fprintf(stderr, " (NID %d in hw table, idx %d)", nid, i);
36847211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
36857211Sjp161948 			return (1);
36867211Sjp161948 			}
36877211Sjp161948 		}
36887211Sjp161948 
36897211Sjp161948 	return (0);
36907211Sjp161948 	}
36917211Sjp161948 #endif	/* SOLARIS_HW_SLOT_SELECTION */
36927211Sjp161948 
36937211Sjp161948 #endif	/* OPENSSL_NO_HW_PK11 */
36947211Sjp161948 #endif	/* OPENSSL_NO_HW */
3695