xref: /onnv-gate/usr/src/common/openssl/crypto/engine/hw_pk11.c (revision 7526:6e029f7753fd)
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 */
70Sstevel@tonic-gate /* This product includes software developed by the OpenSSL Project for
80Sstevel@tonic-gate  * use in the OpenSSL Toolkit (http://www.openssl.org/).
90Sstevel@tonic-gate  *
100Sstevel@tonic-gate  * This project also referenced hw_pkcs11-0.9.7b.patch written by
110Sstevel@tonic-gate  * Afchine Madjlessi.
120Sstevel@tonic-gate  */
130Sstevel@tonic-gate /* ====================================================================
140Sstevel@tonic-gate  * Copyright (c) 2000-2001 The OpenSSL Project.  All rights reserved.
150Sstevel@tonic-gate  *
160Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
170Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
180Sstevel@tonic-gate  * are met:
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
210Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
220Sstevel@tonic-gate  *
230Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
240Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in
250Sstevel@tonic-gate  *    the documentation and/or other materials provided with the
260Sstevel@tonic-gate  *    distribution.
270Sstevel@tonic-gate  *
280Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this
290Sstevel@tonic-gate  *    software must display the following acknowledgment:
300Sstevel@tonic-gate  *    "This product includes software developed by the OpenSSL Project
310Sstevel@tonic-gate  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
320Sstevel@tonic-gate  *
330Sstevel@tonic-gate  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
340Sstevel@tonic-gate  *    endorse or promote products derived from this software without
350Sstevel@tonic-gate  *    prior written permission. For written permission, please contact
360Sstevel@tonic-gate  *    licensing@OpenSSL.org.
370Sstevel@tonic-gate  *
380Sstevel@tonic-gate  * 5. Products derived from this software may not be called "OpenSSL"
390Sstevel@tonic-gate  *    nor may "OpenSSL" appear in their names without prior written
400Sstevel@tonic-gate  *    permission of the OpenSSL Project.
410Sstevel@tonic-gate  *
420Sstevel@tonic-gate  * 6. Redistributions of any form whatsoever must retain the following
430Sstevel@tonic-gate  *    acknowledgment:
440Sstevel@tonic-gate  *    "This product includes software developed by the OpenSSL Project
450Sstevel@tonic-gate  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
460Sstevel@tonic-gate  *
470Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
480Sstevel@tonic-gate  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
490Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
500Sstevel@tonic-gate  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
510Sstevel@tonic-gate  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
520Sstevel@tonic-gate  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
530Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
540Sstevel@tonic-gate  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
550Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
560Sstevel@tonic-gate  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
570Sstevel@tonic-gate  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
580Sstevel@tonic-gate  * OF THE POSSIBILITY OF SUCH DAMAGE.
590Sstevel@tonic-gate  * ====================================================================
600Sstevel@tonic-gate  *
610Sstevel@tonic-gate  * This product includes cryptographic software written by Eric Young
620Sstevel@tonic-gate  * (eay@cryptsoft.com).  This product includes software written by Tim
630Sstevel@tonic-gate  * Hudson (tjh@cryptsoft.com).
640Sstevel@tonic-gate  *
650Sstevel@tonic-gate  */
660Sstevel@tonic-gate 
670Sstevel@tonic-gate #include <stdio.h>
680Sstevel@tonic-gate #include <stdlib.h>
690Sstevel@tonic-gate #include <string.h>
700Sstevel@tonic-gate #include <sys/types.h>
710Sstevel@tonic-gate #include <unistd.h>
720Sstevel@tonic-gate 
730Sstevel@tonic-gate #include <openssl/e_os2.h>
746847Svk199839 #include <openssl/crypto.h>
750Sstevel@tonic-gate #include <openssl/engine.h>
760Sstevel@tonic-gate #include <openssl/dso.h>
770Sstevel@tonic-gate #include <openssl/err.h>
780Sstevel@tonic-gate #include <openssl/bn.h>
792139Sjp161948 #include <openssl/md5.h>
800Sstevel@tonic-gate #include <openssl/pem.h>
816847Svk199839 #ifndef OPENSSL_NO_RSA
820Sstevel@tonic-gate #include <openssl/rsa.h>
836847Svk199839 #endif
846847Svk199839 #ifndef OPENSSL_NO_DSA
856847Svk199839 #include <openssl/dsa.h>
866847Svk199839 #endif
876847Svk199839 #ifndef OPENSSL_NO_DH
886847Svk199839 #include <openssl/dh.h>
896847Svk199839 #endif
900Sstevel@tonic-gate #include <openssl/rand.h>
910Sstevel@tonic-gate #include <openssl/objects.h>
920Sstevel@tonic-gate #include <openssl/x509.h>
937211Sjp161948 #include <openssl/aes.h>
940Sstevel@tonic-gate #include <cryptlib.h>
957211Sjp161948 #include <dlfcn.h>
96*7526SVladimir.Kotal@Sun.COM #include <pthread.h>
970Sstevel@tonic-gate 
980Sstevel@tonic-gate #ifndef OPENSSL_NO_HW
990Sstevel@tonic-gate #ifndef OPENSSL_NO_HW_PK11
1000Sstevel@tonic-gate 
1017211Sjp161948 /* label for debug messages printed on stderr */
1027211Sjp161948 #define	PK11_DBG	"PKCS#11 ENGINE DEBUG"
1037211Sjp161948 /* prints a lot of debug messages on stderr about slot selection process */
1047211Sjp161948 #undef	DEBUG_SLOT_SELECTION
1057211Sjp161948 /*
1067211Sjp161948  * Solaris specific code. See comment at check_hw_mechanisms() for more
1077211Sjp161948  * information.
1087211Sjp161948  */
1097211Sjp161948 #define	SOLARIS_HW_SLOT_SELECTION
1107211Sjp161948 
1117211Sjp161948 /*
1127211Sjp161948  * AES counter mode is not supported in the OpenSSL EVP API yet and neither
1137211Sjp161948  * there are official OIDs for mechanisms based on this mode. With our changes,
1147211Sjp161948  * an application can define its own EVP calls for AES counter mode and then
1157211Sjp161948  * it can make use of hardware acceleration through this engine. However, it's
1167211Sjp161948  * better if we keep AES CTR support code under ifdef's.
1177211Sjp161948  */
1187211Sjp161948 #define	SOLARIS_AES_CTR
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate #include "security/cryptoki.h"
1210Sstevel@tonic-gate #include "security/pkcs11.h"
1220Sstevel@tonic-gate #include "hw_pk11_err.c"
1230Sstevel@tonic-gate 
1247211Sjp161948 #ifdef	SOLARIS_AES_CTR
1257211Sjp161948 /*
1267211Sjp161948  * NIDs for AES counter mode that will be defined during the engine
1277211Sjp161948  * initialization.
1287211Sjp161948  */
1297211Sjp161948 int NID_aes_128_ctr = NID_undef;
1307211Sjp161948 int NID_aes_192_ctr = NID_undef;
1317211Sjp161948 int NID_aes_256_ctr = NID_undef;
1327211Sjp161948 #endif	/* SOLARIS_AES_CTR */
1337211Sjp161948 
1347211Sjp161948 #ifdef	SOLARIS_HW_SLOT_SELECTION
1357211Sjp161948 /*
1367211Sjp161948  * Tables for symmetric ciphers and digest mechs found in the pkcs11_kernel
1377211Sjp161948  * library. See comment at check_hw_mechanisms() for more information.
1387211Sjp161948  */
1397211Sjp161948 int *hw_cnids;
1407211Sjp161948 int *hw_dnids;
1417211Sjp161948 #endif	/* SOLARIS_HW_SLOT_SELECTION */
1427211Sjp161948 
143*7526SVladimir.Kotal@Sun.COM /* PKCS#11 session caches and their locks for all operation types */
144*7526SVladimir.Kotal@Sun.COM static PK11_CACHE session_cache[OP_MAX];
145*7526SVladimir.Kotal@Sun.COM 
1467211Sjp161948 /*
147*7526SVladimir.Kotal@Sun.COM  * As stated in v2.20, 11.7 Object Management Function, in section for
148*7526SVladimir.Kotal@Sun.COM  * C_FindObjectsInit(), at most one search operation may be active at a given
149*7526SVladimir.Kotal@Sun.COM  * time in a given session. Therefore, C_Find{,Init,Final}Objects() should be
150*7526SVladimir.Kotal@Sun.COM  * grouped together to form one atomic search operation. This is already
151*7526SVladimir.Kotal@Sun.COM  * ensured by the property of unique PKCS#11 session handle used for each
152*7526SVladimir.Kotal@Sun.COM  * PK11_SESSION object.
153*7526SVladimir.Kotal@Sun.COM  *
154*7526SVladimir.Kotal@Sun.COM  * This is however not the biggest concern - maintaining consistency of the
155*7526SVladimir.Kotal@Sun.COM  * underlying object store is more important. The same section of the spec also
156*7526SVladimir.Kotal@Sun.COM  * says that one thread can be in the middle of a search operation while another
157*7526SVladimir.Kotal@Sun.COM  * thread destroys the object matching the search template which would result in
158*7526SVladimir.Kotal@Sun.COM  * invalid handle returned from the search operation.
159*7526SVladimir.Kotal@Sun.COM  *
160*7526SVladimir.Kotal@Sun.COM  * Hence, the following locks are used for both protection of the object stores.
161*7526SVladimir.Kotal@Sun.COM  * They are also used for active list protection.
1627211Sjp161948  */
163*7526SVladimir.Kotal@Sun.COM pthread_mutex_t *find_lock[OP_MAX] = { NULL };
164*7526SVladimir.Kotal@Sun.COM 
165*7526SVladimir.Kotal@Sun.COM /*
166*7526SVladimir.Kotal@Sun.COM  * lists of asymmetric key handles which are active (referenced by at least one
167*7526SVladimir.Kotal@Sun.COM  * PK11_SESSION structure, either held by a thread or present in free_session
168*7526SVladimir.Kotal@Sun.COM  * list) for given algorithm type
169*7526SVladimir.Kotal@Sun.COM  */
170*7526SVladimir.Kotal@Sun.COM PK11_active *active_list[OP_MAX] = { NULL };
171*7526SVladimir.Kotal@Sun.COM 
172*7526SVladimir.Kotal@Sun.COM /*
173*7526SVladimir.Kotal@Sun.COM  * Create all secret key objects in a global session so that they are available
1740Sstevel@tonic-gate  * to use for other sessions. These other sessions may be opened or closed
175*7526SVladimir.Kotal@Sun.COM  * without losing the secret key objects.
176*7526SVladimir.Kotal@Sun.COM  */
1770Sstevel@tonic-gate static CK_SESSION_HANDLE	global_session = CK_INVALID_HANDLE;
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate /* ENGINE level stuff */
1800Sstevel@tonic-gate static int pk11_init(ENGINE *e);
1810Sstevel@tonic-gate static int pk11_library_init(ENGINE *e);
1820Sstevel@tonic-gate static int pk11_finish(ENGINE *e);
1830Sstevel@tonic-gate static int pk11_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)());
1840Sstevel@tonic-gate static int pk11_destroy(ENGINE *e);
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate /* RAND stuff */
1870Sstevel@tonic-gate static void pk11_rand_seed(const void *buf, int num);
1880Sstevel@tonic-gate static void pk11_rand_add(const void *buf, int num, double add_entropy);
1890Sstevel@tonic-gate static void pk11_rand_cleanup(void);
1900Sstevel@tonic-gate static int pk11_rand_bytes(unsigned char *buf, int num);
1910Sstevel@tonic-gate static int pk11_rand_status(void);
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate /* These functions are also used in other files */
1947211Sjp161948 PK11_SESSION *pk11_get_session(PK11_OPTYPE optype);
1957211Sjp161948 void pk11_return_session(PK11_SESSION *sp, PK11_OPTYPE optype);
1966847Svk199839 
197*7526SVladimir.Kotal@Sun.COM /* active list manipulation functions used in this file */
198*7526SVladimir.Kotal@Sun.COM extern int pk11_active_delete(CK_OBJECT_HANDLE h, PK11_OPTYPE type);
199*7526SVladimir.Kotal@Sun.COM extern void pk11_free_active_list(PK11_OPTYPE type);
2006847Svk199839 
2016847Svk199839 #ifndef OPENSSL_NO_RSA
2020Sstevel@tonic-gate int pk11_destroy_rsa_key_objects(PK11_SESSION *session);
2036847Svk199839 int pk11_destroy_rsa_object_pub(PK11_SESSION *sp, CK_BBOOL uselock);
2046847Svk199839 int pk11_destroy_rsa_object_priv(PK11_SESSION *sp, CK_BBOOL uselock);
2056847Svk199839 #endif
2066847Svk199839 #ifndef OPENSSL_NO_DSA
2070Sstevel@tonic-gate int pk11_destroy_dsa_key_objects(PK11_SESSION *session);
2086847Svk199839 int pk11_destroy_dsa_object_pub(PK11_SESSION *sp, CK_BBOOL uselock);
2096847Svk199839 int pk11_destroy_dsa_object_priv(PK11_SESSION *sp, CK_BBOOL uselock);
2106847Svk199839 #endif
2116847Svk199839 #ifndef OPENSSL_NO_DH
2120Sstevel@tonic-gate int pk11_destroy_dh_key_objects(PK11_SESSION *session);
2136847Svk199839 int pk11_destroy_dh_object(PK11_SESSION *session, CK_BBOOL uselock);
2146847Svk199839 #endif
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate /* Local helper functions */
2177211Sjp161948 static int pk11_free_all_sessions(void);
218*7526SVladimir.Kotal@Sun.COM static int pk11_free_session_list(PK11_OPTYPE optype);
2197211Sjp161948 static int pk11_setup_session(PK11_SESSION *sp, PK11_OPTYPE optype);
2200Sstevel@tonic-gate static int pk11_destroy_cipher_key_objects(PK11_SESSION *session);
2216847Svk199839 static int pk11_destroy_object(CK_SESSION_HANDLE session,
2220Sstevel@tonic-gate 	CK_OBJECT_HANDLE oh);
2230Sstevel@tonic-gate static const char *get_PK11_LIBNAME(void);
2240Sstevel@tonic-gate static void free_PK11_LIBNAME(void);
2250Sstevel@tonic-gate static long set_PK11_LIBNAME(const char *name);
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate /* Symmetric cipher and digest support functions */
2280Sstevel@tonic-gate static int cipher_nid_to_pk11(int nid);
2297211Sjp161948 #ifdef	SOLARIS_AES_CTR
2307211Sjp161948 static int pk11_add_NID(char *sn, char *ln);
2317211Sjp161948 static int pk11_add_aes_ctr_NIDs(void);
2327211Sjp161948 #endif	/* SOLARIS_AES_CTR */
2330Sstevel@tonic-gate static int pk11_usable_ciphers(const int **nids);
2340Sstevel@tonic-gate static int pk11_usable_digests(const int **nids);
2350Sstevel@tonic-gate static int pk11_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
2360Sstevel@tonic-gate 	const unsigned char *iv, int enc);
2370Sstevel@tonic-gate static int pk11_cipher_final(PK11_SESSION *sp);
2380Sstevel@tonic-gate static int pk11_cipher_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
2390Sstevel@tonic-gate 	const unsigned char *in, unsigned int inl);
2400Sstevel@tonic-gate static int pk11_cipher_cleanup(EVP_CIPHER_CTX *ctx);
2410Sstevel@tonic-gate static int pk11_engine_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
2420Sstevel@tonic-gate 	const int **nids, int nid);
2430Sstevel@tonic-gate static int pk11_engine_digests(ENGINE *e, const EVP_MD **digest,
2440Sstevel@tonic-gate 	const int **nids, int nid);
2450Sstevel@tonic-gate static CK_OBJECT_HANDLE pk11_get_cipher_key(EVP_CIPHER_CTX *ctx,
2460Sstevel@tonic-gate 	const unsigned char *key, CK_KEY_TYPE key_type, PK11_SESSION *sp);
2477211Sjp161948 static int check_new_cipher_key(PK11_SESSION *sp, const unsigned char *key,
2487211Sjp161948 	int key_len);
2490Sstevel@tonic-gate static int md_nid_to_pk11(int nid);
2500Sstevel@tonic-gate static int pk11_digest_init(EVP_MD_CTX *ctx);
2510Sstevel@tonic-gate static int pk11_digest_update(EVP_MD_CTX *ctx,const void *data,
2522139Sjp161948 	size_t count);
2530Sstevel@tonic-gate static int pk11_digest_final(EVP_MD_CTX *ctx,unsigned char *md);
2540Sstevel@tonic-gate static int pk11_digest_copy(EVP_MD_CTX *to,const EVP_MD_CTX *from);
2550Sstevel@tonic-gate static int pk11_digest_cleanup(EVP_MD_CTX *ctx);
2560Sstevel@tonic-gate 
2577211Sjp161948 static int pk11_choose_slots(int *any_slot_found);
2587211Sjp161948 static void pk11_find_symmetric_ciphers(CK_FUNCTION_LIST_PTR pflist,
2597211Sjp161948     CK_SLOT_ID current_slot, int *current_slot_n_cipher,
2607211Sjp161948     int *local_cipher_nids);
2617211Sjp161948 static void pk11_find_digests(CK_FUNCTION_LIST_PTR pflist,
2627211Sjp161948     CK_SLOT_ID current_slot, int *current_slot_n_digest,
2637211Sjp161948     int *local_digest_nids);
2647211Sjp161948 static void pk11_get_symmetric_cipher(CK_FUNCTION_LIST_PTR, int slot_id,
2657211Sjp161948     CK_MECHANISM_TYPE mech, int *current_slot_n_cipher, int *local_cipher_nids,
2667211Sjp161948     int id);
2677211Sjp161948 static void pk11_get_digest(CK_FUNCTION_LIST_PTR pflist, int slot_id,
2687211Sjp161948     CK_MECHANISM_TYPE mech, int *current_slot_n_digest, int *local_digest_nids,
2697211Sjp161948     int id);
2707211Sjp161948 
271*7526SVladimir.Kotal@Sun.COM static int pk11_init_all_locks(void);
272*7526SVladimir.Kotal@Sun.COM static void pk11_free_all_locks(void);
273*7526SVladimir.Kotal@Sun.COM 
2747211Sjp161948 #ifdef	SOLARIS_HW_SLOT_SELECTION
2757211Sjp161948 static int check_hw_mechanisms(void);
2767211Sjp161948 static int nid_in_table(int nid, int *nid_table);
2777211Sjp161948 #endif	/* SOLARIS_HW_SLOT_SELECTION */
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate /* Index for the supported ciphers */
2807211Sjp161948 enum pk11_cipher_id {
2817211Sjp161948 	PK11_DES_CBC,
2827211Sjp161948 	PK11_DES3_CBC,
2837211Sjp161948 	PK11_DES_ECB,
2847211Sjp161948 	PK11_DES3_ECB,
2857211Sjp161948 	PK11_RC4,
2867211Sjp161948 	PK11_AES_128_CBC,
2877211Sjp161948 	PK11_AES_192_CBC,
2887211Sjp161948 	PK11_AES_256_CBC,
2897211Sjp161948 	PK11_AES_128_ECB,
2907211Sjp161948 	PK11_AES_192_ECB,
2917211Sjp161948 	PK11_AES_256_ECB,
2927211Sjp161948 	PK11_BLOWFISH_CBC,
2937211Sjp161948 #ifdef	SOLARIS_AES_CTR
2947211Sjp161948 	PK11_AES_128_CTR,
2957211Sjp161948 	PK11_AES_192_CTR,
2967211Sjp161948 	PK11_AES_256_CTR,
2977211Sjp161948 #endif	/* SOLARIS_AES_CTR */
2987211Sjp161948 	PK11_CIPHER_MAX
2997211Sjp161948 };
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate /* Index for the supported digests */
3027211Sjp161948 enum pk11_digest_id {
3037211Sjp161948 	PK11_MD5,
3047211Sjp161948 	PK11_SHA1,
3057211Sjp161948 	PK11_SHA224,
3067211Sjp161948 	PK11_SHA256,
3077211Sjp161948 	PK11_SHA384,
3087211Sjp161948 	PK11_SHA512,
3097211Sjp161948 	PK11_DIGEST_MAX
3107211Sjp161948 };
3110Sstevel@tonic-gate 
312*7526SVladimir.Kotal@Sun.COM #define	TRY_OBJ_DESTROY(sess_hdl, obj_hdl, retval, uselock, alg_type)	\
3136847Svk199839 	{								\
3146847Svk199839 	if (uselock)							\
315*7526SVladimir.Kotal@Sun.COM 		LOCK_OBJSTORE(alg_type);				\
316*7526SVladimir.Kotal@Sun.COM 	if (pk11_active_delete(obj_hdl, alg_type) == 1)			\
3176847Svk199839 		{							\
3186847Svk199839 		retval = pk11_destroy_object(sess_hdl, obj_hdl);	\
3196847Svk199839 		}							\
3206847Svk199839 	if (uselock)							\
321*7526SVladimir.Kotal@Sun.COM 		UNLOCK_OBJSTORE(alg_type);				\
3226847Svk199839 	}
3236847Svk199839 
3240Sstevel@tonic-gate static int cipher_nids[PK11_CIPHER_MAX];
3250Sstevel@tonic-gate static int digest_nids[PK11_DIGEST_MAX];
3260Sstevel@tonic-gate static int cipher_count		= 0;
3270Sstevel@tonic-gate static int digest_count		= 0;
3280Sstevel@tonic-gate static CK_BBOOL pk11_have_rsa	= CK_FALSE;
3290Sstevel@tonic-gate static CK_BBOOL pk11_have_dsa	= CK_FALSE;
3300Sstevel@tonic-gate static CK_BBOOL pk11_have_dh	= CK_FALSE;
3310Sstevel@tonic-gate static CK_BBOOL pk11_have_random = CK_FALSE;
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate typedef struct PK11_CIPHER_st
3340Sstevel@tonic-gate 	{
3357211Sjp161948 	enum pk11_cipher_id	id;
3364320Sjp161948 	int			nid;
3377211Sjp161948 	int			iv_len;
3384320Sjp161948 	int			key_len;
3394320Sjp161948 	CK_KEY_TYPE		key_type;
3404320Sjp161948 	CK_MECHANISM_TYPE	mech_type;
3410Sstevel@tonic-gate 	} PK11_CIPHER;
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate static PK11_CIPHER ciphers[] =
3440Sstevel@tonic-gate 	{
3457211Sjp161948 	{PK11_DES_CBC,	   NID_des_cbc,      8,  8, CKK_DES,      CKM_DES_CBC, },
3467211Sjp161948 	{PK11_DES3_CBC,	   NID_des_ede3_cbc, 8, 24, CKK_DES3,     CKM_DES3_CBC, },
3477211Sjp161948 	{PK11_DES_ECB,	   NID_des_ecb,      0,  8, CKK_DES,      CKM_DES_ECB, },
3487211Sjp161948 	{PK11_DES3_ECB,	   NID_des_ede3_ecb, 0, 24, CKK_DES3,     CKM_DES3_ECB, },
3497211Sjp161948 	{PK11_RC4,	   NID_rc4,          0, 16, CKK_RC4,      CKM_RC4, },
3507211Sjp161948 	{PK11_AES_128_CBC, NID_aes_128_cbc, 16, 16, CKK_AES,      CKM_AES_CBC, },
3517211Sjp161948 	{PK11_AES_192_CBC, NID_aes_192_cbc, 16, 24, CKK_AES,      CKM_AES_CBC, },
3527211Sjp161948 	{PK11_AES_256_CBC, NID_aes_256_cbc, 16, 32, CKK_AES,      CKM_AES_CBC, },
3537211Sjp161948 	{PK11_AES_128_ECB, NID_aes_128_ecb,  0, 16, CKK_AES,      CKM_AES_ECB, },
3547211Sjp161948 	{PK11_AES_192_ECB, NID_aes_192_ecb,  0, 24, CKK_AES,      CKM_AES_ECB, },
3557211Sjp161948 	{PK11_AES_256_ECB, NID_aes_256_ecb,  0, 32, CKK_AES,      CKM_AES_ECB, },
3567211Sjp161948 	{PK11_BLOWFISH_CBC,NID_bf_cbc,       8, 16, CKK_BLOWFISH, CKM_BLOWFISH_CBC,},
3577211Sjp161948 #ifdef	SOLARIS_AES_CTR
3587211Sjp161948 	/* we don't know the correct NIDs until the engine is initialized */
3597211Sjp161948 	{PK11_AES_128_CTR, NID_undef,	    16, 16, CKK_AES,      CKM_AES_CTR, },
3607211Sjp161948 	{PK11_AES_192_CTR, NID_undef,	    16, 24, CKK_AES,      CKM_AES_CTR, },
3617211Sjp161948 	{PK11_AES_256_CTR, NID_undef,	    16, 32, CKK_AES,      CKM_AES_CTR, },
3627211Sjp161948 #endif	/* SOLARIS_AES_CTR */
3630Sstevel@tonic-gate 	};
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate typedef struct PK11_DIGEST_st
3660Sstevel@tonic-gate 	{
3677211Sjp161948 	enum pk11_digest_id	id;
3684320Sjp161948 	int			nid;
3694320Sjp161948 	CK_MECHANISM_TYPE	mech_type;
3700Sstevel@tonic-gate 	} PK11_DIGEST;
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate static PK11_DIGEST digests[] =
3730Sstevel@tonic-gate 	{
3744320Sjp161948 	{PK11_MD5,	NID_md5,	CKM_MD5, },
3754320Sjp161948 	{PK11_SHA1,	NID_sha1,	CKM_SHA_1, },
3767211Sjp161948 	{PK11_SHA224,	NID_sha224,	CKM_SHA224, },
3777211Sjp161948 	{PK11_SHA256,	NID_sha256,	CKM_SHA256, },
3787211Sjp161948 	{PK11_SHA384,	NID_sha384,	CKM_SHA384, },
3797211Sjp161948 	{PK11_SHA512,	NID_sha512,	CKM_SHA512, },
3804320Sjp161948 	{0,		NID_undef,	0xFFFF, },
3810Sstevel@tonic-gate 	};
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate /* Structure to be used for the cipher_data/md_data in
3840Sstevel@tonic-gate  * EVP_CIPHER_CTX/EVP_MD_CTX structures in order to use the same
3850Sstevel@tonic-gate  * pk11 session in multiple cipher_update calls
3860Sstevel@tonic-gate  */
3870Sstevel@tonic-gate typedef struct PK11_CIPHER_STATE_st
3880Sstevel@tonic-gate 	{
3890Sstevel@tonic-gate 	PK11_SESSION	*sp;
3900Sstevel@tonic-gate 	} PK11_CIPHER_STATE;
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 
3937211Sjp161948 /*
3947211Sjp161948  * libcrypto EVP stuff - this is how we get wired to EVP so the engine gets
3957211Sjp161948  * called when libcrypto requests a cipher NID.
3967211Sjp161948  *
3970Sstevel@tonic-gate  * Note how the PK11_CIPHER_STATE is used here.
3980Sstevel@tonic-gate  */
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate /* DES CBC EVP */
4010Sstevel@tonic-gate static const EVP_CIPHER pk11_des_cbc =
4020Sstevel@tonic-gate 	{
4030Sstevel@tonic-gate 	NID_des_cbc,
4040Sstevel@tonic-gate 	8, 8, 8,
4050Sstevel@tonic-gate 	EVP_CIPH_CBC_MODE,
4060Sstevel@tonic-gate 	pk11_cipher_init,
4070Sstevel@tonic-gate 	pk11_cipher_do_cipher,
4080Sstevel@tonic-gate 	pk11_cipher_cleanup,
4090Sstevel@tonic-gate 	sizeof(PK11_CIPHER_STATE),
4100Sstevel@tonic-gate 	EVP_CIPHER_set_asn1_iv,
4110Sstevel@tonic-gate 	EVP_CIPHER_get_asn1_iv,
4120Sstevel@tonic-gate 	NULL
4130Sstevel@tonic-gate 	};
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate /* 3DES CBC EVP */
4160Sstevel@tonic-gate static const EVP_CIPHER pk11_3des_cbc =
4170Sstevel@tonic-gate 	{
4180Sstevel@tonic-gate 	NID_des_ede3_cbc,
4190Sstevel@tonic-gate 	8, 24, 8,
4200Sstevel@tonic-gate 	EVP_CIPH_CBC_MODE,
4210Sstevel@tonic-gate 	pk11_cipher_init,
4220Sstevel@tonic-gate 	pk11_cipher_do_cipher,
4230Sstevel@tonic-gate 	pk11_cipher_cleanup,
4240Sstevel@tonic-gate 	sizeof(PK11_CIPHER_STATE),
4250Sstevel@tonic-gate 	EVP_CIPHER_set_asn1_iv,
4260Sstevel@tonic-gate 	EVP_CIPHER_get_asn1_iv,
4270Sstevel@tonic-gate 	NULL
4280Sstevel@tonic-gate 	};
4290Sstevel@tonic-gate 
4307211Sjp161948 /*
4317211Sjp161948  * ECB modes don't use an Initial Vector so that's why set_asn1_parameters and
4327211Sjp161948  * get_asn1_parameters fields are set to NULL.
4337211Sjp161948  */
4347211Sjp161948 static const EVP_CIPHER pk11_des_ecb =
4357211Sjp161948 	{
4367211Sjp161948 	NID_des_ecb,
4377211Sjp161948 	8, 8, 8,
4387211Sjp161948 	EVP_CIPH_ECB_MODE,
4397211Sjp161948 	pk11_cipher_init,
4407211Sjp161948 	pk11_cipher_do_cipher,
4417211Sjp161948 	pk11_cipher_cleanup,
4427211Sjp161948 	sizeof(PK11_CIPHER_STATE),
4437211Sjp161948 	NULL,
4447211Sjp161948 	NULL,
4457211Sjp161948 	NULL
4467211Sjp161948 	};
4477211Sjp161948 
4487211Sjp161948 static const EVP_CIPHER pk11_3des_ecb =
4497211Sjp161948 	{
4507211Sjp161948 	NID_des_ede3_ecb,
4517211Sjp161948 	8, 24, 8,
4527211Sjp161948 	EVP_CIPH_ECB_MODE,
4537211Sjp161948 	pk11_cipher_init,
4547211Sjp161948 	pk11_cipher_do_cipher,
4557211Sjp161948 	pk11_cipher_cleanup,
4567211Sjp161948 	sizeof(PK11_CIPHER_STATE),
4577211Sjp161948 	NULL,
4587211Sjp161948 	NULL,
4597211Sjp161948 	NULL
4607211Sjp161948 	};
4617211Sjp161948 
4627211Sjp161948 
4637211Sjp161948 static const EVP_CIPHER pk11_aes_128_cbc =
4640Sstevel@tonic-gate 	{
4650Sstevel@tonic-gate 	NID_aes_128_cbc,
4660Sstevel@tonic-gate 	16, 16, 16,
4670Sstevel@tonic-gate 	EVP_CIPH_CBC_MODE,
4680Sstevel@tonic-gate 	pk11_cipher_init,
4690Sstevel@tonic-gate 	pk11_cipher_do_cipher,
4700Sstevel@tonic-gate 	pk11_cipher_cleanup,
4710Sstevel@tonic-gate 	sizeof(PK11_CIPHER_STATE),
4720Sstevel@tonic-gate 	EVP_CIPHER_set_asn1_iv,
4730Sstevel@tonic-gate 	EVP_CIPHER_get_asn1_iv,
4740Sstevel@tonic-gate 	NULL
4750Sstevel@tonic-gate 	};
4760Sstevel@tonic-gate 
4777211Sjp161948 static const EVP_CIPHER pk11_aes_192_cbc =
4787211Sjp161948 	{
4797211Sjp161948 	NID_aes_192_cbc,
4807211Sjp161948 	16, 24, 16,
4817211Sjp161948 	EVP_CIPH_CBC_MODE,
4827211Sjp161948 	pk11_cipher_init,
4837211Sjp161948 	pk11_cipher_do_cipher,
4847211Sjp161948 	pk11_cipher_cleanup,
4857211Sjp161948 	sizeof(PK11_CIPHER_STATE),
4867211Sjp161948 	EVP_CIPHER_set_asn1_iv,
4877211Sjp161948 	EVP_CIPHER_get_asn1_iv,
4887211Sjp161948 	NULL
4897211Sjp161948 	};
4907211Sjp161948 
4917211Sjp161948 static const EVP_CIPHER pk11_aes_256_cbc =
4927211Sjp161948 	{
4937211Sjp161948 	NID_aes_256_cbc,
4947211Sjp161948 	16, 32, 16,
4957211Sjp161948 	EVP_CIPH_CBC_MODE,
4967211Sjp161948 	pk11_cipher_init,
4977211Sjp161948 	pk11_cipher_do_cipher,
4987211Sjp161948 	pk11_cipher_cleanup,
4997211Sjp161948 	sizeof(PK11_CIPHER_STATE),
5007211Sjp161948 	EVP_CIPHER_set_asn1_iv,
5017211Sjp161948 	EVP_CIPHER_get_asn1_iv,
5027211Sjp161948 	NULL
5037211Sjp161948 	};
5047211Sjp161948 
5057211Sjp161948 /*
5067211Sjp161948  * ECB modes don't use IV so that's why set_asn1_parameters and
5077211Sjp161948  * get_asn1_parameters are set to NULL.
5087211Sjp161948  */
5097211Sjp161948 static const EVP_CIPHER pk11_aes_128_ecb =
5107211Sjp161948 	{
5117211Sjp161948 	NID_aes_128_ecb,
5127211Sjp161948 	16, 16, 0,
5137211Sjp161948 	EVP_CIPH_ECB_MODE,
5147211Sjp161948 	pk11_cipher_init,
5157211Sjp161948 	pk11_cipher_do_cipher,
5167211Sjp161948 	pk11_cipher_cleanup,
5177211Sjp161948 	sizeof(PK11_CIPHER_STATE),
5187211Sjp161948 	NULL,
5197211Sjp161948 	NULL,
5207211Sjp161948 	NULL
5217211Sjp161948 	};
5227211Sjp161948 
5237211Sjp161948 static const EVP_CIPHER pk11_aes_192_ecb =
5247211Sjp161948 	{
5257211Sjp161948 	NID_aes_192_ecb,
5267211Sjp161948 	16, 24, 0,
5277211Sjp161948 	EVP_CIPH_ECB_MODE,
5287211Sjp161948 	pk11_cipher_init,
5297211Sjp161948 	pk11_cipher_do_cipher,
5307211Sjp161948 	pk11_cipher_cleanup,
5317211Sjp161948 	sizeof(PK11_CIPHER_STATE),
5327211Sjp161948 	NULL,
5337211Sjp161948 	NULL,
5347211Sjp161948 	NULL
5357211Sjp161948 	};
5367211Sjp161948 
5377211Sjp161948 static const EVP_CIPHER pk11_aes_256_ecb =
5387211Sjp161948 	{
5397211Sjp161948 	NID_aes_256_ecb,
5407211Sjp161948 	16, 32, 0,
5417211Sjp161948 	EVP_CIPH_ECB_MODE,
5427211Sjp161948 	pk11_cipher_init,
5437211Sjp161948 	pk11_cipher_do_cipher,
5447211Sjp161948 	pk11_cipher_cleanup,
5457211Sjp161948 	sizeof(PK11_CIPHER_STATE),
5467211Sjp161948 	NULL,
5477211Sjp161948 	NULL,
5487211Sjp161948 	NULL
5497211Sjp161948 	};
5507211Sjp161948 
5517211Sjp161948 #ifdef	SOLARIS_AES_CTR
5527211Sjp161948 /*
5537211Sjp161948  * NID_undef's will be changed to the AES counter mode NIDs as soon they are
5547211Sjp161948  * created in pk11_library_init(). Note that the need to change these structures
5557211Sjp161948  * is the reason why we don't define them with the const keyword.
5567211Sjp161948  */
5577211Sjp161948 static EVP_CIPHER pk11_aes_128_ctr =
5587211Sjp161948 	{
5597211Sjp161948 	NID_undef,
5607211Sjp161948 	16, 16, 16,
5617211Sjp161948 	EVP_CIPH_CBC_MODE,
5627211Sjp161948 	pk11_cipher_init,
5637211Sjp161948 	pk11_cipher_do_cipher,
5647211Sjp161948 	pk11_cipher_cleanup,
5657211Sjp161948 	sizeof(PK11_CIPHER_STATE),
5667211Sjp161948 	EVP_CIPHER_set_asn1_iv,
5677211Sjp161948 	EVP_CIPHER_get_asn1_iv,
5687211Sjp161948 	NULL
5697211Sjp161948 	};
5707211Sjp161948 
5717211Sjp161948 static EVP_CIPHER pk11_aes_192_ctr =
5727211Sjp161948 	{
5737211Sjp161948 	NID_undef,
5747211Sjp161948 	16, 24, 16,
5757211Sjp161948 	EVP_CIPH_CBC_MODE,
5767211Sjp161948 	pk11_cipher_init,
5777211Sjp161948 	pk11_cipher_do_cipher,
5787211Sjp161948 	pk11_cipher_cleanup,
5797211Sjp161948 	sizeof(PK11_CIPHER_STATE),
5807211Sjp161948 	EVP_CIPHER_set_asn1_iv,
5817211Sjp161948 	EVP_CIPHER_get_asn1_iv,
5827211Sjp161948 	NULL
5837211Sjp161948 	};
5847211Sjp161948 
5857211Sjp161948 static EVP_CIPHER pk11_aes_256_ctr =
5867211Sjp161948 	{
5877211Sjp161948 	NID_undef,
5887211Sjp161948 	16, 32, 16,
5897211Sjp161948 	EVP_CIPH_CBC_MODE,
5907211Sjp161948 	pk11_cipher_init,
5917211Sjp161948 	pk11_cipher_do_cipher,
5927211Sjp161948 	pk11_cipher_cleanup,
5937211Sjp161948 	sizeof(PK11_CIPHER_STATE),
5947211Sjp161948 	EVP_CIPHER_set_asn1_iv,
5957211Sjp161948 	EVP_CIPHER_get_asn1_iv,
5967211Sjp161948 	NULL
5977211Sjp161948 	};
5987211Sjp161948 #endif	/* SOLARIS_AES_CTR */
5997211Sjp161948 
6007211Sjp161948 static const EVP_CIPHER pk11_bf_cbc =
6017211Sjp161948 	{
6027211Sjp161948 	NID_bf_cbc,
6037211Sjp161948 	8, 16, 8,
6047211Sjp161948 	EVP_CIPH_VARIABLE_LENGTH,
6057211Sjp161948 	pk11_cipher_init,
6067211Sjp161948 	pk11_cipher_do_cipher,
6077211Sjp161948 	pk11_cipher_cleanup,
6087211Sjp161948 	sizeof(PK11_CIPHER_STATE),
6097211Sjp161948 	EVP_CIPHER_set_asn1_iv,
6107211Sjp161948 	EVP_CIPHER_get_asn1_iv,
6117211Sjp161948 	NULL
6127211Sjp161948 	};
6137211Sjp161948 
6140Sstevel@tonic-gate static const EVP_CIPHER pk11_rc4 =
6150Sstevel@tonic-gate 	{
6160Sstevel@tonic-gate 	NID_rc4,
6177211Sjp161948 	1, 16, 0,
6180Sstevel@tonic-gate 	EVP_CIPH_VARIABLE_LENGTH,
6190Sstevel@tonic-gate 	pk11_cipher_init,
6200Sstevel@tonic-gate 	pk11_cipher_do_cipher,
6210Sstevel@tonic-gate 	pk11_cipher_cleanup,
6220Sstevel@tonic-gate 	sizeof(PK11_CIPHER_STATE),
6230Sstevel@tonic-gate 	NULL,
6240Sstevel@tonic-gate 	NULL,
6250Sstevel@tonic-gate 	NULL
6260Sstevel@tonic-gate 	};
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate static const EVP_MD pk11_md5 =
6290Sstevel@tonic-gate 	{
6300Sstevel@tonic-gate 	NID_md5,
6310Sstevel@tonic-gate 	NID_md5WithRSAEncryption,
6320Sstevel@tonic-gate 	MD5_DIGEST_LENGTH,
6330Sstevel@tonic-gate 	0,
6340Sstevel@tonic-gate 	pk11_digest_init,
6350Sstevel@tonic-gate 	pk11_digest_update,
6360Sstevel@tonic-gate 	pk11_digest_final,
6370Sstevel@tonic-gate 	pk11_digest_copy,
6380Sstevel@tonic-gate 	pk11_digest_cleanup,
6390Sstevel@tonic-gate 	EVP_PKEY_RSA_method,
6400Sstevel@tonic-gate 	MD5_CBLOCK,
6410Sstevel@tonic-gate 	sizeof(PK11_CIPHER_STATE),
6420Sstevel@tonic-gate 	};
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate static const EVP_MD pk11_sha1 =
6450Sstevel@tonic-gate 	{
6460Sstevel@tonic-gate 	NID_sha1,
6470Sstevel@tonic-gate 	NID_sha1WithRSAEncryption,
6480Sstevel@tonic-gate 	SHA_DIGEST_LENGTH,
6490Sstevel@tonic-gate 	0,
6500Sstevel@tonic-gate 	pk11_digest_init,
6510Sstevel@tonic-gate 	pk11_digest_update,
6520Sstevel@tonic-gate 	pk11_digest_final,
6530Sstevel@tonic-gate 	pk11_digest_copy,
6540Sstevel@tonic-gate 	pk11_digest_cleanup,
6550Sstevel@tonic-gate 	EVP_PKEY_RSA_method,
6560Sstevel@tonic-gate 	SHA_CBLOCK,
6570Sstevel@tonic-gate 	sizeof(PK11_CIPHER_STATE),
6580Sstevel@tonic-gate 	};
6590Sstevel@tonic-gate 
6607211Sjp161948 static const EVP_MD pk11_sha224 =
6617211Sjp161948 	{
6627211Sjp161948 	NID_sha224,
6637211Sjp161948 	NID_sha224WithRSAEncryption,
6647211Sjp161948 	SHA224_DIGEST_LENGTH,
6657211Sjp161948 	0,
6667211Sjp161948 	pk11_digest_init,
6677211Sjp161948 	pk11_digest_update,
6687211Sjp161948 	pk11_digest_final,
6697211Sjp161948 	pk11_digest_copy,
6707211Sjp161948 	pk11_digest_cleanup,
6717211Sjp161948 	EVP_PKEY_RSA_method,
6727211Sjp161948 	/* SHA-224 uses the same cblock size as SHA-256 */
6737211Sjp161948 	SHA256_CBLOCK,
6747211Sjp161948 	sizeof(PK11_CIPHER_STATE),
6757211Sjp161948 	};
6767211Sjp161948 
6777211Sjp161948 static const EVP_MD pk11_sha256 =
6787211Sjp161948 	{
6797211Sjp161948 	NID_sha256,
6807211Sjp161948 	NID_sha256WithRSAEncryption,
6817211Sjp161948 	SHA256_DIGEST_LENGTH,
6827211Sjp161948 	0,
6837211Sjp161948 	pk11_digest_init,
6847211Sjp161948 	pk11_digest_update,
6857211Sjp161948 	pk11_digest_final,
6867211Sjp161948 	pk11_digest_copy,
6877211Sjp161948 	pk11_digest_cleanup,
6887211Sjp161948 	EVP_PKEY_RSA_method,
6897211Sjp161948 	SHA256_CBLOCK,
6907211Sjp161948 	sizeof(PK11_CIPHER_STATE),
6917211Sjp161948 	};
6927211Sjp161948 
6937211Sjp161948 static const EVP_MD pk11_sha384 =
6947211Sjp161948 	{
6957211Sjp161948 	NID_sha384,
6967211Sjp161948 	NID_sha384WithRSAEncryption,
6977211Sjp161948 	SHA384_DIGEST_LENGTH,
6987211Sjp161948 	0,
6997211Sjp161948 	pk11_digest_init,
7007211Sjp161948 	pk11_digest_update,
7017211Sjp161948 	pk11_digest_final,
7027211Sjp161948 	pk11_digest_copy,
7037211Sjp161948 	pk11_digest_cleanup,
7047211Sjp161948 	EVP_PKEY_RSA_method,
7057211Sjp161948 	/* SHA-384 uses the same cblock size as SHA-512 */
7067211Sjp161948 	SHA512_CBLOCK,
7077211Sjp161948 	sizeof(PK11_CIPHER_STATE),
7087211Sjp161948 	};
7097211Sjp161948 
7107211Sjp161948 static const EVP_MD pk11_sha512 =
7117211Sjp161948 	{
7127211Sjp161948 	NID_sha512,
7137211Sjp161948 	NID_sha512WithRSAEncryption,
7147211Sjp161948 	SHA512_DIGEST_LENGTH,
7157211Sjp161948 	0,
7167211Sjp161948 	pk11_digest_init,
7177211Sjp161948 	pk11_digest_update,
7187211Sjp161948 	pk11_digest_final,
7197211Sjp161948 	pk11_digest_copy,
7207211Sjp161948 	pk11_digest_cleanup,
7217211Sjp161948 	EVP_PKEY_RSA_method,
7227211Sjp161948 	SHA512_CBLOCK,
7237211Sjp161948 	sizeof(PK11_CIPHER_STATE),
7247211Sjp161948 	};
7257211Sjp161948 
7260Sstevel@tonic-gate /* Initialization function. Sets up various pk11 library components.
7270Sstevel@tonic-gate  */
7280Sstevel@tonic-gate /* The definitions for control commands specific to this engine
7290Sstevel@tonic-gate  */
7300Sstevel@tonic-gate #define PK11_CMD_SO_PATH		ENGINE_CMD_BASE
7310Sstevel@tonic-gate static const ENGINE_CMD_DEFN pk11_cmd_defns[] =
7320Sstevel@tonic-gate 	{
7330Sstevel@tonic-gate 		{
7340Sstevel@tonic-gate 		PK11_CMD_SO_PATH,
7350Sstevel@tonic-gate 		"SO_PATH",
7360Sstevel@tonic-gate 		"Specifies the path to the 'pkcs#11' shared library",
7370Sstevel@tonic-gate 		ENGINE_CMD_FLAG_STRING
7380Sstevel@tonic-gate 		},
7390Sstevel@tonic-gate 		{0, NULL, NULL, 0}
7400Sstevel@tonic-gate 	};
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate static RAND_METHOD pk11_random =
7440Sstevel@tonic-gate 	{
7450Sstevel@tonic-gate 	pk11_rand_seed,
7460Sstevel@tonic-gate 	pk11_rand_bytes,
7470Sstevel@tonic-gate 	pk11_rand_cleanup,
7480Sstevel@tonic-gate 	pk11_rand_add,
7490Sstevel@tonic-gate 	pk11_rand_bytes,
7500Sstevel@tonic-gate 	pk11_rand_status
7510Sstevel@tonic-gate 	};
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate /* Constants used when creating the ENGINE
7550Sstevel@tonic-gate  */
7560Sstevel@tonic-gate static const char *engine_pk11_id = "pkcs11";
7570Sstevel@tonic-gate static const char *engine_pk11_name = "PKCS #11 engine support";
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate CK_FUNCTION_LIST_PTR pFuncList = NULL;
7600Sstevel@tonic-gate static const char PK11_GET_FUNCTION_LIST[] = "C_GetFunctionList";
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate /* These are the static string constants for the DSO file name and the function
7637211Sjp161948  * symbol names to bind to.
7640Sstevel@tonic-gate  */
7650Sstevel@tonic-gate #if defined(__sparcv9) || defined(__x86_64) || defined(__amd64)
7660Sstevel@tonic-gate static const char def_PK11_LIBNAME[] = "/usr/lib/64/libpkcs11.so.1";
7670Sstevel@tonic-gate #else
7680Sstevel@tonic-gate static const char def_PK11_LIBNAME[] = "/usr/lib/libpkcs11.so.1";
7690Sstevel@tonic-gate #endif
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate static CK_BBOOL true = TRUE;
7720Sstevel@tonic-gate static CK_BBOOL false = FALSE;
7737211Sjp161948 static CK_SLOT_ID pubkey_SLOTID = 0;
7747211Sjp161948 static CK_SLOT_ID rand_SLOTID = 0;
7750Sstevel@tonic-gate static CK_SLOT_ID SLOTID = 0;
776*7526SVladimir.Kotal@Sun.COM static CK_BBOOL pk11_library_initialized = FALSE;
777*7526SVladimir.Kotal@Sun.COM static CK_BBOOL pk11_atfork_initialized = FALSE;
7787211Sjp161948 static int pk11_pid = 0;
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate static DSO *pk11_dso = NULL;
7810Sstevel@tonic-gate 
782*7526SVladimir.Kotal@Sun.COM /* allocate and initialize all locks used by the engine itself */
783*7526SVladimir.Kotal@Sun.COM static int pk11_init_all_locks(void)
784*7526SVladimir.Kotal@Sun.COM 	{
785*7526SVladimir.Kotal@Sun.COM 	int type;
786*7526SVladimir.Kotal@Sun.COM 
787*7526SVladimir.Kotal@Sun.COM #ifndef OPENSSL_NO_RSA
788*7526SVladimir.Kotal@Sun.COM 	find_lock[OP_RSA] = OPENSSL_malloc(sizeof (pthread_mutex_t));
789*7526SVladimir.Kotal@Sun.COM 	if (find_lock[OP_RSA] == NULL)
790*7526SVladimir.Kotal@Sun.COM 		goto malloc_err;
791*7526SVladimir.Kotal@Sun.COM 	(void) pthread_mutex_init(find_lock[OP_RSA], NULL);
792*7526SVladimir.Kotal@Sun.COM #endif /* OPENSSL_NO_RSA */
793*7526SVladimir.Kotal@Sun.COM 
794*7526SVladimir.Kotal@Sun.COM #ifndef OPENSSL_NO_DSA
795*7526SVladimir.Kotal@Sun.COM 	find_lock[OP_DSA] = OPENSSL_malloc(sizeof (pthread_mutex_t));
796*7526SVladimir.Kotal@Sun.COM 	if (find_lock[OP_DSA] == NULL)
797*7526SVladimir.Kotal@Sun.COM 		goto malloc_err;
798*7526SVladimir.Kotal@Sun.COM 	(void) pthread_mutex_init(find_lock[OP_DSA], NULL);
799*7526SVladimir.Kotal@Sun.COM #endif /* OPENSSL_NO_DSA */
800*7526SVladimir.Kotal@Sun.COM 
801*7526SVladimir.Kotal@Sun.COM #ifndef OPENSSL_NO_DH
802*7526SVladimir.Kotal@Sun.COM 	find_lock[OP_DH] = OPENSSL_malloc(sizeof (pthread_mutex_t));
803*7526SVladimir.Kotal@Sun.COM 	if (find_lock[OP_DH] == NULL)
804*7526SVladimir.Kotal@Sun.COM 		goto malloc_err;
805*7526SVladimir.Kotal@Sun.COM 	(void) pthread_mutex_init(find_lock[OP_DH], NULL);
806*7526SVladimir.Kotal@Sun.COM #endif /* OPENSSL_NO_DH */
807*7526SVladimir.Kotal@Sun.COM 
808*7526SVladimir.Kotal@Sun.COM 	for (type = 0; type < OP_MAX; type++)
809*7526SVladimir.Kotal@Sun.COM 		{
810*7526SVladimir.Kotal@Sun.COM 		session_cache[type].lock =
811*7526SVladimir.Kotal@Sun.COM 		    OPENSSL_malloc(sizeof (pthread_mutex_t));
812*7526SVladimir.Kotal@Sun.COM 		if (session_cache[type].lock == NULL)
813*7526SVladimir.Kotal@Sun.COM 			goto malloc_err;
814*7526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_init(session_cache[type].lock, NULL);
815*7526SVladimir.Kotal@Sun.COM 		}
816*7526SVladimir.Kotal@Sun.COM 
817*7526SVladimir.Kotal@Sun.COM 	return (1);
818*7526SVladimir.Kotal@Sun.COM 
819*7526SVladimir.Kotal@Sun.COM malloc_err:
820*7526SVladimir.Kotal@Sun.COM 	pk11_free_all_locks();
821*7526SVladimir.Kotal@Sun.COM 	PK11err(PK11_F_INIT_ALL_LOCKS, PK11_R_MALLOC_FAILURE);
822*7526SVladimir.Kotal@Sun.COM 	return (0);
823*7526SVladimir.Kotal@Sun.COM 	}
824*7526SVladimir.Kotal@Sun.COM 
825*7526SVladimir.Kotal@Sun.COM static void pk11_free_all_locks(void)
826*7526SVladimir.Kotal@Sun.COM 	{
827*7526SVladimir.Kotal@Sun.COM 	int type;
828*7526SVladimir.Kotal@Sun.COM 
829*7526SVladimir.Kotal@Sun.COM #ifndef OPENSSL_NO_RSA
830*7526SVladimir.Kotal@Sun.COM 	if (find_lock[OP_RSA] != NULL)
831*7526SVladimir.Kotal@Sun.COM 		{
832*7526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_destroy(find_lock[OP_RSA]);
833*7526SVladimir.Kotal@Sun.COM 		OPENSSL_free(find_lock[OP_RSA]);
834*7526SVladimir.Kotal@Sun.COM 		find_lock[OP_RSA] = NULL;
835*7526SVladimir.Kotal@Sun.COM 		}
836*7526SVladimir.Kotal@Sun.COM #endif /* OPENSSL_NO_RSA */
837*7526SVladimir.Kotal@Sun.COM #ifndef OPENSSL_NO_DSA
838*7526SVladimir.Kotal@Sun.COM 	if (find_lock[OP_DSA] != NULL)
839*7526SVladimir.Kotal@Sun.COM 		{
840*7526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_destroy(find_lock[OP_DSA]);
841*7526SVladimir.Kotal@Sun.COM 		OPENSSL_free(find_lock[OP_DSA]);
842*7526SVladimir.Kotal@Sun.COM 		find_lock[OP_DSA] = NULL;
843*7526SVladimir.Kotal@Sun.COM 		}
844*7526SVladimir.Kotal@Sun.COM #endif /* OPENSSL_NO_DSA */
845*7526SVladimir.Kotal@Sun.COM #ifndef OPENSSL_NO_DH
846*7526SVladimir.Kotal@Sun.COM 	if (find_lock[OP_DH] != NULL)
847*7526SVladimir.Kotal@Sun.COM 		{
848*7526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_destroy(find_lock[OP_DH]);
849*7526SVladimir.Kotal@Sun.COM 		OPENSSL_free(find_lock[OP_DH]);
850*7526SVladimir.Kotal@Sun.COM 		find_lock[OP_DH] = NULL;
851*7526SVladimir.Kotal@Sun.COM 		}
852*7526SVladimir.Kotal@Sun.COM #endif /* OPENSSL_NO_DH */
853*7526SVladimir.Kotal@Sun.COM 
854*7526SVladimir.Kotal@Sun.COM 	for (type = 0; type < OP_MAX; type++)
855*7526SVladimir.Kotal@Sun.COM 		{
856*7526SVladimir.Kotal@Sun.COM 		if (session_cache[type].lock != NULL)
857*7526SVladimir.Kotal@Sun.COM 			{
858*7526SVladimir.Kotal@Sun.COM 			(void) pthread_mutex_destroy(session_cache[type].lock);
859*7526SVladimir.Kotal@Sun.COM 			OPENSSL_free(session_cache[type].lock);
860*7526SVladimir.Kotal@Sun.COM 			session_cache[type].lock = NULL;
861*7526SVladimir.Kotal@Sun.COM 			}
862*7526SVladimir.Kotal@Sun.COM 		}
863*7526SVladimir.Kotal@Sun.COM 	}
864*7526SVladimir.Kotal@Sun.COM 
8650Sstevel@tonic-gate /*
8660Sstevel@tonic-gate  * This internal function is used by ENGINE_pk11() and "dynamic" ENGINE support.
8670Sstevel@tonic-gate  */
8680Sstevel@tonic-gate static int bind_pk11(ENGINE *e)
8690Sstevel@tonic-gate 	{
8706847Svk199839 #ifndef OPENSSL_NO_RSA
8710Sstevel@tonic-gate 	const RSA_METHOD *rsa = NULL;
8720Sstevel@tonic-gate 	RSA_METHOD *pk11_rsa = PK11_RSA();
8737211Sjp161948 #endif	/* OPENSSL_NO_RSA */
8740Sstevel@tonic-gate 	if (!pk11_library_initialized)
875*7526SVladimir.Kotal@Sun.COM 		(void) pk11_library_init(e);
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 	if(!ENGINE_set_id(e, engine_pk11_id) ||
8780Sstevel@tonic-gate 	   !ENGINE_set_name(e, engine_pk11_name) ||
8790Sstevel@tonic-gate 	   !ENGINE_set_ciphers(e, pk11_engine_ciphers) ||
8800Sstevel@tonic-gate 	   !ENGINE_set_digests(e, pk11_engine_digests))
8810Sstevel@tonic-gate 	   	return 0;
8820Sstevel@tonic-gate #ifndef OPENSSL_NO_RSA
8830Sstevel@tonic-gate 	if(pk11_have_rsa == CK_TRUE)
8840Sstevel@tonic-gate 		{
8850Sstevel@tonic-gate 		if(!ENGINE_set_RSA(e, PK11_RSA()) ||
8860Sstevel@tonic-gate 	           !ENGINE_set_load_privkey_function(e, pk11_load_privkey) ||
8870Sstevel@tonic-gate 	           !ENGINE_set_load_pubkey_function(e, pk11_load_pubkey))
8880Sstevel@tonic-gate 			return 0;
8897211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
8907211Sjp161948 		fprintf(stderr, "%s: registered RSA\n", PK11_DBG);
8917211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
8920Sstevel@tonic-gate 		}
8937211Sjp161948 #endif	/* OPENSSL_NO_RSA */
8940Sstevel@tonic-gate #ifndef OPENSSL_NO_DSA
8950Sstevel@tonic-gate 	if(pk11_have_dsa == CK_TRUE)
8960Sstevel@tonic-gate 		{
8970Sstevel@tonic-gate 	  	if (!ENGINE_set_DSA(e, PK11_DSA()))
8980Sstevel@tonic-gate 			return 0;
8997211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
9007211Sjp161948 		fprintf(stderr, "%s: registered DSA\n", PK11_DBG);
9017211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
9020Sstevel@tonic-gate 	    	}
9037211Sjp161948 #endif	/* OPENSSL_NO_DSA */
9040Sstevel@tonic-gate #ifndef OPENSSL_NO_DH
9050Sstevel@tonic-gate 	if(pk11_have_dh == CK_TRUE)
9060Sstevel@tonic-gate 		{
9070Sstevel@tonic-gate 	  	if (!ENGINE_set_DH(e, PK11_DH()))
9080Sstevel@tonic-gate 			return 0;
9097211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
9107211Sjp161948 		fprintf(stderr, "%s: registered DH\n", PK11_DBG);
9117211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
9120Sstevel@tonic-gate 	    	}
9137211Sjp161948 #endif	/* OPENSSL_NO_DH */
9140Sstevel@tonic-gate 	if(pk11_have_random)
9150Sstevel@tonic-gate 		{
9160Sstevel@tonic-gate 		if(!ENGINE_set_RAND(e, &pk11_random))
9170Sstevel@tonic-gate 			return 0;
9187211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
9197211Sjp161948 		fprintf(stderr, "%s: registered random\n", PK11_DBG);
9207211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
9210Sstevel@tonic-gate 		}
9220Sstevel@tonic-gate 	if(!ENGINE_set_init_function(e, pk11_init) ||
9230Sstevel@tonic-gate 	   !ENGINE_set_destroy_function(e, pk11_destroy) ||
9240Sstevel@tonic-gate 	   !ENGINE_set_finish_function(e, pk11_finish) ||
9250Sstevel@tonic-gate 	   !ENGINE_set_ctrl_function(e, pk11_ctrl) ||
9260Sstevel@tonic-gate 	   !ENGINE_set_cmd_defns(e, pk11_cmd_defns))
9270Sstevel@tonic-gate 		return 0;
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate /* Apache calls OpenSSL function RSA_blinding_on() once during startup
9300Sstevel@tonic-gate  * which in turn calls bn_mod_exp. Since we do not implement bn_mod_exp
9310Sstevel@tonic-gate  * here, we wire it back to the OpenSSL software implementation.
9320Sstevel@tonic-gate  * Since it is used only once, performance is not a concern. */
9330Sstevel@tonic-gate #ifndef OPENSSL_NO_RSA
9340Sstevel@tonic-gate         rsa = RSA_PKCS1_SSLeay();
9350Sstevel@tonic-gate         pk11_rsa->rsa_mod_exp = rsa->rsa_mod_exp;
9360Sstevel@tonic-gate         pk11_rsa->bn_mod_exp = rsa->bn_mod_exp;
9377211Sjp161948 #endif	/* OPENSSL_NO_RSA */
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate 	/* Ensure the pk11 error handling is set up */
9400Sstevel@tonic-gate 	ERR_load_pk11_strings();
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 	return 1;
9430Sstevel@tonic-gate 	}
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate /* Dynamic engine support is disabled at a higher level for Solaris
9460Sstevel@tonic-gate  */
9477211Sjp161948 #ifdef	ENGINE_DYNAMIC_SUPPORT
9480Sstevel@tonic-gate static int bind_helper(ENGINE *e, const char *id)
9490Sstevel@tonic-gate 	{
9500Sstevel@tonic-gate 	if (id && (strcmp(id, engine_pk11_id) != 0))
9510Sstevel@tonic-gate 		return 0;
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 	if (!bind_pk11(e))
9540Sstevel@tonic-gate 		return 0;
9550Sstevel@tonic-gate 
9560Sstevel@tonic-gate 	return 1;
9570Sstevel@tonic-gate 	}
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate IMPLEMENT_DYNAMIC_CHECK_FN()
9600Sstevel@tonic-gate IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate #else
9630Sstevel@tonic-gate static ENGINE *engine_pk11(void)
9640Sstevel@tonic-gate 	{
9650Sstevel@tonic-gate 	ENGINE *ret = ENGINE_new();
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 	if (!ret)
9680Sstevel@tonic-gate 		return NULL;
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate 	if (!bind_pk11(ret))
9710Sstevel@tonic-gate 		{
9720Sstevel@tonic-gate 		ENGINE_free(ret);
9730Sstevel@tonic-gate 		return NULL;
9740Sstevel@tonic-gate 		}
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 	return ret;
9770Sstevel@tonic-gate 	}
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate void ENGINE_load_pk11(void)
9800Sstevel@tonic-gate 	{
9810Sstevel@tonic-gate 	ENGINE *e_pk11 = NULL;
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 	/* Do not use dynamic PKCS#11 library on Solaris due to
9840Sstevel@tonic-gate 	 * security reasons. We will link it in statically
9850Sstevel@tonic-gate 	 */
9860Sstevel@tonic-gate 	/* Attempt to load PKCS#11 library
9870Sstevel@tonic-gate 	 */
9880Sstevel@tonic-gate 	if (!pk11_dso)
9890Sstevel@tonic-gate 		pk11_dso = DSO_load(NULL, get_PK11_LIBNAME(), NULL, 0);
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate 	if (pk11_dso == NULL)
9920Sstevel@tonic-gate 		{
9930Sstevel@tonic-gate 		PK11err(PK11_F_LOAD, PK11_R_DSO_FAILURE);
9940Sstevel@tonic-gate 		return;
9950Sstevel@tonic-gate 		}
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate 	e_pk11 = engine_pk11();
9980Sstevel@tonic-gate 	if (!e_pk11)
9990Sstevel@tonic-gate 		{
10000Sstevel@tonic-gate 		DSO_free(pk11_dso);
10010Sstevel@tonic-gate 		pk11_dso = NULL;
10020Sstevel@tonic-gate 		return;
10030Sstevel@tonic-gate 		}
10040Sstevel@tonic-gate 
10050Sstevel@tonic-gate 	/* At this point, the pk11 shared library is either dynamically
10060Sstevel@tonic-gate 	 * loaded or statically linked in. So, initialize the pk11
10070Sstevel@tonic-gate 	 * library before calling ENGINE_set_default since the latter
10080Sstevel@tonic-gate 	 * needs cipher and digest algorithm information
10090Sstevel@tonic-gate 	 */
10100Sstevel@tonic-gate 	if (!pk11_library_init(e_pk11))
10110Sstevel@tonic-gate 		{
10120Sstevel@tonic-gate 		DSO_free(pk11_dso);
10130Sstevel@tonic-gate 		pk11_dso = NULL;
10140Sstevel@tonic-gate 		ENGINE_free(e_pk11);
10150Sstevel@tonic-gate 		return;
10160Sstevel@tonic-gate 		}
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 	ENGINE_add(e_pk11);
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate 	ENGINE_free(e_pk11);
10210Sstevel@tonic-gate 	ERR_clear_error();
10220Sstevel@tonic-gate 	}
10237211Sjp161948 #endif	/* ENGINE_DYNAMIC_SUPPORT */
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate /* These are the static string constants for the DSO file name and
10260Sstevel@tonic-gate  * the function symbol names to bind to.
10270Sstevel@tonic-gate  */
10280Sstevel@tonic-gate static const char *PK11_LIBNAME = NULL;
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate static const char *get_PK11_LIBNAME(void)
10310Sstevel@tonic-gate 	{
10320Sstevel@tonic-gate 	if (PK11_LIBNAME)
10330Sstevel@tonic-gate 		return PK11_LIBNAME;
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 	return def_PK11_LIBNAME;
10360Sstevel@tonic-gate 	}
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate static void free_PK11_LIBNAME(void)
10390Sstevel@tonic-gate 	{
10400Sstevel@tonic-gate 	if (PK11_LIBNAME)
10410Sstevel@tonic-gate 		OPENSSL_free((void*)PK11_LIBNAME);
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 	PK11_LIBNAME = NULL;
10440Sstevel@tonic-gate 	}
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate static long set_PK11_LIBNAME(const char *name)
10470Sstevel@tonic-gate 	{
10480Sstevel@tonic-gate 	free_PK11_LIBNAME();
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 	return ((PK11_LIBNAME = BUF_strdup(name)) != NULL ? 1 : 0);
10510Sstevel@tonic-gate 	}
10520Sstevel@tonic-gate 
1053*7526SVladimir.Kotal@Sun.COM /* acquire all engine specific mutexes before fork */
1054*7526SVladimir.Kotal@Sun.COM static void pk11_fork_prepare(void)
1055*7526SVladimir.Kotal@Sun.COM 	{
1056*7526SVladimir.Kotal@Sun.COM 	int i;
1057*7526SVladimir.Kotal@Sun.COM 
1058*7526SVladimir.Kotal@Sun.COM 	LOCK_OBJSTORE(OP_RSA);
1059*7526SVladimir.Kotal@Sun.COM 	LOCK_OBJSTORE(OP_DSA);
1060*7526SVladimir.Kotal@Sun.COM 	LOCK_OBJSTORE(OP_DH);
1061*7526SVladimir.Kotal@Sun.COM 	for (i = 0; i < OP_MAX; i++)
1062*7526SVladimir.Kotal@Sun.COM 		{
1063*7526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_lock(session_cache[i].lock);
1064*7526SVladimir.Kotal@Sun.COM 		}
1065*7526SVladimir.Kotal@Sun.COM 	}
1066*7526SVladimir.Kotal@Sun.COM 
1067*7526SVladimir.Kotal@Sun.COM /* release all engine specific mutexes */
1068*7526SVladimir.Kotal@Sun.COM static void pk11_fork_parent(void)
1069*7526SVladimir.Kotal@Sun.COM 	{
1070*7526SVladimir.Kotal@Sun.COM 	int i;
1071*7526SVladimir.Kotal@Sun.COM 
1072*7526SVladimir.Kotal@Sun.COM 	for (i = OP_MAX - 1; i >= 0; i--)
1073*7526SVladimir.Kotal@Sun.COM 		{
1074*7526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_unlock(session_cache[i].lock);
1075*7526SVladimir.Kotal@Sun.COM 		}
1076*7526SVladimir.Kotal@Sun.COM 	UNLOCK_OBJSTORE(OP_DH);
1077*7526SVladimir.Kotal@Sun.COM 	UNLOCK_OBJSTORE(OP_DSA);
1078*7526SVladimir.Kotal@Sun.COM 	UNLOCK_OBJSTORE(OP_RSA);
1079*7526SVladimir.Kotal@Sun.COM 	}
1080*7526SVladimir.Kotal@Sun.COM 
1081*7526SVladimir.Kotal@Sun.COM /*
1082*7526SVladimir.Kotal@Sun.COM  * same situation as in parent - we need to unlock all locks to make them
1083*7526SVladimir.Kotal@Sun.COM  * accessible to all threads.
1084*7526SVladimir.Kotal@Sun.COM  */
1085*7526SVladimir.Kotal@Sun.COM static void pk11_fork_child(void)
1086*7526SVladimir.Kotal@Sun.COM 	{
1087*7526SVladimir.Kotal@Sun.COM 	int i;
1088*7526SVladimir.Kotal@Sun.COM 
1089*7526SVladimir.Kotal@Sun.COM 	for (i = OP_MAX - 1; i >= 0; i--)
1090*7526SVladimir.Kotal@Sun.COM 		{
1091*7526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_unlock(session_cache[i].lock);
1092*7526SVladimir.Kotal@Sun.COM 		}
1093*7526SVladimir.Kotal@Sun.COM 	UNLOCK_OBJSTORE(OP_DH);
1094*7526SVladimir.Kotal@Sun.COM 	UNLOCK_OBJSTORE(OP_DSA);
1095*7526SVladimir.Kotal@Sun.COM 	UNLOCK_OBJSTORE(OP_RSA);
1096*7526SVladimir.Kotal@Sun.COM 	}
1097*7526SVladimir.Kotal@Sun.COM 
10980Sstevel@tonic-gate /* Initialization function for the pk11 engine */
10990Sstevel@tonic-gate static int pk11_init(ENGINE *e)
11000Sstevel@tonic-gate {
11010Sstevel@tonic-gate 	return pk11_library_init(e);
11020Sstevel@tonic-gate }
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate /* Initialization function. Sets up various pk11 library components.
11050Sstevel@tonic-gate  * It selects a slot based on predefined critiera. In the process, it also
11060Sstevel@tonic-gate  * count how many ciphers and digests to support. Since the cipher and
11070Sstevel@tonic-gate  * digest information is needed when setting default engine, this function
11080Sstevel@tonic-gate  * needs to be called before calling ENGINE_set_default.
11090Sstevel@tonic-gate  */
11100Sstevel@tonic-gate static int pk11_library_init(ENGINE *e)
11110Sstevel@tonic-gate 	{
11120Sstevel@tonic-gate 	CK_C_GetFunctionList p;
11130Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
11140Sstevel@tonic-gate 	CK_INFO info;
11150Sstevel@tonic-gate 	CK_ULONG ul_state_len;
11167211Sjp161948 	int any_slot_found;
1117*7526SVladimir.Kotal@Sun.COM 	int i;
11187211Sjp161948 
11197211Sjp161948 	/*
11207211Sjp161948 	 * pk11_library_initialized is set to 0 in pk11_finish() which is called
11217211Sjp161948 	 * from ENGINE_finish(). However, if there is still at least one
11227211Sjp161948 	 * existing functional reference to the engine (see engine(3) for more
11237211Sjp161948 	 * information), pk11_finish() is skipped. For example, this can happen
11247211Sjp161948 	 * if an application forgets to clear one cipher context. In case of a
11257211Sjp161948 	 * fork() when the application is finishing the engine so that it can be
11267211Sjp161948 	 * reinitialized in the child, forgotten functional reference causes
11277211Sjp161948 	 * pk11_library_initialized to stay 1. In that case we need the PID
11287211Sjp161948 	 * check so that we properly initialize the engine again.
11297211Sjp161948 	 */
11300Sstevel@tonic-gate 	if (pk11_library_initialized)
11317211Sjp161948 		{
11327211Sjp161948 		if (pk11_pid == getpid())
1133*7526SVladimir.Kotal@Sun.COM 			{
11347211Sjp161948 			return 1;
1135*7526SVladimir.Kotal@Sun.COM 			}
11367211Sjp161948 		else
1137*7526SVladimir.Kotal@Sun.COM 			{
11387211Sjp161948 			global_session = CK_INVALID_HANDLE;
1139*7526SVladimir.Kotal@Sun.COM 			/*
1140*7526SVladimir.Kotal@Sun.COM 			 * free the locks first to prevent memory leak in case
1141*7526SVladimir.Kotal@Sun.COM 			 * the application calls fork() without finishing the
1142*7526SVladimir.Kotal@Sun.COM 			 * engine first.
1143*7526SVladimir.Kotal@Sun.COM 			 */
1144*7526SVladimir.Kotal@Sun.COM 			pk11_free_all_locks();
1145*7526SVladimir.Kotal@Sun.COM 			}
11467211Sjp161948 		}
11470Sstevel@tonic-gate 
11480Sstevel@tonic-gate 	if (pk11_dso == NULL)
11490Sstevel@tonic-gate 		{
11500Sstevel@tonic-gate 		PK11err(PK11_F_LIBRARY_INIT, PK11_R_DSO_FAILURE);
11510Sstevel@tonic-gate 		goto err;
11520Sstevel@tonic-gate 		}
11530Sstevel@tonic-gate 
11547211Sjp161948 #ifdef	SOLARIS_AES_CTR
11557211Sjp161948 	/*
11567211Sjp161948 	 * We must do this before we start working with slots since we need all
11577211Sjp161948 	 * NIDs there.
11587211Sjp161948 	 */
11597211Sjp161948 	if (pk11_add_aes_ctr_NIDs() == 0)
11607211Sjp161948 		goto err;
11617211Sjp161948 #endif	/* SOLARIS_AES_CTR */
11627211Sjp161948 
11637211Sjp161948 #ifdef	SOLARIS_HW_SLOT_SELECTION
11647211Sjp161948 	if (check_hw_mechanisms() == 0)
11657211Sjp161948 		goto err;
11667211Sjp161948 #endif	/* SOLARIS_HW_SLOT_SELECTION */
11677211Sjp161948 
11680Sstevel@tonic-gate 	/* get the C_GetFunctionList function from the loaded library
11690Sstevel@tonic-gate 	 */
11700Sstevel@tonic-gate 	p = (CK_C_GetFunctionList)DSO_bind_func(pk11_dso,
11710Sstevel@tonic-gate 		PK11_GET_FUNCTION_LIST);
11720Sstevel@tonic-gate 	if ( !p )
11730Sstevel@tonic-gate 		{
11740Sstevel@tonic-gate 		PK11err(PK11_F_LIBRARY_INIT, PK11_R_DSO_FAILURE);
11750Sstevel@tonic-gate 		goto err;
11760Sstevel@tonic-gate 		}
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate 	/* get the full function list from the loaded library
11790Sstevel@tonic-gate 	 */
11800Sstevel@tonic-gate 	rv = p(&pFuncList);
11810Sstevel@tonic-gate 	if (rv != CKR_OK)
11820Sstevel@tonic-gate 		{
11837211Sjp161948 		PK11err_add_data(PK11_F_LIBRARY_INIT, PK11_R_DSO_FAILURE, rv);
11840Sstevel@tonic-gate 		goto err;
11850Sstevel@tonic-gate 		}
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate 	rv = pFuncList->C_Initialize(NULL_PTR);
11880Sstevel@tonic-gate 	if ((rv != CKR_OK) && (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED))
11890Sstevel@tonic-gate 		{
11907211Sjp161948 		PK11err_add_data(PK11_F_LIBRARY_INIT, PK11_R_INITIALIZE, rv);
11910Sstevel@tonic-gate 		goto err;
11920Sstevel@tonic-gate 		}
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 	rv = pFuncList->C_GetInfo(&info);
11950Sstevel@tonic-gate 	if (rv != CKR_OK)
11960Sstevel@tonic-gate 		{
11977211Sjp161948 		PK11err_add_data(PK11_F_LIBRARY_INIT, PK11_R_GETINFO, rv);
11980Sstevel@tonic-gate 		goto err;
11990Sstevel@tonic-gate 		}
12000Sstevel@tonic-gate 
12017211Sjp161948 	if (pk11_choose_slots(&any_slot_found) == 0)
12020Sstevel@tonic-gate 		goto err;
12030Sstevel@tonic-gate 
12047211Sjp161948 	/*
12057211Sjp161948 	 * The library we use, set in def_PK11_LIBNAME, may not offer any
12067211Sjp161948 	 * slot(s). In that case, we must not proceed but we must not return an
12077211Sjp161948 	 * error. The reason is that applications that try to set up the PKCS#11
12087211Sjp161948 	 * engine don't exit on error during the engine initialization just
12097211Sjp161948 	 * because no slot was present.
12107211Sjp161948 	 */
12117211Sjp161948 	if (any_slot_found == 0)
12127211Sjp161948 		return 1;
12137211Sjp161948 
12140Sstevel@tonic-gate 	if (global_session == CK_INVALID_HANDLE)
12150Sstevel@tonic-gate 		{
12160Sstevel@tonic-gate 		/* Open the global_session for the new process */
12170Sstevel@tonic-gate 		rv = pFuncList->C_OpenSession(SLOTID, CKF_SERIAL_SESSION,
12180Sstevel@tonic-gate 			NULL_PTR, NULL_PTR, &global_session);
12190Sstevel@tonic-gate 		if (rv != CKR_OK)
12200Sstevel@tonic-gate 			{
12217211Sjp161948 			PK11err_add_data(PK11_F_LIBRARY_INIT,
12227211Sjp161948 			    PK11_R_OPENSESSION, rv);
12230Sstevel@tonic-gate 			goto err;
12240Sstevel@tonic-gate 			}
12250Sstevel@tonic-gate 		}
12260Sstevel@tonic-gate 
12270Sstevel@tonic-gate 	/* Disable digest if C_GetOperationState is not supported since
12280Sstevel@tonic-gate 	 * this function is required by OpenSSL digest copy function */
12290Sstevel@tonic-gate 	if (pFuncList->C_GetOperationState(global_session, NULL, &ul_state_len)
12307211Sjp161948 			== CKR_FUNCTION_NOT_SUPPORTED) {
12317211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
12327211Sjp161948 		fprintf(stderr, "%s: C_GetOperationState() not supported, "
12337211Sjp161948 		    "setting digest_count to 0\n", PK11_DBG);
12347211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
12350Sstevel@tonic-gate 		digest_count = 0;
12367211Sjp161948 	}
12370Sstevel@tonic-gate 
1238*7526SVladimir.Kotal@Sun.COM 	pk11_library_initialized = TRUE;
12397211Sjp161948 	pk11_pid = getpid();
1240*7526SVladimir.Kotal@Sun.COM 	/*
1241*7526SVladimir.Kotal@Sun.COM 	 * if initialization of the locks fails pk11_init_all_locks()
1242*7526SVladimir.Kotal@Sun.COM 	 * will do the cleanup.
1243*7526SVladimir.Kotal@Sun.COM 	 */
1244*7526SVladimir.Kotal@Sun.COM 	if (!pk11_init_all_locks())
1245*7526SVladimir.Kotal@Sun.COM 		goto err;
1246*7526SVladimir.Kotal@Sun.COM 	for (i = 0; i < OP_MAX; i++)
1247*7526SVladimir.Kotal@Sun.COM 		session_cache[i].head = NULL;
1248*7526SVladimir.Kotal@Sun.COM 	/*
1249*7526SVladimir.Kotal@Sun.COM 	 * initialize active lists. We only use active lists
1250*7526SVladimir.Kotal@Sun.COM 	 * for asymmetric ciphers.
1251*7526SVladimir.Kotal@Sun.COM 	 */
1252*7526SVladimir.Kotal@Sun.COM 	for (i = 0; i < OP_MAX; i++)
1253*7526SVladimir.Kotal@Sun.COM 		active_list[i] = NULL;
1254*7526SVladimir.Kotal@Sun.COM 
1255*7526SVladimir.Kotal@Sun.COM 	if (!pk11_atfork_initialized)
1256*7526SVladimir.Kotal@Sun.COM 		{
1257*7526SVladimir.Kotal@Sun.COM 		if (pthread_atfork(pk11_fork_prepare, pk11_fork_parent,
1258*7526SVladimir.Kotal@Sun.COM 		    pk11_fork_child) != 0)
1259*7526SVladimir.Kotal@Sun.COM 			{
1260*7526SVladimir.Kotal@Sun.COM 			PK11err(PK11_F_LIBRARY_INIT, PK11_R_ATFORK_FAILED);
1261*7526SVladimir.Kotal@Sun.COM 			goto err;
1262*7526SVladimir.Kotal@Sun.COM 			}
1263*7526SVladimir.Kotal@Sun.COM 		pk11_atfork_initialized = TRUE;
1264*7526SVladimir.Kotal@Sun.COM 		}
1265*7526SVladimir.Kotal@Sun.COM 
12660Sstevel@tonic-gate 	return 1;
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate err:
12690Sstevel@tonic-gate 	return 0;
12700Sstevel@tonic-gate 	}
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate /* Destructor (complements the "ENGINE_pk11()" constructor)
12730Sstevel@tonic-gate  */
12740Sstevel@tonic-gate static int pk11_destroy(ENGINE *e)
12750Sstevel@tonic-gate 	{
12760Sstevel@tonic-gate 	free_PK11_LIBNAME();
12770Sstevel@tonic-gate 	ERR_unload_pk11_strings();
12780Sstevel@tonic-gate 	return 1;
12790Sstevel@tonic-gate 	}
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate /* Termination function to clean up the session, the token, and
12820Sstevel@tonic-gate  * the pk11 library.
12830Sstevel@tonic-gate  */
12840Sstevel@tonic-gate static int pk11_finish(ENGINE *e)
12850Sstevel@tonic-gate 	{
1286*7526SVladimir.Kotal@Sun.COM 	int i;
1287*7526SVladimir.Kotal@Sun.COM 
12880Sstevel@tonic-gate 	if (pk11_dso == NULL)
12890Sstevel@tonic-gate 		{
12900Sstevel@tonic-gate 		PK11err(PK11_F_FINISH, PK11_R_NOT_LOADED);
12910Sstevel@tonic-gate 		goto err;
12920Sstevel@tonic-gate 		}
12930Sstevel@tonic-gate 
12946847Svk199839 	OPENSSL_assert(pFuncList != NULL);
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate 	if (pk11_free_all_sessions() == 0)
12970Sstevel@tonic-gate 		goto err;
12980Sstevel@tonic-gate 
1299*7526SVladimir.Kotal@Sun.COM 	/* free all active lists */
1300*7526SVladimir.Kotal@Sun.COM 	for (i = 0; i < OP_MAX; i++)
1301*7526SVladimir.Kotal@Sun.COM 		pk11_free_active_list(i);
1302*7526SVladimir.Kotal@Sun.COM 
13030Sstevel@tonic-gate 	pFuncList->C_CloseSession(global_session);
13047211Sjp161948 	global_session = CK_INVALID_HANDLE;
13057211Sjp161948 
13067211Sjp161948 	/*
13077211Sjp161948 	 * Since we are part of a library (libcrypto.so), calling this function
13087211Sjp161948 	 * may have side-effects.
13097211Sjp161948 	 */
13107211Sjp161948 #if 0
13110Sstevel@tonic-gate 	pFuncList->C_Finalize(NULL);
13127211Sjp161948 #endif
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate 	if (!DSO_free(pk11_dso))
13150Sstevel@tonic-gate 		{
13160Sstevel@tonic-gate 		PK11err(PK11_F_FINISH, PK11_R_DSO_FAILURE);
13170Sstevel@tonic-gate 		goto err;
13180Sstevel@tonic-gate 		}
13190Sstevel@tonic-gate 	pk11_dso = NULL;
13200Sstevel@tonic-gate 	pFuncList = NULL;
1321*7526SVladimir.Kotal@Sun.COM 	pk11_library_initialized = FALSE;
13227211Sjp161948 	pk11_pid = 0;
1323*7526SVladimir.Kotal@Sun.COM 	pk11_free_all_locks();
13240Sstevel@tonic-gate 
13250Sstevel@tonic-gate 	return 1;
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate err:
13280Sstevel@tonic-gate 	return 0;
13290Sstevel@tonic-gate 	}
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate /* Standard engine interface function to set the dynamic library path */
13320Sstevel@tonic-gate static int pk11_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)())
13330Sstevel@tonic-gate 	{
13340Sstevel@tonic-gate 	int initialized = ((pk11_dso == NULL) ? 0 : 1);
13350Sstevel@tonic-gate 
13360Sstevel@tonic-gate 	switch(cmd)
13370Sstevel@tonic-gate 		{
13380Sstevel@tonic-gate 	case PK11_CMD_SO_PATH:
13390Sstevel@tonic-gate 		if (p == NULL)
13400Sstevel@tonic-gate 			{
13410Sstevel@tonic-gate 			PK11err(PK11_F_CTRL, ERR_R_PASSED_NULL_PARAMETER);
13420Sstevel@tonic-gate 			return 0;
13430Sstevel@tonic-gate 			}
13440Sstevel@tonic-gate 
13450Sstevel@tonic-gate 		if (initialized)
13460Sstevel@tonic-gate 			{
13470Sstevel@tonic-gate 			PK11err(PK11_F_CTRL, PK11_R_ALREADY_LOADED);
13480Sstevel@tonic-gate 			return 0;
13490Sstevel@tonic-gate 			}
13500Sstevel@tonic-gate 
13510Sstevel@tonic-gate 		return set_PK11_LIBNAME((const char*)p);
13520Sstevel@tonic-gate 	default:
13530Sstevel@tonic-gate 		break;
13540Sstevel@tonic-gate 		}
13550Sstevel@tonic-gate 
13560Sstevel@tonic-gate 	PK11err(PK11_F_CTRL,PK11_R_CTRL_COMMAND_NOT_IMPLEMENTED);
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 	return 0;
13590Sstevel@tonic-gate 	}
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate /* Required function by the engine random interface. It does nothing here
13630Sstevel@tonic-gate  */
13640Sstevel@tonic-gate static void pk11_rand_cleanup(void)
13650Sstevel@tonic-gate 	{
13660Sstevel@tonic-gate 	return;
13670Sstevel@tonic-gate 	}
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate static void pk11_rand_add(const void *buf, int num, double add)
13700Sstevel@tonic-gate 	{
13710Sstevel@tonic-gate 	PK11_SESSION *sp;
13720Sstevel@tonic-gate 
13737211Sjp161948 	if ((sp = pk11_get_session(OP_RAND)) == NULL)
13740Sstevel@tonic-gate 		return;
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 	/* Ignore any errors (e.g. CKR_RANDOM_SEED_NOT_SUPPORTED) since
13770Sstevel@tonic-gate 	 * the calling functions do not care anyway
13780Sstevel@tonic-gate 	 */
13790Sstevel@tonic-gate 	pFuncList->C_SeedRandom(sp->session, (unsigned char *) buf, num);
13807211Sjp161948 	pk11_return_session(sp, OP_RAND);
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate 	return;
13830Sstevel@tonic-gate 	}
13840Sstevel@tonic-gate 
13850Sstevel@tonic-gate static void pk11_rand_seed(const void *buf, int num)
13860Sstevel@tonic-gate 	{
13870Sstevel@tonic-gate 	pk11_rand_add(buf, num, 0);
13880Sstevel@tonic-gate 	}
13890Sstevel@tonic-gate 
13900Sstevel@tonic-gate static int pk11_rand_bytes(unsigned char *buf, int num)
13910Sstevel@tonic-gate 	{
13920Sstevel@tonic-gate 	CK_RV rv;
13930Sstevel@tonic-gate 	PK11_SESSION *sp;
13940Sstevel@tonic-gate 
13957211Sjp161948 	if ((sp = pk11_get_session(OP_RAND)) == NULL)
13960Sstevel@tonic-gate 		return 0;
13970Sstevel@tonic-gate 
13980Sstevel@tonic-gate 	rv = pFuncList->C_GenerateRandom(sp->session, buf, num);
13990Sstevel@tonic-gate 	if (rv != CKR_OK)
14000Sstevel@tonic-gate 		{
14017211Sjp161948 		PK11err_add_data(PK11_F_RAND_BYTES, PK11_R_GENERATERANDOM, rv);
14027211Sjp161948 		pk11_return_session(sp, OP_RAND);
14030Sstevel@tonic-gate 		return 0;
14040Sstevel@tonic-gate 		}
14050Sstevel@tonic-gate 
14067211Sjp161948 	pk11_return_session(sp, OP_RAND);
14070Sstevel@tonic-gate 	return 1;
14080Sstevel@tonic-gate 	}
14090Sstevel@tonic-gate 
14100Sstevel@tonic-gate /* Required function by the engine random interface. It does nothing here
14110Sstevel@tonic-gate  */
14120Sstevel@tonic-gate static int pk11_rand_status(void)
14130Sstevel@tonic-gate 	{
14140Sstevel@tonic-gate 	return 1;
14150Sstevel@tonic-gate 	}
14160Sstevel@tonic-gate 
14176847Svk199839 /*
14186847Svk199839  * Free all BIGNUM structures from PK11_SESSION.
14196847Svk199839  */
1420*7526SVladimir.Kotal@Sun.COM static void pk11_free_nums(PK11_SESSION *sp, PK11_OPTYPE optype)
14216847Svk199839 	{
1422*7526SVladimir.Kotal@Sun.COM 	switch (optype)
1423*7526SVladimir.Kotal@Sun.COM 		{
14246847Svk199839 #ifndef	OPENSSL_NO_RSA
1425*7526SVladimir.Kotal@Sun.COM 		case OP_RSA:
1426*7526SVladimir.Kotal@Sun.COM 			if (sp->opdata_rsa_n_num != NULL)
1427*7526SVladimir.Kotal@Sun.COM 				{
1428*7526SVladimir.Kotal@Sun.COM 				BN_free(sp->opdata_rsa_n_num);
1429*7526SVladimir.Kotal@Sun.COM 				sp->opdata_rsa_n_num = NULL;
1430*7526SVladimir.Kotal@Sun.COM 				}
1431*7526SVladimir.Kotal@Sun.COM 			if (sp->opdata_rsa_e_num != NULL)
1432*7526SVladimir.Kotal@Sun.COM 				{
1433*7526SVladimir.Kotal@Sun.COM 				BN_free(sp->opdata_rsa_e_num);
1434*7526SVladimir.Kotal@Sun.COM 				sp->opdata_rsa_e_num = NULL;
1435*7526SVladimir.Kotal@Sun.COM 				}
1436*7526SVladimir.Kotal@Sun.COM 			if (sp->opdata_rsa_d_num != NULL)
1437*7526SVladimir.Kotal@Sun.COM 				{
1438*7526SVladimir.Kotal@Sun.COM 				BN_free(sp->opdata_rsa_d_num);
1439*7526SVladimir.Kotal@Sun.COM 				sp->opdata_rsa_d_num = NULL;
1440*7526SVladimir.Kotal@Sun.COM 				}
1441*7526SVladimir.Kotal@Sun.COM 			break;
14426847Svk199839 #endif
14436847Svk199839 #ifndef	OPENSSL_NO_DSA
1444*7526SVladimir.Kotal@Sun.COM 		case OP_DSA:
1445*7526SVladimir.Kotal@Sun.COM 			if (sp->opdata_dsa_pub_num != NULL)
1446*7526SVladimir.Kotal@Sun.COM 				{
1447*7526SVladimir.Kotal@Sun.COM 				BN_free(sp->opdata_dsa_pub_num);
1448*7526SVladimir.Kotal@Sun.COM 				sp->opdata_dsa_pub_num = NULL;
1449*7526SVladimir.Kotal@Sun.COM 				}
1450*7526SVladimir.Kotal@Sun.COM 			if (sp->opdata_dsa_priv_num != NULL)
1451*7526SVladimir.Kotal@Sun.COM 				{
1452*7526SVladimir.Kotal@Sun.COM 				BN_free(sp->opdata_dsa_priv_num);
1453*7526SVladimir.Kotal@Sun.COM 				sp->opdata_dsa_priv_num = NULL;
1454*7526SVladimir.Kotal@Sun.COM 				}
1455*7526SVladimir.Kotal@Sun.COM 			break;
14566847Svk199839 #endif
14576847Svk199839 #ifndef	OPENSSL_NO_DH
1458*7526SVladimir.Kotal@Sun.COM 		case OP_DH:
1459*7526SVladimir.Kotal@Sun.COM 			if (sp->opdata_dh_priv_num != NULL)
1460*7526SVladimir.Kotal@Sun.COM 				{
1461*7526SVladimir.Kotal@Sun.COM 				BN_free(sp->opdata_dh_priv_num);
1462*7526SVladimir.Kotal@Sun.COM 				sp->opdata_dh_priv_num = NULL;
1463*7526SVladimir.Kotal@Sun.COM 				}
1464*7526SVladimir.Kotal@Sun.COM 			break;
14656847Svk199839 #endif
1466*7526SVladimir.Kotal@Sun.COM 		default:
1467*7526SVladimir.Kotal@Sun.COM 			break;
1468*7526SVladimir.Kotal@Sun.COM 		}
14696847Svk199839 	}
14700Sstevel@tonic-gate 
14716847Svk199839 /*
14726847Svk199839  * Get new PK11_SESSION structure ready for use. Every process must have
14736847Svk199839  * its own freelist of PK11_SESSION structures so handle fork() here
14746847Svk199839  * by destroying the old and creating new freelist.
14756847Svk199839  * The returned PK11_SESSION structure is disconnected from the freelist.
14766847Svk199839  */
14777211Sjp161948 PK11_SESSION *pk11_get_session(PK11_OPTYPE optype)
14780Sstevel@tonic-gate 	{
1479*7526SVladimir.Kotal@Sun.COM 	PK11_SESSION *sp = NULL, *sp1, *freelist;
1480*7526SVladimir.Kotal@Sun.COM 	pthread_mutex_t *freelist_lock;
14810Sstevel@tonic-gate 	CK_RV rv;
14820Sstevel@tonic-gate 
14837211Sjp161948 	switch (optype)
14847211Sjp161948 		{
1485*7526SVladimir.Kotal@Sun.COM 		case OP_RSA:
1486*7526SVladimir.Kotal@Sun.COM 		case OP_DSA:
1487*7526SVladimir.Kotal@Sun.COM 		case OP_DH:
14887211Sjp161948 		case OP_RAND:
14897211Sjp161948 		case OP_DIGEST:
14907211Sjp161948 		case OP_CIPHER:
1491*7526SVladimir.Kotal@Sun.COM 			freelist_lock = session_cache[optype].lock;
14927211Sjp161948 			break;
14937211Sjp161948 		default:
14947211Sjp161948 			PK11err(PK11_F_GET_SESSION,
14957211Sjp161948 				PK11_R_INVALID_OPERATION_TYPE);
1496*7526SVladimir.Kotal@Sun.COM 			return (NULL);
14977211Sjp161948 		}
1498*7526SVladimir.Kotal@Sun.COM 	(void) pthread_mutex_lock(freelist_lock);
1499*7526SVladimir.Kotal@Sun.COM 	freelist = session_cache[optype].head;
15007211Sjp161948 	sp = freelist;
15017211Sjp161948 
15026847Svk199839 	/*
15036847Svk199839 	 * If the free list is empty, allocate new unitialized (filled
15046847Svk199839 	 * with zeroes) PK11_SESSION structure otherwise return first
15056847Svk199839 	 * structure from the freelist.
15066847Svk199839 	 */
15077211Sjp161948 	if (sp == NULL)
15080Sstevel@tonic-gate 		{
15090Sstevel@tonic-gate 		if ((sp = OPENSSL_malloc(sizeof(PK11_SESSION))) == NULL)
15100Sstevel@tonic-gate 			{
15110Sstevel@tonic-gate 			PK11err(PK11_F_GET_SESSION,
15120Sstevel@tonic-gate 				PK11_R_MALLOC_FAILURE);
15130Sstevel@tonic-gate 			goto err;
15140Sstevel@tonic-gate 			}
15150Sstevel@tonic-gate 		memset(sp, 0, sizeof(PK11_SESSION));
15160Sstevel@tonic-gate 		}
15170Sstevel@tonic-gate 	else
15180Sstevel@tonic-gate 		{
15197211Sjp161948 		freelist = sp->next;
15200Sstevel@tonic-gate 		}
15210Sstevel@tonic-gate 
15220Sstevel@tonic-gate 	if (sp->pid != 0 && sp->pid != getpid())
15230Sstevel@tonic-gate 		{
15246847Svk199839 		/*
15256847Svk199839 		 * We are a new process and thus need to free any inherited
15260Sstevel@tonic-gate 		 * PK11_SESSION objects.
15270Sstevel@tonic-gate 		 */
15287211Sjp161948 		while ((sp1 = freelist) != NULL)
15290Sstevel@tonic-gate 			{
15307211Sjp161948 			freelist = sp1->next;
15316847Svk199839 			/*
15327211Sjp161948 			 * NOTE: we do not want to call pk11_free_all_sessions()
15337211Sjp161948 			 * here because it would close underlying PKCS#11
15347211Sjp161948 			 * sessions and destroy all objects.
15356847Svk199839 			 */
1536*7526SVladimir.Kotal@Sun.COM 			pk11_free_nums(sp1, optype);
15370Sstevel@tonic-gate 			OPENSSL_free(sp1);
15380Sstevel@tonic-gate 			}
15390Sstevel@tonic-gate 
1540*7526SVladimir.Kotal@Sun.COM 		/* we have to free the active list as well. */
1541*7526SVladimir.Kotal@Sun.COM 		pk11_free_active_list(optype);
1542*7526SVladimir.Kotal@Sun.COM 
15430Sstevel@tonic-gate 		/* Initialize the process */
15440Sstevel@tonic-gate 		rv = pFuncList->C_Initialize(NULL_PTR);
15450Sstevel@tonic-gate 		if ((rv != CKR_OK) && (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED))
15460Sstevel@tonic-gate 			{
15477211Sjp161948 			PK11err_add_data(PK11_F_GET_SESSION, PK11_R_INITIALIZE,
15487211Sjp161948 			    rv);
15490Sstevel@tonic-gate 			OPENSSL_free(sp);
15500Sstevel@tonic-gate 			sp = NULL;
15510Sstevel@tonic-gate 			goto err;
15520Sstevel@tonic-gate 			}
15530Sstevel@tonic-gate 
15546847Svk199839 		/*
15557211Sjp161948 		 * Choose slot here since the slot table is different on this
15567211Sjp161948 		 * process. If we are here then we must have found at least one
15577211Sjp161948 		 * usable slot before so we don't need to check any_slot_found.
15587211Sjp161948 		 * See pk11_library_init()'s usage of this function for more
15597211Sjp161948 		 * information.
15600Sstevel@tonic-gate 		 */
15617211Sjp161948 #ifdef	SOLARIS_HW_SLOT_SELECTION
15627211Sjp161948 		if (check_hw_mechanisms() == 0)
15637211Sjp161948 			goto err;
15647211Sjp161948 #endif	/* SOLARIS_HW_SLOT_SELECTION */
15657211Sjp161948 		if (pk11_choose_slots(NULL) == 0)
15660Sstevel@tonic-gate 			goto err;
15670Sstevel@tonic-gate 
15680Sstevel@tonic-gate 		/* Open the global_session for the new process */
15690Sstevel@tonic-gate 		rv = pFuncList->C_OpenSession(SLOTID, CKF_SERIAL_SESSION,
15700Sstevel@tonic-gate 			NULL_PTR, NULL_PTR, &global_session);
15710Sstevel@tonic-gate 		if (rv != CKR_OK)
15720Sstevel@tonic-gate 			{
15737211Sjp161948 			PK11err_add_data(PK11_F_GET_SESSION, PK11_R_OPENSESSION,
15747211Sjp161948 			    rv);
15750Sstevel@tonic-gate 			OPENSSL_free(sp);
15760Sstevel@tonic-gate 			sp = NULL;
15770Sstevel@tonic-gate 			goto err;
15780Sstevel@tonic-gate 			}
15790Sstevel@tonic-gate 
15800Sstevel@tonic-gate 		/* It is an inherited session and needs re-initialization.
15810Sstevel@tonic-gate 		 */
15827211Sjp161948 		if (pk11_setup_session(sp, optype) == 0)
15830Sstevel@tonic-gate 			{
15840Sstevel@tonic-gate 			OPENSSL_free(sp);
15850Sstevel@tonic-gate 			sp = NULL;
15860Sstevel@tonic-gate 			}
15870Sstevel@tonic-gate 		}
15880Sstevel@tonic-gate 	else if (sp->pid == 0)
15890Sstevel@tonic-gate 		{
15907211Sjp161948 		/* It is a new session and needs initialization. */
15917211Sjp161948 		if (pk11_setup_session(sp, optype) == 0)
15920Sstevel@tonic-gate 			{
15930Sstevel@tonic-gate 			OPENSSL_free(sp);
15940Sstevel@tonic-gate 			sp = NULL;
15950Sstevel@tonic-gate 			}
15960Sstevel@tonic-gate 		}
15970Sstevel@tonic-gate 
1598*7526SVladimir.Kotal@Sun.COM 	/* set new head for the list of PK11_SESSION objects */
1599*7526SVladimir.Kotal@Sun.COM 	session_cache[optype].head = freelist;
16007211Sjp161948 
16010Sstevel@tonic-gate err:
16026847Svk199839 	if (sp != NULL)
16030Sstevel@tonic-gate 		sp->next = NULL;
16040Sstevel@tonic-gate 
1605*7526SVladimir.Kotal@Sun.COM 	(void) pthread_mutex_unlock(freelist_lock);
16060Sstevel@tonic-gate 
16070Sstevel@tonic-gate 	return sp;
16080Sstevel@tonic-gate 	}
16090Sstevel@tonic-gate 
16100Sstevel@tonic-gate 
16117211Sjp161948 void pk11_return_session(PK11_SESSION *sp, PK11_OPTYPE optype)
16120Sstevel@tonic-gate 	{
1613*7526SVladimir.Kotal@Sun.COM 	pthread_mutex_t *freelist_lock;
1614*7526SVladimir.Kotal@Sun.COM 	PK11_SESSION *freelist;
1615*7526SVladimir.Kotal@Sun.COM 
16160Sstevel@tonic-gate 	if (sp == NULL || sp->pid != getpid())
16170Sstevel@tonic-gate 		return;
16180Sstevel@tonic-gate 
16197211Sjp161948 	switch (optype)
16207211Sjp161948 		{
1621*7526SVladimir.Kotal@Sun.COM 		case OP_RSA:
1622*7526SVladimir.Kotal@Sun.COM 		case OP_DSA:
1623*7526SVladimir.Kotal@Sun.COM 		case OP_DH:
16247211Sjp161948 		case OP_RAND:
16257211Sjp161948 		case OP_DIGEST:
16267211Sjp161948 		case OP_CIPHER:
1627*7526SVladimir.Kotal@Sun.COM 			freelist_lock = session_cache[optype].lock;
16287211Sjp161948 			break;
1629*7526SVladimir.Kotal@Sun.COM 		default:
1630*7526SVladimir.Kotal@Sun.COM 			PK11err(PK11_F_RETURN_SESSION,
1631*7526SVladimir.Kotal@Sun.COM 				PK11_R_INVALID_OPERATION_TYPE);
1632*7526SVladimir.Kotal@Sun.COM 			return;
16337211Sjp161948 		}
16340Sstevel@tonic-gate 
1635*7526SVladimir.Kotal@Sun.COM 	(void) pthread_mutex_lock(freelist_lock);
1636*7526SVladimir.Kotal@Sun.COM 	freelist = session_cache[optype].head;
1637*7526SVladimir.Kotal@Sun.COM 	sp->next = freelist;
1638*7526SVladimir.Kotal@Sun.COM 	session_cache[optype].head = sp;
1639*7526SVladimir.Kotal@Sun.COM 	(void) pthread_mutex_unlock(freelist_lock);
16400Sstevel@tonic-gate 	}
16410Sstevel@tonic-gate 
16420Sstevel@tonic-gate 
16430Sstevel@tonic-gate /* Destroy all objects. This function is called when the engine is finished
16440Sstevel@tonic-gate  */
16450Sstevel@tonic-gate static int pk11_free_all_sessions()
16460Sstevel@tonic-gate 	{
16477211Sjp161948 	int ret = 1;
1648*7526SVladimir.Kotal@Sun.COM 	int type;
16490Sstevel@tonic-gate 
16506847Svk199839 #ifndef OPENSSL_NO_RSA
16516847Svk199839 	(void) pk11_destroy_rsa_key_objects(NULL);
16527211Sjp161948 #endif	/* OPENSSL_NO_RSA */
16536847Svk199839 #ifndef OPENSSL_NO_DSA
16546847Svk199839 	(void) pk11_destroy_dsa_key_objects(NULL);
16557211Sjp161948 #endif	/* OPENSSL_NO_DSA */
16566847Svk199839 #ifndef OPENSSL_NO_DH
16576847Svk199839 	(void) pk11_destroy_dh_key_objects(NULL);
16587211Sjp161948 #endif	/* OPENSSL_NO_DH */
16596847Svk199839 	(void) pk11_destroy_cipher_key_objects(NULL);
16607211Sjp161948 
16617211Sjp161948 	/*
16627211Sjp161948 	 * We try to release as much as we can but any error means that we will
16637211Sjp161948 	 * return 0 on exit.
16647211Sjp161948 	 */
1665*7526SVladimir.Kotal@Sun.COM 	for (type = 0; type < OP_MAX; type++)
1666*7526SVladimir.Kotal@Sun.COM 		{
1667*7526SVladimir.Kotal@Sun.COM 		if (pk11_free_session_list(type) == 0)
1668*7526SVladimir.Kotal@Sun.COM 			ret = 0;
1669*7526SVladimir.Kotal@Sun.COM 		}
16707211Sjp161948 
16717211Sjp161948 	return ret;
16727211Sjp161948 	}
16730Sstevel@tonic-gate 
16747211Sjp161948 /*
1675*7526SVladimir.Kotal@Sun.COM  * Destroy session structures from the linked list specified. Free as many
1676*7526SVladimir.Kotal@Sun.COM  * sessions as possible but any failure in C_CloseSession() means that we
1677*7526SVladimir.Kotal@Sun.COM  * return an error on return.
16787211Sjp161948  */
1679*7526SVladimir.Kotal@Sun.COM static int pk11_free_session_list(PK11_OPTYPE optype)
16807211Sjp161948 	{
16817211Sjp161948 	CK_RV rv;
16827211Sjp161948 	PK11_SESSION *sp = NULL;
1683*7526SVladimir.Kotal@Sun.COM 	PK11_SESSION *freelist = NULL;
16847211Sjp161948 	pid_t mypid = getpid();
1685*7526SVladimir.Kotal@Sun.COM 	pthread_mutex_t *freelist_lock;
16867211Sjp161948 	int ret = 1;
16877211Sjp161948 
1688*7526SVladimir.Kotal@Sun.COM 	switch (optype)
1689*7526SVladimir.Kotal@Sun.COM 		{
1690*7526SVladimir.Kotal@Sun.COM 		case OP_RSA:
1691*7526SVladimir.Kotal@Sun.COM 		case OP_DSA:
1692*7526SVladimir.Kotal@Sun.COM 		case OP_DH:
1693*7526SVladimir.Kotal@Sun.COM 		case OP_RAND:
1694*7526SVladimir.Kotal@Sun.COM 		case OP_DIGEST:
1695*7526SVladimir.Kotal@Sun.COM 		case OP_CIPHER:
1696*7526SVladimir.Kotal@Sun.COM 			freelist_lock = session_cache[optype].lock;
1697*7526SVladimir.Kotal@Sun.COM 			break;
1698*7526SVladimir.Kotal@Sun.COM 		default:
1699*7526SVladimir.Kotal@Sun.COM 			PK11err(PK11_F_FREE_ALL_SESSIONS,
1700*7526SVladimir.Kotal@Sun.COM 				PK11_R_INVALID_OPERATION_TYPE);
1701*7526SVladimir.Kotal@Sun.COM 			return (0);
1702*7526SVladimir.Kotal@Sun.COM 		}
1703*7526SVladimir.Kotal@Sun.COM 
1704*7526SVladimir.Kotal@Sun.COM 	(void) pthread_mutex_lock(freelist_lock);
1705*7526SVladimir.Kotal@Sun.COM 	freelist = session_cache[optype].head;
1706*7526SVladimir.Kotal@Sun.COM 	while ((sp = freelist) != NULL)
17070Sstevel@tonic-gate 		{
17080Sstevel@tonic-gate 		if (sp->session != CK_INVALID_HANDLE && sp->pid == mypid)
17090Sstevel@tonic-gate 			{
17100Sstevel@tonic-gate 			rv = pFuncList->C_CloseSession(sp->session);
17110Sstevel@tonic-gate 			if (rv != CKR_OK)
17120Sstevel@tonic-gate 				{
17137211Sjp161948 				PK11err_add_data(PK11_F_FREE_ALL_SESSIONS,
17147211Sjp161948 					PK11_R_CLOSESESSION, rv);
17157211Sjp161948 				ret = 0;
17160Sstevel@tonic-gate 				}
17170Sstevel@tonic-gate 			}
1718*7526SVladimir.Kotal@Sun.COM 		freelist = sp->next;
1719*7526SVladimir.Kotal@Sun.COM 		pk11_free_nums(sp, optype);
17200Sstevel@tonic-gate 		OPENSSL_free(sp);
17210Sstevel@tonic-gate 		}
17227211Sjp161948 
1723*7526SVladimir.Kotal@Sun.COM 	(void) pthread_mutex_unlock(freelist_lock);
17240Sstevel@tonic-gate 	return ret;
17250Sstevel@tonic-gate 	}
17260Sstevel@tonic-gate 
17270Sstevel@tonic-gate 
17287211Sjp161948 static int pk11_setup_session(PK11_SESSION *sp, PK11_OPTYPE optype)
17290Sstevel@tonic-gate 	{
17300Sstevel@tonic-gate 	CK_RV rv;
17317211Sjp161948 	CK_SLOT_ID myslot;
17327211Sjp161948 
17337211Sjp161948 	switch (optype)
17347211Sjp161948 		{
1735*7526SVladimir.Kotal@Sun.COM 		case OP_RSA:
1736*7526SVladimir.Kotal@Sun.COM 		case OP_DSA:
1737*7526SVladimir.Kotal@Sun.COM 		case OP_DH:
17387211Sjp161948 			myslot = pubkey_SLOTID;
17397211Sjp161948 			break;
17407211Sjp161948 		case OP_RAND:
17417211Sjp161948 			myslot = rand_SLOTID;
17427211Sjp161948 			break;
17437211Sjp161948 		case OP_DIGEST:
17447211Sjp161948 		case OP_CIPHER:
17457211Sjp161948 			myslot = SLOTID;
17467211Sjp161948 			break;
17477211Sjp161948 		default:
17487211Sjp161948 			PK11err(PK11_F_SETUP_SESSION,
17497211Sjp161948 			    PK11_R_INVALID_OPERATION_TYPE);
17507211Sjp161948 			return 0;
17517211Sjp161948 		}
17527211Sjp161948 
17530Sstevel@tonic-gate 	sp->session = CK_INVALID_HANDLE;
17547211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
17557211Sjp161948 	fprintf(stderr, "%s: myslot=%d optype=%d\n", PK11_DBG, myslot, optype);
17567211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
17577211Sjp161948 	rv = pFuncList->C_OpenSession(myslot, CKF_SERIAL_SESSION,
17580Sstevel@tonic-gate 		NULL_PTR, NULL_PTR, &sp->session);
17590Sstevel@tonic-gate 	if (rv == CKR_CRYPTOKI_NOT_INITIALIZED)
17600Sstevel@tonic-gate 		{
17610Sstevel@tonic-gate 		/*
17620Sstevel@tonic-gate 		 * We are probably a child process so force the
17630Sstevel@tonic-gate 		 * reinitialize of the session
17640Sstevel@tonic-gate 		 */
1765*7526SVladimir.Kotal@Sun.COM 		pk11_library_initialized = FALSE;
17660Sstevel@tonic-gate 		(void) pk11_library_init(NULL);
17677211Sjp161948 		rv = pFuncList->C_OpenSession(myslot, CKF_SERIAL_SESSION,
17680Sstevel@tonic-gate 			NULL_PTR, NULL_PTR, &sp->session);
17690Sstevel@tonic-gate 		}
17700Sstevel@tonic-gate 	if (rv != CKR_OK)
17710Sstevel@tonic-gate 		{
17727211Sjp161948 		PK11err_add_data(PK11_F_SETUP_SESSION, PK11_R_OPENSESSION, rv);
17730Sstevel@tonic-gate 		return 0;
17740Sstevel@tonic-gate 		}
17750Sstevel@tonic-gate 
1776*7526SVladimir.Kotal@Sun.COM 	sp->pid = getpid();
1777*7526SVladimir.Kotal@Sun.COM 
1778*7526SVladimir.Kotal@Sun.COM 	switch (optype)
17790Sstevel@tonic-gate 		{
17806847Svk199839 #ifndef OPENSSL_NO_RSA
1781*7526SVladimir.Kotal@Sun.COM 		case OP_RSA:
1782*7526SVladimir.Kotal@Sun.COM 			sp->opdata_rsa_pub_key = CK_INVALID_HANDLE;
1783*7526SVladimir.Kotal@Sun.COM 			sp->opdata_rsa_priv_key = CK_INVALID_HANDLE;
1784*7526SVladimir.Kotal@Sun.COM 			sp->opdata_rsa_pub = NULL;
1785*7526SVladimir.Kotal@Sun.COM 			sp->opdata_rsa_n_num = NULL;
1786*7526SVladimir.Kotal@Sun.COM 			sp->opdata_rsa_e_num = NULL;
1787*7526SVladimir.Kotal@Sun.COM 			sp->opdata_rsa_priv = NULL;
1788*7526SVladimir.Kotal@Sun.COM 			sp->opdata_rsa_d_num = NULL;
1789*7526SVladimir.Kotal@Sun.COM 			break;
17907211Sjp161948 #endif	/* OPENSSL_NO_RSA */
17916847Svk199839 #ifndef OPENSSL_NO_DSA
1792*7526SVladimir.Kotal@Sun.COM 		case OP_DSA:
1793*7526SVladimir.Kotal@Sun.COM 			sp->opdata_dsa_pub_key = CK_INVALID_HANDLE;
1794*7526SVladimir.Kotal@Sun.COM 			sp->opdata_dsa_priv_key = CK_INVALID_HANDLE;
1795*7526SVladimir.Kotal@Sun.COM 			sp->opdata_dsa_pub = NULL;
1796*7526SVladimir.Kotal@Sun.COM 			sp->opdata_dsa_pub_num = NULL;
1797*7526SVladimir.Kotal@Sun.COM 			sp->opdata_dsa_priv = NULL;
1798*7526SVladimir.Kotal@Sun.COM 			sp->opdata_dsa_priv_num = NULL;
1799*7526SVladimir.Kotal@Sun.COM 			break;
18007211Sjp161948 #endif	/* OPENSSL_NO_DSA */
18016847Svk199839 #ifndef OPENSSL_NO_DH
1802*7526SVladimir.Kotal@Sun.COM 		case OP_DH:
1803*7526SVladimir.Kotal@Sun.COM 			sp->opdata_dh_key = CK_INVALID_HANDLE;
1804*7526SVladimir.Kotal@Sun.COM 			sp->opdata_dh = NULL;
1805*7526SVladimir.Kotal@Sun.COM 			sp->opdata_dh_priv_num = NULL;
1806*7526SVladimir.Kotal@Sun.COM 			break;
18077211Sjp161948 #endif	/* OPENSSL_NO_DH */
1808*7526SVladimir.Kotal@Sun.COM 		case OP_CIPHER:
1809*7526SVladimir.Kotal@Sun.COM 			sp->opdata_cipher_key = CK_INVALID_HANDLE;
1810*7526SVladimir.Kotal@Sun.COM 			sp->opdata_encrypt = -1;
1811*7526SVladimir.Kotal@Sun.COM 			break;
1812*7526SVladimir.Kotal@Sun.COM 		}
18130Sstevel@tonic-gate 
18140Sstevel@tonic-gate 	return 1;
18150Sstevel@tonic-gate 	}
18160Sstevel@tonic-gate 
18176847Svk199839 #ifndef OPENSSL_NO_RSA
18186847Svk199839 /* Destroy RSA public key from single session. */
18196847Svk199839 int pk11_destroy_rsa_object_pub(PK11_SESSION *sp, CK_BBOOL uselock)
18206847Svk199839 	{
18216847Svk199839 	int ret = 0;
18226847Svk199839 
1823*7526SVladimir.Kotal@Sun.COM 	if (sp->opdata_rsa_pub_key != CK_INVALID_HANDLE)
18246847Svk199839 		{
1825*7526SVladimir.Kotal@Sun.COM 		TRY_OBJ_DESTROY(sp->session, sp->opdata_rsa_pub_key,
1826*7526SVladimir.Kotal@Sun.COM 		    ret, uselock, OP_RSA);
1827*7526SVladimir.Kotal@Sun.COM 		sp->opdata_rsa_pub_key = CK_INVALID_HANDLE;
1828*7526SVladimir.Kotal@Sun.COM 		sp->opdata_rsa_pub = NULL;
1829*7526SVladimir.Kotal@Sun.COM 		if (sp->opdata_rsa_n_num != NULL)
1830*7526SVladimir.Kotal@Sun.COM 			{
1831*7526SVladimir.Kotal@Sun.COM 			BN_free(sp->opdata_rsa_n_num);
1832*7526SVladimir.Kotal@Sun.COM 			sp->opdata_rsa_n_num = NULL;
1833*7526SVladimir.Kotal@Sun.COM 			}
1834*7526SVladimir.Kotal@Sun.COM 		if (sp->opdata_rsa_e_num != NULL)
1835*7526SVladimir.Kotal@Sun.COM 			{
1836*7526SVladimir.Kotal@Sun.COM 			BN_free(sp->opdata_rsa_e_num);
1837*7526SVladimir.Kotal@Sun.COM 			sp->opdata_rsa_e_num = NULL;
1838*7526SVladimir.Kotal@Sun.COM 			}
18396847Svk199839 		}
18406847Svk199839 
18416847Svk199839 	return (ret);
18426847Svk199839 	}
18436847Svk199839 
18446847Svk199839 /* Destroy RSA private key from single session. */
18456847Svk199839 int pk11_destroy_rsa_object_priv(PK11_SESSION *sp, CK_BBOOL uselock)
18460Sstevel@tonic-gate 	{
18470Sstevel@tonic-gate 	int ret = 0;
18486847Svk199839 
1849*7526SVladimir.Kotal@Sun.COM 	if (sp->opdata_rsa_priv_key != CK_INVALID_HANDLE)
18506847Svk199839 		{
1851*7526SVladimir.Kotal@Sun.COM 		TRY_OBJ_DESTROY(sp->session, sp->opdata_rsa_priv_key,
1852*7526SVladimir.Kotal@Sun.COM 		    ret, uselock, OP_RSA);
1853*7526SVladimir.Kotal@Sun.COM 		sp->opdata_rsa_priv_key = CK_INVALID_HANDLE;
1854*7526SVladimir.Kotal@Sun.COM 		sp->opdata_rsa_priv = NULL;
1855*7526SVladimir.Kotal@Sun.COM 		if (sp->opdata_rsa_d_num != NULL)
1856*7526SVladimir.Kotal@Sun.COM 			{
1857*7526SVladimir.Kotal@Sun.COM 			BN_free(sp->opdata_rsa_d_num);
1858*7526SVladimir.Kotal@Sun.COM 			sp->opdata_rsa_d_num = NULL;
1859*7526SVladimir.Kotal@Sun.COM 			}
18606847Svk199839 		}
18616847Svk199839 
18626847Svk199839 	return (ret);
18636847Svk199839 	}
18646847Svk199839 
18656847Svk199839 /*
18667211Sjp161948  * Destroy RSA key object wrapper. If session is NULL, try to destroy all
18677211Sjp161948  * objects in the free list.
18686847Svk199839  */
18696847Svk199839 int pk11_destroy_rsa_key_objects(PK11_SESSION *session)
18706847Svk199839 	{
18716847Svk199839 	int ret = 1;
18720Sstevel@tonic-gate 	PK11_SESSION *sp = NULL;
18730Sstevel@tonic-gate 	PK11_SESSION *local_free_session;
18746847Svk199839 	CK_BBOOL uselock = TRUE;
18750Sstevel@tonic-gate 
18766847Svk199839 	if (session != NULL)
18770Sstevel@tonic-gate 		local_free_session = session;
18780Sstevel@tonic-gate 	else
18796847Svk199839 		{
1880*7526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_lock(session_cache[OP_RSA].lock);
1881*7526SVladimir.Kotal@Sun.COM 		local_free_session = session_cache[OP_RSA].head;
18826847Svk199839 		uselock = FALSE;
18836847Svk199839 		}
18840Sstevel@tonic-gate 
18856847Svk199839 	/*
18866847Svk199839 	 * go through the list of sessions and delete key objects
18876847Svk199839 	 */
18880Sstevel@tonic-gate 	while ((sp = local_free_session) != NULL)
18890Sstevel@tonic-gate 		{
18900Sstevel@tonic-gate 		local_free_session = sp->next;
18910Sstevel@tonic-gate 
18926847Svk199839 		/*
18936847Svk199839 		 * Do not terminate list traversal if one of the
18946847Svk199839 		 * destroy operations fails.
18956847Svk199839 		 */
18966847Svk199839 		if (pk11_destroy_rsa_object_pub(sp, uselock) == 0)
18970Sstevel@tonic-gate 			{
18986847Svk199839 			ret = 0;
18996847Svk199839 			continue;
19000Sstevel@tonic-gate 			}
19016847Svk199839 		if (pk11_destroy_rsa_object_priv(sp, uselock) == 0)
19026847Svk199839 			{
19036847Svk199839 			ret = 0;
19046847Svk199839 			continue;
19056847Svk199839 			}
19066847Svk199839 		}
19070Sstevel@tonic-gate 
19086847Svk199839 	if (session == NULL)
1909*7526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_unlock(session_cache[OP_RSA].lock);
19100Sstevel@tonic-gate 
19110Sstevel@tonic-gate 	return ret;
19120Sstevel@tonic-gate 	}
19137211Sjp161948 #endif	/* OPENSSL_NO_RSA */
19140Sstevel@tonic-gate 
19156847Svk199839 #ifndef OPENSSL_NO_DSA
19166847Svk199839 /* Destroy DSA public key from single session. */
19176847Svk199839 int pk11_destroy_dsa_object_pub(PK11_SESSION *sp, CK_BBOOL uselock)
19180Sstevel@tonic-gate 	{
19190Sstevel@tonic-gate 	int ret = 0;
19206847Svk199839 
1921*7526SVladimir.Kotal@Sun.COM 	if (sp->opdata_dsa_pub_key != CK_INVALID_HANDLE)
19226847Svk199839 		{
1923*7526SVladimir.Kotal@Sun.COM 		TRY_OBJ_DESTROY(sp->session, sp->opdata_dsa_pub_key,
1924*7526SVladimir.Kotal@Sun.COM 		    ret, uselock, OP_DSA);
1925*7526SVladimir.Kotal@Sun.COM 		sp->opdata_dsa_pub_key = CK_INVALID_HANDLE;
1926*7526SVladimir.Kotal@Sun.COM 		sp->opdata_dsa_pub = NULL;
1927*7526SVladimir.Kotal@Sun.COM 		if (sp->opdata_dsa_pub_num != NULL)
1928*7526SVladimir.Kotal@Sun.COM 			{
1929*7526SVladimir.Kotal@Sun.COM 			BN_free(sp->opdata_dsa_pub_num);
1930*7526SVladimir.Kotal@Sun.COM 			sp->opdata_dsa_pub_num = NULL;
1931*7526SVladimir.Kotal@Sun.COM 			}
19326847Svk199839 		}
19336847Svk199839 
19346847Svk199839 	return (ret);
19356847Svk199839 	}
19366847Svk199839 
19376847Svk199839 /* Destroy DSA private key from single session. */
19386847Svk199839 int pk11_destroy_dsa_object_priv(PK11_SESSION *sp, CK_BBOOL uselock)
19396847Svk199839 	{
19406847Svk199839 	int ret = 0;
19416847Svk199839 
1942*7526SVladimir.Kotal@Sun.COM 	if (sp->opdata_dsa_priv_key != CK_INVALID_HANDLE)
19436847Svk199839 		{
1944*7526SVladimir.Kotal@Sun.COM 		TRY_OBJ_DESTROY(sp->session, sp->opdata_dsa_priv_key,
1945*7526SVladimir.Kotal@Sun.COM 		    ret, uselock, OP_DSA);
1946*7526SVladimir.Kotal@Sun.COM 		sp->opdata_dsa_priv_key = CK_INVALID_HANDLE;
1947*7526SVladimir.Kotal@Sun.COM 		sp->opdata_dsa_priv = NULL;
1948*7526SVladimir.Kotal@Sun.COM 		if (sp->opdata_dsa_priv_num != NULL)
1949*7526SVladimir.Kotal@Sun.COM 			{
1950*7526SVladimir.Kotal@Sun.COM 			BN_free(sp->opdata_dsa_priv_num);
1951*7526SVladimir.Kotal@Sun.COM 			sp->opdata_dsa_priv_num = NULL;
1952*7526SVladimir.Kotal@Sun.COM 			}
19536847Svk199839 		}
19546847Svk199839 
19556847Svk199839 	return (ret);
19566847Svk199839 	}
19576847Svk199839 
19586847Svk199839 /*
19597211Sjp161948  * Destroy DSA key object wrapper. If session is NULL, try to destroy all
19607211Sjp161948  * objects in the free list.
19616847Svk199839  */
19626847Svk199839 int pk11_destroy_dsa_key_objects(PK11_SESSION *session)
19636847Svk199839 	{
19646847Svk199839 	int ret = 1;
19650Sstevel@tonic-gate 	PK11_SESSION *sp = NULL;
19660Sstevel@tonic-gate 	PK11_SESSION *local_free_session;
19676847Svk199839 	CK_BBOOL uselock = TRUE;
19680Sstevel@tonic-gate 
19696847Svk199839 	if (session != NULL)
19700Sstevel@tonic-gate 		local_free_session = session;
19710Sstevel@tonic-gate 	else
19726847Svk199839 		{
1973*7526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_lock(session_cache[OP_DSA].lock);
1974*7526SVladimir.Kotal@Sun.COM 		local_free_session = session_cache[OP_DSA].head;
19756847Svk199839 		uselock = FALSE;
19766847Svk199839 		}
19776847Svk199839 
19786847Svk199839 	/*
19796847Svk199839 	 * go through the list of sessions and delete key objects
19806847Svk199839 	 */
19810Sstevel@tonic-gate 	while ((sp = local_free_session) != NULL)
19820Sstevel@tonic-gate 		{
19830Sstevel@tonic-gate 		local_free_session = sp->next;
19840Sstevel@tonic-gate 
19856847Svk199839 		/*
19866847Svk199839 		 * Do not terminate list traversal if one of the
19876847Svk199839 		 * destroy operations fails.
19886847Svk199839 		 */
19896847Svk199839 		if (pk11_destroy_dsa_object_pub(sp, uselock) == 0)
19900Sstevel@tonic-gate 			{
19916847Svk199839 			ret = 0;
19926847Svk199839 			continue;
19930Sstevel@tonic-gate 			}
19946847Svk199839 		if (pk11_destroy_dsa_object_priv(sp, uselock) == 0)
19956847Svk199839 			{
19966847Svk199839 			ret = 0;
19976847Svk199839 			continue;
19986847Svk199839 			}
19990Sstevel@tonic-gate 		}
20006847Svk199839 
20016847Svk199839 	if (session == NULL)
2002*7526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_unlock(session_cache[OP_DSA].lock);
20030Sstevel@tonic-gate 
20040Sstevel@tonic-gate 	return ret;
20050Sstevel@tonic-gate 	}
20067211Sjp161948 #endif	/* OPENSSL_NO_DSA */
20076847Svk199839 
20086847Svk199839 #ifndef OPENSSL_NO_DH
20096847Svk199839 /* Destroy DH key from single session. */
20106847Svk199839 int pk11_destroy_dh_object(PK11_SESSION *sp, CK_BBOOL uselock)
20116847Svk199839 	{
20126847Svk199839 	int ret = 0;
20136847Svk199839 
2014*7526SVladimir.Kotal@Sun.COM 	if (sp->opdata_dh_key != CK_INVALID_HANDLE)
20156847Svk199839 		{
2016*7526SVladimir.Kotal@Sun.COM 		TRY_OBJ_DESTROY(sp->session, sp->opdata_dh_key,
2017*7526SVladimir.Kotal@Sun.COM 		    ret, uselock, OP_DH);
2018*7526SVladimir.Kotal@Sun.COM 		sp->opdata_dh_key = CK_INVALID_HANDLE;
2019*7526SVladimir.Kotal@Sun.COM 		sp->opdata_dh = NULL;
2020*7526SVladimir.Kotal@Sun.COM 		if (sp->opdata_dh_priv_num != NULL)
2021*7526SVladimir.Kotal@Sun.COM 			{
2022*7526SVladimir.Kotal@Sun.COM 			BN_free(sp->opdata_dh_priv_num);
2023*7526SVladimir.Kotal@Sun.COM 			sp->opdata_dh_priv_num = NULL;
2024*7526SVladimir.Kotal@Sun.COM 			}
20256847Svk199839 		}
20266847Svk199839 
20276847Svk199839 	return (ret);
20286847Svk199839 	}
20296847Svk199839 
20306847Svk199839 /*
20316847Svk199839  * Destroy DH key object wrapper.
20326847Svk199839  *
20336847Svk199839  * arg0: pointer to PKCS#11 engine session structure
20346847Svk199839  *       if session is NULL, try to destroy all objects in the free list
20356847Svk199839  */
20366847Svk199839 int pk11_destroy_dh_key_objects(PK11_SESSION *session)
20376847Svk199839 	{
20386847Svk199839 	int ret = 1;
20396847Svk199839 	PK11_SESSION *sp = NULL;
20406847Svk199839 	PK11_SESSION *local_free_session;
20416847Svk199839 	CK_BBOOL uselock = TRUE;
20426847Svk199839 
20436847Svk199839 	if (session != NULL)
20446847Svk199839 		local_free_session = session;
20456847Svk199839 	else
20466847Svk199839 		{
2047*7526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_lock(session_cache[OP_DH].lock);
2048*7526SVladimir.Kotal@Sun.COM 		local_free_session = session_cache[OP_DH].head;
20496847Svk199839 		uselock = FALSE;
20506847Svk199839 		}
20516847Svk199839 
20526847Svk199839 	while ((sp = local_free_session) != NULL)
20536847Svk199839 		{
20546847Svk199839 		local_free_session = sp->next;
20556847Svk199839 
20566847Svk199839 		/*
20576847Svk199839 		 * Do not terminate list traversal if one of the
20586847Svk199839 		 * destroy operations fails.
20596847Svk199839 		 */
20606847Svk199839 		if (pk11_destroy_dh_object(sp, uselock) == 0)
20616847Svk199839 			{
20626847Svk199839 			ret = 0;
20636847Svk199839 			continue;
20646847Svk199839 			}
20656847Svk199839 		}
20666847Svk199839 err:
20676847Svk199839 	if (session == NULL)
2068*7526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_unlock(session_cache[OP_DH].lock);
20696847Svk199839 
20706847Svk199839 	return ret;
20716847Svk199839 	}
20727211Sjp161948 #endif	/* OPENSSL_NO_DH */
20730Sstevel@tonic-gate 
20740Sstevel@tonic-gate static int pk11_destroy_object(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE oh)
20750Sstevel@tonic-gate 	{
20760Sstevel@tonic-gate 	CK_RV rv;
20770Sstevel@tonic-gate 	rv = pFuncList->C_DestroyObject(session, oh);
20780Sstevel@tonic-gate 	if (rv != CKR_OK)
20790Sstevel@tonic-gate 		{
20807211Sjp161948 		PK11err_add_data(PK11_F_DESTROY_OBJECT, PK11_R_DESTROYOBJECT,
20817211Sjp161948 		    rv);
20820Sstevel@tonic-gate 		return 0;
20830Sstevel@tonic-gate 		}
20840Sstevel@tonic-gate 
20850Sstevel@tonic-gate 	return 1;
20860Sstevel@tonic-gate 	}
20870Sstevel@tonic-gate 
20880Sstevel@tonic-gate 
20890Sstevel@tonic-gate /* Symmetric ciphers and digests support functions
20900Sstevel@tonic-gate  */
20910Sstevel@tonic-gate 
20920Sstevel@tonic-gate static int
20930Sstevel@tonic-gate cipher_nid_to_pk11(int nid)
20940Sstevel@tonic-gate 	{
20950Sstevel@tonic-gate 	int i;
20960Sstevel@tonic-gate 
20970Sstevel@tonic-gate 	for (i = 0; i < PK11_CIPHER_MAX; i++)
20980Sstevel@tonic-gate 		if (ciphers[i].nid == nid)
20990Sstevel@tonic-gate 			return (ciphers[i].id);
21000Sstevel@tonic-gate 	return (-1);
21010Sstevel@tonic-gate 	}
21020Sstevel@tonic-gate 
21030Sstevel@tonic-gate static int
21040Sstevel@tonic-gate pk11_usable_ciphers(const int **nids)
21050Sstevel@tonic-gate 	{
21060Sstevel@tonic-gate 	if (cipher_count > 0)
21070Sstevel@tonic-gate 		*nids = cipher_nids;
21080Sstevel@tonic-gate 	else
21090Sstevel@tonic-gate 		*nids = NULL;
21100Sstevel@tonic-gate 	return (cipher_count);
21110Sstevel@tonic-gate 	}
21120Sstevel@tonic-gate 
21130Sstevel@tonic-gate static int
21140Sstevel@tonic-gate pk11_usable_digests(const int **nids)
21150Sstevel@tonic-gate 	{
21160Sstevel@tonic-gate 	if (digest_count > 0)
21170Sstevel@tonic-gate 		*nids = digest_nids;
21180Sstevel@tonic-gate 	else
21190Sstevel@tonic-gate 		*nids = NULL;
21200Sstevel@tonic-gate 	return (digest_count);
21210Sstevel@tonic-gate 	}
21220Sstevel@tonic-gate 
21237211Sjp161948 /*
21247211Sjp161948  * Init context for encryption or decryption using a symmetric key.
21257211Sjp161948  */
21267211Sjp161948 static int pk11_init_symmetric(EVP_CIPHER_CTX *ctx, PK11_CIPHER *pcipher,
21277211Sjp161948 	PK11_SESSION *sp, CK_MECHANISM_PTR pmech)
21287211Sjp161948 	{
21297211Sjp161948 	CK_RV rv;
21307211Sjp161948 #ifdef	SOLARIS_AES_CTR
21317211Sjp161948 	CK_AES_CTR_PARAMS ctr_params;
21327211Sjp161948 #endif	/* SOLARIS_AES_CTR */
21337211Sjp161948 
21347211Sjp161948 	/*
21357211Sjp161948 	 * We expect pmech->mechanism to be already set and
21367211Sjp161948 	 * pParameter/ulParameterLen initialized to NULL/0 before
21377211Sjp161948 	 * pk11_init_symetric() is called.
21387211Sjp161948 	 */
21397211Sjp161948 	OPENSSL_assert(pmech->mechanism != NULL);
21407211Sjp161948 	OPENSSL_assert(pmech->pParameter == NULL);
21417211Sjp161948 	OPENSSL_assert(pmech->ulParameterLen == 0);
21427211Sjp161948 
21437211Sjp161948 #ifdef	SOLARIS_AES_CTR
21447211Sjp161948 	if (ctx->cipher->nid == NID_aes_128_ctr ||
21457211Sjp161948 	    ctx->cipher->nid == NID_aes_192_ctr ||
21467211Sjp161948 	    ctx->cipher->nid == NID_aes_256_ctr)
21477211Sjp161948 		{
21487211Sjp161948 		pmech->pParameter = (void *)(&ctr_params);
21497211Sjp161948 		pmech->ulParameterLen = sizeof(ctr_params);
21507211Sjp161948 		/*
21517211Sjp161948 		 * For now, we are limited to the fixed length of the counter,
21527211Sjp161948 		 * it covers the whole counter block. That's what RFC 4344
21537211Sjp161948 		 * needs. For more information on internal structure of the
21547211Sjp161948 		 * counter block, see RFC 3686. If needed in the future, we can
21557211Sjp161948 		 * add code so that the counter length can be set via
21567211Sjp161948 		 * ENGINE_ctrl() function.
21577211Sjp161948 		 */
21587211Sjp161948 		ctr_params.ulCounterBits = AES_BLOCK_SIZE * 8;
21597211Sjp161948 		OPENSSL_assert(pcipher->iv_len == AES_BLOCK_SIZE);
21607211Sjp161948 		memcpy(ctr_params.cb, ctx->iv, AES_BLOCK_SIZE);
21617211Sjp161948 		}
21627211Sjp161948 	else
21637211Sjp161948 #endif	/* SOLARIS_AES_CTR */
21647211Sjp161948 		{
21657211Sjp161948 		if (pcipher->iv_len > 0)
21667211Sjp161948 			{
21677211Sjp161948 			pmech->pParameter = (void *)ctx->iv;
21687211Sjp161948 			pmech->ulParameterLen = pcipher->iv_len;
21697211Sjp161948 			}
21707211Sjp161948 		}
21717211Sjp161948 
21727211Sjp161948 	/* if we get here, the encryption needs to be reinitialized */
21737211Sjp161948 	if (ctx->encrypt)
2174*7526SVladimir.Kotal@Sun.COM 		rv = pFuncList->C_EncryptInit(sp->session, pmech,
2175*7526SVladimir.Kotal@Sun.COM 			sp->opdata_cipher_key);
21767211Sjp161948 	else
2177*7526SVladimir.Kotal@Sun.COM 		rv = pFuncList->C_DecryptInit(sp->session, pmech,
2178*7526SVladimir.Kotal@Sun.COM 			sp->opdata_cipher_key);
21797211Sjp161948 
21807211Sjp161948 	if (rv != CKR_OK)
21817211Sjp161948 		{
21827211Sjp161948 		PK11err_add_data(PK11_F_CIPHER_INIT, ctx->encrypt ?
21837211Sjp161948 		    PK11_R_ENCRYPTINIT : PK11_R_DECRYPTINIT, rv);
21847211Sjp161948 		pk11_return_session(sp, OP_CIPHER);
21857211Sjp161948 		return (0);
21867211Sjp161948 		}
21877211Sjp161948 
21887211Sjp161948 	return (1);
21897211Sjp161948 	}
21907211Sjp161948 
21910Sstevel@tonic-gate static int
21920Sstevel@tonic-gate pk11_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
21930Sstevel@tonic-gate     const unsigned char *iv, int enc)
21940Sstevel@tonic-gate 	{
21954320Sjp161948 	CK_MECHANISM mech;
21960Sstevel@tonic-gate 	int index;
21970Sstevel@tonic-gate 	PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->cipher_data;
21980Sstevel@tonic-gate 	PK11_SESSION *sp;
21997211Sjp161948 	PK11_CIPHER *p_ciph_table_row;
22000Sstevel@tonic-gate 
22010Sstevel@tonic-gate 	state->sp = NULL;
22020Sstevel@tonic-gate 
22030Sstevel@tonic-gate 	index = cipher_nid_to_pk11(ctx->cipher->nid);
22040Sstevel@tonic-gate 	if (index < 0 || index >= PK11_CIPHER_MAX)
22050Sstevel@tonic-gate 		return 0;
22060Sstevel@tonic-gate 
22077211Sjp161948 	p_ciph_table_row = &ciphers[index];
22087211Sjp161948 	/*
22097211Sjp161948 	 * iv_len in the ctx->cipher structure is the maximum IV length for the
22107211Sjp161948 	 * current cipher and it must be less or equal to the IV length in our
22117211Sjp161948 	 * ciphers table. The key length must match precisely. Every application
22127211Sjp161948 	 * can define its own EVP functions so this code serves as a sanity
22137211Sjp161948 	 * check.
22147211Sjp161948 	 *
22157211Sjp161948 	 * Note that the reason why the IV length in ctx->cipher might be
22167211Sjp161948 	 * greater than the actual length is that OpenSSL uses BLOCK_CIPHER_defs
22177211Sjp161948 	 * macro to define functions that return EVP structures for all DES
22187211Sjp161948 	 * modes. So, even ECB modes get 8 byte IV.
22197211Sjp161948 	 */
22207211Sjp161948 	if (ctx->cipher->iv_len < p_ciph_table_row->iv_len ||
22217211Sjp161948 	    ctx->key_len != p_ciph_table_row->key_len)
22227211Sjp161948 		{
22237211Sjp161948 		PK11err(PK11_F_CIPHER_INIT, PK11_R_KEY_OR_IV_LEN_PROBLEM);
22240Sstevel@tonic-gate 		return 0;
22257211Sjp161948 		}
22267211Sjp161948 
22277211Sjp161948 	if ((sp = pk11_get_session(OP_CIPHER)) == NULL)
22280Sstevel@tonic-gate 		return 0;
22290Sstevel@tonic-gate 
22304320Sjp161948 	/* if applicable, the mechanism parameter is used for IV */
22317211Sjp161948 	mech.mechanism = p_ciph_table_row->mech_type;
22324320Sjp161948 	mech.pParameter = NULL;
22334320Sjp161948 	mech.ulParameterLen = 0;
22344320Sjp161948 
22350Sstevel@tonic-gate 	/* The key object is destroyed here if it is not the current key
22360Sstevel@tonic-gate 	 */
22377211Sjp161948 	(void) check_new_cipher_key(sp, key, p_ciph_table_row->key_len);
22380Sstevel@tonic-gate 
22390Sstevel@tonic-gate 	/* If the key is the same and the encryption is also the same,
22406847Svk199839 	 * then just reuse it. However, we must not forget to reinitialize the
22416847Svk199839 	 * context that was finalized in pk11_cipher_cleanup().
22420Sstevel@tonic-gate 	 */
2243*7526SVladimir.Kotal@Sun.COM 	if (sp->opdata_cipher_key != CK_INVALID_HANDLE &&
2244*7526SVladimir.Kotal@Sun.COM 	    sp->opdata_encrypt == ctx->encrypt)
22450Sstevel@tonic-gate 		{
22460Sstevel@tonic-gate 		state->sp = sp;
22477211Sjp161948 		if (pk11_init_symmetric(ctx, p_ciph_table_row, sp, &mech) == 0)
22486847Svk199839 			return (0);
22496847Svk199839 
22506847Svk199839 		return (1);
22510Sstevel@tonic-gate 		}
22520Sstevel@tonic-gate 
22530Sstevel@tonic-gate 	/* Check if the key has been invalidated. If so, a new key object
22540Sstevel@tonic-gate 	 * needs to be created.
22550Sstevel@tonic-gate 	 */
2256*7526SVladimir.Kotal@Sun.COM 	if (sp->opdata_cipher_key == CK_INVALID_HANDLE)
22570Sstevel@tonic-gate 		{
2258*7526SVladimir.Kotal@Sun.COM 		sp->opdata_cipher_key = pk11_get_cipher_key(
22597211Sjp161948 			ctx, key, p_ciph_table_row->key_type, sp);
22600Sstevel@tonic-gate 		}
22610Sstevel@tonic-gate 
2262*7526SVladimir.Kotal@Sun.COM 	if (sp->opdata_encrypt != ctx->encrypt && sp->opdata_encrypt != -1)
22630Sstevel@tonic-gate 		{
22640Sstevel@tonic-gate 		/* The previous encryption/decryption
22650Sstevel@tonic-gate 		 * is different. Need to terminate the previous
22660Sstevel@tonic-gate 		 * active encryption/decryption here
22670Sstevel@tonic-gate 		 */
22680Sstevel@tonic-gate 		if (!pk11_cipher_final(sp))
22690Sstevel@tonic-gate 			{
22707211Sjp161948 			pk11_return_session(sp, OP_CIPHER);
22710Sstevel@tonic-gate 			return 0;
22720Sstevel@tonic-gate 			}
22730Sstevel@tonic-gate 		}
22740Sstevel@tonic-gate 
2275*7526SVladimir.Kotal@Sun.COM 	if (sp->opdata_cipher_key == CK_INVALID_HANDLE)
22760Sstevel@tonic-gate 		{
22777211Sjp161948 		pk11_return_session(sp, OP_CIPHER);
22780Sstevel@tonic-gate 		return 0;
22790Sstevel@tonic-gate 		}
22800Sstevel@tonic-gate 
22816847Svk199839 	/* now initialize the context with a new key */
22827211Sjp161948 	if (pk11_init_symmetric(ctx, p_ciph_table_row, sp, &mech) == 0)
22836847Svk199839 		return (0);
22840Sstevel@tonic-gate 
2285*7526SVladimir.Kotal@Sun.COM 	sp->opdata_encrypt = ctx->encrypt;
22860Sstevel@tonic-gate 	state->sp = sp;
22870Sstevel@tonic-gate 
22880Sstevel@tonic-gate 	return 1;
22890Sstevel@tonic-gate 	}
22900Sstevel@tonic-gate 
22910Sstevel@tonic-gate /* When reusing the same key in an encryption/decryption session for a
22920Sstevel@tonic-gate  * decryption/encryption session, we need to close the active session
22930Sstevel@tonic-gate  * and recreate a new one. Note that the key is in the global session so
22940Sstevel@tonic-gate  * that it needs not be recreated.
22950Sstevel@tonic-gate  *
22960Sstevel@tonic-gate  * It is more appropriate to use C_En/DecryptFinish here. At the time of this
22970Sstevel@tonic-gate  * development, these two functions in the PKCS#11 libraries used return
22980Sstevel@tonic-gate  * unexpected errors when passing in 0 length output. It may be a good
22990Sstevel@tonic-gate  * idea to try them again if performance is a problem here and fix
23000Sstevel@tonic-gate  * C_En/DecryptFinial if there are bugs there causing the problem.
23010Sstevel@tonic-gate  */
23020Sstevel@tonic-gate static int
23030Sstevel@tonic-gate pk11_cipher_final(PK11_SESSION *sp)
23040Sstevel@tonic-gate 	{
23050Sstevel@tonic-gate 	CK_RV rv;
23060Sstevel@tonic-gate 
2307*7526SVladimir.Kotal@Sun.COM 	rv = pFuncList->C_CloseSession(sp->session);
23080Sstevel@tonic-gate 	if (rv != CKR_OK)
23090Sstevel@tonic-gate 		{
23107211Sjp161948 		PK11err_add_data(PK11_F_CIPHER_FINAL, PK11_R_CLOSESESSION, rv);
23110Sstevel@tonic-gate 		return 0;
23120Sstevel@tonic-gate 		}
23130Sstevel@tonic-gate 
23140Sstevel@tonic-gate 	rv = pFuncList->C_OpenSession(SLOTID, CKF_SERIAL_SESSION,
2315*7526SVladimir.Kotal@Sun.COM 		NULL_PTR, NULL_PTR, &sp->session);
23160Sstevel@tonic-gate 	if (rv != CKR_OK)
23170Sstevel@tonic-gate 		{
23187211Sjp161948 		PK11err_add_data(PK11_F_CIPHER_FINAL, PK11_R_OPENSESSION, rv);
23190Sstevel@tonic-gate 		return 0;
23200Sstevel@tonic-gate 		}
23210Sstevel@tonic-gate 
23220Sstevel@tonic-gate 	return 1;
23230Sstevel@tonic-gate 	}
23240Sstevel@tonic-gate 
23250Sstevel@tonic-gate /* An engine interface function. The calling function allocates sufficient
23260Sstevel@tonic-gate  * memory for the output buffer "out" to hold the results */
23270Sstevel@tonic-gate static int
23280Sstevel@tonic-gate pk11_cipher_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
23290Sstevel@tonic-gate 	const unsigned char *in, unsigned int inl)
23300Sstevel@tonic-gate 	{
23310Sstevel@tonic-gate 	PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->cipher_data;
23320Sstevel@tonic-gate 	PK11_SESSION *sp;
23330Sstevel@tonic-gate 	CK_RV rv;
23340Sstevel@tonic-gate 	unsigned long outl = inl;
23350Sstevel@tonic-gate 
23360Sstevel@tonic-gate 	if (state == NULL || state->sp == NULL)
23370Sstevel@tonic-gate 		return 0;
23380Sstevel@tonic-gate 
23390Sstevel@tonic-gate 	sp = (PK11_SESSION *) state->sp;
23400Sstevel@tonic-gate 
23410Sstevel@tonic-gate 	if (!inl)
23420Sstevel@tonic-gate 		return 1;
23430Sstevel@tonic-gate 
23440Sstevel@tonic-gate 	/* RC4 is the only stream cipher we support */
23450Sstevel@tonic-gate 	if (ctx->cipher->nid != NID_rc4 && (inl % ctx->cipher->block_size) != 0)
23460Sstevel@tonic-gate 		return 0;
23470Sstevel@tonic-gate 
23480Sstevel@tonic-gate 	if (ctx->encrypt)
23490Sstevel@tonic-gate 		{
2350*7526SVladimir.Kotal@Sun.COM 		rv = pFuncList->C_EncryptUpdate(sp->session,
23510Sstevel@tonic-gate 			(unsigned char *)in, inl, out, &outl);
23520Sstevel@tonic-gate 
23530Sstevel@tonic-gate 		if (rv != CKR_OK)
23540Sstevel@tonic-gate 			{
23557211Sjp161948 			PK11err_add_data(PK11_F_CIPHER_DO_CIPHER,
23567211Sjp161948 			    PK11_R_ENCRYPTUPDATE, rv);
23570Sstevel@tonic-gate 			return 0;
23580Sstevel@tonic-gate 			}
23590Sstevel@tonic-gate 		}
23600Sstevel@tonic-gate 	else
23610Sstevel@tonic-gate 		{
2362*7526SVladimir.Kotal@Sun.COM 		rv = pFuncList->C_DecryptUpdate(sp->session,
23630Sstevel@tonic-gate 			(unsigned char *)in, inl, out, &outl);
23640Sstevel@tonic-gate 
23650Sstevel@tonic-gate 		if (rv != CKR_OK)
23660Sstevel@tonic-gate 			{
23677211Sjp161948 			PK11err_add_data(PK11_F_CIPHER_DO_CIPHER,
23687211Sjp161948 			    PK11_R_DECRYPTUPDATE, rv);
23690Sstevel@tonic-gate 			return 0;
23700Sstevel@tonic-gate 			}
23710Sstevel@tonic-gate 		}
23720Sstevel@tonic-gate 
23730Sstevel@tonic-gate 	/* for DES_CBC, DES3_CBC, AES_CBC, and RC4, the output size is always
23740Sstevel@tonic-gate 	 * the same size of input
23750Sstevel@tonic-gate 	 * The application has guaranteed to call the block ciphers with
23760Sstevel@tonic-gate 	 * correctly aligned buffers.
23770Sstevel@tonic-gate 	 */
23780Sstevel@tonic-gate 	if (inl != outl)
23790Sstevel@tonic-gate 		return 0;
23800Sstevel@tonic-gate 
23810Sstevel@tonic-gate 	return 1;
23820Sstevel@tonic-gate 	}
23830Sstevel@tonic-gate 
23846847Svk199839 /*
23857211Sjp161948  * Return the session to the pool. Calling C_EncryptFinal() and C_DecryptFinal()
23867211Sjp161948  * here is the right thing because in EVP_DecryptFinal_ex(), engine's
23877211Sjp161948  * do_cipher() is not even called, and in EVP_EncryptFinal_ex() it is called but
23887211Sjp161948  * the engine can't find out that it's the finalizing call. We wouldn't
23897211Sjp161948  * necessarily have to finalize the context here since reinitializing it with
23907211Sjp161948  * C_(Encrypt|Decrypt)Init() should be fine but for the sake of correctness,
23917211Sjp161948  * let's do it. Some implementations might leak memory if the previously used
23927211Sjp161948  * context is initialized without finalizing it first.
23930Sstevel@tonic-gate  */
23940Sstevel@tonic-gate static int
23950Sstevel@tonic-gate pk11_cipher_cleanup(EVP_CIPHER_CTX *ctx)
23960Sstevel@tonic-gate 	{
23976847Svk199839 	CK_RV rv;
23987211Sjp161948 	CK_ULONG len = EVP_MAX_BLOCK_LENGTH;
23996847Svk199839 	CK_BYTE buf[EVP_MAX_BLOCK_LENGTH];
24000Sstevel@tonic-gate 	PK11_CIPHER_STATE *state = ctx->cipher_data;
24010Sstevel@tonic-gate 
24020Sstevel@tonic-gate 	if (state != NULL && state->sp != NULL)
24030Sstevel@tonic-gate 		{
24046847Svk199839 		/*
24056847Svk199839 		 * We are not interested in the data here, we just need to get
24066847Svk199839 		 * rid of the context.
24076847Svk199839 		 */
24086847Svk199839 		if (ctx->encrypt)
24096847Svk199839 			rv = pFuncList->C_EncryptFinal(
2410*7526SVladimir.Kotal@Sun.COM 			    state->sp->session, buf, &len);
24116847Svk199839 		else
24126847Svk199839 			rv = pFuncList->C_DecryptFinal(
2413*7526SVladimir.Kotal@Sun.COM 			    state->sp->session, buf, &len);
24146847Svk199839 
24156847Svk199839 		if (rv != CKR_OK)
24166847Svk199839 			{
24177211Sjp161948 			PK11err_add_data(PK11_F_CIPHER_CLEANUP, ctx->encrypt ?
24187211Sjp161948 			    PK11_R_ENCRYPTFINAL : PK11_R_DECRYPTFINAL, rv);
24197211Sjp161948 			pk11_return_session(state->sp, OP_CIPHER);
24206847Svk199839 			return (0);
24216847Svk199839 			}
24226847Svk199839 
24237211Sjp161948 		pk11_return_session(state->sp, OP_CIPHER);
24240Sstevel@tonic-gate 		state->sp = NULL;
24250Sstevel@tonic-gate 		}
24260Sstevel@tonic-gate 
24276847Svk199839 	return (1);
24286847Svk199839 	}
24296847Svk199839 
24300Sstevel@tonic-gate /* Registered by the ENGINE when used to find out how to deal with
24310Sstevel@tonic-gate  * a particular NID in the ENGINE. This says what we'll do at the
24320Sstevel@tonic-gate  * top level - note, that list is restricted by what we answer with
24330Sstevel@tonic-gate  */
24340Sstevel@tonic-gate static int
24350Sstevel@tonic-gate pk11_engine_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
24360Sstevel@tonic-gate 	const int **nids, int nid)
24370Sstevel@tonic-gate 	{
24380Sstevel@tonic-gate 	if (!cipher)
24390Sstevel@tonic-gate 		return (pk11_usable_ciphers(nids));
24400Sstevel@tonic-gate 
24410Sstevel@tonic-gate 	switch (nid)
24420Sstevel@tonic-gate 		{
24430Sstevel@tonic-gate 		case NID_des_ede3_cbc:
24440Sstevel@tonic-gate 			*cipher = &pk11_3des_cbc;
24450Sstevel@tonic-gate 			break;
24460Sstevel@tonic-gate 		case NID_des_cbc:
24470Sstevel@tonic-gate 			*cipher = &pk11_des_cbc;
24480Sstevel@tonic-gate 			break;
24497211Sjp161948 		case NID_des_ede3_ecb:
24507211Sjp161948 			*cipher = &pk11_3des_ecb;
24517211Sjp161948 			break;
24527211Sjp161948 		case NID_des_ecb:
24537211Sjp161948 			*cipher = &pk11_des_ecb;
24547211Sjp161948 			break;
24550Sstevel@tonic-gate 		case NID_aes_128_cbc:
24567211Sjp161948 			*cipher = &pk11_aes_128_cbc;
24577211Sjp161948 			break;
24587211Sjp161948 		case NID_aes_192_cbc:
24597211Sjp161948 			*cipher = &pk11_aes_192_cbc;
24607211Sjp161948 			break;
24617211Sjp161948 		case NID_aes_256_cbc:
24627211Sjp161948 			*cipher = &pk11_aes_256_cbc;
24637211Sjp161948 			break;
24647211Sjp161948 		case NID_aes_128_ecb:
24657211Sjp161948 			*cipher = &pk11_aes_128_ecb;
24667211Sjp161948 			break;
24677211Sjp161948 		case NID_aes_192_ecb:
24687211Sjp161948 			*cipher = &pk11_aes_192_ecb;
24697211Sjp161948 			break;
24707211Sjp161948 		case NID_aes_256_ecb:
24717211Sjp161948 			*cipher = &pk11_aes_256_ecb;
24727211Sjp161948 			break;
24737211Sjp161948 		case NID_bf_cbc:
24747211Sjp161948 			*cipher = &pk11_bf_cbc;
24750Sstevel@tonic-gate 			break;
24760Sstevel@tonic-gate 		case NID_rc4:
24770Sstevel@tonic-gate 			*cipher = &pk11_rc4;
24780Sstevel@tonic-gate 			break;
24790Sstevel@tonic-gate 		default:
24807211Sjp161948 #ifdef	SOLARIS_AES_CTR
24817211Sjp161948 			/*
24827211Sjp161948 			 * These can't be in separated cases because the NIDs
24837211Sjp161948 			 * here are not constants.
24847211Sjp161948 			 */
24857211Sjp161948 			if (nid == NID_aes_128_ctr)
24867211Sjp161948 				*cipher = &pk11_aes_128_ctr;
24877211Sjp161948 			else if (nid == NID_aes_192_ctr)
24887211Sjp161948 				*cipher = &pk11_aes_192_ctr;
24897211Sjp161948 			else if (nid == NID_aes_256_ctr)
24907211Sjp161948 				*cipher = &pk11_aes_256_ctr;
24917211Sjp161948 			else
24927211Sjp161948 #endif	/* SOLARIS_AES_CTR */
24930Sstevel@tonic-gate 			*cipher = NULL;
24940Sstevel@tonic-gate 			break;
24950Sstevel@tonic-gate 		}
24960Sstevel@tonic-gate 	return (*cipher != NULL);
24970Sstevel@tonic-gate 	}
24980Sstevel@tonic-gate 
24990Sstevel@tonic-gate static int
25000Sstevel@tonic-gate pk11_engine_digests(ENGINE *e, const EVP_MD **digest,
25010Sstevel@tonic-gate 	const int **nids, int nid)
25020Sstevel@tonic-gate 	{
25030Sstevel@tonic-gate 	if (!digest)
25040Sstevel@tonic-gate 		return (pk11_usable_digests(nids));
25050Sstevel@tonic-gate 
25060Sstevel@tonic-gate 	switch (nid)
25070Sstevel@tonic-gate 		{
25080Sstevel@tonic-gate 		case NID_md5:
25090Sstevel@tonic-gate 			*digest = &pk11_md5;
25100Sstevel@tonic-gate 			break;
25110Sstevel@tonic-gate 		case NID_sha1:
25120Sstevel@tonic-gate 			*digest = &pk11_sha1;
25130Sstevel@tonic-gate 			break;
25147211Sjp161948 		case NID_sha224:
25157211Sjp161948 			*digest = &pk11_sha224;
25167211Sjp161948 			break;
25177211Sjp161948 		case NID_sha256:
25187211Sjp161948 			*digest = &pk11_sha256;
25197211Sjp161948 			break;
25207211Sjp161948 		case NID_sha384:
25217211Sjp161948 			*digest = &pk11_sha384;
25227211Sjp161948 			break;
25237211Sjp161948 		case NID_sha512:
25247211Sjp161948 			*digest = &pk11_sha512;
25257211Sjp161948 			break;
25260Sstevel@tonic-gate 		default:
25270Sstevel@tonic-gate 			*digest = NULL;
25280Sstevel@tonic-gate 			break;
25290Sstevel@tonic-gate 		}
25300Sstevel@tonic-gate 	return (*digest != NULL);
25310Sstevel@tonic-gate 	}
25320Sstevel@tonic-gate 
25330Sstevel@tonic-gate 
25340Sstevel@tonic-gate /* Create a secret key object in a PKCS#11 session
25350Sstevel@tonic-gate  */
25360Sstevel@tonic-gate static CK_OBJECT_HANDLE pk11_get_cipher_key(EVP_CIPHER_CTX *ctx,
25370Sstevel@tonic-gate 	const unsigned char *key, CK_KEY_TYPE key_type, PK11_SESSION *sp)
25380Sstevel@tonic-gate 	{
25390Sstevel@tonic-gate 	CK_RV rv;
25400Sstevel@tonic-gate 	CK_OBJECT_HANDLE h_key = CK_INVALID_HANDLE;
25410Sstevel@tonic-gate 	CK_OBJECT_CLASS obj_key = CKO_SECRET_KEY;
25420Sstevel@tonic-gate 	CK_ULONG ul_key_attr_count = 6;
25430Sstevel@tonic-gate 
25440Sstevel@tonic-gate 	CK_ATTRIBUTE  a_key_template[] =
25450Sstevel@tonic-gate 		{
25460Sstevel@tonic-gate 		{CKA_CLASS, (void*) NULL, sizeof(CK_OBJECT_CLASS)},
25470Sstevel@tonic-gate 		{CKA_KEY_TYPE, (void*) NULL, sizeof(CK_KEY_TYPE)},
25480Sstevel@tonic-gate 		{CKA_TOKEN, &false, sizeof(false)},
25490Sstevel@tonic-gate 		{CKA_ENCRYPT, &true, sizeof(true)},
25500Sstevel@tonic-gate 		{CKA_DECRYPT, &true, sizeof(true)},
25510Sstevel@tonic-gate 		{CKA_VALUE, (void*) NULL, 0},
25520Sstevel@tonic-gate 		};
25530Sstevel@tonic-gate 
25540Sstevel@tonic-gate 	/* Create secret key object in global_session. All other sessions
25550Sstevel@tonic-gate 	 * can use the key handles. Here is why:
25560Sstevel@tonic-gate 	 * OpenSSL will call EncryptInit and EncryptUpdate using a secret key.
25570Sstevel@tonic-gate 	 * It may then call DecryptInit and DecryptUpdate using the same key.
25580Sstevel@tonic-gate 	 * To use the same key object, we need to call EncryptFinal with
25590Sstevel@tonic-gate 	 * a 0 length message. Currently, this does not work for 3DES
25600Sstevel@tonic-gate 	 * mechanism. To get around this problem, we close the session and
25610Sstevel@tonic-gate 	 * then create a new session to use the same key object. When a session
25620Sstevel@tonic-gate 	 * is closed, all the object handles will be invalid. Thus, create key
25630Sstevel@tonic-gate 	 * objects in a global session, an individual session may be closed to
25640Sstevel@tonic-gate 	 * terminate the active operation.
25650Sstevel@tonic-gate 	 */
25660Sstevel@tonic-gate 	CK_SESSION_HANDLE session = global_session;
25670Sstevel@tonic-gate 	a_key_template[0].pValue = &obj_key;
25680Sstevel@tonic-gate 	a_key_template[1].pValue = &key_type;
25690Sstevel@tonic-gate 	a_key_template[5].pValue = (void *) key;
25700Sstevel@tonic-gate 	a_key_template[5].ulValueLen = (unsigned long) ctx->key_len;
25710Sstevel@tonic-gate 
25724602Sjp161948 	rv = pFuncList->C_CreateObject(session,
25734602Sjp161948 		a_key_template, ul_key_attr_count, &h_key);
25740Sstevel@tonic-gate 	if (rv != CKR_OK)
25750Sstevel@tonic-gate 		{
25767211Sjp161948 		PK11err_add_data(PK11_F_GET_CIPHER_KEY, PK11_R_CREATEOBJECT,
25777211Sjp161948 		    rv);
25780Sstevel@tonic-gate 		goto err;
25790Sstevel@tonic-gate 		}
25800Sstevel@tonic-gate 
25810Sstevel@tonic-gate 	/* Save the key information used in this session.
25820Sstevel@tonic-gate 	 * The max can be saved is PK11_KEY_LEN_MAX.
25830Sstevel@tonic-gate 	 */
2584*7526SVladimir.Kotal@Sun.COM 	sp->opdata_key_len = ctx->key_len > PK11_KEY_LEN_MAX ?
25850Sstevel@tonic-gate 		PK11_KEY_LEN_MAX : ctx->key_len;
2586*7526SVladimir.Kotal@Sun.COM 	memcpy(sp->opdata_key, key, sp->opdata_key_len);
25870Sstevel@tonic-gate err:
25880Sstevel@tonic-gate 
25890Sstevel@tonic-gate 	return h_key;
25900Sstevel@tonic-gate 	}
25910Sstevel@tonic-gate 
25920Sstevel@tonic-gate static int
25930Sstevel@tonic-gate md_nid_to_pk11(int nid)
25940Sstevel@tonic-gate 	{
25950Sstevel@tonic-gate 	int i;
25960Sstevel@tonic-gate 
25970Sstevel@tonic-gate 	for (i = 0; i < PK11_DIGEST_MAX; i++)
25980Sstevel@tonic-gate 		if (digests[i].nid == nid)
25990Sstevel@tonic-gate 			return (digests[i].id);
26000Sstevel@tonic-gate 	return (-1);
26010Sstevel@tonic-gate 	}
26020Sstevel@tonic-gate 
26030Sstevel@tonic-gate static int
26040Sstevel@tonic-gate pk11_digest_init(EVP_MD_CTX *ctx)
26050Sstevel@tonic-gate         {
26060Sstevel@tonic-gate 	CK_RV rv;
26074320Sjp161948 	CK_MECHANISM mech;
26080Sstevel@tonic-gate 	int index;
26090Sstevel@tonic-gate 	PK11_SESSION *sp;
26100Sstevel@tonic-gate 	PK11_DIGEST *pdp;
26110Sstevel@tonic-gate 	PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->md_data;
26120Sstevel@tonic-gate 
26130Sstevel@tonic-gate 	state->sp = NULL;
26140Sstevel@tonic-gate 
26150Sstevel@tonic-gate 	index = md_nid_to_pk11(ctx->digest->type);
26160Sstevel@tonic-gate 	if (index < 0 || index >= PK11_DIGEST_MAX)
26170Sstevel@tonic-gate 		return 0;
26180Sstevel@tonic-gate 
26190Sstevel@tonic-gate 	pdp = &digests[index];
26207211Sjp161948 	if ((sp = pk11_get_session(OP_DIGEST)) == NULL)
26210Sstevel@tonic-gate 		return 0;
26220Sstevel@tonic-gate 
26234320Sjp161948 	/* at present, no parameter is needed for supported digests */
26244320Sjp161948 	mech.mechanism = pdp->mech_type;
26254320Sjp161948 	mech.pParameter = NULL;
26264320Sjp161948 	mech.ulParameterLen = 0;
26274320Sjp161948 
26284320Sjp161948 	rv = pFuncList->C_DigestInit(sp->session, &mech);
26290Sstevel@tonic-gate 
26300Sstevel@tonic-gate 	if (rv != CKR_OK)
26310Sstevel@tonic-gate 		{
26327211Sjp161948 		PK11err_add_data(PK11_F_DIGEST_INIT, PK11_R_DIGESTINIT, rv);
26337211Sjp161948 		pk11_return_session(sp, OP_DIGEST);
26340Sstevel@tonic-gate 		return 0;
26350Sstevel@tonic-gate 		}
26360Sstevel@tonic-gate 
26370Sstevel@tonic-gate 	state->sp = sp;
26380Sstevel@tonic-gate 
26390Sstevel@tonic-gate 	return 1;
26400Sstevel@tonic-gate 	}
26410Sstevel@tonic-gate 
26420Sstevel@tonic-gate static int
26432139Sjp161948 pk11_digest_update(EVP_MD_CTX *ctx,const void *data,size_t count)
26440Sstevel@tonic-gate         {
26450Sstevel@tonic-gate 	CK_RV rv;
26460Sstevel@tonic-gate 	PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->md_data;
26470Sstevel@tonic-gate 
26480Sstevel@tonic-gate 	/* 0 length message will cause a failure in C_DigestFinal */
26490Sstevel@tonic-gate 	if (count == 0)
26500Sstevel@tonic-gate 		return 1;
26510Sstevel@tonic-gate 
26520Sstevel@tonic-gate 	if (state == NULL || state->sp == NULL)
26530Sstevel@tonic-gate 		return 0;
26540Sstevel@tonic-gate 
26550Sstevel@tonic-gate 	rv = pFuncList->C_DigestUpdate(state->sp->session, (CK_BYTE *) data,
26560Sstevel@tonic-gate 		count);
26570Sstevel@tonic-gate 
26580Sstevel@tonic-gate 	if (rv != CKR_OK)
26590Sstevel@tonic-gate 		{
26607211Sjp161948 		PK11err_add_data(PK11_F_DIGEST_UPDATE, PK11_R_DIGESTUPDATE, rv);
26617211Sjp161948 		pk11_return_session(state->sp, OP_DIGEST);
26620Sstevel@tonic-gate 		state->sp = NULL;
26630Sstevel@tonic-gate 		return 0;
26640Sstevel@tonic-gate 		}
26650Sstevel@tonic-gate 
26660Sstevel@tonic-gate 	return 1;
26670Sstevel@tonic-gate 	}
26680Sstevel@tonic-gate 
26690Sstevel@tonic-gate static int
26700Sstevel@tonic-gate pk11_digest_final(EVP_MD_CTX *ctx,unsigned char *md)
26710Sstevel@tonic-gate         {
26720Sstevel@tonic-gate 	CK_RV rv;
26730Sstevel@tonic-gate 	unsigned long len;
26740Sstevel@tonic-gate 	PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->md_data;
26750Sstevel@tonic-gate 	len = ctx->digest->md_size;
26760Sstevel@tonic-gate 
26770Sstevel@tonic-gate 	if (state == NULL || state->sp == NULL)
26780Sstevel@tonic-gate 		return 0;
26790Sstevel@tonic-gate 
26800Sstevel@tonic-gate 	rv = pFuncList->C_DigestFinal(state->sp->session, md, &len);
26810Sstevel@tonic-gate 
26820Sstevel@tonic-gate 	if (rv != CKR_OK)
26830Sstevel@tonic-gate 		{
26847211Sjp161948 		PK11err_add_data(PK11_F_DIGEST_FINAL, PK11_R_DIGESTFINAL, rv);
26857211Sjp161948 		pk11_return_session(state->sp, OP_DIGEST);
26860Sstevel@tonic-gate 		state->sp = NULL;
26870Sstevel@tonic-gate 		return 0;
26880Sstevel@tonic-gate 		}
26890Sstevel@tonic-gate 
26900Sstevel@tonic-gate 	if (ctx->digest->md_size != len)
26910Sstevel@tonic-gate 		return 0;
26920Sstevel@tonic-gate 
26930Sstevel@tonic-gate 	/* Final is called and digest is returned, so return the session
26940Sstevel@tonic-gate 	 * to the pool
26950Sstevel@tonic-gate 	 */
26967211Sjp161948 	pk11_return_session(state->sp, OP_DIGEST);
26970Sstevel@tonic-gate 	state->sp = NULL;
26980Sstevel@tonic-gate 
26990Sstevel@tonic-gate 	return 1;
27000Sstevel@tonic-gate 	}
27010Sstevel@tonic-gate 
27020Sstevel@tonic-gate static int
27030Sstevel@tonic-gate pk11_digest_copy(EVP_MD_CTX *to,const EVP_MD_CTX *from)
27040Sstevel@tonic-gate         {
27050Sstevel@tonic-gate 	CK_RV rv;
27060Sstevel@tonic-gate 	int ret = 0;
27070Sstevel@tonic-gate 	PK11_CIPHER_STATE *state, *state_to;
27080Sstevel@tonic-gate 	CK_BYTE_PTR pstate = NULL;
27090Sstevel@tonic-gate 	CK_ULONG ul_state_len;
27100Sstevel@tonic-gate 
27110Sstevel@tonic-gate 	/* The copy-from state */
27120Sstevel@tonic-gate 	state = (PK11_CIPHER_STATE *) from->md_data;
27130Sstevel@tonic-gate 	if (state == NULL || state->sp == NULL)
27140Sstevel@tonic-gate 		goto err;
27150Sstevel@tonic-gate 
27160Sstevel@tonic-gate 	/* Initialize the copy-to state */
27170Sstevel@tonic-gate 	if (!pk11_digest_init(to))
27180Sstevel@tonic-gate 		goto err;
27190Sstevel@tonic-gate 	state_to = (PK11_CIPHER_STATE *) to->md_data;
27200Sstevel@tonic-gate 
27210Sstevel@tonic-gate 	/* Get the size of the operation state of the copy-from session */
27220Sstevel@tonic-gate 	rv = pFuncList->C_GetOperationState(state->sp->session, NULL,
27230Sstevel@tonic-gate 		&ul_state_len);
27240Sstevel@tonic-gate 
27250Sstevel@tonic-gate 	if (rv != CKR_OK)
27260Sstevel@tonic-gate 		{
27277211Sjp161948 		PK11err_add_data(PK11_F_DIGEST_COPY, PK11_R_GET_OPERATION_STATE,
27287211Sjp161948 		    rv);
27290Sstevel@tonic-gate 		goto err;
27300Sstevel@tonic-gate 		}
27310Sstevel@tonic-gate 	if (ul_state_len == 0)
27320Sstevel@tonic-gate 		{
27330Sstevel@tonic-gate 		goto err;
27340Sstevel@tonic-gate 		}
27350Sstevel@tonic-gate 
27360Sstevel@tonic-gate 	pstate = OPENSSL_malloc(ul_state_len);
27370Sstevel@tonic-gate 	if (pstate == NULL)
27380Sstevel@tonic-gate 		{
27396847Svk199839 		PK11err(PK11_F_DIGEST_COPY, PK11_R_MALLOC_FAILURE);
27400Sstevel@tonic-gate 		goto err;
27410Sstevel@tonic-gate 		}
27420Sstevel@tonic-gate 
27430Sstevel@tonic-gate 	/* Get the operation state of the copy-from session */
27440Sstevel@tonic-gate 	rv = pFuncList->C_GetOperationState(state->sp->session, pstate,
27450Sstevel@tonic-gate 		&ul_state_len);
27460Sstevel@tonic-gate 
27470Sstevel@tonic-gate 	if (rv != CKR_OK)
27480Sstevel@tonic-gate 		{
27497211Sjp161948 		PK11err_add_data(PK11_F_DIGEST_COPY, PK11_R_GET_OPERATION_STATE,
27507211Sjp161948 		    rv);
27510Sstevel@tonic-gate 		goto err;
27520Sstevel@tonic-gate 		}
27530Sstevel@tonic-gate 
27540Sstevel@tonic-gate 	/* Set the operation state of the copy-to session */
27550Sstevel@tonic-gate 	rv = pFuncList->C_SetOperationState(state_to->sp->session, pstate,
27560Sstevel@tonic-gate 		ul_state_len, 0, 0);
27570Sstevel@tonic-gate 
27580Sstevel@tonic-gate 	if (rv != CKR_OK)
27590Sstevel@tonic-gate 		{
27607211Sjp161948 		PK11err_add_data(PK11_F_DIGEST_COPY, PK11_R_SET_OPERATION_STATE, rv);
27610Sstevel@tonic-gate 		goto err;
27620Sstevel@tonic-gate 		}
27630Sstevel@tonic-gate 
27640Sstevel@tonic-gate 	ret = 1;
27650Sstevel@tonic-gate err:
27660Sstevel@tonic-gate 	if (pstate != NULL)
27670Sstevel@tonic-gate 		OPENSSL_free(pstate);
27680Sstevel@tonic-gate 
27690Sstevel@tonic-gate 	return ret;
27700Sstevel@tonic-gate 	}
27710Sstevel@tonic-gate 
27720Sstevel@tonic-gate /* Return any pending session state to the pool */
27730Sstevel@tonic-gate static int
27740Sstevel@tonic-gate pk11_digest_cleanup(EVP_MD_CTX *ctx)
27750Sstevel@tonic-gate 	{
27760Sstevel@tonic-gate 	PK11_CIPHER_STATE *state = ctx->md_data;
27774602Sjp161948 	unsigned char buf[EVP_MAX_MD_SIZE];
27780Sstevel@tonic-gate 
27790Sstevel@tonic-gate 	if (state != NULL && state->sp != NULL)
27800Sstevel@tonic-gate 		{
27814602Sjp161948 		/*
27824602Sjp161948 		 * If state->sp is not NULL then pk11_digest_final() has not
27834602Sjp161948 		 * been called yet. We must call it now to free any memory
27844602Sjp161948 		 * that might have been allocated in the token when
27854602Sjp161948 		 * pk11_digest_init() was called.
27864602Sjp161948 		 */
2787*7526SVladimir.Kotal@Sun.COM 		(void) pk11_digest_final(ctx, buf);
27887211Sjp161948 		pk11_return_session(state->sp, OP_DIGEST);
27890Sstevel@tonic-gate 		state->sp = NULL;
27900Sstevel@tonic-gate 		}
27910Sstevel@tonic-gate 
27920Sstevel@tonic-gate 	return 1;
27930Sstevel@tonic-gate 	}
27940Sstevel@tonic-gate 
27956847Svk199839 /*
27967211Sjp161948  * Check if the new key is the same as the key object in the session. If the key
27977211Sjp161948  * is the same, no need to create a new key object. Otherwise, the old key
27987211Sjp161948  * object needs to be destroyed and a new one will be created. Return 1 for
27997211Sjp161948  * cache hit, 0 for cache miss. Note that we must check the key length first
28007211Sjp161948  * otherwise we could end up reusing a different, longer key with the same
28017211Sjp161948  * prefix.
28020Sstevel@tonic-gate  */
28037211Sjp161948 static int check_new_cipher_key(PK11_SESSION *sp, const unsigned char *key,
28047211Sjp161948 	int key_len)
28050Sstevel@tonic-gate 	{
2806*7526SVladimir.Kotal@Sun.COM 	if (sp->opdata_key_len != key_len ||
2807*7526SVladimir.Kotal@Sun.COM 	    memcmp(sp->opdata_key, key, key_len) != 0)
28086847Svk199839 		{
28097211Sjp161948 		(void) pk11_destroy_cipher_key_objects(sp);
28106847Svk199839 		return (0);
28116847Svk199839 		}
28126847Svk199839 	return (1);
28130Sstevel@tonic-gate 	}
28140Sstevel@tonic-gate 
28150Sstevel@tonic-gate /* Destroy one or more secret key objects.
28160Sstevel@tonic-gate  */
28170Sstevel@tonic-gate static int pk11_destroy_cipher_key_objects(PK11_SESSION *session)
28180Sstevel@tonic-gate 	{
28190Sstevel@tonic-gate 	int ret = 0;
28200Sstevel@tonic-gate 	PK11_SESSION *sp = NULL;
28210Sstevel@tonic-gate 	PK11_SESSION *local_free_session;
28220Sstevel@tonic-gate 
2823*7526SVladimir.Kotal@Sun.COM 	if (session != NULL)
28240Sstevel@tonic-gate 		local_free_session = session;
28250Sstevel@tonic-gate 	else
2826*7526SVladimir.Kotal@Sun.COM 		{
2827*7526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_lock(session_cache[OP_CIPHER].lock);
2828*7526SVladimir.Kotal@Sun.COM 		local_free_session = session_cache[OP_CIPHER].head;
2829*7526SVladimir.Kotal@Sun.COM 		}
2830*7526SVladimir.Kotal@Sun.COM 
28310Sstevel@tonic-gate 	while ((sp = local_free_session) != NULL)
28320Sstevel@tonic-gate 		{
28330Sstevel@tonic-gate 		local_free_session = sp->next;
28340Sstevel@tonic-gate 
2835*7526SVladimir.Kotal@Sun.COM 		if (sp->opdata_cipher_key != CK_INVALID_HANDLE)
28360Sstevel@tonic-gate 			{
28370Sstevel@tonic-gate 			/* The secret key object is created in the
28380Sstevel@tonic-gate 			 * global_session. See pk11_get_cipher_key
28390Sstevel@tonic-gate 			 */
28400Sstevel@tonic-gate 			if (pk11_destroy_object(global_session,
2841*7526SVladimir.Kotal@Sun.COM 				sp->opdata_cipher_key) == 0)
28420Sstevel@tonic-gate 				goto err;
2843*7526SVladimir.Kotal@Sun.COM 			sp->opdata_cipher_key = CK_INVALID_HANDLE;
28440Sstevel@tonic-gate 			}
28450Sstevel@tonic-gate 		}
28460Sstevel@tonic-gate 	ret = 1;
28470Sstevel@tonic-gate err:
2848*7526SVladimir.Kotal@Sun.COM 
2849*7526SVladimir.Kotal@Sun.COM 	if (session == NULL)
2850*7526SVladimir.Kotal@Sun.COM 		(void) pthread_mutex_unlock(session_cache[OP_CIPHER].lock);
28510Sstevel@tonic-gate 
28520Sstevel@tonic-gate 	return ret;
28530Sstevel@tonic-gate 	}
28540Sstevel@tonic-gate 
28550Sstevel@tonic-gate 
28560Sstevel@tonic-gate /*
28577211Sjp161948  * Public key mechanisms optionally supported
28580Sstevel@tonic-gate  *
28590Sstevel@tonic-gate  * CKM_RSA_X_509
28600Sstevel@tonic-gate  * CKM_RSA_PKCS
28610Sstevel@tonic-gate  * CKM_DSA
28620Sstevel@tonic-gate  *
28637211Sjp161948  * The first slot that supports at least one of those mechanisms is chosen as a
28647211Sjp161948  * public key slot.
28650Sstevel@tonic-gate  *
28660Sstevel@tonic-gate  * Symmetric ciphers optionally supported
28670Sstevel@tonic-gate  *
28680Sstevel@tonic-gate  * CKM_DES3_CBC
28690Sstevel@tonic-gate  * CKM_DES_CBC
28700Sstevel@tonic-gate  * CKM_AES_CBC
28717211Sjp161948  * CKM_DES3_ECB
28727211Sjp161948  * CKM_DES_ECB
28737211Sjp161948  * CKM_AES_ECB
28747211Sjp161948  * CKM_AES_CTR
28750Sstevel@tonic-gate  * CKM_RC4
28767211Sjp161948  * CKM_BLOWFISH_CBC
28770Sstevel@tonic-gate  *
28780Sstevel@tonic-gate  * Digests optionally supported
28790Sstevel@tonic-gate  *
28800Sstevel@tonic-gate  * CKM_MD5
28810Sstevel@tonic-gate  * CKM_SHA_1
28827211Sjp161948  * CKM_SHA224
28837211Sjp161948  * CKM_SHA256
28847211Sjp161948  * CKM_SHA384
28857211Sjp161948  * CKM_SHA512
28867211Sjp161948  *
28877211Sjp161948  * The output of this function is a set of global variables indicating which
28887211Sjp161948  * mechanisms from RSA, DSA, DH and RAND are present, and also two arrays of
28897211Sjp161948  * mechanisms, one for symmetric ciphers and one for digests. Also, 3 global
28907211Sjp161948  * variables carry information about which slot was chosen for (a) public key
28917211Sjp161948  * mechanisms, (b) random operations, and (c) symmetric ciphers and digests.
28920Sstevel@tonic-gate  */
28930Sstevel@tonic-gate static int
28947211Sjp161948 pk11_choose_slots(int *any_slot_found)
28950Sstevel@tonic-gate 	{
28960Sstevel@tonic-gate 	CK_SLOT_ID_PTR pSlotList = NULL_PTR;
28970Sstevel@tonic-gate 	CK_ULONG ulSlotCount = 0;
28980Sstevel@tonic-gate 	CK_MECHANISM_INFO mech_info;
28990Sstevel@tonic-gate 	CK_TOKEN_INFO token_info;
29000Sstevel@tonic-gate 	int i;
29010Sstevel@tonic-gate 	CK_RV rv;
29020Sstevel@tonic-gate 	CK_SLOT_ID best_slot_sofar;
29030Sstevel@tonic-gate 	CK_BBOOL found_candidate_slot = CK_FALSE;
29040Sstevel@tonic-gate 	int slot_n_cipher = 0;
29050Sstevel@tonic-gate 	int slot_n_digest = 0;
29060Sstevel@tonic-gate 	CK_SLOT_ID current_slot = 0;
29070Sstevel@tonic-gate 	int current_slot_n_cipher = 0;
29080Sstevel@tonic-gate 	int current_slot_n_digest = 0;
29090Sstevel@tonic-gate 
29100Sstevel@tonic-gate 	int local_cipher_nids[PK11_CIPHER_MAX];
29110Sstevel@tonic-gate 	int local_digest_nids[PK11_DIGEST_MAX];
29127211Sjp161948 
29137211Sjp161948 	/* let's initialize the output parameter */
29147211Sjp161948 	if (any_slot_found != NULL)
29157211Sjp161948 		*any_slot_found = 0;
29167211Sjp161948 
29177211Sjp161948 	/* Get slot list for memory allocation */
29180Sstevel@tonic-gate 	rv = pFuncList->C_GetSlotList(0, NULL_PTR, &ulSlotCount);
29190Sstevel@tonic-gate 
29200Sstevel@tonic-gate 	if (rv != CKR_OK)
29210Sstevel@tonic-gate 		{
29227211Sjp161948 		PK11err_add_data(PK11_F_CHOOSE_SLOT, PK11_R_GETSLOTLIST, rv);
29237211Sjp161948 		return 0;
29240Sstevel@tonic-gate 		}
29250Sstevel@tonic-gate 
29267211Sjp161948 	/* it's not an error if we didn't find any providers */
29270Sstevel@tonic-gate 	if (ulSlotCount == 0)
29280Sstevel@tonic-gate 		{
29297211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
29307211Sjp161948 		fprintf(stderr, "%s: no crypto providers found\n", PK11_DBG);
29317211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
29327211Sjp161948 		return 1;
29330Sstevel@tonic-gate 		}
29340Sstevel@tonic-gate 
29350Sstevel@tonic-gate 	pSlotList = OPENSSL_malloc(ulSlotCount * sizeof (CK_SLOT_ID));
29360Sstevel@tonic-gate 
29370Sstevel@tonic-gate 	if (pSlotList == NULL)
29380Sstevel@tonic-gate 		{
29396847Svk199839 		PK11err(PK11_F_CHOOSE_SLOT, PK11_R_MALLOC_FAILURE);
29407211Sjp161948 		return 0;
29410Sstevel@tonic-gate 		}
29420Sstevel@tonic-gate 
29430Sstevel@tonic-gate 	/* Get the slot list for processing */
29440Sstevel@tonic-gate 	rv = pFuncList->C_GetSlotList(0, pSlotList, &ulSlotCount);
29450Sstevel@tonic-gate 	if (rv != CKR_OK)
29460Sstevel@tonic-gate 		{
29477211Sjp161948 		PK11err_add_data(PK11_F_CHOOSE_SLOT, PK11_R_GETSLOTLIST, rv);
29480Sstevel@tonic-gate 		OPENSSL_free(pSlotList);
29497211Sjp161948 		return 0;
29500Sstevel@tonic-gate 		}
29510Sstevel@tonic-gate 
29527211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
29537211Sjp161948 	fprintf(stderr, "%s: provider: %s\n", PK11_DBG, def_PK11_LIBNAME);
29547211Sjp161948 	fprintf(stderr, "%s: number of slots: %d\n", PK11_DBG, ulSlotCount);
29557211Sjp161948 
29567211Sjp161948 	fprintf(stderr, "%s: == checking rand slots ==\n", PK11_DBG);
29577211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
29587211Sjp161948 	for (i = 0; i < ulSlotCount; i++)
29597211Sjp161948 		{
29607211Sjp161948 		current_slot = pSlotList[i];
29617211Sjp161948 
29627211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
29637211Sjp161948 	fprintf(stderr, "%s: checking slot: %d\n", PK11_DBG, i);
29647211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
29657211Sjp161948 		/* Check if slot has random support. */
29667211Sjp161948 		rv = pFuncList->C_GetTokenInfo(current_slot, &token_info);
29677211Sjp161948 		if (rv != CKR_OK)
29687211Sjp161948 			continue;
29697211Sjp161948 
29707211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
29717211Sjp161948 	fprintf(stderr, "%s: token label: %.32s\n", PK11_DBG, token_info.label);
29727211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
29737211Sjp161948 
29747211Sjp161948 		if (token_info.flags & CKF_RNG)
29757211Sjp161948 			{
29767211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
29777211Sjp161948 	fprintf(stderr, "%s: this token has CKF_RNG flag\n", PK11_DBG);
29787211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
29797211Sjp161948 			pk11_have_random = CK_TRUE;
29807211Sjp161948 			break;
29817211Sjp161948 			}
29827211Sjp161948 		}
29837211Sjp161948 
29847211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
29857211Sjp161948 	fprintf(stderr, "%s: == checking pubkey slots ==\n", PK11_DBG);
29867211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
29870Sstevel@tonic-gate 	for (i = 0; i < ulSlotCount; i++)
29880Sstevel@tonic-gate 		{
29890Sstevel@tonic-gate 		CK_BBOOL slot_has_rsa = CK_FALSE;
29900Sstevel@tonic-gate 		CK_BBOOL slot_has_dsa = CK_FALSE;
29910Sstevel@tonic-gate 		CK_BBOOL slot_has_dh = CK_FALSE;
29920Sstevel@tonic-gate 		current_slot = pSlotList[i];
29937211Sjp161948 
29947211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
29957211Sjp161948 	fprintf(stderr, "%s: checking slot: %d\n", PK11_DBG, i);
29967211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
29970Sstevel@tonic-gate 		rv = pFuncList->C_GetTokenInfo(current_slot, &token_info);
29980Sstevel@tonic-gate 		if (rv != CKR_OK)
29990Sstevel@tonic-gate 			continue;
30000Sstevel@tonic-gate 
30017211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
30027211Sjp161948 	fprintf(stderr, "%s: token label: %.32s\n", PK11_DBG, token_info.label);
30037211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
30047211Sjp161948 
30056847Svk199839 #ifndef OPENSSL_NO_RSA
30060Sstevel@tonic-gate 		/*
30070Sstevel@tonic-gate 		 * Check if this slot is capable of signing and
30080Sstevel@tonic-gate 		 * verifying with CKM_RSA_PKCS.
30090Sstevel@tonic-gate 		 */
30100Sstevel@tonic-gate 		rv = pFuncList->C_GetMechanismInfo(current_slot, CKM_RSA_PKCS,
30110Sstevel@tonic-gate 			&mech_info);
30120Sstevel@tonic-gate 
30130Sstevel@tonic-gate 		if (rv == CKR_OK && ((mech_info.flags & CKF_SIGN) &&
30140Sstevel@tonic-gate 				(mech_info.flags & CKF_VERIFY)))
30150Sstevel@tonic-gate 			{
30160Sstevel@tonic-gate 			/*
30170Sstevel@tonic-gate 			 * Check if this slot is capable of encryption,
30180Sstevel@tonic-gate 			 * decryption, sign, and verify with CKM_RSA_X_509.
30190Sstevel@tonic-gate 			 */
30200Sstevel@tonic-gate 			rv = pFuncList->C_GetMechanismInfo(current_slot,
30210Sstevel@tonic-gate 			  CKM_RSA_X_509, &mech_info);
30220Sstevel@tonic-gate 
30230Sstevel@tonic-gate 			if (rv == CKR_OK && ((mech_info.flags & CKF_SIGN) &&
30240Sstevel@tonic-gate 			    (mech_info.flags & CKF_VERIFY) &&
30250Sstevel@tonic-gate 			    (mech_info.flags & CKF_ENCRYPT) &&
30260Sstevel@tonic-gate 			    (mech_info.flags & CKF_VERIFY_RECOVER) &&
30270Sstevel@tonic-gate 			    (mech_info.flags & CKF_DECRYPT)))
30287211Sjp161948 				{
30290Sstevel@tonic-gate 				slot_has_rsa = CK_TRUE;
30307211Sjp161948 				}
30310Sstevel@tonic-gate 			}
30327211Sjp161948 #endif	/* OPENSSL_NO_RSA */
30337211Sjp161948 
30346847Svk199839 #ifndef OPENSSL_NO_DSA
30350Sstevel@tonic-gate 		/*
30360Sstevel@tonic-gate 		 * Check if this slot is capable of signing and
30370Sstevel@tonic-gate 		 * verifying with CKM_DSA.
30380Sstevel@tonic-gate 		 */
30390Sstevel@tonic-gate 		rv = pFuncList->C_GetMechanismInfo(current_slot, CKM_DSA,
30400Sstevel@tonic-gate 			&mech_info);
30410Sstevel@tonic-gate 		if (rv == CKR_OK && ((mech_info.flags & CKF_SIGN) &&
30420Sstevel@tonic-gate 		    (mech_info.flags & CKF_VERIFY)))
30437211Sjp161948 			{
30440Sstevel@tonic-gate 			slot_has_dsa = CK_TRUE;
30457211Sjp161948 			}
3046*7526SVladimir.Kotal@Sun.COM 
30477211Sjp161948 #endif	/* OPENSSL_NO_DSA */
30487211Sjp161948 
30496847Svk199839 #ifndef OPENSSL_NO_DH
30500Sstevel@tonic-gate 		/*
30510Sstevel@tonic-gate 		 * Check if this slot is capable of DH key generataion and
30520Sstevel@tonic-gate 		 * derivation.
30530Sstevel@tonic-gate 		 */
30540Sstevel@tonic-gate 		rv = pFuncList->C_GetMechanismInfo(current_slot,
30550Sstevel@tonic-gate 		  CKM_DH_PKCS_KEY_PAIR_GEN, &mech_info);
30560Sstevel@tonic-gate 
30570Sstevel@tonic-gate 		if (rv == CKR_OK && (mech_info.flags & CKF_GENERATE_KEY_PAIR))
30580Sstevel@tonic-gate 			{
30590Sstevel@tonic-gate 			rv = pFuncList->C_GetMechanismInfo(current_slot,
30600Sstevel@tonic-gate 				CKM_DH_PKCS_DERIVE, &mech_info);
30610Sstevel@tonic-gate 			if (rv == CKR_OK && (mech_info.flags & CKF_DERIVE))
30627211Sjp161948 				{
30630Sstevel@tonic-gate 				slot_has_dh = CK_TRUE;
30647211Sjp161948 				}
30650Sstevel@tonic-gate 			}
30667211Sjp161948 #endif	/* OPENSSL_NO_DH */
30677211Sjp161948 
30680Sstevel@tonic-gate 		if (!found_candidate_slot &&
30690Sstevel@tonic-gate 		    (slot_has_rsa || slot_has_dsa || slot_has_dh))
30700Sstevel@tonic-gate 			{
30717211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
30720Sstevel@tonic-gate 			fprintf(stderr,
30737211Sjp161948 			  "%s: potential slot: %d\n", PK11_DBG, current_slot);
30747211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
30750Sstevel@tonic-gate 			best_slot_sofar = current_slot;
30760Sstevel@tonic-gate 			pk11_have_rsa = slot_has_rsa;
30770Sstevel@tonic-gate 			pk11_have_dsa = slot_has_dsa;
30780Sstevel@tonic-gate 			pk11_have_dh = slot_has_dh;
30790Sstevel@tonic-gate 			found_candidate_slot = CK_TRUE;
30807211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
30817211Sjp161948 			fprintf(stderr,
30827211Sjp161948 		            "%s: setting found_candidate_slot to CK_TRUE\n",
30837211Sjp161948 			    PK11_DBG);
30840Sstevel@tonic-gate 			fprintf(stderr,
30857211Sjp161948 		            "%s: best so far slot: %d\n", PK11_DBG,
30860Sstevel@tonic-gate 		    	    best_slot_sofar);
30877211Sjp161948 			}
30887211Sjp161948 		else
30897211Sjp161948 			{
30907211Sjp161948 			fprintf(stderr,
30917211Sjp161948 			  "%s: no rsa/dsa/dh\n", PK11_DBG);
30920Sstevel@tonic-gate 			}
30937211Sjp161948 #else
30947211Sjp161948 			} /* if */
30957211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
30967211Sjp161948 		} /* for */
30977211Sjp161948 
30987211Sjp161948 	if (found_candidate_slot)
30997211Sjp161948 		{
31007211Sjp161948 		pubkey_SLOTID = best_slot_sofar;
31017211Sjp161948 		}
31027211Sjp161948 
31037211Sjp161948 	found_candidate_slot = CK_FALSE;
31047211Sjp161948 	best_slot_sofar = 0;
31057211Sjp161948 
31067211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
31077211Sjp161948 	fprintf(stderr, "%s: == checking cipher/digest ==\n", PK11_DBG);
31087211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
31097211Sjp161948 	for (i = 0; i < ulSlotCount; i++)
31107211Sjp161948 		{
31117211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
31127211Sjp161948 	fprintf(stderr, "%s: checking slot: %d\n", PK11_DBG, i);
31137211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
31147211Sjp161948 
31157211Sjp161948 		current_slot = pSlotList[i];
31167211Sjp161948 		current_slot_n_cipher = 0;
31177211Sjp161948 		current_slot_n_digest = 0;
31187211Sjp161948 		memset(local_cipher_nids, 0, sizeof(local_cipher_nids));
31197211Sjp161948 		memset(local_digest_nids, 0, sizeof(local_digest_nids));
31207211Sjp161948 
31217211Sjp161948 		pk11_find_symmetric_ciphers(pFuncList, current_slot,
31227211Sjp161948 		    &current_slot_n_cipher, local_cipher_nids);
31237211Sjp161948 
31247211Sjp161948 		pk11_find_digests(pFuncList, current_slot,
31257211Sjp161948 		    &current_slot_n_digest, local_digest_nids);
31267211Sjp161948 
31277211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
31287211Sjp161948 		fprintf(stderr, "%s: current_slot_n_cipher %d\n", PK11_DBG,
31297211Sjp161948 			current_slot_n_cipher);
31307211Sjp161948 		fprintf(stderr, "%s: current_slot_n_digest %d\n", PK11_DBG,
31317211Sjp161948 			current_slot_n_digest);
31327211Sjp161948 		fprintf(stderr, "%s: best so far cipher/digest slot: %d\n",
31337211Sjp161948 			PK11_DBG, best_slot_sofar);
31347211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
31350Sstevel@tonic-gate 
31360Sstevel@tonic-gate 		/*
31370Sstevel@tonic-gate 		 * If the current slot supports more ciphers/digests than
31387250Sjp161948 		 * the previous best one we change the current best to this one,
31390Sstevel@tonic-gate 		 * otherwise leave it where it is.
31400Sstevel@tonic-gate 		 */
31417250Sjp161948 		if ((current_slot_n_cipher + current_slot_n_digest) >
31427250Sjp161948 		    (slot_n_cipher + slot_n_digest))
31430Sstevel@tonic-gate 			{
31447211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
31457211Sjp161948 			fprintf(stderr,
31467211Sjp161948 				"%s: changing best so far slot to %d\n",
31477211Sjp161948 				PK11_DBG, current_slot);
31487211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
31497211Sjp161948 			best_slot_sofar = SLOTID = current_slot;
31507250Sjp161948 			cipher_count = slot_n_cipher = current_slot_n_cipher;
31517250Sjp161948 			digest_count = slot_n_digest = current_slot_n_digest;
31527250Sjp161948 			memcpy(cipher_nids, local_cipher_nids,
3153*7526SVladimir.Kotal@Sun.COM 			    sizeof (local_cipher_nids));
3154*7526SVladimir.Kotal@Sun.COM 			memcpy(digest_nids, local_digest_nids,
3155*7526SVladimir.Kotal@Sun.COM 			    sizeof (local_digest_nids));
31560Sstevel@tonic-gate 			}
31570Sstevel@tonic-gate 		}
31580Sstevel@tonic-gate 
31597211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
31607211Sjp161948 	fprintf(stderr,
3161*7526SVladimir.Kotal@Sun.COM 	    "%s: chosen pubkey slot: %d\n", PK11_DBG, pubkey_SLOTID);
31620Sstevel@tonic-gate 	fprintf(stderr,
3163*7526SVladimir.Kotal@Sun.COM 	    "%s: chosen rand slot: %d\n", PK11_DBG, rand_SLOTID);
31640Sstevel@tonic-gate 	fprintf(stderr,
3165*7526SVladimir.Kotal@Sun.COM 	    "%s: chosen cipher/digest slot: %d\n", PK11_DBG, SLOTID);
31667211Sjp161948 	fprintf(stderr,
3167*7526SVladimir.Kotal@Sun.COM 	    "%s: pk11_have_rsa %d\n", PK11_DBG, pk11_have_rsa);
31680Sstevel@tonic-gate 	fprintf(stderr,
3169*7526SVladimir.Kotal@Sun.COM 	    "%s: pk11_have_dsa %d\n", PK11_DBG, pk11_have_dsa);
31707211Sjp161948 	fprintf(stderr,
3171*7526SVladimir.Kotal@Sun.COM 	    "%s: pk11_have_dh %d\n", PK11_DBG, pk11_have_dh);
31720Sstevel@tonic-gate 	fprintf(stderr,
3173*7526SVladimir.Kotal@Sun.COM 	    "%s: pk11_have_random %d\n", PK11_DBG, pk11_have_random);
31740Sstevel@tonic-gate 	fprintf(stderr,
3175*7526SVladimir.Kotal@Sun.COM 	    "%s: cipher_count %d\n", PK11_DBG, cipher_count);
31767211Sjp161948 	fprintf(stderr,
3177*7526SVladimir.Kotal@Sun.COM 	    "%s: digest_count %d\n", PK11_DBG, digest_count);
31787211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
31790Sstevel@tonic-gate 
31806847Svk199839 	if (pSlotList != NULL)
31816847Svk199839 		OPENSSL_free(pSlotList);
31820Sstevel@tonic-gate 
31837211Sjp161948 #ifdef	SOLARIS_HW_SLOT_SELECTION
31847211Sjp161948 	OPENSSL_free(hw_cnids);
31857211Sjp161948 	OPENSSL_free(hw_dnids);
31867211Sjp161948 #endif	/* SOLARIS_HW_SLOT_SELECTION */
31877211Sjp161948 
31887211Sjp161948 	if (any_slot_found != NULL)
31897211Sjp161948 		*any_slot_found = 1;
31907211Sjp161948 	return 1;
31910Sstevel@tonic-gate 	}
31920Sstevel@tonic-gate 
31937211Sjp161948 static void pk11_get_symmetric_cipher(CK_FUNCTION_LIST_PTR pflist,
31947211Sjp161948     int slot_id, CK_MECHANISM_TYPE mech, int *current_slot_n_cipher,
31957211Sjp161948     int *local_cipher_nids, int id)
31967211Sjp161948 	{
31977211Sjp161948 	CK_MECHANISM_INFO mech_info;
31987211Sjp161948 	CK_RV rv;
31997211Sjp161948 
32007211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
32017211Sjp161948 	fprintf(stderr, "%s: checking mech: %x", PK11_DBG, mech);
32027211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
32037211Sjp161948 	rv = pflist->C_GetMechanismInfo(slot_id, mech, &mech_info);
32047211Sjp161948 
32057211Sjp161948 	if (rv != CKR_OK)
32067211Sjp161948 		{
32077211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
32087211Sjp161948 		fprintf(stderr, " not found\n");
32097211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
32107211Sjp161948 		return;
32117211Sjp161948 		}
32127211Sjp161948 
32137211Sjp161948 	if ((mech_info.flags & CKF_ENCRYPT) &&
32147211Sjp161948 	    (mech_info.flags & CKF_DECRYPT))
32157211Sjp161948 		{
32167211Sjp161948 #ifdef	SOLARIS_HW_SLOT_SELECTION
32177211Sjp161948 		if (nid_in_table(ciphers[id].nid, hw_cnids))
32187211Sjp161948 #endif	/* SOLARIS_HW_SLOT_SELECTION */
32197211Sjp161948 			{
32207211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
32217211Sjp161948 		fprintf(stderr, " usable\n");
32227211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
32237211Sjp161948 			local_cipher_nids[(*current_slot_n_cipher)++] =
32247211Sjp161948 			    ciphers[id].nid;
32257211Sjp161948 			}
32267211Sjp161948 #ifdef	SOLARIS_HW_SLOT_SELECTION
32277211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
32287211Sjp161948 		else
32297211Sjp161948 			{
32307211Sjp161948 		fprintf(stderr, " rejected, software implementation only\n");
32317211Sjp161948 			}
32327211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
32337211Sjp161948 #endif	/* SOLARIS_HW_SLOT_SELECTION */
32347211Sjp161948 		}
32357211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
32367211Sjp161948 	else
32377211Sjp161948 		{
32387211Sjp161948 		fprintf(stderr, " unusable\n");
32397211Sjp161948 		}
32407211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
32417211Sjp161948 
32427211Sjp161948 	return;
32437211Sjp161948 	}
32447211Sjp161948 
32457211Sjp161948 static void pk11_get_digest(CK_FUNCTION_LIST_PTR pflist, int slot_id,
32467211Sjp161948     CK_MECHANISM_TYPE mech, int *current_slot_n_digest, int *local_digest_nids,
32477211Sjp161948     int id)
32480Sstevel@tonic-gate 	{
32490Sstevel@tonic-gate 	CK_MECHANISM_INFO mech_info;
32500Sstevel@tonic-gate 	CK_RV rv;
32510Sstevel@tonic-gate 
32527211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
32537211Sjp161948 	fprintf(stderr, "%s: checking mech: %x", PK11_DBG, mech);
32547211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
32557211Sjp161948 	rv = pflist->C_GetMechanismInfo(slot_id, mech, &mech_info);
32560Sstevel@tonic-gate 
32570Sstevel@tonic-gate 	if (rv != CKR_OK)
32580Sstevel@tonic-gate 		{
32597211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
32607211Sjp161948 		fprintf(stderr, " not found\n");
32617211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
32627211Sjp161948 		return;
32630Sstevel@tonic-gate 		}
32640Sstevel@tonic-gate 
32650Sstevel@tonic-gate 	if (mech_info.flags & CKF_DIGEST)
32660Sstevel@tonic-gate 		{
32677211Sjp161948 #ifdef	SOLARIS_HW_SLOT_SELECTION
32687211Sjp161948 	    	if (nid_in_table(digests[id].nid, hw_dnids))
32697211Sjp161948 #endif	/* SOLARIS_HW_SLOT_SELECTION */
32707211Sjp161948 			{
32717211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
32727211Sjp161948 		fprintf(stderr, " usable\n");
32737211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
32747211Sjp161948 			local_digest_nids[(*current_slot_n_digest)++] =
32757211Sjp161948 			    digests[id].nid;
32767211Sjp161948 			}
32777211Sjp161948 #ifdef	SOLARIS_HW_SLOT_SELECTION
32787211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
32797211Sjp161948 		else
32807211Sjp161948 			{
32817211Sjp161948 		fprintf(stderr, " rejected, software implementation only\n");
32827211Sjp161948 			}
32837211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
32847211Sjp161948 #endif	/* SOLARIS_HW_SLOT_SELECTION */
32857211Sjp161948 		}
32867211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
32877211Sjp161948 	else
32887211Sjp161948 		{
32897211Sjp161948 		fprintf(stderr, " unusable\n");
32900Sstevel@tonic-gate 		}
32917211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
32927211Sjp161948 
32937211Sjp161948 	return;
32947211Sjp161948 	}
32957211Sjp161948 
32967211Sjp161948 #ifdef	SOLARIS_AES_CTR
32977211Sjp161948 /* create a new NID when we have no OID for that mechanism */
32987211Sjp161948 static int pk11_add_NID(char *sn, char *ln)
32997211Sjp161948 	{
33007211Sjp161948 	ASN1_OBJECT *o;
33017211Sjp161948 	int nid;
33027211Sjp161948 
33037211Sjp161948 	if ((o = ASN1_OBJECT_create(OBJ_new_nid(1), (unsigned char *)"",
33047211Sjp161948 	    1, sn, ln)) == NULL)
33057211Sjp161948 		{
33067211Sjp161948 		return 0;
33077211Sjp161948 		}
33087211Sjp161948 
33097211Sjp161948 	/* will return NID_undef on error */
33107211Sjp161948 	nid = OBJ_add_object(o);
33117211Sjp161948 	ASN1_OBJECT_free(o);
33127211Sjp161948 
33137211Sjp161948 	return (nid);
33147211Sjp161948 	}
33157211Sjp161948 
33167211Sjp161948 /*
33177211Sjp161948  * Create new NIDs for AES counter mode. OpenSSL doesn't support them now so we
33187211Sjp161948  * have to help ourselves here.
33197211Sjp161948  */
33207211Sjp161948 static int pk11_add_aes_ctr_NIDs(void)
33217211Sjp161948 	{
33227211Sjp161948 	/* are we already set? */
33237211Sjp161948 	if (NID_aes_256_ctr != NID_undef)
33247211Sjp161948 		return 1;
33257211Sjp161948 
33267211Sjp161948 	/*
33277211Sjp161948 	 * There are no official names for AES counter modes yet so we just
33287211Sjp161948 	 * follow the format of those that exist.
33297211Sjp161948 	 */
33307211Sjp161948 	if ((NID_aes_128_ctr = pk11_add_NID("AES-128-CTR", "aes-128-ctr")) ==
33317211Sjp161948 	    NID_undef)
33327211Sjp161948 		goto err;
33337211Sjp161948 	ciphers[PK11_AES_128_CTR].nid = pk11_aes_128_ctr.nid = NID_aes_128_ctr;
33347211Sjp161948 	if ((NID_aes_192_ctr = pk11_add_NID("AES-192-CTR", "aes-192-ctr")) ==
33357211Sjp161948 	    NID_undef)
33367211Sjp161948 		goto err;
33377211Sjp161948 	ciphers[PK11_AES_192_CTR].nid = pk11_aes_192_ctr.nid = NID_aes_192_ctr;
33387211Sjp161948 	if ((NID_aes_256_ctr = pk11_add_NID("AES-256-CTR", "aes-256-ctr")) ==
33397211Sjp161948 	    NID_undef)
33407211Sjp161948 		goto err;
33417211Sjp161948 	ciphers[PK11_AES_256_CTR].nid = pk11_aes_256_ctr.nid = NID_aes_256_ctr;
33420Sstevel@tonic-gate 	return 1;
33437211Sjp161948 
33447211Sjp161948 err:
33457211Sjp161948 	PK11err(PK11_F_ADD_AES_CTR_NIDS, PK11_R_ADD_NID_FAILED);
33467211Sjp161948 	return 0;
33470Sstevel@tonic-gate 	}
33487211Sjp161948 #endif	/* SOLARIS_AES_CTR */
33497211Sjp161948 
33507211Sjp161948 /* Find what symmetric ciphers this slot supports. */
33517211Sjp161948 static void pk11_find_symmetric_ciphers(CK_FUNCTION_LIST_PTR pflist,
33527211Sjp161948     CK_SLOT_ID current_slot, int *current_slot_n_cipher, int *local_cipher_nids)
33537211Sjp161948 	{
33547211Sjp161948 	int i;
33557211Sjp161948 
33567211Sjp161948 	for (i = 0; i < PK11_CIPHER_MAX; ++i)
33577211Sjp161948 		{
33587211Sjp161948 		pk11_get_symmetric_cipher(pflist, current_slot,
33597211Sjp161948 		    ciphers[i].mech_type, current_slot_n_cipher,
33607211Sjp161948 		    local_cipher_nids, ciphers[i].id);
33617211Sjp161948 		}
33627211Sjp161948 	}
33637211Sjp161948 
33647211Sjp161948 /* Find what digest algorithms this slot supports. */
33657211Sjp161948 static void pk11_find_digests(CK_FUNCTION_LIST_PTR pflist,
33667211Sjp161948     CK_SLOT_ID current_slot, int *current_slot_n_digest, int *local_digest_nids)
33677211Sjp161948 	{
33687211Sjp161948 	int i;
33697211Sjp161948 
33707211Sjp161948 	for (i = 0; i < PK11_DIGEST_MAX; ++i)
33717211Sjp161948 		{
33727211Sjp161948 		pk11_get_digest(pflist, current_slot, digests[i].mech_type,
33737211Sjp161948 		    current_slot_n_digest, local_digest_nids, digests[i].id);
33747211Sjp161948 		}
33757211Sjp161948 	}
33767211Sjp161948 
33777211Sjp161948 #ifdef	SOLARIS_HW_SLOT_SELECTION
33787211Sjp161948 /*
33797211Sjp161948  * It would be great if we could use pkcs11_kernel directly since this library
33807211Sjp161948  * offers hardware slots only. That's the easiest way to achieve the situation
33817211Sjp161948  * where we use the hardware accelerators when present and OpenSSL native code
33827211Sjp161948  * otherwise. That presumes the fact that OpenSSL native code is faster than the
33837211Sjp161948  * code in the soft token. It's a logical assumption - Crypto Framework has some
33847211Sjp161948  * inherent overhead so going there for the software implementation of a
33857211Sjp161948  * mechanism should be logically slower in contrast to the OpenSSL native code,
33867211Sjp161948  * presuming that both implementations are of similar speed. For example, the
33877211Sjp161948  * soft token for AES is roughly three times slower than OpenSSL for 64 byte
33887211Sjp161948  * blocks and still 20% slower for 8KB blocks. So, if we want to ship products
33897211Sjp161948  * that use the PKCS#11 engine by default, we must somehow avoid that regression
33907211Sjp161948  * on machines without hardware acceleration. That's why switching to the
33917211Sjp161948  * pkcs11_kernel library seems like a very good idea.
33927211Sjp161948  *
33937211Sjp161948  * The problem is that OpenSSL built with SunStudio is roughly 2x slower for
33947211Sjp161948  * asymmetric operations (RSA/DSA/DH) than the soft token built with the same
33957211Sjp161948  * compiler. That means that if we switched to pkcs11_kernel from the libpkcs11
33967211Sjp161948  * library, we would have had a performance regression on machines without
33977211Sjp161948  * hardware acceleration for asymmetric operations for all applications that use
33987211Sjp161948  * the PKCS#11 engine. There is one such application - Apache web server since
33997211Sjp161948  * it's shipped configured to use the PKCS#11 engine by default. Having said
34007211Sjp161948  * that, we can't switch to the pkcs11_kernel library now and have to come with
34017211Sjp161948  * a solution that, on non-accelerated machines, uses the OpenSSL native code
34027211Sjp161948  * for all symmetric ciphers and digests while it uses the soft token for
34037211Sjp161948  * asymmetric operations.
34047211Sjp161948  *
34057211Sjp161948  * This is the idea: dlopen() pkcs11_kernel directly and find out what
34067211Sjp161948  * mechanisms are there. We don't care about duplications (more slots can
34077211Sjp161948  * support the same mechanism), we just want to know what mechanisms can be
34087211Sjp161948  * possibly supported in hardware on that particular machine. As said before,
34097211Sjp161948  * pkcs11_kernel will show you hardware providers only.
34107211Sjp161948  *
34117211Sjp161948  * Then, we rely on the fact that since we use libpkcs11 library we will find
34127211Sjp161948  * the metaslot. When we go through the metaslot's mechanisms for symmetric
34137211Sjp161948  * ciphers and digests, we check that any found mechanism is in the table
34147211Sjp161948  * created using the pkcs11_kernel library. So, as a result we have two arrays
34157211Sjp161948  * of mechanisms that were advertised as supported in hardware which was the
34167211Sjp161948  * goal of that whole excercise. Thus, we can use libpkcs11 but avoid soft token
34177211Sjp161948  * code for symmetric ciphers and digests. See pk11_choose_slots() for more
34187211Sjp161948  * information.
34197211Sjp161948  *
34207211Sjp161948  * This is Solaris specific code, if SOLARIS_HW_SLOT_SELECTION is not defined
34217211Sjp161948  * the code won't be used.
34227211Sjp161948  */
34237211Sjp161948 #if defined(__sparcv9) || defined(__x86_64) || defined(__amd64)
34247211Sjp161948 static const char pkcs11_kernel[] = "/usr/lib/security/64/pkcs11_kernel.so.1";
34257211Sjp161948 #else
34267211Sjp161948 static const char pkcs11_kernel[] = "/usr/lib/security/pkcs11_kernel.so.1";
34277211Sjp161948 #endif
34287211Sjp161948 
34297211Sjp161948 /*
34307211Sjp161948  * Check hardware capabilities of the machines. The output are two lists,
34317211Sjp161948  * hw_cnids and hw_dnids, that contain hardware mechanisms found in all hardware
34327211Sjp161948  * providers together. They are not sorted and may contain duplicate mechanisms.
34337211Sjp161948  */
34347211Sjp161948 static int check_hw_mechanisms(void)
34357211Sjp161948 	{
34367211Sjp161948 	int i;
34377211Sjp161948 	CK_RV rv;
34387211Sjp161948 	void *handle;
34397211Sjp161948 	CK_C_GetFunctionList p;
34407211Sjp161948 	CK_TOKEN_INFO token_info;
34417211Sjp161948 	CK_ULONG ulSlotCount = 0;
34427211Sjp161948 	int n_cipher = 0, n_digest = 0;
34437211Sjp161948 	CK_FUNCTION_LIST_PTR pflist = NULL;
34447211Sjp161948 	CK_SLOT_ID_PTR pSlotList = NULL_PTR;
34457211Sjp161948 	int *tmp_hw_cnids, *tmp_hw_dnids;
34467211Sjp161948 	int hw_ctable_size, hw_dtable_size;
34477211Sjp161948 
34487211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
34497211Sjp161948 	fprintf(stderr, "%s: SOLARIS_HW_SLOT_SELECTION code running\n",
34507211Sjp161948 	    PK11_DBG);
34510Sstevel@tonic-gate #endif
34527211Sjp161948 	if ((handle = dlopen(pkcs11_kernel, RTLD_LAZY)) == NULL)
34537211Sjp161948 		{
34547211Sjp161948 		PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_DSO_FAILURE);
34557211Sjp161948 		goto err;
34567211Sjp161948 		}
34577211Sjp161948 
34587211Sjp161948 	if ((p = (CK_C_GetFunctionList)dlsym(handle,
34597211Sjp161948 	    PK11_GET_FUNCTION_LIST)) == NULL)
34607211Sjp161948 		{
34617211Sjp161948 		PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_DSO_FAILURE);
34627211Sjp161948 		goto err;
34637211Sjp161948 		}
34647211Sjp161948 
34657211Sjp161948 	/* get the full function list from the loaded library
34667211Sjp161948 	 */
34677211Sjp161948 	if (p(&pflist) != CKR_OK)
34687211Sjp161948 		{
34697211Sjp161948 		PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_DSO_FAILURE);
34707211Sjp161948 		goto err;
34717211Sjp161948 		}
34727211Sjp161948 
34737211Sjp161948 	rv = pflist->C_Initialize(NULL_PTR);
34747211Sjp161948 	if ((rv != CKR_OK) && (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED))
34757211Sjp161948 		{
34767211Sjp161948 		PK11err_add_data(PK11_F_CHECK_HW_MECHANISMS,
34777211Sjp161948 		    PK11_R_INITIALIZE, rv);
34787211Sjp161948 		goto err;
34797211Sjp161948 		}
34807211Sjp161948 
34817211Sjp161948 	if (pflist->C_GetSlotList(0, NULL_PTR, &ulSlotCount) != CKR_OK)
34827211Sjp161948 		{
34837211Sjp161948 		PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_GETSLOTLIST);
34847211Sjp161948 		goto err;
34857211Sjp161948 		}
34867211Sjp161948 
34877211Sjp161948 	/* no slots, set the hw mechanism tables as empty */
34887211Sjp161948 	if (ulSlotCount == 0)
34897211Sjp161948 		{
34907211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
34917211Sjp161948 	fprintf(stderr, "%s: no hardware mechanisms found\n", PK11_DBG);
34920Sstevel@tonic-gate #endif
34937211Sjp161948 		hw_cnids = OPENSSL_malloc(sizeof (int));
34947211Sjp161948 		hw_dnids = OPENSSL_malloc(sizeof (int));
34957211Sjp161948 		if (hw_cnids == NULL || hw_dnids == NULL)
34967211Sjp161948 			{
34977211Sjp161948 			PK11err(PK11_F_CHECK_HW_MECHANISMS,
34987211Sjp161948 			    PK11_R_MALLOC_FAILURE);
34997211Sjp161948 			return (0);
35007211Sjp161948 			}
35017211Sjp161948 		/* this means empty tables */
35027211Sjp161948 		hw_cnids[0] = NID_undef;
35037211Sjp161948 		hw_dnids[0] = NID_undef;
35047211Sjp161948 		return (1);
35057211Sjp161948 		}
35067211Sjp161948 
35077211Sjp161948 	pSlotList = OPENSSL_malloc(ulSlotCount * sizeof (CK_SLOT_ID));
35087211Sjp161948 	if (pSlotList == NULL)
35097211Sjp161948 		{
35107211Sjp161948 		PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_MALLOC_FAILURE);
35117211Sjp161948 		goto err;
35127211Sjp161948 		}
35137211Sjp161948 
35147211Sjp161948 	/* Get the slot list for processing */
35157211Sjp161948 	if (pflist->C_GetSlotList(0, pSlotList, &ulSlotCount) != CKR_OK)
35167211Sjp161948 		{
35177211Sjp161948 		PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_GETSLOTLIST);
35187211Sjp161948 		goto err;
35197211Sjp161948 		}
35207211Sjp161948 
35217211Sjp161948 	/*
35227211Sjp161948 	 * We don't care about duplicit mechanisms in multiple slots and also
35237211Sjp161948 	 * reserve one slot for the terminal NID_undef which we use to stop the
35247211Sjp161948 	 * search.
35257211Sjp161948 	 */
35267211Sjp161948 	hw_ctable_size = ulSlotCount * PK11_CIPHER_MAX + 1;
35277211Sjp161948 	hw_dtable_size = ulSlotCount * PK11_DIGEST_MAX + 1;
35287211Sjp161948 	tmp_hw_cnids = OPENSSL_malloc(hw_ctable_size * sizeof (int));
35297211Sjp161948 	tmp_hw_dnids = OPENSSL_malloc(hw_dtable_size * sizeof (int));
35307211Sjp161948 	if (tmp_hw_cnids == NULL || tmp_hw_dnids == NULL)
35317211Sjp161948 		{
35327211Sjp161948 		PK11err(PK11_F_CHECK_HW_MECHANISMS, PK11_R_MALLOC_FAILURE);
35337211Sjp161948 		goto err;
35347211Sjp161948 		}
35357211Sjp161948 
35367211Sjp161948 	/*
35377211Sjp161948 	 * Do not use memset since we should not rely on the fact that NID_undef
35387211Sjp161948 	 * is zero now.
35397211Sjp161948 	 */
35407211Sjp161948 	for (i = 0; i < hw_ctable_size; ++i)
35417211Sjp161948 		tmp_hw_cnids[i] = NID_undef;
35427211Sjp161948 	for (i = 0; i < hw_dtable_size; ++i)
35437211Sjp161948 		tmp_hw_dnids[i] = NID_undef;
35447211Sjp161948 
35457211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
35467211Sjp161948 	fprintf(stderr, "%s: provider: %s\n", PK11_DBG, pkcs11_kernel);
35477211Sjp161948 	fprintf(stderr, "%s: found %d hardware slots\n", PK11_DBG, ulSlotCount);
35487211Sjp161948 	fprintf(stderr, "%s: now looking for mechs supported in hw\n",
35497211Sjp161948 	    PK11_DBG);
35507211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
35517211Sjp161948 
35527211Sjp161948 	for (i = 0; i < ulSlotCount; i++)
35537211Sjp161948 		{
35547211Sjp161948 		if (pflist->C_GetTokenInfo(pSlotList[i], &token_info) != CKR_OK)
35557211Sjp161948 			continue;
35567211Sjp161948 
35577211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
35587211Sjp161948 	fprintf(stderr, "%s: token label: %.32s\n", PK11_DBG, token_info.label);
35597211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
35607211Sjp161948 
35617211Sjp161948 		/*
35627211Sjp161948 		 * We are filling the hw mech tables here. Global tables are
35637211Sjp161948 		 * still NULL so all mechanisms are put into tmp tables.
35647211Sjp161948 		 */
35657211Sjp161948 		pk11_find_symmetric_ciphers(pflist, pSlotList[i],
35667211Sjp161948 		    &n_cipher, tmp_hw_cnids);
35677211Sjp161948 		pk11_find_digests(pflist, pSlotList[i],
35687211Sjp161948 		    &n_digest, tmp_hw_dnids);
35697211Sjp161948 		}
35707211Sjp161948 
35717211Sjp161948 	/*
35727211Sjp161948 	 * Since we are part of a library (libcrypto.so), calling this function
35737211Sjp161948 	 * may have side-effects. Also, C_Finalize() is triggered by
35747211Sjp161948 	 * dlclose(3C).
35757211Sjp161948 	 */
35767211Sjp161948 #if 0
35777211Sjp161948 	pflist->C_Finalize(NULL);
35787211Sjp161948 #endif
35797211Sjp161948 	OPENSSL_free(pSlotList);
35807211Sjp161948 	dlclose(handle);
35817211Sjp161948 	hw_cnids = tmp_hw_cnids;
35827211Sjp161948 	hw_dnids = tmp_hw_dnids;
35837211Sjp161948 
35847211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
35857211Sjp161948 	fprintf(stderr, "%s: hw mechs check complete\n", PK11_DBG);
35867211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
35877211Sjp161948 	return (1);
35887211Sjp161948 
35897211Sjp161948 err:
35907211Sjp161948 	if (pSlotList != NULL)
35917211Sjp161948 		OPENSSL_free(pSlotList);
35927211Sjp161948 	if (tmp_hw_cnids != NULL)
35937211Sjp161948 		OPENSSL_free(tmp_hw_cnids);
35947211Sjp161948 	if (tmp_hw_dnids != NULL)
35957211Sjp161948 		OPENSSL_free(tmp_hw_dnids);
35967211Sjp161948 
35977211Sjp161948 	return (0);
35987211Sjp161948 	}
35997211Sjp161948 
36007211Sjp161948 /*
36017211Sjp161948  * Check presence of a NID in the table of NIDs. The table may be NULL (i.e.,
36027211Sjp161948  * non-existent).
36037211Sjp161948  */
36047211Sjp161948 static int nid_in_table(int nid, int *nid_table)
36057211Sjp161948 	{
36067211Sjp161948 	int i = 0;
36077211Sjp161948 
36087211Sjp161948 	/*
36097211Sjp161948 	 * a special case. NULL means that we are initializing a new
36107211Sjp161948 	 * table.
36117211Sjp161948 	 */
36127211Sjp161948 	if (nid_table == NULL)
36137211Sjp161948 		return (1);
36147211Sjp161948 
36157211Sjp161948 	/*
36167211Sjp161948 	 * the table is never full, there is always at least one
36177211Sjp161948 	 * NID_undef.
36187211Sjp161948 	 */
36197211Sjp161948 	while (nid_table[i] != NID_undef)
36207211Sjp161948 		{
36217211Sjp161948 		if (nid_table[i++] == nid)
36227211Sjp161948 			{
36237211Sjp161948 #ifdef	DEBUG_SLOT_SELECTION
36247211Sjp161948 	fprintf(stderr, " (NID %d in hw table, idx %d)", nid, i);
36257211Sjp161948 #endif	/* DEBUG_SLOT_SELECTION */
36267211Sjp161948 			return (1);
36277211Sjp161948 			}
36287211Sjp161948 		}
36297211Sjp161948 
36307211Sjp161948 	return (0);
36317211Sjp161948 	}
36327211Sjp161948 #endif	/* SOLARIS_HW_SLOT_SELECTION */
36337211Sjp161948 
36347211Sjp161948 #endif	/* OPENSSL_NO_HW_PK11 */
36357211Sjp161948 #endif	/* OPENSSL_NO_HW */
3636