xref: /onnv-gate/usr/src/common/openssl/crypto/engine/hw_pk11.c (revision 6847:3ecb9a3b003b)
10Sstevel@tonic-gate /*
2*6847Svk199839  * 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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
70Sstevel@tonic-gate 
80Sstevel@tonic-gate /* crypto/engine/hw_pk11.c */
90Sstevel@tonic-gate /* This product includes software developed by the OpenSSL Project for
100Sstevel@tonic-gate  * use in the OpenSSL Toolkit (http://www.openssl.org/).
110Sstevel@tonic-gate  *
120Sstevel@tonic-gate  * This project also referenced hw_pkcs11-0.9.7b.patch written by
130Sstevel@tonic-gate  * Afchine Madjlessi.
140Sstevel@tonic-gate  */
150Sstevel@tonic-gate /* ====================================================================
160Sstevel@tonic-gate  * Copyright (c) 2000-2001 The OpenSSL Project.  All rights reserved.
170Sstevel@tonic-gate  *
180Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
190Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
200Sstevel@tonic-gate  * are met:
210Sstevel@tonic-gate  *
220Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
230Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
240Sstevel@tonic-gate  *
250Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
260Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in
270Sstevel@tonic-gate  *    the documentation and/or other materials provided with the
280Sstevel@tonic-gate  *    distribution.
290Sstevel@tonic-gate  *
300Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this
310Sstevel@tonic-gate  *    software must display the following acknowledgment:
320Sstevel@tonic-gate  *    "This product includes software developed by the OpenSSL Project
330Sstevel@tonic-gate  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
340Sstevel@tonic-gate  *
350Sstevel@tonic-gate  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
360Sstevel@tonic-gate  *    endorse or promote products derived from this software without
370Sstevel@tonic-gate  *    prior written permission. For written permission, please contact
380Sstevel@tonic-gate  *    licensing@OpenSSL.org.
390Sstevel@tonic-gate  *
400Sstevel@tonic-gate  * 5. Products derived from this software may not be called "OpenSSL"
410Sstevel@tonic-gate  *    nor may "OpenSSL" appear in their names without prior written
420Sstevel@tonic-gate  *    permission of the OpenSSL Project.
430Sstevel@tonic-gate  *
440Sstevel@tonic-gate  * 6. Redistributions of any form whatsoever must retain the following
450Sstevel@tonic-gate  *    acknowledgment:
460Sstevel@tonic-gate  *    "This product includes software developed by the OpenSSL Project
470Sstevel@tonic-gate  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
480Sstevel@tonic-gate  *
490Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
500Sstevel@tonic-gate  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
510Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
520Sstevel@tonic-gate  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
530Sstevel@tonic-gate  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
540Sstevel@tonic-gate  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
550Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
560Sstevel@tonic-gate  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
570Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
580Sstevel@tonic-gate  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
590Sstevel@tonic-gate  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
600Sstevel@tonic-gate  * OF THE POSSIBILITY OF SUCH DAMAGE.
610Sstevel@tonic-gate  * ====================================================================
620Sstevel@tonic-gate  *
630Sstevel@tonic-gate  * This product includes cryptographic software written by Eric Young
640Sstevel@tonic-gate  * (eay@cryptsoft.com).  This product includes software written by Tim
650Sstevel@tonic-gate  * Hudson (tjh@cryptsoft.com).
660Sstevel@tonic-gate  *
670Sstevel@tonic-gate  */
680Sstevel@tonic-gate 
690Sstevel@tonic-gate #include <stdio.h>
700Sstevel@tonic-gate #include <stdlib.h>
710Sstevel@tonic-gate #include <string.h>
720Sstevel@tonic-gate #include <sys/types.h>
730Sstevel@tonic-gate #include <unistd.h>
740Sstevel@tonic-gate 
750Sstevel@tonic-gate #include <openssl/e_os2.h>
76*6847Svk199839 #include <openssl/crypto.h>
770Sstevel@tonic-gate #include <openssl/engine.h>
780Sstevel@tonic-gate #include <openssl/dso.h>
790Sstevel@tonic-gate #include <openssl/err.h>
800Sstevel@tonic-gate #include <openssl/bn.h>
812139Sjp161948 #include <openssl/md5.h>
820Sstevel@tonic-gate #include <openssl/pem.h>
83*6847Svk199839 #ifndef OPENSSL_NO_RSA
840Sstevel@tonic-gate #include <openssl/rsa.h>
85*6847Svk199839 #endif
86*6847Svk199839 #ifndef OPENSSL_NO_DSA
87*6847Svk199839 #include <openssl/dsa.h>
88*6847Svk199839 #endif
89*6847Svk199839 #ifndef OPENSSL_NO_DH
90*6847Svk199839 #include <openssl/dh.h>
91*6847Svk199839 #endif
920Sstevel@tonic-gate #include <openssl/rand.h>
930Sstevel@tonic-gate #include <openssl/objects.h>
940Sstevel@tonic-gate #include <openssl/x509.h>
950Sstevel@tonic-gate #include <cryptlib.h>
960Sstevel@tonic-gate 
970Sstevel@tonic-gate #ifndef OPENSSL_NO_HW
980Sstevel@tonic-gate #ifndef OPENSSL_NO_HW_PK11
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate #undef DEBUG_SLOT_SELECTION
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate #include "security/cryptoki.h"
1030Sstevel@tonic-gate #include "security/pkcs11.h"
1040Sstevel@tonic-gate #include "hw_pk11_err.c"
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate /* The head of the free PK11 session list */
1080Sstevel@tonic-gate static struct PK11_SESSION_st *free_session = NULL;
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate /* Create all secret key objects in a global session so that they are available
1110Sstevel@tonic-gate  * to use for other sessions. These other sessions may be opened or closed
1120Sstevel@tonic-gate  * without losing the secret key objects */
1130Sstevel@tonic-gate static CK_SESSION_HANDLE	global_session = CK_INVALID_HANDLE;
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate /* ENGINE level stuff */
1160Sstevel@tonic-gate static int pk11_init(ENGINE *e);
1170Sstevel@tonic-gate static int pk11_library_init(ENGINE *e);
1180Sstevel@tonic-gate static int pk11_finish(ENGINE *e);
1190Sstevel@tonic-gate static int pk11_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)());
1200Sstevel@tonic-gate static int pk11_destroy(ENGINE *e);
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate /* RAND stuff */
1230Sstevel@tonic-gate static void pk11_rand_seed(const void *buf, int num);
1240Sstevel@tonic-gate static void pk11_rand_add(const void *buf, int num, double add_entropy);
1250Sstevel@tonic-gate static void pk11_rand_cleanup(void);
1260Sstevel@tonic-gate static int pk11_rand_bytes(unsigned char *buf, int num);
1270Sstevel@tonic-gate static int pk11_rand_status(void);
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate /* These functions are also used in other files */
1300Sstevel@tonic-gate PK11_SESSION *pk11_get_session();
1310Sstevel@tonic-gate void pk11_return_session(PK11_SESSION *sp);
132*6847Svk199839 
133*6847Svk199839 /* active list manipulation functions used here */
134*6847Svk199839 int pk11_active_delete(CK_OBJECT_HANDLE h);
135*6847Svk199839 
136*6847Svk199839 #ifndef OPENSSL_NO_RSA
1370Sstevel@tonic-gate int pk11_destroy_rsa_key_objects(PK11_SESSION *session);
138*6847Svk199839 int pk11_destroy_rsa_object_pub(PK11_SESSION *sp, CK_BBOOL uselock);
139*6847Svk199839 int pk11_destroy_rsa_object_priv(PK11_SESSION *sp, CK_BBOOL uselock);
140*6847Svk199839 #endif
141*6847Svk199839 #ifndef OPENSSL_NO_DSA
1420Sstevel@tonic-gate int pk11_destroy_dsa_key_objects(PK11_SESSION *session);
143*6847Svk199839 int pk11_destroy_dsa_object_pub(PK11_SESSION *sp, CK_BBOOL uselock);
144*6847Svk199839 int pk11_destroy_dsa_object_priv(PK11_SESSION *sp, CK_BBOOL uselock);
145*6847Svk199839 #endif
146*6847Svk199839 #ifndef OPENSSL_NO_DH
1470Sstevel@tonic-gate int pk11_destroy_dh_key_objects(PK11_SESSION *session);
148*6847Svk199839 int pk11_destroy_dh_object(PK11_SESSION *session, CK_BBOOL uselock);
149*6847Svk199839 #endif
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate /* Local helper functions */
1520Sstevel@tonic-gate static int pk11_free_all_sessions();
1530Sstevel@tonic-gate static int pk11_setup_session(PK11_SESSION *sp);
1540Sstevel@tonic-gate static int pk11_destroy_cipher_key_objects(PK11_SESSION *session);
155*6847Svk199839 static int pk11_destroy_object(CK_SESSION_HANDLE session,
1560Sstevel@tonic-gate 	CK_OBJECT_HANDLE oh);
1570Sstevel@tonic-gate static const char *get_PK11_LIBNAME(void);
1580Sstevel@tonic-gate static void free_PK11_LIBNAME(void);
1590Sstevel@tonic-gate static long set_PK11_LIBNAME(const char *name);
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate /* Symmetric cipher and digest support functions */
1620Sstevel@tonic-gate static int cipher_nid_to_pk11(int nid);
1630Sstevel@tonic-gate static int pk11_usable_ciphers(const int **nids);
1640Sstevel@tonic-gate static int pk11_usable_digests(const int **nids);
1650Sstevel@tonic-gate static int pk11_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
1660Sstevel@tonic-gate 	const unsigned char *iv, int enc);
167*6847Svk199839 static int pk11_init_symmetric(EVP_CIPHER_CTX *ctx, PK11_SESSION *sp,
168*6847Svk199839 	CK_MECHANISM_PTR pmech);
1690Sstevel@tonic-gate static int pk11_cipher_final(PK11_SESSION *sp);
1700Sstevel@tonic-gate static int pk11_cipher_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
1710Sstevel@tonic-gate 	const unsigned char *in, unsigned int inl);
1720Sstevel@tonic-gate static int pk11_cipher_cleanup(EVP_CIPHER_CTX *ctx);
1730Sstevel@tonic-gate static int pk11_engine_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
1740Sstevel@tonic-gate 	const int **nids, int nid);
1750Sstevel@tonic-gate static int pk11_engine_digests(ENGINE *e, const EVP_MD **digest,
1760Sstevel@tonic-gate 	const int **nids, int nid);
1770Sstevel@tonic-gate static CK_OBJECT_HANDLE pk11_get_cipher_key(EVP_CIPHER_CTX *ctx,
1780Sstevel@tonic-gate 	const unsigned char *key, CK_KEY_TYPE key_type, PK11_SESSION *sp);
179*6847Svk199839 static int check_new_cipher_key(PK11_SESSION *sp, const unsigned char *key);
1800Sstevel@tonic-gate static int md_nid_to_pk11(int nid);
1810Sstevel@tonic-gate static int pk11_digest_init(EVP_MD_CTX *ctx);
1820Sstevel@tonic-gate static int pk11_digest_update(EVP_MD_CTX *ctx,const void *data,
1832139Sjp161948 	size_t count);
1840Sstevel@tonic-gate static int pk11_digest_final(EVP_MD_CTX *ctx,unsigned char *md);
1850Sstevel@tonic-gate static int pk11_digest_copy(EVP_MD_CTX *to,const EVP_MD_CTX *from);
1860Sstevel@tonic-gate static int pk11_digest_cleanup(EVP_MD_CTX *ctx);
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate static int pk11_choose_slot();
1890Sstevel@tonic-gate static int pk11_count_symmetric_cipher(int slot_id, CK_MECHANISM_TYPE mech,
1900Sstevel@tonic-gate     int *current_slot_n_cipher, int *local_cipher_nids, int id);
1910Sstevel@tonic-gate static int pk11_count_digest(int slot_id, CK_MECHANISM_TYPE mech,
1920Sstevel@tonic-gate     int *current_slot_n_digest, int *local_digest_nids, int id);
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate /* Index for the supported ciphers */
1950Sstevel@tonic-gate #define PK11_DES_CBC		0
1960Sstevel@tonic-gate #define PK11_DES3_CBC		1
1970Sstevel@tonic-gate #define PK11_AES_CBC		2
1980Sstevel@tonic-gate #define PK11_RC4		3
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate /* Index for the supported digests */
2010Sstevel@tonic-gate #define PK11_MD5		0
2020Sstevel@tonic-gate #define PK11_SHA1		1
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate #define PK11_CIPHER_MAX		4	/* Max num of ciphers supported */
2050Sstevel@tonic-gate #define PK11_DIGEST_MAX		2	/* Max num of digests supported */
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate #define PK11_KEY_LEN_MAX	24
2080Sstevel@tonic-gate 
209*6847Svk199839 #define	TRY_OBJ_DESTROY(sess_hdl, obj_hdl, retval, uselock)		\
210*6847Svk199839 	{								\
211*6847Svk199839 	if (uselock)							\
212*6847Svk199839 		CRYPTO_w_lock(CRYPTO_LOCK_PK11_ENGINE);			\
213*6847Svk199839 	if (pk11_active_delete(obj_hdl) == 1)				\
214*6847Svk199839 		{							\
215*6847Svk199839 		retval = pk11_destroy_object(sess_hdl, obj_hdl);	\
216*6847Svk199839 		}							\
217*6847Svk199839 	if (uselock)							\
218*6847Svk199839 		CRYPTO_w_unlock(CRYPTO_LOCK_PK11_ENGINE);		\
219*6847Svk199839 	}
220*6847Svk199839 
2210Sstevel@tonic-gate static int cipher_nids[PK11_CIPHER_MAX];
2220Sstevel@tonic-gate static int digest_nids[PK11_DIGEST_MAX];
2230Sstevel@tonic-gate static int cipher_count		= 0;
2240Sstevel@tonic-gate static int digest_count		= 0;
2250Sstevel@tonic-gate static CK_BBOOL pk11_have_rsa	= CK_FALSE;
2260Sstevel@tonic-gate static CK_BBOOL pk11_have_dsa	= CK_FALSE;
2270Sstevel@tonic-gate static CK_BBOOL pk11_have_dh	= CK_FALSE;
2280Sstevel@tonic-gate static CK_BBOOL pk11_have_random = CK_FALSE;
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate typedef struct PK11_CIPHER_st
2310Sstevel@tonic-gate 	{
2324320Sjp161948 	int			id;
2334320Sjp161948 	int			nid;
2344320Sjp161948 	int			ivmax;
2354320Sjp161948 	int			key_len;
2364320Sjp161948 	CK_KEY_TYPE		key_type;
2374320Sjp161948 	CK_MECHANISM_TYPE	mech_type;
2380Sstevel@tonic-gate 	} PK11_CIPHER;
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate static PK11_CIPHER ciphers[] =
2410Sstevel@tonic-gate 	{
2424320Sjp161948 	{PK11_DES_CBC,  NID_des_cbc,      8,  8,   CKK_DES,  CKM_DES_CBC, },
2434320Sjp161948 	{PK11_DES3_CBC, NID_des_ede3_cbc, 8,  24,  CKK_DES3, CKM_DES3_CBC, },
2444320Sjp161948 	{PK11_AES_CBC,  NID_aes_128_cbc,  16, 16,  CKK_AES,  CKM_AES_CBC, },
2454320Sjp161948 	{PK11_RC4,      NID_rc4,          0,  16,  CKK_RC4,  CKM_RC4, },
2460Sstevel@tonic-gate 	};
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate typedef struct PK11_DIGEST_st
2490Sstevel@tonic-gate 	{
2504320Sjp161948 	int			id;
2514320Sjp161948 	int			nid;
2524320Sjp161948 	CK_MECHANISM_TYPE	mech_type;
2530Sstevel@tonic-gate 	} PK11_DIGEST;
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate static PK11_DIGEST digests[] =
2560Sstevel@tonic-gate 	{
2574320Sjp161948 	{PK11_MD5,	NID_md5,	CKM_MD5, },
2584320Sjp161948 	{PK11_SHA1,	NID_sha1,	CKM_SHA_1, },
2594320Sjp161948 	{0,		NID_undef,	0xFFFF, },
2600Sstevel@tonic-gate 	};
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate /* Structure to be used for the cipher_data/md_data in
2630Sstevel@tonic-gate  * EVP_CIPHER_CTX/EVP_MD_CTX structures in order to use the same
2640Sstevel@tonic-gate  * pk11 session in multiple cipher_update calls
2650Sstevel@tonic-gate  */
2660Sstevel@tonic-gate typedef struct PK11_CIPHER_STATE_st
2670Sstevel@tonic-gate 	{
2680Sstevel@tonic-gate 	PK11_SESSION	*sp;
2690Sstevel@tonic-gate 	} PK11_CIPHER_STATE;
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate /* libcrypto EVP stuff - this is how we get wired to EVP so the engine
2730Sstevel@tonic-gate  * gets called when libcrypto requests a cipher NID.
2740Sstevel@tonic-gate  * Note how the PK11_CIPHER_STATE is used here.
2750Sstevel@tonic-gate  */
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate /* DES CBC EVP */
2780Sstevel@tonic-gate static const EVP_CIPHER pk11_des_cbc =
2790Sstevel@tonic-gate 	{
2800Sstevel@tonic-gate 	NID_des_cbc,
2810Sstevel@tonic-gate 	8, 8, 8,
2820Sstevel@tonic-gate 	EVP_CIPH_CBC_MODE,
2830Sstevel@tonic-gate 	pk11_cipher_init,
2840Sstevel@tonic-gate 	pk11_cipher_do_cipher,
2850Sstevel@tonic-gate 	pk11_cipher_cleanup,
2860Sstevel@tonic-gate 	sizeof(PK11_CIPHER_STATE),
2870Sstevel@tonic-gate 	EVP_CIPHER_set_asn1_iv,
2880Sstevel@tonic-gate 	EVP_CIPHER_get_asn1_iv,
2890Sstevel@tonic-gate 	NULL
2900Sstevel@tonic-gate 	};
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate /* 3DES CBC EVP */
2930Sstevel@tonic-gate static const EVP_CIPHER pk11_3des_cbc =
2940Sstevel@tonic-gate 	{
2950Sstevel@tonic-gate 	NID_des_ede3_cbc,
2960Sstevel@tonic-gate 	8, 24, 8,
2970Sstevel@tonic-gate 	EVP_CIPH_CBC_MODE,
2980Sstevel@tonic-gate 	pk11_cipher_init,
2990Sstevel@tonic-gate 	pk11_cipher_do_cipher,
3000Sstevel@tonic-gate 	pk11_cipher_cleanup,
3010Sstevel@tonic-gate 	sizeof(PK11_CIPHER_STATE),
3020Sstevel@tonic-gate 	EVP_CIPHER_set_asn1_iv,
3030Sstevel@tonic-gate 	EVP_CIPHER_get_asn1_iv,
3040Sstevel@tonic-gate 	NULL
3050Sstevel@tonic-gate 	};
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate static const EVP_CIPHER pk11_aes_cbc =
3080Sstevel@tonic-gate 	{
3090Sstevel@tonic-gate 	NID_aes_128_cbc,
3100Sstevel@tonic-gate 	16, 16, 16,
3110Sstevel@tonic-gate 	EVP_CIPH_CBC_MODE,
3120Sstevel@tonic-gate 	pk11_cipher_init,
3130Sstevel@tonic-gate 	pk11_cipher_do_cipher,
3140Sstevel@tonic-gate 	pk11_cipher_cleanup,
3150Sstevel@tonic-gate 	sizeof(PK11_CIPHER_STATE),
3160Sstevel@tonic-gate 	EVP_CIPHER_set_asn1_iv,
3170Sstevel@tonic-gate 	EVP_CIPHER_get_asn1_iv,
3180Sstevel@tonic-gate 	NULL
3190Sstevel@tonic-gate 	};
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate static const EVP_CIPHER pk11_rc4 =
3220Sstevel@tonic-gate 	{
3230Sstevel@tonic-gate 	NID_rc4,
3240Sstevel@tonic-gate 	1,16,0,
3250Sstevel@tonic-gate 	EVP_CIPH_VARIABLE_LENGTH,
3260Sstevel@tonic-gate 	pk11_cipher_init,
3270Sstevel@tonic-gate 	pk11_cipher_do_cipher,
3280Sstevel@tonic-gate 	pk11_cipher_cleanup,
3290Sstevel@tonic-gate 	sizeof(PK11_CIPHER_STATE),
3300Sstevel@tonic-gate 	NULL,
3310Sstevel@tonic-gate 	NULL,
3320Sstevel@tonic-gate 	NULL
3330Sstevel@tonic-gate 	};
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate static const EVP_MD pk11_md5 =
3360Sstevel@tonic-gate 	{
3370Sstevel@tonic-gate 	NID_md5,
3380Sstevel@tonic-gate 	NID_md5WithRSAEncryption,
3390Sstevel@tonic-gate 	MD5_DIGEST_LENGTH,
3400Sstevel@tonic-gate 	0,
3410Sstevel@tonic-gate 	pk11_digest_init,
3420Sstevel@tonic-gate 	pk11_digest_update,
3430Sstevel@tonic-gate 	pk11_digest_final,
3440Sstevel@tonic-gate 	pk11_digest_copy,
3450Sstevel@tonic-gate 	pk11_digest_cleanup,
3460Sstevel@tonic-gate 	EVP_PKEY_RSA_method,
3470Sstevel@tonic-gate 	MD5_CBLOCK,
3480Sstevel@tonic-gate 	sizeof(PK11_CIPHER_STATE),
3490Sstevel@tonic-gate 	};
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate static const EVP_MD pk11_sha1 =
3520Sstevel@tonic-gate 	{
3530Sstevel@tonic-gate 	NID_sha1,
3540Sstevel@tonic-gate 	NID_sha1WithRSAEncryption,
3550Sstevel@tonic-gate 	SHA_DIGEST_LENGTH,
3560Sstevel@tonic-gate 	0,
3570Sstevel@tonic-gate 	pk11_digest_init,
3580Sstevel@tonic-gate 	pk11_digest_update,
3590Sstevel@tonic-gate 	pk11_digest_final,
3600Sstevel@tonic-gate 	pk11_digest_copy,
3610Sstevel@tonic-gate 	pk11_digest_cleanup,
3620Sstevel@tonic-gate 	EVP_PKEY_RSA_method,
3630Sstevel@tonic-gate 	SHA_CBLOCK,
3640Sstevel@tonic-gate 	sizeof(PK11_CIPHER_STATE),
3650Sstevel@tonic-gate 	};
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate /* Initialization function. Sets up various pk11 library components.
3680Sstevel@tonic-gate  */
3690Sstevel@tonic-gate /* The definitions for control commands specific to this engine
3700Sstevel@tonic-gate  */
3710Sstevel@tonic-gate #define PK11_CMD_SO_PATH		ENGINE_CMD_BASE
3720Sstevel@tonic-gate static const ENGINE_CMD_DEFN pk11_cmd_defns[] =
3730Sstevel@tonic-gate 	{
3740Sstevel@tonic-gate 		{
3750Sstevel@tonic-gate 		PK11_CMD_SO_PATH,
3760Sstevel@tonic-gate 		"SO_PATH",
3770Sstevel@tonic-gate 		"Specifies the path to the 'pkcs#11' shared library",
3780Sstevel@tonic-gate 		ENGINE_CMD_FLAG_STRING
3790Sstevel@tonic-gate 		},
3800Sstevel@tonic-gate 		{0, NULL, NULL, 0}
3810Sstevel@tonic-gate 	};
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate static RAND_METHOD pk11_random =
3850Sstevel@tonic-gate 	{
3860Sstevel@tonic-gate 	pk11_rand_seed,
3870Sstevel@tonic-gate 	pk11_rand_bytes,
3880Sstevel@tonic-gate 	pk11_rand_cleanup,
3890Sstevel@tonic-gate 	pk11_rand_add,
3900Sstevel@tonic-gate 	pk11_rand_bytes,
3910Sstevel@tonic-gate 	pk11_rand_status
3920Sstevel@tonic-gate 	};
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate /* Constants used when creating the ENGINE
3960Sstevel@tonic-gate  */
3970Sstevel@tonic-gate static const char *engine_pk11_id = "pkcs11";
3980Sstevel@tonic-gate static const char *engine_pk11_name = "PKCS #11 engine support";
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate CK_FUNCTION_LIST_PTR pFuncList = NULL;
4010Sstevel@tonic-gate static const char PK11_GET_FUNCTION_LIST[] = "C_GetFunctionList";
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate /* These are the static string constants for the DSO file name and the function
4040Sstevel@tonic-gate  * symbol names to bind to.
4050Sstevel@tonic-gate  */
4060Sstevel@tonic-gate #if defined(__sparcv9) || defined(__x86_64) || defined(__amd64)
4070Sstevel@tonic-gate static const char def_PK11_LIBNAME[] = "/usr/lib/64/libpkcs11.so.1";
4080Sstevel@tonic-gate #else
4090Sstevel@tonic-gate static const char def_PK11_LIBNAME[] = "/usr/lib/libpkcs11.so.1";
4100Sstevel@tonic-gate #endif
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate static CK_BBOOL true = TRUE;
4130Sstevel@tonic-gate static CK_BBOOL false = FALSE;
4140Sstevel@tonic-gate static CK_SLOT_ID SLOTID = 0;
4150Sstevel@tonic-gate static int pk11_library_initialized = 0;
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate static DSO *pk11_dso = NULL;
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate /*
4200Sstevel@tonic-gate  * This internal function is used by ENGINE_pk11() and "dynamic" ENGINE support.
4210Sstevel@tonic-gate  */
4220Sstevel@tonic-gate static int bind_pk11(ENGINE *e)
4230Sstevel@tonic-gate 	{
424*6847Svk199839 #ifndef OPENSSL_NO_RSA
4250Sstevel@tonic-gate 	const RSA_METHOD *rsa = NULL;
4260Sstevel@tonic-gate 	RSA_METHOD *pk11_rsa = PK11_RSA();
427*6847Svk199839 #endif
4280Sstevel@tonic-gate 	if (!pk11_library_initialized)
4290Sstevel@tonic-gate 		pk11_library_init(e);
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	if(!ENGINE_set_id(e, engine_pk11_id) ||
4320Sstevel@tonic-gate 	   !ENGINE_set_name(e, engine_pk11_name) ||
4330Sstevel@tonic-gate 	   !ENGINE_set_ciphers(e, pk11_engine_ciphers) ||
4340Sstevel@tonic-gate 	   !ENGINE_set_digests(e, pk11_engine_digests))
4350Sstevel@tonic-gate 	   	return 0;
4360Sstevel@tonic-gate #ifndef OPENSSL_NO_RSA
4370Sstevel@tonic-gate 	if(pk11_have_rsa == CK_TRUE)
4380Sstevel@tonic-gate 		{
4390Sstevel@tonic-gate 		if(!ENGINE_set_RSA(e, PK11_RSA()) ||
4400Sstevel@tonic-gate 	           !ENGINE_set_load_privkey_function(e, pk11_load_privkey) ||
4410Sstevel@tonic-gate 	           !ENGINE_set_load_pubkey_function(e, pk11_load_pubkey))
4420Sstevel@tonic-gate 			return 0;
4430Sstevel@tonic-gate #ifdef DEBUG_SLOT_SELECTION
4440Sstevel@tonic-gate 		fprintf(stderr, "OPENSSL_PKCS#11_ENGINE: registered RSA\n");
4450Sstevel@tonic-gate #endif /* DEBUG_SLOT_SELECTION */
4460Sstevel@tonic-gate 		}
4470Sstevel@tonic-gate #endif
4480Sstevel@tonic-gate #ifndef OPENSSL_NO_DSA
4490Sstevel@tonic-gate 	if(pk11_have_dsa == CK_TRUE)
4500Sstevel@tonic-gate 		{
4510Sstevel@tonic-gate 	  	if (!ENGINE_set_DSA(e, PK11_DSA()))
4520Sstevel@tonic-gate 			return 0;
4530Sstevel@tonic-gate #ifdef DEBUG_SLOT_SELECTION
4540Sstevel@tonic-gate 		fprintf(stderr, "OPENSSL_PKCS#11_ENGINE: registered DSA\n");
4550Sstevel@tonic-gate #endif /* DEBUG_SLOT_SELECTION */
4560Sstevel@tonic-gate 	    	}
4570Sstevel@tonic-gate #endif
4580Sstevel@tonic-gate #ifndef OPENSSL_NO_DH
4590Sstevel@tonic-gate 	if(pk11_have_dh == CK_TRUE)
4600Sstevel@tonic-gate 		{
4610Sstevel@tonic-gate 	  	if (!ENGINE_set_DH(e, PK11_DH()))
4620Sstevel@tonic-gate 			return 0;
4630Sstevel@tonic-gate #ifdef DEBUG_SLOT_SELECTION
4640Sstevel@tonic-gate 		fprintf(stderr, "OPENSSL_PKCS#11_ENGINE: registered DH\n");
4650Sstevel@tonic-gate #endif /* DEBUG_SLOT_SELECTION */
4660Sstevel@tonic-gate 	    	}
4670Sstevel@tonic-gate #endif
4680Sstevel@tonic-gate 	if(pk11_have_random)
4690Sstevel@tonic-gate 		{
4700Sstevel@tonic-gate 		if(!ENGINE_set_RAND(e, &pk11_random))
4710Sstevel@tonic-gate 			return 0;
4720Sstevel@tonic-gate #ifdef DEBUG_SLOT_SELECTION
4730Sstevel@tonic-gate 		fprintf(stderr, "OPENSSL_PKCS#11_ENGINE: registered random\n");
4740Sstevel@tonic-gate #endif /* DEBUG_SLOT_SELECTION */
4750Sstevel@tonic-gate 		}
4760Sstevel@tonic-gate 	if(!ENGINE_set_init_function(e, pk11_init) ||
4770Sstevel@tonic-gate 	   !ENGINE_set_destroy_function(e, pk11_destroy) ||
4780Sstevel@tonic-gate 	   !ENGINE_set_finish_function(e, pk11_finish) ||
4790Sstevel@tonic-gate 	   !ENGINE_set_ctrl_function(e, pk11_ctrl) ||
4800Sstevel@tonic-gate 	   !ENGINE_set_cmd_defns(e, pk11_cmd_defns))
4810Sstevel@tonic-gate 		return 0;
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate /* Apache calls OpenSSL function RSA_blinding_on() once during startup
4840Sstevel@tonic-gate  * which in turn calls bn_mod_exp. Since we do not implement bn_mod_exp
4850Sstevel@tonic-gate  * here, we wire it back to the OpenSSL software implementation.
4860Sstevel@tonic-gate  * Since it is used only once, performance is not a concern. */
4870Sstevel@tonic-gate #ifndef OPENSSL_NO_RSA
4880Sstevel@tonic-gate         rsa = RSA_PKCS1_SSLeay();
4890Sstevel@tonic-gate         pk11_rsa->rsa_mod_exp = rsa->rsa_mod_exp;
4900Sstevel@tonic-gate         pk11_rsa->bn_mod_exp = rsa->bn_mod_exp;
4910Sstevel@tonic-gate #endif
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	/* Ensure the pk11 error handling is set up */
4940Sstevel@tonic-gate 	ERR_load_pk11_strings();
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	return 1;
4970Sstevel@tonic-gate 	}
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate /* Dynamic engine support is disabled at a higher level for Solaris
5000Sstevel@tonic-gate  */
5010Sstevel@tonic-gate #ifdef ENGINE_DYNAMIC_SUPPORT
5020Sstevel@tonic-gate static int bind_helper(ENGINE *e, const char *id)
5030Sstevel@tonic-gate 	{
5040Sstevel@tonic-gate 	if (id && (strcmp(id, engine_pk11_id) != 0))
5050Sstevel@tonic-gate 		return 0;
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	if (!bind_pk11(e))
5080Sstevel@tonic-gate 		return 0;
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 	return 1;
5110Sstevel@tonic-gate 	}
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate IMPLEMENT_DYNAMIC_CHECK_FN()
5140Sstevel@tonic-gate IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate #else
5170Sstevel@tonic-gate static ENGINE *engine_pk11(void)
5180Sstevel@tonic-gate 	{
5190Sstevel@tonic-gate 	ENGINE *ret = ENGINE_new();
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	if (!ret)
5220Sstevel@tonic-gate 		return NULL;
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	if (!bind_pk11(ret))
5250Sstevel@tonic-gate 		{
5260Sstevel@tonic-gate 		ENGINE_free(ret);
5270Sstevel@tonic-gate 		return NULL;
5280Sstevel@tonic-gate 		}
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 	return ret;
5310Sstevel@tonic-gate 	}
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate void ENGINE_load_pk11(void)
5340Sstevel@tonic-gate 	{
5350Sstevel@tonic-gate 	ENGINE *e_pk11 = NULL;
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	/* Do not use dynamic PKCS#11 library on Solaris due to
5380Sstevel@tonic-gate 	 * security reasons. We will link it in statically
5390Sstevel@tonic-gate 	 */
5400Sstevel@tonic-gate 	/* Attempt to load PKCS#11 library
5410Sstevel@tonic-gate 	 */
5420Sstevel@tonic-gate 	if (!pk11_dso)
5430Sstevel@tonic-gate 		pk11_dso = DSO_load(NULL, get_PK11_LIBNAME(), NULL, 0);
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	if (pk11_dso == NULL)
5460Sstevel@tonic-gate 		{
5470Sstevel@tonic-gate 		PK11err(PK11_F_LOAD, PK11_R_DSO_FAILURE);
5480Sstevel@tonic-gate 		return;
5490Sstevel@tonic-gate 		}
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	e_pk11 = engine_pk11();
5520Sstevel@tonic-gate 	if (!e_pk11)
5530Sstevel@tonic-gate 		{
5540Sstevel@tonic-gate 		DSO_free(pk11_dso);
5550Sstevel@tonic-gate 		pk11_dso = NULL;
5560Sstevel@tonic-gate 		return;
5570Sstevel@tonic-gate 		}
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	/* At this point, the pk11 shared library is either dynamically
5600Sstevel@tonic-gate 	 * loaded or statically linked in. So, initialize the pk11
5610Sstevel@tonic-gate 	 * library before calling ENGINE_set_default since the latter
5620Sstevel@tonic-gate 	 * needs cipher and digest algorithm information
5630Sstevel@tonic-gate 	 */
5640Sstevel@tonic-gate 	if (!pk11_library_init(e_pk11))
5650Sstevel@tonic-gate 		{
5660Sstevel@tonic-gate 		DSO_free(pk11_dso);
5670Sstevel@tonic-gate 		pk11_dso = NULL;
5680Sstevel@tonic-gate 		ENGINE_free(e_pk11);
5690Sstevel@tonic-gate 		return;
5700Sstevel@tonic-gate 		}
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 	ENGINE_add(e_pk11);
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	ENGINE_free(e_pk11);
5750Sstevel@tonic-gate 	ERR_clear_error();
5760Sstevel@tonic-gate 	}
5770Sstevel@tonic-gate #endif
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate /* These are the static string constants for the DSO file name and
5800Sstevel@tonic-gate  * the function symbol names to bind to.
5810Sstevel@tonic-gate  */
5820Sstevel@tonic-gate static const char *PK11_LIBNAME = NULL;
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate static const char *get_PK11_LIBNAME(void)
5850Sstevel@tonic-gate 	{
5860Sstevel@tonic-gate 	if (PK11_LIBNAME)
5870Sstevel@tonic-gate 		return PK11_LIBNAME;
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	return def_PK11_LIBNAME;
5900Sstevel@tonic-gate 	}
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate static void free_PK11_LIBNAME(void)
5930Sstevel@tonic-gate 	{
5940Sstevel@tonic-gate 	if (PK11_LIBNAME)
5950Sstevel@tonic-gate 		OPENSSL_free((void*)PK11_LIBNAME);
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 	PK11_LIBNAME = NULL;
5980Sstevel@tonic-gate 	}
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate static long set_PK11_LIBNAME(const char *name)
6010Sstevel@tonic-gate 	{
6020Sstevel@tonic-gate 	free_PK11_LIBNAME();
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	return ((PK11_LIBNAME = BUF_strdup(name)) != NULL ? 1 : 0);
6050Sstevel@tonic-gate 	}
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate /* Initialization function for the pk11 engine */
6080Sstevel@tonic-gate static int pk11_init(ENGINE *e)
6090Sstevel@tonic-gate {
6100Sstevel@tonic-gate 	return pk11_library_init(e);
6110Sstevel@tonic-gate }
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate /* Initialization function. Sets up various pk11 library components.
6140Sstevel@tonic-gate  * It selects a slot based on predefined critiera. In the process, it also
6150Sstevel@tonic-gate  * count how many ciphers and digests to support. Since the cipher and
6160Sstevel@tonic-gate  * digest information is needed when setting default engine, this function
6170Sstevel@tonic-gate  * needs to be called before calling ENGINE_set_default.
6180Sstevel@tonic-gate  */
6190Sstevel@tonic-gate static int pk11_library_init(ENGINE *e)
6200Sstevel@tonic-gate 	{
6210Sstevel@tonic-gate 	CK_C_GetFunctionList p;
6220Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
6230Sstevel@tonic-gate 	CK_INFO info;
6240Sstevel@tonic-gate 	CK_ULONG ul_state_len;
6250Sstevel@tonic-gate 	char tmp_buf[20];
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	if (pk11_library_initialized)
6280Sstevel@tonic-gate 		return 1;
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 	if (pk11_dso == NULL)
6310Sstevel@tonic-gate 		{
6320Sstevel@tonic-gate 		PK11err(PK11_F_LIBRARY_INIT, PK11_R_DSO_FAILURE);
6330Sstevel@tonic-gate 		goto err;
6340Sstevel@tonic-gate 		}
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 	/* get the C_GetFunctionList function from the loaded library
6370Sstevel@tonic-gate 	 */
6380Sstevel@tonic-gate 	p = (CK_C_GetFunctionList)DSO_bind_func(pk11_dso,
6390Sstevel@tonic-gate 		PK11_GET_FUNCTION_LIST);
6400Sstevel@tonic-gate 	if ( !p )
6410Sstevel@tonic-gate 		{
6420Sstevel@tonic-gate 		PK11err(PK11_F_LIBRARY_INIT, PK11_R_DSO_FAILURE);
6430Sstevel@tonic-gate 		goto err;
6440Sstevel@tonic-gate 		}
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	/* get the full function list from the loaded library
6470Sstevel@tonic-gate 	 */
6480Sstevel@tonic-gate 	rv = p(&pFuncList);
6490Sstevel@tonic-gate 	if (rv != CKR_OK)
6500Sstevel@tonic-gate 		{
6510Sstevel@tonic-gate 		PK11err(PK11_F_LIBRARY_INIT, PK11_R_DSO_FAILURE);
6520Sstevel@tonic-gate 		snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
6530Sstevel@tonic-gate 		ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
6540Sstevel@tonic-gate 		goto err;
6550Sstevel@tonic-gate 		}
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	rv = pFuncList->C_Initialize(NULL_PTR);
6580Sstevel@tonic-gate 	if ((rv != CKR_OK) && (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED))
6590Sstevel@tonic-gate 		{
6600Sstevel@tonic-gate 		PK11err(PK11_F_LIBRARY_INIT, PK11_R_INITIALIZE);
6610Sstevel@tonic-gate 		snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
6620Sstevel@tonic-gate 		ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
6630Sstevel@tonic-gate 		goto err;
6640Sstevel@tonic-gate 		}
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 	rv = pFuncList->C_GetInfo(&info);
6670Sstevel@tonic-gate 	if (rv != CKR_OK)
6680Sstevel@tonic-gate 		{
6690Sstevel@tonic-gate 		PK11err(PK11_F_LIBRARY_INIT, PK11_R_GETINFO);
6700Sstevel@tonic-gate 		snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
6710Sstevel@tonic-gate 		ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
6720Sstevel@tonic-gate 		goto err;
6730Sstevel@tonic-gate 		}
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	if (pk11_choose_slot() == 0)
6760Sstevel@tonic-gate 		goto err;
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 	if (global_session == CK_INVALID_HANDLE)
6790Sstevel@tonic-gate 		{
6800Sstevel@tonic-gate 		/* Open the global_session for the new process */
6810Sstevel@tonic-gate 		rv = pFuncList->C_OpenSession(SLOTID, CKF_SERIAL_SESSION,
6820Sstevel@tonic-gate 			NULL_PTR, NULL_PTR, &global_session);
6830Sstevel@tonic-gate 		if (rv != CKR_OK)
6840Sstevel@tonic-gate 			{
6850Sstevel@tonic-gate 			PK11err(PK11_F_LIBRARY_INIT, PK11_R_OPENSESSION);
6860Sstevel@tonic-gate 			snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
6870Sstevel@tonic-gate 			ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
6880Sstevel@tonic-gate 			goto err;
6890Sstevel@tonic-gate 			}
6900Sstevel@tonic-gate 		}
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	/* Disable digest if C_GetOperationState is not supported since
6930Sstevel@tonic-gate 	 * this function is required by OpenSSL digest copy function */
6940Sstevel@tonic-gate 	if (pFuncList->C_GetOperationState(global_session, NULL, &ul_state_len)
6950Sstevel@tonic-gate 			== CKR_FUNCTION_NOT_SUPPORTED)
6960Sstevel@tonic-gate 		digest_count = 0;
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	pk11_library_initialized = 1;
6990Sstevel@tonic-gate 	return 1;
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate err:
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	return 0;
7040Sstevel@tonic-gate 	}
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate /* Destructor (complements the "ENGINE_pk11()" constructor)
7070Sstevel@tonic-gate  */
7080Sstevel@tonic-gate static int pk11_destroy(ENGINE *e)
7090Sstevel@tonic-gate 	{
7100Sstevel@tonic-gate 	free_PK11_LIBNAME();
7110Sstevel@tonic-gate 	ERR_unload_pk11_strings();
7120Sstevel@tonic-gate 	return 1;
7130Sstevel@tonic-gate 	}
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate /* Termination function to clean up the session, the token, and
7160Sstevel@tonic-gate  * the pk11 library.
7170Sstevel@tonic-gate  */
7180Sstevel@tonic-gate static int pk11_finish(ENGINE *e)
7190Sstevel@tonic-gate 	{
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 	if (pk11_dso == NULL)
7220Sstevel@tonic-gate 		{
7230Sstevel@tonic-gate 		PK11err(PK11_F_FINISH, PK11_R_NOT_LOADED);
7240Sstevel@tonic-gate 		goto err;
7250Sstevel@tonic-gate 		}
7260Sstevel@tonic-gate 
727*6847Svk199839 	OPENSSL_assert(pFuncList != NULL);
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	if (pk11_free_all_sessions() == 0)
7300Sstevel@tonic-gate 		goto err;
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	pFuncList->C_CloseSession(global_session);
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	/* Since we are part of a library (libcrypto.so), calling this
7350Sstevel@tonic-gate 	 * function may have side-effects.
7360Sstevel@tonic-gate 	pFuncList->C_Finalize(NULL);
7370Sstevel@tonic-gate 	 */
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 	if (!DSO_free(pk11_dso))
7400Sstevel@tonic-gate 		{
7410Sstevel@tonic-gate 		PK11err(PK11_F_FINISH, PK11_R_DSO_FAILURE);
7420Sstevel@tonic-gate 		goto err;
7430Sstevel@tonic-gate 		}
7440Sstevel@tonic-gate 	pk11_dso = NULL;
7450Sstevel@tonic-gate 	pFuncList = NULL;
7460Sstevel@tonic-gate 	pk11_library_initialized = 0;
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 	return 1;
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate err:
7510Sstevel@tonic-gate 	return 0;
7520Sstevel@tonic-gate 	}
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate /* Standard engine interface function to set the dynamic library path */
7550Sstevel@tonic-gate static int pk11_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)())
7560Sstevel@tonic-gate 	{
7570Sstevel@tonic-gate 	int initialized = ((pk11_dso == NULL) ? 0 : 1);
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate 	switch(cmd)
7600Sstevel@tonic-gate 		{
7610Sstevel@tonic-gate 	case PK11_CMD_SO_PATH:
7620Sstevel@tonic-gate 		if (p == NULL)
7630Sstevel@tonic-gate 			{
7640Sstevel@tonic-gate 			PK11err(PK11_F_CTRL, ERR_R_PASSED_NULL_PARAMETER);
7650Sstevel@tonic-gate 			return 0;
7660Sstevel@tonic-gate 			}
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 		if (initialized)
7690Sstevel@tonic-gate 			{
7700Sstevel@tonic-gate 			PK11err(PK11_F_CTRL, PK11_R_ALREADY_LOADED);
7710Sstevel@tonic-gate 			return 0;
7720Sstevel@tonic-gate 			}
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 		return set_PK11_LIBNAME((const char*)p);
7750Sstevel@tonic-gate 	default:
7760Sstevel@tonic-gate 		break;
7770Sstevel@tonic-gate 		}
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 	PK11err(PK11_F_CTRL,PK11_R_CTRL_COMMAND_NOT_IMPLEMENTED);
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 	return 0;
7820Sstevel@tonic-gate 	}
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate /* Required function by the engine random interface. It does nothing here
7860Sstevel@tonic-gate  */
7870Sstevel@tonic-gate static void pk11_rand_cleanup(void)
7880Sstevel@tonic-gate 	{
7890Sstevel@tonic-gate 	return;
7900Sstevel@tonic-gate 	}
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate static void pk11_rand_add(const void *buf, int num, double add)
7930Sstevel@tonic-gate 	{
7940Sstevel@tonic-gate 	PK11_SESSION *sp;
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 	if ((sp = pk11_get_session()) == NULL)
7970Sstevel@tonic-gate 		return;
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 	/* Ignore any errors (e.g. CKR_RANDOM_SEED_NOT_SUPPORTED) since
8000Sstevel@tonic-gate 	 * the calling functions do not care anyway
8010Sstevel@tonic-gate 	 */
8020Sstevel@tonic-gate 	pFuncList->C_SeedRandom(sp->session, (unsigned char *) buf, num);
8030Sstevel@tonic-gate 	pk11_return_session(sp);
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate 	return;
8060Sstevel@tonic-gate 	}
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate static void pk11_rand_seed(const void *buf, int num)
8090Sstevel@tonic-gate 	{
8100Sstevel@tonic-gate 	pk11_rand_add(buf, num, 0);
8110Sstevel@tonic-gate 	}
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate static int pk11_rand_bytes(unsigned char *buf, int num)
8140Sstevel@tonic-gate 	{
8150Sstevel@tonic-gate 	CK_RV rv;
8160Sstevel@tonic-gate 	PK11_SESSION *sp;
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 	if ((sp = pk11_get_session()) == NULL)
8190Sstevel@tonic-gate 		return 0;
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 	rv = pFuncList->C_GenerateRandom(sp->session, buf, num);
8220Sstevel@tonic-gate 	if (rv != CKR_OK)
8230Sstevel@tonic-gate 		{
8240Sstevel@tonic-gate 		char tmp_buf[20];
8250Sstevel@tonic-gate 		PK11err(PK11_F_RAND_BYTES, PK11_R_GENERATERANDOM);
8260Sstevel@tonic-gate 		snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
8270Sstevel@tonic-gate 		ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
8280Sstevel@tonic-gate 		pk11_return_session(sp);
8290Sstevel@tonic-gate 		return 0;
8300Sstevel@tonic-gate 		}
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 	pk11_return_session(sp);
8330Sstevel@tonic-gate 	return 1;
8340Sstevel@tonic-gate 	}
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate /* Required function by the engine random interface. It does nothing here
8380Sstevel@tonic-gate  */
8390Sstevel@tonic-gate static int pk11_rand_status(void)
8400Sstevel@tonic-gate 	{
8410Sstevel@tonic-gate 	return 1;
8420Sstevel@tonic-gate 	}
8430Sstevel@tonic-gate 
844*6847Svk199839 /*
845*6847Svk199839  * Free all BIGNUM structures from PK11_SESSION.
846*6847Svk199839  */
847*6847Svk199839 static void pk11_free_nums(PK11_SESSION *sp)
848*6847Svk199839 	{
849*6847Svk199839 #ifndef	OPENSSL_NO_RSA
850*6847Svk199839 		if (sp->rsa_n_num != NULL)
851*6847Svk199839 			BN_free(sp->rsa_n_num);
852*6847Svk199839 		if (sp->rsa_e_num != NULL)
853*6847Svk199839 			BN_free(sp->rsa_e_num);
854*6847Svk199839 		if (sp->rsa_d_num != NULL)
855*6847Svk199839 			BN_free(sp->rsa_d_num);
856*6847Svk199839 #endif
857*6847Svk199839 #ifndef	OPENSSL_NO_DSA
858*6847Svk199839 		if (sp->dsa_pub_num != NULL)
859*6847Svk199839 			BN_free(sp->dsa_pub_num);
860*6847Svk199839 		if (sp->dsa_priv_num != NULL)
861*6847Svk199839 			BN_free(sp->dsa_priv_num);
862*6847Svk199839 #endif
863*6847Svk199839 #ifndef	OPENSSL_NO_DH
864*6847Svk199839 		if (sp->dh_priv_num != NULL)
865*6847Svk199839 			BN_free(sp->dh_priv_num);
866*6847Svk199839 #endif
867*6847Svk199839 	}
8680Sstevel@tonic-gate 
869*6847Svk199839 /*
870*6847Svk199839  * Get new PK11_SESSION structure ready for use. Every process must have
871*6847Svk199839  * its own freelist of PK11_SESSION structures so handle fork() here
872*6847Svk199839  * by destroying the old and creating new freelist.
873*6847Svk199839  * The returned PK11_SESSION structure is disconnected from the freelist.
874*6847Svk199839  */
8750Sstevel@tonic-gate PK11_SESSION *pk11_get_session()
8760Sstevel@tonic-gate 	{
8770Sstevel@tonic-gate 	PK11_SESSION *sp, *sp1;
8780Sstevel@tonic-gate 	CK_RV rv;
8790Sstevel@tonic-gate 	char tmp_buf[20];
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate 	CRYPTO_w_lock(CRYPTO_LOCK_PK11_ENGINE);
882*6847Svk199839 	/*
883*6847Svk199839 	 * If the free list is empty, allocate new unitialized (filled
884*6847Svk199839 	 * with zeroes) PK11_SESSION structure otherwise return first
885*6847Svk199839 	 * structure from the freelist.
886*6847Svk199839 	 */
8870Sstevel@tonic-gate 	if ((sp = free_session) == NULL)
8880Sstevel@tonic-gate 		{
8890Sstevel@tonic-gate 		if ((sp = OPENSSL_malloc(sizeof(PK11_SESSION))) == NULL)
8900Sstevel@tonic-gate 			{
8910Sstevel@tonic-gate 			PK11err(PK11_F_GET_SESSION,
8920Sstevel@tonic-gate 				PK11_R_MALLOC_FAILURE);
8930Sstevel@tonic-gate 			goto err;
8940Sstevel@tonic-gate 			}
8950Sstevel@tonic-gate 		memset(sp, 0, sizeof(PK11_SESSION));
8960Sstevel@tonic-gate 		}
8970Sstevel@tonic-gate 	else
8980Sstevel@tonic-gate 		{
8990Sstevel@tonic-gate 		free_session = sp->next;
9000Sstevel@tonic-gate 		}
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	if (sp->pid != 0 && sp->pid != getpid())
9030Sstevel@tonic-gate 		{
904*6847Svk199839 		/*
905*6847Svk199839 		 * We are a new process and thus need to free any inherited
9060Sstevel@tonic-gate 		 * PK11_SESSION objects.
9070Sstevel@tonic-gate 		 */
9080Sstevel@tonic-gate 		while ((sp1 = free_session) != NULL)
9090Sstevel@tonic-gate 			{
9100Sstevel@tonic-gate 			free_session = sp1->next;
911*6847Svk199839 			/*
912*6847Svk199839 			 * NOTE:
913*6847Svk199839 			 *   we do not want to call pk11_free_all_sessions()
914*6847Svk199839 			 *   here because it would close underlying PKCS11
915*6847Svk199839 			 *   sessions and destroy objects.
916*6847Svk199839 			 */
917*6847Svk199839 			pk11_free_nums(sp1);
9180Sstevel@tonic-gate 			OPENSSL_free(sp1);
9190Sstevel@tonic-gate 			}
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate 		/* Initialize the process */
9220Sstevel@tonic-gate 		rv = pFuncList->C_Initialize(NULL_PTR);
9230Sstevel@tonic-gate 		if ((rv != CKR_OK) && (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED))
9240Sstevel@tonic-gate 			{
9250Sstevel@tonic-gate 			PK11err(PK11_F_GET_SESSION, PK11_R_INITIALIZE);
9260Sstevel@tonic-gate 			snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
9270Sstevel@tonic-gate 			ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
9280Sstevel@tonic-gate 			OPENSSL_free(sp);
9290Sstevel@tonic-gate 			sp = NULL;
9300Sstevel@tonic-gate 			goto err;
9310Sstevel@tonic-gate 			}
9320Sstevel@tonic-gate 
933*6847Svk199839 		/*
934*6847Svk199839 		 * Choose slot here since the slot table is different on
9350Sstevel@tonic-gate 		 * this process.
9360Sstevel@tonic-gate 		 */
9370Sstevel@tonic-gate 		if (pk11_choose_slot() == 0)
9380Sstevel@tonic-gate 			goto err;
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 		/* Open the global_session for the new process */
9410Sstevel@tonic-gate 		rv = pFuncList->C_OpenSession(SLOTID, CKF_SERIAL_SESSION,
9420Sstevel@tonic-gate 			NULL_PTR, NULL_PTR, &global_session);
9430Sstevel@tonic-gate 		if (rv != CKR_OK)
9440Sstevel@tonic-gate 			{
9450Sstevel@tonic-gate 			PK11err(PK11_F_GET_SESSION, PK11_R_OPENSESSION);
9460Sstevel@tonic-gate 			snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
9470Sstevel@tonic-gate 			ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
9480Sstevel@tonic-gate 			OPENSSL_free(sp);
9490Sstevel@tonic-gate 			sp = NULL;
9500Sstevel@tonic-gate 			goto err;
9510Sstevel@tonic-gate 			}
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 		/* It is an inherited session and needs re-initialization.
9540Sstevel@tonic-gate 		 */
9550Sstevel@tonic-gate 		if (pk11_setup_session(sp) == 0)
9560Sstevel@tonic-gate 			{
9570Sstevel@tonic-gate 			OPENSSL_free(sp);
9580Sstevel@tonic-gate 			sp = NULL;
9590Sstevel@tonic-gate 			}
9600Sstevel@tonic-gate 		}
9610Sstevel@tonic-gate 	else if (sp->pid == 0)
9620Sstevel@tonic-gate 		{
9630Sstevel@tonic-gate 		/* It is a new session and needs initialization.
9640Sstevel@tonic-gate 		 */
9650Sstevel@tonic-gate 		if (pk11_setup_session(sp) == 0)
9660Sstevel@tonic-gate 			{
9670Sstevel@tonic-gate 			OPENSSL_free(sp);
9680Sstevel@tonic-gate 			sp = NULL;
9690Sstevel@tonic-gate 			}
9700Sstevel@tonic-gate 		}
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate err:
973*6847Svk199839 	if (sp != NULL)
9740Sstevel@tonic-gate 		sp->next = NULL;
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 	CRYPTO_w_unlock(CRYPTO_LOCK_PK11_ENGINE);
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	return sp;
9790Sstevel@tonic-gate 	}
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate void pk11_return_session(PK11_SESSION *sp)
9830Sstevel@tonic-gate 	{
9840Sstevel@tonic-gate 	if (sp == NULL || sp->pid != getpid())
9850Sstevel@tonic-gate 		return;
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate 	CRYPTO_w_lock(CRYPTO_LOCK_PK11_ENGINE);
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate 	sp->next = free_session;
9910Sstevel@tonic-gate 	free_session = sp;
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate 	CRYPTO_w_unlock(CRYPTO_LOCK_PK11_ENGINE);
9940Sstevel@tonic-gate 	}
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate /* Destroy all objects. This function is called when the engine is finished
9980Sstevel@tonic-gate  */
9990Sstevel@tonic-gate static int pk11_free_all_sessions()
10000Sstevel@tonic-gate 	{
10010Sstevel@tonic-gate 	CK_RV rv;
10020Sstevel@tonic-gate 	PK11_SESSION *sp = NULL;
10030Sstevel@tonic-gate 	pid_t mypid = getpid();
10040Sstevel@tonic-gate 	int ret = 0;
10050Sstevel@tonic-gate 
1006*6847Svk199839 #ifndef OPENSSL_NO_RSA
1007*6847Svk199839 	(void) pk11_destroy_rsa_key_objects(NULL);
1008*6847Svk199839 #endif
1009*6847Svk199839 #ifndef OPENSSL_NO_DSA
1010*6847Svk199839 	(void) pk11_destroy_dsa_key_objects(NULL);
1011*6847Svk199839 #endif
1012*6847Svk199839 #ifndef OPENSSL_NO_DH
1013*6847Svk199839 	(void) pk11_destroy_dh_key_objects(NULL);
1014*6847Svk199839 #endif
1015*6847Svk199839 	(void) pk11_destroy_cipher_key_objects(NULL);
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate 	CRYPTO_w_lock(CRYPTO_LOCK_PK11_ENGINE);
10180Sstevel@tonic-gate 	while ((sp = free_session) != NULL)
10190Sstevel@tonic-gate 		{
10200Sstevel@tonic-gate 		if (sp->session != CK_INVALID_HANDLE && sp->pid == mypid)
10210Sstevel@tonic-gate 			{
10220Sstevel@tonic-gate 			rv = pFuncList->C_CloseSession(sp->session);
10230Sstevel@tonic-gate 			if (rv != CKR_OK)
10240Sstevel@tonic-gate 				{
10250Sstevel@tonic-gate 				char tmp_buf[20];
10260Sstevel@tonic-gate 				PK11err(PK11_F_FREE_ALL_SESSIONS,
10270Sstevel@tonic-gate 					PK11_R_CLOSESESSION);
10280Sstevel@tonic-gate 				snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
10290Sstevel@tonic-gate 				ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
10300Sstevel@tonic-gate 				}
10310Sstevel@tonic-gate 			}
10320Sstevel@tonic-gate 		if (sp->session_cipher != CK_INVALID_HANDLE && sp->pid == mypid)
10330Sstevel@tonic-gate 			{
10340Sstevel@tonic-gate 			rv = pFuncList->C_CloseSession(sp->session_cipher);
10350Sstevel@tonic-gate 			if (rv != CKR_OK)
10360Sstevel@tonic-gate 				{
10370Sstevel@tonic-gate 				char tmp_buf[20];
10380Sstevel@tonic-gate 				PK11err(PK11_F_FREE_ALL_SESSIONS,
10390Sstevel@tonic-gate 					PK11_R_CLOSESESSION);
10400Sstevel@tonic-gate 				snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
10410Sstevel@tonic-gate 				ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
10420Sstevel@tonic-gate 				}
10430Sstevel@tonic-gate 			}
10440Sstevel@tonic-gate 		free_session = sp->next;
1045*6847Svk199839 		pk11_free_nums(sp);
10460Sstevel@tonic-gate 		OPENSSL_free(sp);
10470Sstevel@tonic-gate 		}
10480Sstevel@tonic-gate 	ret = 1;
10490Sstevel@tonic-gate err:
10500Sstevel@tonic-gate 	CRYPTO_w_unlock(CRYPTO_LOCK_PK11_ENGINE);
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate 	return ret;
10530Sstevel@tonic-gate 	}
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate static int pk11_setup_session(PK11_SESSION *sp)
10570Sstevel@tonic-gate 	{
10580Sstevel@tonic-gate 	CK_RV rv;
10590Sstevel@tonic-gate 	sp->session = CK_INVALID_HANDLE;
10600Sstevel@tonic-gate 	rv = pFuncList->C_OpenSession(SLOTID, CKF_SERIAL_SESSION,
10610Sstevel@tonic-gate 		NULL_PTR, NULL_PTR, &sp->session);
10620Sstevel@tonic-gate 	if (rv == CKR_CRYPTOKI_NOT_INITIALIZED)
10630Sstevel@tonic-gate 		{
10640Sstevel@tonic-gate 		/*
10650Sstevel@tonic-gate 		 * We are probably a child process so force the
10660Sstevel@tonic-gate 		 * reinitialize of the session
10670Sstevel@tonic-gate 		 */
10680Sstevel@tonic-gate 		pk11_library_initialized = 0;
10690Sstevel@tonic-gate 		(void) pk11_library_init(NULL);
10700Sstevel@tonic-gate 		rv = pFuncList->C_OpenSession(SLOTID, CKF_SERIAL_SESSION,
10710Sstevel@tonic-gate 			NULL_PTR, NULL_PTR, &sp->session);
10720Sstevel@tonic-gate 		}
10730Sstevel@tonic-gate 	if (rv != CKR_OK)
10740Sstevel@tonic-gate 		{
10750Sstevel@tonic-gate 		char tmp_buf[20];
10760Sstevel@tonic-gate 		PK11err(PK11_F_SETUP_SESSION, PK11_R_OPENSESSION);
10770Sstevel@tonic-gate 		snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
10780Sstevel@tonic-gate 		ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
10790Sstevel@tonic-gate 		return 0;
10800Sstevel@tonic-gate 		}
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 	sp->session_cipher = CK_INVALID_HANDLE;
10830Sstevel@tonic-gate 	rv = pFuncList->C_OpenSession(SLOTID, CKF_SERIAL_SESSION,
10840Sstevel@tonic-gate 		NULL_PTR, NULL_PTR, &sp->session_cipher);
10850Sstevel@tonic-gate 	if (rv != CKR_OK)
10860Sstevel@tonic-gate 		{
10870Sstevel@tonic-gate 		char tmp_buf[20];
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate 		(void) pFuncList->C_CloseSession(sp->session);
10900Sstevel@tonic-gate 		sp->session = CK_INVALID_HANDLE;
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 		PK11err(PK11_F_SETUP_SESSION, PK11_R_OPENSESSION);
10930Sstevel@tonic-gate 		snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
10940Sstevel@tonic-gate 		ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
10950Sstevel@tonic-gate 		return 0;
10960Sstevel@tonic-gate 		}
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	sp->pid = getpid();
10990Sstevel@tonic-gate 	sp->rsa_pub_key = CK_INVALID_HANDLE;
11000Sstevel@tonic-gate 	sp->rsa_priv_key = CK_INVALID_HANDLE;
11010Sstevel@tonic-gate 	sp->dsa_pub_key = CK_INVALID_HANDLE;
11020Sstevel@tonic-gate 	sp->dsa_priv_key = CK_INVALID_HANDLE;
11030Sstevel@tonic-gate 	sp->dh_key = CK_INVALID_HANDLE;
11040Sstevel@tonic-gate 	sp->cipher_key = CK_INVALID_HANDLE;
1105*6847Svk199839 #ifndef OPENSSL_NO_RSA
1106*6847Svk199839 	sp->rsa_pub = NULL;
1107*6847Svk199839 	sp->rsa_n_num = NULL;
1108*6847Svk199839 	sp->rsa_e_num = NULL;
1109*6847Svk199839 	sp->rsa_priv = NULL;
1110*6847Svk199839 	sp->rsa_d_num = NULL;
1111*6847Svk199839 #endif
1112*6847Svk199839 #ifndef OPENSSL_NO_DSA
1113*6847Svk199839 	sp->dsa_pub = NULL;
1114*6847Svk199839 	sp->dsa_pub_num = NULL;
1115*6847Svk199839 	sp->dsa_priv = NULL;
1116*6847Svk199839 	sp->dsa_priv_num = NULL;
1117*6847Svk199839 #endif
1118*6847Svk199839 #ifndef OPENSSL_NO_DH
11190Sstevel@tonic-gate 	sp->dh = NULL;
1120*6847Svk199839 	sp->dh_priv_num = NULL;
1121*6847Svk199839 #endif
11220Sstevel@tonic-gate 	sp->encrypt = -1;
11230Sstevel@tonic-gate 
11240Sstevel@tonic-gate 	return 1;
11250Sstevel@tonic-gate 	}
11260Sstevel@tonic-gate 
1127*6847Svk199839 #ifndef OPENSSL_NO_RSA
1128*6847Svk199839 /* Destroy RSA public key from single session. */
1129*6847Svk199839 int pk11_destroy_rsa_object_pub(PK11_SESSION *sp, CK_BBOOL uselock)
1130*6847Svk199839 	{
1131*6847Svk199839 	int ret = 0;
1132*6847Svk199839 
1133*6847Svk199839 	if (sp->rsa_pub_key != CK_INVALID_HANDLE)
1134*6847Svk199839 		{
1135*6847Svk199839 		TRY_OBJ_DESTROY(sp->session, sp->rsa_pub_key, ret, uselock);
1136*6847Svk199839 		sp->rsa_pub_key = CK_INVALID_HANDLE;
1137*6847Svk199839 		sp->rsa_pub = NULL;
1138*6847Svk199839 		if (sp->rsa_n_num != NULL)
1139*6847Svk199839 			BN_free(sp->rsa_n_num);
1140*6847Svk199839 		sp->rsa_n_num = NULL;
1141*6847Svk199839 		if (sp->rsa_e_num != NULL)
1142*6847Svk199839 			BN_free(sp->rsa_e_num);
1143*6847Svk199839 		sp->rsa_e_num = NULL;
1144*6847Svk199839 		}
1145*6847Svk199839 
1146*6847Svk199839 	return (ret);
1147*6847Svk199839 	}
1148*6847Svk199839 
1149*6847Svk199839 /* Destroy RSA private key from single session. */
1150*6847Svk199839 int pk11_destroy_rsa_object_priv(PK11_SESSION *sp, CK_BBOOL uselock)
11510Sstevel@tonic-gate 	{
11520Sstevel@tonic-gate 	int ret = 0;
1153*6847Svk199839 
1154*6847Svk199839 	if (sp->rsa_priv_key != CK_INVALID_HANDLE)
1155*6847Svk199839 		{
1156*6847Svk199839 		TRY_OBJ_DESTROY(sp->session, sp->rsa_priv_key, ret, uselock);
1157*6847Svk199839 		sp->rsa_priv_key = CK_INVALID_HANDLE;
1158*6847Svk199839 		sp->rsa_priv = NULL;
1159*6847Svk199839 		if (sp->rsa_d_num != NULL)
1160*6847Svk199839 			BN_free(sp->rsa_d_num);
1161*6847Svk199839 		sp->rsa_d_num = NULL;
1162*6847Svk199839 		}
1163*6847Svk199839 
1164*6847Svk199839 	return (ret);
1165*6847Svk199839 	}
1166*6847Svk199839 
1167*6847Svk199839 
1168*6847Svk199839 /*
1169*6847Svk199839  * Destroy RSA key object wrapper.
1170*6847Svk199839  *
1171*6847Svk199839  * arg0: pointer to PKCS#11 engine session structure
1172*6847Svk199839  *       if session is NULL, try to destroy all objects in the free list
1173*6847Svk199839  */
1174*6847Svk199839 int pk11_destroy_rsa_key_objects(PK11_SESSION *session)
1175*6847Svk199839 	{
1176*6847Svk199839 	int ret = 1;
11770Sstevel@tonic-gate 	PK11_SESSION *sp = NULL;
11780Sstevel@tonic-gate 	PK11_SESSION *local_free_session;
1179*6847Svk199839 	CK_BBOOL uselock = TRUE;
11800Sstevel@tonic-gate 
1181*6847Svk199839 	if (session != NULL)
11820Sstevel@tonic-gate 		local_free_session = session;
11830Sstevel@tonic-gate 	else
1184*6847Svk199839 		{
1185*6847Svk199839 		CRYPTO_w_lock(CRYPTO_LOCK_PK11_ENGINE);
11860Sstevel@tonic-gate 		local_free_session = free_session;
1187*6847Svk199839 		uselock = FALSE;
1188*6847Svk199839 		}
11890Sstevel@tonic-gate 
1190*6847Svk199839 	/*
1191*6847Svk199839 	 * go through the list of sessions and delete key objects
1192*6847Svk199839 	 */
11930Sstevel@tonic-gate 	while ((sp = local_free_session) != NULL)
11940Sstevel@tonic-gate 		{
11950Sstevel@tonic-gate 		local_free_session = sp->next;
11960Sstevel@tonic-gate 
1197*6847Svk199839 		/*
1198*6847Svk199839 		 * Do not terminate list traversal if one of the
1199*6847Svk199839 		 * destroy operations fails.
1200*6847Svk199839 		 */
1201*6847Svk199839 		if (pk11_destroy_rsa_object_pub(sp, uselock) == 0)
12020Sstevel@tonic-gate 			{
1203*6847Svk199839 			ret = 0;
1204*6847Svk199839 			continue;
12050Sstevel@tonic-gate 			}
1206*6847Svk199839 		if (pk11_destroy_rsa_object_priv(sp, uselock) == 0)
1207*6847Svk199839 			{
1208*6847Svk199839 			ret = 0;
1209*6847Svk199839 			continue;
1210*6847Svk199839 			}
1211*6847Svk199839 		}
12120Sstevel@tonic-gate 
1213*6847Svk199839 	if (session == NULL)
1214*6847Svk199839 		CRYPTO_w_unlock(CRYPTO_LOCK_PK11_ENGINE);
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate 	return ret;
12170Sstevel@tonic-gate 	}
1218*6847Svk199839 #endif
12190Sstevel@tonic-gate 
1220*6847Svk199839 #ifndef OPENSSL_NO_DSA
1221*6847Svk199839 /* Destroy DSA public key from single session. */
1222*6847Svk199839 int pk11_destroy_dsa_object_pub(PK11_SESSION *sp, CK_BBOOL uselock)
12230Sstevel@tonic-gate 	{
12240Sstevel@tonic-gate 	int ret = 0;
1225*6847Svk199839 
1226*6847Svk199839 	if (sp->dsa_pub_key != CK_INVALID_HANDLE)
1227*6847Svk199839 		{
1228*6847Svk199839 		TRY_OBJ_DESTROY(sp->session, sp->dsa_pub_key, ret, uselock);
1229*6847Svk199839 		sp->dsa_pub_key = CK_INVALID_HANDLE;
1230*6847Svk199839 		sp->dsa_pub = NULL;
1231*6847Svk199839 		if (sp->dsa_pub_num != NULL)
1232*6847Svk199839 			BN_free(sp->dsa_pub_num);
1233*6847Svk199839 		sp->dsa_pub_num = NULL;
1234*6847Svk199839 		}
1235*6847Svk199839 
1236*6847Svk199839 	return (ret);
1237*6847Svk199839 	}
1238*6847Svk199839 
1239*6847Svk199839 /* Destroy DSA private key from single session. */
1240*6847Svk199839 int pk11_destroy_dsa_object_priv(PK11_SESSION *sp, CK_BBOOL uselock)
1241*6847Svk199839 	{
1242*6847Svk199839 	int ret = 0;
1243*6847Svk199839 
1244*6847Svk199839 	if (sp->dsa_priv_key != CK_INVALID_HANDLE)
1245*6847Svk199839 		{
1246*6847Svk199839 		TRY_OBJ_DESTROY(sp->session, sp->dsa_priv_key, ret, uselock);
1247*6847Svk199839 		sp->dsa_priv_key = CK_INVALID_HANDLE;
1248*6847Svk199839 		sp->dsa_priv = NULL;
1249*6847Svk199839 		if (sp->dsa_priv_num != NULL)
1250*6847Svk199839 			BN_free(sp->dsa_priv_num);
1251*6847Svk199839 		sp->dsa_priv_num = NULL;
1252*6847Svk199839 		}
1253*6847Svk199839 
1254*6847Svk199839 	return (ret);
1255*6847Svk199839 	}
1256*6847Svk199839 
1257*6847Svk199839 /*
1258*6847Svk199839  * Destroy DSA key object wrapper.
1259*6847Svk199839  *
1260*6847Svk199839  * arg0: pointer to PKCS#11 engine session structure
1261*6847Svk199839  *       if session is NULL, try to destroy all objects in the free list
1262*6847Svk199839  */
1263*6847Svk199839 int pk11_destroy_dsa_key_objects(PK11_SESSION *session)
1264*6847Svk199839 	{
1265*6847Svk199839 	int ret = 1;
12660Sstevel@tonic-gate 	PK11_SESSION *sp = NULL;
12670Sstevel@tonic-gate 	PK11_SESSION *local_free_session;
1268*6847Svk199839 	CK_BBOOL uselock = TRUE;
12690Sstevel@tonic-gate 
1270*6847Svk199839 	if (session != NULL)
12710Sstevel@tonic-gate 		local_free_session = session;
12720Sstevel@tonic-gate 	else
1273*6847Svk199839 		{
1274*6847Svk199839 		CRYPTO_w_lock(CRYPTO_LOCK_PK11_ENGINE);
12750Sstevel@tonic-gate 		local_free_session = free_session;
1276*6847Svk199839 		uselock = FALSE;
1277*6847Svk199839 		}
1278*6847Svk199839 
1279*6847Svk199839 	/*
1280*6847Svk199839 	 * go through the list of sessions and delete key objects
1281*6847Svk199839 	 */
12820Sstevel@tonic-gate 	while ((sp = local_free_session) != NULL)
12830Sstevel@tonic-gate 		{
12840Sstevel@tonic-gate 		local_free_session = sp->next;
12850Sstevel@tonic-gate 
1286*6847Svk199839 		/*
1287*6847Svk199839 		 * Do not terminate list traversal if one of the
1288*6847Svk199839 		 * destroy operations fails.
1289*6847Svk199839 		 */
1290*6847Svk199839 		if (pk11_destroy_dsa_object_pub(sp, uselock) == 0)
12910Sstevel@tonic-gate 			{
1292*6847Svk199839 			ret = 0;
1293*6847Svk199839 			continue;
12940Sstevel@tonic-gate 			}
1295*6847Svk199839 		if (pk11_destroy_dsa_object_priv(sp, uselock) == 0)
1296*6847Svk199839 			{
1297*6847Svk199839 			ret = 0;
1298*6847Svk199839 			continue;
1299*6847Svk199839 			}
13000Sstevel@tonic-gate 		}
1301*6847Svk199839 
1302*6847Svk199839 	if (session == NULL)
1303*6847Svk199839 		CRYPTO_w_unlock(CRYPTO_LOCK_PK11_ENGINE);
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate 	return ret;
13060Sstevel@tonic-gate 	}
1307*6847Svk199839 #endif
1308*6847Svk199839 
1309*6847Svk199839 #ifndef OPENSSL_NO_DH
1310*6847Svk199839 /* Destroy DH key from single session. */
1311*6847Svk199839 int pk11_destroy_dh_object(PK11_SESSION *sp, CK_BBOOL uselock)
1312*6847Svk199839 	{
1313*6847Svk199839 	int ret = 0;
1314*6847Svk199839 
1315*6847Svk199839 	if (sp->dh_key != CK_INVALID_HANDLE)
1316*6847Svk199839 		{
1317*6847Svk199839 		TRY_OBJ_DESTROY(sp->session, sp->dh_key, ret, uselock);
1318*6847Svk199839 		sp->dh_key = CK_INVALID_HANDLE;
1319*6847Svk199839 		sp->dh = NULL;
1320*6847Svk199839 		if (sp->dh_priv_num != NULL)
1321*6847Svk199839 			BN_free(sp->dh_priv_num);
1322*6847Svk199839 		sp->dh_priv_num = NULL;
1323*6847Svk199839 		}
1324*6847Svk199839 
1325*6847Svk199839 	return (ret);
1326*6847Svk199839 	}
1327*6847Svk199839 
1328*6847Svk199839 /*
1329*6847Svk199839  * Destroy DH key object wrapper.
1330*6847Svk199839  *
1331*6847Svk199839  * arg0: pointer to PKCS#11 engine session structure
1332*6847Svk199839  *       if session is NULL, try to destroy all objects in the free list
1333*6847Svk199839  */
1334*6847Svk199839 int pk11_destroy_dh_key_objects(PK11_SESSION *session)
1335*6847Svk199839 	{
1336*6847Svk199839 	int ret = 1;
1337*6847Svk199839 	PK11_SESSION *sp = NULL;
1338*6847Svk199839 	PK11_SESSION *local_free_session;
1339*6847Svk199839 	CK_BBOOL uselock = TRUE;
1340*6847Svk199839 
1341*6847Svk199839 	if (session != NULL)
1342*6847Svk199839 		local_free_session = session;
1343*6847Svk199839 	else
1344*6847Svk199839 		{
1345*6847Svk199839 		CRYPTO_w_lock(CRYPTO_LOCK_PK11_ENGINE);
1346*6847Svk199839 		local_free_session = free_session;
1347*6847Svk199839 		uselock = FALSE;
1348*6847Svk199839 		}
1349*6847Svk199839 
1350*6847Svk199839 	while ((sp = local_free_session) != NULL)
1351*6847Svk199839 		{
1352*6847Svk199839 		local_free_session = sp->next;
1353*6847Svk199839 
1354*6847Svk199839 		/*
1355*6847Svk199839 		 * Do not terminate list traversal if one of the
1356*6847Svk199839 		 * destroy operations fails.
1357*6847Svk199839 		 */
1358*6847Svk199839 		if (pk11_destroy_dh_object(sp, uselock) == 0)
1359*6847Svk199839 			{
1360*6847Svk199839 			ret = 0;
1361*6847Svk199839 			continue;
1362*6847Svk199839 			}
1363*6847Svk199839 		}
1364*6847Svk199839 err:
1365*6847Svk199839 	if (session == NULL)
1366*6847Svk199839 		CRYPTO_w_unlock(CRYPTO_LOCK_PK11_ENGINE);
1367*6847Svk199839 
1368*6847Svk199839 	return ret;
1369*6847Svk199839 	}
1370*6847Svk199839 #endif
1371*6847Svk199839 
13720Sstevel@tonic-gate 
13730Sstevel@tonic-gate static int pk11_destroy_object(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE oh)
13740Sstevel@tonic-gate 	{
13750Sstevel@tonic-gate 	CK_RV rv;
13760Sstevel@tonic-gate 	rv = pFuncList->C_DestroyObject(session, oh);
13770Sstevel@tonic-gate 	if (rv != CKR_OK)
13780Sstevel@tonic-gate 		{
13790Sstevel@tonic-gate 		char tmp_buf[20];
13800Sstevel@tonic-gate 		PK11err(PK11_F_DESTROY_OBJECT, PK11_R_DESTROYOBJECT);
13810Sstevel@tonic-gate 		snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
13820Sstevel@tonic-gate 		ERR_add_error_data(2, "PK11 CK_RV=0X",
13830Sstevel@tonic-gate 			tmp_buf);
13840Sstevel@tonic-gate 		return 0;
13850Sstevel@tonic-gate 		}
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate 	return 1;
13880Sstevel@tonic-gate 	}
13890Sstevel@tonic-gate 
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate /* Symmetric ciphers and digests support functions
13920Sstevel@tonic-gate  */
13930Sstevel@tonic-gate 
13940Sstevel@tonic-gate static int
13950Sstevel@tonic-gate cipher_nid_to_pk11(int nid)
13960Sstevel@tonic-gate 	{
13970Sstevel@tonic-gate 	int i;
13980Sstevel@tonic-gate 
13990Sstevel@tonic-gate 	for (i = 0; i < PK11_CIPHER_MAX; i++)
14000Sstevel@tonic-gate 		if (ciphers[i].nid == nid)
14010Sstevel@tonic-gate 			return (ciphers[i].id);
14020Sstevel@tonic-gate 	return (-1);
14030Sstevel@tonic-gate 	}
14040Sstevel@tonic-gate 
14050Sstevel@tonic-gate static int
14060Sstevel@tonic-gate pk11_usable_ciphers(const int **nids)
14070Sstevel@tonic-gate 	{
14080Sstevel@tonic-gate 	if (cipher_count > 0)
14090Sstevel@tonic-gate 		*nids = cipher_nids;
14100Sstevel@tonic-gate 	else
14110Sstevel@tonic-gate 		*nids = NULL;
14120Sstevel@tonic-gate 	return (cipher_count);
14130Sstevel@tonic-gate 	}
14140Sstevel@tonic-gate 
14150Sstevel@tonic-gate static int
14160Sstevel@tonic-gate pk11_usable_digests(const int **nids)
14170Sstevel@tonic-gate 	{
14180Sstevel@tonic-gate 	if (digest_count > 0)
14190Sstevel@tonic-gate 		*nids = digest_nids;
14200Sstevel@tonic-gate 	else
14210Sstevel@tonic-gate 		*nids = NULL;
14220Sstevel@tonic-gate 	return (digest_count);
14230Sstevel@tonic-gate 	}
14240Sstevel@tonic-gate 
14250Sstevel@tonic-gate static int
14260Sstevel@tonic-gate pk11_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
14270Sstevel@tonic-gate     const unsigned char *iv, int enc)
14280Sstevel@tonic-gate 	{
14290Sstevel@tonic-gate 	CK_RV rv;
14304320Sjp161948 	CK_MECHANISM mech;
14310Sstevel@tonic-gate 	int index;
14320Sstevel@tonic-gate 	PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->cipher_data;
14330Sstevel@tonic-gate 	PK11_SESSION *sp;
14340Sstevel@tonic-gate 	PK11_CIPHER *pcp;
14350Sstevel@tonic-gate 	char tmp_buf[20];
14360Sstevel@tonic-gate 
14370Sstevel@tonic-gate 	state->sp = NULL;
14380Sstevel@tonic-gate 
14390Sstevel@tonic-gate 	index = cipher_nid_to_pk11(ctx->cipher->nid);
14400Sstevel@tonic-gate 	if (index < 0 || index >= PK11_CIPHER_MAX)
14410Sstevel@tonic-gate 		return 0;
14420Sstevel@tonic-gate 
14430Sstevel@tonic-gate 	pcp = &ciphers[index];
14440Sstevel@tonic-gate 	if (ctx->cipher->iv_len > pcp->ivmax || ctx->key_len != pcp->key_len)
14450Sstevel@tonic-gate 		return 0;
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 	if ((sp = pk11_get_session()) == NULL)
14480Sstevel@tonic-gate 		return 0;
14490Sstevel@tonic-gate 
14504320Sjp161948 	/* if applicable, the mechanism parameter is used for IV */
14514320Sjp161948 	mech.mechanism = pcp->mech_type;
14524320Sjp161948 	mech.pParameter = NULL;
14534320Sjp161948 	mech.ulParameterLen = 0;
14544320Sjp161948 
14550Sstevel@tonic-gate 	/* The key object is destroyed here if it is not the current key
14560Sstevel@tonic-gate 	 */
1457*6847Svk199839 	(void) check_new_cipher_key(sp, key);
14580Sstevel@tonic-gate 
14590Sstevel@tonic-gate 	/* If the key is the same and the encryption is also the same,
1460*6847Svk199839 	 * then just reuse it. However, we must not forget to reinitialize the
1461*6847Svk199839 	 * context that was finalized in pk11_cipher_cleanup().
14620Sstevel@tonic-gate 	 */
14630Sstevel@tonic-gate 	if (sp->cipher_key != CK_INVALID_HANDLE && sp->encrypt == ctx->encrypt)
14640Sstevel@tonic-gate 		{
14650Sstevel@tonic-gate 		state->sp = sp;
1466*6847Svk199839 		if (pk11_init_symmetric(ctx, sp, &mech) == 0)
1467*6847Svk199839 			return (0);
1468*6847Svk199839 
1469*6847Svk199839 		return (1);
14700Sstevel@tonic-gate 		}
14710Sstevel@tonic-gate 
14720Sstevel@tonic-gate 	/* Check if the key has been invalidated. If so, a new key object
14730Sstevel@tonic-gate 	 * needs to be created.
14740Sstevel@tonic-gate 	 */
14750Sstevel@tonic-gate 	if (sp->cipher_key == CK_INVALID_HANDLE)
14760Sstevel@tonic-gate 		{
14770Sstevel@tonic-gate 		sp->cipher_key = pk11_get_cipher_key(
14780Sstevel@tonic-gate 			ctx, key, pcp->key_type, sp);
14790Sstevel@tonic-gate 		}
14800Sstevel@tonic-gate 
14810Sstevel@tonic-gate 	if (sp->encrypt != ctx->encrypt && sp->encrypt != -1)
14820Sstevel@tonic-gate 		{
14830Sstevel@tonic-gate 		/* The previous encryption/decryption
14840Sstevel@tonic-gate 		 * is different. Need to terminate the previous
14850Sstevel@tonic-gate 		 * active encryption/decryption here
14860Sstevel@tonic-gate 		 */
14870Sstevel@tonic-gate 		if (!pk11_cipher_final(sp))
14880Sstevel@tonic-gate 			{
14890Sstevel@tonic-gate 			pk11_return_session(sp);
14900Sstevel@tonic-gate 			return 0;
14910Sstevel@tonic-gate 			}
14920Sstevel@tonic-gate 		}
14930Sstevel@tonic-gate 
14940Sstevel@tonic-gate 	if (sp->cipher_key == CK_INVALID_HANDLE)
14950Sstevel@tonic-gate 		{
14960Sstevel@tonic-gate 		pk11_return_session(sp);
14970Sstevel@tonic-gate 		return 0;
14980Sstevel@tonic-gate 		}
14990Sstevel@tonic-gate 
1500*6847Svk199839 	/* now initialize the context with a new key */
1501*6847Svk199839 	if (pk11_init_symmetric(ctx, sp, &mech) == 0)
1502*6847Svk199839 		return (0);
15030Sstevel@tonic-gate 
15040Sstevel@tonic-gate 	sp->encrypt = ctx->encrypt;
15050Sstevel@tonic-gate 	state->sp = sp;
15060Sstevel@tonic-gate 
15070Sstevel@tonic-gate 	return 1;
15080Sstevel@tonic-gate 	}
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate /* When reusing the same key in an encryption/decryption session for a
15110Sstevel@tonic-gate  * decryption/encryption session, we need to close the active session
15120Sstevel@tonic-gate  * and recreate a new one. Note that the key is in the global session so
15130Sstevel@tonic-gate  * that it needs not be recreated.
15140Sstevel@tonic-gate  *
15150Sstevel@tonic-gate  * It is more appropriate to use C_En/DecryptFinish here. At the time of this
15160Sstevel@tonic-gate  * development, these two functions in the PKCS#11 libraries used return
15170Sstevel@tonic-gate  * unexpected errors when passing in 0 length output. It may be a good
15180Sstevel@tonic-gate  * idea to try them again if performance is a problem here and fix
15190Sstevel@tonic-gate  * C_En/DecryptFinial if there are bugs there causing the problem.
15200Sstevel@tonic-gate  */
15210Sstevel@tonic-gate static int
15220Sstevel@tonic-gate pk11_cipher_final(PK11_SESSION *sp)
15230Sstevel@tonic-gate 	{
15240Sstevel@tonic-gate 	CK_RV rv;
15250Sstevel@tonic-gate 	char tmp_buf[20];
15260Sstevel@tonic-gate 
15270Sstevel@tonic-gate 	rv = pFuncList->C_CloseSession(sp->session_cipher);
15280Sstevel@tonic-gate 	if (rv != CKR_OK)
15290Sstevel@tonic-gate 		{
15300Sstevel@tonic-gate 		PK11err(PK11_F_CIPHER_FINAL, PK11_R_CLOSESESSION);
15310Sstevel@tonic-gate 		snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
15320Sstevel@tonic-gate 		ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
15330Sstevel@tonic-gate 		return 0;
15340Sstevel@tonic-gate 		}
15350Sstevel@tonic-gate 
15360Sstevel@tonic-gate 	rv = pFuncList->C_OpenSession(SLOTID, CKF_SERIAL_SESSION,
15370Sstevel@tonic-gate 		NULL_PTR, NULL_PTR, &sp->session_cipher);
15380Sstevel@tonic-gate 	if (rv != CKR_OK)
15390Sstevel@tonic-gate 		{
15400Sstevel@tonic-gate 		PK11err(PK11_F_CIPHER_FINAL, PK11_R_OPENSESSION);
15410Sstevel@tonic-gate 		snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
15420Sstevel@tonic-gate 		ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
15430Sstevel@tonic-gate 		return 0;
15440Sstevel@tonic-gate 		}
15450Sstevel@tonic-gate 
15460Sstevel@tonic-gate 	return 1;
15470Sstevel@tonic-gate 	}
15480Sstevel@tonic-gate 
15490Sstevel@tonic-gate /* An engine interface function. The calling function allocates sufficient
15500Sstevel@tonic-gate  * memory for the output buffer "out" to hold the results */
15510Sstevel@tonic-gate static int
15520Sstevel@tonic-gate pk11_cipher_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
15530Sstevel@tonic-gate 	const unsigned char *in, unsigned int inl)
15540Sstevel@tonic-gate 	{
15550Sstevel@tonic-gate 	PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->cipher_data;
15560Sstevel@tonic-gate 	PK11_SESSION *sp;
15570Sstevel@tonic-gate 	CK_RV rv;
15580Sstevel@tonic-gate 	unsigned long outl = inl;
15590Sstevel@tonic-gate 	char tmp_buf[20];
15600Sstevel@tonic-gate 
15610Sstevel@tonic-gate 	if (state == NULL || state->sp == NULL)
15620Sstevel@tonic-gate 		return 0;
15630Sstevel@tonic-gate 
15640Sstevel@tonic-gate 	sp = (PK11_SESSION *) state->sp;
15650Sstevel@tonic-gate 
15660Sstevel@tonic-gate 	if (!inl)
15670Sstevel@tonic-gate 		return 1;
15680Sstevel@tonic-gate 
15690Sstevel@tonic-gate 	/* RC4 is the only stream cipher we support */
15700Sstevel@tonic-gate 	if (ctx->cipher->nid != NID_rc4 && (inl % ctx->cipher->block_size) != 0)
15710Sstevel@tonic-gate 		return 0;
15720Sstevel@tonic-gate 
15730Sstevel@tonic-gate 	if (ctx->encrypt)
15740Sstevel@tonic-gate 		{
15750Sstevel@tonic-gate 		rv = pFuncList->C_EncryptUpdate(sp->session_cipher,
15760Sstevel@tonic-gate 			(unsigned char *)in, inl, out, &outl);
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate 		if (rv != CKR_OK)
15790Sstevel@tonic-gate 			{
15800Sstevel@tonic-gate 			PK11err(PK11_F_CIPHER_DO_CIPHER,
15810Sstevel@tonic-gate 				PK11_R_ENCRYPTUPDATE);
15820Sstevel@tonic-gate 			snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
15830Sstevel@tonic-gate 			ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
15840Sstevel@tonic-gate 			return 0;
15850Sstevel@tonic-gate 			}
15860Sstevel@tonic-gate 		}
15870Sstevel@tonic-gate 	else
15880Sstevel@tonic-gate 		{
15890Sstevel@tonic-gate 		rv = pFuncList->C_DecryptUpdate(sp->session_cipher,
15900Sstevel@tonic-gate 			(unsigned char *)in, inl, out, &outl);
15910Sstevel@tonic-gate 
15920Sstevel@tonic-gate 		if (rv != CKR_OK)
15930Sstevel@tonic-gate 			{
15940Sstevel@tonic-gate 			PK11err(PK11_F_CIPHER_DO_CIPHER,
15950Sstevel@tonic-gate 				PK11_R_DECRYPTUPDATE);
15960Sstevel@tonic-gate 			snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
15970Sstevel@tonic-gate 			ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
15980Sstevel@tonic-gate 			return 0;
15990Sstevel@tonic-gate 			}
16000Sstevel@tonic-gate 		}
16010Sstevel@tonic-gate 
16020Sstevel@tonic-gate 	/* for DES_CBC, DES3_CBC, AES_CBC, and RC4, the output size is always
16030Sstevel@tonic-gate 	 * the same size of input
16040Sstevel@tonic-gate 	 * The application has guaranteed to call the block ciphers with
16050Sstevel@tonic-gate 	 * correctly aligned buffers.
16060Sstevel@tonic-gate 	 */
16070Sstevel@tonic-gate 	if (inl != outl)
16080Sstevel@tonic-gate 		return 0;
16090Sstevel@tonic-gate 
16100Sstevel@tonic-gate 	return 1;
16110Sstevel@tonic-gate 	}
16120Sstevel@tonic-gate 
1613*6847Svk199839 /*
1614*6847Svk199839  * Return the session to the pool. Calling C_EncryptFinal() and
1615*6847Svk199839  * C_DecryptFinal() here is the right thing because in
1616*6847Svk199839  * EVP_DecryptFinal_ex(), engine's do_cipher() is not even called, and in
1617*6847Svk199839  * EVP_EncryptFinal_ex() it is called but the engine can't find out that
1618*6847Svk199839  * it's the finalizing call. We wouldn't necessarily have to finalize the
1619*6847Svk199839  * context here since reinitializing it with C_(Encrypt|Decrypt)Init()
1620*6847Svk199839  * should be fine but for the sake of correctness, let's do it. Some
1621*6847Svk199839  * implementations might leak memory if the previously used context is
1622*6847Svk199839  * initialized without finalizing it first.
16230Sstevel@tonic-gate  */
16240Sstevel@tonic-gate static int
16250Sstevel@tonic-gate pk11_cipher_cleanup(EVP_CIPHER_CTX *ctx)
16260Sstevel@tonic-gate 	{
1627*6847Svk199839 	CK_RV rv;
1628*6847Svk199839 	CK_ULONG len;
1629*6847Svk199839 	char tmp_buf[20];
1630*6847Svk199839 	CK_BYTE buf[EVP_MAX_BLOCK_LENGTH];
16310Sstevel@tonic-gate 	PK11_CIPHER_STATE *state = ctx->cipher_data;
16320Sstevel@tonic-gate 
16330Sstevel@tonic-gate 	if (state != NULL && state->sp != NULL)
16340Sstevel@tonic-gate 		{
1635*6847Svk199839 		/*
1636*6847Svk199839 		 * We are not interested in the data here, we just need to get
1637*6847Svk199839 		 * rid of the context.
1638*6847Svk199839 		 */
1639*6847Svk199839 		if (ctx->encrypt)
1640*6847Svk199839 			rv = pFuncList->C_EncryptFinal(
1641*6847Svk199839 			    state->sp->session_cipher, buf, &len);
1642*6847Svk199839 		else
1643*6847Svk199839 			rv = pFuncList->C_DecryptFinal(
1644*6847Svk199839 			    state->sp->session_cipher, buf, &len);
1645*6847Svk199839 
1646*6847Svk199839 		if (rv != CKR_OK)
1647*6847Svk199839 			{
1648*6847Svk199839 			PK11err(PK11_F_CIPHER_CLEANUP, ctx->encrypt ?
1649*6847Svk199839 			    PK11_R_ENCRYPTFINAL : PK11_R_DECRYPTFINAL);
1650*6847Svk199839 			snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
1651*6847Svk199839 			ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
1652*6847Svk199839 			pk11_return_session(state->sp);
1653*6847Svk199839 			return (0);
1654*6847Svk199839 			}
1655*6847Svk199839 
16560Sstevel@tonic-gate 		pk11_return_session(state->sp);
16570Sstevel@tonic-gate 		state->sp = NULL;
16580Sstevel@tonic-gate 		}
16590Sstevel@tonic-gate 
1660*6847Svk199839 	return (1);
1661*6847Svk199839 	}
1662*6847Svk199839 
1663*6847Svk199839 /*
1664*6847Svk199839  * Init context for encryption or decryption using a symmetric key.
1665*6847Svk199839  */
1666*6847Svk199839 static int pk11_init_symmetric(EVP_CIPHER_CTX *ctx, PK11_SESSION *sp,
1667*6847Svk199839     CK_MECHANISM_PTR pmech)
1668*6847Svk199839 	{
1669*6847Svk199839 	CK_RV rv;
1670*6847Svk199839 	char tmp_buf[20];
1671*6847Svk199839 
1672*6847Svk199839 	if (ctx->cipher->iv_len > 0)
1673*6847Svk199839 		{
1674*6847Svk199839 		/*
1675*6847Svk199839 		 * We expect pmech->mechanism to be already set and
1676*6847Svk199839 		 * pParameter/ulParameterLen initialized to NULL/0 before
1677*6847Svk199839 		 * pk11_init_symetric() is called.
1678*6847Svk199839 		 */
1679*6847Svk199839 		OPENSSL_assert(pmech->mechanism != NULL);
1680*6847Svk199839 		OPENSSL_assert(pmech->pParameter == NULL);
1681*6847Svk199839 		OPENSSL_assert(pmech->ulParameterLen == 0);
1682*6847Svk199839 		pmech->pParameter = (void *) ctx->iv;
1683*6847Svk199839 		pmech->ulParameterLen = ctx->cipher->iv_len;
1684*6847Svk199839 		}
1685*6847Svk199839 
1686*6847Svk199839 	/* If we get here, the encryption needs to be reinitialized */
1687*6847Svk199839 	if (ctx->encrypt)
1688*6847Svk199839 		rv = pFuncList->C_EncryptInit(sp->session_cipher, pmech,
1689*6847Svk199839 			sp->cipher_key);
1690*6847Svk199839 	else
1691*6847Svk199839 		rv = pFuncList->C_DecryptInit(sp->session_cipher, pmech,
1692*6847Svk199839 			sp->cipher_key);
1693*6847Svk199839 
1694*6847Svk199839 	if (rv != CKR_OK)
1695*6847Svk199839 		{
1696*6847Svk199839 		PK11err(PK11_F_CIPHER_INIT, ctx->encrypt ?
1697*6847Svk199839 		    PK11_R_ENCRYPTINIT : PK11_R_DECRYPTINIT);
1698*6847Svk199839 		snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
1699*6847Svk199839 		ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
1700*6847Svk199839 		pk11_return_session(sp);
1701*6847Svk199839 		return (0);
1702*6847Svk199839 		}
1703*6847Svk199839 
1704*6847Svk199839 	return (1);
17050Sstevel@tonic-gate 	}
17060Sstevel@tonic-gate 
17070Sstevel@tonic-gate /* Registered by the ENGINE when used to find out how to deal with
17080Sstevel@tonic-gate  * a particular NID in the ENGINE. This says what we'll do at the
17090Sstevel@tonic-gate  * top level - note, that list is restricted by what we answer with
17100Sstevel@tonic-gate  */
17110Sstevel@tonic-gate static int
17120Sstevel@tonic-gate pk11_engine_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
17130Sstevel@tonic-gate 	const int **nids, int nid)
17140Sstevel@tonic-gate 	{
17150Sstevel@tonic-gate 	if (!cipher)
17160Sstevel@tonic-gate 		return (pk11_usable_ciphers(nids));
17170Sstevel@tonic-gate 
17180Sstevel@tonic-gate 	switch (nid)
17190Sstevel@tonic-gate 		{
17200Sstevel@tonic-gate 		case NID_des_ede3_cbc:
17210Sstevel@tonic-gate 			*cipher = &pk11_3des_cbc;
17220Sstevel@tonic-gate 			break;
17230Sstevel@tonic-gate 		case NID_des_cbc:
17240Sstevel@tonic-gate 			*cipher = &pk11_des_cbc;
17250Sstevel@tonic-gate 			break;
17260Sstevel@tonic-gate 		case NID_aes_128_cbc:
17270Sstevel@tonic-gate 			*cipher = &pk11_aes_cbc;
17280Sstevel@tonic-gate 			break;
17290Sstevel@tonic-gate 		case NID_rc4:
17300Sstevel@tonic-gate 			*cipher = &pk11_rc4;
17310Sstevel@tonic-gate 			break;
17320Sstevel@tonic-gate 		default:
17330Sstevel@tonic-gate 			*cipher = NULL;
17340Sstevel@tonic-gate 			break;
17350Sstevel@tonic-gate 		}
17360Sstevel@tonic-gate 	return (*cipher != NULL);
17370Sstevel@tonic-gate 	}
17380Sstevel@tonic-gate 
17390Sstevel@tonic-gate static int
17400Sstevel@tonic-gate pk11_engine_digests(ENGINE *e, const EVP_MD **digest,
17410Sstevel@tonic-gate 	const int **nids, int nid)
17420Sstevel@tonic-gate 	{
17430Sstevel@tonic-gate 	if (!digest)
17440Sstevel@tonic-gate 		return (pk11_usable_digests(nids));
17450Sstevel@tonic-gate 
17460Sstevel@tonic-gate 	switch (nid)
17470Sstevel@tonic-gate 		{
17480Sstevel@tonic-gate 		case NID_md5:
17490Sstevel@tonic-gate 			*digest = &pk11_md5;
17500Sstevel@tonic-gate 			break;
17510Sstevel@tonic-gate 		case NID_sha1:
17520Sstevel@tonic-gate 			*digest = &pk11_sha1;
17530Sstevel@tonic-gate 			break;
17540Sstevel@tonic-gate 		default:
17550Sstevel@tonic-gate 			*digest = NULL;
17560Sstevel@tonic-gate 			break;
17570Sstevel@tonic-gate 		}
17580Sstevel@tonic-gate 	return (*digest != NULL);
17590Sstevel@tonic-gate 	}
17600Sstevel@tonic-gate 
17610Sstevel@tonic-gate 
17620Sstevel@tonic-gate /* Create a secret key object in a PKCS#11 session
17630Sstevel@tonic-gate  */
17640Sstevel@tonic-gate static CK_OBJECT_HANDLE pk11_get_cipher_key(EVP_CIPHER_CTX *ctx,
17650Sstevel@tonic-gate 	const unsigned char *key, CK_KEY_TYPE key_type, PK11_SESSION *sp)
17660Sstevel@tonic-gate 	{
17670Sstevel@tonic-gate 	CK_RV rv;
17680Sstevel@tonic-gate 	CK_OBJECT_HANDLE h_key = CK_INVALID_HANDLE;
17690Sstevel@tonic-gate 	CK_OBJECT_CLASS obj_key = CKO_SECRET_KEY;
17700Sstevel@tonic-gate 	CK_ULONG ul_key_attr_count = 6;
17710Sstevel@tonic-gate 	char tmp_buf[20];
17720Sstevel@tonic-gate 
17730Sstevel@tonic-gate 	CK_ATTRIBUTE  a_key_template[] =
17740Sstevel@tonic-gate 		{
17750Sstevel@tonic-gate 		{CKA_CLASS, (void*) NULL, sizeof(CK_OBJECT_CLASS)},
17760Sstevel@tonic-gate 		{CKA_KEY_TYPE, (void*) NULL, sizeof(CK_KEY_TYPE)},
17770Sstevel@tonic-gate 		{CKA_TOKEN, &false, sizeof(false)},
17780Sstevel@tonic-gate 		{CKA_ENCRYPT, &true, sizeof(true)},
17790Sstevel@tonic-gate 		{CKA_DECRYPT, &true, sizeof(true)},
17800Sstevel@tonic-gate 		{CKA_VALUE, (void*) NULL, 0},
17810Sstevel@tonic-gate 		};
17820Sstevel@tonic-gate 
17830Sstevel@tonic-gate 	/* Create secret key object in global_session. All other sessions
17840Sstevel@tonic-gate 	 * can use the key handles. Here is why:
17850Sstevel@tonic-gate 	 * OpenSSL will call EncryptInit and EncryptUpdate using a secret key.
17860Sstevel@tonic-gate 	 * It may then call DecryptInit and DecryptUpdate using the same key.
17870Sstevel@tonic-gate 	 * To use the same key object, we need to call EncryptFinal with
17880Sstevel@tonic-gate 	 * a 0 length message. Currently, this does not work for 3DES
17890Sstevel@tonic-gate 	 * mechanism. To get around this problem, we close the session and
17900Sstevel@tonic-gate 	 * then create a new session to use the same key object. When a session
17910Sstevel@tonic-gate 	 * is closed, all the object handles will be invalid. Thus, create key
17920Sstevel@tonic-gate 	 * objects in a global session, an individual session may be closed to
17930Sstevel@tonic-gate 	 * terminate the active operation.
17940Sstevel@tonic-gate 	 */
17950Sstevel@tonic-gate 	CK_SESSION_HANDLE session = global_session;
17960Sstevel@tonic-gate 	a_key_template[0].pValue = &obj_key;
17970Sstevel@tonic-gate 	a_key_template[1].pValue = &key_type;
17980Sstevel@tonic-gate 	a_key_template[5].pValue = (void *) key;
17990Sstevel@tonic-gate 	a_key_template[5].ulValueLen = (unsigned long) ctx->key_len;
18000Sstevel@tonic-gate 
18014602Sjp161948 	rv = pFuncList->C_CreateObject(session,
18024602Sjp161948 		a_key_template, ul_key_attr_count, &h_key);
18030Sstevel@tonic-gate 	if (rv != CKR_OK)
18040Sstevel@tonic-gate 		{
18054602Sjp161948 		PK11err(PK11_F_GET_CIPHER_KEY, PK11_R_CREATEOBJECT);
18060Sstevel@tonic-gate 		snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
18070Sstevel@tonic-gate 		ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
18080Sstevel@tonic-gate 		goto err;
18090Sstevel@tonic-gate 		}
18100Sstevel@tonic-gate 
18110Sstevel@tonic-gate 	/* Save the key information used in this session.
18120Sstevel@tonic-gate 	 * The max can be saved is PK11_KEY_LEN_MAX.
18130Sstevel@tonic-gate 	 */
18140Sstevel@tonic-gate 	sp->key_len = ctx->key_len > PK11_KEY_LEN_MAX ?
18150Sstevel@tonic-gate 		PK11_KEY_LEN_MAX : ctx->key_len;
18160Sstevel@tonic-gate 	memcpy(sp->key, key, sp->key_len);
18170Sstevel@tonic-gate err:
18180Sstevel@tonic-gate 
18190Sstevel@tonic-gate 	return h_key;
18200Sstevel@tonic-gate 	}
18210Sstevel@tonic-gate 
18220Sstevel@tonic-gate static int
18230Sstevel@tonic-gate md_nid_to_pk11(int nid)
18240Sstevel@tonic-gate 	{
18250Sstevel@tonic-gate 	int i;
18260Sstevel@tonic-gate 
18270Sstevel@tonic-gate 	for (i = 0; i < PK11_DIGEST_MAX; i++)
18280Sstevel@tonic-gate 		if (digests[i].nid == nid)
18290Sstevel@tonic-gate 			return (digests[i].id);
18300Sstevel@tonic-gate 	return (-1);
18310Sstevel@tonic-gate 	}
18320Sstevel@tonic-gate 
18330Sstevel@tonic-gate static int
18340Sstevel@tonic-gate pk11_digest_init(EVP_MD_CTX *ctx)
18350Sstevel@tonic-gate         {
18360Sstevel@tonic-gate 	CK_RV rv;
18374320Sjp161948 	CK_MECHANISM mech;
18380Sstevel@tonic-gate 	int index;
18390Sstevel@tonic-gate 	PK11_SESSION *sp;
18400Sstevel@tonic-gate 	PK11_DIGEST *pdp;
18410Sstevel@tonic-gate 	PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->md_data;
18420Sstevel@tonic-gate 
18430Sstevel@tonic-gate 	state->sp = NULL;
18440Sstevel@tonic-gate 
18450Sstevel@tonic-gate 	index = md_nid_to_pk11(ctx->digest->type);
18460Sstevel@tonic-gate 	if (index < 0 || index >= PK11_DIGEST_MAX)
18470Sstevel@tonic-gate 		return 0;
18480Sstevel@tonic-gate 
18490Sstevel@tonic-gate 	pdp = &digests[index];
18500Sstevel@tonic-gate 	if ((sp = pk11_get_session()) == NULL)
18510Sstevel@tonic-gate 		return 0;
18520Sstevel@tonic-gate 
18534320Sjp161948 	/* at present, no parameter is needed for supported digests */
18544320Sjp161948 	mech.mechanism = pdp->mech_type;
18554320Sjp161948 	mech.pParameter = NULL;
18564320Sjp161948 	mech.ulParameterLen = 0;
18574320Sjp161948 
18584320Sjp161948 	rv = pFuncList->C_DigestInit(sp->session, &mech);
18590Sstevel@tonic-gate 
18600Sstevel@tonic-gate 	if (rv != CKR_OK)
18610Sstevel@tonic-gate 		{
18620Sstevel@tonic-gate 		char tmp_buf[20];
18630Sstevel@tonic-gate 		PK11err(PK11_F_DIGEST_INIT, PK11_R_DIGESTINIT);
18640Sstevel@tonic-gate 		snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
18650Sstevel@tonic-gate 		ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
18660Sstevel@tonic-gate 		pk11_return_session(sp);
18670Sstevel@tonic-gate 		return 0;
18680Sstevel@tonic-gate 		}
18690Sstevel@tonic-gate 
18700Sstevel@tonic-gate 	state->sp = sp;
18710Sstevel@tonic-gate 
18720Sstevel@tonic-gate 	return 1;
18730Sstevel@tonic-gate 	}
18740Sstevel@tonic-gate 
18750Sstevel@tonic-gate static int
18762139Sjp161948 pk11_digest_update(EVP_MD_CTX *ctx,const void *data,size_t count)
18770Sstevel@tonic-gate         {
18780Sstevel@tonic-gate 	CK_RV rv;
18790Sstevel@tonic-gate 	PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->md_data;
18800Sstevel@tonic-gate 
18810Sstevel@tonic-gate 	/* 0 length message will cause a failure in C_DigestFinal */
18820Sstevel@tonic-gate 	if (count == 0)
18830Sstevel@tonic-gate 		return 1;
18840Sstevel@tonic-gate 
18850Sstevel@tonic-gate 	if (state == NULL || state->sp == NULL)
18860Sstevel@tonic-gate 		return 0;
18870Sstevel@tonic-gate 
18880Sstevel@tonic-gate 	rv = pFuncList->C_DigestUpdate(state->sp->session, (CK_BYTE *) data,
18890Sstevel@tonic-gate 		count);
18900Sstevel@tonic-gate 
18910Sstevel@tonic-gate 	if (rv != CKR_OK)
18920Sstevel@tonic-gate 		{
18930Sstevel@tonic-gate 		char tmp_buf[20];
18940Sstevel@tonic-gate 		PK11err(PK11_F_DIGEST_UPDATE, PK11_R_DIGESTUPDATE);
18950Sstevel@tonic-gate 		snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
18960Sstevel@tonic-gate 		ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
18970Sstevel@tonic-gate 		pk11_return_session(state->sp);
18980Sstevel@tonic-gate 		state->sp = NULL;
18990Sstevel@tonic-gate 		return 0;
19000Sstevel@tonic-gate 		}
19010Sstevel@tonic-gate 
19020Sstevel@tonic-gate 	return 1;
19030Sstevel@tonic-gate 	}
19040Sstevel@tonic-gate 
19050Sstevel@tonic-gate static int
19060Sstevel@tonic-gate pk11_digest_final(EVP_MD_CTX *ctx,unsigned char *md)
19070Sstevel@tonic-gate         {
19080Sstevel@tonic-gate 	CK_RV rv;
19090Sstevel@tonic-gate 	unsigned long len;
19100Sstevel@tonic-gate 	PK11_CIPHER_STATE *state = (PK11_CIPHER_STATE *) ctx->md_data;
19110Sstevel@tonic-gate 	len = ctx->digest->md_size;
19120Sstevel@tonic-gate 
19130Sstevel@tonic-gate 	if (state == NULL || state->sp == NULL)
19140Sstevel@tonic-gate 		return 0;
19150Sstevel@tonic-gate 
19160Sstevel@tonic-gate 	rv = pFuncList->C_DigestFinal(state->sp->session, md, &len);
19170Sstevel@tonic-gate 
19180Sstevel@tonic-gate 	if (rv != CKR_OK)
19190Sstevel@tonic-gate 		{
19200Sstevel@tonic-gate 		char tmp_buf[20];
19210Sstevel@tonic-gate 		PK11err(PK11_F_DIGEST_FINAL, PK11_R_DIGESTFINAL);
19220Sstevel@tonic-gate 		snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
19230Sstevel@tonic-gate 		ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
19240Sstevel@tonic-gate 		pk11_return_session(state->sp);
19250Sstevel@tonic-gate 		state->sp = NULL;
19260Sstevel@tonic-gate 		return 0;
19270Sstevel@tonic-gate 		}
19280Sstevel@tonic-gate 
19290Sstevel@tonic-gate 	if (ctx->digest->md_size != len)
19300Sstevel@tonic-gate 		return 0;
19310Sstevel@tonic-gate 
19320Sstevel@tonic-gate 	/* Final is called and digest is returned, so return the session
19330Sstevel@tonic-gate 	 * to the pool
19340Sstevel@tonic-gate 	 */
19350Sstevel@tonic-gate 	pk11_return_session(state->sp);
19360Sstevel@tonic-gate 	state->sp = NULL;
19370Sstevel@tonic-gate 
19380Sstevel@tonic-gate 	return 1;
19390Sstevel@tonic-gate 	}
19400Sstevel@tonic-gate 
19410Sstevel@tonic-gate static int
19420Sstevel@tonic-gate pk11_digest_copy(EVP_MD_CTX *to,const EVP_MD_CTX *from)
19430Sstevel@tonic-gate         {
19440Sstevel@tonic-gate 	CK_RV rv;
19450Sstevel@tonic-gate 	int ret = 0;
19460Sstevel@tonic-gate 	PK11_CIPHER_STATE *state, *state_to;
19470Sstevel@tonic-gate 	CK_BYTE_PTR pstate = NULL;
19480Sstevel@tonic-gate 	CK_ULONG ul_state_len;
19490Sstevel@tonic-gate 	char tmp_buf[20];
19500Sstevel@tonic-gate 
19510Sstevel@tonic-gate 	/* The copy-from state */
19520Sstevel@tonic-gate 	state = (PK11_CIPHER_STATE *) from->md_data;
19530Sstevel@tonic-gate 	if (state == NULL || state->sp == NULL)
19540Sstevel@tonic-gate 		goto err;
19550Sstevel@tonic-gate 
19560Sstevel@tonic-gate 	/* Initialize the copy-to state */
19570Sstevel@tonic-gate 	if (!pk11_digest_init(to))
19580Sstevel@tonic-gate 		goto err;
19590Sstevel@tonic-gate 	state_to = (PK11_CIPHER_STATE *) to->md_data;
19600Sstevel@tonic-gate 
19610Sstevel@tonic-gate 	/* Get the size of the operation state of the copy-from session */
19620Sstevel@tonic-gate 	rv = pFuncList->C_GetOperationState(state->sp->session, NULL,
19630Sstevel@tonic-gate 		&ul_state_len);
19640Sstevel@tonic-gate 
19650Sstevel@tonic-gate 	if (rv != CKR_OK)
19660Sstevel@tonic-gate 		{
19670Sstevel@tonic-gate 		PK11err(PK11_F_DIGEST_COPY, PK11_R_GET_OPERATION_STATE);
19680Sstevel@tonic-gate 		snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
19690Sstevel@tonic-gate 		ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
19700Sstevel@tonic-gate 		goto err;
19710Sstevel@tonic-gate 		}
19720Sstevel@tonic-gate 	if (ul_state_len == 0)
19730Sstevel@tonic-gate 		{
19740Sstevel@tonic-gate 		goto err;
19750Sstevel@tonic-gate 		}
19760Sstevel@tonic-gate 
19770Sstevel@tonic-gate 	pstate = OPENSSL_malloc(ul_state_len);
19780Sstevel@tonic-gate 	if (pstate == NULL)
19790Sstevel@tonic-gate 		{
1980*6847Svk199839 		PK11err(PK11_F_DIGEST_COPY, PK11_R_MALLOC_FAILURE);
19810Sstevel@tonic-gate 		goto err;
19820Sstevel@tonic-gate 		}
19830Sstevel@tonic-gate 
19840Sstevel@tonic-gate 	/* Get the operation state of the copy-from session */
19850Sstevel@tonic-gate 	rv = pFuncList->C_GetOperationState(state->sp->session, pstate,
19860Sstevel@tonic-gate 		&ul_state_len);
19870Sstevel@tonic-gate 
19880Sstevel@tonic-gate 	if (rv != CKR_OK)
19890Sstevel@tonic-gate 		{
19900Sstevel@tonic-gate 		PK11err(PK11_F_DIGEST_COPY, PK11_R_GET_OPERATION_STATE);
19910Sstevel@tonic-gate 		snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
19920Sstevel@tonic-gate 		ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
19930Sstevel@tonic-gate 		goto err;
19940Sstevel@tonic-gate 		}
19950Sstevel@tonic-gate 
19960Sstevel@tonic-gate 	/* Set the operation state of the copy-to session */
19970Sstevel@tonic-gate 	rv = pFuncList->C_SetOperationState(state_to->sp->session, pstate,
19980Sstevel@tonic-gate 		ul_state_len, 0, 0);
19990Sstevel@tonic-gate 
20000Sstevel@tonic-gate 	if (rv != CKR_OK)
20010Sstevel@tonic-gate 		{
20020Sstevel@tonic-gate 		PK11err(PK11_F_DIGEST_COPY, PK11_R_SET_OPERATION_STATE);
20030Sstevel@tonic-gate 		snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
20040Sstevel@tonic-gate 		ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
20050Sstevel@tonic-gate 		goto err;
20060Sstevel@tonic-gate 		}
20070Sstevel@tonic-gate 
20080Sstevel@tonic-gate 	ret = 1;
20090Sstevel@tonic-gate err:
20100Sstevel@tonic-gate 	if (pstate != NULL)
20110Sstevel@tonic-gate 		OPENSSL_free(pstate);
20120Sstevel@tonic-gate 
20130Sstevel@tonic-gate 	return ret;
20140Sstevel@tonic-gate 	}
20150Sstevel@tonic-gate 
20160Sstevel@tonic-gate /* Return any pending session state to the pool */
20170Sstevel@tonic-gate static int
20180Sstevel@tonic-gate pk11_digest_cleanup(EVP_MD_CTX *ctx)
20190Sstevel@tonic-gate 	{
20200Sstevel@tonic-gate 	PK11_CIPHER_STATE *state = ctx->md_data;
20214602Sjp161948 	unsigned char buf[EVP_MAX_MD_SIZE];
20220Sstevel@tonic-gate 
20230Sstevel@tonic-gate 	if (state != NULL && state->sp != NULL)
20240Sstevel@tonic-gate 		{
20254602Sjp161948 		/*
20264602Sjp161948 		 * If state->sp is not NULL then pk11_digest_final() has not
20274602Sjp161948 		 * been called yet. We must call it now to free any memory
20284602Sjp161948 		 * that might have been allocated in the token when
20294602Sjp161948 		 * pk11_digest_init() was called.
20304602Sjp161948 		 */
20314602Sjp161948 		pk11_digest_final(ctx,buf);
20320Sstevel@tonic-gate 		pk11_return_session(state->sp);
20330Sstevel@tonic-gate 		state->sp = NULL;
20340Sstevel@tonic-gate 		}
20350Sstevel@tonic-gate 
20360Sstevel@tonic-gate 	return 1;
20370Sstevel@tonic-gate 	}
20380Sstevel@tonic-gate 
2039*6847Svk199839 /*
2040*6847Svk199839  * Check if the new key is the same as the key object in the session.
20410Sstevel@tonic-gate  * If the key is the same, no need to create a new key object. Otherwise,
2042*6847Svk199839  * the old key object needs to be destroyed and a new one will be created.
2043*6847Svk199839  * Return 1 for cache hit, 0 for cache miss.
20440Sstevel@tonic-gate  */
2045*6847Svk199839 static int check_new_cipher_key(PK11_SESSION *sp, const unsigned char *key)
20460Sstevel@tonic-gate 	{
20470Sstevel@tonic-gate 	if (memcmp(sp->key, key, sp->key_len) != 0)
2048*6847Svk199839 		{
20490Sstevel@tonic-gate 		pk11_destroy_cipher_key_objects(sp);
2050*6847Svk199839 		return (0);
2051*6847Svk199839 		}
2052*6847Svk199839 	return (1);
20530Sstevel@tonic-gate 	}
20540Sstevel@tonic-gate 
20550Sstevel@tonic-gate /* Destroy one or more secret key objects.
20560Sstevel@tonic-gate  */
20570Sstevel@tonic-gate static int pk11_destroy_cipher_key_objects(PK11_SESSION *session)
20580Sstevel@tonic-gate 	{
20590Sstevel@tonic-gate 	int ret = 0;
20600Sstevel@tonic-gate 	PK11_SESSION *sp = NULL;
20610Sstevel@tonic-gate 	PK11_SESSION *local_free_session;
20620Sstevel@tonic-gate 
20630Sstevel@tonic-gate 	CRYPTO_w_lock(CRYPTO_LOCK_PK11_ENGINE);
20640Sstevel@tonic-gate 	if (session)
20650Sstevel@tonic-gate 		local_free_session = session;
20660Sstevel@tonic-gate 	else
20670Sstevel@tonic-gate 		local_free_session = free_session;
20680Sstevel@tonic-gate 	while ((sp = local_free_session) != NULL)
20690Sstevel@tonic-gate 		{
20700Sstevel@tonic-gate 		local_free_session = sp->next;
20710Sstevel@tonic-gate 
20720Sstevel@tonic-gate 		if (sp->cipher_key != CK_INVALID_HANDLE)
20730Sstevel@tonic-gate 			{
20740Sstevel@tonic-gate 			/* The secret key object is created in the
20750Sstevel@tonic-gate 			 * global_session. See pk11_get_cipher_key
20760Sstevel@tonic-gate 			 */
20770Sstevel@tonic-gate 			if (pk11_destroy_object(global_session,
20780Sstevel@tonic-gate 				sp->cipher_key) == 0)
20790Sstevel@tonic-gate 				goto err;
20800Sstevel@tonic-gate 			sp->cipher_key = CK_INVALID_HANDLE;
20810Sstevel@tonic-gate 			}
20820Sstevel@tonic-gate 		}
20830Sstevel@tonic-gate 	ret = 1;
20840Sstevel@tonic-gate err:
20850Sstevel@tonic-gate 	CRYPTO_w_unlock(CRYPTO_LOCK_PK11_ENGINE);
20860Sstevel@tonic-gate 
20870Sstevel@tonic-gate 	return ret;
20880Sstevel@tonic-gate 	}
20890Sstevel@tonic-gate 
20900Sstevel@tonic-gate 
20910Sstevel@tonic-gate /*
20920Sstevel@tonic-gate  * Required mechanisms
20930Sstevel@tonic-gate  *
20940Sstevel@tonic-gate  * CKM_RSA_X_509
20950Sstevel@tonic-gate  * CKM_RSA_PKCS
20960Sstevel@tonic-gate  * CKM_DSA
20970Sstevel@tonic-gate  *
20980Sstevel@tonic-gate  * As long as these required mechanisms are met, it will return success.
20990Sstevel@tonic-gate  * Otherwise, it will return failure and the engine initialization will fail.
21000Sstevel@tonic-gate  * The application will then decide whether to use another engine or
21010Sstevel@tonic-gate  * no engine.
21020Sstevel@tonic-gate  *
21030Sstevel@tonic-gate  * Symmetric ciphers optionally supported
21040Sstevel@tonic-gate  *
21050Sstevel@tonic-gate  * CKM_DES3_CBC
21060Sstevel@tonic-gate  * CKM_DES_CBC
21070Sstevel@tonic-gate  * CKM_AES_CBC
21080Sstevel@tonic-gate  * CKM_RC4
21090Sstevel@tonic-gate  *
21100Sstevel@tonic-gate  * Digests optionally supported
21110Sstevel@tonic-gate  *
21120Sstevel@tonic-gate  * CKM_MD5
21130Sstevel@tonic-gate  * CKM_SHA_1
21140Sstevel@tonic-gate  */
21150Sstevel@tonic-gate 
21160Sstevel@tonic-gate static int
21170Sstevel@tonic-gate pk11_choose_slot()
21180Sstevel@tonic-gate 	{
21190Sstevel@tonic-gate 	CK_SLOT_ID_PTR pSlotList = NULL_PTR;
21200Sstevel@tonic-gate 	CK_ULONG ulSlotCount = 0;
21210Sstevel@tonic-gate 	CK_MECHANISM_INFO mech_info;
21220Sstevel@tonic-gate 	CK_TOKEN_INFO token_info;
21230Sstevel@tonic-gate 	int i;
21240Sstevel@tonic-gate 	CK_RV rv;
21250Sstevel@tonic-gate 	CK_SLOT_ID best_slot_sofar;
21260Sstevel@tonic-gate 	CK_BBOOL found_candidate_slot = CK_FALSE;
21270Sstevel@tonic-gate 	int slot_n_cipher = 0;
21280Sstevel@tonic-gate 	int slot_n_digest = 0;
21290Sstevel@tonic-gate 	CK_SLOT_ID current_slot = 0;
21300Sstevel@tonic-gate 	int current_slot_n_cipher = 0;
21310Sstevel@tonic-gate 	int current_slot_n_digest = 0;
21320Sstevel@tonic-gate 
21330Sstevel@tonic-gate 	int local_cipher_nids[PK11_CIPHER_MAX];
21340Sstevel@tonic-gate 	int local_digest_nids[PK11_DIGEST_MAX];
21350Sstevel@tonic-gate 	char tmp_buf[20];
21360Sstevel@tonic-gate 	int retval = 0;
21370Sstevel@tonic-gate 
21380Sstevel@tonic-gate 	/* Get slot list for memory alloction */
21390Sstevel@tonic-gate 	rv = pFuncList->C_GetSlotList(0, NULL_PTR, &ulSlotCount);
21400Sstevel@tonic-gate 
21410Sstevel@tonic-gate 	if (rv != CKR_OK)
21420Sstevel@tonic-gate 		{
21430Sstevel@tonic-gate 		PK11err(PK11_F_CHOOSE_SLOT, PK11_R_GETSLOTLIST);
21440Sstevel@tonic-gate 		snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
21450Sstevel@tonic-gate 		ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
21460Sstevel@tonic-gate 		return retval;
21470Sstevel@tonic-gate 		}
21480Sstevel@tonic-gate 
21490Sstevel@tonic-gate 	if (ulSlotCount == 0)
21500Sstevel@tonic-gate 		{
21510Sstevel@tonic-gate 		PK11err(PK11_F_CHOOSE_SLOT, PK11_R_GETSLOTLIST);
21520Sstevel@tonic-gate 		return retval;
21530Sstevel@tonic-gate 		}
21540Sstevel@tonic-gate 
21550Sstevel@tonic-gate 	pSlotList = OPENSSL_malloc(ulSlotCount * sizeof (CK_SLOT_ID));
21560Sstevel@tonic-gate 
21570Sstevel@tonic-gate 	if (pSlotList == NULL)
21580Sstevel@tonic-gate 		{
2159*6847Svk199839 		PK11err(PK11_F_CHOOSE_SLOT, PK11_R_MALLOC_FAILURE);
21600Sstevel@tonic-gate 		return retval;
21610Sstevel@tonic-gate 		}
21620Sstevel@tonic-gate 
21630Sstevel@tonic-gate 	/* Get the slot list for processing */
21640Sstevel@tonic-gate 	rv = pFuncList->C_GetSlotList(0, pSlotList, &ulSlotCount);
21650Sstevel@tonic-gate 	if (rv != CKR_OK)
21660Sstevel@tonic-gate 		{
21670Sstevel@tonic-gate 		PK11err(PK11_F_CHOOSE_SLOT, PK11_R_GETSLOTLIST);
21680Sstevel@tonic-gate 		snprintf(tmp_buf, sizeof (tmp_buf), "%lx", rv);
21690Sstevel@tonic-gate 		ERR_add_error_data(2, "PK11 CK_RV=0X", tmp_buf);
21700Sstevel@tonic-gate 		OPENSSL_free(pSlotList);
21710Sstevel@tonic-gate 		return retval;
21720Sstevel@tonic-gate 		}
21730Sstevel@tonic-gate 
21740Sstevel@tonic-gate 	for (i = 0; i < ulSlotCount; i++)
21750Sstevel@tonic-gate 		{
21760Sstevel@tonic-gate 		CK_BBOOL slot_has_rsa = CK_FALSE;
21770Sstevel@tonic-gate 		CK_BBOOL slot_has_dsa = CK_FALSE;
21780Sstevel@tonic-gate 		CK_BBOOL slot_has_dh = CK_FALSE;
21790Sstevel@tonic-gate 		current_slot = pSlotList[i];
21800Sstevel@tonic-gate 		current_slot_n_cipher = 0;
21810Sstevel@tonic-gate 		current_slot_n_digest = 0;
21820Sstevel@tonic-gate 		memset(local_cipher_nids, 0, sizeof(local_cipher_nids));
21830Sstevel@tonic-gate 		memset(local_digest_nids, 0, sizeof(local_digest_nids));
21840Sstevel@tonic-gate 
21850Sstevel@tonic-gate #ifdef DEBUG_SLOT_SELECTION
21860Sstevel@tonic-gate 		fprintf(stderr, "OPENSSL_PKCS#11_ENGINE: checking slot: %d\n",
21870Sstevel@tonic-gate 		    current_slot);
21880Sstevel@tonic-gate #endif
21890Sstevel@tonic-gate 		/* Check if slot has random support. */
21900Sstevel@tonic-gate 		rv = pFuncList->C_GetTokenInfo(current_slot, &token_info);
21910Sstevel@tonic-gate 		if (rv != CKR_OK)
21920Sstevel@tonic-gate 			continue;
21930Sstevel@tonic-gate 
21940Sstevel@tonic-gate 		if (token_info.flags & CKF_RNG)
21950Sstevel@tonic-gate 			pk11_have_random = CK_TRUE;
2196*6847Svk199839 #ifndef OPENSSL_NO_RSA
21970Sstevel@tonic-gate 		/*
21980Sstevel@tonic-gate 		 * Check if this slot is capable of signing and
21990Sstevel@tonic-gate 		 * verifying with CKM_RSA_PKCS.
22000Sstevel@tonic-gate 		 */
22010Sstevel@tonic-gate 		rv = pFuncList->C_GetMechanismInfo(current_slot, CKM_RSA_PKCS,
22020Sstevel@tonic-gate 			&mech_info);
22030Sstevel@tonic-gate 
22040Sstevel@tonic-gate 		if (rv == CKR_OK && ((mech_info.flags & CKF_SIGN) &&
22050Sstevel@tonic-gate 				(mech_info.flags & CKF_VERIFY)))
22060Sstevel@tonic-gate 			{
22070Sstevel@tonic-gate 			/*
22080Sstevel@tonic-gate 			 * Check if this slot is capable of encryption,
22090Sstevel@tonic-gate 			 * decryption, sign, and verify with CKM_RSA_X_509.
22100Sstevel@tonic-gate 			 */
22110Sstevel@tonic-gate 			rv = pFuncList->C_GetMechanismInfo(current_slot,
22120Sstevel@tonic-gate 			  CKM_RSA_X_509, &mech_info);
22130Sstevel@tonic-gate 
22140Sstevel@tonic-gate 			if (rv == CKR_OK && ((mech_info.flags & CKF_SIGN) &&
22150Sstevel@tonic-gate 			    (mech_info.flags & CKF_VERIFY) &&
22160Sstevel@tonic-gate 			    (mech_info.flags & CKF_ENCRYPT) &&
22170Sstevel@tonic-gate 			    (mech_info.flags & CKF_VERIFY_RECOVER) &&
22180Sstevel@tonic-gate 			    (mech_info.flags & CKF_DECRYPT)))
22190Sstevel@tonic-gate 				slot_has_rsa = CK_TRUE;
22200Sstevel@tonic-gate 			}
2221*6847Svk199839 #endif
2222*6847Svk199839 #ifndef OPENSSL_NO_DSA
22230Sstevel@tonic-gate 		/*
22240Sstevel@tonic-gate 		 * Check if this slot is capable of signing and
22250Sstevel@tonic-gate 		 * verifying with CKM_DSA.
22260Sstevel@tonic-gate 		 */
22270Sstevel@tonic-gate 		rv = pFuncList->C_GetMechanismInfo(current_slot, CKM_DSA,
22280Sstevel@tonic-gate 			&mech_info);
22290Sstevel@tonic-gate 		if (rv == CKR_OK && ((mech_info.flags & CKF_SIGN) &&
22300Sstevel@tonic-gate 		    (mech_info.flags & CKF_VERIFY)))
22310Sstevel@tonic-gate 			slot_has_dsa = CK_TRUE;
2232*6847Svk199839 #endif
2233*6847Svk199839 #ifndef OPENSSL_NO_DH
22340Sstevel@tonic-gate 		/*
22350Sstevel@tonic-gate 		 * Check if this slot is capable of DH key generataion and
22360Sstevel@tonic-gate 		 * derivation.
22370Sstevel@tonic-gate 		 */
22380Sstevel@tonic-gate 		rv = pFuncList->C_GetMechanismInfo(current_slot,
22390Sstevel@tonic-gate 		  CKM_DH_PKCS_KEY_PAIR_GEN, &mech_info);
22400Sstevel@tonic-gate 
22410Sstevel@tonic-gate 		if (rv == CKR_OK && (mech_info.flags & CKF_GENERATE_KEY_PAIR))
22420Sstevel@tonic-gate 			{
22430Sstevel@tonic-gate 			rv = pFuncList->C_GetMechanismInfo(current_slot,
22440Sstevel@tonic-gate 				CKM_DH_PKCS_DERIVE, &mech_info);
22450Sstevel@tonic-gate 			if (rv == CKR_OK && (mech_info.flags & CKF_DERIVE))
22460Sstevel@tonic-gate 				slot_has_dh = CK_TRUE;
22470Sstevel@tonic-gate 			}
2248*6847Svk199839 #endif
22490Sstevel@tonic-gate 		if (!found_candidate_slot &&
22500Sstevel@tonic-gate 		    (slot_has_rsa || slot_has_dsa || slot_has_dh))
22510Sstevel@tonic-gate 			{
22520Sstevel@tonic-gate #ifdef DEBUG_SLOT_SELECTION
22530Sstevel@tonic-gate 			fprintf(stderr,
22540Sstevel@tonic-gate 			    "OPENSSL_PKCS#11_ENGINE: potential slot: %d\n",
22550Sstevel@tonic-gate 			    current_slot);
22560Sstevel@tonic-gate #endif
22570Sstevel@tonic-gate 			best_slot_sofar = current_slot;
22580Sstevel@tonic-gate 			pk11_have_rsa = slot_has_rsa;
22590Sstevel@tonic-gate 			pk11_have_dsa = slot_has_dsa;
22600Sstevel@tonic-gate 			pk11_have_dh = slot_has_dh;
22610Sstevel@tonic-gate 			found_candidate_slot = CK_TRUE;
22620Sstevel@tonic-gate #ifdef DEBUG_SLOT_SELECTION
22630Sstevel@tonic-gate 			fprintf(stderr,
22640Sstevel@tonic-gate 		    	    "OPENSSL_PKCS#11_ENGINE: best so far slot: %d\n",
22650Sstevel@tonic-gate 		    	    best_slot_sofar);
22660Sstevel@tonic-gate #endif
22670Sstevel@tonic-gate 			}
22680Sstevel@tonic-gate 
22690Sstevel@tonic-gate 		/* Count symmetric cipher support. */
22700Sstevel@tonic-gate 		if (!pk11_count_symmetric_cipher(current_slot, CKM_DES_CBC,
22710Sstevel@tonic-gate 				&current_slot_n_cipher, local_cipher_nids,
22720Sstevel@tonic-gate 				PK11_DES_CBC))
22730Sstevel@tonic-gate 			continue;
22740Sstevel@tonic-gate 		if (!pk11_count_symmetric_cipher(current_slot, CKM_DES3_CBC,
22750Sstevel@tonic-gate 				&current_slot_n_cipher, local_cipher_nids,
22760Sstevel@tonic-gate 				PK11_DES3_CBC))
22770Sstevel@tonic-gate 			continue;
22780Sstevel@tonic-gate 		if (!pk11_count_symmetric_cipher(current_slot, CKM_AES_CBC,
22790Sstevel@tonic-gate 				&current_slot_n_cipher, local_cipher_nids,
22800Sstevel@tonic-gate 				PK11_AES_CBC))
22810Sstevel@tonic-gate 			continue;
22820Sstevel@tonic-gate 		if (!pk11_count_symmetric_cipher(current_slot, CKM_RC4,
22830Sstevel@tonic-gate 				&current_slot_n_cipher, local_cipher_nids,
22840Sstevel@tonic-gate 				PK11_RC4))
22850Sstevel@tonic-gate 			continue;
22860Sstevel@tonic-gate 
22870Sstevel@tonic-gate 		/* Count digest support */
22880Sstevel@tonic-gate 		if (!pk11_count_digest(current_slot, CKM_MD5,
22890Sstevel@tonic-gate 				&current_slot_n_digest, local_digest_nids,
22900Sstevel@tonic-gate 				PK11_MD5))
22910Sstevel@tonic-gate 			continue;
22920Sstevel@tonic-gate 		if (!pk11_count_digest(current_slot, CKM_SHA_1,
22930Sstevel@tonic-gate 				&current_slot_n_digest, local_digest_nids,
22940Sstevel@tonic-gate 				PK11_SHA1))
22950Sstevel@tonic-gate 			continue;
22960Sstevel@tonic-gate 
22970Sstevel@tonic-gate 		/*
22980Sstevel@tonic-gate 		 * If the current slot supports more ciphers/digests than
22990Sstevel@tonic-gate 		 * the previous best one we change the current best to this one.
23000Sstevel@tonic-gate 		 * otherwise leave it where it is.
23010Sstevel@tonic-gate 		 */
23020Sstevel@tonic-gate 		if (((current_slot_n_cipher > slot_n_cipher) &&
23030Sstevel@tonic-gate 		    (current_slot_n_digest > slot_n_digest)) &&
23040Sstevel@tonic-gate 		    ((slot_has_rsa == pk11_have_rsa) &&
23050Sstevel@tonic-gate 		     (slot_has_dsa == pk11_have_dsa) &&
23060Sstevel@tonic-gate 		     (slot_has_dh == pk11_have_dh)))
23070Sstevel@tonic-gate 			{
23080Sstevel@tonic-gate 			best_slot_sofar = current_slot;
23090Sstevel@tonic-gate 			slot_n_cipher = current_slot_n_cipher;
23100Sstevel@tonic-gate 			slot_n_digest = current_slot_n_digest;
23110Sstevel@tonic-gate 
23120Sstevel@tonic-gate 			memcpy(cipher_nids, local_cipher_nids,
23130Sstevel@tonic-gate 				sizeof(local_cipher_nids));
23140Sstevel@tonic-gate 			memcpy(digest_nids, local_digest_nids,
23150Sstevel@tonic-gate 				sizeof(local_digest_nids));
23160Sstevel@tonic-gate 			}
23170Sstevel@tonic-gate 
23180Sstevel@tonic-gate 		}
23190Sstevel@tonic-gate 
23200Sstevel@tonic-gate 	if (found_candidate_slot)
23210Sstevel@tonic-gate 		{
23220Sstevel@tonic-gate 		cipher_count = slot_n_cipher;
23230Sstevel@tonic-gate 		digest_count = slot_n_digest;
23240Sstevel@tonic-gate 		SLOTID = best_slot_sofar;
23250Sstevel@tonic-gate 		retval = 1;
23260Sstevel@tonic-gate 		}
23270Sstevel@tonic-gate 	else
23280Sstevel@tonic-gate 		{
23290Sstevel@tonic-gate 		cipher_count = 0;
23300Sstevel@tonic-gate 		digest_count = 0;
23310Sstevel@tonic-gate 		}
23320Sstevel@tonic-gate 
23330Sstevel@tonic-gate #ifdef DEBUG_SLOT_SELECTION
23340Sstevel@tonic-gate 	fprintf(stderr,
23350Sstevel@tonic-gate 	  "OPENSSL_PKCS#11_ENGINE: choose slot: %d\n", SLOTID);
23360Sstevel@tonic-gate 	fprintf(stderr,
23370Sstevel@tonic-gate 	  "OPENSSL_PKCS#11_ENGINE: pk11_have_rsa %d\n", pk11_have_rsa);
23380Sstevel@tonic-gate 	fprintf(stderr,
23390Sstevel@tonic-gate 	  "OPENSSL_PKCS#11_ENGINE: pk11_have_dsa %d\n", pk11_have_dsa);
23400Sstevel@tonic-gate 	fprintf(stderr,
23410Sstevel@tonic-gate 	  "OPENSSL_PKCS#11_ENGINE: pk11_have_dh %d\n", pk11_have_dh);
23420Sstevel@tonic-gate 	fprintf(stderr,
23430Sstevel@tonic-gate 	  "OPENSSL_PKCS#11_ENGINE: pk11_have_random %d\n", pk11_have_random);
23440Sstevel@tonic-gate #endif /* DEBUG_SLOT_SELECTION */
23450Sstevel@tonic-gate 
2346*6847Svk199839 	if (pSlotList != NULL)
2347*6847Svk199839 		OPENSSL_free(pSlotList);
23480Sstevel@tonic-gate 
23490Sstevel@tonic-gate 	return retval;
23500Sstevel@tonic-gate 	}
23510Sstevel@tonic-gate 
23520Sstevel@tonic-gate static int pk11_count_symmetric_cipher(int slot_id, CK_MECHANISM_TYPE mech,
23530Sstevel@tonic-gate     int *current_slot_n_cipher, int *local_cipher_nids, int id)
23540Sstevel@tonic-gate 	{
23550Sstevel@tonic-gate 	CK_MECHANISM_INFO mech_info;
23560Sstevel@tonic-gate 	CK_RV rv;
23570Sstevel@tonic-gate 
23580Sstevel@tonic-gate 	rv = pFuncList->C_GetMechanismInfo(slot_id, mech, &mech_info);
23590Sstevel@tonic-gate 
23600Sstevel@tonic-gate 	if (rv != CKR_OK)
23610Sstevel@tonic-gate 		return 0;
23620Sstevel@tonic-gate 
23630Sstevel@tonic-gate 	if ((mech_info.flags & CKF_ENCRYPT) &&
23640Sstevel@tonic-gate 			(mech_info.flags & CKF_DECRYPT))
23650Sstevel@tonic-gate 		{
23660Sstevel@tonic-gate 		local_cipher_nids[(*current_slot_n_cipher)++] = ciphers[id].nid;
23670Sstevel@tonic-gate 		}
23680Sstevel@tonic-gate 
23690Sstevel@tonic-gate 	return 1;
23700Sstevel@tonic-gate 	}
23710Sstevel@tonic-gate 
23720Sstevel@tonic-gate 
23730Sstevel@tonic-gate static int pk11_count_digest(int slot_id, CK_MECHANISM_TYPE mech,
23740Sstevel@tonic-gate     int *current_slot_n_digest, int *local_digest_nids, int id)
23750Sstevel@tonic-gate 	{
23760Sstevel@tonic-gate 	CK_MECHANISM_INFO mech_info;
23770Sstevel@tonic-gate 	CK_RV rv;
23780Sstevel@tonic-gate 
23790Sstevel@tonic-gate 	rv = pFuncList->C_GetMechanismInfo(slot_id, mech, &mech_info);
23800Sstevel@tonic-gate 
23810Sstevel@tonic-gate 	if (rv != CKR_OK)
23820Sstevel@tonic-gate 		return 0;
23830Sstevel@tonic-gate 
23840Sstevel@tonic-gate 	if (mech_info.flags & CKF_DIGEST)
23850Sstevel@tonic-gate 		{
23860Sstevel@tonic-gate 		local_digest_nids[(*current_slot_n_digest)++] = digests[id].nid;
23870Sstevel@tonic-gate 		}
23880Sstevel@tonic-gate 
23890Sstevel@tonic-gate 	return 1;
23900Sstevel@tonic-gate 	}
23910Sstevel@tonic-gate #endif
23920Sstevel@tonic-gate #endif
2393